/* Program: TAILZ - display tail end of ASCII file. Author: Carson Wilson, sysop, Antelope Freeway RAS, 312/764-5162, Chicago. Date: 19 Aug 90 Version: 1.0 Assembly: BDS Z, linked with Z3FUNC.CRL from Cameron Cotrill's CFORZxx.LBR. Link with -n option to avoid warmboot on exit. Compile and link with -e2000 for faster execution/smaller size. Changes: Works under CP/M and Z System. Displays last 10 lines by default like its Unix cousin. Allows Z System "//" help syntax. Improved help message. Now compatible with secure Z Systems: - Tests for illegal file types (.COM, etc). - Aborts on illegal directories or if NonWheel tries to view a $SYStem file. Gives invokation name in help and error messages (ZCPR only). Chains to Z System error handler (if present) on no file, bad numeric value, bad directory, and AFN errors. If Z not present displays error messages instead. Removed "empty file" error message; now just exits (also like Unix cousin). Comments: To display the tail of a file whose name begins with "-" you must use a directory spec, e.g., "TAILZ A:-MYFILE". Derived from: TAIL.C -- Print last several lines of a text file. Written by Leor Zolman, 3/83 If you modify TAILZ, please contact me if possible before distributing the new version to eliminate duplication of effort. */ #include #define LINES_DEF 10 /* number of lines before EOF to display */ #define NBSECTS 200 /* number of sectors before EOF to buffer */ #define TXTBUFSIZE (NBSECTS * SECSIZ + 1) /* size of text buffer */ /* Z System error types. */ #define ecBADDIR 2 /* Bad directory */ #define ecAMBIG 8 /* AFN */ #define ecBADNUM 9 /* Bad number */ #define ecNOFILE 10 /* No file */ #define ecTPAFULL 12 /* TPA overflow */ char invnam[14]; int lastchar(c) char c; { return (!c) || (c == CPMEOF); } void zerr(code,defstring) /* Exit to Z System error handler */ char code, *defstring; { char *msgptr, *getmsg(); msgptr = getmsg(); *msgptr = code; /* set error byte */ *(msgptr+3) |= 14; /* set external, no ECP, no shell bits */ exit(); /* return and let CCP handle errors */ } main(argc,argv) char **argv; { char *getefcb(), *fn2as(); int i, fd, sects; unsigned filsiz; int lineno, lincnt; char txtbuf[TXTBUFSIZE]; /* sector buffer */ char c, *txtptr, *lastsec, *filnam, *temp; filnam = NULL; lineno = LINES_DEF; if (zenv()) { /* if Z system */ fn2a(getefcb(),invnam); /* get invokation name */ invnam[index(invnam,".")] = 0; /* want NAME only */ pwdmode(0); /* don't re-check FCB1 or 2 */ } else strcpy(invnam,"TAILZ"); /* default invocation name */ for (i = 1; i < argc; i++) /* parse command line */ { if (argv[i][0] == '-') { if (!(lineno = atoi(&argv[i][1]))) /* can't parse # */ if (zenv()) zerr(ecBADNUM); else goto abort; } else if (filnam) /* > 1 filespecs */ goto abort; else { /* test for illegal filetypes */ filnam = argv[i]; if ((index(filnam,".EXE") != -1) || (index(filnam,".COM") != -1) || (index(filnam,".OBJ") != -1) || (index(filnam,".BIN") != -1) || (index(filnam,".ZIP") != -1) || (index(filnam,".SYS") != -1) || (index(filnam,".LBR") != -1) || (index(filnam,".ARC") != -1) || (filnam[index(filnam,".")+2] == 'Z') || (filnam[index(filnam,".")+2] == 'Q')) { printf("\n %s: Can't process %s files.\n", invnam,filnam+index(filnam,".")); exit(); } if ((index(filnam,"*") != -1) || (index(filnam,"?") != -1)) { if (zenv()) zerr(ecAMBIG); else { printf("\n %s: Ambiguous file name.\n", invnam); exit(); } } } } if (argc < 2 || !filnam || lineno < 0 || (filnam[0] == '/' && filnam[1] == '/')) { abort: puts("\nTAILZ, Version 1.0 - display text file tail.\n"); puts(" Syntax:\n"); printf(" %s [dir:]ufn - display last 10 lines.\n", invnam); printf(" %s -n [dir:]ufn - display last n lines.\n", invnam); exit(); } fd = open(filnam,0); char *fcbptr; fcbptr = fcbaddr(fd); if ((fd == ERROR) || /* no file */ ((*(fcbptr+10) & 0x80) && /* SYS file and not wheel */ zenv() && !getwhl())) if (zenv()) if (errno() == 15) zerr(ecBADDIR); else zerr(ecNOFILE); else { printf("\n %s: Can't open %s.\n",invnam,filnam); exit(); } filsiz = cfsize(fd); /* find size of file in sectors */ seek(fd, (filsiz > NBSECTS) ? -NBSECTS : -filsiz, 2); /* seek to EOF */ if (!(sects = read(fd, txtbuf, NBSECTS))) exit(); /* empty file */ lastsec = txtbuf + ((sects-1) * SECSIZ); lastsec[SECSIZ] = '\0'; for (txtptr = lastsec; !lastchar(*txtptr); txtptr++) ; --txtptr; /* txtptr now points to last char of text */ lincnt = 0; while (1) { if (txtptr < txtbuf) { if (sects < NBSECTS) { txtptr++; break; } /* else TPA error */ if (zenv()) zerr(ecTPAFULL); else { printf("\n %s: Text buffer overflow.\n", invnam); exit(); } } if (*txtptr == '\n') lincnt++; if (lincnt == lineno+1) break; txtptr--; } txtptr++; /* skip initial \n */ while (!lastchar(c = *txtptr++)) if ((c != '\n') || (!lastchar(*(txtptr+1)))) /* skip last \n */ putchar(c); close(fd); }