/* Tail - Display the last lines of a file. Original effort by Fabio Rossetti. Inspired by the tail program by Gary Brant found on <>< 179. (c) 1989 by Fabio Rossetti To compile under Lattice C v5.0x use: lc -O -v -cus tail blink lib:cres.o tail.o to tail lib lib:a.lib lib:lc.lib sd nd */ #include #include #include #include #include #include #include #include #include struct ArpBase *ArpBase=NULL; struct Process *Pr; LONG argc; #define NARGS 4 #define BFSIZE 256 #define FROM argv[0] #define TO argv[1] #define LIN argv[2] #define BAN argv[3] STRPTR argv[NARGS]; #define MAXLIN 256 TEXT *Lin[256]; TEXT *Buf,*OBuf; TEXT Banner[256]; struct UserAnchor { struct AnchorPath ua_AP; BYTE moremem[255]; /* extension */ }; struct UserAnchor *Anchor=NULL; /* Trick to keep code down to size */ VOID MemCleanup() { } /* shutdown routine */ VOID Cleanup(r1,r2,msg) LONG r1,r2; STRPTR msg; { if (msg) Puts(msg); if (ArpBase) CloseLibrary((struct Library *)ArpBase); Pr->pr_Result2 = r2; exit(r1); } VOID Tail(Inp,Out,lines) BPTR Inp,Out; ULONG lines; { REGISTER TEXT *il = Lin[0]; REGISTER LONG count, obp=0,p=0,i,fl=0; /* enqueue the last lines read */ for(;;) { /* read until eof */ if (!obp) if (!(count = Read(Inp,Buf,BFSIZE))) { /* the last line */ if(fl) { *il = '\0'; p++;} break; } fl = 1; if (*(Buf + obp) == '\n') { fl = 0; ++obp; *il = '\0'; p++; il = Lin[p%lines]; if (SetSignal(0,0) & SIGBREAKF_CTRL_C) Cleanup(RETURN_WARN,NULL,"***Break"); } else { if (((TEXT *)il - (TEXT *)Lin[p%lines]) > MAXLIN) Cleanup(RETURN_FAIL,NULL,"Buffer overflow"); *il++ = *(Buf + obp++); } if (obp == count) obp = 0; } /* display queue */ if (p <= lines) for(i=0; i < p; i++) FPrintf(Out,"%s\n",Lin[i]); else { for(i=(p%lines); i < lines; i++) { if (SetSignal(0,0) & SIGBREAKF_CTRL_C) Cleanup(RETURN_WARN,NULL,"***Break"); FPrintf(Out,"%s\n",Lin[i]); } if ((lines != 1) && ((p%lines) != 0)) for(i=0; i <= (p%lines)-1 ; i++) { FPrintf(Out,"%s\n",Lin[i]); if (SetSignal(0,0) & SIGBREAKF_CTRL_C) Cleanup(RETURN_WARN,NULL,"***Break"); } } } VOID _main(Line) STRPTR Line; { BPTR infh,outfh; LONG Lines,Result,i=0,j; char **ArV; Pr = (struct Process*)FindTask(NULL); if(!(ArpBase = (struct ArpBase*)OpenLibrary(ArpName,ArpVersion))) Cleanup(RETURN_FAIL,ERROR_INVALID_RESIDENT_LIBRARY,NULL); /* parse command line */ for (argc=0;argc < NARGS ;++argc) argv[argc] = (STRPTR) NULL; while(*Line > ' ') ++Line; if((argc = GADS(++Line, strlen(Line), "Usage: Tail [Files file1 file2 ...] [TO filename] [LIN linenumber] [BAN]", argv, "Files/...,TO/K,LIN/K,BAN/S" )) < 0) Cleanup(RETURN_WARN,NULL,FROM); if (!(Buf = ArpAllocMem(BFSIZE,MEMF_CLEAR))) Cleanup(RETURN_FAIL,ERROR_NO_FREE_STORE,"Error: no memory"); if ( Anchor = (struct UserAnchor *)ArpAlloc( (ULONG)sizeof( *Anchor )) ) { Anchor->ua_AP.ap_Length = 255; /* Want full path built */ } else Cleanup(RETURN_FAIL,ERROR_NO_FREE_STORE,"Error:No memory"); if (LIN) { Lines = Atol(LIN); if((Errno == ERRBADINT) || (Lines <=0)) Cleanup(RETURN_ERROR,NULL,"Bad args"); if(Lines > 255) Cleanup(RETURN_WARN,NULL,"Too many lines"); } else Lines = 10; /* set up queue */ for (j = 0; j < Lines; j++) { if (!(Lin[j]=ArpAllocMem(MAXLIN,MEMF_CLEAR))) Cleanup(RETURN_ERROR,ERROR_NO_FREE_STORE,"Error: no memory!"); } if(TO) { if(!(outfh=ArpOpen(TO,MODE_NEWFILE))) { Printf("Can't open %s\n",TO); Cleanup(RETURN_ERROR,ERROR_OBJECT_NOT_FOUND,NULL); } } else outfh = Output(); ArV = (char **)FROM; if (ArV[0]) { if ( Anchor = (struct UserAnchor *)ArpAlloc( (ULONG)sizeof( *Anchor )) ) { Anchor->ua_AP.ap_Length = 255; /* Want full path built */ } else Cleanup(RETURN_FAIL,ERROR_NO_FREE_STORE,"Error: no memory"); while (ArV[i] != NULL) { Result = FindFirst(ArV[i],(struct AnchorPath*) Anchor); while (Result == 0) { if (Anchor->ua_AP.ap_Info.fib_DirEntryType < 0) { if(!(infh=ArpOpen(Anchor->ua_AP.ap_Buf,MODE_OLDFILE))) { Printf("Can't open %s\n",FROM); Cleanup(RETURN_ERROR,ERROR_OBJECT_NOT_FOUND,NULL); } else { if (BAN) { PathName(ArpLock(Anchor->ua_AP.ap_Buf, ACCESS_READ),Banner,255); FPrintf(outfh,"*** File %s ***\n", Banner); } Tail(infh,outfh,Lines); } } else { Printf("%s is a directory !\n",ArV[i]); Cleanup(RETURN_ERROR,ERROR_OBJECT_WRONG_TYPE,NULL); } Result = FindNext((struct AnchorPath*) Anchor ); } i++; } } else Tail(Input(),outfh,Lines); Cleanup(NULL,NULL,NULL); }