home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcresour / 1989_05 / shell.asm next >
Assembly Source File  |  1989-01-21  |  20KB  |  684 lines

  1. comment |
  2.    This is the control program of the menu system.  Its job is to
  3.    alternately execute the user-interface program and whatever programs
  4.    the user wants to run.  It communicates with the user-interface program'
  5.    via the inter-application communications area (IACA)
  6.  
  7.    Written for MASM 5.1 and TASM 1.0
  8.     |
  9.  
  10. ;----------------------------------------------------------
  11. ;  Order of segments
  12. ;----------------------------------------------------------
  13.         .MODEL SMALL,C
  14.         .STACK
  15.         .DATA
  16.         .CODE
  17. end_seg        segment
  18. end_seg        ends
  19.  
  20. ;----------------------------------------------------------
  21. ;  Data and buffers
  22. ;----------------------------------------------------------
  23.         .DATA
  24. IACA        equ    4f0h            ;Offset of IACA
  25. STDERR        equ    2            ;Handle for STDERR
  26. CR        equ    0dh            ;Carriage return
  27. UI_BUFSIZE    equ    800h              ;Allow 2K bytes for U_I data
  28. ENV_SIZE    equ    800h            ;Allow 2K bytes for environ.
  29.     
  30. EPB        equ    $            ;EXEC parameter block
  31. EPB_environ    dw    0            ;Use inherited environment
  32. EPB_cmd_tail    dw    offset cmd_tail           ;Address of command tail
  33.         dw    seg    cmd_tail
  34. EPB_fcb1    dw    offset fcb1        ;Pointers to FCBs
  35.         dw    seg    fcb1
  36. EPB_fcb2    dw    offset fcb2
  37.         dw    seg    fcb2
  38.  
  39. model_fcb    db    0
  40.         db    11 dup ('?')
  41.         db    25 dup (0)
  42. fcb_len        equ    $-model_fcb
  43.  
  44. fcb1        db    fcb_len dup(0)
  45. fcb2        db    fcb_len dup(0)
  46.     ;----------
  47.     ;  Execution codes returned
  48.     ;  from user-interface (U-I)
  49.     ;  (add 80H or 128 to each to 
  50.     ;  force a pause after program ends)
  51.     ;----------
  52. call_table    dw    offset    exit        ;Code 0: EXIT to DOS
  53.         dw    offset    reset        ;Code 1: EXIT to DOS -
  54.                         ; & restore orig. directory
  55.         dw    offset    cmd_exec    ;Code 2: Exec via Command.Com
  56.         dw    offset    dir_exec    ;Code 3: Execute .EXE or .COM
  57.         dw    offset    shell_exec    ;Code 4: Shell to DOS
  58.         dw    offset    change_env    ;Code 5: Alter environment
  59. LAST_CODE    equ    5
  60. INVALID_CODE    equ    07fh
  61.     ;-----------
  62.     ;  Buffer space
  63.     ;-----------
  64. EVEN
  65. exec_path    db    128 dup    (?)        ;Program path from U-I
  66. exec_tail    db    128 dup (?)        ;Command tail from U-I
  67. ui_buf        db    UI_BUFSIZE dup (?)    ;U-I's memory buffer
  68. exec_code    dw    ?            ;Return code from U-I
  69.  
  70. cmd_path    dw    ?            ;Ptr to Command.Com path
  71. ui_path        dw    ?             ;Ptr to user interface path
  72. cur_drive    db    ?
  73. cur_directory    db    66 dup (0)
  74.  
  75. prog_path    db    128 dup (0)        ;Program to execute
  76. cmd_tail    db    128 dup (0)        ;Line to execute
  77.  
  78. sp_save        dw    ?            ;To save stack pointer
  79. ss_save        dw    ?            ;To save stack segment
  80. our_psp        dw    ?            ;Segment of our PSP
  81. env_seg        dw    ?            ;Segment of environment copy
  82. env_end        dw    ?            ;Offset of end of environment
  83. pause_flag    dw    0
  84.     ;-----------
  85.     ;  Literal strings
  86.     ;  and messages
  87.     ;-----------
  88. comspec        db    "COMSPEC=",0        ;Environment string
  89. ui_spec        db    "PCRSHELL=",0        ;Environment string
  90.  
  91. no_var        db    "Cannot find COMSPEC or PCRSHELL environment variable"
  92. no_var_len    dw    $-no_var
  93.  
  94. bad_code    db    "Unknown execution code"
  95. bad_code_len    dw    $-bad_code
  96.  
  97. bad_mem        db    "Memory allocation error"
  98. bad_mem_len    dw    $-bad_mem
  99.  
  100. no_env        db    "Cannot allocate memory for new environment"
  101. no_env_len    dw    $-no_env
  102.  
  103. long_env    db    "Inherited environment is too long"
  104. long_env_len    dw    $-long_env
  105.  
  106. stop        db    " -- Program stopping"
  107. stop_len    dw    $-stop
  108.  
  109. ;----------------------------------------------------------
  110. ;  Program code
  111. ;----------------------------------------------------------
  112.     .CODE
  113. error    macro    msg
  114.     mov    cx,&msg&_len
  115.     lea    dx,&msg
  116.     call    errorout
  117.     endm
  118.     ;-----------
  119.     ;  Program begins here
  120.     ;-----------
  121. begin:    mov    ax,@data              ;Set up registers
  122.     mov    ds,ax
  123.     mov    our_psp,es            ;Save PSP
  124.     mov    ss_save,ss            ;  and stack segment
  125.     cld
  126.     call    save_dir            ;Save current default dir.
  127.     call    release_mem            ;Release unneeded RAM
  128.     call    new_envr            ;Make copy of environment
  129.  
  130.     push    ds                ;Copy data segment
  131.     pop    es                ;  to ES
  132.     lea    di,ui_buf            ;ES:DI ==> U-I's memory buff.
  133.     mov    cx,UI_BUFSIZE/2            ;Words to fill
  134.     sub    ax,ax                ;AX = 0
  135.     rep    stosw                ;Clear buffer
  136.     call    find_paths            ;Find paths to Command.Com
  137.     ;------------
  138.     ;  Main program loop
  139.     ;------------
  140. lp:    call    run_ui                ;Exec user_interface
  141.     push    ds                ;Copy data segment
  142.     pop    es                ;  to ES
  143.     lea    si,model_fcb            ;Clear FCB1
  144.     lea    di,fcb1                ;  by copying the
  145.     mov    cx,fcb_len            ;  model FCB into it
  146.     rep    movsb
  147.     lea    si,model_fcb            ;Clear FCB2
  148.     lea    di,fcb2                ;  in the same way
  149.     mov    cx,fcb_len
  150.     rep    movsb
  151.     lea    di,prog_path            ;Clear prog_path &
  152.     mov    ax,0                ; cmd_tail
  153.     mov    cx,128
  154.     rep    stosw
  155.  
  156.     mov    bx,[exec_code]            ;Get execution code
  157.     and    bx,80h                ;Isolate Pause bit
  158.     mov    pause_flag,bx            ;  and save it
  159.     mov    bx,[exec_code]            ;Get return code again
  160.     and    bx,7fh                ;Clear pause bit
  161.     cmp    bx,LAST_CODE            ;Is code okay?
  162.     jbe    lp2                ;Yes -- go
  163.     error    bad_code            ;Else report error
  164.  
  165. lp2:    add    bx,bx                ;BX * 2 for call table
  166.     call    [call_table+bx]            ;Call requested routine
  167.     jmp    lp                ;Loop back to U-I again
  168. ;----------------------------------------------------------
  169. ;  Utility Routines
  170. ;----------------------------------------------------------
  171.     ;-----------
  172.     ;  Find length of a string
  173.     ;  Offset and segment are received
  174.     ;  on the stack.  Length is returned
  175.     ;  in AX
  176.     ;-----------
  177. strlen        proc    uses es di cx, str_off:word, str_seg:word
  178.     mov    es,str_seg            ;Put string address
  179.     mov    di,str_off            ;  in ES:DI
  180.     sub    al,al                ;AL = 0 (end marker)
  181.     mov    cx,-1                ;Maximum possible length
  182.     repne    scasb                ;Search for end
  183.     dec    di                ;DI ==> last character
  184.     mov    ax,di                ;Offset in AX
  185.     sub    ax,str_off            ;AX = string length
  186.     ret
  187. strlen        endp
  188.     ;-----------
  189.     ;  Copy a string from DS:SI to ES:DI
  190.     ;  Maximum length to copy received on stack
  191.     ;  Returns number of bytes moved in AX (including 0 byte)
  192.     ;-----------
  193. strcpy        proc    uses di si bx cx, max_len:word
  194.     mov    cx,max_len            ;Length in CX
  195.     sub    bx,bx                ;BX will count bytes
  196. cpy1:    or    cx,cx                ;Test for end
  197.     jz    cpy2                ;Go if at end
  198.     lodsb                    ;Else get a byte
  199.     stosb                    ;Move it
  200.     inc    bx                ;Count it
  201.     dec    cx                ;Reduce maximum left
  202.     or    al,al                ;Was it end of string?
  203.     jnz    cpy1                ;No -- move another
  204. cpy2:    mov    ax,bx                ;Return count of bytes
  205.     ret
  206. strcpy        endp
  207.     ;-----------
  208.     ;  Save the default drive
  209.     ;  and subdirectory.
  210.     ;-----------
  211. save_dir    proc uses dx si
  212.     mov    ah,19h                ;DOS Service: Get cur. disk
  213.     int    21h                ;Call DOS
  214.     mov    [cur_drive],al            ;Save default drive
  215.     mov    dl,al                ;Drive in DL
  216.     inc    dl                ;A=1, B=2, etc.
  217.     lea    si,cur_directory        ;SI ==> buffer
  218.     add    al,'A'                ;AL has drive letter
  219.     mov    [si],al                ;Save it
  220.     mov    byte ptr [si+1],':'        ; and a colon
  221.     add    si,2                ;Move pointer past drive
  222.     mov    ah,47h                ;DOS Service: Get cur. dir.
  223.     int    21h                ;Call DOS
  224.     ret
  225. save_dir    endp
  226.     ;-----------
  227.     ;  Restore default drive
  228.     ;  and directory
  229.     ;-----------
  230. restore_dir    proc    uses dx
  231.     mov    dl,[cur_drive]            ;Get original drive
  232.     mov    ah,0eh                ;DOS Service: set cur. disk
  233.     int    21h                ;Call DOS
  234.     lea    dx,cur_directory        ;DX ==> directory
  235.     mov    ah,3bh                ;DOS Service: Change dir.
  236.     int    21h                ;Call DOS
  237.     ret
  238. restore_dir    endp
  239.     ;-----------
  240.     ;  Release unneeded memory
  241.     ;  to make room for child
  242.     ;  programs
  243.     ;-----------
  244. release_mem    proc    uses bx
  245.     mov    ax,our_psp            ;Get seg. of this program
  246.     mov    es,ax                ;ES==> our PSP
  247.     mov    bx,seg end_seg            ;BX = end of our program
  248.     sub    bx,ax                ;BX = paragraphs to keep
  249.     mov    ah,4ah                ;DOS Service: set block size
  250.     int    21h                ;Call DOS
  251.     jc    rel_mem1            ;Go if error
  252.     ret                    ;Else return
  253. rel_mem1:
  254.     error    bad_mem                ;Abort if error
  255. release_mem    endp
  256.     ;-----------
  257.     ;  Report error and
  258.     ;  abort program.  Receives
  259.     ;  pointer to message in DX
  260.     ;  and message length in CX
  261.     ;-----------
  262. errorout    proc
  263.     mov    bx,STDERR            ;Report to screen
  264.     mov    ah,40h                ;DOS Service: write to handle
  265.     int    21h                ;Call DOS
  266.     lea    dx,stop                ;DS:DX==> halting message
  267.     mov    cx,stop_len            ;CX has length
  268.     mov    ah,40h                ;Write to handle again
  269.     int    21h                ;Call DOS
  270.     call    restore_dir            ;Restore original dir.
  271.     mov    ax,4cffh            ;Exit with error
  272.     int    21h                ;Return to DOS
  273. errorout    endp
  274. ;----------------------------------------------------------
  275. ;  EXEC functions -- These routines run child programs
  276. ;----------------------------------------------------------
  277.     ;----------
  278.     ;  Execute a 
  279.     ;  child program
  280.     ;----------
  281. execute        proc    uses bx cx dx di si
  282.     push    ds
  283.     pop    es                ;ES ==> our data segment
  284.     lea    dx,prog_path            ;DS:DX ==> prog. to execute
  285.     lea    bx,epb                ;ES:BX ==> EPB
  286.     push    bp                ;Save stack frame pointer
  287.     mov    [sp_save],sp            ;Save stack pointer
  288.     mov    ax,4b00h            ;Func. 4b: execute program
  289.     int    21h                ;Call DOS
  290.     mov    ax,@data            ;Restore data segment
  291.     mov    ds,ax
  292.     mov    ss,[ss_save]            ;Restore stack
  293.     mov    sp,[sp_save]
  294.     pop    bp                ;Restore frame pointer
  295.     cld                    ;Avoid possible bug in 2.x
  296.     test    pause_flag,-1            ;Should we pause?
  297.     jz    ex1                ;No -- go
  298.     mov    ah,8                ;Else wait for keystroke
  299.     int    21h
  300.     cmp    al,0                ;Extended key?
  301.     jne    ex1                ;No -- go
  302.     mov    ah,8                ;Yes -- call again
  303.     int    21h                ; for rest of key code
  304. ex1:    ret
  305. execute        endp
  306.     ;----------
  307.     ;  Run the user-interface program
  308.     ;  after setting up the appropriate
  309.     ;  values in the inter-application 
  310.     ;  communications area (IACA)
  311.     ;----------
  312. run_ui        proc uses cx di si
  313.     mov    exec_code,INVALID_CODE        ;Make sure of valid return
  314.     mov    pause_flag,0            ;No pause on return
  315.     sub    ax,ax                ;AX = 0
  316.     mov    es,ax                ;ES ==> BIOS area
  317.     mov    di,IACA                ;ES:DI ==> IACA
  318.     mov    ax,ds                ;Get data segment
  319.     stosw                    ;Save it
  320.     lea    ax,exec_path            ;Get offset of path buffer
  321.     stosw                    ;Save it
  322.     lea    ax,exec_tail            ;Get offset of tail buffer
  323.     stosw                    ;Save it
  324.     lea    ax,ui_buf            ;Get offset of memory buffer
  325.     stosw                    ;Save it
  326.     lea    ax,exec_code            ;Get offset of code word
  327.     stosw                    ;Save it
  328.  
  329.     push    ds                ;Copy data segment
  330.     pop    es                ;  to ES
  331.     lea    di,cmd_tail            ;ES:DI==> command tail 
  332.     sub    ax,ax                ;AX = 0
  333.     stosw                    ;Clear command tail
  334.  
  335.     lea    di,prog_path            ;ES:DI ==> program path
  336.     mov    si,[ui_path]
  337.     push    ds                ;Save DS
  338.     mov    ds,[env_seg]            ;DS:SI ==> U-I path name
  339.     mov    ax,128                ;Maximum bytes to move
  340.     push    ax
  341.     call    strcpy                ;Move the string
  342.     add    sp,2                ;Clear the stack
  343.     pop    ds                ;Recover data segment
  344.     call    execute                ;Execute U-I
  345.     ret
  346. run_ui        endp
  347. ;----------------------------------------------------------
  348. ;  Routines to service commands from User Interface
  349. ;----------------------------------------------------------
  350.     ;----------
  351.     ;  Execution code 0
  352.     ;  Exit to DOS
  353.     ;----------
  354. exit    proc
  355.     mov    ax,4c00h            ;Return to DOS -- no error
  356.     int    21h
  357. exit    endp
  358.     ;----------
  359.     ;  Execution code 1
  360.     ;  Reset original default
  361.     ;  drive & directory and
  362.     ;  exit to DOS
  363.     ;----------
  364. reset    proc
  365.     call    restore_dir            ;Restore default dir.
  366.     jmp    exit                ;Now exit
  367. reset    endp
  368.     ;----------
  369.     ;  Execution code 2
  370.     ;  Execute a program
  371.     ;  or DOS command
  372.     ;  via Command.Com
  373.     ;----------
  374. cmd_exec    proc
  375.     push    ds
  376.     pop    es                ;ES==> data segment
  377.     push    ds                ;Save DS
  378.     lea    di,prog_path            ;ES:DI==> program name buffer
  379.     mov    si,[cmd_path]
  380.     mov    ds,[env_seg]            ;DS:SI==> Command.Com path
  381.     mov    ax,128                ;Bytes to move
  382.     push    ax
  383.     call    strcpy                ;Move path name
  384.     add    sp,2                ;Clear the stack
  385.     pop    ds                ;Recover data segment
  386.     lea    di,cmd_tail+1            ;ES:DI==> tail buffer
  387.     push    di                ;Save the address
  388.     mov    al,'/'                ;Start tail with
  389.     stosb                          ; "/c "
  390.     mov    al,'c'
  391.     stosb
  392.     mov    al,' '
  393.     stosb
  394.     lea    si,exec_tail            ;DS:SI==> command to run
  395.     mov    ax,124                ;Maximum bytes
  396.     push    ax
  397.     call    strcpy                ;Move the string
  398.     add    sp,2
  399.     pop    di                ;DS:DI ==> cmd_tail + 1
  400.     push    ds                ;Push segment of cmd_tail
  401.     push    di                ; and offset of cmd_tail text
  402.     call    strlen                ;Find length of tail
  403.     add    sp,4                ;Clear the stack
  404.     mov    bx,ax                ;Length in BX
  405.     cmp    byte ptr [di+bx-1],CR        ;Does it end with a CR?
  406.     jne    ce1                ;No -- go
  407.     dec    ax                ;Else reduce count
  408.     jmp    short ce2            ;And go
  409. ce1:    mov    byte ptr [di+bx],CR        ;Put carriage return at end
  410. ce2:    mov    [cmd_tail],al            ;Put count in place
  411.     call    execute                ;Run the program
  412.     ret
  413. cmd_exec    endp
  414.     ;-----------
  415.     ;  Execution code 3
  416.     ;  Execute an .EXE or .COM
  417.     ;  program directly
  418.     ;-----------
  419. dir_exec    proc
  420.     push    ds                ;Copy data segment
  421.     pop    es                ; to ES
  422.     lea    si,exec_path            ;DS:SI==> program to run
  423.     lea    di,prog_path            ;ES:DI==> execution buffer
  424.     mov    ax,128                ;Maximum bytes
  425.     push    ax
  426.     call    strcpy                ;Copy the string
  427.     add    sp,2                ;Clear the stack
  428.     lea    si,exec_tail            ;Program tail
  429.     lea    di,cmd_tail+1            ;Execution tail
  430.     mov    ax,127                ;Maximum tail bytes
  431.     push    ax
  432.     call    strcpy                ;Move the tail
  433.     add    sp,2                ;Clear the stack
  434.     dec    ax                ;Don't count 0 byte
  435.     mov    bx,ax                ;Length of string in BX
  436.     cmp    [cmd_tail+bx],CR        ;Is last byte a CR?
  437.     jne    de1                ;No -- go
  438.     dec    ax                ;Else reduce count
  439.     jmp    short de2            ;And go
  440. de1:    mov    [cmd_tail+bx+1],CR        ;Terminate with a CR
  441. de2:    mov    [cmd_tail],al            ;Store the count
  442.     or    al,al                ;Was there a tail?
  443.     jz    dir_exec1            ;No -- go
  444.  
  445.     lea    si,cmd_tail+1            ;DS:SI==> tail text
  446.     lea    di,fcb1                ;ES:DI==> 1st FCB
  447.     mov    ax,2901h            ;DOS Service: Parse fname
  448.     int    21h                ;Call DOS
  449.     lea    di,fcb2                ;ES:DI==> 2nd FCB
  450.     mov    ax,2901h            ;DOS Service: Parse fname
  451.     int    21h                ;Call DOS
  452. dir_exec1:
  453.     call    execute                ;Run the program
  454.     ret
  455. dir_exec    endp
  456.     ;-----------
  457.     ;  Execution code 4
  458.     ;  Shell to Command.Com
  459.     ;  and give user control
  460.     ;-----------
  461. shell_exec    proc
  462.     push    ds                ;Copy data segment
  463.     pop    es                ;  to ES
  464.     lea    di,prog_path            ;ES:DI==>execution buffer
  465.     push    ds                ;Save data segment
  466.     mov    si,[cmd_path]
  467.     mov    ds,[env_seg]            ;DS:SI==>Command.Com path
  468.     mov    ax,128                ;Maximum bytes
  469.     push    ax
  470.     call    strcpy                ;Copy path name
  471.     add    sp,2                ;Clear the stack
  472.     pop    ds                ;Recover data segment
  473.     call    execute
  474.     ret
  475. shell_exec    endp
  476.     ;-----------
  477.     ;  Execution code 5
  478.     ;  Add, delete or change
  479.     ;  environment string
  480.     ;-----------
  481. change_env    proc
  482.     call    del_env_string            ;Delete old value
  483.     push    ds                ;Copy data segment
  484.     pop    es                ;  to ES
  485.     lea    di,exec_tail            ;ES:DI==>new value
  486.     mov    cx,128                ;Maximum bytes
  487.     mov    al,"="                ;Look for "="
  488.     repne    scasb
  489.     cmp    byte ptr es:[di],0        ;Is there new text?
  490.     je    change_env1            ;No -- go
  491.     call    add_env_string            ;Else add this string
  492. change_env1:
  493.     call    find_paths            ;Readjust path pointers
  494.     ret
  495. change_env    endp
  496. ;----------------------------------------------------------
  497. ;  Environment routines -- These routines handle our copy
  498. ;  of the environment, which is passed to both the user-interface
  499. ;  and to every application
  500. ;----------------------------------------------------------
  501.     ;-----------
  502.     ;  Create a new environment that
  503.     ;  we can manipulate and send to
  504.     ;  child programs
  505.     ;-----------
  506. new_envr    proc uses bx cx si di
  507.     mov    bx,ENV_SIZE/16        ;BX = # of paragraphs for environ.
  508.     mov    ah,48h            ;DOS Service: Allocate block
  509.     int    21h            ;Get memory block
  510.     jnc    env1            ;Go if okay
  511.     error    no_env            ;Else report error and stop
  512. env1:    mov    [EPB_environ],ax    ;Save new segment in EPB
  513.     mov    [env_seg],ax        ;  and for us
  514.     mov    es,ax            ;ES==> new segment
  515.     push    ds            ;Save DS
  516.     mov    bx,our_psp        ;Get PSP address
  517.     mov    ds,bx            ;DS==> PSP
  518.     mov    ds,ds:[2ch]        ;DS==> inherited environment
  519.     sub    si,si            ;DS:SI==> current environment
  520.     mov    di,si            ;ES:DI==> new environment
  521.     sub    cx,cx            ;CX will count bytes
  522. env2:    test    byte ptr ds:[si],-1    ;Are we done?
  523.     jz    env4            ;Yes -- go
  524. env3:    lodsb                ;Get a byte
  525.     stosb                ;Store it
  526.     inc    cx            ;And count it
  527.     or    al,al            ;End of string?
  528.     jz    env2            ;Yes -- start next string
  529.     cmp    cx,ENV_SIZE        ;Past the end?
  530.     jae    env_err            ;Yes -- report error
  531.     jmp    env3            ;Else do next byte
  532. env4:    lodsb                ;Get last 0
  533.     stosb                ;Store it
  534.     pop    ds            ;Clear stack
  535.     dec    di            ;DI ==> last 0
  536.     mov    [env_end],di        ;Save address of end of env.
  537.     ret
  538. env_err:
  539.     pop    ds            ;Clear the stack
  540.     error    long_env        ;Report error and end
  541. new_envr    endp
  542.     ;----------
  543.     ;  Find environment variable in 
  544.     ;  our copy of the environment.
  545.     ;  Return a pointer to beginning 
  546.     ;  of environment string in ES:AX
  547.     ;  Receives a pointer requested name in DS:SI
  548.     ;----------
  549. find_env_var    proc    uses di si cx dx 
  550.     mov    es,env_seg        ;ES:DI ==> copy of environ.
  551.     sub    di,di
  552.     push    ds
  553.     push    si            ;Pass string address
  554.     call    strlen            ;Find length of string at DS:SI
  555.     add    sp,4            ;Clear stack
  556.     mov    dx,ax            ;DX has length
  557. fen1:    cmp    byte ptr es:[di],0    ;End of environment?
  558.     jz    fen_err            ;Yes -- error return
  559.     mov    cx,dx            ;Length in CX
  560.     push    di            ;Remember where we started
  561.     push    si
  562.     repe    cmpsb            ;At variable name?
  563.     pop    si            ;Recover start of strings
  564.     pop    di
  565.     jz    fen_found        ;Found it!
  566.     mov    al,0            ;Else search for end of string
  567.     mov    cx,8000h        ;Look for 32K
  568.     repne    scasb            ;Move to end of string
  569.     jmp    fen1            ;And try again
  570. fen_err:
  571.     mov    ax,-1            ;Return impossible addr.
  572.     jmp    short fen_end
  573. fen_found:
  574.     mov    ax,di            ;Move addr. to AX
  575. fen_end:
  576.     ret                ;Return to caller
  577. find_env_var    endp
  578.     ;-----------
  579.     ;  Find value of environment string
  580.     ;  Receives pointer to beginning of
  581.     ;  name, returns pointer to beginning
  582.     ;  of value
  583.     ;-----------
  584. find_env_val    proc    uses es di cx, var_off:word
  585.     mov    es,env_seg
  586.     mov    di,var_off        ;ES:DI ==> environ. variable
  587.     mov    al,"="            ;Look for "=" sign
  588.     mov    cx,-1            ;Maximum length
  589.     repne    scasb            ;Look for "="
  590.     mov    ax,di            ;Pointer to val in AX
  591.     ret
  592. find_env_val    endp
  593.     ;-----------
  594.     ;  Find paths to Command.Com and user-interface
  595.     ;  by looking in our copy of the environment.
  596.     ;  Abort with an error if either is missing.
  597.     ;-----------
  598. find_paths    proc    uses si
  599.     lea    si,comspec        ;DS:SI ==> "Command.Com"
  600.     call    find_env_var        ;Get addr. in environment
  601.     cmp    ax,-1            ;Was it found?
  602.     je    fp_error        ;No -- go
  603.     push    ax            ;Else pass offset
  604.     call    find_env_val        ;Find beginning of path
  605.     add    sp,2            ;Clear stack
  606.     mov    [cmd_path],ax        ;Save address
  607.     lea    si,ui_spec        ;DS:SI ==> "PCRSHELL"
  608.     call    find_env_var        ;Get addr. in environment
  609.     cmp    ax,-1            ;Was it found?
  610.     je    fp_error        ;No -- go
  611.     push    ax            ;Else pass offset
  612.     call    find_env_val        ;Find beginning of path
  613.     add    sp,2            ;Clear stack
  614.     mov    [ui_path],ax        ;Save address
  615.     ret
  616. fp_error:
  617.     error    no_var            ;Report error and abort
  618. find_paths    endp
  619.     ;-----------
  620.     ;  Erase environment variable by
  621.     ;  copying all following strings over
  622.     ;  it.  String to erase is in exec_tail buffer.
  623.     ;-----------
  624. del_env_string    proc    uses di si cx
  625.     push    ds
  626.     pop    es
  627.     lea    di,exec_tail        ;ES:DI ==> exec_tail
  628.     mov    cx,128            ;Maximum size
  629.     mov    al,'='            ;Look for "="
  630.     repne    scasb            ;Find end of variable name
  631.     dec    di            ;ES:DI ==> "="
  632.     mov    byte ptr es:[di],0    ;Terminate name
  633.     lea    si,exec_tail        ;DS:SI ==> name
  634.     call    find_env_var        ;Find name in environment
  635.     mov    byte ptr ds:[di],'='    ;Replace "="
  636.     cmp    ax,-1            ;Did we find it?
  637.     je    del_env_end        ;No -- go
  638.     mov    di,ax            ;ES:DI ==> string to erase
  639.     push    di            ;Save address
  640.     mov    al,0            ;Look for end of string
  641.     mov    cx,-1            ;Look until end
  642.     repne    scasb            ;Move to 1st byte after end
  643.     mov    si,di            ;SI ==> next string
  644.     pop    di            ;ES:DI ==> beginning of string
  645.     mov    cx,[env_end]        ;CX has address of end of env.
  646.     push    ds
  647.     mov    ds,env_seg        ;DS:SI ==> next string
  648. del_env1:
  649.     movsb                ;Move a byte
  650.     cmp    si,cx            ;Are we done?
  651.     jbe    del_env1        ;No -- loop back
  652.     dec    di            ;ES:DI ==> last 0
  653.     pop    ds            ;Restore data segment
  654.     mov    [env_end],di        ;Save end address
  655. del_env_end:
  656.     ret
  657. del_env_string    endp
  658.     ;-----------
  659.     ;  Add a string to our copy of the
  660.     ;  environment table.  The string is
  661.     ;  in the exec_tail buffer
  662.     ;-----------
  663. add_env_string    proc    uses di si cx
  664.     mov    es,[env_seg]
  665.     mov    di,[env_end]        ;ES:DI ==> end of environment
  666.     lea    si,exec_tail        ;DS:SI ==> new string
  667.     push    ds
  668.     push    si            ;Pass address of string
  669.     call    strlen            ;Find length to add
  670.     add    sp,4            ;Clear the stack
  671.     inc    ax            ;Length + final 0
  672.     mov    cx,ax            ;Save string length
  673.     add    ax,di            ;Is there room for it?
  674.     cmp    ax,ENV_SIZE
  675.     ja    add_env_end        ;No -- simply return
  676.     rep    movsb            ;Move the string
  677.     mov    byte ptr es:[di],0    ;Terminate environment
  678.     mov    [env_end],di        ;Save new end address
  679. add_env_end:
  680.     ret
  681. add_env_string    endp
  682.     end    begin
  683.  
  684.