tail.c (3451B)
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 PR_fprintf(err, "Usage: tail [-n <n>] [-f] [-h] <filename>\n"); 23 PR_fprintf(err, "\t-t <n> Dally time in milliseconds\n"); 24 PR_fprintf(err, "\t-n <n> Number of bytes before <eof>\n"); 25 PR_fprintf(err, "\t-f Follow the <eof>\n"); 26 PR_fprintf(err, "\t-h This message and nothing else\n"); 27 } /* Help */ 28 29 PRIntn main(PRIntn argc, char** argv) { 30 PRIntn rv = 0; 31 PLOptStatus os; 32 PRStatus status; 33 PRFileDesc* file; 34 PRFileInfo fileInfo; 35 PRIntervalTime dally; 36 char buffer[BUFFER_SIZE]; 37 PRBool follow = PR_FALSE; 38 const char* filename = NULL; 39 PRUint32 position = 0, seek = 0, time = 0; 40 PLOptState* opt = PL_CreateOptState(argc, argv, "hfn:"); 41 42 out = PR_GetSpecialFD(PR_StandardOutput); 43 err = PR_GetSpecialFD(PR_StandardError); 44 45 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 46 if (PL_OPT_BAD == os) { 47 continue; 48 } 49 switch (opt->option) { 50 case 0: /* it's the filename */ 51 filename = opt->value; 52 break; 53 case 'n': /* bytes before end of file */ 54 seek = atoi(opt->value); 55 break; 56 case 't': /* dally time */ 57 time = atoi(opt->value); 58 break; 59 case 'f': /* follow the end of file */ 60 follow = PR_TRUE; 61 break; 62 case 'h': /* user wants some guidance */ 63 Help(); /* so give him an earful */ 64 return 2; /* but not a lot else */ 65 break; 66 default: 67 break; 68 } 69 } 70 PL_DestroyOptState(opt); 71 72 if (0 == time) { 73 time = 1000; 74 } 75 dally = PR_MillisecondsToInterval(time); 76 77 if (NULL == filename) { 78 (void)PR_fprintf(out, "Input file not specified\n"); 79 rv = 1; 80 goto done; 81 } 82 file = PR_Open(filename, PR_RDONLY, 0); 83 if (NULL == file) { 84 PL_FPrintError(err, "File cannot be opened for reading"); 85 return 1; 86 } 87 88 status = PR_GetOpenFileInfo(file, &fileInfo); 89 if (PR_FAILURE == status) { 90 PL_FPrintError(err, "Cannot acquire status of file"); 91 rv = 1; 92 goto done; 93 } 94 if (seek > 0) { 95 if (seek > fileInfo.size) { 96 seek = 0; 97 } 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 104 do { 105 while (position < fileInfo.size) { 106 PRInt32 read, bytes = fileInfo.size - position; 107 if (bytes > sizeof(buffer)) { 108 bytes = sizeof(buffer); 109 } 110 read = PR_Read(file, buffer, bytes); 111 if (read != bytes) { 112 PL_FPrintError(err, "Cannot read to eof"); 113 } 114 position += read; 115 PR_Write(out, buffer, read); 116 } 117 118 if (follow) { 119 PR_Sleep(dally); 120 status = PR_GetOpenFileInfo(file, &fileInfo); 121 if (PR_FAILURE == status) { 122 PL_FPrintError(err, "Cannot acquire status of file"); 123 rv = 1; 124 goto done; 125 } 126 } 127 } while (follow); 128 129 done: 130 PR_Close(file); 131 132 return rv; 133 } /* main */ 134 135 /* tail.c */