Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 lines
5.6 KiB

  1. /* tail - first n lines to STDOUT
  2. *
  3. * 15-May-1994 PeterWi Cloned from head.c
  4. *
  5. * 1-Apr-1997 v-charls (intel) Added the -f option
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <io.h>
  11. #include <sys\stat.h>
  12. #include <fcntl.h>
  13. #include <windows.h>
  14. int Tail(char *pszFile, int nLines, BOOL fBanner, BOOL keepOpen);
  15. #define BUFSZ 4096
  16. void Usage(void);
  17. void
  18. __cdecl main( argc, argv )
  19. int argc;
  20. char *argv[];
  21. {
  22. int nArg;
  23. int cLines = 10; // default
  24. int nFiles = 0;
  25. int nErr = 0;
  26. int keepOpen = FALSE; // default
  27. if ((argc > 1) && ((*argv[1] == '-') || (*argv[1] == '/'))) {
  28. if (argv[1][1] == '?') {
  29. Usage( );
  30. exit( 0 );
  31. }
  32. if (argv[1][1] == 'f') {
  33. keepOpen = TRUE;
  34. }
  35. else {
  36. cLines = atoi( argv[1]+1 );
  37. }
  38. nArg = 2;
  39. }
  40. else {
  41. nArg = 1;
  42. }
  43. nFiles = argc - nArg;
  44. //
  45. // May only keep open exactly one file
  46. //
  47. if ((nFiles != 1) && (keepOpen)) {
  48. Usage( );
  49. exit( 0 );
  50. }
  51. if (nFiles < 1) {
  52. nErr += Tail( NULL, cLines, FALSE, keepOpen );
  53. }
  54. else while (nArg < argc) {
  55. nErr += Tail( argv[nArg], cLines, (nFiles > 1), keepOpen );
  56. nArg++;
  57. }
  58. if (nErr)
  59. {
  60. exit( 2 );
  61. }
  62. else
  63. {
  64. exit( 0 );
  65. }
  66. }
  67. void Usage( void )
  68. {
  69. printf( "usage: TAIL [switches] [filename]*\n"
  70. " switches: [-?] display this message\n"
  71. " [-n] display last n lines of each file (default 10)\n"
  72. " [-f filename] keep checking filename for new lines\n"
  73. );
  74. }
  75. int Tail( char *pszFile, int nLines, BOOL fBanner, BOOL keepOpen )
  76. {
  77. int fd;
  78. int nErr = 0;
  79. LONGLONG offset;
  80. int cRead;
  81. int amt;
  82. int i;
  83. int nFound;
  84. char buff[BUFSZ];
  85. struct _stati64 fileStat;
  86. LONGLONG oldSize;
  87. LONGLONG toRead;
  88. /*
  89. * Open file for reading
  90. */
  91. if ( pszFile ) {
  92. if ( (fd = _open( pszFile, O_RDONLY | O_TEXT, 0 )) == -1 ) {
  93. fprintf( stderr, "TAIL: can't open %s\n", pszFile );
  94. return 1;
  95. }
  96. }
  97. else {
  98. fd = 0;
  99. }
  100. /*
  101. * Banner printed if there is more than one input file
  102. */
  103. if ( fBanner ) {
  104. fprintf( stdout, "==> %s <==\n", pszFile );
  105. }
  106. if ( (offset = _lseeki64( fd, 0, SEEK_END )) == -1 ) {
  107. fprintf( stderr, "TAIL: lseeki64() failed %d\n", errno );
  108. nErr++;
  109. goto CloseOut;
  110. }
  111. // Backup BUFSZ bytes from end of file and see how many lines we have
  112. if ( _fstati64( fd, &fileStat ) == -1 ) {
  113. fprintf( stderr, "TAIL: fstati64() failed\n" );
  114. nErr++;
  115. goto CloseOut;
  116. }
  117. //
  118. // Save it away for later comparison...
  119. //
  120. oldSize = fileStat.st_size;
  121. if (fileStat.st_size == 0) {
  122. fileStat.st_size = BUFSZ;
  123. }
  124. offset = 0;
  125. nFound = 0;
  126. // stop when found the req'd no. of lines or when backed up to
  127. // the start of the file.
  128. while ( (nFound <= nLines) && (offset < fileStat.st_size) ) {
  129. offset += BUFSZ;
  130. if ( offset > fileStat.st_size ) {
  131. offset = fileStat.st_size;
  132. }
  133. if ( _lseeki64( fd, -offset, SEEK_END ) == -1L ) {
  134. fprintf( stderr, "TAIL: lseeki64() failed\n" );
  135. nErr++;
  136. goto CloseOut;
  137. }
  138. if ( (cRead = _read( fd, buff, BUFSZ )) == -1 ) {
  139. fprintf( stderr, "TAIL: read() failed\n" );
  140. nErr++;
  141. goto CloseOut;
  142. }
  143. // count back nLines
  144. i = cRead;
  145. while ( --i >= 0 ) {
  146. if ( buff[i] == '\n' ) {
  147. if ( ++nFound > nLines ) {
  148. break;
  149. }
  150. }
  151. }
  152. }
  153. i++; // either 1 past start of file or sitting on '\n'. In either
  154. // case we must advance 1.
  155. // print from the current index to the end of file.
  156. while ( cRead != 0 ) {
  157. if ( _write( 1, &buff[i], cRead - i ) == -1 ) {
  158. fprintf( stderr, "TAIL: write() failed\n" );
  159. nErr++;
  160. goto CloseOut;
  161. }
  162. i = 0; // after first buff, all buffers are of cRead bytes
  163. if ( (cRead = _read( fd, buff, BUFSZ )) == -1 ) {
  164. fprintf( stderr, "TAIL: read() failed\n" );
  165. nErr++;
  166. goto CloseOut;
  167. }
  168. }
  169. if ( fBanner ) {
  170. fprintf(stdout, "\n");
  171. }
  172. if (keepOpen) {
  173. while (1) {
  174. if ( _fstati64( fd, &fileStat ) == -1 ) {
  175. fprintf( stderr, "TAIL: fstat() failed\n" );
  176. nErr++;
  177. goto CloseOut;
  178. }
  179. toRead = fileStat.st_size - oldSize;
  180. while (toRead) {
  181. if (toRead > BUFSZ) {
  182. amt = BUFSZ;
  183. }
  184. else {
  185. amt = (int)toRead;
  186. }
  187. if ( (cRead = _read( fd, buff, amt )) == -1 ) {
  188. fprintf( stderr, "TAIL: read() failed\n" );
  189. nErr++;
  190. goto CloseOut;
  191. }
  192. if ( cRead == 0 ) { // found EOF
  193. break;
  194. }
  195. if (_write( 1, buff, cRead ) != cRead ) {
  196. fprintf( stderr, "TAIL: write() failed\n" );
  197. nErr++;
  198. goto CloseOut;
  199. }
  200. toRead -= cRead;
  201. }
  202. oldSize = fileStat.st_size;
  203. SleepEx( 1000, TRUE );
  204. }
  205. }
  206. CloseOut:
  207. if ( _close( fd ) == -1 ) {
  208. fprintf( stderr, "TAIL: close() failed\n" );
  209. }
  210. return nErr;
  211. }