home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rxfiles.zip / rxdostry.asm < prev    next >
Assembly Source File  |  1997-08-14  |  20KB  |  546 lines

  1. ;-----------------------------------------------------------------------
  2. ; RXDOSTRY.RX by (MASM 6.0) ML /AT /Fe RXDOSTRY.RX RXDOSTRY.ASM
  3. ;
  4. ; intended to be called by PC DOS 7 REXX as external function:
  5. ; say 'CHOICE return code =' RXDOSTRY( 'CHOICE /C:ABC' )
  6. ;
  7. ; Note especially how the SIGINT handler of REXX is replaced by
  8. ; the old handler in place before REXX started (test CHOICE ^C)
  9. ;-----------------------------------------------------------------------
  10.  
  11. code     segment para public 'CODE'
  12.  
  13.          assume cs:code, ds:code, es:code, ss:code
  14.  
  15.          org    16h
  16. RXpid    dw     ?               ;_psp:0x16 parent (REXX) pid
  17.  
  18.          org    2Ch
  19. envseg   dw     ?               ;_psp:0x2C environment segment
  20.  
  21.          org    54h
  22. DOSREXX4 dd     ?               ;_psp:0x54 'REXX' signature
  23. SHVENTRY dd     ?               ;_psp:0x58 shared variable handler
  24.  
  25.          org    82h
  26. RXARGC   dw     ?               ;_psp:0x82 number of arguments
  27. RXARGV   dd     ?               ;_psp:0x84 arg.s (length, pointer)
  28. RXRESULT dd     ?               ;_psp:0x88 RESULT buffer (256 bytes)
  29.  
  30.          org    100h            ;COM entry point at CS:100
  31. start:   jmp    stack           ;set stack, release memory
  32.  
  33. ;-----------------------------------------------------------------------
  34.  
  35. pathptr  dd     ?               ;address actual PATH
  36.  
  37. execpar  dw     ?               ;segment environment
  38.          dd     ?               ;pointer command line
  39. fcb1     dd     5Ch             ;pointer own 1st FCB
  40. fcb2     dd     6Ch             ;pointer own 2nd FCB
  41.  
  42. exe      db     '.\????????.EXE    EXE'         ;4 blanks for parse FCB
  43. com      db     '.\????????.COM    COM'         ;EXE, COM for test type
  44.  
  45. COMSIZE  equ    130             ;128 + 2 (count + CR resp. name + blank)
  46. comline  db     COMSIZE dup (0Dh)       ;command arguments end with CR
  47. command  db     COMSIZE dup (0)         ;buffer for search command file
  48.  
  49. pathtxt  db     'PATH=',0       ;search PATH setting
  50. arg1len  dw     ?               ;length of first and only REXX argument
  51.  
  52. argerr   db     13,10,7,'invalid REXX argument',13,10,0
  53. errname  db     13,10,7,'illegal drive or ambiguous command',13,10,0
  54. exectext db     13,10,7,'DOS cannot execute given command',13,10,0
  55. missing  db     13,10,7,'cannot locate command "',0
  56. misscom  db     '" or "',0
  57. missend  db     '"',13,10,0
  58.  
  59. ;-----------------------------------------------------------------------
  60. main     proc   near            ;enter after initialization
  61.  
  62.          cmp    word ptr DOSREXX4+2,'XX'
  63.          jne    badarg
  64.          cmp    RXARGC,1        ;one and only one REXX argument string
  65.          je     envir
  66.  
  67. badlen:  push   es
  68.          pop    ds
  69. badarg:  mov    dx,offset argerr
  70. badmsg:  call   message
  71.          jmp    fail            ;exit
  72.  
  73. envir:   mov    bx,envseg       ;PSP offset 2Ch environment
  74.          mov    execpar,bx      ;own environmemt segment BX
  75.          mov    word ptr fcb1+2,ds
  76.          mov    word ptr fcb2+2,ds
  77.  
  78.          lds    si,RXARGV
  79.          mov    cx,[si]         ;length 1st argument
  80.          cmp    cx,COMSIZE-2    ;2 bytes count + CR
  81.          ja     badlen          ;argument too long
  82.  
  83.          push   cx              ;keep length for later
  84.          lds    si,[si+2]       ;address 1st argument
  85.          mov    di,offset comline+1
  86.          rep    movsb           ;copy to comline+1
  87.         ;comline: CR + REXX_argument_string + CR
  88.         ;comline: CR + trash + command + space + args + CR
  89.  
  90.          mov    ds,es:RXpid     ;parent (REXX) PSP
  91.          mov    si,0Eh          ;PSP offset INT 23h
  92.          lds    dx,[si]         ;parent old INT 23h
  93.          mov    ax,2523h        ;set SIGINT handler
  94.          int    21h
  95.  
  96.          push   es
  97.          pop    ds
  98. ;;;;;;;; mov    bx,execpar      ;BX points to environment
  99.          call   initpath        ;search PATH for pathptr
  100.  
  101.          mov    si,offset comline+1
  102.          pop    cx              ;restore saved length
  103.  
  104. testarg: jcxz   badarg          ;any character left ?
  105.          dec    cx
  106.          lodsb
  107.          cmp    al,' '          ;skip white space at
  108.          jbe    testarg         ;begin of command name
  109.  
  110.          dec    si              ;SI = 1st valid char.
  111.          inc    cx              ;CX = remaining length
  112.          mov    di,offset comline
  113.         ;comline: CR + trash + command + space + args + CR
  114.         ;ES:DI at CR + trash + command + space + args + CR
  115.         ;DS:SI at command + space + args + CR
  116.  
  117. cominc:  cmp    byte ptr [si],' '
  118.          jbe    comgot          ;copy 1st argument to
  119.          movsb                  ;command name buffer
  120.          loop   cominc
  121.  
  122. comgot:  xor    ax,ax
  123.          stosb                  ;AL 0 to name buffer
  124.         ;comline: command + 0 + trash + space + args + CR
  125.         ;ES:DI at trash + space + args + CR
  126.         ;DS:SI at space + args + CR
  127.  
  128.          lea    bx,[si-1]       ;rest length of arguments
  129.          mov    [bx],cl         ;to new command line size
  130.          mov    word ptr execpar+02,bx
  131.          mov    word ptr execpar+04,ds
  132.         ;comline: command + 0 + ? + size + space + args + CR
  133.         ;DS:BX at size + space + args + CR
  134.         ;DS:SI at space + args + CR
  135.  
  136.          les    di,fcb1         ;PSP offset 5Ch is 1st FCB
  137.          mov    ax,2901h        ;parse 2nd argument to FCB
  138.          int    21h             ;(skip leading separators)
  139.  
  140.          les    di,fcb2         ;PSP offset 6Ch is 2nd FCB
  141.          mov    ax,2901h        ;parse 3rd argument to FCB
  142.          int    21h             ;(incompatible simplified)
  143.  
  144. ;-----------------------------------------------------------------------
  145. ;        parse command to file name
  146.  
  147.          push   ds
  148.          pop    es
  149.          mov    dx,offset comline
  150.          call   strlen          ;lenght of command name
  151.          mov    di,dx           ;scan end of path in DI
  152.          mov    al,'\'
  153.  
  154. haspath: mov    si,di           ;keep end of path in SI
  155.          jcxz   endpath         ;skip specified path
  156.          repne  scasb           ;scan path character AL
  157.          jz     haspath
  158.  
  159. endpath: xchg   dx,si           ;keep end of path in DX
  160.          mov    cx,dx           ;determine length in CX
  161.          sub    cx,si           ;(use path length excl.
  162.          push   cx              ; command name if given)
  163.  
  164.          mov    si,dx
  165.          mov    di,offset com   ;parse '????????.COM',0
  166.          call   parse           ;or explicit extension
  167.  
  168.          mov    si,dx
  169.          mov    di,offset exe   ;parse '????????.EXE',0
  170.          call   parse           ;or explicit extension
  171.  
  172.          pop    cx              ;restore path length CX
  173.          or     al,al
  174.          jnz    badname         ;bad drive or '*' / '?'
  175.  
  176.          mov    di,offset com+2
  177.          call   comorexe        ;file extension 'COM' ?
  178.          je     search
  179.          mov    di,offset exe+2
  180.          call   comorexe        ;file extension 'EXE' ?
  181.          je     search
  182.  
  183. badname: mov    dx,offset errname
  184.          jmp    badmsg          ;exit
  185.  
  186. ;-----------------------------------------------------------------------
  187. ;        search command (given type or COM / EXE, given path or PATH)
  188.  
  189. search:  mov    bx,offset command
  190.          jcxz   nopath          ;no path specified ?
  191.  
  192.          mov    si,offset comline
  193.          mov    di,bx           ;command file target
  194.          rep    movsb           ;copy specified path
  195.  
  196.          mov    dx,offset com+2
  197.          push   di              ;keeping target DI
  198.          call   strcpy          ;try xxx.COM at DI
  199.          pop    di              ;restore target DI
  200.          mov    dx,bx           ;command file path
  201.          mov    ax,4300h        ;test COM existence:
  202.          int    21h             ;get file attribute
  203.          jnc    gotfile
  204.  
  205.          mov    dx,offset exe+2
  206.          call   strcpy          ;try xxx.EXE at DI
  207.          mov    dx,bx           ;command file path
  208.          mov    ax,4300h        ;test EXE existence:
  209.          int    21h             ;get file attribute
  210.          jnc    gotfile
  211.  
  212.          mov    dx,offset missing
  213.          push   bx
  214.          call   message         ;cannot find command
  215.          pop    dx              ;with specified path
  216.          call   message
  217.          mov    dx,offset missend
  218.          jmp    badmsg          ;exit
  219.  
  220. nopath:  mov    dx,offset com   ;test COM existence:
  221.          mov    ax,4300h        ;get file attribute
  222.          int    21h
  223.          jnc    gotfile
  224.  
  225.          mov    dx,offset exe   ;test EXE existence:
  226.          mov    ax,4300h        ;get file attribute
  227.          int    21h
  228.  
  229. gotfile: jnc    doit
  230.  
  231.          call   nextpath        ;DI: next PATH token
  232.          jc     nofile          ;command file target
  233.  
  234.          mov    dx,offset com+2
  235.          push   di              ;keeping target DI
  236.          call   strcpy          ;try xxx.COM at DI
  237.          pop    di              ;restore target DI
  238.          mov    dx,bx           ;command file path
  239.          mov    ax,4300h        ;test COM existence:
  240.          int    21h             ;get file attribute
  241.          jnc    gotfile
  242.  
  243.          mov    dx,offset exe+2
  244.          call   strcpy          ;try xxx.EXE at DI
  245.          mov    dx,bx           ;command file path
  246.          mov    ax,4300h        ;test EXE existence:
  247.          int    21h             ;get file attribute
  248.  
  249.          jmp    gotfile         ;try next PATH token
  250.  
  251. nofile:  mov    dx,offset missing
  252.          call   message         ;cannot find command
  253.          mov    dx,offset com+2
  254.          call   message         ;COM
  255.          mov    dx,offset misscom
  256.          call   message         ;or
  257.          mov    dx,offset exe+2
  258.          call   message         ;EXE
  259.          mov    dx,offset missend
  260.          jmp    badmsg          ;exit
  261.  
  262. ;-----------------------------------------------------------------------
  263. ;        execute DOS external command, common exit handling
  264.  
  265. savesp   dw     (?)             ;DOS 2.x exec can destroy SP
  266. savess   dw     (?)             ;DOS 2.x exec can destroy SS
  267.  
  268. doit:    push   ds
  269.          push   es
  270.          mov    cs:savess,ss
  271.          mov    cs:savesp,sp    ;DS:DX ASCIIZ command
  272.          mov    ax,4B00h        ;ES:BX exec parameter
  273.          mov    bx,offset execpar
  274.          int    21h             ;DOS exec function in
  275.          cli                    ;DOS 2.x destroys all
  276.  
  277.          mov    ss,cs:savess    ;no interrupts during
  278.          mov    sp,cs:savesp    ;restauration DS = ES
  279.          pop    es              ;and stack SS:SP
  280.          pop    ds
  281.          sti                    ;interrupts now okay
  282.  
  283.          jnc    didexec         ;no carry: exec done
  284.  
  285.          mov    dx,offset exectext
  286.          jmp    badmsg          ;exit
  287.  
  288. didexec: les    di,RXRESULT
  289.          mov    ah,4Dh          ;get last exit code
  290.          int    21h
  291.  
  292.          mov    ah,0            ;AX = exit code 0..255
  293.          mov    cl,100          ;AL = quotient  0..  2
  294.          div    cl              ;AH = remainder 0.. 99
  295.  
  296.          mov    cx,'00'
  297.          or     al,cl
  298.          cmp    al,ch
  299.          je     lt_100
  300.          xor    ch,ch
  301.          stosb                  ;e.g. 1 of exit code 123
  302.  
  303. lt_100:  mov    al,ah
  304.          aam                    ;adjust remainder 0..99
  305.          xchg   al,ah
  306.          or     al,cl
  307.          cmp    al,ch
  308.          je     lt_010
  309.          stosb                  ;e.g. 2 of exit code 123
  310.  
  311. lt_010:  mov    al,ah
  312.          or     al,cl
  313.          stosb                  ;e.g. 3 of exit code 123
  314.  
  315.          xor    al,al           ;return code, AL := 0
  316.          stosb                  ;ASCIIZ result string
  317.          jmp    exit
  318.  
  319. fail:    mov    al,1            ;return code, AL := 1
  320. exit:    mov    ah,4Ch          ;terminate with RC AL
  321.          int    21h
  322.  
  323. main     endp
  324.  
  325. ;-----------------------------------------------------------------------
  326. initpath proc   near            ;search for path in environment BX
  327.  
  328.          push   ds              ;modifies AX, CX, DI, SI
  329.          mov    word ptr pathptr+2,bx
  330.          mov    ds,bx           ;environment segment
  331.          xor    ax,ax           ;DS:SI start BX:0000
  332.          mov    si,ax
  333.  
  334. scanit:  mov    cx,5
  335.          mov    di,offset pathtxt
  336.          repe   cmpsb           ;look for 'PATH='
  337.          mov    cx,si           ;terminate search at segment limit
  338.          not    cx              ;this will work for length < 64 KB
  339.          jne    skipit          ;CMPSB NOT changed 'PATH=' found ?
  340.  
  341.          pop    ds              ;restore own data segment
  342.          mov    word ptr pathptr+0,si
  343.          ret                    ;BX:SI is real PATH begin
  344.  
  345. skipit:  lodsb                  ;look for terminating NUL byte
  346.          or     al,al
  347.          loopnz skipit
  348.          jcxz   envend          ;environment segment > 64 KB ?
  349.  
  350.          cmp    [si],al         ;go on with search
  351.          jne    scanit          ;unless double NUL
  352.  
  353. envend:  pop    ds              ;restore own data segment
  354.          lea    si,[pathtxt+5]
  355.          mov    word ptr pathptr+0,si
  356.          mov    word ptr pathptr+2,ds
  357.          ret                    ;DS:SI for NUL PATH dummy
  358.  
  359. initpath endp
  360.  
  361. ;-----------------------------------------------------------------------
  362. nextpath proc   near            ;search for path in environment
  363.  
  364.          push   ds              ;modifies AX, DI, SI
  365.          mov    ah,11111111b    ;yet no character mark
  366.          mov    di,offset command
  367.          lds    si,pathptr
  368.          test   ah,[si]
  369.          jnz    incpath         ;handle ASCIIZ string end
  370.  
  371.          pop    ds              ;restore own data segment
  372.          stc                    ;indicate PATH end (carry)
  373.          ret
  374.  
  375. incpath: lodsb
  376.          cmp    al,';'
  377.          je     textend         ;handle PATH token end ';'
  378.          or     al,al
  379.          jz     textend         ;handle ASCIIZ string end
  380.          stosb
  381.          mov    ah,al           ;mark for got a character
  382.          jmp    incpath
  383.  
  384. textend: pop    ds              ;restore own data segment
  385.          mov    word ptr pathptr+0,si
  386.          cmp    ah,11111111b
  387.          jz     nextpath        ;oops, empty path token ?
  388.  
  389.          cmp    byte ptr [di-1],':'
  390.          jz     pathend         ;expect DOS disk character
  391.          mov    al,'\'
  392.          cmp    [di-1],al       ;':' or DOS path character
  393.          jz     pathend         ;otherwise patch '\'
  394.          stosb
  395.  
  396. pathend: clc                    ;indicate token (no carry)
  397.          ret                    ;DI points to end of token
  398.  
  399. nextpath endp
  400.  
  401. ;-----------------------------------------------------------------------
  402. parse    proc   near            ;parse name SI to filename.ext DI
  403.  
  404.          push   di              ;modifies AX, CX, DI, SI
  405.          inc    di              ;skip '.' in target data
  406.          mov    al,'\'
  407.          stosb                  ;reserve e.g. '.\' or 'A:'
  408.  
  409.          mov    ax,2908h        ;parse command name SI
  410.          int    21h             ;to DI, keep extension
  411.          or     al,al
  412.          jz     parseok         ;'*' or '?' or bad drive ?
  413.  
  414.          pop    di              ;restore initial target
  415.          ret                    ;AL > 0 indicates error
  416.  
  417. parseok: push   di              ;keep target
  418.          mov    cx,8            ;copy filename to begin
  419.          lea    si,[di+1]       ;i.e. overwrite drive X
  420.          rep    movsb
  421.          mov    al,' '          ;AL is terminator blank
  422.          stosb
  423.  
  424.          pop    di              ;scan for blank end and
  425.          mov    cx,9            ;replace by point
  426.          repne  scasb
  427.          mov    byte ptr [di-1],'.'
  428.  
  429.          push   di              ;keep target
  430.          mov    cx,3            ;copy file extension SI
  431.          rep    movsb
  432.  
  433.          pop    di              ;scan for blank end and
  434.          mov    cx,4            ;replace by NUL
  435.          repne  scasb
  436.          xor    ax,ax
  437.          mov    [di-1],al
  438.  
  439.          pop    di              ;restore initial target
  440.          mov    si,offset comline
  441.          cmp    byte ptr [si+1],':'
  442.          jnz    parsend         ;replace dummy path
  443.          movsw                  ;by specified drive
  444.  
  445. parsend: ret                    ;indicate okay AL 0
  446.  
  447. parse    endp
  448.  
  449. ;-----------------------------------------------------------------------
  450. comorexe proc   near            ;file type DI+16 in identifier DI ?
  451.  
  452.          push   cx              ;modifies AL, DI, SI
  453.          mov    al,'.'          ;keep CX, AH
  454.          lea    si,[di+16]
  455.          mov    cx,9            ;scan type following guaranteed '.'
  456.          repne  scasb
  457.          mov    cx,3            ;test type (uppercase parse result)
  458.          repe   cmpsb           ;for simplicity assume 3 bytes type
  459.          pop    cx
  460.          ret                    ;flag E equal types or NE not equal
  461.  
  462. comorexe endp
  463.  
  464. ;-----------------------------------------------------------------------
  465. strlen   proc   near            ;return length ASCIIZ string ES:DX
  466.  
  467.          xchg   di,dx           ;modifies AX, CX
  468.          mov    cx,di           ;keep DX, DI, ES
  469.          not    cx              ;terminate search at segment limit
  470.          push   di              ;this will work for length < 64 KB
  471.          xor    al,al
  472.          repne  scasb           ;search NUL
  473.          mov    cx,di           ;DI points behind NUL (or is NULL)
  474.          pop    di              ;restore DI
  475.          sub    cx,di           ;length inclusive NUL
  476.          dec    cx              ;length exclusive NUL
  477.          xchg   dx,di           ;restore DX
  478.          ret                    ;returns CX string length
  479.  
  480. strlen   endp
  481.  
  482. ;-----------------------------------------------------------------------
  483. strcpy   proc   near            ;ASCIIZ string DS:DX to ES:DI
  484.  
  485.          push   cx              ;modifies AX, DI
  486.          push   es              ;keep CX, DX, ES
  487.          push   ds
  488.          pop    es              ;set ES = DS
  489.          call   strlen          ;string length CX
  490.          pop    es              ;load old ES
  491.          jcxz   nulcpy
  492.  
  493.          push   di              ;target + length
  494.          add    di,cx           ;in segment ES ?
  495.          jnc    allcpy          ;then copy all
  496.          sub    cx,di           ;else truncate
  497.  
  498. allcpy:  pop    di              ;target DI
  499.          push   si              ;saving SI
  500.          mov    si,dx           ;source DX
  501.          rep    movsb
  502.          pop    si
  503.  
  504. nulcpy:  mov    [di],cl         ;target terminator
  505.          pop    cx              ;DI is end of copy
  506.          ret
  507.  
  508. strcpy   endp
  509.  
  510. ;-----------------------------------------------------------------------
  511. message  proc   near            ;ASCIIZ string DS:DX to STDERR
  512.  
  513.          push   ax              ;modifies BX, CX
  514.          push   es              ;keep AX, DX, DS, ES
  515.          push   ds
  516.          pop    es              ;set ES = DS
  517.          call   strlen          ;CX = strlen( ES:DX )
  518.          pop    es              ;load old ES
  519.  
  520.          mov    bx,2            ;ASCIIZ string DS:DX to STDERR
  521.          mov    ah,40h
  522.          int    21h
  523.          pop    ax
  524.          ret
  525.  
  526. message  endp
  527.  
  528. ;-----------------------------------------------------------------------
  529.          align  16
  530. stkparas equ    32              ;stack size 512 = 32 * 16
  531.  
  532. stack    label  near            ;initialise *.com program
  533.  
  534.          mov    bx,offset stack + 16 * stkparas
  535.          mov    sp,bx           ;new stack 100h above init
  536.          mov    cl,4
  537.          shr    bx,cl           ;used number of paragraphs:
  538.          mov    ah,4ah          ;modify allocated memory to
  539.          int    21h             ;needed size i.e. free rest
  540.  
  541.          jmp    main            ;current SP must be beyond
  542.  
  543. ;-----------------------------------------------------------------------
  544. code     ends
  545.          end    start           ;program entry point
  546.