title like, do some lines, man ;++ ; ; Count the lines in files. ; ; By John Wilson. ; ; 01/10/88 JMBW Created. ; 02/17/95 JMBW Accepts wildcards as cmd line args, default=STDIN. ; Converted to .COM file for smaller size. ; ;-- .radix 8 ; lf= 12 cr= 15 ; code segment assume cs:code org 100h ;.COM file ; beg: jmp short beg1 db 10,10 ;(two backspaces) db 'LINES.COM, by John Wilson',cr,lf db 'Z'-100 ;EOF for TYPE beg1: cld ;DF=0 ; give back memory we don't need cmp sp,offset pdl ;make sure we have it in the first place jb beg3 mov sp,offset pdl ;shrink stack if so mov bx,mem ;size of memory to save in paragraphs mov ah,4Ah ;func=setblock int 21h jc beg3 ;punt on failure, can't reorganize memory ; allocate buffer mov bx,0FFFh ;size=64KB -1 par (REPNE can't reach all 64K) beg2: mov ah,48h ;func=getblock int 21h jnc beg4 ;got it, skip mov bx,ax ;copy amount DOS says it can give test bx,bx ;anything? jnz beg2 ;try again if so beg3: ; failed, punt mov dx,offset nomem ;pt at msg mov cx,21d ;length mov bx,0002h ;STDERR mov ah,40h ;func=write int 21h mov ax,4C01h ;func=punt int 21h beg4: ; got it, copy cmd line out of DTA mov ds:buf,ax ;save buf ptr mov cl,4 ;shift count sal bx,cl ;get # bytes in buf mov ds:buflen,bx ;save xor ah,ah ;ah=0 mov si,80h ;pt at JCL lodsb ;get length mov cx,ax ;copy mov di,offset jcl ;pt at cmd line buffer push di ;save ptr rep movsb ;copy it there pop si ;point at it mov cx,ax ;restore length prs1: ; parse out each word and look it up as a wildcard jcxz prs3 ;skip if nothing to do prs2: lodsb ;get a byte cmp al,' ' ;blank or ctrl char? ja prs6 ;no loop prs2 ;ignore if so prs3: ; end of command line mov di,offset lbuf ;pt at LBUF cmp ds:nfiles,1 ;gotten anything? jb prs5 ;no, read STDIN je prs4 ;exactly one thing, done ; more than one file, print total mov si,offset total ;pt at string mov cx,7 ;LEN('Total: ') rep movsb ;copy mov ax,ds:totlin ;get total # lines mov dx,ds:totlin+2 call prline ;finish off line prs4: int 20h prs5: ; no files given, read standard input mov si,offset stdin ;pt at string mov cx,9d ;LEN('(stdin): ') rep movsb ;copy call count ;count it up, print result int 20h prs6: ; beginning of a word mov di,offset lbuf ;point at LBUF mov dx,di ;copy ptr dec si ;back up prs7: lodsb ;get a char cmp al,' ' ;blank or ctrl char? jbe prs11 ;yes, end of word cmp al,'/' ;either kind of slash? je prs9 cmp al,'\' je prs8 cmp al,'a' ;lower case? jb prs10 cmp al,'z' ja prs10 sub al,40 ;convert to upper if so jmp short prs10 prs8: mov al,'/' ;normalize to forward slash prs9: lea dx,[di+1] ;point after it prs10: stosb ;save loop prs7 ;loop inc si ;correct for next prs11: dec si ;unget last char ; si,cx=cmd line descriptor, di points past end of filespec in LBUF ; dx points at beginning of filename in filespec in LBUF push si ;save push cx push dx ;save filename ptr xor al,al ;mark end stosb dec di ;back up in case of error mov dx,offset lbuf ;pt at begn xor cx,cx ;attrib=generic file mov ah,4Eh ;func=find first int 21h jc prs14 ;error, no matches prs12: pop di ;get ptr to filename in LBUF push di ;save again mov si,9Eh ;pt at filename in default DTA prs13: lodsb ;get a byte stosb ;save test al,al ;end? jnz prs13 ;loop if not dec di ;back up mov dx,offset lbuf ;pt at filename mov ax,3D00h ;func=open /RONLY int 21h ;open it jc prs15 mov ds:handle,ax ;save mov ax," :" ;': ' stosw call count ;count up this file mov bx,ds:handle ;get handle mov ah,3Eh ;func=close int 21h mov dx,80h ;point at default PSP (not in V2, MS geeks!!!) mov ah,4Fh ;func=find next int 21h jnc prs12 ;loop if got another pop di ;flush filename ptr once and for all pop cx ;restore cmd line ptr pop si jmp prs1 prs14: ; file not found mov si,offset fnf ;pt at msg mov cx,18d ;length jmp short prs16 prs15: ; open error mov si,offset opnerr ;pt at msg mov cx,19d ;length prs16: rep movsb ;copy msg mov dx,offset lbuf ;pt at buf mov cx,di ;calc length sub cx,dx mov bx,0002h ;STDERR mov ah,40h ;func=write int 21h mov ax,4C01h ;func=punt int 21h ;+ ; ; Count and display number of line feeds in a file. ; ; File handle is in CS:HANDLE. ; ; ds,es preserved ; es:di pointer into LBUF for decimal number ; ;- count: push di ;save push ds push es inc ds:nfiles ;count it mov ds:hiline,0 ;nuke high word of line count mov ax,ds:buf ;pt at buf mov ds,ax ;with ds mov es,ax ;and es xor si,si ;init low word of line count cnt1: ; read a bufferload xor dx,dx ;offset=0 mov cx,cs:buflen ;length mov bx,cs:handle ;file handle mov ah,3Fh ;func=read int 21h ;do it jc cnt3 ;err, treat as eof mov cx,ax ;copy count jcxz cnt3 ;eof, skip xor di,di ;start of buf mov al,lf ;line feed cnt2: repne scasb ;look for it jne cnt1 ;end of buf, load next inc si ;count it jnz cnt2 ;look again (OK if cx=0) inc cs:hiline ;bump high count jmp short cnt2 cnt3: ; display count pop es ;restore pop ds pop di mov ax,si ;copy mov dx,ds:hiline add ds:totlin,ax ;add to total adc ds:totlin+2,dx ;jmp short prline ;print line, return ;+ ; ; Add a number to LBUF and print the whole line. ; ; dx:ax number ; es:di ptr to end of line in LBUF ; ;- prline: call prdec ;print # in decimal mov ax,cr+(lf*400) ;crlf stosw mov dx,offset lbuf ;pt at buf mov cx,di ;calc length sub cx,dx mov bx,0001h ;STDOUT mov ah,40h ;func=write int 21h ret ;+ ; ; Print decimal # in dx:ax. ; ; es:di buffer (updated on return) ; ;- prdec: mov bx,10d ;divisor prdec1: xor cx,cx ;assume high order result=0 (no overflow) cmp dx,bx ;number .lt. divisor*65536? jb prdec2 ;yes, a single DIV will do it ; result won't fit in 16 bits (quo.lt.65536, rem.lt.bx) ; do the division in two steps so as to get correct low order mov cx,ax ;save low order mov ax,dx ;copy high order xor dx,dx ;0-extend div bx ;do first 16-bit "digit" of long division xchg ax,cx ;save high "digit" of result, get low order prdec2: div bx ;(dx is remainder "carried" from first div) ; cx:ax=quotient, dx=remainder push dx ;save remainder mov dx,cx ;copy or cx,ax ;should we recurse? jz prdec3 call prdec1 ;yes prdec3: pop ax ;restore remainder or al,'0' ;convert to decimal stosb ;save ret ; nomem db 'Insufficient memory',cr,lf total db 'Total: ' stdin db '(stdin): ' fnf db ': File not found',cr,lf opnerr db ': File open error',cr,lf ; totlin dw 0,0 ;total # lines nfiles dw 0 ;# files processed so far ; handle dw 0000h ;file handle (STDIN unless changed) ; lines dw 2 dup(?) ;# lines in current file ; buf dw 1 dup(?) ;seg addr of file buffer buflen dw 1 dup(?) ;length in bytes of file buffer ; hiline dw 1 dup(?) ;high word of # lines in current file ; jcl db 127d dup(?) ;copy of JCL (moved out of DTA for FINDNEXT) ; lbuf db 132d+2 dup(?) ;output line buffer ; dw 100h dup(?) ;stack pdl label word ; mem= ((($+0Fh)-beg)/10h)+10h ;# paragraphs to save, including 10h for PSP ; code ends ; end beg