home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l040 / 11.ddi / WHEREIS.ZIP / IFINDFIL.ASM < prev    next >
Encoding:
Assembly Source File  |  1992-10-27  |  14.0 KB  |  395 lines

  1.  
  2. ;   FILENAME: IFINDFIL.ASM
  3. ;
  4. ;   Copyright (c) 1988, 1992 by Borland International, Inc.
  5. ;
  6. ;   DESCRIPTION:  This module implement a routine that performs a recursive
  7. ;   search through a hard disk of a specified file.
  8. ;
  9. ;   ASSEMBLY INSTRUCTIONS: To assemble this module use the following
  10. ;   TASM command line.
  11. ;
  12. ;       TASM /dMDL=memorymodel ifindfil
  13. ;
  14. ;   'memorymodel' in the above command line may be replaced by TINY, SMALL,
  15. ;   MEDIUM, COMPACT, LARGE or HUGE. If assembling this module to run on
  16. ;   a 286/386 machine, turn on the P286 directive in order to take advantage of
  17. ;   286/386 specific instructions. For example:
  18. ;
  19. ;       TASM /dMDL=memorymodel /jP286 ifindfil
  20.  
  21. jumps
  22.  
  23. %tabsize 4
  24.  
  25. ifndef  MDL
  26.     display "Error: This module requires that you provide a memory model"
  27.     display "    definition on the command line. I.E. /dMDL=SMALL."
  28.     err ; Force a fatal error
  29. else
  30.     ideal                   ; Use TASM's Ideal mode
  31. %   model   MDL,pascal      ; Define the memory model
  32.  
  33.     include "iwhglobl.inc"
  34.     include "imacros.mac"
  35.     include "idos.inc"
  36.     include "dos.inc"
  37.     include "idos.mac"
  38.     include "kbd.inc"
  39.     include "bios.inc"
  40.     include "ibios.mac"
  41.  
  42.         global      BreakPressed:byte  ; Check this often for a nonzero
  43.                                        ; value. Terminate if a nonzero
  44.                                        ; value is found.
  45.     dataseg
  46.         AllFiles    db  "*.*",0     ; ASCIIZ string representing all files
  47.         SwitchChar  db  1,'\'       ; Directory seperating character
  48.         CurrentDir  db  MAX_PATH_LENGTH dup (0)
  49.         MakePascalString BlankLine, <13, 10>
  50.  
  51.         ; The following variable keep track of going through the
  52.         ; file specifications that were given on the command line.
  53.         FileSpecIndex db ?
  54.         FileSpecPtr   dw ?
  55.  
  56.  
  57.     codeseg
  58.  
  59.     macro   NewLine                 ; Force a new line
  60. ;;        ifdef  _286_
  61. ;;            push    seg BlankLine
  62. ;;            push    offset BlankLine
  63. ;;        else
  64. ;;            mov     ax, seg BlankLine
  65. ;;            push    ax
  66. ;;            mov     ax, offset BlankLine
  67. ;;            push    ax
  68. ;;        endif
  69.         call    WritePascalString,seg BlankLine,offset BlankLine
  70.     endm
  71.  
  72. TerminateKeyMssg db 13,10
  73.                  db '**ERROR** Whereis terminated due to keypress.'
  74.                  db 13,10,0
  75.  
  76.     ; The following messages should not include a line feed.
  77. PauseKeyMssg      db 'Press space to continue....',13,0
  78. PauseKeyEraseMssg db '                           ',13,0
  79.  
  80.     proc    FindFiles
  81.  
  82.     ;   This routine does a recursive search down through the directory
  83.     ;   structure of a disk looking for a file. If the routine finds a
  84.     ;   match it displays the complete drive\path\filename. The routine
  85.     ;   uses the following algorithm:
  86.     ;
  87.     ;       make room for a local copy of the Dta
  88.     ;       change directories to the location of the file we're looking for
  89.     ;       find all matches in the current directory
  90.     ;       for each sub-directory in the current directory
  91.     ;           Do a recursive call to this routine
  92.     ;       restore the original directory
  93.     ;
  94.     ;   The routine uses the global variable FileSpec as the specification
  95.     ;   of the file to search for.
  96.     ;   If any key is pressed, a message is printed and then this routine
  97.     ;   calls Terminate.
  98.     ;
  99.     ;   Input
  100.     ;       DS - points to the segment in which FileSpec resides
  101.     ;       Path - A pascal style string representing the path in which to
  102.     ;              search for the file
  103.     ;   Output
  104.     ;       none
  105.     ;   Calling convention
  106.     ;       Pascal
  107.     ;   Registers modified
  108.     ;       ax, bx, cx, dx, si, es, flags
  109.  
  110.     arg     Path:byte:MAX_PATH_LENGTH=PARM_SIZE
  111.     local   DataTransferArea:byte:DTA_SIZE=LOCAL_SIZE ;
  112.  
  113.     ; The PASCAL calling convention on the MODEL statement causes TASM
  114.     ; to do the following automatically.
  115. ;        push    bp
  116. ;        mov     bp, sp
  117. ;        ; make room for the Dta, Drive, Path and Filename on the stack
  118. ;        sub     sp, LOCAL_SIZE
  119.  
  120.         mov     [FileSpecIndex],1       ; Keep track which one we are searching
  121.         mov     [FileSpecPtr],offset FileSpec
  122.  
  123.  
  124.         mov     si, bp                  ; Get the address of the Dta buffer
  125.         sub     si, DTA_SIZE
  126.         push    ds                      ; Store ds before call to SetDTA
  127.         SetDTA  <ss>, <si>              ; Set the current Dta address
  128.         pop     ds                      ; Restore ds after SetDTA
  129.         if @CodeSize eq 0               ; FindFiles is near
  130.             add     si, DTA_SIZE + 5    ; Get the address of the Path
  131.         else
  132.             add     si, DTA_SIZE + 7    ; Get the address of the Path
  133.         endif
  134.  
  135.         xor     bx, bx
  136.         mov     bl, [byte ss:si-1]      ; Get the length byte
  137.         cmp     bl, 1                   ; Check if the path is 1 letter. If it
  138.         jle     ChangeDirs              ; is we don't want to remove it.
  139.         cmp     [byte ss:si+bx-1], '\'  ; Check if the path ends with a '\'. If
  140.         jne     ChangeDirs              ; it does, remove it.
  141.         mov     [byte ss:si+bx-1], 0
  142.         dec     [byte ss:si-1]
  143.     ChangeDirs:
  144.         push    ds
  145.         ChangeDirectory <ss>, <si>      ; Change the directory
  146.         GetCurrentDir   <0>, <seg CurrentDir>, <offset CurrentDir>
  147.         pop     ds
  148.         if (@Cpu and 100b) eq 100b
  149.             push    seg CurrentDir
  150.             push    offset CurrentDir
  151.         else
  152.             mov     ax, seg CurrentDir
  153.             push    ax
  154.             mov     ax, offset CurrentDir
  155.             push    ax
  156.         endif
  157.         mov     ax, 0020h               ; Replace spaces with 0
  158.         mov     cx, MAX_PATH_LENGTH
  159.         call    FindAndReplace
  160.  
  161.     FirstFile:
  162.         mov     ax,[FileSpecPtr]
  163.         inc     ax                      ; Get past length byte
  164.         FindFirst   <0FFh>, <ds>, <ax>
  165.     NextFile:                           ; Find each of the matching files
  166.         cmp     ax, 0
  167.         jne     CheckNextFileSpec
  168.  
  169.         ; Check if the user has pressed a key to interrupt WHEREIS.
  170.         GetKbdStatus
  171.         jz      NoKey
  172.  
  173.         call    KeyWasPressed
  174.  
  175.  
  176.         ; Come here to print a matching file.
  177.     NoKey:
  178.         if (@Cpu and 100b) eq 100b
  179.             push    seg Drive           ; Get the address of the drive
  180.             push    offset Drive        ; description
  181.         else
  182.             mov     ax, seg Drive
  183.             push    ax
  184.             mov     ax, offset Drive
  185.             push    ax
  186.         endif
  187.         mov     al, [Drive]
  188.         xor     ah, ah
  189.         call    WritePascalString       ; Display the drive description
  190.         mov     ax, seg CurrentDir
  191.         mov     es, ax
  192.         mov     di, offset CurrentDir
  193.         cmp     [byte es:di], 'A'       ; Check if the string is empty
  194.         jl      DontNeedBackSlash
  195.         dec     di                      ; Decrement the offset of the pointer
  196.     DontNeedBackSlash:
  197.         push    es
  198.         push    di
  199.         call    WriteASCIIZString
  200.         if (@Cpu and 100b) eq 100b
  201.             push    seg SwitchChar
  202.             push    offset SwitchChar
  203.         else
  204.             mov     ax, seg SwitchChar
  205.             push    ax
  206.             mov     ax, offset SwitchChar
  207.             push    ax
  208.         endif
  209.         call    WritePascalString
  210.  
  211.         mov     si, bp
  212.         sub     si, DTA_SIZE - (offset (Dta).Filename)
  213.         push    ss  si  ; Push an extra copy of offset of filename
  214.  
  215.         ; Write the filename. Pass the address of the filename
  216.         call    WriteASCIIZString,ss,si
  217.         NewLine
  218.  
  219.         pop     si ax  ; Offset of filename   ax:si
  220.         mov     di,offset CurrentDir
  221.         push    ds                      ; Store ds before call to
  222.                                         ; ExecuteDosCommand and SetDTA
  223.         call    ExecuteDosCommand       ; Do the command for the file.
  224.  
  225.         mov     si, bp                  ; Get the address of the Dta buffer
  226.         sub     si, DTA_SIZE
  227.         SetDTA  <ss>, <si>              ; Set the current Dta address
  228.         pop     ds                      ; Restore ds after SetDTA
  229.  
  230.         FindNext
  231.         jmp     NextFile
  232.  
  233.     CheckNextFileSpec:
  234.         cmp     [BreakPressed],0        ; Check for CTRL-BREAK
  235.         jnz     GiveAbortMessage
  236.  
  237.         add     [FileSpecPtr],FILE_SPEC_SIZE    ; Point to next filespec
  238.         mov     al,[FileSpecIndex]              ; Bump up counter
  239.         inc     al
  240.         mov     [FileSpecIndex],al
  241.         cmp     al,[FileSpecCounter]
  242.         jle     FirstFile                       ; Go back to search another filespec
  243.  
  244.     CheckDirectories:
  245.         push    ds
  246.         FindFirst   <010000b>, <(seg AllFiles)>, <(offset AllFiles)>
  247.         pop     ds
  248.     NextDirectory:
  249.         cmp     ax, 0                   ; Check if we've found a sub-directory
  250.         je      CheckAttributes
  251.         jmp     Exit
  252.     CheckAttributes:                    ; Check if it's a directory
  253.         mov     si, bp                  ; Get the address of the attribute
  254.         sub     si, DTA_SIZE - (offset (Dta).FileAttribute)
  255.         mov     al, [byte ss:si]        ; Get the directory entries attributes
  256.         and     al, 10000b
  257.         cmp     al, 10000b
  258.         jne     GetNextDirectory
  259.  
  260.         ; Check if the directory is '.' or '..'
  261.  
  262.         mov     si, bp                  ; Get the address of the attribute
  263.         sub     si, DTA_SIZE - (offset (Dta).Filename)
  264.         cmp     [byte ss:si], '.'       ; If it's '.' or '..' then skip
  265.         je      GetNextDirectory        ; it
  266.  
  267.         ; Copy the new path onto the stack
  268.  
  269.         sub     sp, MAX_PATH_LENGTH     ; Make room on the stack
  270.         mov     bx, sp
  271.         push    ss                      ; Push segment address of Path
  272.         mov     si, bp
  273.         if @CodeSize eq 0               ; FindFiles is near
  274.             add     si, 4               ; get offset of current path string
  275.         else
  276.             add     si, 6
  277.         endif
  278.         push    si                      ; Push offset of path
  279.         push    ss                      ; Push address to copy to
  280.         push    bx
  281.         mov     al, [byte Path]         ; Get the path length
  282.         inc     al                      ; Copy the length byte also
  283.         call    ByteCopy                ; Copy the path onto the stack
  284.  
  285.         ; Append the new directory to the path on the stack
  286.  
  287.         push    es di                   ; Save es:di before call to
  288.                                         ; GetASCIIZStrLen
  289.         mov     si, bp                  ; Get the address of the current Dta
  290.  
  291.         ; Get the address of the directory name from it's location in the Dta
  292.  
  293.         sub     si, DTA_SIZE - (offset (Dta).Filename)
  294.         call    GetASCIIZStrLen,ss,si   ; Get the length of the directory name
  295.         pop     di es                   ; Restore es:di
  296.  
  297.         cmp     [byte es:di-1], '\'     ; Check if the path on the stack ends
  298.         je      HasBackSlash            ; with a '\'. If not append one.
  299.         mov     [byte es:di], '\'
  300.         inc     di
  301.         push    si
  302.         mov     si, sp                  ; Adjust the length byte of the string
  303.         inc     [byte ss:si+2]
  304.         pop     si
  305.     HasBackSlash:
  306.         ; Copy the directory name
  307.         call    ByteCopy,ss,si, \       ; Address of the directory name.
  308.                          es,di          ; Address to copy directory name to
  309.  
  310.         mov     si, sp                  ; Adjust the length byte of the string
  311.         dec     al                      ; we appended to. Don't include the
  312.         add     [byte ss:si], al        ; terminating 0 in the length
  313.  
  314.         ; Do recursive call
  315.  
  316.         call    FindFiles               ; Do the search for the file(s)
  317.         push    ds
  318.         mov     ax, bp
  319.         if  @CodeSize eq 0              ; Near code models
  320.             add     ax, 5
  321.         else
  322.             add     ax, 7
  323.         endif
  324.         ChangeDirectory <ss>, <ax>      ; Change to the directory that was
  325.         pop     ds                      ; active before the recursive call
  326.  
  327. ;; Remember, the following cleanup is done automatically by Pascal Model.
  328. ;;        add     sp, MAX_PATH_LENGTH     ; Remove space allocated on the stack
  329.  
  330.         mov     si, bp
  331.         sub     si, DTA_SIZE
  332.         push    ds
  333.         SetDTA  <ss>, <si>              ; Restore the Dta
  334.         pop     ds
  335.     GetNextDirectory:
  336.         FindNext                        ; Find the next sub-directory
  337.         jmp     NextDirectory
  338.     Exit:
  339.  
  340.      ; Once again, the cleanup is done automatically because of PASCAL model.
  341. ;        add     sp, LOCAL_SIZE
  342. ;        pop     bp
  343.         ret
  344.     endp    FindFiles
  345.  
  346.  
  347.     proc    KeyWasPressed
  348.  
  349.     ;   This routine handles pausing if a space or ^S was pressed,
  350.     ;   or terminating WHEREIS if any other key was pressed.
  351.  
  352.         ; Throw out the key(s) that were pressed.
  353.     DiscardKeys:
  354.         GetChar
  355.         cmp     al,' '          ; Check for space pressed to pause
  356.         je      JustPausing
  357.         cmp     al,'s'-'a'+1    ; Check for ^S pressed to pause
  358.         je      JustPausing
  359.  
  360.     FlushKeyboard:
  361.         GetKbdStatus
  362.         jz   GiveAbortMessage
  363.         GetChar
  364.         jmp  FlushKeyboard
  365.  
  366.  
  367.     GiveAbortMessage:
  368.         ; Give a message to the user that WHEREIS is terminating.
  369.         call    WriteASCIIZString,seg TerminateKeyMssg,offset TerminateKeyMssg
  370.  
  371.         call    Terminate
  372.  
  373.  
  374.     JustPausing:
  375.         ; Give a message to the user that WHEREIS is pausing
  376.         call    WriteASCIIZString,seg PauseKeyMssg,offset PauseKeyMssg
  377.  
  378.     WaitForSpace:
  379.         GetKbdStatus
  380.         jz   WaitForSpace
  381.         GetChar
  382.         cmp  al,' '
  383.         jne  FlushKeyboard
  384.  
  385.         ; Now get rid of the reminder
  386.         call    WriteASCIIZString,seg PauseKeyEraseMssg,offset PauseKeyEraseMssg
  387.  
  388.         ret
  389.     endp    KeyWasPressed
  390.  
  391.  
  392. endif   ; ifndef MDL
  393.  
  394. end
  395.