/******************************************************************************* * K&R 5-13 * * Print last lines of file * * Basically a rehash of the linesort program. The point was kind of to * use the argument reading method for -type args, but this "cheat" makes * it work with more input. If -n is not set by user, default is 10. * * program: my_tail * usage..: my_tail -n[NUM OF LAST LINES TO PRINT] * Ex: my_tail -n5 < some_file * date...: 21 November 2024 * * ~yetimach ******************************************************************************/ #include #include #include void writelines(char *lineptr[], int nlines){ while (nlines-- > 0) printf("%s\n", *lineptr++); } int my_getline(char *s, int max){ int c, i; for (i = 0; i < max-1 && (c = getchar()) != '\n' && c != EOF; *s++ = c, i++) ; *s = '\0'; if (i >= max-1) return -1; else return i; } #define ALLOCSIZE 1000 static char allocbuf[ALLOCSIZE]; static char *allocp = allocbuf; char *alloc(int n){ /*allocbuf is an array. Adding ALLOCSIZE gives its full length. Subtracting * allocp results in how much space is left in allocbuf because allocp was * set to the beginning of allocbuf on declatation. */ if (allocbuf + ALLOCSIZE - allocp >= n){ allocp += n; return allocp - n; }else return NULL; } void afree(char *p){ if (p >= allocbuf && p < allocbuf + ALLOCSIZE) allocp = p; } #define MAXLEN 1000 int readlines(char *lineptr[], int maxlines){ int len, nlines; char *p, line[MAXLEN]; nlines = 0; while ((len = my_getline(line, MAXLEN)) > 0) if (nlines >= maxlines || (p = alloc(len+1)) == NULL) return -1; else { line[len] = '\0'; strcpy(p, line); lineptr[nlines++] = p; } return nlines; } int positive_int_from_argv(char *s){ int num, c ; num = c = 0; while (!isdigit(c = *s++) && c != '\0') ; if (c == '\0') return num; if (isdigit(c)){ num = c - '0'; } while (isdigit(c = *s++)) num = (num * 10) + (c - '0'); return num; } #define MAXLINES 1000 char *lineptr[MAXLINES]; int main(int argc, char *argv[]) { int print_n = 10; /*number of lines to print*/ if (argc == 1) ; else if (argc == 2){ print_n = positive_int_from_argv(*++argv); if (print_n == 0){ printf("error: invalid number of lines: '%s'\n", *argv); return 1; } } else { printf("usage: my_tail -n[NUMBER OF LINES TO PRINT]\n" "-n optional, default 10\nEX my_tail -n5\n"); return 1; } int nlines; if ((nlines = readlines(lineptr, MAXLINES)) >= 0){ if (nlines >= print_n){ nlines -= print_n; /*make nlines number of line to start printing*/ writelines(&lineptr[nlines], print_n); /*and start from pointer to*/ } else /*that line*/ writelines(lineptr, nlines); } else { printf("error: input too big\n"); return 1; } return 0; }