add LICENSE.BSD-2.0 file
[platform/upstream/nspr.git] / tools / tail.c
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
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
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 */