3 ;********************************************************************
5 ;* UTILITY NAME: find.exe
7 ;* SOURCE FILE NAME: find.asm
9 ;* STATUS: Find utility, DOS Version 4.0
11 ;* SYNTAX (Command line)
13 ;* FIND [/V][/C][/N] "string" [[d:][path]filename[.ext]...]
17 ;* /V - Display all lines NOT containing the string
18 ;* /C - Display only a count of lines containing string
19 ;* /N - Display number of line containing string
24 ;* Searches the specified file(s) looking for the string the user
25 ;* entered from the command line. If file name(s) are specifeied,
26 ;* those names are displayed, and if the string is found, then the
27 ;* entire line containing that string will be displayed. Optional
28 ;* parameters modify that behavior and are described above. String
29 ;* arguments have to be enclosed in double quotes. (Two double quotes
30 ;* if a double quote is to be included). Only one string argument is
31 ;* presently allowed. The maximum line size is determined by buffer
32 ;* size. Bigger lines will bomb the program. If no file name is given
33 ;* then it will asssume the input is coming from the standard Input.
34 ;* No errors are reported when reading from standard Input.
38 ;* The program returns errorlevel:
39 ;* 0 - OK, and some matches
46 ;* V1.1 8/23/82 M.A.U. (Microsoft)
48 ;* V1.2 9/22/82 M.A.U. (Microsoft)
49 ;* Added the -c and -n options
51 ;* 9/23/82 M.A.U. (Microsoft)
52 ;* Added DOS version number control
54 ;* 10/07/82 Rev.2 M.A.U. (Microsoft)
55 ;* Changed quote for double quotes, and added
58 ;* 10/20/82 Rev.3 M.A.U. (Microsoft)
59 ;* Modified IBM name to FIND, and changed the text
62 ;* 10/25/82 Rev.4 M.A.U. (Microsoft)
63 ;* Changed name to FIND and all messages to the
66 ;* 10/27/82 Rev.5 M.A.U. (Microsoft)
67 ;* Made the correct exit on version check in case
70 ;* 11/4/82 Rev. 5 A.R. Reynolds (Microsoft)
71 ;* Messages moved to external module
73 ;* 11/10/82 Rev. 6 M.A. U. (Microsoft)
74 ;* Corrected problem with line numbers, and a problem
75 ;* with seeking for 0 chars.
77 ;* 03/30/83 Rev. 7 M.A. U. (Microsoft)
78 ;* Added patch area for bug fixing.
80 ;* 04/14/83 Rev. 8 M.A. U. (Microsoft)
81 ;* Made changes for Kanji characters. (ugh!)
83 ;* 12/17/84 Rev. 9 Zibo (Microsoft)
84 ;* Fix boundary case for buffer containing exact line
86 ;* V4.0 : 6/29/87 Russ W (IBM)
87 ;* Lines commented with ;AN000;
88 ;* Add support for IBM Parse service routines
89 ;* Add support for IBM Message Retriever Service Routines
90 ;* Add support for Code Page File Tags
91 ;* Made PROCs out of all labels that were targets of a call (not commented with AN000)
92 ;* Removed patch area for "bug fixing"
94 ;* V4.0 : 9/15/87 Bill L, (IBM)
95 ;* ;AN001; = DCR 201, changes to extended attributes support
99 ;* ;AN005; = PTM 1643, PTM 1675, PTM 1754
100 ;* ;AN006; = DBCS support
101 ;* ;AN007; = Optimizations to save disk space on ship diskettes
103 ;**********************************************************************
105 ;--------------------------
107 ;--------------------------
114 ;---------------------------;
116 ;---------------------------;
119 INCLUDE SYSCALL.INC ;
120 INCLUDE sysmsg
.inc ; ;AN000; Include message equates and MACROS
121 INCLUDE find
.inc ; ;AN000; Include find equates and MACROS
124 ;---------------------------;
126 MSG_UTILNAME
<FIND
> ;AN000;
128 ;--------------------------
130 ;--------------------------
134 CR equ
0dh ;A Carriage Return
135 LF equ
0ah ;A Line Feed
136 quote_char equ 22h
;A double quote character
139 buffer_size equ
4096 ;file buffer size
140 st_buf_size equ
128 ;string arg. buffer size
141 fname_buf_size equ
64 ;file name buffer size
144 ;----- DOS EQUATES -----;
145 STDIN equ
0 ;AN000; Handle
146 STDOUT equ
1 ;AN000; Handle
147 STDERR equ
2 ;AN000; Handle
149 GetCPSW equ
03303h ;AN000; Int 021h function call
150 GetExtAttr equ
05702h ;AN000; Int 021h function call
151 SetExtAttr equ
05704h ;AN000; Int 021h function call
153 ERROR_ACCESS_DENIED equ
5 ;AN000; Int 021h error return
155 CPSWActive equ
1 ;AN000; Indicates Code Page support is active
156 CPSWNotActive equ
0 ;AN000; Just the opposite
158 ERRORLEVEL_ZERO equ
0 ;AN000; Termination error level
159 ERRORLEVEL_ONE equ
1 ;AN000; Termination error level
160 ERRORLEVEL_TWO equ
2 ;AN000; Termination error level
162 ;------------------------
164 ;------------------------
166 msg_file_not_found equ
2 ;AN000; File not found %s
167 msg_access_denied equ
5 ;AN000; Access denied %s
168 msg_read_error equ
30 ;AN000; Read error in %s
169 msg_inv_num_parm equ
2 ;AN000; Invalid number of parameters
170 msg_inv_parm equ
10 ;AN000; Invalid Parameter %s
171 msg_required_missing equ
2 ;AN005; Required parameter missing
172 msg_find equ
4 ;AN000; FIND:
173 msg_code_page_mismatch equ
37 ;AN005; Code Page mismatch
174 msg_switch equ
3 ;AN005; Invalid switch
176 ;-----------------------
178 ;-----------------------
195 ;------------------------
197 ;------------------------
198 Left_Align equ
0 ;AN000; 00xxxxxx
199 Right_Align equ 80h
;AN000; 10xxxxxx
201 Char_Field_Char equ
0 ;AN000; a0000000
202 Char_Field_ASCIIZ equ 10h
;AN000; a0010000
204 Unsgn_Bin_Byte equ 11h
;AN000; a0010001 - Unsigned Binary to Decimal character
205 Unsgn_Bin_Word equ 21h
;AN000; a0100001
206 Unsgn_Bin_DWord equ 31h
;AN000; a0110001
208 Sgn_Bin_Byte equ 12h
;AN000; a0010010 - Signed Binary to Decimal character
209 Sgn_Bin_Word equ 22h
;AN000; a0100010
210 Sgn_Bin_DWord equ 32h
;AN000; a0110010
212 Bin_Hex_Byte equ 13h
;AN000; a0010011 - Unsigned Binary to Hexidecimal character
213 Bin_Hex_Word equ 23h
;AN000; a0100011
214 Bin_Hex_DWord equ 33h
;AN000; a0110011
216 ;------------------------------
217 ; EXTENDED ATTRIBUTE Equates
218 ;------------------------------
219 File_Type_None equ
00000000b ;AN001; unspecified file type
220 File_Type_Text equ
00100000b ;AN001; ASCII text file
221 File_Type_Rtl equ
00100001b ;AN001; ASCII text file in RTL
223 EAISBINARY equ
02h ;AN001; ea_type
224 EASYSTEM equ 8000h
;AN001; ea_flags
226 ;---------------------------------------
227 ;-------------- CODE SEGMENT -----------
228 ;---------------------------------------
239 ;--------------------
245 ;--------------------
247 EXTRN heading
:byte,heading_len
:byte
249 ;*********************************
250 ;* Extended Attribute Structures *
251 ;*********************************
252 querylist
struc ;AN001; ;query general list
254 qea_type db EAISBINARY
;AN001;
255 qea_flags dw EASYSTEM
;AN001;
256 qea_namelen db ?
;AN001;
257 qea_name db " " ;AN001;
258 querylist ends
;AN001;
260 cp_qlist querylist
<1,EAISBINARY
,EASYSTEM
,2,"CP"> ;AN001; ;query code page attr.
262 cp_list
label word ;AN001; ;code page attr. get/set list
263 dw 1 ;AN001; ; # of list entries
264 db EAISBINARY
;AN001; ; ea type
265 dw EASYSTEM
;AN001; ; ea flags
266 db ?
;AN001; ; ea return code
267 db 2 ;AN001; ; ea name length
268 dw 2 ;AN001; ; ea value length
269 db "CP" ;AN001; ; ea name
270 cp dw ?
;AN001; ; ea value (code page)
271 cp_len equ
($ - cp_list
) ;AN001;
273 ;-------Save area for Code Pages
274 src_cp dw ?
;AN000; Save area for source code page
275 tgt_cp dw ?
;AN000; Save area for target code page
276 str_cp dw ?
;AN005; Save area for search string code page
280 ;-----------------------
281 ;----- Misc Data ------
282 bufferDB db 6 dup(0) ;AN006;
283 dbcs_off dw 0 ;AN006;
284 dbcs_seg dw 0 ;AN006;
285 dbcs_len dw 0 ;AN006;
289 n2_buf db 8 dup(0) ;buffer for number conversion
291 errlevel db ERRORLEVEL_ZERO
;AN000; Errrorlevel save area
293 ;----- OPTION FLAGS ----
294 ; If a flag is set (0ffh) then the option has been selected, if
295 ;reset (0) then it has been not. All options are reset initially.
296 ; NOTE: the order of this table has to remain consistent with the
297 ;options dispatch code. If any changes are made they have to
298 ;correspond with the code.
302 v_flag db FALSE
;AN000; Set to FALSE
303 c_flag db FALSE
;AN000; Set to FALSE
304 n_flag db FALSE
;AN000; Set to FALSE
308 mtch_cntr dw 0 ;matched lines counter
309 line_cntr dw 0 ;line counter
311 ;-------------------------------------------
312 ;- MESSAGE RETRIEVER SUBSTITUTION LIST
313 ;-------------------------------------------
315 MSG_SERVICES
<MSGDATA
> ;AN000;
317 sublist
label dword ;AN000;
318 sl_size db 11 ;AN000; SUBLIST Size, in bytes
319 sl_res db 0 ;AN000; reserved
320 sl_ptr_o dw ?
;AN000; Offset PTR to data item
321 sl_ptr_s dw ?
;AN000; Segment PTR to data item
322 sl_n db 0 ;AN000; n of %n
323 sl_flag db ?
;AN000; Data-Type flags
324 sl_maxw db 0 ;AN000; Max width
325 sl_minw db 0 ;AN000; Min width
326 sl_pad db ' ' ;AN000; Pad character
329 parm db ?
;AN000; Save area for invalid parm
330 cpsw_state db CPSWNotActive
;AN000; Save area indicating state of Code Page Support
332 ;******************************************************************************
333 ;* PARSER DATA STRUCTURES FOLLOW
334 ;******************************************************************************
336 parms
label byte ;AN000;
337 dw parmsx
;AN000; POINTER TO PARMS STRUCURE
338 db 1 ;AN000; DELIMITER LIST FOLLOWS
339 db 1 ;AN000; NUMBER OF ADDITIONAL DELIMITERS
340 db ";" ;AN000; ADDITIONAL DELIMITER
342 parms1
label byte ;AN005;
343 dw parmsx1
;AN005; POINTER TO PARMS STRUCURE
344 db 1 ;AN005; DELIMITER LIST FOLLOWS
345 db 1 ;AN005; NUMBER OF ADDITIONAL DELIMITERS
346 db ";" ;AN005; ADDITIONAL DELIMITER
348 ;------------------------------
349 ;- STRUCTURE TO DEFINE FIND SYNTAX REQUIREMENTS
350 ;------------------------------
351 parmsx
label word ;AN000;
352 db 1,2 ;AN000; THERE ARE BETWEEN 1 AND 2 POSITIONAL PARMS
353 dw pos1
;AN000; POINTER TO POSITIONAL DEFINITION AREA
354 dw pos2
;AN000; POINTER TO POSITIONAL DEFINITION AREA
355 db 1 ;AN000; THERE IS 1 SWITCH DEF AREA FOR "/V, /C, AND /N"
356 dw sw1
;AN000; POINTER TO FIRST SWITCH DEFINITION AREA
357 dw 0 ;AN000; THERE ARE NO KEYWORDS IN FIND SYNTAX
359 parmsx1
label word ;AN005;
360 db 0,0 ;AN005; THERE ARE BETWEEN 1 AND 2 POSITIONAL PARMS
361 db 1 ;AN005; THERE IS 1 SWITCH DEF AREA FOR "/V, /C, AND /N"
362 dw sw1
;AN005; POINTER TO FIRST SWITCH DEFINITION AREA
363 dw 0 ;AN005; THERE ARE NO KEYWORDS IN FIND SYNTAX
365 ;------------------------------
366 ;- STRUCTURE TO DEFINE POSITIONAL PARM
367 ;------------------------------
368 pos1
label word ;AN000;
369 dw 0080h ;AN000; QUOTED STRING, REQUIRED
370 dw 0000h ;AN000; NO CAPITALIZE
371 dw ret_buff
;AN000; PLACE RESULT IN RET_BUFF
372 dw novals
;AN000; NO VALUE LIST
373 db 0 ;AN000; NO KEYWORDS
375 ;------------------------------
376 ;- STRUCTURE TO DEFINE POSITIONAL PARM
377 ;------------------------------
378 pos2
label word ;AN000;
379 dw 0203h ;AN000; FILE NAME, OPTIONAL, REPEATS ALLOWED
380 dw 0001h ;AN000; CAPITALIZE BY FILE TABLE
381 dw ret_buff
;AN000; PLACE RESULT IN RET_BUFF
382 dw novals
;AN000; NO VALUE LIST
383 db 0 ;AN000; NO KEYWORDS
386 ;------------------------------
387 ;- STRUCTURE TO DEFINE THE SWITCHES
388 ;------------------------------
389 sw1
label word ;AN000;
390 dw 0 ;AN000; NO MATCH FLAGS
391 dw 2 ;AN005; capitalize
392 dw ret_buff
;AN000; PLACE RESULT IN RET_BUFF
393 dw novals
;AN000; NO VALUE LIST
394 db 3 ;AN000; THREE SWITCHES IN FOLLOWING LIST
395 n_swch db "/N",0 ;AN000;
396 v_swch db "/V",0 ;AN000;
397 c_swch db "/C",0 ;AN000;
400 ;------------------------------
401 ;- VALUE LIST DEFINITION FOR NO VALUES
402 ;------------------------------
403 novals
label word ;AN000;
404 db 0 ;AN000; VALUE LIST
407 ;------------------------------
408 ;- RETURN BUFFER FOR POSITIONAL PARAMETERS
409 ;------------------------------
410 ret_buff
label word ;AN000;
411 rb_type db ?
;AN000; TYPE RETURNED
412 rb_item_tag db ?
;AN000; SPACE FOR ITEM TAG
413 rb_synonym dw ?
;AN000; ES:rb_synonym points to synonym
414 rb_value_lo dw ?
;AN000; SPACE FOR VALUE
415 rb_value_hi dw ?
;AN000; SPACE FOR VALUE
420 did_file db FALSE
;AN004; if true then already processed a file
421 got_eol db FALSE
;AN004; if false then possibly more filenames on command line
422 got_filename db FALSE
;AN004; if true then parser found a filename on command line
423 got_srch_str db FALSE
;AN000; if true then parser found search string on command line
424 ordinal dw 0 ;AN000; parser ordinal
425 crlf db CR
,LF
;AN000;
429 ;************************************************************
431 ;* SUBROUTINE NAME: main
433 ;* SUBROUTINE FUNCTION:
434 ;* Process the command line. If there are no errors, then open
435 ;* the specified files, search for string, display it to the
436 ;* standard output device.
438 ;* INPUT: Command line (described in program header)
441 ;* Files will be opened and read in. Regardless of the command
442 ;* line parameters entered by the user, output will be written
443 ;* to the standard output device handle 1.
446 ;* File(s) opened (if not STDIN), read successfully, and closed.
447 ;* Display requested information.
450 ;* Incorrect DOS version
451 ;* Invalid number of parameters
458 ;* INTERNAL REFERENCES:
470 ;**************************************************************************
472 MSG_SERVICES
<FIND
.ctl
,FIND
.cla
,FIND
.cl1
,FIND
.cl2
> ;AN000;
473 MSG_SERVICES
<DISPLAYmsg
,LOADmsg
,CHARmsg
,NOCHECKSTDIN
> ;AN003; Make retriever services available
476 mov ax,cs ;load ES to the right area,
480 call sysloadmsg
;AN000; Preload messages, Check DOS Version.
481 jnc Set_for_parse
;AN000; If no error, parse command line
483 call prt_find
;AN005;
484 call sysdispmsg
;AN005;
486 mov ah,Exit
;AN000; Terminate new way
487 mov al,0 ;AN000; Errorlevel 0 (Compatible!)
488 int 021h ;AN000; Bye bye!
490 ;-----------------------------------
491 ;- DOS version is ok. Parse cmd line
492 ;-----------------------------------
494 call get_dbcs_vector
;AN006; ;Get DOS dbcs table vector
496 mov ah,GetCurrentPSP
;AN000; Get PSP address, returned in BX
498 mov ds,bx ;AN000; Put PSP Seg in DS
499 mov si,081h ;AN000; Offset of command line in PSP
500 xor cx,cx ;AN000; Number of args processed so far = 0
501 mov cs:ordinal
,cx ;AN000; init parser ordinal
503 ;--------------------------------------
504 ; See if there was nothing entered
505 ;--------------------------------------
506 cmp byte ptr ds:080h,0 ;AN000; Check length of command line,
507 jne p_parse
;AN005; Go process the parameters
508 mov ax,msg_inv_num_parm
;AN000; No parms, too bad!
509 mov dh,2 ;AN005; message class
510 call display_and_die
;AN000; Tell the unfortunate user
512 mov cs:got_filename
,FALSE
;AN004; input file default is STDIN
514 push cs ;A0005; ensure es is correct
517 call clr_cntrs
;AN005; set all counters to zero
518 mov cx,cs:ordinal
;AN005; init parser ordinal
519 call pre_parse
;AN005;
521 push cs ;A0000; ensure es is correct
524 call clr_cntrs
; set all counters to zero
525 mov cx,cs:ordinal
;AN000; init parser ordinal
526 call parse
;AN000; Parse command line
528 push si ;AN000; Save ptr to remaining command line
531 push cs ;Load new DS with CS
533 mov cs:ordinal
,cx ;AN000; Save parser ordinal
535 ;---------------------
537 ;---------------------
538 mov cs:file_name_buf
,di ;save buffer offset from parser
539 xor bx,bx ;AN000;indicate no save again
540 call get_length
;AN000;get filespec length
541 mov es:file_name_len
,ax ;save the name length
543 ;---------------------
544 ;- Check current state of CPSW
545 ;---------------------
547 mov ax,GetCPSW
;AN000; Get CPSW state, assume support is OFF
548 int 021h ;AN000; DL: 0=NotSupported,1=Supported
549 jc open_read
;AN000; If error, assume CPSW inactive
550 mov cs:cpsw_state
,dl ;AN000; Save current state
551 and dl,dl ;AN007; ;AN000; If inactive, (same as CMP dl,0)
552 je open_read
;AN000; do nothing
554 ;-------Code Page Switching is loaded and active!
555 ;-------Save codepage of target handle ----------
556 mov bx,STDOUT
;AN000; For Standard output device
557 call get_cp
;AN000; Get the current codepage
558 jc open_read
;AN000; Error condition
559 mov ax,cs:cp
;AN000; Save target code page
560 mov cs:tgt_cp
,ax ;AN000; for later reference
561 xor bx,bx ;AN007; ;AN005; bx=STDIN. For search string
562 call get_cp
;AN005; Get the code page
563 jc open_read
;AN005; Error condition
564 mov ax,cs:cp
;AN005; Save code page value
565 mov cs:str_cp
,ax ;AN005; ..
567 ;---------------------
568 ;- OPEN FILE FOR READING
569 ;---------------------
571 push cs ;Load new DS with CS
573 cmp cs:got_filename
,TRUE
;AN004; using STDIN
574 je o_cont
;AN004; no, open the file
575 xor ax,ax ;AN007; ;AN004; file handle (ax) = STDIN
576 jmp short cp_check
;AN007; ;AN004; skip open of file
578 mov dx,cs:file_name_buf
;AC000;addrss. of the file name
581 mov al,0 ;file open for reading
582 int 021h ;call the DOS
583 ljc do_open_error
;AN000;
584 ;-------Open was successful. Make sure codepages are the same
586 cmp cs:cpsw_state
,CPSWNotActive
;AN000; Is Code Page support active
587 je say_name
;AN000; No, continue
589 push ax ;AN000; Save source handle
590 mov bx,ax ;AN000; Source handle in BX
591 call get_cp
;AN000; Get codepage of source file
593 mov ax,cs:cp
;AN000; Place source CP in ax
594 cmp ax,cs:str_cp
;AN005; search string code page = src file code page ?
595 je c_cont
;AN005; yes, they are the same, ok
596 and ax,ax ;AN007; ;AN005; src filename cp = 0
597 je c_cont
;AN005; yes, this cp=0 is ok.
598 mov ax,msg_code_page_mismatch
;AN005; Error, code page mismatch
599 mov dh,1 ;AN005; message class
600 call display_and_die
;AN005; bye!
602 cmp ax,cs:tgt_cp
;AN000; Is same as target cp ?
603 je cp_match
;AN000; Yes? Do nothing
605 mov bx,STDOUT
;AN000; Standard output device
606 call set_cp
;AN000; Set codepage to that of source
608 pop ax ;AN000; Restore handle
609 ;---------------------
611 ;---------------------
613 push ax ;save file handle
614 cmp cs:got_filename
,FALSE
;AN004; using STDIN
615 je xx1
;AN004; yes, don't print a filename
616 mov dx,offset heading
617 mov cl,cs:heading_len
621 mov dx,cs:file_name_buf
;AC000;
622 mov cx,cs:file_name_len
625 cmp cs:c_flag
,TRUE
;count only flag set?
634 ;---------------------
635 ;- Fill Buffer for Matching
636 ;---------------------
638 mov bx,ax ;retrieve handle
640 mov dx,offset buffer
;data buffer addrss.
644 jnc no_read_error
;if carry then read error
647 or ax,ax ;if ax=0 then all done
650 cmp cs:c_flag
,TRUE
;count only flag set?
654 and bx,bx ;Using STD IN?
656 jmp foo
;if so: all done, exit
658 mov ah,close
;otherwise close the file
660 jmp scan_rest
;get another file
663 jmp open_error
;AN000;
664 ;---------------------------
665 ; We have read in an entire buffer. Scan for a ^Z and terminate the buffer
666 ; there. Change only CX
667 ;---------------------------
679 ;---------------------------
680 ; If zero is set, the the previous character is a ^Z. If it is reset then
681 ; the previous character is the end of buffer. With ^Z, we back up over the
683 ;---------------------------
688 sub ax,dx ; get true length of buffer
695 ;---------------------------
697 ;---------------------------
698 ;Note: If input is being taken from a file the stack contains
699 ; (from top to bottom):
700 ; - Pointer to the next command in the command line
701 ; - Pointer to the program segment prefix (to be loaded into
702 ; DS to access the command line.
703 ; if the input is from the standard input then NONE of it will be
705 ;---------------------------
708 push bx ;save the file handle
709 mov bp,offset buffer
;ptr to first line of file
710 ;---------------------------
711 ; At this point we must check to make sure there is AT LEAST one LF in the
712 ; buffer. If there is not, then we must insert one at the end so we
713 ; don't get stuck trying to get one complete line in the buffer when
714 ; we can't cause the buffer ain't big enough.
715 ;---------------------------
716 push ax ; Save true buffer size
717 mov cx,ax ; scan whole buffer
719 mov di,bp ; start of buffer
721 pop ax ; recover buffer size
722 mov di,ax ;displacement from beg of buffer
723 jnz last_line
; No line feeds, must insert one
724 ;---------------------------
725 ; Check to see if we reached EOF (return from READ less than buffer_size).
726 ; If EOF we must make sure we end with a CRLF pair.
727 ;---------------------------
728 cmp ax,buffer_size
-1 ;last line of the file?
729 jg no_last_line
;nope
730 last_line: ;if yes, add a CRLF just in case
732 cmp byte ptr[bx+di-1],LF
;finished with a LF?
733 je no_last_line
;yes, it's an OK line.
734 mov byte ptr[bx+di],CR
;put a CR at the end of the data
736 mov byte ptr[bx+di],LF
;put a LF ...
740 push di ;save the # of chars. in the buffer
742 mov dx,cs:st_length
;length of the string arg.
743 dec dx ;adjust for later use
749 ;----- SCAN LINES IN THE BUFFER FOR A MATCH -------------------------;
750 ;Note: at this point the stack contains (from top to bottom):
751 ; - Stuff mentioned before
753 ; - Number of chars. left in the buffer from the next line.
754 ; - Addrs. of the next line in the buffer.
756 ; plus, DX has the adjusted length of the string argument.
758 ; We are about to begin scanning a line. We start by determining if there is
759 ; a complete line in the buffer. If so, we scan for the char. If NOT, we go
761 ;---------------------------
763 pop bp ;addrs. of next line in the buffer
764 mov di,bp ;points to beg. of a line
765 pop cx ;get # of chars left in the buffer
766 mov bx,cx ;save in case a non-complete line
767 mov al,LF
;search for a Line Feed
768 jcxz more_stuff_o
;no chars left in buffer
770 jnz more_stuff_o
;no full line left in buffer
771 push cx ;save chars left in buffer
772 push di ;points to beg. of next line
774 sub cx,bp ;length of the current line
775 mov bx,cx ;save in case it has a match
776 dec cx ;Discount the LF we found
777 cmp byte ptr ES:[DI-2],CR
; Is there a CR to discount too?
778 jnz NO_SECOND_DEC
; No there is not.
779 dec cx ;CR character discounted
781 inc cs:line_cntr
;increment line counter
782 jcxz try_again_opt
;if line empty go to next line
783 mov di,bp ;pointer to the beg. of current line
785 ;---------------------------
788 ; CX adjusted line length
789 ; DX adjusted string argument length
790 ; DI points to beg. of line
791 ;---------------------------
792 push dx ;save for next line
796 inc dx ;different algorithm!
797 mov si,offset st_buffer
;pointer to beg. of string argument
802 call is_prefix
;check for a prefix char
806 cmp cx,1 ; Can not compare a two byte char
807 jbe try_again_opt1
; if there is only one available
810 jmp short back_up
;AN007;
817 pop ax ; Original length of comp string
820 ;---------------------------
821 ; Our match failed IN THE MIDDLE of the string (partial match). We need
822 ; to back up in the line to the NEXT char after the one which matched
823 ; the first char of the search string and try again. The amount to
824 ; back up to where we started is ax-dx (the result MAY be 0, this is OK).
825 ; we then need to skip ONE char in the line.
826 ;---------------------------
827 sub ax,dx ; AX = AX-DX
828 sub di,ax ; Do the back up.
829 add cx,ax ; restore count too!
830 call next_kchar
;no match, advance di to next kanji
831 jc try_again_opt1
;not enough chars left in line
832 jmp short lop
;try another char in line
836 jmp short try_again_opt
;AN007;
840 dec dx ;last char had prefix so it was
844 jz a_matchk
; no chars left: a match!
847 jmp comp_next_char
; loop if chars left in arg.
851 cmp cs:v_flag
,TRUE
;is flag set?
852 jne prt_line
;no, print the line
855 ;---------------------------
856 ;- NO MATCH: CHECK FOR THE v OPTION
857 ;---------------------------
859 cmp cs:v_flag
,TRUE
;is flag set?
860 jne try_again
;no goto next line
862 ;---------------------------
863 ;- PRINT THE LINE WITH THE MATCH
864 ;Note: at this point the stack contains (top to bottom)
865 ; - Stuff mentioned before
867 ; plus, BP points to begginig of the current line, BX has the length
868 ;of the current line including the CRLF, and DX the adjusted length of
869 ;the string argument.
870 ;---------------------------
873 cmp cs:c_flag
,TRUE
;is count only flag set?
875 inc cs:mtch_cntr
;yes, increment counter
879 push dx ;save the adjusted string arg. length
880 cmp cs:n_flag
,TRUE
;is line number flag set?
890 ;----- READ MORE TEXT LINES INTO THE BUFFER -------------------------;
891 ; The scanning routines have detected that the buffer does not
892 ;contain a full line any more. More lines have to be read into the
893 ;buffer. But first perform a seek on the file in order to re-read
894 ;the non-complete line into the begining of the buffer.
895 ; Uppon entry BP contains points to the begining of the non-complete
896 ;line, and BX has the number of characters left in the buffer.
897 ; The Stack contains (top to bottom):
898 ; - Pointer to the next command in the command line
899 ; - Pointer to the program segment prefix (to be loaded into
900 ; DS to access the command line).
904 mov dx,bx ;get chars left in buffer
905 pop bx ;get the handle
906 or dx,dx ;are there 0 left?
907 jz no_seek
;yes, do not seek
908 neg dx ;form two's complement
910 mov al,1 ;seek from the current position
911 mov ah,lseek
;seek on file
915 jmp refill
;no errors: refill the buffer
917 and bx,bx ;AN007; ;Using STD IN?
918 je foo
;if so: all done, exit
919 mov ah,close
;close the file
922 ;------ Set message number and go display it
924 mov ax,msg_read_error
;AN000; Read error message
925 jmp short r_error
;AN007;
927 ;---------------------
929 ;---------------------
931 cmp ax,ERROR_ACCESS_DENIED
;AN000;
934 mov ax,msg_access_denied
;AN000; Message for Access Denied
935 jmp short r_error
;AN007; ;AN000; Do the rest
938 mov ax,msg_file_not_found
;AN000; Message for File Not Found
941 call prt_find
;AN005;
942 mov cs:sl_ptr_s
,ds ;AN000; Save segment of subst text
943 mov cx,cs:file_name_buf
;AN000;
944 mov cs:sl_ptr_o
,cx ;AN000; Save offset of subst text
945 mov cs:sl_flag
,left_align
+char_field_ASCIIZ
;AN000; Type of insertion text
946 mov bx,STDERR
;AN000; Sent to STD OUT
947 mov cx,1 ;AN000; One substitution string
948 mov dh,1 ;AN000; Its a utility message
950 call display_msg
;AN000; Display rror message
952 ;---------------------
953 ;- SCAN THE REST OF THE COMMAND LINE
954 ;---------------------
956 pop ds ;restore pointer to comm. line
957 pop si ;restore pointer to next comm.
958 mov cs:did_file
,TRUE
;AN004; tell parser we did a file, so if it doesn't find another, ok!
959 cmp cs:got_eol
,TRUE
;AN004; Check if nothing left on command line
960 je foo
;AN004; no, nothing left on command line, exit
964 mov cs:errlevel
,ERRORLEVEL_ZERO
;AN000; Proper code
965 call terminate
;AN000; reset codepage and terminate
968 ;--------------------------
970 ;--------------------------
972 mov byte ptr cs:mtch_cntr
,0
973 mov byte ptr cs:line_cntr
,0
978 ;--------------------------
979 ; Print Count of Matched lines
980 ; Modifies: AX,CX,DX and DI
981 ;--------------------------
982 print_count proc
near
984 and bx,bx ;AN007; ;using STDIN?
985 jz sj3
;if so do not print file name
989 call prout
;print colon
992 mov di,offset n2_buf
;buffer for characters
993 call bin2asc
;convert to ascii
995 call prout
;print the number
998 call prout
;print an end of line
1003 ;--------------------------
1004 ; Print relative line number
1006 ; Modifies: AX,CX and DI
1007 ;--------------------------
1012 mov di,offset n2_buf
1014 mov byte ptr[di],"]"
1017 mov dx,offset n1_buf
1024 ;--------------------------
1025 ; Print string to STDOUT
1026 ;--------------------------
1034 ;--------------------------
1035 ; Binary to Ascii conversion routine
1038 ; DI Points to one past the last char in the
1041 ; Result in the buffer MSD first
1044 ; AX,BX,CX,DX and DI
1045 ;--------------------------
1055 add dl,'0' ;convert to ASCII
1071 ;--------------------------
1072 ; CAPIALIZES THE CHARACTER IN AL
1074 ; AL has the character to Capitalize
1076 ; AL has the capitalized character
1079 ;--------------------------
1080 ;make_caps proc near
1092 ;--------------------------
1093 ; ADVANCE POINTER TO NEXT KANJI CHARACTER
1094 ; entry: DI points to a Kanji string
1095 ; CX length in bytes of the string
1096 ; exit: DI points to next Kanji char
1097 ; CX has number of bytes left
1099 ;--------------------------
1100 next_kchar proc
near
1106 jcxz no_kleft
; for insurance
1118 ;--------------------------
1119 ; Get DOS dbcs table vector
1123 ;--------------------------
1124 get_dbcs_vector proc
near ;AN006;
1132 mov ax,cs ;AN006; ;segment of return buffer
1134 mov di,offset bufferDB
;AN006; ;offset of return buffer
1135 mov ah,65h
;AN006; ;get extended country info
1136 mov al,07h ;AN006; ;get DBCS environment table
1137 mov bx,0ffffh ;AN006; ;use active code page
1138 mov cx,5 ;AN006; ;number of bytes returned
1139 mov dx,0ffffh ;AN006; ;default country ID
1140 int 21h
;AN006; ;DOS function call,vector returned
1142 inc di ;AN006; ;skip over id byte returned
1143 mov ax,word ptr es:[di] ;AN006; ;get offset of DBCS table
1144 mov cs:dbcs_off
,ax ;AN006; ;save it
1146 add di,2 ;AN006; ;skip over offset to get segment
1147 mov bx,word ptr es:[di] ;AN006; ;get segment of DBCS table
1148 mov cs:dbcs_seg
,bx ;AN006; ;save it
1150 mov di,ax ;AN006; ;Point to DBCS table to get length
1152 mov ax,word ptr es:[di] ;AN006;
1153 mov cs:dbcs_len
,ax ;AN006;
1154 add cs:dbcs_off
,2 ;AN006; ;change offset to point to table
1164 get_dbcs_vector endp
;AN006;
1167 ;--------------------------
1168 ; FIND OUT IS THE BYTE IS A KANJI PREFIX
1169 ; entry: DI points to a kanji string
1170 ; exit: Carry set if it is a kanji prefix
1172 ;--------------------------
1173 is_prefix proc
near ;AN006;
1178 mov si,cs:dbcs_off
;ES:SI -> DOS dbcs table
1182 mov al,byte ptr cs:[di] ;get first byte of string
1184 ; Two consecutive 00 bytes signifies end of table
1188 cmp word ptr es:[si],00h ;Check for two consecutive 00 bytes
1189 jne is_next1
;no, continue
1190 clc ;clear carry - byte is not lead byte of db char
1191 jmp short is_exit
;AN007; ;yes, found them, quit
1194 ; Check if byte is within range values of DOS dbcs table
1198 cmp al,byte ptr es:[si] ;is byte >= first byte in range?
1199 jae is_next2
;yes, continue
1200 jmp short is_again
;AN007; ;no, loop again
1203 cmp al,byte ptr es:[si+1] ;is byte <= last byte in range?
1204 jbe is_found
;yes, found a lead byte of db char
1207 add si,2 ;no, increment ptr to next range
1211 stc ;byte is lead byte of db char, set carry
1223 ;---------------------
1224 ;- Terminate process
1225 ;---------------------
1226 terminate proc
near ;AN000;
1227 mov ah,exit
;AN000; Terminate function call
1228 mov al,cs:errlevel
;AN000; Errorlevel placed in AL
1229 int 021h ;AN000; Terminate
1230 ret ;AN000; Meaningless return
1231 terminate endp
;AN000;
1234 ;************************************************************
1236 ;* SUBROUTINE NAME: set_cp
1238 ;* FUNCTION: Sets the cp of the handle in bx to the cp in LIST structure
1242 ;* cp_list.cp = code page to set for the file handle in BX
1245 ;* Codepage will be set to that requested, or an error will be
1246 ;* returned in AX with carry flag set.
1248 ;************************************************************
1249 set_cp proc
near ;AN000;
1250 mov ax,SetExtAttr
;AN000; Set target codepage to that of source
1251 mov di,offset cp_list
;AC001; Input buffer address
1252 int 021h ;AN000; Call DOS
1253 ret ;AN000; Return to caller
1258 ;************************************************************
1260 ;* SUBROUTINE NAME: get_cp
1262 ;* FUNCTION: Gets the cp of the handle in bx
1268 ;* Codepage for the file handle in bx will be returned in
1269 ;* the CP_LIST.CP structure, or an error will be returned in
1270 ;* AX with carry flag set.
1272 ;************************************************************
1273 get_cp proc
near ;AN000;
1279 mov ax,GetExtAttr
;AN000; Get codepage
1280 mov di,offset cp_list
;AN000; Input buffer address
1281 mov si,offset cp_qlist
;AN001; which ea to select
1282 mov cx,cp_len
;AN001; buffer length
1283 int 021h ;AN000; Call to DOS
1286 ret ;AN000; Return to caller
1291 ;************************************************************
1293 ;* SUBROUTINE NAME: display_msg
1295 ;* SUBROUTINE FUNCTION:
1296 ;* Display the requested message to the specified handle
1299 ;* 1) AX = Number of the message to be displayed.
1300 ;* 2) BX = Handle to be written to.
1301 ;* 3) DH = Code indicating message class
1304 ;* The message corresponding to the requested msg number will
1305 ;* be written to the requested handle.
1308 ;* Message will be successfully written to requested handle.
1311 ;* None. Note that theoretically an error can be returned from
1312 ;* SYSDISPMSG, but there is nothing that the application can do.
1314 ;* INTERNAL REFERENCES:
1315 ;* System Display Message service routines
1317 ;* EXTERNAL REFERENCES:
1320 ;************************************************************
1321 display_msg proc
near ;AN000;
1322 push ds ;AN000; Save DS
1323 push cs ;AN000; Substitution list segment
1325 mov si,offset sublist
;AN000; Substitution list offset
1326 ; mov dh,-1 ;AN000; Message class
1327 ; 1=DOS Extended error
1329 ; -1=Utility message
1330 mov dl,0 ;AN000; DOS INT 21H function number to use for input
1331 ; 00H=No input, 01H=Keyboard input,
1332 ; 07H=Direct Console Input Without Echo,
1333 ; 08H=Console Input Without Echo, 0AH=Buffered Keyboard Input
1334 call SYSDISPMSG
;AN000; AX=Extended key value if wait for key
1335 ; jnc disp_done ;AN000; If CARRY SET then registers will contain extended error information
1336 ; AX - Extended error Number
1338 ; BL - Suggested action
1341 pop ds ;AN000; Restore DS
1343 display_msg ENDP
;AN000;
1346 ;************************************************************
1348 ;* SUBROUTINE NAME: parse
1350 ;* SUBROUTINE FUNCTION:
1351 ;* Call the DOS PARSE Service Routines to process the command
1352 ;* line. Search for valid switches (/N, /V, and /C) and take
1353 ;* appropriate action for each. Extract the search string.
1355 ;* INPUT: DS:SI points to string to parse
1356 ;* ES:DI parser parms
1358 ;* OUTPUT: ES:DI points to filespec for text search
1362 ;* If /V, /C, or /N entered, set appropriate flag.
1363 ;* Save the search string.
1367 ;* If user enters any invalid parameter or switch, then this
1368 ;* routine will display an error message and terminate with
1371 ;************************************************************
1372 EOL equ
-1 ;AN000; Indicator for End-Of-Line
1373 NOERROR equ
0 ;AN000; Return Indicator for No Errors
1374 SYNTAX equ
9 ;AN000; Syntax error from parser
1376 SWITCH equ
3 ;AN000;
1377 FILESPEC equ
5 ;AN000;
1378 QUOTED_STRING equ
9 ;AN000;
1380 parse proc
near ;AN000;
1381 ;--------------------------------------
1382 ; address of command line in DS:SI
1383 ;--------------------------------------
1384 ;------------------------------------------
1385 ;- Look for the search string and switches
1386 ;------------------------------------------
1388 mov di,offset parms
;AN000; Address of parse control block at ES:DI
1389 xor dx,dx ;AN000; Reserved
1390 call sysparse
;AN000; Parse parm at DS:SI
1391 cmp ax,EOL
;AN000; Are we at End Of Line ??
1392 jne p_next
;AN004; No eol found
1393 mov cs:got_eol
,TRUE
;AN004; no more filenames to get!
1394 cmp cs:did_file
,TRUE
;AN004; did we do a file already ?
1395 lje doexit
;AN004; yes, exit
1396 jmp end_parse
;AN004; Yes, done here
1397 p_next: ;AN004; continue
1398 and ax,ax ;AN007; ;AN000; Was there an error?
1399 je CONT2
;AN000; No, continue processing
1401 mov dh,2 ;AN005; Its a PARSE message
1402 call display_and_die
;AN005;
1403 CONT2: ;AN000; Something valid was entered
1404 cmp cs:rb_type
,QUOTED_STRING
;AN000; Is it a quoted string ?
1405 je its_a_quoted_string
;AN000; Yes, go process it
1406 cmp cs:rb_type
,FILESPEC
;AN000; Is it a filespec?
1408 mov di,cs:rb_value_lo
;AN000; Look for another
1409 mov cs:got_filename
,TRUE
;AN004; got a filename
1410 jmp short end_parse
;AN007; ;AN000; Look for another
1412 cmp cs:rb_type
,SWITCH
;AN000; Is it a switch ?
1413 je its_a_switch
;AN000; Yes, go process it
1414 mov ax,msg_inv_parm
;AN000; None of above, too bad
1415 mov dh,2 ;AN005; message class
1416 call display_and_die
;AN000; Tell the poor user and terminate
1418 ;-----------------------------
1419 ;- The search string was entered
1420 ;-----------------------------
1421 its_a_quoted_string: ;AN000; Found a quoted string
1422 cmp cs:got_srch_str
,TRUE
;AN000; Do we already have one?
1423 jne its_ok
;AN000; No, it's ok
1424 mov ax,msg_inv_parm
;AN000; Yes, Invalid parm!
1425 mov dh,2 ;AN005; message class
1426 call display_and_die
;AN000; Tell user and die gracefully
1428 mov di,cs:rb_value_lo
;AN000; Get pointer to it
1429 mov bx,offset st_buffer
;AN000; save buffer offset
1430 call get_length
;AN000; get string length
1431 mov cs:st_length
,ax ;AN000; save length
1432 mov cs:got_srch_str
,TRUE
;AN000; Indicate that we have it
1433 jmp parse_loop
;AN000;
1435 ;-----------------------------
1436 ;- A valid switch was entered
1437 ;-----------------------------
1438 its_a_switch: ;AN000;
1439 mov bx,cs:rb_synonym
;AN000; Get offset of switch entered
1440 cmp bx,offset n_swch
;AN000; Is it the /N switch?
1441 jne chek_v
;AN000: Yes, process it.
1442 jmp parse_loop
;AN000; Look for another
1444 cmp bx,offset v_swch
;AN000; Is it the /N switch?
1445 jne chek_c
;AN000: Yes, process it.
1446 jmp parse_loop
;AN000; Look for another
1448 cmp bx,offset c_swch
;AN000; Is it the /N switch?
1449 jne whoops
;AN000: Yes, process it.
1450 jmp parse_loop
;AN000; Look for another
1451 whoops: ;AN000; None of the above (can we ever get here?)
1452 mov ax,msg_switch
;AN000; Invalid parameter
1453 mov dh,2 ;AN005; message class
1454 call display_and_die
;AN000; Yes, tell the poor user and terminate
1456 end_parse: ;AN000; A filename should be next
1457 cmp cs:got_srch_str
,TRUE
;AN000; Do we already have one?
1459 mov ax,msg_required_missing
;AN005;
1460 mov dh,-1 ;AN005; message class
1461 call display_and_die
;AN000; Yes, tell the poor user and terminate
1466 mov cs:errlevel
,ERRORLEVEL_ZERO
;AN000; Proper code
1467 call terminate
;AN000; reset codepage and terminate
1472 ;------------------------------------
1474 ;- Procedure name: pre_parse
1476 ;- Purpose: parse for all switches now
1477 ;- so that they can be applied for
1478 ;- all filenames on command line.
1482 ;------------------------------------
1483 pre_parse proc
near ;AN005;
1494 mov di,offset parms1
;AN005; Address of parse control block at ES:DI
1495 xor dx,dx ;AN005; Reserved
1496 call sysparse
;AN005; Parse parm at DS:SI
1498 cmp ax,EOL
;AN005; Are we at End Of Line ??
1499 je pp_end
;AN005; No eol found
1501 cmp ax,SWITCH
;AN005; invalid switch ?
1502 jne pp_next
;AN005; no
1504 mov ax,msg_switch
;AN005; Invalid switch
1505 mov dh,2 ;AN005; message class
1506 call display_and_die
;AN005; Yes, tell the poor user and terminate
1508 and ax,ax ;AN007; ;AN005; Was there an error?
1509 jne pp_loop
;AN005; No, continue processing
1511 cmp cs:rb_type
,SWITCH
;AN005; Is it a switch ?
1515 mov bx,cs:rb_synonym
;AN005; Get offset of switch entered
1516 cmp bx,offset n_swch
;AN005; Is it the /N switch?
1517 jne pp_chek_v
;AN005: Yes, process it.
1518 mov cs:n_flag
,TRUE
;AN005; Set the corresponding flag
1519 jmp pp_loop
;AN005; Look for another
1521 cmp bx,offset v_swch
;AN005; Is it the /N switch?
1522 jne pp_chek_c
;AN005: Yes, process it.
1523 mov cs:v_flag
,TRUE
;AN005; Set the corresponding flag
1524 jmp pp_loop
;AN005; Look for another
1526 cmp bx,offset c_swch
;AN005; Is it the /N switch?
1527 jne pp_error
;AN005: Yes, process it.
1528 mov cs:c_flag
,TRUE
;AN005; Set the corresponding flag
1529 jmp pp_loop
;AN005; Look for another
1531 pp_error: ;AN005; None of the above (can we ever get here?)
1532 mov ax,msg_switch
;AN005; Invalid parameter
1533 mov dh,2 ;AN005; message class
1534 call display_and_die
;AN005; Yes, tell the poor user and terminate
1536 pp_end: ;AN005; A filename should be next
1547 pre_parse endp
;AN005;
1550 ;------------------------------------
1552 ;- Procedure name: prt_find
1554 ;- Purpose: When FIND is used as a filter,
1555 ;- then display error messages with the
1556 ;- prefix: "FIND: ".
1560 ;------------------------------------
1561 prt_find proc
near ;AN005;
1562 cmp cs:got_filename
,TRUE
;AN005; Check if should print "FIND:"
1564 push ax ;AN005; Save error
1566 mov dh,-1 ;AN005; Display FIND:
1567 mov ax,msg_find
;AN005;
1568 xor cx,cx ;AN007; ;AN005; No substitution text
1569 mov bx,STDERR
;AN005; Sent to STD OUT
1570 call display_msg
;AN005; Display the message
1572 pop ax ;AN005; Restore error
1575 prt_find endp
;AN005;
1578 ;------------------------------------
1580 ;- Procedure name: display_and_die
1582 ;- Purpose: Called when the parser finds that
1583 ;- required arguments were not entered
1584 ;- from the command line.
1586 ;- INPUT: AX = Error number
1588 ;------------------------------------
1589 display_and_die proc
near
1590 call prt_find
;AN005;
1591 xor cx,cx ;AN007; ;AN000; No substitution text
1592 mov cs:errlevel
,ERRORLEVEL_TWO
;AC005; Error code for exit
1594 mov bx,STDERR
;AN000; Sent to STD OUT
1595 call display_msg
;AN000; Display the message
1596 call terminate
;AN000; and Terminate
1598 display_and_die endp
1600 ;------------------------------------
1602 ;- Procedure name: get_length
1604 ;- Purpose: determine the length of a null
1607 ;- INPUT: ES:DI = string address
1608 ;- ES:BX = save address (0=no save)
1610 ;- OUTPUT: AX = length of string
1611 ;------------------------------------
1612 get_length proc
near
1616 xor ax,ax ;init string length
1618 mov dl,es:[di] ;get character
1621 mov es:[bx],dl ;save character
1622 inc bx ;save next character
1624 and dl,dl ;AN007; ;check for eol (asciiz string)
1625 je done_look
;if so, exit
1626 cmp dl,0dh ;AN005; check for eol (carriage return)
1627 je done_look
;AN005;
1628 inc ax ;increment length
1629 inc di ;look at next character
1642 ;----- BUFFER AREA --------
1643 st_length dw 0 ;String argument length
1644 st_buffer db st_buf_size
dup(?
) ;String argument buffer
1646 file_name_len dw 0 ;File name length
1647 file_name_buf dw 0 ;File name buffer offset
1649 buffer db buffer_size
+2 dup(?
) ;file data buffer
1655 ;--------------------------
1656 ;--- STACK SEGMENT ---
1657 ;--------------------------
1658 stack segment para
stack 'STACK'
1659 dw (362 - 80h
) +64 dup(?
,?
) ;(362 - 80h) == New - old IBM ROM