;Copyright (C) 1999 Dmitry Bakhvalov ; ;$Id: wc.asm,v 1.4 2001/08/28 06:31:55 konst Exp $ ; ;hackers' wc ; ;This version is 95% GNU compatable :) ;It doesnt support --long options, doesnt have --version and --help. ;It doesnt print total field when multiply files are given in the command ;line. ; ;0.01: 20-Feb-2000 initial release ;0.02: 23-Aug-2000 reading from stdin fixed (TH) ;0.03: 25-Aug-2001 option without argument fixed (JH) ; ;syntax: wc [option] [file, file, file...] ; ; If no file is given stdin is used. ; Options are: ; -l : print only the number of lines ; -w : print only the number of words ; -c : print only the number of bytes ; Options are cummulative. ; If no options are given - print the number of lines, ; words and bytes. ; ; returns -1 on error, 0 on success ; ; If someone really feels like he needs more of the original GNU wc's ; options - just ask me or better yet add 'em yourself :) ; ; Send me any feedback,suggestions,additional code, etc. %include "system.inc" CODESEG START: pop eax ; get argc dec eax jnz has_arguments pop ebx jmp use_stdin has_arguments: pop eax ; get argv[0] get_next_arg: pop ebx test ebx,ebx jz near no_more_args mov esi,opts_table ; table mov edi,_lines xor ecx,ecx mov cl,3 mov dl,100b fetch_from_table: lodsw cmp word [ebx],ax ; is it our option? jnz try_next_option ; nope or byte [flgs],dl ; set bitflag jmps get_next_arg ;pop ebx ; get the next argument off the stack try_next_option: shr dl,1 xor eax,eax ; clear counters stosd loop fetch_from_table just_open_it: xor eax,eax cmp byte [ebx],'-' ; user wants STDIN jz use_stdin mov edi,ebx ; save filename mov byte [_opened_a_file], 1 sys_open EMPTY,O_RDONLY test eax,eax js near error jmp set_filehandle use_stdin: mov byte [_use_stdin], 1 set_filehandle: mov ebp,eax read_file: sys_read ebp,buf,buf_size test eax,eax js near error jz print_results mov esi,ecx ; esi=ecx=buf mov ecx,eax ; ecx=bites read xor eax,eax buf_is_not_empty: mov ebx,_bytes lodsb ; get next char inc dword [ebx] ; count this char sub ebx,4 ; ebx=_words cmp al,' ' jz inside_a_word cmp al,9 jz inside_a_word cmp al,10 jz inside_a_word mov ah,1 ; set flag (inside a word) jmp count_lines inside_a_word: test ah,ah ; inside a word? jz count_lines ; nope inc dword [ebx] ; count this word xor ah,ah ; reset flag count_lines: sub ebx,4 ; ebx=_lines cmp al,10 ; is it a '\n' ? jnz not_a_new_line inc dword [ebx] ; count this new line not_a_new_line: dec ecx ; jnz buf_is_not_empty jmp read_file print_results: push edi ; save filename xor ecx,ecx mov bl,[flgs] mov cl,3 mov dl,100b mov esi,_lines next_counter: push ecx lodsd test bl,bl jz print_it_now test bl,dl jz skip_it print_it_now: mov edi,num_buf mov ecx,edi call bin_to_dec call print skip_it: shr dl,1 pop ecx loop next_counter pop ecx ; restore filename cmp byte [_use_stdin], 1 jz print_newline call print print_newline: mov ecx,cr ; print \n call print jmp get_next_arg no_more_args: cmp byte [_opened_a_file], 0 jne true_exit mov byte [_opened_a_file], 1 xor eax, eax jmp use_stdin true_exit: xor ebx,ebx jmp do_exit error: xor ebx,ebx dec ebx do_exit: sys_exit ; ; -------------------------------- procedures --------------------------------- ; ; ecx=string to print print: pushad mov esi,ecx call strlen ; ecx already holds string, edx holds strlen sys_write STDOUT popad ret ; esi=string ; edx=strlen strlen: push eax push esi xor eax,eax mov edx,eax dec edx .do_strlen: inc edx lodsb test al,al jnz .do_strlen pop esi pop eax ret ; eax=number edi=buf to store string ; - bin_to_dec: pushad xor ecx,ecx mov ebx,ecx mov bl,10 .div_again: xor edx,edx div ebx add dl,'0' push edx inc ecx test eax,eax jnz .div_again .keep_popping: pop eax stosb loop .keep_popping ; put \t\x0 mov ax,0x009 stosw popad ret DATASEG opts_table: dw "-l" dw "-w" dw "-c" flgs: db 0 cr: db 10,0 UDATASEG _lines: resd 1 _words: resd 1 _bytes: resd 1 _use_stdin: resb 1 _opened_a_file: resb 1 num_buf: resb 16 buf: resb 4096 buf_size equ $-buf END