;++ ; ; Select specific pages of a text file for printing (or whatever). ; ; By John Wilson. ; ; 11/16/95 JMBW Created. ; ;-- .radix 8 locals ; bufsiz= 32768d/10h ;I/O buffer size in paragraphs ; nrange= 20d ;# pages or ranges of pages specifiable with /PAGES ; bs= 10 tab= 11 lf= 12 ff= 14 cr= 15 ; kw macro text,addr kh= 0 ki= 0 irpc kc,&text ki= ki+1 ifidn <&kc>,<-> kh= ki endif endm ;; irpc ife kh .err No hyphen in string: &text exitm endif ;; ife kh db kh-1,ki-1 ;;len to match, total len irpc kc,&text ;;keyword text ifdif <&kc>,<-> db '&kc' endif endm ;; irpc dw &addr endm ; callr macro dest ;;call and return jmp &dest endm ; code segment assume cs:code org 100h start: cld ;always move forwards ; make sure we have enough memory to run cmp sp,offset pdl ;enough? jb nomem ;no mov sp,offset pdl ;shrink stack mov bx,((pdl-start)/10h)+10h ;# paragraphs to keep mov ah,4Ah ;func=setblock int 21h ; get character for parsing switches mov ax,3700h ;func=get SWITCHAR int 21h ;into dl mov ds:swchar,dl ;save ; scan command line mov si,80h ;point at command line lodsb ;get length cbw ;ah=0 mov cx,ax ;copy @@1: ; get next word or switch call skip ;skip blanks, tabs jc go ;that's all cmp al,ds:swchar ;switch? je @@3 ;yes ; it's a filename call getw ;get it cmp byte ptr ds:inmlen,0 ;do we have an input name already? jnz @@2 ;yes mov ds:inmlen,dl ;this is it, save mov ds:iname,bx jmp short @@1 @@2: cmp byte ptr ds:onmlen,0 ;how about an output name? jnz @@4 ;yes, so what the hell is this? mov ds:onmlen,dl ;save output filename mov ds:oname,bx jmp short @@1 @@3: ; switch inc si ;skip the '/' dec cx call getw ;get the switch name jc @@4 ;none mov ax,offset swtchs ;point at switch table call tbluk ;look up jc @@4 call ax ;process it jmp short @@1 @@4: ; syntax error, print usage blurb mov di,offset usage ;pt at string mov cx,lusage ;length push cx ;save push di mov al,'~' ;char to replace with SWITCHAR mov ah,ds:swchar ;SWITCHAR @@5: repne scasb ;find it? jne @@6 ;no mov byte ptr [di-1],ah ;replace jmp short @@5 ;look more @@6: pop dx ;restore ptr, len pop cx jmp short errmsg nomem: ; insufficient memory mov dx,offset nomem1 ;pt at msg mov cx,lnmem1 errmsg: ; print err msg, dx=ptr, cx=length push cs ;guarantee ds=cs pop ds mov bx,0002h ;handle=STDERR mov ah,40h ;func=write int 21h mov ax,4C01h ;func=punt int 21h synerr: mov dx,offset syerr1 ;pt at msg mov cx,lsyer1 jmp short errmsg ;+ ; ; Begin processing. ; ; Open files, allocate buffers, find our first page. ; ;- go: ; open input file xor ch,ch ;ch=0 mov cl,ds:inmlen ;get length of input filename jcxz @@1 ;none (and no output file), leave STDIN/OUT mov si,ds:iname ;get input filename mov di,offset fnbuf ;pt at buf (es still =ds from entry) mov dx,di ;save ptr rep movsb ;copy mov [di],cl ;mark end mov ax,3D00h ;func=open /RONLY int 21h jc @@5 mov ds:inhnd,ax ;save handle mov ds:outhnd,0004h ;input file exists, default output=PRN mov cl,ds:onmlen ;get length of output filename jcxz @@1 ;none, leave STDPRN mov si,ds:oname ;get output filename mov di,offset fnbuf ;pt at buf mov dx,di ;save ptr rep movsb ;copy mov [di],cl ;mark end mov ah,3Ch ;func=create (cx=0 from REP MOVSB) int 21h jc @@6 mov ds:outhnd,ax ;save handle @@1: ; allocate I/O buffers mov bx,bufsiz ;ask for input buf @@2: mov ah,48h ;func=getblock int 21h jnc @@3 ;got it test bx,bx ;anything left? jnz @@2 jmp short nomem ;no @@3: mov ds:inbuf,ax ;save ptr mov cl,4 ;shift count sal bx,cl ;get # bytes mov ds:insiz,bx ;save mov bx,bufsiz ;ask for output buf @@4: mov ah,48h ;func=getblock int 21h jnc @@7 ;got it test bx,bx ;anything left? jnz @@4 jmp nomem ;no @@5: mov dx,offset operr1 ;pt at msg mov cx,loper1 jmp errmsg @@6: mov dx,offset crerr1 ;pt at msg mov cx,lcrer1 jmp errmsg @@7: mov ds:outbuf,ax ;save ptr mov cl,4 ;shift count sal bx,cl ;get # bytes mov ds:outsiz,bx ;save mov ds:outctr,bx ;that many bytes free xor cx,cx ;nothing in buf now test byte ptr ds:rvrsf,-1 ;going backwards? jnz bwards ;yes ;jmp short fwards ;+ ; ; Going through file forwards. ; ;- fwards: inc cs:pgno ;page # +1 call check ;check page # jc @@1 ;don't print it call prpage ;print the page jnc fwards ;loop ; page approved but is off eof, print a blank page if /BACKS and even test byte ptr cs:backf,-1 ;doing /BACKS? jz @@2 test byte ptr cs:pgno,1 ;yes, even page? jnz @@2 call form ;yes, do a form feed jmp short @@2 @@1: call skpage ;skip the page jnc fwards @@2: jmp done ;+ ; ; Going through file backwards. ; ; First go through it forwards and record where each page begins, so we can ; go backwards w/o having to back up to the previous form feed for each page ; just to keep our registration correct. ; ;- bwards: ; build a table of starting locs of all pages in the file mov bx,-1 ;see how much core is available @@1: mov ah,48h ;func=getblock int 21h jnc @@2 ;success test bx,bx ;anything left? jnz @@1 ;yes jmp nomem ;no @@2: ; init page table ptrs mov cs:pagtab,ax ;save addr mov cs:pagptr,0 ;init ptr mov cs:pagptr+2,ax mov cs:pagtsz,bx ;and size add bx,ax ;get ending addr mov cs:pagmax,bx ;point at it xor dx,dx ;initial col=0 xor si,si ;initial offset=0 @@3: ; see if we have space to store starting col and posn inc cs:pgno ;bump page # mov ax,cs:pagptr ;get pointer mov bx,cs:pagptr+2 mov di,ax ;point at it mov es,bx add al,6 ;+6 (3 words per page) cmp al,10h ;off end of paragraph? jb @@4 and al,0Fh ;yes inc bx @@4: cmp bx,cs:pagmax ;out of space? jb @@6 ;no ja @@5 ;yes test ax,ax ;maybe, OK if we hit it exactly jz @@6 @@5: ; too many pages mov dx,offset tmpag2 ;pt at msg mov cx,ltmpg2 jmp errmsg @@6: ; we're OK, save file addr (dword) and starting column (word) mov cs:pagptr,ax ;update mov cs:pagptr+2,bx push dx ;save starting column call getptr ;get current pointer stosw ;save LSW mov ax,dx ;MSW stosw pop dx ;restore col mov ax,dx ;copy it stosw call skpage ;skip the page jnc @@3 ;loop if not EOF ; delete starting addr of eof sub cs:pagptr,6 ;un-save last loc jnc @@7 add cs:pagptr,10h ;keep ptr normalized dec cs:pagptr+2 @@7: ; we're at end, find average length of page and figure out how much ; we should overshoot when asked to SEEK, so if we're lucky we'll ; get more than one page per bufferload mov ax,cs:pos ;get position of EOF mov dx,cs:pos+2 mov bx,cs:pgno ;get # pages dec bx ;was too high by 1 cmp dx,bx ;will DIV overflow? (>=64KB/page) jae @@8 ;yes, leave it at 0 div bx ;ax=average length of page add ax,ax ;allow for twice the average jc @@8 ;that overflowed, leave at 0 mov cx,cs:insiz ;size of input buffer sub cx,ax ;bite off 2x average page jc @@8 ;forget it, leave at 0 mov cs:sekoff,cx ;if anything left, overshoot by that much @@8: ; start with blank page if /BACKS test byte ptr cs:backf,-1 ;doing /BACKS? jz @@9 test byte ptr cs:pgno,1 ;yes, even page? jnz @@9 call check ;yes, not limited by /PAGES? jc @@9 call form ;yes, do a form feed @@9: ; go through pages backwards, checking each dec cs:pgno ;back up to prev page jz done ;0, nothing left sub cs:pagptr,6 ;back up ptr jnc @@10 add cs:pagptr,10h ;whoops dec cs:pagptr+2 @@10: call check ;should we print the page? jc @@9 ;no les di,dword ptr cs:pagptr ;yes, point at page entry mov ax,es:[di] ;get posn mov dx,es:[di+2] call seek ;fetch a buffer mov dx,es:[di+4] ;get starting col call prpage ;print the page jmp short @@9 ;+ ; ; Finished printing, flush output buf and exit. ; ;- done: les di,dword ptr cs:outptr ;load up ptr call flush ;flush output buf mov bx,cs:inhnd ;close input file mov ah,3Eh ;func=close int 21h ;;; first see if output is to a file mov bx,cs:outhnd ;close output file mov ah,3Eh ;func=close int 21h int 20h ;+ ; ; Check to see whether we should print page # CS:PGNO. ; Return CF=0 if so, CF=1 if not. ; ; si,cx preserved ; ;- check: mov ax,cs:pgno ;get page # test byte ptr cs:frntf,-1 ;should we print fronts? jz @@1 ;no test byte ptr cs:backf,-1 ;did they specify both? jnz @@2 ;yes, doesn't rule out much test al,1 ;is page number odd? (CF=0) jz @@5 ;no, don't print ret @@1: test byte ptr cs:backf,-1 ;did they specify neither? jz @@2 ;yes, so anything goes test al,1 ;is page number even? (CF=0) jnz @@5 ;no, don't print ret @@2: ; no /FRONTS or /BACKS (or both), check /PAGES list mov dx,cs:rngctr ;get counter of # ranges test dx,dx ;any? jz @@6 ;no, take everything mov bx,offset rnglst ;pt at list @@3: cmp ax,cs:[bx] ;in range? jb @@4 cmp ax,cs:[bx+2] jbe @@6 ;yes @@4: add bx,4 ;no, advance to next dec dx ;done all? jnz @@3 ;no @@5: stc ;don't print ret @@6: clc ;take it ret ; swtchs label byte kw ,backs ;print only backs of pages kw ,backs ;syn. for backs kw ,fronts ;print only fronts of pages ; kw ,lines ;set # printable lines/page kw ,margin ;set left margin kw ,fronts ;print only odd pages kw ,pages ;print only a range of pages kw ,revers ;print pages in reverse order kw ,wrap ;wrap lines that go past right margin db 0 ;+ ; ; /BACKS ; ; Print only even-numbered pages (backs of two-sided sheets). ; ;- backs: mov byte ptr ds:backf,1 ;set flag ret ;+ ; ; /FRONTS ; ; Print only odd-numbered pages (fronts of two-sided sheets). ; ;- fronts: mov byte ptr ds:frntf,1 ;set flag ret ;+ ; ; /MARGIN:a[,b] ; ; Specify # of blanks to add at left margin. If only "a" is specified, it is ; used for all pages; if "a,b" are both specified then "a" is used for ; odd-numbered pages (fronts of two-sided sheets) and "b" is used for ; even-numbered pages (backs of two-sided sheets). ; ;- margin: jcxz @@2 ;nothing left, invalid lodsb ;eat a char dec cx cmp al,':' ;must be colon jne @@2 ; get first number call getdec ;get a number jc @@2 ;failed mov ds:nblank,ax ;save mov ds:nblank+2,ax ;in both slots jcxz @@1 ;nothing left cmp byte ptr [si],',' ;comma? jne @@1 inc si ;yes, eat it dec cx call getdec ;get second number jc @@2 ;failed mov ds:nblank,ax ;replace # for even pages (backs) @@1: ret @@2: jmp synerr ;+ ; ; /PAGES:range1[,range2[,range3 ...]] ; ; Specify ranges of pages to be printed. A range is either a single page ; number, or two page numbers separated by a hyphen (-). Both this switch and ; the /FRONTS and /BACKS are used to decide whether a given page is printed, so ; for example if "/FRONTS/PAGES:1-5" is specified then pages 1, 3, and 5 are ; printed. ; ;- pages: sub cx,1 ;get colon jc @@3 ;none lodsb cmp al,':' ;colon, right? jne @@3 ;error if not @@1: ; get next element of range call getdec ;get a number jc @@3 ;none, skip mov bx,ax ;copy twice in case not range (start=end) jcxz @@2 ;just a number, skip cmp byte ptr [si],'-' ;hyphen? jne @@2 ;no, just a number inc si ;yes, eat it dec cx push ax ;save start of range call getdec ;get end of range pop bx ;[catch] jc @@3 ;failed cmp ax,bx ;in order? jb @@2 xchg ax,bx ;get them in order @@2: ; ax=begn of range, bx=end, save them mov di,ds:rngctr ;get ptr cmp di,nrange ;already maxed out? je @@4 ;yes add di,di ;*2 add di,di ;*4 mov ds:rnglst[di],ax ;save mov ds:rnglst+2[di],bx inc ds:rngctr ;bump ctr jcxz @@5 ;end of list cmp byte ptr [si],',' ;comma? jne @@5 inc si ;yes, eat it dec cx jmp short @@1 ;around for more @@3: jmp synerr ;syntax error @@4: mov dx,offset tmpag1 ;pt at msg mov cx,ltmpg1 jmp errmsg @@5: ret ;+ ; ; /REVERSE ; ; Print pages in reverse order. Useful for printing double-sided sheets in two ; passes, or for single-sided output on printers that stack backwards. This ; can get confusing... ; ;- revers: mov byte ptr ds:rvrsf,1 ;set flag ret ;+ ; ; /WRAP ; ; Wrap text that overflows right margin. ; ;- wrap: mov byte ptr ds:wrapf,1 ;set flag ret ; subttl page I/O routines ;+ ; ; Skip a page of text. ; ; ds:si input ptr \ updated ; cx # bytes left / on return ; dx col # at begn of page (updated for next page on return) ; ; Returns CF=1 if EOF (nothing read at all). ; ;- skpage: mov di,cs:pglen ;get height test cx,cx ;got anything? jnz @@1 call read ;no, refill buf jcxz @@5 ;eof right off the bat @@1: ; handle next char lodsb ;get a char cmp al,40 ;control char? jb @@7 ;yes @@2: inc dx ;+1 column @@3: cmp dx,cs:pgwid ;off right marg? jae @@6 ;yes @@4: loop @@1 ;loop around for more call read ;get more jcxz @@12 ;eof jmp short @@1 ;loop around for more @@5: stc ;eof before reading anything ret @@6: ; off right marg test byte ptr cs:wrapf,-1 ;do we care about wrapping? jz @@4 ;no xor dx,dx ;back to left marg jmp short @@10 ;pretend it was LF @@7: ; control char cmp al,bs ;backspace? je @@8 cmp al,tab ;tab? je @@9 cmp al,lf ;lf? je @@10 cmp al,ff ;ff? je @@11 cmp al,cr ;cr? je @@13 inc dx ;anything else is just "^x" jmp short @@2 ;go add the other col @@8: ; backspace sub dx,1 ;left a col jnc @@4 inc dx ;stop at left marg jmp short @@4 @@9: ; tab add dx,8d ;ahead 8 cols and dl,not 7 ;back to stop jmp short @@3 @@10: ; line feed dec di ;count off a line jnz @@4 ;loop if not done @@11: ; form feed dec cx ;count it @@12: clc ;happy return ret @@13: ; carriage return xor dx,dx ;back to left marg jmp short @@4 ;+ ; ; Print a page. ; ; ds:si input ptr \ updated ; cx # bytes left / on return ; dx col # at begn of page (updated for next page on return) ; ; Returns CF=1 if EOF (nothing read at all). ; ;- prpage: les di,dword ptr cs:outptr ;get pointer mov bp,cs:outctr ;get # bytes free test dx,dx ;starting at left marg? jz @@1 mov bx,dx ;no, copy call blanks ;write enough blanks to get us there @@1: mov bx,cs:pgno ;get page # and bx,1 ;isolate even/odd bit add bx,bx ;*2 mov bx,cs:nblank[bx] ;look up # blanks to add at left marg mov cs:padcnt,bx ;save (leave bx set up) mov ax,cs:pglen ;get height mov cs:lctr,ax ;init ctr test cx,cx ;got anything? jnz @@2 call read ;no, refill buf jcxz @@8 ;eof right off the bat @@2: ; handle next char lodsb ;get a char cmp al,40 ;control char? jb @@12 ;yes ; printing char, pad now if needed test bx,bx ;already done? jnz @@7 ;no @@3: inc dx ;+1 column @@4: cmp dx,cs:pgwid ;off right marg? jae @@10 ;yes @@5: ; save a char stosb ;save dec bp ;count it jz @@9 @@6: loop @@2 ;loop around for more call read ;get more test cx,cx ;get anything? jnz @@2 ;yes jmp @@23 ;eof, print form feed @@7: ; add padding push ax ;save call blanks ;write blanks, leaving bx=0 when done pop ax ;restore jmp short @@3 @@8: stc ;eof before reading anything ret @@9: call flush ;flush output buf jmp short @@6 ;continue @@10: ; off right marg test byte ptr cs:wrapf,-1 ;do we care about wrapping? jz @@5 ;no @@11: dec si ;unget mov al,cr ;write cr call outchr xor dx,dx ;back to col 0 mov bx,cs:padcnt ;reinit pad count mov al,lf ;write lf call outchr dec cs:lctr ;count off a line jnz @@2 ;re-get char if not done jmp @@23 ;done, print form feed @@12: ; control char cmp al,bs ;backspace? je @@15 cmp al,tab ;tab? je @@18 cmp al,lf ;lf? je @@21 cmp al,ff ;ff? je @@22 cmp al,cr ;cr? je @@16 test byte ptr cs:wrapf,-1 ;do we care if it wraps? jz @@13 ;no push bx ;save mov bx,dx ;copy inc bx ;+2 inc bx cmp bx,cs:pgwid ;off right marg? pop bx ;[restore] jae @@11 ;yes, wrap and re-do char @@13: push ax ;save ; add padding if needed test bx,bx ;any padding queued? jz @@14 call blanks ;write the blanks, leaving bx=0 @@14: mov al,'^' ;write a '^' call outchr inc dx ;count it pop ax ;restore xor al,100 ;change to letter jmp @@3 ;go add the other col @@15: ; backspace sub dx,1 ;left a col jnc @@17 inc dx ;stop at left marg jmp @@6 @@16: jmp short @@25 @@17: jmp @@5 @@18: ; tab mov ax,dx ;save old value add dx,8d ;ahead 8 cols and dl,not 7 ;back to stop test byte ptr cs:wrapf,-1 ;do we care if it wraps? jz @@19 ;no cmp dx,cs:pgwid ;off right marg? jae @@20 ;yes @@19: push bx ;save mov bx,dx ;copy new posn sub bx,ax ;subtract old posn call blanks ;write that many blanks pop bx ;restore jmp @@6 @@20: mov al,cr ;leave out the tab, just crlf call outchr xor dx,dx mov bx,cs:padcnt ;reinit pad count mov al,lf ;print LF @@21: ; line feed dec cs:lctr ;count off a line jnz @@17 ;loop if not done @@22: ; form feed dec cx ;count it @@23: test dx,dx ;at BOL? jz @@24 mov al,cr ;no, write a CR call outchr @@24: mov al,ff ;write an FF call outchr mov cs:outptr,di ;update mov cs:outctr,bp clc ;happy return ret @@25: ; carriage return xor dx,dx ;back to left marg mov bx,cs:padcnt ;reinit pad count jmp @@5 ; blanks: ; write bx blanks (es:di set up), bx=0 on return mov al,' ' ;blank @@1: stosb ;write one dec bp ;buf full? jz @@2 ;yes dec bx ;count it jnz @@1 ret @@2: call flush ;flush the buf dec bx ;count the last blank jnz blanks ;reload AL and continue unless done ret ; form: ; write a form feed les di,dword ptr cs:outptr ;get pointer mov bp,cs:outctr ;get # bytes free mov al,ff ;get form feed call outchr ;write it mov cs:outptr,di ;update mov cs:outctr,bp ret ; outchr: ; write a char stosb ;write it dec bp ;buf full? jz $+3 ret ;callr flush ;flush output buf ;+ ; ; Flush output buffer. ; ; es:di pointer into buffer ; ; bx,cx,dx,si,bp,ds preserved ; ;- flush: push bx ;save push cx push dx push ds push es ;copy es to ds pop ds xor dx,dx ;offset=0 mov cx,di ;length jcxz @@1 mov bx,cs:outhnd ;handle mov ah,40h ;func=write int 21h jc wrerr @@1: pop ds ;restore pop dx pop cx pop bx xor di,di ;point at begn mov bp,ds:outsiz ;reinit ctr ret wrerr: mov dx,offset wrerr1 ;pt at msg mov cx,lwrer1 jmp errmsg ; subttl file I/O routines ;+ ; ; Get input file pointer. ; ; ds:si current offset into buffer ; dx:ax returns 32-bit file offset, suitable for SEEK ; ;- getptr: mov ax,cs:pos ;get posn of base of buffer mov dx,cs:pos+2 add ax,si ;add in offset adc dx,0 ret ;+ ; ; Seek input file to a specified position and load a buffer. ; ; We try to be sneaky about seeks when we're reading the file backwards, since ; we don't want to have to fill the whole buffer for each new page and then ; waste most of it. So, during the forward scan of the file, we calculated the ; average number of bytes per page. Then we really seek to a location such ; that the desired address is at the end of the buffer, minus 2x the average ; page length. That way the vast majority of pages will still lie entirely ; within the buffer we really load, plus if the pages aren't too big we will ; have the previous several pages already in the buffer for future searches. ; ; On entry: ; dx:ax posn to go to ; ; On return: ; ds:si buffer ptr ; cx # bytes left ; es,di preserved ; ;- seek: mov bx,ax ;copy mov cx,dx sub bx,cs:pos ;subtract base of curr buf sbb cx,cs:pos+2 jnz @@1 ;>64KB away, or negative mov cx,cs:inlen ;get end of buf sub cx,bx ;find # to go after this one jbe @@1 ;none, need new buffer mov si,bx ;yes mov ds,cs:inbuf ;make sure we're pointing at buf ret @@1: ; don't already have it, be sneaky if going backwards test byte ptr cs:rvrsf,-1 ;going backwards? jz @@3 ;no, just do what they ask push ax ;save push dx sub ax,cs:sekoff ;overshoot as much as is safe sbb dx,0 jnc @@2 xor ax,ax ;whoops, stop at 0000:0000 xor dx,dx @@2: call @@3 ;seek to that address pop dx ;restore the addr we really want pop ax jmp short seek ;will be within buf this time @@3: ; decided on real address to use mov cx,dx ;rearrange regs mov dx,ax mov bx,cs:inhnd ;handle mov ax,4200h ;func=seek from BOF int 21h jc rderr ;read error mov cs:nxtpos,ax ;save mov cs:nxtpos+2,dx ;callr read ;read buf, return ;+ ; ; Load input buffer. ; ; On return: ; ; ds:si pointer to buffer ; cx # bytes at ds:si, 0 if EOF ; bx,dx,di,bp,es preserved ; ;- read: push bx ;save push dx push di push cs ;copy cs to ds pop ds mov ax,ds:nxtpos ;get next position mov dx,ds:nxtpos+2 mov ds:pos,ax ;it's current now mov ds:pos+2,dx xor dx,dx ;offset=0 mov cx,ds:insiz ;size of buffer mov bx,ds:inhnd ;handle mov ah,3Fh ;func=read mov ds,ds:inbuf ;seg addr int 21h jc rderr mov si,dx ;point at it mov cx,ax ;copy length mov cs:inlen,ax ;save length add cs:nxtpos,ax ;update posn for next time adc cs:nxtpos+2,0 pop di ;restore pop dx pop bx ret rderr: mov dx,offset rderr1 ;pt at msg mov cx,lrder1 jmp errmsg ; subttl parsing routines ;+ ; ; Parse a decimal #. ; ; Returns: ; ax number ; si,cx updated (si pts at first non-digit) ; CF=1 if there was no number (ax=0) ; ;- getdec: xor bx,bx ;init mov di,10d ;multiplier call skip ;skip white space jc @@3 ;nothing there, done push si ;save @@1: lodsb ;get a char sub al,'0' ;convert cmp al,9d ;digit? ja @@2 ;no cbw ;ah=0 xchg ax,bx ;save, get old # mul di ;*10 test dx,dx ;overflow? jnz outran add bx,ax ;add in new digit jc outran loop @@1 ;loop inc si ;compensate for below @@2: dec si ;unget pop di ;catch starting posn cmp di,si ;see if we moved (di',cr,lf db 'page [infile [outfile]] ~switches',cr,lf db ' ~FRONTS (syn. ~ODD)',cr,lf db ' ~BACKS (syn. ~EVEN)',cr,lf db ' ~MARGIN:fronts[,backs]',cr,lf db ' ~PAGES:a-b,c,d-e',cr,lf db ' ~REVERSE',cr,lf db ' ~WRAP',cr,lf lusage= $-usage ; inmlen db 0 ;length of input filename or 0 if none onmlen db 0 ;length of output filename or 0 if none ; inhnd dw 0000h ;input file handle, default=STDIN outhnd dw 0001h ;output file handle, default=STDOUT ; pos dw 0,0 ;location of base of input buffer nxtpos dw 0,0 ;position of begn of next READ pgno dw 0 ;current page number sekoff dw 0 ;amount to over-seek when going backwards ; rvrsf db 0 ;NZ => print pages in reverse frntf db 0 ;NZ => print fronts of pages backf db 0 ;NZ => print backs of pages wrapf db 0 ;NZ => wrap long lines pgwid dw 80d ;# cols per page pglen dw 60d ;# printable lines per page nblank dw 0,0 ;# blanks to add at left of even, odd pages ; outptr dw 0 ;ptr into output buf outbuf dw 1 dup(?) ;seg addr of output buf (MUST FOLLOW OUTPTR) outctr dw 1 dup(?) ;# bytes free in OUTBUF ; rngctr dw 0 ;# entries in RNGLST ; subttl pure storage ; swchar db 1 dup(?) ;SWITCHAR iname dw 1 dup(?) ;ptr to input filename in cmd line oname dw 1 dup(?) ;ptr to output filename in cmd line inbuf dw 1 dup(?) ;seg addr of input buf insiz dw 1 dup(?) ;size in bytes of INBUF outsiz dw 1 dup(?) ;size in bytes of OUTBUF ; fnbuf label byte ;filename buf, overlays RNGLST rnglst dw 2*nrange dup(?) ;start, end page # for each range if ($-fnbuf) lt 80h ;must be big enough for cmd line +0 db (80h-($-fnbuf)) dup(?) endif ; pagtab dw 1 dup(?) ;page table base (seg addr) pagptr dw 2 dup(?) ;current addr in page table pagtsz dw 1 dup(?) ;page table size (in paragraphs) pagmax dw 1 dup(?) ;seg addr following end of table ; inlen dw 1 dup(?) ;# bytes currently in INBUF ; lctr dw 1 dup(?) ;line counter in PRPAGE padcnt dw 1 dup(?) ;# blanks to add in PRPAGE ; dw 100h dup(?) ;stack goes here if (($-start) and 0Fh) db (10h-(($-start) and 0Fh)) dup(?) endif pdl label word ;SP code ends end start