home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcmagazi / 1987 / 04 / search.asm next >
Assembly Source File  |  1987-12-12  |  29KB  |  608 lines

  1. ;                    Search.asm
  2. ; FORMAT: SEARCH [d:][path][filename] [string][/P][/C][/B]
  3. ; At least one parameter must be entered.
  4. ; /P=printer  /C=case sensitive  /B=include executable files
  5. ; in string searches.  Default is diskwide search.  Limit search
  6. ; by adding parameters.  String must be enclosed in quotes.
  7.  
  8. CODE SEGMENT                           ;*************************
  9. ASSUME CS:CODE,DS:CODE                 ;*                       *
  10. ORG 100H                               ;*  REMEMBER TO EXE2BIN  *
  11.                                        ;*                       *
  12. START:         JMP    BEGINNING        ;*************************
  13.  
  14. ;              DATA AREA
  15. ;              ---------
  16. COPYRIGHT      DB  'Copyright 1986 Ziff Davis Publishing Co.',1AH
  17. PROGRAMMER     DB  'Michael J. Mefford'
  18. SEARCH_SPEC    DW  OFFSET GLOBAL
  19. GLOBAL         DB  '*.*',0
  20. ROOT           DB  '\',0
  21. PARENT         DB  '..',0
  22. CURRENT_DISK   DB  ?
  23. PATH_END       DW  ?
  24. PARA_START     DW  ?
  25. GOOD_PARA      DB  0
  26. STRING_START   DW  ?
  27. STRING_CT      DW  0
  28. LINE_NUM       DW  1
  29.  
  30. STRING_FLAG    DB  0
  31. PATH_FLAG      DB  0
  32. PRINT_FLAG     DB  0
  33. CASE_FLAG      DB  0
  34. BINARY_FLAG    DB  0
  35. EOF_FLAG       DB  0
  36. MATCH_FLAG     DB  0
  37. DISPLAY_FLAG   DB  0
  38.  
  39. EXE            DB  'EXE'
  40. COM            DB  'COM'
  41. BAD_PARA       DB  'Invalid parameters',7,'$'
  42. SEARCH         DB  13,10,'Searching for ',0
  43. DIRECTORY      DB  13,10,13,10,'Directory ',0
  44. LINE           DB  9,'Line number ',0
  45. SPACING        DB  13,10,32,32,0
  46.  
  47. DIR_ATTRIBUTE  EQU 10H
  48. ALL_FILES      EQU  6H
  49. QUOTES         EQU 22H
  50.  
  51. ;--------------------------------------------------------------;
  52. ; The first task is to initialize 100 bytes at the end of code ;
  53. ; to one.  This will be used to track the directory level.     ;
  54. ; The current drive and directory and drive will be saved.     ;
  55. ; Then the command line at 80H in the PSP will be parsed.      ;
  56. ;--------------------------------------------------------------;
  57.  
  58. BEGINNING:     CLD                           ;All string instructions will be
  59.                MOV    AL,1                   ; done in a forward direction.
  60.                MOV    CX,100                 ;Initialize directory subscripts
  61.                MOV    DI,OFFSET SUBSCRIPTS   ;to one.
  62.                REP    STOSB
  63.  
  64.                MOV    AH,19H                 ;Retrieve and save the current
  65.                INT    21H                    ; drive.
  66.                MOV    CURRENT_DISK,AL
  67.  
  68.                MOV    SI,OFFSET CURRENT_DIR+1     ;Leave room for "\".
  69.                MOV    DL,0
  70.                MOV    AH,47H                 ;Retrieve and save the
  71.                INT    21H                    ; the current directory.
  72.                MOV    DX,OFFSET DTA          ;Point the disk transfer address
  73.                CALL   CHANGE_DTA             ; to the end of code.
  74.  
  75.                CMP    BYTE PTR DS:[80H],0    ;If no parameters, exit with error.
  76.                JA     FIRST_PARA
  77.                JMP    EXIT
  78. FIRST_PARA:    MOV    SI,82H                 ;Point to the first byte of the
  79. NEXT_PARA:     LODSB                         ; command line.
  80.                CMP    AL,32                  ;Scan off leading spaces.
  81.                JZ     NEXT_PARA
  82.                CMP    AL,QUOTES              ;If no filespec, parse string.
  83.                JNZ    CK_CR
  84.                JMP    STRING
  85. CK_CR:         CMP    AL,13                  ;If no parameters, exit with error.
  86.                JNZ    CK_DRIVE
  87.                JMP    EXIT
  88.  
  89. CK_DRIVE:      CMP    BYTE PTR [SI],':'
  90.                JNZ    NO_DRIVE               ;If drive spec exists,
  91.                AND    AL,5FH                 ; convert drive to DOS format by
  92.                SUB    AL,'A'                 ; capitalizing and changing to
  93.                MOV    DL,AL                  ; hex number.
  94.                MOV    AH,0EH                 ;Change drive.
  95.                INT    21H
  96.                INC    SI
  97.                CALL   PARA_END               ;If end of filespec, done parsing
  98.                JC     DRIVE_ONLY             ; here
  99.                LODSB                         ; otherwise get next parameter.
  100.                CMP    AL,QUOTES              ;If it's quotes exit with error.
  101.                JNZ    NO_DRIVE               ; (need a space delimiter
  102.                JMP    EXIT                   ; before string.)
  103.  
  104. NO_DRIVE:      MOV    PARA_START,SI          ;We now are pointing to the start
  105.                DEC    PARA_START             ; of the filespec parameter.
  106.                MOV    PATH_END,SI            ;Will assume the end of path to
  107.                DEC    PATH_END               ; be parameter start-1.
  108.                DEC    PATH_END
  109.                CMP    AL,'\'                 ;If search is to start at root,
  110.                JNZ    CK_GLOBAL              ; change the directory to the root
  111.                MOV    DX,OFFSET ROOT         ; and adjust the start pointer.
  112.                CALL   CHANGE_DIR
  113.                MOV    PATH_FLAG,1            ;Flag that a path exists.
  114.                INC    PARA_START
  115.                CALL   PARA_END
  116. DRIVE_ONLY:    JC     NEXT_DELIMIT           ;If no other filespec, done here.
  117. CK_GLOBAL:     CMP    AL,'*'                 ;If *.*, search the entire disk.
  118.                JNZ    CK_SWITCH
  119.                LODSB
  120.                CMP    AL,'.'
  121.                JZ     GOT_DOT
  122.                JMP    EXIT
  123. GOT_DOT:       LODSB
  124.                CMP    AL,'*'
  125.                JZ     NEXT_DELIMIT
  126. CK_SWITCH:     CMP    AL,'/'                 ;  We will loop from here to >----+
  127.                JNZ    NEXT_FILESPEC          ;                                 |
  128.                CALL   SWITCH                 ;                                 |
  129.                CMP    AL,QUOTES              ;If quotes without space,         |
  130.                JNZ    NEXT_FILESPEC          ;                                 |
  131.                JMP    EXIT                   ; exit with error.                |
  132. NEXT_FILESPEC: LODSB                         ;                                 |
  133.                CMP    AL,32                  ;If space character or below,     |
  134.                JBE    FILESPEC               ; we have the filespec.           |
  135.                CMP    AL,'\'                 ;Check for path.                  |
  136.                JNZ    CK_SWITCH              ;                                 |
  137.                MOV    PATH_FLAG,1            ;                                 |
  138.                MOV    PATH_END,SI            ;If path found, update variables. |
  139.                DEC    PATH_END               ;                                 |
  140.                JMP    SHORT CK_SWITCH        ; here to find the filespec. <----+
  141.  
  142. ;------------------------------------------------------------;
  143. ; Now that we have the filespec, will check if it is a path. ;
  144. ;------------------------------------------------------------;
  145.  
  146. FILESPEC:      MOV    BL,AL                  ;Save current delimiter.
  147.                MOV    BYTE PTR [SI-1],0      ;Format the end for DOS with a 0.
  148.                MOV    BYTE PTR DTA+21,0      ;Initiate file attribute to 0.
  149.                MOV    DX,PARA_START
  150.                MOV    CX,10H
  151.                CALL   FIND_FIRST             ;Get file's attribute via DOS.
  152. FOUND_FILE:    CMP    BYTE PTR DTA+21,10H
  153.                JNZ    NO_PATH                ;If it is a path, update variables
  154.                MOV    PATH_FLAG,1
  155.                MOV    PATH_END,SI
  156.                DEC    PATH_END
  157.                JMP    SHORT CK_DELIMITER     
  158. NO_PATH:       MOV    DX,PATH_END            ; otherwise, it is a filename;
  159.                INC    DX                     ; update path end; change search
  160.                MOV    SEARCH_SPEC,DX         ; spec from global to filename.
  161. CK_DELIMITER:  CMP    BL,13                  ;Check if delimiter is carriage
  162.                JZ     NO_STRING              ; return.  If yes, no string.
  163.  
  164. ;------------------------------------------------------------------;
  165. ; Done with filespec.  Now continuing by parsing string parameter. ;
  166. ;------------------------------------------------------------------;
  167.  
  168. NEXT_DELIMIT:  LODSB
  169.                CMP    AL,32                  ;Scan off delimiting spaces.
  170.                JZ     NEXT_DELIMIT
  171.                CMP    AL,'/'                 ;Check if switch.
  172.                JNZ    NO_SWITCH
  173.                CALL   SWITCH
  174.                JMP    SHORT NEXT_DELIMIT
  175. NO_SWITCH:     CMP    AL,13                  ;If carriage return, no string.
  176.                JZ     NO_STRING
  177.                CMP    AL,QUOTES              ;If quotes, start of string.
  178.                JNZ    NEXT_DELIMIT
  179.  
  180. STRING:        MOV    STRING_FLAG,1          ;Flag that string exists.
  181.                MOV    STRING_START,SI        ;Point to start of string.
  182.                XOR    BH,BH
  183.                MOV    BL,BYTE PTR DS:[80H]
  184.                ADD    BX,81H                 ;Point to end of parameters and
  185. NEXT_QUOTE:    DEC    BX                       ;work backwards until find
  186.                CMP    BYTE PTR DS:[BX],QUOTES  ;first quotes.
  187.                JZ     END_STRING
  188.                CMP    BX,SI                  ;If only one quote,
  189.                JZ     EXIT                   ; exit with error.
  190.                JMP    SHORT NEXT_QUOTE
  191.  
  192. END_STRING:    MOV    BYTE PTR DS:[BX],0     ;Got end of string; mark with 0.
  193.                PUSH   BX                     ;Save position.
  194.                SUB    BX,SI                  ;Subtract to get string length.
  195.                MOV    STRING_CT,BX
  196.                POP    SI                     ;Restore position.
  197. LAST_PARA:     LODSB                         ;We have the string.  Now all
  198.                CMP    AL,'/'                 ; have left to do is check for
  199.                JNZ    LAST_SWITCH            ; switches.
  200.                CALL   SWITCH
  201. LAST_SWITCH:   CMP    AL,13
  202.                JNZ    LAST_PARA
  203.  
  204. ;-----------------------------------------------------;
  205. ; If no case sensitive switch, capitalize the string. ;
  206. ;-----------------------------------------------------;
  207.  
  208.                CMP    CASE_FLAG,1
  209.                JZ     NO_STRING
  210.                MOV    CX,STRING_CT
  211.                MOV    BX,STRING_START
  212.                CALL   CAPITALIZE
  213.  
  214. ;----------------------------------------------------------;
  215. ; If we got this far, the parameters were found valid.     ;
  216. ; If a string was found, display it.  If path was found,   ;
  217. ; change directory and search, otherwise do global search. ;
  218. ;----------------------------------------------------------;
  219.  
  220. NO_STRING:     MOV    GOOD_PARA,1            ;Flag as good parameters.
  221.                CMP    STRING_FLAG,1          ;If string exists, display it.
  222.                JNZ    STRINGLESS
  223.                MOV    SI,OFFSET SEARCH
  224.                CALL   WRITE_STRING
  225.                MOV    SI,STRING_START
  226.                CALL   WRITE_STRING
  227. STRINGLESS:    CMP    PATH_FLAG,1            
  228.                JNZ    GLOBAL_SEARCH          ;If path does not exist, do global
  229.                MOV    BX,PATH_END            ; search, otherwise, change 
  230.                MOV    BYTE PTR [BX],0        ; directory and display it.
  231.                MOV    DX,PARA_START
  232.                CALL   CHANGE_DIR
  233.                CALL   PRINT_DIR
  234.                MOV    DX,SEARCH_SPEC         ;Find first matching filename.
  235.                MOV    CX,ALL_FILES           
  236.                CALL   FIND_FIRST
  237.                JC     EXIT                   ;If no match, exit.
  238.                CALL   READ_FILE              ;If string, read the file.
  239. NEXT_PATH:     CALL   FIND_NEXT              ;Loop here finding subsequent
  240.                JC     EXIT                   ; matching files until no more.
  241.                CALL   READ_FILE
  242.                JMP    SHORT NEXT_PATH
  243.  
  244. ;-------------------------------------------------------;
  245. ; This is the exit. The drive and directory is restored ;
  246. ; to how it was found. If parameters are invalid, error ;
  247. ; message is displayed, otherwise, just return to DOS.  ;
  248. ;-------------------------------------------------------;
  249.  
  250. EXIT:          MOV    DL,CURRENT_DISK        ;Change drive.
  251.                MOV    AH,0EH
  252.                INT    21H
  253.  
  254.                MOV    DX,OFFSET ROOT              ;Assume we came from root.
  255.                CMP    BYTE PTR CURRENT_DIR,0      ;If root, it will be a zero.
  256.                JZ     CHANGE_IT
  257.                MOV    BYTE PTR CURRENT_DIR,'\'    ;Else, format with "\"
  258.                MOV    DX,OFFSET CURRENT_DIR
  259. CHANGE_IT:     CALL   CHANGE_DIR             ;Change directory.
  260.                MOV    DL,13                  ;Clear printer buffer
  261.                CALL   DISPLAY                ; carriage return and linefeed.
  262.                MOV    DL,10
  263.                CALL   DISPLAY
  264.                CMP    GOOD_PARA,1
  265.                JZ     DONE
  266.                MOV    DX,OFFSET BAD_PARA
  267.                MOV    AH,9H
  268.                INT    21H                    ;Display error message if invalid.
  269. DONE:          INT    20H                    ;Terminate.
  270.  
  271. ;---------------------------------------------------------------;
  272. ; This routine will systematically change directories up and    ;
  273. ; down the directory tree, searching for the matching filename. ;
  274. ;---------------------------------------------------------------;
  275.  
  276. GLOBAL_SEARCH: MOV    DX,OFFSET ROOT         ;Start the search from root.
  277.                CALL   CHANGE_DIR
  278.                MOV    BP,OFFSET SUBSCRIPTS   ;Point to first level directory.
  279. FIRST_FILE:    CALL   PRINT_DIR              ;Print the directory.
  280.                MOV    DX,SEARCH_SPEC
  281.                MOV    CX,ALL_FILES           ;Find first matching filename
  282.                CALL   FIND_FIRST             ; in this directory.
  283.                JC     FIRST_DIR
  284.                CALL   READ_FILE
  285.  
  286. NEXT_FILE:     CALL   FIND_NEXT              ;Find next matching filename.
  287.                JC     FIRST_DIR
  288.                CALL   READ_FILE              ;If string, read the file.
  289.                JMP    SHORT NEXT_FILE        ;Loop here until no more matches.
  290.  
  291. PARENT_DIR:    CMP    BP,OFFSET SUBSCRIPTS   ;When we try to return to parent
  292.                JZ     EXIT                   ; directory and are in root, we
  293.                MOV    DX,OFFSET PARENT       ; are done. Otherwise, change
  294.                CALL   CHANGE_DIR             ; to parent directory.
  295.                MOV    BYTE PTR DS:[BP],1     ;Put one back in previous level
  296.                DEC    BP                     ; and point to parent level.
  297.  
  298.  
  299. FIRST_DIR:     XOR    BL,BL                  ;Use BL as pointer to directory no.
  300.                MOV    DX,OFFSET GLOBAL       
  301.                MOV    CX,DIR_ATTRIBUTE       ;Ask for global match.
  302.                CALL   FIND_FIRST             ;Find first matching.
  303.                JC     PARENT_DIR             
  304. CK_DIR:        CMP    BYTE PTR DTA+21,10H    ;If not a directory get next.
  305.                JNZ    NEXT_DIR
  306.                CMP    BYTE PTR DTA+30,'.'    ;If it is a dot directory get next.
  307.                JZ     NEXT_DIR
  308.                INC    BL                     ;Increment position in directory.
  309.                CMP    BL,DS:[BP]             ;Continue until new directory.
  310.                JNZ    NEXT_DIR
  311.                INC    BYTE PTR DS:[BP]       ;Update variables.
  312.                MOV    DX,OFFSET DTA+30
  313.                CALL   CHANGE_DIR             ;Change the directory.
  314.                INC    BP
  315.                JMP    SHORT FIRST_FILE       ;Get all files in new directory.
  316.  
  317. NEXT_DIR:      CALL   FIND_NEXT              ;Get all subdirectories in current
  318.                JC     PARENT_DIR             ; directory then go to parent.
  319.                JMP    SHORT CK_DIR
  320.  
  321.                ;*************;
  322.                ; SUBROUTINES ;
  323.                ;*************;
  324.  
  325. CHANGE_DIR:    MOV    AH,3BH
  326.                INT    21H
  327.                RET
  328.  
  329. CHANGE_DTA:    MOV    AH,1AH
  330.                INT    21H
  331.                RET
  332.  
  333. FIND_FIRST:    MOV    AH,4EH
  334.                INT    21H
  335.                RET
  336.  
  337. FIND_NEXT:     MOV    AH,4FH
  338.                INT    21H
  339.                RET
  340.  
  341. ;---------------------------------------------------;
  342. ; This subroutine checks for delimiting characters. ;
  343. ;---------------------------------------------------;
  344.  
  345. PARA_END:      CMP    BYTE PTR [SI],32       
  346.                JBE    SET_CARRY
  347.                CMP    BYTE PTR [SI],'/'
  348.                JZ     SET_CARRY
  349.                CLC
  350.                RET
  351. SET_CARRY:     STC
  352.                RET
  353.  
  354. ;---------------------------------------------------;
  355. ; This subroutine checks for the switch characters. ;
  356. ;---------------------------------------------------;
  357.  
  358. SWITCH:        MOV    BYTE PTR [SI-1],0      ;Zero in place of /.
  359.                MOV    BL,DS:[SI]             ;Retrieve the character.
  360.                AND    BL,5FH                 ;Capitalize.
  361.                CMP    BL,'P'
  362.                JNZ    CK_CASE
  363.                MOV    PRINT_FLAG,1
  364. CK_CASE:       CMP    BL,'C'
  365.                JNZ    CK_BINARY
  366.                MOV    CASE_FLAG,1
  367. CK_BINARY:     CMP    BL,'B'
  368.                JNZ    END_SWITCH
  369.                MOV    BINARY_FLAG,1
  370. END_SWITCH:    RET
  371.  
  372. ;---------------------------------------------------------;
  373. ; This subroutine prints the current drive and directory. ;
  374. ;---------------------------------------------------------;
  375.  
  376. PRINT_DIR:     MOV    SI,OFFSET DIRECTORY    ;Print "Directory "
  377.                CALL   WRITE_STRING
  378.                MOV    AH,19H                 ;Get current drive and display.
  379.                INT    21H
  380.                ADD    AL,'A'
  381.                MOV    DL,AL
  382.                CALL   DISPLAY
  383.                MOV    DL,':'                 ;Add the colon.
  384.                CALL   DISPLAY
  385.                MOV    DL,'\'                 ;And root.
  386.                CALL   DISPLAY
  387.                MOV    SI,OFFSET WORKING_DIR  
  388.                MOV    DL,0
  389.                MOV    AH,47H                 ;Get the current directory 
  390.                INT    21H                    ; and display.
  391.                CMP    BYTE PTR WORKING_DIR,0
  392.                JZ     END_DIR
  393.                CALL   WRITE_STRING
  394. END_DIR:       RET
  395.  
  396. ;-----------------------------------------------------------;
  397. ; This is the major subroutine. If a string is to be found, ;
  398. ; the file is opened, read and compared with the string.    ;
  399. ;-----------------------------------------------------------;
  400.  
  401. READ_FILE:     PUSH   BP                     ;Save the BP; caller is using it.
  402.                CMP    STRING_FLAG,1          ;If no string, simply display file.
  403.                JZ     BINARY_READ
  404.                JMP    PRINT_FILE
  405. BINARY_READ:   CMP    BINARY_FLAG,1          ;If /B was found open the file
  406.                JZ     OPEN_FILE              ; otherwise, skip EXE and COM files
  407.                CALL   EXE_COM
  408.                JNC    OPEN_FILE
  409.                JMP    RETURN
  410.  
  411. OPEN_FILE:     MOV    EOF_FLAG,0             ;Reset EOF and MATCH flags.
  412.                MOV    MATCH_FLAG,0
  413.                MOV    DX,OFFSET DTA+30
  414.                MOV    AX,3D00H               ;Open the file for reading.
  415.                INT    21H
  416.                MOV    BX,AX
  417. GET_FILE:      PUSH   BX                     ;Save the file handle for closing.
  418.                MOV    DX,OFFSET FILE
  419.                MOV    CX,63488               ;Attempt to read 63488 bytes.
  420.                MOV    AH,3FH
  421.                INT    21H
  422.                CMP    AX,63488               ;If less than 63488, we got
  423.                JZ     FILE_END               ; all of the file; flag so.
  424.                MOV    EOF_FLAG,1
  425. FILE_END:      CMP    AX,0                   ;If no bytes to read, close file.
  426.                JZ     CLOSE_FILE
  427.  
  428. WORDSTAR:      MOV    CX,AX
  429.                MOV    BX,OFFSET FILE
  430. STRIP:         AND    BYTE PTR DS:[BX],7FH   ;Strip the high bit for WORDSTAR.
  431.                INC    BX
  432.                LOOP   STRIP
  433.  
  434.                CMP    CASE_FLAG,1            ;If not case sensitive, capitalize.
  435.                JZ     SENSITIVE
  436.                MOV    CX,AX
  437.                MOV    BX,OFFSET FILE
  438.                CALL   CAPITALIZE
  439.  
  440. SENSITIVE:     CMP    AX,STRING_CT           ;If string count is larger than
  441.                JB     CLOSE_FILE             ; file, we are done here.
  442.                MOV    BP,AX                  ;BP will count bytes of file.
  443.                MOV    BX,OFFSET FILE         ;BX will track position in file.
  444.                MOV    DX,STRING_START        ;Store string start in DX
  445.                SUB    BP,STRING_CT           
  446.                INC    BP
  447. NEXT_BYTE:     MOV    SI,BX                  ;Recover file position.
  448.                MOV    DI,DX                  ;Recover string start.
  449.                MOV    CX,STRING_CT           ;Get string length.
  450.                MOV    AH,CL                  ;Track delimiters.
  451. LOAD_BYTE:     LODSB                         ;Get a byte.
  452.                CMP    AL,32                  ;If it is below space, skip.
  453.                JAE    COMPARE
  454.                DEC    AH                     ;Track skips so not endless loop.
  455.                JNZ    LOAD_BYTE
  456.                JMP    SHORT NEXT_LOAD
  457. COMPARE:       DEC    AH                     ;Compare with string.
  458.                SCASB
  459.                JNZ    NEXT_LOAD              ;If no match, move up in file.
  460. NEXT_COMPARE:  LOOP   LOAD_BYTE
  461.                MOV    MATCH_FLAG,1           ;If all bytes match, flag.
  462.                MOV    LINE_NUM,SI            ;Save position in file.
  463.                JMP    SHORT CLOSE_FILE       ;And close file.
  464. NEXT_LOAD:     INC    BX                     ;Otherwise, point to next byte
  465.                DEC    BP                     ;in file and decrement byte counter
  466.                JNZ    NEXT_BYTE              ;and get next byte.
  467.  
  468. EOF:           CMP    EOF_FLAG,1             ;If we did not get all the file,
  469.                JZ     CLOSE_FILE             ;return for more, otherwise close.
  470.                MOV    CX,0FFFFH              ;Bump the file pointer back the
  471.                MOV    DX,STRING_CT           ;length of the file so we will
  472.                NEG    DX                     ;not miss match at the break.
  473.                POP    BX
  474.                MOV    AX,4201H               ;Move pointer via DOS.
  475.                INT    21H
  476.                JMP    GET_FILE               ;And get more bytes.
  477.  
  478. CLOSE_FILE:    POP    BX                     ;Recover file handle.
  479.                MOV    AH,3EH                 ;And close.
  480.                INT    21H
  481.                CMP    MATCH_FLAG,1           ;if no match, return.
  482.                JNZ    RETURN
  483.  
  484. PRINT_FILE:    MOV    SI,OFFSET SPACING      ;Indent then display the file.
  485.                CALL   WRITE_STRING
  486.                MOV    SI,OFFSET DTA+30
  487.                CALL   WRITE_STRING
  488.                CMP    STRING_FLAG,1
  489.                JNZ    RETURN
  490.                CALL   PRINT_LINE             ;Print line number match was found.
  491. RETURN:        POP    BP                     ;Restore BP
  492.                RET                           ;And return.
  493.  
  494. ;------------------------------------------;
  495. ; These two subroutines do the displaying. ;
  496. ;------------------------------------------;
  497.  
  498. DISPLAY:       CMP    PRINT_FLAG,1           ;If /P, echo to the printer.
  499.                JNZ    NOT_PRINTER
  500.                MOV    AH,5
  501.                INT    21H
  502. NOT_PRINTER:   MOV    AH,2
  503.                INT    21H
  504.                RET
  505.  
  506. WRITE_IT:      MOV    DL,AL
  507.                CALL   DISPLAY
  508. WRITE_STRING:  LODSB
  509.                CMP    AL,0                   ;Zero marks end of string.
  510.                JNZ    WRITE_IT
  511.                RET
  512.  
  513. ;-------------------------------------------;
  514. ; This subroutine will capitalize the file. ;
  515. ;-------------------------------------------;
  516.  
  517. CAPITALIZE:    CMP    BYTE PTR DS:[BX],'a'
  518.                JB     NEXT_CAP
  519.                AND    BYTE PTR DS:[BX],5FH
  520. NEXT_CAP:      INC    BX
  521.                LOOP   CAPITALIZE
  522.                RET
  523.  
  524. ;------------------------------------------------------------;
  525. ; This subroutine will check to see it file is .EXE or .COM. ;
  526. ;------------------------------------------------------------;
  527.  
  528. EXE_COM:       MOV    SI,OFFSET DTA+30       ;Point to filename.
  529. EXTENSION:     LODSB                         ; and search for dot.
  530.                CMP    AL,0                   ;If zero, end of filename.
  531.                JZ     NOT_BINARY
  532.                CMP    AL,'.'
  533.                JNZ    EXTENSION
  534.                MOV    AX,SI                  ;Save extension pointer.
  535.                MOV    DI,OFFSET EXE          ;Compare first with EXE
  536.                MOV    CX,3
  537.                REP    CMPSB
  538.                JZ     BINARY
  539.                MOV    SI,AX
  540.                MOV    DI,OFFSET COM          ;Then compare with COM
  541.                MOV    CX,3
  542.                REP    CMPSB
  543.                JZ     BINARY
  544. NOT_BINARY:    CLC                           ;Return with no carry is no match.
  545.                RET
  546. BINARY:        STC                           ;Return with carry is match.
  547.                RET
  548.  
  549. ;----------------------------------------------------------------------------;
  550. ; This subroutine will calculate and display the line number for each match. ;
  551. ;----------------------------------------------------------------------------;
  552.  
  553. PRINT_LINE:    XOR    BH,BH                  ;Get the cursor position to see
  554.                MOV    AH,3                   ; if need to add a tab character
  555.                INT    10H                    ; to format the display.
  556.                CMP    DL,7                   ;If column 8 or less, add tab.
  557.                JA     NO_TAB
  558.                MOV    DL,9
  559.                CALL   DISPLAY
  560. NO_TAB:        MOV    SI,OFFSET LINE         ;Display "Line number "
  561.                CALL   WRITE_STRING
  562.                MOV    CX,LINE_NUM            ;Retrieve offset into file to
  563.                SUB    CX,OFFSET FILE         ; calculate the number of bytes
  564.                MOV    SI,OFFSET FILE         ; to look for carriage returns.
  565.                MOV    BX,1                   ;Start at line one.
  566. CK_LINE:       LODSB
  567.                CMP    AL,13                  ;Count the carriage returns.
  568.                JNZ    NEXT_LINE
  569.                INC    BX
  570. NEXT_LINE:     LOOP   CK_LINE
  571.  
  572.                MOV    DISPLAY_FLAG,0         ;Reset the display flag.
  573. TENTHS:        MOV    CX,10000               ;Get ten thousands by dividing.
  574.                CALL   DIVIDE
  575.                MOV    CX,1000                ;Get thousands by dividing.
  576.                CALL   DIVIDE
  577.                MOV    CX,100                 ;Get hundreds by dividing.
  578.                CALL   DIVIDE
  579.                MOV    CX,10                  ;Get tens by dividing.
  580.                CALL   DIVIDE
  581.                MOV    CX,1                   ;Get ones by dividing.
  582.                CALL   DIVIDE
  583.                RET
  584.  
  585. DIVIDE:        MOV    AX,BX                  ;Number in AX
  586.                XOR    DX,DX                  ; and zero in DX
  587.                DIV    CX                     ; divide by CX
  588.                MOV    BX,DX                  ; remainder into BX
  589.                MOV    DL,AL                  ; and quotient into DL.
  590.                CMP    AL,0                   ;Is it zero?
  591.                JZ     FLAG                   ;If yes, is a non zero displayed?
  592.                OR     DISPLAY_FLAG,AL        ;If non zero indicate by flag.
  593. FLAG:          CMP    DISPLAY_FLAG,0         ;Has there been a display?
  594.                JZ     END_LINE               ;If no, return.
  595.  
  596. DISP_NUMBER:   ADD    DL,30H                 ;Convert hexadecimal to decimal
  597.                CALL   DISPLAY                ;And display.
  598. END_LINE:      RET
  599.  
  600.  
  601. SUBSCRIPTS:
  602. CURRENT_DIR    EQU    SUBSCRIPTS+100
  603. WORKING_DIR    EQU    CURRENT_DIR+64
  604. DTA            EQU    WORKING_DIR+64
  605. FILE           EQU    DTA+65
  606. CODE ENDS
  607. END  START
  608.