| | .MODEL | SMALL | |
| INCLUDE | PCMAC.INC | | |
| | ASSUME | SS:NOTHING | |
| ; | | | |
| | .STACK | 100 | |
| ; | | | ; Constants |
| BUFLEN | EQU | 512 | ; Must be a power of 2 |
| CR | EQU | 13 | |
| LF | EQU | 10 | |
| WANTED | EQU | 20 | ; Number of lines of tail desired |
| CtrlZ | EQU | 26 | ; Sometimes used to end text files |
| ; | | | |
| | .DATA | | |
| Buffer | DB | BUFLEN DUP (?) | |
| Handle | DW | ? | ; The file handle |
| LCount | DW | ? | ; Number of Line Feeds encountered |
| Start | DD | ? | ; loc of buf srart in file; least sig first |
| UsageMsg | DB | 'usage: tail filename',CR,LF,'$' | |
| ; | | | |
| | .CODE | | |
| | EXTRN | ParseCmd : NEAR, CseCmd : NEAR, CCheck : NEAR | |
| Tail | PROC | | |
| | mov | ax, @data | |
| | mov | ds, ax | |
| | call | ParseCmd | ; Get filename from command line |
| | test | si, si | |
| | jnz | DoOpen | |
| | _PutStr | UsageMsg | |
| | _Exit | 2 | |
| DoOpen: | | | |
| | push | ds | |
| | _Open | si, Read, es | |
| | pop | ds | |
| | call | CCheck | |
| | mov | Handle, ax | |
| | mov | LCount, Wanted + 1 | ; Initialize line count |
| | _LSeek | Handle, FromEnd, 0 | ; Find length of file |
| | call | CCheck | |
| | add | ax, BufLEN - 1 | ; Round end of file to next |
| | | | ; even multiple |
| | adc | dx, 0; | ; of BUFLEN (NOTE |
| | and | ax, NOT (BUFLEN - 1) | ; MULTIPLE PRECISION |
| | mov | WORD PTR [Start], ax | ; BUFLEN must be a pwr |
| | mov | WORD PTR [Start + 2], dx | ; of 2 FOR THE 'AND' |
| | | | ; TO WORK |
| | mov | ax, ds | |
| | mov | es, ax | |
| | pushf | | |
| | std | | |
| ReadNextRecord: | | | |
| | sub | WORD PTR [Start], | BUFLEN |
| | sbb | WORD PTR [Start + 2], 0 | |
| | jge | DoRead | |
| | mov | WORD PTR [Start], 0 | ; If < 0, we're at start |
| | mov | WORD PTR [Start + 2], 0; | |
| | jmp | Done | |
| DoRead: | | | |
| | _LSeek | Handle, FromStart, <WORD PTR Start>, <WORD PTR Start+2> | |
| | call | CCheck | |
| | _Read | Handle, buffer, BUFLEN | |
| | call | CCheck | |
| | mov | cx, ax | ; save number of characters read |
| | jcxz | ReadNextRecord | ; shouldn't happen |
| | mov | di, OFFSET Buffer -1 | ; Set up ptr to end of buffer |
| | add | di, cx | |
| | mov | al, LF | Character to search for |
| LineLoop: | | | |
| | repne | scasb | ; stop on LF or start of buffer |
| | jne | ReadNextRecord | ; LF not found |
| | dec | LCount | |
| | jnz | LineLoop | |
| | sub | di, OFFSET Buffer - 2 | ; di already one past LF |
| | add | WORD PTR [Start], di | ; update to start of tail |
| | adc | WORD PTR [Start + 2], 0 | |
| Done: | | | |
| | _Lseek | Handle, FromSTart, <WORD PTR Start>, <WORD PTR Start + 2> + 2> | |
| | call | CCheck | |
| | cld | | ; Reset direction up |
| OutputLoop: | | | |
| | _Read | Handle, buffer, BUFLEN | |
| | call | CCheck | |
| | mov | cx, ax; | ; number of bytes read => cx |
| | jcxz | EOF | |
| | mov | si, OFFSET Buffer | |
| DisplayLoop: | | | |
| | lodsb | | |
| | cmp | al, CtrlZ | ; Sometimes text file terminator |
| | je | EOF | |
| | _PutCh | al | |
| | loop | DisplayLoop | |
| | jmp | OutputLoop | |
| EOF: | | | |
|
| | popf | | |
| | _Exit | 0 | ; normal termination |
| Tail | ENDP | | |
| | END | Tail | |
| | | | |