tail.c (1845B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <unistd.h> 6 7 #include "text.h" 8 #include "util.h" 9 10 static void dropinit(FILE *, const char *, long); 11 static void taketail(FILE *, const char *, long); 12 13 static void 14 usage(void) 15 { 16 eprintf("usage: %s [-n lines] [file]\n", argv0); 17 } 18 19 int 20 main(int argc, char *argv[]) 21 { 22 long n = 10; 23 FILE *fp; 24 void (*tail)(FILE *, const char *, long) = taketail; 25 char *lines; 26 int ret = 0; 27 int newline, many; 28 29 ARGBEGIN { 30 case 'n': 31 lines = EARGF(usage()); 32 n = abs(estrtol(lines, 0)); 33 if (lines[0] == '+') 34 tail = dropinit; 35 break; 36 ARGNUM: 37 n = ARGNUMF(0); 38 break; 39 default: 40 usage(); 41 } ARGEND; 42 if (argc == 0) { 43 tail(stdin, "<stdin>", n); 44 } else { 45 many = argc > 1; 46 for (newline = 0; argc > 0; argc--, argv++) { 47 if (!(fp = fopen(argv[0], "r"))) { 48 weprintf("fopen %s:", argv[0]); 49 ret = 1; 50 continue; 51 } 52 if (many) 53 printf("%s==> %s <==\n", 54 newline ? "\n" : "", argv[0]); 55 newline = 1; 56 tail(fp, argv[0], n); 57 fclose(fp); 58 } 59 } 60 return ret; 61 } 62 63 static void 64 dropinit(FILE *fp, const char *str, long n) 65 { 66 char *buf = NULL; 67 size_t size = 0; 68 ssize_t len; 69 unsigned long i = 0; 70 71 while (i < n && ((len = getline(&buf, &size, fp)) != -1)) 72 if (len && buf[len - 1] == '\n') 73 i++; 74 free(buf); 75 concat(fp, str, stdout, "<stdout>"); 76 } 77 78 static void 79 taketail(FILE *fp, const char *str, long n) 80 { 81 char **ring = NULL; 82 long i, j; 83 size_t *size = NULL; 84 85 ring = ecalloc(n, sizeof *ring); 86 size = ecalloc(n, sizeof *size); 87 88 for (i = j = 0; getline(&ring[i], &size[i], fp) != -1; i = j = (i + 1) % n) 89 ; 90 if (ferror(fp)) 91 eprintf("%s: read error:", str); 92 93 do { 94 if (ring[j]) { 95 fputs(ring[j], stdout); 96 free(ring[j]); 97 } 98 } while ((j = (j+1)%n) != i); 99 free(ring); 100 free(size); 101 }