home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol7n03.zip / RUN.ASM < prev    next >
Assembly Source File  |  1988-02-16  |  22KB  |  498 lines

  1. ;----------------------------------------------------------------------
  2. ;                  RUN.ASM
  3. ;  Format:   RUN [/C][/S][d:][directory] filename [arguments]
  4. ;  /C = Change to the directory and run
  5. ;  /S = Stay in current directory and run
  6. ;  Default is /S
  7. ;----------------------------------------------------------------------
  8. CODE SEGMENT                           ;********************************;
  9. ASSUME CS:CODE,DS:CODE                 ;*                              *;
  10. ORG 100H                               ;*  Requires MASM 2.0 or later  *;
  11.                                        ;*     Remember to EXE2BIN      *;
  12. START:         JMP    BEGINNING        ;*                              *;
  13.                                        ;********************************;
  14.  
  15. ;              DATA AREA
  16. ;              ---------
  17. COPYRIGHT      DB     "RUN 1.0 (c) 1987 Ziff Communications Co.",13,10
  18.                DB     "PC Magazine ",254," Michael J. Mefford",13,10,"$",26
  19.  
  20. CURRENT_DISK   DB     ?                      
  21. WORKING_DISK   DB     0FFH
  22. FILE_START     DW     ?
  23. FILENAME_END   DW     ?
  24. ARGUMENTS      DW     ?
  25. PATH_END       DW     0
  26. CHANGE_FLAG    DB     0
  27. BAT_FLAG       DB     0
  28.  
  29. SYNTAX  DB  13,10,"Syntax:  RUN [/C][/S][d:][directory] filename [arguments]"
  30.         DB  13,10,"/C = Change to the directory and run"
  31.         DB  13,10,"/S = Stay in current directory and run"
  32.         DB  13,10,"Default is /S"
  33. CR_LF   DB  13,10,"$"
  34.  
  35. FAIL           DB     13,10,"Can't find $"
  36. SEARCHING      DB     13,10,"Searching for $"
  37. DELIMITERS     DB     9,13,32,"/<>."
  38. EXE            DB     "EXE",0
  39. COM            DB     "COM",0
  40. BAT            DB     "BAT",0
  41. ROOT           DB     "\",0
  42. STAR_DOT_STAR  DB     "*.*",0
  43. PARENT         DB     "..",0
  44. COPY           DB     " /C "
  45. COMSPEC        DB     "COMSPEC="
  46.  
  47. STACK_SEG      DW     ?
  48. STACK_PTR      DW     ?
  49.  
  50. PARAMETER_BLOCK  LABEL  WORD
  51.  
  52. ENVIRONMENT    DW     0
  53. COM_LINE_PTR   DW     PARAMETER,?
  54. FCB_1ST        DW     FCB_5CH,  ?
  55. FCB_2ND        DW     FCB_6CH,  ?
  56.  
  57. ;----------------------------------------------------------------------------;
  58. ; Some housekeeping first. Since we will be changing the default drive       ;
  59. ; and directory to the requested drive and directory, we need to save the    ;
  60. ; current defaults, so they can be restored.  Change the default DTA.        ;
  61. ; Move the stack and deallocate memory so we have room to spawn the program. ;
  62. ;----------------------------------------------------------------------------;
  63.  
  64. ;              CODE AREA
  65. ;              ---------
  66. BEGINNING:
  67.                MOV    AH,9
  68.                MOV    DX,OFFSET COPYRIGHT
  69.                INT    21H
  70.  
  71.                CLD                           ;String moves forward.
  72.                CALL   GET_DRIVE              ;Get current drive.
  73.                MOV    CURRENT_DISK,AL        ;Save.
  74.                MOV    SI,OFFSET CURRENT_DIR  ;Get current directory.
  75.                CALL   GET_DIR
  76.  
  77.                MOV    DX,OFFSET DTA          ;Move the disk transfer address
  78.                MOV    AH,1AH                 ; to the end of code to protect
  79.                INT    21H                    ; command line parameters at 80h.
  80.  
  81.                MOV    SP,OFFSET CODE_END     ;Move the stack down to the
  82.                MOV    BX,SP                  ; end of code segment.
  83.                ADD    BX,15                  ;Round up paragraph size.
  84.                MOV    CL,4
  85.                SHR    BX,CL
  86.                MOV    AH,4AH                 ;Deallocate rest of memory.
  87.                INT    21H
  88.  
  89. ;--------------------------------------------------;
  90. ; Parse the command line parameters.  Start by     ;
  91. ; scanning off spaces and RUN's switch characters. ;
  92. ;--------------------------------------------------;
  93.  
  94.                MOV    SI,80H                 ;Point to command line parameters.
  95.                LODSB
  96.                CMP    AL,0                   ;Are there any?
  97.                JZ     BAD_SYNTAX             ;If no, exit.
  98.  
  99. NEXT_LEADING:  LODSB                         ;Get a byte.
  100.                CMP    AL,"/"                 ;Is it a switch character?
  101.                JNZ    CK_CR                  ;If no, check if end.
  102.                LODSB                         ;Else, get switch character.
  103.                CMP    AL,13                  ;Make sure not end.
  104.                JZ     BAD_SYNTAX
  105.                AND    AL,5FH                 ;Capitalize.
  106.                CMP    AL,"C"                 ;Is it "C"?
  107.                JNZ    CK_NOCHANGE
  108.                MOV    CHANGE_FLAG,1          ;If yes, indicate to change dir.
  109. CK_NOCHANGE:   CMP    AL,"S"                 ;Else, is it "S"?
  110.                JNZ    NEXT_LEADING           ;If no, next leading character.
  111.                MOV    CHANGE_FLAG,0          ;Else, indicate not to change dir.
  112.                JMP    SHORT NEXT_LEADING
  113.  
  114. CK_CR:         CMP    AL,13                  ;Is it carriage return?
  115.                JNZ    CK_LEADING             ;If yes, bad syntax.
  116. BAD_SYNTAX:    JMP    SYNTAX_EXIT
  117. CK_LEADING:    CMP    AL,32                  ;Is it a space or tab?
  118.                JBE    NEXT_LEADING           ;If yes, get next character.
  119.                DEC    SI                     ;Else, adjust pointer back one.
  120.                PUSH   SI                     ;Save as possible path request.
  121.                MOV    FILE_START,SI          ;Save as possible start of filename
  122.  
  123. ;----------------------------------------------------;
  124. ; We now have the start of the run file.  Next scan  ;
  125. ; to the end of filename looking for a path request. ;
  126. ;----------------------------------------------------;
  127.  
  128. NEXT_PATH:     LODSB                         ;Get a byte.
  129.                CMP    AL,":"                 ;Drive request?
  130.                JNZ    CK_PATH                ;If no, check if directory.
  131.                MOV    DL,[SI-2]              ;Else, retrieve drive.
  132.                AND    DL,5FH                 ;Capitalize.
  133.                SUB    DL,"A"                 ;Convert to DOS format.
  134.                CALL   CHANGE_DRIVE           ;Change drive.
  135.                MOV    FILE_START,SI          ;Save as possible start of filename
  136.                JMP    SHORT NEXT_PATH
  137.  
  138. CK_PATH:       CMP    AL,"\"                 ;Is it a path delimiter?
  139.                JNZ    CK_DELIMITER           ;If no, see if end of filename.
  140.                MOV    PATH_END,SI            ;Else, save as path end.
  141.                MOV    FILE_START,SI          ;Save as possible start of filename
  142. CK_DELIMITER:  MOV    DI,OFFSET DELIMITERS   ;Check for tab, carriage return,
  143.                MOV    CX,6                   ; space, switch, or redirection
  144.                REPNZ  SCASB                  ; characters as filename end.
  145.                JNZ    NEXT_PATH              ;Continue until found.
  146.  
  147.                DEC    SI                     ;Else, adjust pointer back one.
  148.                MOV    ARGUMENTS,SI           ;Save as start of arguments.
  149.  
  150. ;--------------------------------------------------; 
  151. ; Parse the arguments for two file control blocks. ;
  152. ;--------------------------------------------------;
  153.  
  154.                MOV    DI,OFFSET FCB_5CH      ;Point to first FCB storage.
  155.                MOV    AX,2901H               ;Parse and scan off leading
  156.                INT    21H                    ; separators.
  157.                MOV    DI,OFFSET FCB_6CH      ;Same for second FCB.
  158.                MOV    AX,2901H
  159.                INT    21H
  160.  
  161. ;----------------------------------------------------;
  162. ; Store working path so can be restored on exit.     ;
  163. ; Store run filename stripping extension in process. ;
  164. ;----------------------------------------------------;
  165.  
  166.                CALL   GET_DRIVE              ;Store working drive.
  167.                MOV    WORKING_DISK,AL
  168.                MOV    SI,OFFSET WORKING_DIR  ;Store working directory.
  169.                CALL   GET_DIR
  170.  
  171.                MOV    SI,FILE_START          ;Store the run filename.
  172.                MOV    DI,OFFSET FILENAME
  173. NEXT_FILENAME: LODSB                         ;Get a byte.
  174.                PUSH   DI
  175.                MOV    DI,OFFSET DELIMITERS   ;Are we at the end of filename
  176.                MOV    CX,7                   ; or encountered dot?
  177.                REPNZ  SCASB
  178.                POP    DI
  179.                JZ     STORE_DOT              ;If yes, done here.
  180.                STOSB
  181.                JMP    SHORT NEXT_FILENAME
  182.  
  183. STORE_DOT:     MOV    AL,"."
  184.                STOSB
  185.                MOV    FILENAME_END,DI        ;Store end of filename.
  186.  
  187. ;---------------------------------------------------------;
  188. ; If a path was found, change directory and search for    ;
  189. ; run file.  Else, do a diskwide search for the run file. ;
  190. ;---------------------------------------------------------;
  191.  
  192.                POP    DX                     ;Retrieve filespec start.
  193.                MOV    SI,PATH_END            ;Did we find a path?
  194.                CMP    SI,0
  195.                JZ     GLOBAL                 ;If no, do global search.
  196.                CMP    BYTE PTR [SI-2],":"    ;Else, check if special
  197.                JZ     CHANGE_IT              ; case of root directory.
  198.                CMP    BYTE PTR [SI-2],32
  199.                JBE    CHANGE_IT              ;If yes, change directory.
  200.                DEC    SI                     ;If no, adjust pointer.
  201. CHANGE_IT:     PUSH   [SI]                   ;Save path end.
  202.                MOV    BYTE PTR [SI],0        ;Convert to ASCIIZ for DOS.
  203.                CALL   CHANGE_DIR             ;Change directory.
  204.                POP    [SI]                   ;Restore path end.
  205.  
  206.                CALL   CK_EXECUTABLE          ;Search current directory
  207.                JNC    RUN_IT                 ; for filename; run it if found.
  208.                JMP    SHORT ERROR_EXIT       ;Else, exit with message.
  209.  
  210. GLOBAL:        CALL   GLOBAL_SEARCH          ;If no directory request, do a
  211.                JC     ERROR_EXIT             ; diskwide search for filename.
  212. RUN_IT:        CALL   EXEC                   ;If found, execute it.
  213.                JMP    SHORT EXIT
  214.  
  215. ;-----------------------------------------------------------------------;
  216. ; This is the exit routine. Restore the defaults the way we found them. ;
  217. ;-----------------------------------------------------------------------;
  218.  
  219. ERROR_EXIT:    MOV    DX,OFFSET FAIL         ;Display "Can't find ".
  220.                CALL   PRINT_STRING
  221.                CALL   PRINT_NAME             ;Display filename.
  222. SYNTAX_EXIT:   MOV    DX,OFFSET SYNTAX       ;Display RUN syntax.
  223.                CALL   PRINT_STRING
  224.                MOV    AL,1                   ;Error code of one.
  225.                JMP    SHORT TERMINATE
  226.  
  227. EXIT:          XOR    AL,AL                  ;Error code of zero.
  228. TERMINATE:     PUSH   AX                     ;Save error code.
  229.                CALL   RESTORE_PATH           ;Restore defaults.
  230.                POP    AX                     ;Retrieve error code.
  231.                MOV    AH,4CH                 ;Exit.
  232.                INT    21H
  233.  
  234.                ;***************;
  235.                ;* SUBROUTINES *;
  236.                ;***************;
  237.  
  238. ;-----------------------------------------------------------------;
  239. ; This subroutine adds the extension COM, EXE and BAT             ;
  240. ; (in that order) to the filename and checks to see if it exists. ;
  241. ;-----------------------------------------------------------------;
  242.  
  243. CK_EXECUTABLE: MOV    DX,OFFSET FILENAME     ;Point to filename.
  244.                MOV    BX,FILENAME_END        ;Point to filename end.
  245.                MOV    SI,OFFSET COM          ;Check for .COM
  246.                CALL   FIND_MATCH
  247.                JNC    CK_END
  248.                MOV    SI,OFFSET EXE          ;Check for .EXE
  249.                CALL   FIND_MATCH
  250.                JNC    CK_END
  251.                MOV    SI,OFFSET BAT          ;Check for .BAT
  252.                CALL   FIND_MATCH
  253.                JC     CK_END
  254.                MOV    BAT_FLAG,1             ;If batch file, indicate so.
  255. CK_END:        RET
  256.  
  257. ;---------------------------;
  258.  
  259. FIND_MATCH:    MOV    DI,BX                  ;Add extension to filename.
  260.                MOVSW
  261.                MOVSW
  262.                MOV    CX,7
  263.                CALL   FIND_FIRST             ;See if it exists.
  264.                RET
  265.  
  266. ;-----------------------------------------------------------------;
  267. ; This subroutine executes the file.  If it's a batch file, load  ;
  268. ; secondary copy of COMMAND.COM.  Else, let 4Bh execute the file. ;
  269. ;-----------------------------------------------------------------;
  270.  
  271. EXEC:          PUSH   DS                     ;Save segment registers.
  272.                PUSH   ES
  273.                CLI
  274.                MOV    STACK_SEG,SS           ;Save stack segment and pointer.
  275.                MOV    STACK_PTR,SP
  276.                STI
  277.  
  278.                MOV    COM_LINE_PTR + 2,DS    ;Point to command line.
  279.                MOV    FCB_1ST + 2,DS         ;Point to file control blocks.
  280.                MOV    FCB_2ND + 2,DS
  281.  
  282.                CMP    BAT_FLAG,1             ;Is it a batch file?
  283.                JNZ    EXECUTE                ;If no, just execute file.
  284.                MOV    SI,OFFSET COPY            ;Else, let COMMAND.COM/C run it.
  285.                MOV    DI,OFFSET PARAMETER + 1   ;Construct parameter.
  286.                MOVSW
  287.                MOVSW
  288.                CALL   MAKE_FILESPEC          ;Add filespec.
  289.                DEC    DI
  290.                CALL   ADD_PARAMETER          ;Add arguments.
  291.  
  292.                MOV    AX,DS:[2CH]            ;Retrieve environment segment.
  293.                MOV    DS,AX
  294.                XOR    AX,AX
  295.  
  296. FIND_COMSPEC:  MOV    SI,AX                  ;Search for "COMSPEC=".
  297.                INC    AX
  298.                MOV    DI,OFFSET COMSPEC
  299.                MOV    CX,4
  300.                REPZ   CMPSW
  301.                JNZ    FIND_COMSPEC
  302.                MOV    DX,SI                  ;What follows is COMMAND.COM path.
  303.                JMP    SHORT EXEC_FILE        ;Ready to execute.
  304.  
  305. EXECUTE:       MOV    DI,OFFSET FILESPEC     ;Construct filespec.
  306.                CALL   MAKE_FILESPEC
  307.                MOV    DI,OFFSET PARAMETER + 1    ;Construct arguments.
  308.                CALL   ADD_PARAMETER
  309.                MOV    DX,OFFSET FILESPEC
  310.  
  311. EXEC_FILE:     MOV    BX,OFFSET PARAMETER_BLOCK  ;Point to parameter block.
  312.                MOV    AX,4B00H                   ;Execute.
  313.                INT    21H
  314.  
  315.                CLI
  316.                MOV    SP,CS:STACK_PTR        ;Restore stack segment and pointer.
  317.                MOV    SS,CS:STACK_SEG
  318.                STI
  319.                POP    ES                     ;Restore segment registers.
  320.                POP    DS
  321.                RET
  322.  
  323. ;---------------------------;
  324.  
  325. MAKE_FILESPEC: CMP    CHANGE_FLAG,1          ;Are we to change directory?
  326.                JZ     ADD_FILENAME           ;If yes, execute filename.
  327.                MOV    AL,WORKING_DISK        ;Else, add working drive.
  328.                ADD    AL,"A"
  329.                STOSB
  330.                MOV    AL,":"
  331.                STOSB
  332.                MOV    SI,DI                  ;Add working directory.
  333.                CALL   GET_DIR
  334.                CALL   RESTORE_PATH           ;Restore default path.
  335.                MOV    DI,SI
  336.                CMP    BYTE PTR [DI],0        ;If root, ready for filename.
  337.                JZ     ADD_FILENAME
  338. FIND_END:      INC    DI                     ;Else, find end of path.
  339.                CMP    BYTE PTR [DI],0
  340.                JNZ    FIND_END
  341.                MOV    AL,"\"                 ;Tack on "\" path delimiter.
  342.                STOSB
  343. ADD_FILENAME:  MOV    SI,OFFSET FILENAME     ;Add on filename.
  344. NEXT_NAME:     LODSB
  345.                STOSB
  346.                CMP    AL,0
  347.                JNZ    NEXT_NAME
  348.                RET
  349.  
  350. ;---------------------------;
  351.  
  352. ADD_PARAMETER: MOV    SI,ARGUMENTS           ;Add on arguments.
  353. GET_PARAMETER: LODSB
  354.                STOSB
  355.                CMP    AL,13
  356.                JNZ    GET_PARAMETER
  357.                XOR    CL,CL                     ;Zero in counter.
  358.                MOV    SI,OFFSET PARAMETER + 1
  359. CNT_PARAMETER: LODSB
  360.                CMP    AL,13
  361.                JZ     END_PARAMETER
  362.                INC    CL                     ;Count parameter length.
  363.                JMP    SHORT CNT_PARAMETER    
  364. END_PARAMETER: MOV    PARAMETER,CL           ;Store as first byte of parameter.
  365.                RET
  366.  
  367. ;---------------------------------------------;
  368. ; This subroutine restores the default paths. ;
  369. ;---------------------------------------------;
  370.  
  371. RESTORE_PATH:  CMP    WORKING_DISK,0FFH      ;Did we get defaults?
  372.                JZ     END_RESTORE            ;If no, done here.
  373.                MOV    DX,OFFSET WORKING_DIR
  374.                CALL   CHANGE_DIR
  375.                MOV    DL,CURRENT_DISK
  376.                CALL   CHANGE_DRIVE
  377.                MOV    DX,OFFSET CURRENT_DIR
  378.                CALL   CHANGE_DIR
  379. END_RESTORE:   RET
  380.  
  381. ;----------------------------------------;
  382. ; These are the DOS support subroutines. ;
  383. ;----------------------------------------;
  384.  
  385. PRINT_NAME:    MOV    SI,OFFSET FILENAME     ;Print filename
  386. NEXT_PRINT:    LODSB
  387.                CMP    AL,"."
  388.                JZ     END_NAME
  389.                MOV    DL,AL
  390.                MOV    AH,2                   ; via DOS Display Output.
  391.                INT    21H
  392.                JMP    SHORT NEXT_PRINT
  393. END_NAME:      MOV    DX,OFFSET CR_LF        ;Print carriage return linefeed.
  394.                CALL   PRINT_STRING
  395.                RET
  396.  
  397. GET_DRIVE:     MOV    AH,19H
  398.                JMP    SHORT DOS_CALL
  399.  
  400. CHANGE_DRIVE:  MOV    AH,0EH
  401.                JMP    SHORT DOS_CALL
  402.  
  403. FIND_FIRST:    MOV    AH,4EH
  404.                JMP    SHORT DOS_CALL
  405.  
  406. FIND_NEXT:     MOV    AH,4FH
  407.                JMP    SHORT DOS_CALL
  408.  
  409. GET_DIR:       MOV    BYTE PTR [SI],"\"      ;DOS doesn't preface directory
  410.                INC    SI                     ; with slash so we must.
  411.                XOR    DL,DL
  412.                MOV    AH,47H                 ;Retrieve default directory.
  413.                JMP    SHORT DOS_CALL
  414.  
  415. CHANGE_DIR:    MOV    AH,3BH
  416.                JMP    SHORT DOS_CALL
  417.  
  418. PRINT_STRING:  MOV    AH,9
  419.                JMP    SHORT DOS_CALL
  420.  
  421. CK_KEY:        MOV    AH,0BH
  422.  
  423. ;---------------------------;
  424.  
  425. DOS_CALL:      INT    21H
  426.                RET
  427.  
  428. ;---------------------------------------------------------------;
  429. ; This subroutine will systematically change directories up and ;
  430. ; down the directory tree, searching for the matching filename. ;
  431. ;---------------------------------------------------------------;
  432.  
  433. GLOBAL_SEARCH: MOV    DX,OFFSET SEARCHING    ;Display searching message.
  434.                CALL   PRINT_STRING
  435.                CALL   PRINT_NAME             ;Display filename.
  436.                MOV    DX,OFFSET ROOT         ;Start the search from root.
  437.                CALL   CHANGE_DIR
  438.                MOV    DI,OFFSET DIR_LEVEL
  439.                MOV    BP,DI                  ;Point to first level directory.
  440.                MOV    AX,0101H               ;Store initial level of one.
  441.                MOV    CX,64 / 2
  442.                REP    STOSW
  443.  
  444. FIRST_FILE:    CALL   CK_KEY                 ;Was a key pressed?
  445.                CMP    AL,0
  446.                JNZ    END_SEARCHING          ;If yes, abort search.
  447.                CALL   CK_EXECUTABLE          ;Check if matching executable.
  448.                JC     FIRST_DIR              ;If no, try next directory.
  449.                RET                           ;Else, return to execute.
  450.  
  451. PARENT_DIR:    CMP    BP,OFFSET DIR_LEVEL    ;When we try to return to parent
  452.                JNZ    CONTINUE               ; directory and are in root, we
  453. END_SEARCHING: STC                           ; are done.
  454.                RET
  455.  
  456. CONTINUE:      MOV    DX,OFFSET PARENT       ;Otherwise, change
  457.                CALL   CHANGE_DIR             ; to parent directory.
  458.                MOV    BYTE PTR DS:[BP],1     ;Put one back in previous level
  459.                DEC    BP                     ; and point to parent level.
  460.  
  461. FIRST_DIR:     XOR    BL,BL                  ;Use BL as pointer to directory no.
  462.                MOV    DX,OFFSET STAR_DOT_STAR
  463.                MOV    CX,10H                 ;Ask for directory match.
  464.                CALL   FIND_FIRST             ;Find first matching.
  465.                JC     PARENT_DIR
  466. CK_DIR:        CMP    BYTE PTR DS:[DTA+21],10H  ;If not a directory, get next.
  467.                JNZ    NEXT_DIR
  468.                CMP    BYTE PTR DS:[DTA+30],'.'  ;If dot directory, get next.
  469.                JZ     NEXT_DIR
  470.                INC    BL                     ;Increment position in directory.
  471.                CMP    BL,DS:[BP]             ;Continue until new directory.
  472.                JNZ    NEXT_DIR
  473.                INC    BYTE PTR DS:[BP]       ;Update variables.
  474.                MOV    DX,OFFSET DTA + 30
  475.                CALL   CHANGE_DIR             ;Change the directory.
  476.                INC    BP
  477.                JMP    SHORT FIRST_FILE       ;See if directory has a run file.
  478.  
  479. NEXT_DIR:      CALL   FIND_NEXT              ;Get all subdirectories in current
  480.                JC     PARENT_DIR             ; directory then go to parent.
  481.                JMP    SHORT CK_DIR
  482.  
  483. ;---------------------------;
  484.  
  485. PARAMETER      LABEL  BYTE
  486. FCB_5CH        EQU    PARAMETER + 256
  487. FCB_6CH        EQU    FCB_5CH + 16
  488. CURRENT_DIR    EQU    FCB_6CH + 16
  489. WORKING_DIR    EQU    CURRENT_DIR + 65
  490. DIR_LEVEL      EQU    WORKING_DIR + 65
  491. FILENAME       EQU    DIR_LEVEL + 64
  492. FILESPEC       EQU    FILENAME + 13
  493. DTA            EQU    FILESPEC + 67 + 13
  494. CODE_END       EQU    DTA + 43 + 256
  495.  
  496. CODE ENDS
  497. END  START
  498.