home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l224 / 2.img / TAEXMPL1.ZIP / IWHEREIS.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-10-29  |  19.5 KB  |  613 lines

  1. ;   FILENAME: IWHEREIS.ASM
  2. ;
  3. ;   Copyright (c) 1988, 1990 by Borland International, Inc.
  4. ;
  5. ;   DESCRIPTION:  This program does a search for the file(s) specified on the
  6. ;   command line. It can also perform a DOS command on each file that is
  7. ;   found.
  8. ;
  9. ; Syntax: WHEREIS [d:][path]filename filename filename... [dos_command]
  10. ;  dos_command is a command surrounded by "",'', or []. It will be called
  11. ;  for each file that is found. It should include at least one of these:
  12. ;     %1 - Insert full path, filename and extension
  13. ;     %2 - Filename and extension (no path)
  14. ;     %3 - Only the path.
  15. ;     %4 - Only the filename before the extension followed by a .
  16. ;     %5 - Only the extension, preceeded by a .
  17. ;  For example to delete all .BAK files on a drive:
  18. ;     WHEREIS  *.BAK [DEL %2]",13,10>
  19. ;
  20. ;   Note that dos_command may be any valid DOS command, including invoking
  21. ;   batch files or built-in DOS commands. Note that the RMDIR, (also RD),
  22. ;   command should not be used on the directory that WHEREIS is currently
  23. ;   executing in.
  24. ;
  25. ;
  26. ;   ASSEMBLY INSTRUCTIONS: To assemble this module use the following
  27. ;   TASM command line.
  28. ;
  29. ;       TASM /m /dMDL=memorymodel iwhereis
  30. ;
  31. ;   /m in the above command line allows TASM to use extra passes to resolve
  32. ;   jumps and other operations to their shortest form and get rid of extra NOPs.
  33. ;   'memorymodel' in the above command line may be replaced by TINY, SMALL,
  34. ;   MEDIUM, COMPACT, LARGE or HUGE. If assembling this module to run on
  35. ;   a 286/386 machine, turn on the P286 directive in order to take advantage of
  36. ;   286/386 specific instructions. For example:
  37. ;
  38. ;       TASM /m /dMDL=memorymodel /jP286 iwhereis
  39. ;
  40. ;   SYSTEM REQUIREMENTS:
  41. ;       TASM 2.0
  42. ;       256K
  43. ;       DOS 2.0 or later
  44.  
  45. ; TURBO ASSEMBLER NEW FEATURES:
  46. ; TASM 2.0 has many new features. The following is a list of a few of
  47. ; them that have been used to make this program easier and more readable.
  48. ; To find the examples in the code, just seach for "**n", where n is a
  49. ; number from the following table.
  50.  
  51. ; Special TASM 2.0 features:
  52. ;    **1  - TASM automatically pushes the immediate value in a way that
  53. ;           preserves all registers if the processor mode is 8086. If
  54. ;           186 or above, then TASM pushes the value directly.
  55. ;    **2  - Many lines of assembler are replaced by the use of the
  56. ;           extended call syntax.
  57. ;    **3  - Conditional jumps that go out of range are automatically
  58. ;           adjusted to a different code sequence that allows the
  59. ;           further jump. Other jumps, even if forward referenced, are
  60. ;           automatically changed to the shortest possible code sequence
  61. ;           without extra NOPs, because of multipass capability.
  62. ;    **4  - TASM handles forward referenced variables that occur
  63. ;           in a segment other than DS: by automatically inserting
  64. ;           the proper segment override, and without causing phase errors.
  65. ;    **5  - TASM's ability to handle multiple objects on a single
  66. ;           PUSH or POP command makes coding shorter.
  67. ;    **6  - TASM's new line continuation feature while in IDEAL mode
  68. ;           makes long argument lists very easy.
  69.  
  70.  
  71. jumps      ; Have TASM automatically resolve out of range jumps
  72.  
  73. %tabsize 4
  74.  
  75. ifndef  MDL
  76.     display "Error: This module requires that you provide a memory model"
  77.     display "    definition on the command line. I.E. /dMDL=SMALL."
  78.     err ; Force a fatal error
  79. else
  80.  
  81.     ideal                   ; Use TASM's Ideal mode
  82.     model   MDL,pascal      ; Define the memory model
  83.                             ; Set language to PASCAL so we can rely on TASM's
  84.                             ; new extended call features.
  85.  
  86.     Version EQU "2.01"
  87.  
  88.     include "iwhglobl.inc"  ; Public symbol declarations
  89.     include "imacros.mac"   ; Various macros
  90.     include "bios.inc"
  91.     include "ibios.mac"
  92.     include "kbd.inc"      ; Keyboard scan codes
  93.     include "dos.inc"      ; Equates representing DOS functions/services
  94.     include "idos.mac"
  95.  
  96.     stack   7FFFh           ; Allocate 32K stack
  97.  
  98.  
  99.  
  100.  
  101.     codeseg
  102.     SavedDS     dw  ?       ; For the control-break handler to find the path
  103.                             ; variables for restoring the original path and
  104.                             ; drive.
  105.  
  106.     BreakPressed    db 0    ; Set by Int1B handler to one if
  107.                             ; CTRL-BREAK pressed. Allows us to break even
  108.                             ; if DOS BREAK is set to off.
  109.     global BreakPressed:byte     ; So other modules can check it!
  110.  
  111.  
  112.     dataseg
  113.  
  114.     PspAddress  dw  ?       ; Segment address of Program Segment Prefix(PSP)
  115.     DisplayPage db  0       ; Current display page
  116.  
  117.     Old1BHandlerSeg dw ?
  118.     Old1BHandlerOfs dw ?
  119.  
  120.  
  121.     include "WHUSAGE.INC"   ; Usage screen declaration
  122.  
  123.     ; Pascal style strings to store the parsed file specification.
  124.  
  125.     Drive       db  0," :  "
  126.     Path        db  MAX_PATH_LENGTH  dup (0)
  127.  
  128.     ; Following is used as a scratchpad when parsing additional filespecs
  129.     ; from the command line.
  130.     tempDrive   db  0," :  "
  131.     tempPath    db  MAX_PATH_LENGTH  dup (0)
  132.  
  133.  
  134.     FileSpecCounter db 0    ; Count how many filespecs we parsed
  135.     NextFileSpec    dw 0    ; Location of where to put next filespec
  136.  
  137.     DrivePtr    dw   ?      ; Points to where the file parse routine should
  138.     PathPtr     dw   ?      ; place its results.
  139.  
  140.  
  141.     FileSpec    db  MAX_FILE_SPECS dup (FILE_SPEC_SIZE dup (0))
  142.                             ; Make room for the filenames, each with a
  143.                             ; preceeding length byte and terminating 0
  144.  
  145.     db  '\'
  146.     HomeDirectory   db  MAX_PATH_LENGTH dup (0)
  147.     OldDrive        db  ?
  148.  
  149.     ; When working through the arguments on the command line to setup
  150.     ; filespecs,
  151.     CurrentArgument db  MAX_PATH_LENGTH+FILE_SPEC_SIZE dup (0)
  152.  
  153.     codeseg
  154.  
  155.     proc    GetArgument
  156.     ;   This procedure gets an argument transfered into a temporary
  157.     ;   buffer where all leading spaces are removed from the string.
  158.     ;
  159.     ;   Input
  160.     ;       AL contains number of argument to get.
  161.     ;   Output
  162.     ;       If argument exists:
  163.     ;          AL number of argument
  164.     ;          ES:DI points to temporary argument buffer
  165.     ;       If argument does not exist:
  166.     ;          AL contains 0
  167.     ;   Calling conventions
  168.     ;       NA
  169.     ;   Registers modified
  170.     ;       all
  171.  
  172.         call    ParamString
  173.         or      al,al
  174.         jz      @@Finished      ; A zero return means no more arguments.
  175.  
  176.  
  177.  
  178.         push    ax              ; Save it to restore return value from ParamString
  179.  
  180. ; **2
  181. ;   The following lines are neatly replaced by a single line CALL with
  182. ;   extended syntax. All the variables are automatically pushed on the
  183. ;   stack in the proper order, automatically.
  184. ;
  185. ;        push    es
  186. ;        push    di
  187. ;
  188. ;        if (@Cpu and 100b) eq 100b
  189. ;            push    seg CurrentArgument
  190. ;        else
  191. ;            mov     ax, seg CurrentArgument
  192. ;            push    ax
  193. ;        endif
  194. ;        if (@Cpu and 100b) eq 100b
  195. ;            push    offset CurrentArgument
  196. ;        else
  197. ;            mov     ax, offset CurrentArgument
  198. ;            push    ax
  199. ;        endif
  200.  
  201.         xor     ah,ah
  202.         mov     al,[byte es:di]
  203.         inc     ax
  204.  
  205.         call    ByteCopy,es,di,seg CurrentArgument,Offset CurrentArgument
  206.  
  207.     @@DeleteSpaces:
  208.         cmp     [CurrentArgument+1], SPACE
  209.         jne     @@NoMoreSpaces
  210.  
  211. ; **2
  212. ;        if (@Cpu and 100b) eq 100b
  213. ;            push    seg CurrentArgument
  214. ;        else
  215. ;            mov     ax, seg CurrentArgument
  216. ;            push    ax
  217. ;        endif
  218. ;        if (@Cpu and 100b) eq 100b
  219. ;            push    offset CurrentArgument
  220. ;        else
  221. ;            mov     ax, offset CurrentArgument
  222. ;            push    ax
  223. ;        endif
  224.  
  225.         mov     cx, 1           ; Remove the first character
  226.         mov     ax, 1           ; from the string
  227.         call    DeleteChar,seg CurrentArgument,offset CurrentArgument
  228.  
  229.         jmp     @@DeleteSpaces
  230.     @@NoMoreSpaces:
  231.         mov     ax,seg CurrentArgument
  232.         mov     es,ax
  233.         mov     di,offset CurrentArgument
  234.  
  235.         pop     ax
  236.  
  237.  
  238.  
  239.     @@Finished:
  240.         ret
  241.     endp    GetArgument
  242.  
  243.  
  244.  
  245.     dataseg
  246.  
  247. MakePascalString  SearchMssg,<"WHEREIS parameters:",13,10>
  248.  
  249.     codeseg
  250.     proc    Show_Args
  251.     ;   This procedure displays all the command line parameters sent
  252.     ;   to the program.
  253.     ;
  254.     ;   Input
  255.     ;       none
  256.     ;   Output
  257.     ;       none
  258.     ;   Calling conventions
  259.     ;       NA
  260.     ;   Registers modified
  261.     ;       all
  262.  
  263.         push es di ax                 ;**5
  264.         call WritePascalString,ds,offset SearchMssg
  265.         mov  [argcount],1             ;**4
  266.  
  267.     @@Show_loop:
  268.         mov  al,[argcount]
  269.         call GetArgument
  270.         or   al,al         ; Check for zero return. Means no more arguments.
  271.         jz   @@Show_Exit
  272.  
  273.         call WritePascalString,es,di  ; Show the current argument
  274.  
  275.         push seg BlankLine            ;**1
  276.         push offset BlankLine
  277.         call WritePascalString
  278.  
  279.         inc  [argcount]               ;**4
  280.         jmp  @@Show_loop
  281.  
  282.     @@Show_Exit:
  283.         pop  ax di es                 ;**5
  284.         ret
  285.  
  286.     argcount db 1                     ;**4
  287.     endp    Show_Args
  288.  
  289.  
  290.  
  291.     proc Main
  292.  
  293.     ;************************* Program Entry Point ***************************
  294.     ; Execution of the program begins here.
  295.  
  296.     EntryPoint:
  297.         mov     ax, @data       ; Initialize ds by moving segment address
  298.         mov     ds, ax          ; of data segment into ds register
  299.         push    bp              ; Setup a starting stack frame.
  300.         mov     bp, sp
  301.  
  302.         call    Initialize      ; Initialize data structures, etc.
  303.  
  304.         call    Show_Args
  305.  
  306.  
  307.         mov     [FileSpecCounter],0  ; FileSpecCounter has # files found so far
  308.         mov     [NextFileSpec],offset FileSpec
  309.         mov     [PathPtr],offset Path
  310.         mov     [DrivePtr],offset Drive
  311.  
  312.  
  313.         mov     al,[FileSpecCounter]
  314.     ProcessFileSpec:                 ; Jump to here if AL already loaded
  315.         cmp     al,MAX_FILE_SPECS
  316.         je      @@StartFileSearch    ;**3
  317.  
  318.         inc     al
  319.         call    GetArgument
  320.         or      al,al
  321.         jz      @@StartFileSearch    ; If al=0, we are at the end of arguments.
  322.  
  323.         mov     al,[byte es:di+1]
  324.         call    IsDelimiter
  325.         jc      HandleDosCommand
  326.  
  327. ; **2
  328. ;        push    es              ; Store the location of the unparsed file spec.
  329. ;        push    di
  330. ;
  331. ;        ; Pull apart the drive, path and filename so we can store the
  332. ;        ; filename specification.
  333. ;
  334. ;        push    ds              ; Push the address to store the drive spec. in
  335. ;        if (@Cpu and 100b) eq 100b
  336. ;            push    offset Drive
  337. ;        else
  338. ;            mov     ax, offset Drive
  339. ;            push    ax
  340. ;        endif
  341. ;        push    ds              ; Push the address to store the path spec. in
  342. ;        if (@Cpu and 100b) eq 100b
  343. ;            push    offset Path
  344. ;        else
  345. ;            mov     ax, offset Path
  346. ;            push    ax
  347. ;        endif
  348. ;        push    ds              ; Push address to store filename spec. in
  349. ;        if (@Cpu and 100b) eq 100b
  350. ;            push    offset FileSpec
  351. ;        else
  352. ;            mov     ax, offset FileSpec
  353. ;            push    ax
  354. ;        endif
  355.  
  356.         ; Parse the filename into it's components
  357.         call    ParseFilename,es,di, \             ;Filespec to be parsed
  358.                               ds,[DrivePtr],   \   ;**6
  359.                               ds,[PathPtr],    \
  360.                               ds,[NextFileSpec]
  361.  
  362.         mov     al,[FileSpecCounter]
  363.         or      al,al
  364.         jz      CheckFirstArg     ; If al is zero, we are checking first
  365.                                   ; argument, so we can allow drive and
  366.                                   ; path specification.
  367.  
  368.         mov     bx,[PathPtr]
  369.         cmp     [byte bx], 0      ; Check if the parsed path is empty
  370.         jne     @@IllegalPath
  371.         mov     bx,[DrivePtr]     ; Check if the parsed drive is empty
  372.         cmp     [byte bx],0
  373.         jne     @@IllegalPath
  374.  
  375.         jmp     @@GetAnotherFileSpec
  376.  
  377.     @@IllegalPath:                ; Give an error for path on parameter other
  378.                                   ; than the first.
  379.         call    PathAfterFirst
  380.  
  381.  
  382.     CheckFirstArg:
  383.        ; For the next arguments, set the pointers to dummy areas
  384.        ; since we don't pay attention to the path and drive for
  385.        ; arguments other than the first.
  386.         mov     [PathPtr],offset tempPath
  387.         mov     [DrivePtr],offset tempDrive
  388.  
  389.         cmp     [byte Path], 0          ; Check if the path is empty
  390.         jne     HaveAPath
  391.         mov     [byte Path], 1
  392.         mov     [byte Path+1], '\'
  393.     HaveAPath:
  394.         cmp     [byte Drive], 0         ; Check if a drive definition exists
  395.         je      DontChangeDrives
  396.         cmp     [byte Drive+1], 61h     ; Check if the drive letter is lower
  397.         jng     IsCapitalized           ; case
  398.         sub     [byte Drive+1], 20h     ; Capitalize the drive letter
  399.     IsCapitalized:
  400.         mov     al, [byte Drive+1]
  401.         sub     al, 'A'
  402.         ChangeDrive <al>                ; Change to the appropriate drive
  403.         jmp     DoneWithFirstArg
  404.     DontChangeDrives:
  405.         mov     [byte Drive], 2         ; Initialize the drive
  406.         mov     al, [byte OldDrive]
  407.         mov     [byte Drive+1], al      ; string with the
  408.         add     [byte Drive+1], 'A'     ; current drive.
  409.     DoneWithFirstArg:
  410.         jmp     @@GetAnotherFileSpec
  411.  
  412.  
  413.     HandleDosCommand:
  414.         ; If a DOS command is given, it is surrounded by quotes.
  415.         ; We need to strip the quotes, and store it in the module that
  416.         ; handles executing DOS commands.
  417.         call    ParseDosCommand
  418.         jnc     @@DoneWithArg           ; If no errors, we are done with this arg
  419.         call    OnlyOneDosCommand
  420.  
  421.     @@GetAnotherFileSpec:
  422.         add     [NextFileSpec],FILE_SPEC_SIZE
  423.  
  424.         ; Increment the FileSpecCounter
  425.         mov     al,[FileSpecCounter]
  426.         inc     al
  427.         mov     [FileSpecCounter],al  ; FileSpecCounter has # files found so far
  428.     @@DoneWithArg:
  429.         jmp     ProcessFileSpec
  430.  
  431.     @@StartFileSearch:
  432.         ; We are now done analyzing the command line parameters.
  433.         ; Copy the start path onto the stack
  434.  
  435.         sub     sp, MAX_PATH_LENGTH     ; Make room on the stack
  436.         mov     si, sp
  437.  
  438.         xor     ah, ah
  439.         mov     al, [byte Path]         ; Get the path length
  440.         inc     al                      ; We want to copy the length byte also
  441.         inc     al                      ; And the null terminator
  442.         call    ByteCopy,ds,offset Path,ss,si   ; Copy the path onto the stack
  443.  
  444.  
  445.         call    FindFiles               ; Do the search for the file(s)
  446.         call    Terminate               ; End the program
  447.     ;*************************************************************************
  448.     endp    main
  449.  
  450.  
  451.     proc    Terminate
  452.  
  453.     ;   This procedure handles exiting from WHEREIS and restoring the
  454.     ;   original directory and drive.
  455.  
  456.         mov     ax, [SavedDS]
  457.         mov     ds,ax
  458.         mov     al, [byte OldDrive]     ; Get the original disk drive
  459.         ChangeDrive <al>                ; Restore the original disk drive
  460.         ChangeDirectory <seg HomeDirectory>, <((offset HomeDirectory) - 1)>
  461.  
  462.         mov     es,[Old1BHandlerSeg]
  463.         mov     bx,[Old1BHandlerOfs]
  464.         SetVector  1Bh, es, bx
  465.  
  466.         mov     ah, DOS_TERMINATE_EXE
  467.         int     DOS_FUNCTION
  468.     endp    Terminate
  469.  
  470.  
  471.     proc    Int1B far
  472.  
  473.     ;   This procedure handles intercepting CTRL-BREAK so that the
  474.     ;   main directory searching loop can break out.
  475.  
  476.         mov     [BreakPressed],1        ; Set break flag
  477.         iret
  478.  
  479.     endp    Int1B
  480.  
  481.  
  482.  
  483.     proc    Initialize
  484.  
  485.     ;   This procedure initializes all global variables and data structures
  486.     ;   used by the program.
  487.     ;
  488.     ;   Input
  489.     ;       none
  490.     ;   Output
  491.     ;       none
  492.     ;   Calling conventions
  493.     ;       NA
  494.     ;   Registers modified
  495.     ;       ax, flags
  496.  
  497.         ; Store the PSP address by storing es in the variable PspAddress.
  498.         ; Note that we do it this way instead of using DOS function 62h because
  499.         ; the function is only available on DOS 3.0 or later.
  500.  
  501.         mov     [PspAddress], es
  502.  
  503.         push    ds
  504.         GetCurrentDir   <0>, <seg HomeDirectory>, <offset HomeDirectory>
  505.         pop     ds
  506.         GetDrive                        ; Get the current disk drive
  507.         mov     [byte OldDrive], al     ; Save it
  508.  
  509.  
  510.         ; Install a control break handler.
  511.         push    ds
  512.         mov     ax,ds         ; Save DS for future reference by break handler!
  513.         mov     [SavedDS],ax
  514.         SetVector  23h,<seg Terminate>,<offset Terminate>
  515. ;        mov     ah,25h        ; Int 25 = Set interrupt
  516. ;        mov     al,23h
  517. ;        mov     dx,seg Terminate
  518. ;        mov     ds,dx
  519. ;        mov     dx,offset Terminate
  520. ;        int     21h
  521.  
  522.         ; Also, so the main loop for going thru directories can respond
  523.         ; in a timely fashion to ctrl-break being pressed, install a
  524.         ; handler for vector 1Bh.
  525.  
  526.         GetVector  1Bh
  527.  
  528.         pop     ds
  529.         mov     [Old1BHandlerSeg],es
  530.         mov     [Old1BHandlerOfs],bx
  531.         push    ds
  532.  
  533.         SetVector  1Bh, <seg Int1B>, <offset Int1B>
  534.  
  535.         pop     ds
  536.  
  537.  
  538.         ; Verify that the user provided command line parameters.
  539.  
  540.         call    ParamCount
  541.         or      al, al                  ; Were any parameters passed by user?
  542.         jnz     @@Exit
  543.         call    UsageScreen             ; If no, display usage screen
  544.  
  545.     @@Exit:
  546.  
  547.         ret
  548.     endp    Initialize
  549.  
  550.  
  551.     proc    UsageScreen
  552.  
  553.     ;   This routine displays a 'usage' screen that describes the syntax for
  554.     ;   using WHEREIS. It then terminates the program.
  555.     ;
  556.     ;   Input
  557.     ;       ds - Points to data segment where usage screen text is located
  558.     ;   Output
  559.     ;       none
  560.     ;   Calling conventions
  561.     ;       NA
  562.     ;   Registers modified
  563.     ;       ax, cx, dx
  564.  
  565.         call    WriteAsciizString,ds,offset Syntax
  566.         call    Terminate               ; Terminate program
  567.     endp    UsageScreen
  568.  
  569.  
  570.     proc    PathAfterFirst
  571.  
  572.     ;   This routine displays a 'usage' screen that tells the user that
  573.     ;   drive and path info may only be given on the first argument.
  574.     ;   It then terminates the program.
  575.     ;
  576.     ;   Input
  577.     ;       ds - Points to data segment where usage screen text is located
  578.     ;   Output
  579.     ;       none
  580.     ;   Calling conventions
  581.     ;       NA
  582.     ;   Registers modified
  583.     ;       ax, cx, dx
  584.  
  585.         call    WritePascalString,ds,offset OnlyFirst    ;**2
  586.         call    Terminate               ; Terminate program
  587.     endp
  588.  
  589.  
  590.     proc    OnlyOneDosCommand
  591.  
  592.     ;   This routine displays a 'usage' screen that tells the user that
  593.     ;   drive and path info may only be given on the first argument.
  594.     ;   It then terminates the program.
  595.     ;
  596.     ;   Input
  597.     ;       ds - Points to data segment where usage screen text is located
  598.     ;   Output
  599.     ;       none
  600.     ;   Calling conventions
  601.     ;       NA
  602.     ;   Registers modified
  603.     ;       ax, cx, dx
  604.  
  605.         call    WritePascalString,ds,offset OnlyOneCommand
  606.         call    Terminate               ; Terminate program
  607.     endp    OnlyOneDosCommand
  608.  
  609.  
  610. endif   ; ifndef MDL
  611.  
  612. end EntryPoint
  613.