1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "prio.h"
7 #include "prprf.h"
8 #include "prinit.h"
9 #include "prthread.h"
10 #include "prinrval.h"
11
12 #include "plerror.h"
13 #include "plgetopt.h"
14
15 #include <stdlib.h>
16
17 #define BUFFER_SIZE 500
18
19 static PRFileDesc *out = NULL, *err = NULL;
20
Help(void)21 static void Help(void)
22 {
23 PR_fprintf(err, "Usage: tail [-n <n>] [-f] [-h] <filename>\n");
24 PR_fprintf(err, "\t-t <n> Dally time in milliseconds\n");
25 PR_fprintf(err, "\t-n <n> Number of bytes before <eof>\n");
26 PR_fprintf(err, "\t-f Follow the <eof>\n");
27 PR_fprintf(err, "\t-h This message and nothing else\n");
28 } /* Help */
29
main(PRIntn argc,char ** argv)30 PRIntn main(PRIntn argc, char **argv)
31 {
32 PRIntn rv = 0;
33 PLOptStatus os;
34 PRStatus status;
35 PRFileDesc *file;
36 PRFileInfo fileInfo;
37 PRIntervalTime dally;
38 char buffer[BUFFER_SIZE];
39 PRBool follow = PR_FALSE;
40 const char *filename = NULL;
41 PRUint32 position = 0, seek = 0, time = 0;
42 PLOptState *opt = PL_CreateOptState(argc, argv, "hfn:");
43
44 out = PR_GetSpecialFD(PR_StandardOutput);
45 err = PR_GetSpecialFD(PR_StandardError);
46
47 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
48 {
49 if (PL_OPT_BAD == os) continue;
50 switch (opt->option)
51 {
52 case 0: /* it's the filename */
53 filename = opt->value;
54 break;
55 case 'n': /* bytes before end of file */
56 seek = atoi(opt->value);
57 break;
58 case 't': /* dally time */
59 time = atoi(opt->value);
60 break;
61 case 'f': /* follow the end of file */
62 follow = PR_TRUE;
63 break;
64 case 'h': /* user wants some guidance */
65 Help(); /* so give him an earful */
66 return 2; /* but not a lot else */
67 break;
68 default:
69 break;
70 }
71 }
72 PL_DestroyOptState(opt);
73
74 if (0 == time) time = 1000;
75 dally = PR_MillisecondsToInterval(time);
76
77 if (NULL == filename)
78 {
79 (void)PR_fprintf(out, "Input file not specified\n");
80 rv = 1; goto done;
81 }
82 file = PR_Open(filename, PR_RDONLY, 0);
83 if (NULL == file)
84 {
85 PL_FPrintError(err, "File cannot be opened for reading");
86 return 1;
87 }
88
89 status = PR_GetOpenFileInfo(file, &fileInfo);
90 if (PR_FAILURE == status)
91 {
92 PL_FPrintError(err, "Cannot acquire status of file");
93 rv = 1; goto done;
94 }
95 if (seek > 0)
96 {
97 if (seek > fileInfo.size) seek = 0;
98 position = PR_Seek(file, (fileInfo.size - seek), PR_SEEK_SET);
99 if (-1 == (PRInt32)position)
100 PL_FPrintError(err, "Cannot seek to starting position");
101 }
102
103 do
104 {
105 while (position < fileInfo.size)
106 {
107 PRInt32 read, bytes = fileInfo.size - position;
108 if (bytes > sizeof(buffer)) bytes = sizeof(buffer);
109 read = PR_Read(file, buffer, bytes);
110 if (read != bytes)
111 PL_FPrintError(err, "Cannot read to eof");
112 position += read;
113 PR_Write(out, buffer, read);
114 }
115
116 if (follow)
117 {
118 PR_Sleep(dally);
119 status = PR_GetOpenFileInfo(file, &fileInfo);
120 if (PR_FAILURE == status)
121 {
122 PL_FPrintError(err, "Cannot acquire status of file");
123 rv = 1; goto done;
124 }
125 }
126 } while (follow);
127
128 done:
129 PR_Close(file);
130
131 return rv;
132 } /* main */
133
134 /* tail.c */
135