home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol9n14.zip / BAT2EXEC.ZIP / BAT2EXEC.ASM next >
Assembly Source File  |  1990-05-17  |  109KB  |  3,575 lines

  1.         page    66,132
  2. ;============================================================================
  3. ; BAT2EXEC.COM - a batch file compiler
  4. ;
  5. ;    BAT2EXEC filename
  6. ;
  7. ; Revision History:
  8. ;
  9. ;    Version 1.0    Initial Release     PC Magazine Vol 9 Num 14
  10. ;
  11. ;============================================================================
  12.  
  13.         code    segment
  14.         assume    cs:code
  15.  
  16.         org    2ch
  17. env_segment    dw    ?            ;Word containing the segment
  18.                         ;  of the program's env. block.
  19.         org    80h
  20. command_tail    db    ?            ;Offset of the command tail.
  21.  
  22.         org    100h
  23.  
  24. main:        jmp    initialize
  25. program     db    13,10,"BAT2EXEC 1.0 "
  26. copyright    db    "(c) 1990 Ziff Communications Co.",10,13
  27. author        db    "PC Magazine ",254," Douglas Boling"
  28.         db    10,13,"$",1Ah
  29. ;----------------------------------------------------------------------------
  30. ;Equates used to find data offsets in the compiled program.
  31. ;----------------------------------------------------------------------------
  32. run_buff_size    dw    256            ;Size of runtime buffers
  33.  
  34. std_data_size    equ    offset data_end - data_start
  35. code_start_ptr    equ    [bp + offset code_start - offset data_start]
  36. com_stack_ptr    equ    [bp + offset stack_ptr - offset data_start]
  37. com_prog_size    equ    [bp + offset prog_segsize - offset data_start]
  38. com_label_start equ    [bp + offset label_list_strt - offset data_start]
  39. string1_buff    equ    [bp + offset str1_buff_ptr - offset data_start]
  40. string2_buff    equ    [bp + offset str2_buff_ptr - offset data_start]
  41. string3_buff    equ    [bp + offset str3_buff_ptr - offset data_start]
  42. forloop_ptr    equ    [bp + offset floop_ptr - offset data_start]
  43. stdout_hdl    equ    [bp + offset file_handle1 - offset data_start]
  44. outfile_hdl    equ    [bp + offset file_handle2 - offset data_start]
  45. stdin_hdl    equ    [bp + offset file_handle3 - offset data_start]
  46. infile_hdl    equ    [bp + offset file_handle4 - offset data_start]
  47. environment_seg equ    [bp + offset master_env - offset data_start]
  48. dos_version    equ    [bp + offset version_num - offset data_start]
  49. process_rc    equ    [bp + offset proc_rc - offset data_start]
  50. shift_count    equ    [bp + offset shift_cnt - offset data_start]
  51.  
  52. code_call_size    equ    offset code_call_end - offset code_call
  53. code_jmp_size    equ    offset code_jmp_end - offset code_jmp
  54. code_jc_size    equ    offset code_jc_end - offset code_jc
  55. code_jnc_size    equ    offset code_jnc_end - offset code_jnc
  56. code_jmpdis_size   equ       offset code_jmpdis_end - offset code_jmpdis
  57. code_leasi_size equ    offset code_leasi_end - offset code_leasi
  58. code_movsi_size equ    offset code_movsi_end - offset code_movsi
  59. code_movsiim_size equ    offset code_movsiim_end - offset code_movsiim
  60. code_leadi_size equ    offset code_leadi_end - offset code_leadi
  61. code_movdi_size equ    offset code_movdi_end - offset code_movdi
  62. code_movdiim_size equ    offset code_movdiim_end - offset code_movdiim
  63. ;============================================================================
  64. ;Compiler data
  65. ;============================================================================
  66. fileecho    db    0            ;File echo flag
  67. lineecho    db    0            ;Current line echo flag
  68.  
  69. command_table    db    "IF",0                  ;Commands processed by
  70.         db    "REM",0                 ;  compiler
  71.         db    "FOR",0
  72.         db    "ECHO",0
  73.         db    "GOTO",0
  74.         db    "EXIT",0
  75.         db    "PAUSE",0
  76.         db    "SHIFT",0
  77.         db    "SET",0
  78.         db    "CALL",0
  79.         db    "PATH",0
  80.         db    "PROMPT",0
  81.         db    "CD",0                  ;DOS commands internal to
  82.         db    "MD",0                  ;  command.com.
  83.         db    "RD",0
  84.         db    "CLS",0
  85.         db    "DIR",0
  86.         db    "DEL",0
  87.         db    "REN",0
  88.         db    "VER",0
  89.         db    "VOL",0
  90.         db    "CTTY",0
  91.         db    "CHCP",0
  92.         db    "TYPE",0
  93.         db    "COPY",0
  94.         db    "DATE",0
  95.         db    "TIME",0
  96.         db    "ERASE",0
  97.         db    "CHDIR",0
  98.         db    "MKDIR",0
  99.         db    "RMDIR",0
  100.         db    "BREAK",0
  101.         db    "RENAME",0
  102.         db    "DELETE",0
  103.         db    "VERIFY",0
  104.         db    "COMMAND",0,0
  105.  
  106. batcmd_jmptbl    dw    if_cmd            ;if command
  107.         dw    rem_cmd         ;rem command
  108.         dw    for_cmd         ;for command
  109.         dw    echo_cmd        ;echo command
  110.         dw    goto_cmd        ;goto command
  111.         dw    rem_cmd         ;exit command
  112.         dw    pause_cmd        ;pause command
  113.         dw    shift_cmd        ;shift command
  114.         dw    set_cmd         ;set command
  115.  
  116.         dw    internal_cmd        ;call command
  117.         dw    set_cmd         ;Path command
  118.         dw    set_cmd         ;Prompt command
  119.         dw    internal_cmd        ;DOS internal command
  120.         dw    external_cmd        ;DOS program
  121.         dw    label_cmd        ;Process BAT label
  122. batcmd_jmptbl1    =    $
  123.  
  124. ifstr1        db    "ERRORLEVEL"
  125. ifstr2        db    "EXIST"
  126.  
  127. internal_cmdsw    db    "/C "                   ;Switch for transient commands
  128.  
  129. for_active_flag db    0            ;Set if parsing a FOR loop
  130. goto_active    db    0            ;Set if goto parsed
  131. goto_data_ptr    dw    0            ;Data offset of last goto
  132.  
  133. cmd_switches    db    ?            ;Used if command line switches
  134. cmd_switch_end    =    $            ;  needed.
  135.  
  136. last_routine    dw    offset init_code_next    ;Last canned routine used.
  137.  
  138. codebuff_start    dw    0            ;Buffer to construct the code
  139. codebuff_ptr    dd    0            ;  image of the COM file.
  140.  
  141. databuff_start    dw    ?            ;Buffer to hold the data
  142. databuff_end    dw    ?            ;  image of the COM file.
  143.  
  144. firstlabel    dw    -1            ;Ptr to 1st label in COM file
  145.  
  146. outbuff_ptr    dd    0            ;Buffer to hold the final
  147. outbuff_end    dw    0            ;  image of the COM file.
  148.  
  149. quote_flag    db    0            ;Disable translate flag
  150. redirect_in    db    0            ;Input redirection flag
  151. redirect_out    db    0            ;Output redirection flag
  152.  
  153. pipe_toggle    db    0            ;Piping file flag
  154. pipein_file    dw    0
  155. pipein_flag    db    0
  156. pipeout_file    dw    0
  157. pipeout_flag    db    0
  158. pipe1_file    dw    0
  159.         db    "T^M^P_$1.!!!",0        ;Name of piping file 1
  160. pipe2_file    dw    0
  161.         db    "T^M^P_$2.!!!",0        ;Name of piping file 2
  162.  
  163. inbuff_ptr    dw    offset end_of_code+512    ;Buffer for BAT file
  164. inbuff_size    dw    16384            ;Size of input buffer
  165.  
  166. file_pointer    dw    ?            ;Ptr to BAT data not read.
  167. file_handle    dw    ?            ;Handle of BAT file
  168. file_linecount    dw    0            ;Line number being processed.
  169.  
  170. com_string    db    ".COM",0                ;Extension for output file
  171. outfile_name    db    13 dup (" ")            ;Name of output file.
  172.  
  173. filemsg1    db    13,10,"Error in line $" ;File identification message.
  174.  
  175. errmsg0     db    "Need DOS 2.0 or greater$"
  176. errmsg1     db    13,10,"Syntax: BAT2EXEC [filename]",13,10,"$"
  177. errmsg2     db    "Can",39,"t find input file$"
  178. errmsg3     db    "Not enough memory$"
  179. errmsg4     db    "No input file specified$"
  180. errmsg5     db    "COM file size too big$"
  181. errmsg6     db    "Syntax error$"
  182. errmsg7     db    "Compiler data buffer full$"
  183. errmsg8     db    "Label defined more than once$"
  184. errmsg9     db    "Label "
  185. errmsg9labl    db    8 dup (" ")
  186.         db    "not found$"
  187. errmsg10    db    "Illegal disk specified$"
  188. errmsg11    db    "FOR loops cannot be nested$"
  189. endmsg        db    13,10,"$"
  190.  
  191. ;----------------------------------------------------------------------------
  192. ; Start of compiler code.
  193. ;----------------------------------------------------------------------------
  194. initialize    proc    near
  195.         assume    cs:code,ds:code,es:code
  196.         mov    dx,offset program    ;Display copyright message.
  197.         mov    ah,9
  198.         int    21h
  199.         cld                ;Set string operations 'up.'
  200.         mov    ah,30h            ;Get DOS version, run only
  201.         int    21h            ;  if 2.0 or greater.
  202.         xchg    al,ah            ;Swap major, minor numbers
  203.         mov    dx,offset errmsg0    ;Bad DOS version
  204.         cmp    ah,2
  205.         jb    jmp_disp_error
  206.  
  207.         mov    sp,offset end_of_code + 512    ;Move stack
  208.         mov    ah,4ah                ;Reduce memory
  209.         mov    bx,1000h            ; allocation to 64K
  210.         int    21h
  211.  
  212.         mov    ax,inbuff_ptr        ;Compute start of buffer for
  213.         add    ax,inbuff_size        ;  COM file data.
  214.         mov    databuff_start,ax
  215.  
  216.         mov    ah,48h            ;Allocate memory block for
  217.         mov    bx,1000h        ;  intermediate buffer.
  218.         int    21h
  219.         mov    dx,offset errmsg3    ;Not enough memory msg
  220.         jc    jmp_disp_error
  221.         mov    word ptr codebuff_ptr[2],ax    ;Save segment.
  222.  
  223.         mov    ah,48h            ;Allocate memory block for
  224.         mov    bx,1000h        ;  output file buffer.
  225.         int    21h
  226.         jc    jmp_disp_error
  227.         mov    word ptr outbuff_ptr[2],ax    ;Save segment.
  228. ;
  229. ;Parse the command line for switches.
  230. ;
  231.         mov    si,offset command_tail
  232.         xor    cx,cx
  233.         or    cl,[si]         ;Get command line length
  234.         je    parse_cmdline_end    ;If zero, skip parse routine
  235.         inc    si
  236. parse_cmdline_l1:
  237.         xor    bl,bl            ;Search for the next
  238.         call    scanline        ;  non-space character.
  239.         jc    parse_cmdline_end
  240.         mov    al,[si]
  241.         cmp    al,"/"                  ;See if command switch
  242.         je    parse_switch_found
  243.         call    loadbatfile        ;Load input BAT file
  244.         jc    jmp_disp_error
  245.         jmp    short parse_cmdline_end
  246. parse_switch_found:
  247.         mov    dx,offset errmsg2    ;No cmd line switches.
  248. jmp_disp_error:
  249.         jmp    disp_error
  250. parse_cmdline_end:
  251. ;
  252. ;Compile BAT file line by line.
  253. ;
  254.         mov    si,inbuff_ptr        ;SI points to input BAT file
  255.         mov    di,databuff_start    ;DI points to COM file data.
  256.         add    di,std_data_size
  257. new_line:
  258.         inc    file_linecount        ;Inc line number
  259.         mov    al,fileecho        ;Copy the file echo status to
  260.         mov    lineecho,al        ;  the line echo flag
  261.         xor    bl,bl            ;Look for 1st character
  262.         call    scan4char
  263.         jnc    comp_1
  264.         cmp    al,13            ;See if carrage return, if so
  265.         je    new_line        ;  continue, else assume end
  266.         jmp    short comp_end        ;  of file.
  267. comp_1:
  268.         call    redirect_check
  269.         cmp    byte ptr [si],'@'       ;See if non echo prefix
  270.         jne    comp_2
  271.         mov    lineecho,0        ;Don't echo this line
  272.         inc    si            ;Move past @
  273. comp_2:
  274.         call    parse            ;Parse 1st word in the line.
  275.         jc    comp_error
  276.         jmp    new_line
  277. comp_error:
  278.         jmp    disp_error
  279. comp_end:
  280. ;
  281. ;Inline code complete, append terminate code.
  282. ;
  283.         call    redirect_close
  284.         mov    databuff_end,di     ;Save ptr to end of data.
  285.         les    di,codebuff_ptr
  286.         assume    es:nothing
  287.         mov    si,offset end_code    ;Append terminate code
  288.         mov    cx,offset end_code_end-offset end_code
  289.         rep    movsb
  290.         mov    word ptr codebuff_ptr,di ;Save ptr to end of COM code.
  291. ;
  292. ;File processed. Assemble data and code into one routine.  Start by
  293. ;stringing the canned routines together using the links set by the
  294. ;INCLUDE routine.
  295. ;
  296.         les    di,outbuff_ptr         ;Get ptr to output buffer
  297.         mov    si,offset init_code_next ;  for COM file.
  298. file_1:     mov    cx,[si-2]        ;Get size of routine
  299.         push    [si]            ;Save pointer to next routine
  300.         add    si,4            ;Skip past number of links
  301.         rep    movsb            ;Copy routine to COM file.
  302.         pop    si
  303.         or    si,si            ;See if last routine
  304.         jne    file_1            ;No, loop back.
  305. ;
  306. ;Save starting offset of data to be used by the COM program.
  307. ;
  308.         mov    bp,offset data_start_ptr-offset init_code
  309.         mov    ax,100h         ;AX = end pointer
  310.         add    ax,di            ;Add length of canned routines.
  311.         mov    es:[bp],ax        ;Save data start pointer
  312.         mov    bp,di            ;Use BP as starting data offset
  313.  
  314.         mov    si,databuff_start    ;Compute length of COM data
  315.         mov    cx,databuff_end     ;  plus the canned routines.
  316.         sub    cx,si
  317.         add    ax,cx            ;Add data length to end ptr
  318. ;
  319. ;Now that we have the length of the canned routines and the data, we can
  320. ;compute the starting offset of the inline code.  Use this number to adjust
  321. ;the jump table entries in the label list.  While fixing offsets check to
  322. ;see that all labels have code offsets, if not, print no label error msg.
  323. ;When complete, append data to file.
  324. ;
  325.         mov    bx,offset firstlabel    ;Get pointer to the first label
  326.         mov    dx,[bx]         ;Get offset to 1st label entry
  327.         add    dx,bx            ;Add in BX to get absolute off
  328. file_11:
  329.         cmp    word ptr [bx],-1    ;See if at end of label list.
  330.         je    file_13
  331.         add    bx,[bx]         ;Get next in list
  332.         cmp    word ptr [bx+2],-1    ;See if label ptr to code
  333.         je    file_12         ;  initialized. No, error.
  334.         add    [bx+2],ax        ;Add starting offset of code
  335.         jmp    short file_11
  336. file_12:
  337.         mov    si,bx            ;Label not defined as a
  338.         add    si,5            ;  destination.  Print error
  339.         xor    cx,cx            ;  message inc lost label.
  340.         mov    cl,[bx+4]        ;Get size of label
  341.         push    cs
  342.         pop    es
  343.         mov    di,offset errmsg9labl
  344.         rep    movsb
  345.         mov    dx,offset errmsg9    ;Label not found msg
  346.         jmp    disp_error
  347. file_13:
  348.         rep    movsb            ;Append data to COM file.
  349.         sub    dx,databuff_start    ;Set pointer to 1st label list
  350.         mov    es:com_label_start,dx    ;Initialize pointer.
  351. ;
  352. ;Append the inline code to the program.
  353. ;
  354.         mov    ax,100h
  355.         add    ax,di
  356.         mov    es:code_start_ptr,ax    ;Save offset of main code.
  357.  
  358.         mov    cx,word ptr codebuff_ptr
  359.         mov    si,codebuff_start    ;Get pointer to code
  360.         mov    ds,word ptr codebuff_ptr[2]
  361.         assume    ds:nothing
  362.         sub    cx,si            ;Get size of code
  363.         add    ax,cx            ;Make sure canned routines
  364.         jnc    file_2            ;  and data < 64 K bytes.
  365. file_too_big:    mov    dx,offset errmsg5    ;COM file too big msg
  366.         jmp    disp_error
  367. file_2:
  368.         rep    movsb            ;Append inline code.
  369. ;
  370. ;Compute the size of the data buffers and the stack used by the COM program.
  371. ;Write these numbers to the COM file data area.
  372. ;
  373.         push    cs
  374.         pop    ds
  375.         assume    ds:code
  376.         add    ax,512            ;Add room for stack
  377.         jc    file_too_big
  378.         and    ax,0fffeh        ;Set stack on even word.
  379.         mov    es:com_stack_ptr,ax    ;Save run time stack pointer
  380.         add    ax,2            ;Make room for buff length word
  381.         mov    es:string1_buff,ax    ;Save ptr to parsing buffer.
  382.         add    ax,258            ;Add room for buffer 2
  383.         jc    file_too_big
  384.         mov    es:string2_buff,ax    ;Save ptr to parsing buffer 2
  385.         add    ax,258            ;Add room for buffer
  386.         jc    file_too_big
  387.         mov    es:string3_buff,ax    ;Save ptr to For loop buffer
  388.         add    ax,256            ;Add room for buffer
  389.         jc    file_too_big
  390.  
  391.         mov    outbuff_end,di        ;Save end pointer to file
  392.         add    ax,15
  393.         jc    file_3            ;Compute size of COM file
  394.         mov    cl,4            ;  in paragraphs.
  395.         shr    ax,cl
  396.         mov    es:com_prog_size,ax    ;Save file size
  397.         mov    byte ptr es:shift_count,0    ;Clear shift count
  398. file_3:
  399. ;
  400. ;Write file to disk.
  401. ;
  402.         mov    ah,3ch            ;Create file
  403.         xor    cx,cx            ;Normal attributes
  404.         mov    dx,offset outfile_name    ;Name of file
  405.         int    21h
  406.  
  407.         mov    bx,ax            ;Copy handle
  408.         mov    ah,40h            ;Write file
  409.         push    ds
  410.         lds    dx,outbuff_ptr        ;Get start of buffer
  411.         mov    cx,cs:[outbuff_end]    ;Get number of bytes to write
  412.         sub    cx,dx
  413.         int    21h            ;Write file to disk
  414.         pop    ds
  415.  
  416.         mov    ah,3eh            ;Close file
  417.         int    21h
  418. ;
  419. ;Compile complete. Clean up and end.
  420. ;
  421. good_exit:
  422.         xor    al,al            ;Return code = 0
  423. exit:
  424.         push    ax            ;Save return code
  425.         mov    ah,49h            ;Release memory block used
  426.         mov    es,word ptr cs:[codebuff_ptr+2] ;  for file buffer.
  427.         int    21h
  428.  
  429.         pop    ax            ;Get back return code
  430.         mov    ah,4Ch            ;Terminate
  431.         int    21h
  432. ;
  433. ;Display error message.
  434. ;
  435. disp_error:
  436.         push    cs
  437.         pop    ds
  438.         assume    ds:code
  439.         cmp    file_linecount,0
  440.         je    disp_error1        ;If processing a file, print
  441.         push    dx            ;  a message informing the
  442.         mov    dx,offset filemsg1    ;  user the line that
  443.         call    printmsg        ;  contained the error.
  444.         mov    ax,file_linecount
  445.         call    hex2asc
  446.         mov    dx,offset endmsg
  447.         call    printmsg
  448.         pop    dx
  449. disp_error1:
  450.         call    printmsgcr        ;print string
  451.         mov    al,01            ;Terminate with RC = 1
  452.         jmp    short exit
  453.  
  454. ;-----------------------------------------------------------------------------
  455. ; PARSE  Parse a statment.
  456. ; Entry:  SI - Pointer to string to parse.
  457. ;      DI - Pointer to end of COM file data.
  458. ; Exit:   CF - Set if error.
  459. ;      SI - Updated.
  460. ;-----------------------------------------------------------------------------
  461. parse        proc    near
  462.         mov    bx,14
  463.         mov    al,[si]         ;See if label
  464.         cmp    al,":"
  465.         je    parse_2
  466.  
  467.         mov    bx,12
  468.         cmp    al,"%"                  ;See if cmd line param or env
  469.         je    parse_2         ;  var. If so, internal cmd
  470.  
  471.         mov    ax,[si+1]        ;See if change to default disk
  472.         cmp    al,":"
  473.         jne    parse_1
  474.         mov    bx, 12            ;Set internal command.
  475.         cmp    ah," "
  476.         jbe    parse_2
  477. parse_1:
  478.         call    capsword        ;Capitalize batch command
  479.         push    di            ;Search list of BAT cmds.
  480.         mov    di,offset command_table
  481.         call    findstr
  482.         pop    di
  483. parse_2:
  484.         push    bx            ;Scan past command except for
  485.         cmp    bx,8            ;  external progs, inter cmds,
  486.         ja    parse_3         ;  and labels.
  487.         mov    bl,1
  488.         call    scan4char
  489.         jnc    parse_3         ;If end of line, back up to
  490.         dec    si            ;  show CR.
  491. parse_3:
  492.         pop    bx
  493.         shl    bx,1            ;Compute offset of routine to
  494.         add    bx,offset batcmd_jmptbl ;  call.
  495.         call    [bx]            ;Call routine to compile line.
  496.         ret
  497. parse        endp
  498.  
  499. ;-----------------------------------------------------------------------------
  500. ; FINDSTR  determines if a string is in a list.
  501. ; Entry:  SI - Pointer to ASCII string to find.
  502. ;      DI - Pointer to list of ASCIIZ strings.
  503. ;      CX - Size of string
  504. ; Exit:   CF - Clear if string found
  505. ;      BX - If CF clear, index into list
  506. ;-----------------------------------------------------------------------------
  507. findstr     proc    near
  508.         push    cx
  509.         push    es
  510.         push    cs            ;Point ES:DI to table of
  511.         pop    es            ;  batch commands.
  512.         mov    dx,cx            ;Save length of string
  513.         xor    bx,bx            ;Zero index counter
  514. finds_1:
  515.         push    si
  516.         mov    cx,dx            ;Restore command size
  517.         repe    cmpsb            ;Compare command
  518.         pop    si
  519.         je    string_found
  520.         inc    bx
  521.         xor    al,al
  522.         cmp    [di-1],al
  523.         jne    finds_2
  524.         dec    di
  525. finds_2:
  526.         mov    cx,10            ;Scan to next zero
  527.         repne    scasb
  528.         cmp    byte ptr [di],0     ;See if second zero. If so
  529.         jne    finds_1         ;  end of list.
  530.         mov    bx,13
  531.         stc                ;Indicate string not found
  532. findstr_exit:
  533.         pop    es
  534.         pop    cx
  535.         ret
  536. string_found:
  537.         cmp    bx,12            ;If past the BAT commands,
  538.         jb    findstr_3        ;  then it is an internal cmd.
  539.         mov    bx,12
  540. findstr_3:
  541.         clc                ;Set string found flag
  542.         jmp    short findstr_exit
  543. findstr     endp
  544.  
  545. ;-----------------------------------------------------------------------------
  546. ; CAPSWORD capitalizes word pointed to by SI
  547. ; Entry:  SI - Pointer to ASCII word to capitalize
  548. ; Exit:   CX - Size of word
  549. ;-----------------------------------------------------------------------------
  550. capsword    proc near
  551.         assume    ds:nothing,es:nothing
  552.         push    di
  553.         push    si
  554.         push    es
  555.         push    ds            ;Set ES:DI = DS:SI
  556.         pop    es
  557.         mov    di,si
  558.         xor    cx,cx            ;Clear byte counter.
  559. caps_1:
  560.         lodsb                ;Get character
  561.         cmp    al,"0"                  ;Allow numbers
  562.         jb    caps_exit
  563.         cmp    al,"9"
  564.         jbe    caps_2
  565.         cmp    al,"A"                  ;If between A and Z, continue
  566.         jb    caps_exit
  567.         cmp    al,"Z"
  568.         jbe    caps_2
  569.         cmp    al,"a"                  ;If batween a and z,
  570.         jb    caps_exit        ;  capitalize it, else, exit
  571.         cmp    al,"z"
  572.         ja    caps_exit
  573.         and    al,0DFh
  574. caps_2:
  575.         stosb                ;Save character
  576.         inc    cx            ;Inc byte counter
  577.         jmp    short caps_1
  578. caps_exit:
  579.         pop    es
  580.         pop    si
  581.         pop    di
  582.         ret
  583. capsword    endp
  584.  
  585. ;-----------------------------------------------------------------------------
  586. ; REDIRECT CLOSE post process redirection commands
  587. ; Entry:  DI - Pointer to end of COM file data.
  588. ; Exit:   CF - Set if error.
  589. ;      Batch file line updated to remove any redirection symbols
  590. ;-----------------------------------------------------------------------------
  591. redirect_close    proc    near
  592.         assume    cs:code,ds:code
  593.         cmp    redirect_in,0        ;See if redirecton active
  594.         je    redirclose_1
  595.         mov    redirect_in,0
  596.         mov    bx,offset redirci_next    ;Append close redirect file
  597.         call    include_code        ;  routine to code.
  598.         xor    cx,cx
  599.         call    inline_code
  600. redirclose_1:
  601.         cmp    redirect_out,0        ;See if redirecton active
  602.         je    redirclose_2
  603.         mov    redirect_out,0
  604.         mov    bx,offset redirco_next    ;Append close redirect file
  605.         call    include_code        ;  routine to code.
  606.         xor    cx,cx
  607.         call    inline_code
  608. redirclose_2:
  609.         cmp    pipein_flag,0        ;See if in pipe curr active
  610.         je    redirclose_3
  611.         mov    dx,pipein_file        ;Get offset of input pipe file
  612.         mov    cx,1            ;Indicate parameter type
  613.         mov    bx,offset redirdel_next ;Delete the piping file
  614.         call    include_code
  615.         call    inline_code
  616.         mov    pipein_flag,0        ;Clear flag
  617. redirclose_3:
  618.         cmp    pipeout_flag,0        ;See if out pipe curr active
  619.         je    redirclose_exit
  620.         mov    dx,pipeout_file     ;Get offset of input pipe file
  621.         xor    bx,bx            ;Add output redirection code
  622.         xor    ax,ax            ;  to file.
  623.         call    redirect_openi
  624.         mov    pipein_flag,1        ;Set pipe input flag
  625.         mov    pipeout_flag,0        ;Clear pipe output flag
  626.         mov    pipein_file,dx        ;Copy pointer to filename
  627. redirclose_exit:
  628.         ret
  629. redirect_close    endp
  630.  
  631. ;-----------------------------------------------------------------------------
  632. ; REDIRECT CHECK process redirection commands
  633. ; Entry:  SI - Pointer to current BAT file line
  634. ;      DI - Pointer to end of COM file data.
  635. ; Exit:   CF - Set if error.
  636. ;      Batch file line updated to remove any redirection symbols
  637. ;-----------------------------------------------------------------------------
  638. redirect_check    proc    near
  639.         assume    cs:code,ds:code
  640.         push    si
  641.         call    redirect_close
  642.         mov    quote_flag,0
  643. redirect_1:
  644.         mov    bp,si            ;Save current position
  645.         lodsb
  646.         cmp    al,'"'                  ;See if quote
  647.         jne    redirect_2
  648.         not    quote_flag
  649. redirect_2:
  650.         cmp    quote_flag,0        ;Ignore characters in quotes
  651.         jne    redirect_3
  652. ;
  653. ; Check for piping
  654. ;
  655.         cmp    al,'|'                  ;Check for piping symbol
  656.         jne    redirect_5
  657.         mov    byte ptr [si-1],13    ;Replace | with CR
  658.  
  659.         mov    bx,offset pipe1_file    ;Get offset of pipe file to
  660.         cmp    pipe_toggle,0        ;  use.  Alternate files so
  661.         jne    redirect_3        ;  that input and output files
  662.         mov    bx,offset pipe2_file    ;  don't get mixed up.
  663. redirect_3:
  664.         not    pipe_toggle
  665.         xor    dx,dx            ;If file not already used,
  666.         or    dx,[bx]         ;  load the filename into
  667.         jne    redirect_4        ;  the COM data buffer.
  668.         mov    dx,di
  669.         sub    dx,databuff_start    ;Compute offset of filename
  670.         mov    [bx],dx         ;Save pointer to filename
  671.         lea    si,[bx+2]        ;Get address of filename
  672.         mov    ah,1
  673.         call    copy_string        ;Copy name to COM data buffer
  674.         xor    al,al            ;Terminate filename with zero
  675.         stosb
  676. redirect_4:
  677.         mov    pipeout_file,dx
  678.         mov    pipeout_flag,1
  679.         xor    bx,bx            ;Add output redirection code
  680.         xor    ax,ax            ;  to file.
  681.         call    redirect_openo
  682.         jmp    short redirect_exit    ;Terminate line scan.
  683. ;
  684. ; Check for output redirection
  685. ;
  686. redirect_5:
  687.         cmp    al,'>'                  ;Check for redirect out
  688.         jne    redirect_7
  689.         xor    bx,bx
  690.         cmp    byte ptr [si],'>'       ;Check for append redirect
  691.         jne    redirect_6
  692.         lodsb                ;Remove 2nd >
  693.         inc    bx
  694. redirect_6:
  695.         push    bx            ;Save append flag
  696.         xor    bl,bl
  697.         call    scan4char        ;Get filename
  698.         mov    dx,di
  699.         mov    ah,1            ;Copy only one word
  700.         call    copy_string
  701.         xor    al,al            ;Terminate name with zero
  702.         stosb
  703.         sub    dx,databuff_start    ;Compute offset of filename
  704.         pop    ax
  705.         call    redirect_openo
  706.         call    erase_redirect        ;Erase redirect from line.
  707.         jmp    short redirect_1
  708. redirect_7:
  709.         cmp    al,'<'                  ;Check for redirect in
  710.         jne    redirect_10
  711.         xor    bl,bl
  712.         call    scan4char        ;Get filename
  713.         mov    dx,di
  714.         mov    ah,1            ;Copy only one word
  715.         call    copy_string
  716.         xor    al,al            ;Terminate name with zero
  717.         stosb
  718.         sub    dx,databuff_start    ;Compute offset of filename
  719.         call    redirect_openi
  720.         call    erase_redirect        ;Erase redirect from line.
  721.         jmp    redirect_1
  722. redirect_10:
  723.         cmp    al,13
  724.         je    redirect_exit
  725.         jmp    redirect_1
  726. redirect_exit:
  727.         clc
  728.         pop    si
  729.         ret
  730. redirect_check    endp
  731.  
  732. ;-----------------------------------------------------------------------------
  733. ; REDIRECT OPENO process redirection commands
  734. ; Entry:  AX - 1 = append file.
  735. ; Entry:  DX - Offset from data buffer start of file name
  736. ;      BX - 0 no translation of filename.
  737. ;-----------------------------------------------------------------------------
  738. redirect_openo    proc    near
  739.         assume    cs:code,ds:code
  740.         push    si
  741.         push    ax            ;Save append flag
  742.         mov    cx,0031h        ;Indicate parameter type
  743.         or    bx,bx            ;See if env var or cmd line
  744.         je    redirect_oo1        ;  parms.
  745.  
  746.         mov    bx,offset procstr_next    ;Get offset of translate
  747.         call    include_code        ;  routine. Include if needed.
  748.  
  749.         mov    bx,offset str1_buff_ptr - offset data_start
  750.         mov    cx,0032h        ;Indicate parameter type
  751.         call    inline_code        ;Insert translate code.
  752. redirect_oo1:
  753.         mov    bx,offset rediroo_next    ;Append open redirect file
  754.         call    include_code
  755.         pop    bx            ;Restore append flag
  756.         call    inline_code
  757.         mov    redirect_out,1        ;Set redirect active flag
  758.         pop    si
  759.         ret
  760. redirect_openo    endp
  761.  
  762. ;-----------------------------------------------------------------------------
  763. ; REDIRECT OPENI loads code to open a file for input redirection
  764. ; Entry:  DX - Offset from data buffer start of file name
  765. ;      BX - 0 no translation of filename.
  766. ;-----------------------------------------------------------------------------
  767. redirect_openi    proc    near
  768.         assume    cs:code,ds:code
  769.         push    si
  770.         mov    cx,1            ;Indicate parameter type
  771.         or    bx,bx            ;See if env var or cmd line
  772.         je    redirect_oi1        ;  parms.
  773.  
  774.         mov    bx,offset procstr_next    ;Get offset of translate
  775.         call    include_code        ;  routine. Include if needed.
  776.  
  777.         mov    bx,offset str1_buff_ptr - offset data_start
  778.         mov    cx,2            ;Indicate parameter type
  779.         call    inline_code        ;Insert translate code.
  780. redirect_oi1:
  781.         mov    bx,offset rediroi_next    ;Append open redirect file
  782.         call    include_code
  783.         call    inline_code
  784.         mov    redirect_in,1        ;Set redirect active flag
  785.         pop    si
  786.         ret
  787. redirect_openi    endp
  788.  
  789. ;-----------------------------------------------------------------------------
  790. ; ERASE REDIRECT
  791. ; Entry:  BP - Pointer to redirect character
  792. ;      SI - Pointer to end of redirect phrase.
  793. ;-----------------------------------------------------------------------------
  794. erase_redirect    proc    near
  795.         assume    cs:code,ds:code
  796.         push    di            ;Save ptr to data buffer
  797.         mov    al,' '
  798.         mov    di,bp            ;Get start of redirect string
  799.         dec    si
  800. erase_1:
  801.         stosb
  802.         cmp    di,si
  803.         jb    erase_1
  804.         pop    di
  805.         ret
  806. erase_redirect    endp
  807.  
  808. ;-----------------------------------------------------------------------------
  809. ; IF CMD compiles an IF command.
  810. ; Entry:  SI - Pointer to character after the IF command
  811. ;      DI - Pointer to end of compiled data.
  812. ; Exit:   AL - Error code if CF set
  813. ;      CF - Set if error
  814. ;      SI,DI updated.
  815. ;-----------------------------------------------------------------------------
  816. if_cmd        proc    near
  817.         assume    cs:code,ds:code
  818.         xor    bl,bl            ;Find 1st char of next word
  819.         call    scan4char
  820.         mov    bx,si            ;Save pointer to test
  821.         mov    dx,di
  822.         mov    bp,0            ;Clear 'NOT' flag
  823. ;
  824. ;See if NOT prefix is used in test
  825. ;
  826.         lodsw                ;Get 1st two chars of test
  827.         or    ax,2020h
  828.         cmp    ax,'on'                 ;See if 'no'
  829.         jne    if_cmd_000
  830.         lodsw                ;Get 2nd and 3rd characters
  831.         or    al,20h            ;Convert 3rd char to lower
  832.         cmp    al,'t'                  ;  case.   See if last char is
  833.         jne    if_cmd_000        ;  't' followed by s space
  834.         cmp    ah,' '
  835.         ja    if_cmd_000
  836.         inc    bp
  837.         xor    bl,bl            ;Find next word
  838.         call    scan4char
  839.         mov    bx,si
  840. ;
  841. ;Test for string compare by looking for == signs.
  842. ;
  843. if_cmd_000:
  844.         mov    si,bx            ;Restore pointer to condition
  845. if_cmd_00:
  846.         lodsb                ;Scan past first string to
  847.         cmp    al,'='                  ;  determine if this is a
  848.         je    if_cmd_02        ;  string comparison.
  849.         cmp    al,9
  850.         je    if_cmd_01
  851.         cmp    al,' '
  852.         jb    if_syntax_jmp
  853.         jne    if_cmd_00
  854. if_cmd_01:
  855.         lodsb                ;Scan past any spaces before
  856.         cmp    al,9            ;  the equals signs.
  857.         je    if_cmd_01
  858.         cmp    al,' '
  859.         je    if_cmd_01
  860.         jnb    if_cmd_02
  861. if_syntax_jmp:
  862.         jmp    if_syntax
  863. if_cmd_02:
  864.         cmp    word ptr [si-1],"=="    ;See if string compare
  865.         jne    if_cmd_0        ;No, check other tests
  866.         inc    si            ;Move SI past equals signs
  867.         push    si            ;Save pointer to 2nd string
  868.         mov    si,bx            ;Restore ptr to 1st string
  869.         push    di            ;Save ptr to size byte
  870.         inc    di
  871.         mov    dx,di            ;Save ptr to start of string
  872.         sub    dx,databuff_start
  873.         mov    ah,1            ;Copy only one word
  874.         call    copy_string        ;Load string into data space
  875.         or    bx,bx            ;See if translation is needed
  876.         mov    bx,dx
  877.         pop    bx
  878.         mov    [bx],cl         ;Save length of string
  879.         mov    cl,1            ;Assume LEA parameter call
  880.         je    if_cmd_03
  881.  
  882.         mov    bx,offset procstr_next    ;Append translate string
  883.         call    include_code        ;  routine to code.
  884.         mov    bx,offset str2_buff_ptr - offset data_start
  885.         mov    cx,0021h        ;Indicate parameter type
  886.         call    inline_code        ;Insert translate code.
  887.         mov    dx,bx            ;Copy ptr to buffer.
  888.         mov    cx,2            ;Use MOV parameter type
  889. if_cmd_03:
  890.         pop    si            ;Restore ptr to 2nd string
  891.         push    dx            ;Save pointer to 1st string
  892.         push    cx            ;Save parameter type
  893. if_cmd_04:
  894.         push    di            ;Save ptr to size byte
  895.         inc    di
  896.         mov    dx,di            ;Save ptr to start of string
  897.         sub    dx,databuff_start
  898.         mov    ah,1
  899.         call    copy_string        ;Load string into data space
  900.         or    bx,bx            ;See if translation is needed
  901.         pop    bx
  902.         mov    [bx],cl         ;Save length of string
  903.         mov    cx,10h            ;Set parameter type
  904.         je    if_cmd_06
  905.  
  906.         mov    bx,offset procstr_next    ;Append translate string
  907.         call    include_code        ;  routine to code.
  908.         mov    bx,offset str1_buff_ptr - offset data_start
  909.         mov    cx,0021h        ;Indicate parameter type
  910.         call    inline_code        ;Insert translate code.
  911.         mov    dx,bx            ;Copy ptr to buffer.
  912.         mov    cx,20h            ;Use proper parameter type
  913. if_cmd_06:
  914.         mov    bx,offset ifequal_next    ;Append comparison code
  915.         call    include_code
  916.         pop    bx            ;Restore param 1 type
  917.         and    bl,0fh
  918.         or    cl,bl            ;Combine parameter types
  919.         mov    bx,dx            ;Move parameter 2
  920.         pop    dx            ;Restore parameter 1
  921.         call    inline_code        ;Add call to string compare
  922.         jmp    if_cmd_10
  923. if_syntax:
  924.         mov    dx,offset errmsg6    ;Syntax error.
  925.         stc
  926.         jmp    if_exit
  927. ;
  928. ;See if ERRORLEVEL test.
  929. ;
  930. if_cmd_0:
  931.         mov    si,bx            ;Restore pointer to test
  932.         mov    di,offset ifstr1    ;See if ERRORLEVEL test
  933.         call    capsword
  934.         cmp    cx,10
  935.         jne    if_cmd_2
  936.         repe    cmpsb            ;Compare strings
  937.         jne    if_cmd_2
  938.         mov    bx,offset iferrlev_next ;Save offset of errlev code
  939.         push    bx            ;  on stack.  Use exist code
  940.         jmp    short if_cmd_21     ;  to append error code.
  941. ;
  942. ;See if EXIST test.
  943. ;
  944. if_cmd_2:
  945.         mov    si,bx            ;Restore pointer to test
  946.         mov    di,offset ifstr2    ;See if EXIST test
  947.         cmp    cx,5            ;Check length of string
  948.         jne    if_syntax
  949.         repe    cmpsb            ;Compare strings
  950.         jne    if_syntax
  951.         mov    bx,offset ifexist_next    ;Save test existance code off
  952.         push    bx
  953. if_cmd_21:
  954.         xor    bl,bl
  955.         call    scan4char        ;Scan to next word.
  956.         mov    di,dx            ;Restore data pointer
  957.         sub    dx,databuff_start
  958.         mov    ah,1
  959.         call    copy_string
  960.         xor    al,al            ;Terminate string with zero.
  961.         stosb
  962.         mov    cl,21h            ;Set parameter type
  963.         or    bx,bx            ;See if translation is needed
  964.         je    if_cmd_3
  965.  
  966.         mov    bx,offset procstr_next    ;Append translate string
  967.         call    include_code        ;  routine to code.
  968.         mov    bx,offset str1_buff_ptr - offset data_start
  969.         mov    cx,0021h        ;Indicate parameter type
  970.         call    inline_code        ;Insert translate code.
  971.         mov    dx,bx            ;Copy ptr to buffer.
  972.         mov    cl,22h            ;Use proper parameter type
  973. if_cmd_3:
  974.         pop    bx            ;Restore test code offset
  975.         call    include_code
  976.         mov    bx,offset str2_buff_ptr - offset data_start
  977.         call    inline_code        ;Insert exist test call
  978. if_cmd_10:
  979.         mov    cx,200h         ;Include Jump if carry opcode
  980.         or    bp,bp
  981.         je    if_cmd_12
  982.         mov    cx,300h         ;Change to Jump if not carry
  983. if_cmd_12:
  984.         call    inline_code
  985.         push    ax            ;Save address of jmp to modify
  986.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  987. ;
  988. ;Compile the remainder of the line as if it were a normal statment.
  989. ;
  990.         xor    bl,bl            ;Scan for next word
  991.         call    scan4char
  992.         call    parse            ;Compile remainder of line.
  993.  
  994.         pop    cx            ;Compute the difference for the
  995.         pop    bx            ;  jmp opcode.
  996.         jc    if_exit         ;If error during parse, exit.
  997.         push    es
  998.         mov    ax,word ptr codebuff_ptr
  999.         mov    es,word ptr codebuff_ptr[2]
  1000.         sub    ax,cx
  1001.         mov    es:[bx],ax        ;Save jmp offset
  1002.         pop    es
  1003.         clc
  1004. if_exit:
  1005.         ret
  1006. if_cmd        endp
  1007.  
  1008. ;-----------------------------------------------------------------------------
  1009. ; FOR CMD compiles an FOR command.
  1010. ; Entry:  SI - Pointer to character after the FOR command
  1011. ;      DI - Pointer to end of compiled data.
  1012. ; Exit:   AL - Error code if CF set
  1013. ;      CF - Set if error
  1014. ;      SI,DI updated.
  1015. ;-----------------------------------------------------------------------------
  1016. for_cmd     proc    near
  1017.         assume    cs:code,ds:code
  1018.         cmp    for_active_flag,0
  1019.         je    for_cmd_0
  1020.         mov    dx,offset errmsg11    ;No nested FOR loops
  1021.         stc
  1022.         jmp    for_exit
  1023. for_cmd_0:
  1024.         mov    goto_active,0        ;Clear goto detect flag
  1025.         inc    for_active_flag
  1026.         xor    bl,bl            ;Find 1st char of next word
  1027.         call    scan4char
  1028.         jc    jmp_for_syntax
  1029.         mov    bp,si            ;Save pointer to loop variable
  1030.         mov    dx,di
  1031.         sub    dx,word ptr databuff_start
  1032. ;
  1033. ;Copy the set data to the com file data area.  As always, if environment
  1034. ;variables or command line parameters are in the data, insert a call to
  1035. ;the translate routine before calling the for loop routine.
  1036. ;
  1037. for_cmd_1:
  1038.         lodsb                ;Scan until '(' is found
  1039.         cmp    al,13            ;  indicating the start of the
  1040.         jne    for_cmd_2        ;  data set.
  1041. jmp_for_syntax:
  1042.         jmp    for_syntax
  1043. for_cmd_2:
  1044.         cmp    al,'('
  1045.         jne    for_cmd_1
  1046.         mov    ah,2            ;Copy until ')' found.
  1047.         call    copy_string
  1048.         xor    al,al            ;Terminate string with zero.
  1049.         stosb
  1050.  
  1051.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1052.         mov    cl,11h            ;Set parameter type
  1053. ;        or    bx,bx            ;See if translation is needed
  1054. ;        je    for_cmd_3
  1055.  
  1056.         mov    bx,offset procstr_next    ;Append translate string
  1057.         call    include_code        ;  routine to code.
  1058.         mov    bx,offset str3_buff_ptr - offset data_start
  1059.         mov    cx,0021h        ;Indicate parameter type
  1060.         call    inline_code        ;Insert translate code.
  1061.         mov    dx,bx            ;Copy ptr to buffer.
  1062.         mov    cl,12h            ;Use proper parameter type
  1063. for_cmd_3:
  1064.         mov    bx,offset forloop_next
  1065.         call    include_code
  1066.         mov    bx,di            ;Initialize for loop data
  1067.         sub    bx,databuff_start    ;  structure.
  1068.         mov    word ptr [di],0
  1069.         inc    di
  1070.         inc    di
  1071.         call    inline_code        ;Insert call to loop code.
  1072.         mov    cx,200h         ;Include Jump if carry opcode
  1073.         call    inline_code
  1074.         push    ax            ;Save address of jmp to modify
  1075.         push    word ptr codebuff_ptr    ;Save current code buff ptr
  1076.  
  1077. ;
  1078. ;Scan the remainder of the line. Replace all instances of the loop variable
  1079. ;with a special code that the run time translate routine understands.
  1080. ;
  1081.         xor    bl,bl            ;Find DO
  1082.         call    scan4char
  1083.         jc    for_syntax_1
  1084.         mov    bl,1            ;Find end of 'DO'
  1085.         call    scan4char
  1086.         jc    for_syntax_1
  1087.         xor    bl,bl            ;Find start of loop command.
  1088.         call    scan4char
  1089.         jc    for_syntax_1
  1090.         push    si            ;Save pointer to command.
  1091.         push    di            ;Save data buffer pointer.
  1092.         mov    di,si
  1093.         mov    bl,2            ;Find the end of the line.
  1094.         call    scan4char
  1095.         mov    dx,si            ;Save pointer to end of line
  1096. for_cmd_4:
  1097.         mov    si,bp            ;Get ptr to loop variable.
  1098.         mov    cx,3            ;Scan the remainder of the
  1099.         repe    cmpsb            ;  line for the loop variable.
  1100.         jne    for_cmd_5        ;  When found, replace with
  1101.         dec    di            ;  % followed by 7fh. This
  1102.         dec    di            ;  flag tells the runtime
  1103.         mov    ax,207fh        ;  xlate routine to sub in
  1104.         stosw                ;  the loop string.
  1105. for_cmd_5:
  1106.         cmp    di,dx            ;See if at the end of the line.
  1107.         jb    for_cmd_4
  1108.         pop    di            ;Restore data buffer ptr
  1109.         pop    si            ;Restore ptr to command.
  1110. ;
  1111. ;Compile the remainder of the line as if it were a normal statment.
  1112. ;
  1113.         call    parse            ;Compile remainder of line.
  1114.  
  1115.         pop    dx            ;Get code ptr after loop code
  1116.         pop    bx            ;Get addr of JC
  1117.         pop    ax            ;Get code ptr to loop code
  1118.         jc    for_exit1
  1119.  
  1120.         sub    ax,word ptr codebuff_ptr ;Compute displacment from END
  1121.         sub    ax,3             ;  of JMP opcode.
  1122.         mov    cx,400h         ;Insert JMP opcode after code
  1123.         call    inline_code        ;  for statments inside FOR
  1124.         mov    ax,word ptr codebuff_ptr;  loop.
  1125.         sub    ax,dx
  1126.         push    es
  1127.         mov    es,word ptr codebuff_ptr[2]
  1128.         mov    es:[bx],ax
  1129.         pop    es
  1130. ;
  1131. ; If goto parsed during FOR, place jump for goto after FOR loop
  1132. ;
  1133.         cmp    goto_active,0
  1134.         je    for_exit
  1135.         mov    dx,goto_data_ptr
  1136.         mov    bx,offset gotodly_next    ;Append goto delay
  1137.         call    include_code        ;  routine to code.
  1138.         mov    cx,1
  1139.         call    inline_code        ;Add code to COM file.
  1140. for_exit:
  1141.         clc
  1142. for_exit1:
  1143.         mov    for_active_flag,0    ;Clear flag
  1144.         ret
  1145. for_syntax_1:
  1146.         add    sp,6            ;Clean off stack
  1147. for_syntax:
  1148.         mov    dx,offset errmsg6    ;Syntax error
  1149.         stc
  1150.         jmp    short for_exit1
  1151. for_cmd     endp
  1152.  
  1153. ;-----------------------------------------------------------------------------
  1154. ; GOTO CMD compiles a goto command.
  1155. ; Entry:  SI - Pointer to first character after the command.
  1156. ;      DI - Pointer to end of compiled data.
  1157. ; Exit:   AL - Error code if CF set
  1158. ;      CF - Set if error
  1159. ;      SI,DI updated.
  1160. ;-----------------------------------------------------------------------------
  1161. goto_cmd    proc    near
  1162.         assume    cs:code,ds:code
  1163.         mov    goto_active,1        ;Needed for FOR loop
  1164.         mov    bp,di            ;Save ptr to start of string.
  1165.         xor    bl,bl            ;Find the first nonspace char.
  1166.         call    scan4char
  1167.         push    si
  1168.         xor    ax,ax
  1169.         stosw                ;Save word in case FOR loop
  1170.         xor    ah,ah            ;  delay goto.
  1171.         call    copy_string        ;Copy label to COM data.
  1172.         xor    al,al            ;Terminate label with zero
  1173.         stosb
  1174.         pop    si
  1175.         mov    dx,offset errmsg8    ;Check to see if label found.
  1176.         or    cx,cx            ;If not, error.
  1177.         je    goto_cmd_error
  1178.         cmp    for_active_flag,0    ;If in for loop, force eval
  1179.         jne    goto_c1         ;  Jmp must occur after FOR
  1180.  
  1181.         or    bx,bx            ;See if env var or cmd line
  1182.         je    goto_c2         ;  parms.  If not hard code jmp
  1183. goto_c1:
  1184.         mov    bx,offset procstr_next    ;Get offset of translate
  1185.         call    include_code        ;  routine. Include if needed.
  1186.  
  1187.         mov    dx,bp            ;Get pointer to label.
  1188.         sub    dx,databuff_start    ;Compute offset.
  1189.         mov    goto_data_ptr,dx    ;Save offset in case FOR loop
  1190.         add    dx,2            ;Move past word ptr
  1191.         mov    bx,offset str1_buff_ptr - offset data_start
  1192.         mov    cx,0021h        ;Indicate parameter type
  1193.         call    inline_code        ;Insert translate code.
  1194.         mov    dx,bx
  1195.         mov    cx,32h            ;Use proper parameter type
  1196.         mov    bx,offset goto_next    ;Append goto string
  1197.         call    include_code        ;  routine to code.
  1198.         xor    bx,bx
  1199.         cmp    for_active_flag,0    ;If in FOR loop delay goto.
  1200.         je    goto_c11        ;  Pass ptr to word to save
  1201.         mov    bx,goto_data_ptr    ;  destination address.
  1202. goto_c11:
  1203.         call    inline_code        ;Add code to COM file.
  1204.         jmp    goto_cmd_exit
  1205. ;
  1206. ;Since label doesn't use env vars or cmd line params, hard code JMP.
  1207. ;
  1208. goto_c2:
  1209.         mov    di,bp            ;Reset data ptr to ignore label
  1210.         call    getlabel        ;See if label in list.
  1211.         mov    ax,bx            ;Copy pointer to label pointer
  1212.         add    ax,2            ;  to code.
  1213.         sub    ax,databuff_start    ;Compute offset of pointer
  1214.         mov    cx,100h         ;Insert JMP opcode.
  1215.         call    inline_code
  1216. goto_cmd_exit:
  1217.         mov    bl,2
  1218.         call    scan4char        ;Scan to the end of the line.
  1219.         clc
  1220. goto_cmd_exit1: ret
  1221. goto_cmd_error:
  1222.         stc
  1223.         jmp    short goto_cmd_exit1
  1224. goto_cmd       endp
  1225.  
  1226. ;-----------------------------------------------------------------------------
  1227. ; LABEL CMD processes a label found in the bat file.
  1228. ; Entry:  SI - Pointer to first character of the label
  1229. ;      DI - Pointer to end of compiled data.
  1230. ; Exit:   AL - Error code if CF set
  1231. ;      CF - Set if error
  1232. ;      SI,DI updated.
  1233. ;-----------------------------------------------------------------------------
  1234. label_cmd    proc    near
  1235.         assume    cs:code,ds:code
  1236.         inc    si            ;Move past ':'
  1237.         call    getlabel
  1238.         cmp    word ptr [bx+2],-1    ;See if list entry initialized
  1239.         jne    label_error        ;  if so error.
  1240.         mov    ax,word ptr codebuff_ptr
  1241.         mov    [bx+2],ax        ;Save code ptr in COM data
  1242.         mov    bl,2
  1243.         call    scan4char        ;Scan to the end of the line.
  1244.         clc
  1245. label_exit:
  1246.         ret
  1247. label_error:
  1248.         mov    dx,offset errmsg8    ;Two identical labels
  1249.         stc
  1250.         jmp    short label_exit
  1251. label_cmd    endp
  1252.  
  1253. ;-----------------------------------------------------------------------------
  1254. ; GETLABEL searches the label list in the data area.  If a matching label entry
  1255. ;   is found it is returned, if not a label entry is created.
  1256. ; Entry:  SI - Pointer to first character of the label
  1257. ;      DI - Pointer to end of compiled data.
  1258. ; Exit:   BX - Points to label entry.
  1259. ;      SI,DI updated.
  1260. ;-----------------------------------------------------------------------------
  1261. getlabel    proc    near
  1262.         assume    cs:code,ds:code
  1263.         call    capsword        ;Convert to caps & get length.
  1264.         cmp    cx,8            ;Max length of a label 8
  1265.         jbe    getlabel_1        ;  characters to be consistant
  1266.         mov    cx,8            ;  with DOS.
  1267. getlabel_1:
  1268.         mov    bp,di            ;Save data ptr
  1269.         mov    di,offset firstlabel    ;Get ptr to the 1st label
  1270.         mov    bx,di
  1271.         cmp    word ptr [di],-1    ;See if any labels defined.
  1272.         je    getlabel_2        ;No, skip label list search.
  1273.  
  1274.         push    cx            ;Save label size
  1275.         add    bx,[bx]         ;Point to first label
  1276.         call    lblsrch_code        ;Search label list.
  1277.         pop    cx
  1278.         mov    di,bp            ;Create label entry.
  1279.         jnc    getlabel_exit
  1280. getlabel_2:
  1281.         mov    di,bp            ;Create label entry.
  1282.         mov    ax,-1
  1283.         stosw                ;Clear end of list tag
  1284.         stosw                ;Indicate unitialized label
  1285.         mov    al,cl
  1286.         stosb                ;Save length of label
  1287.         rep    movsb            ;Copy label into data buffer
  1288.         mov    ax,bp
  1289.         sub    ax,bx            ;Compute offset to new label
  1290.         mov    [bx],ax         ;Load offset in prev. label
  1291.         mov    bx,bp            ;Get start of label entry
  1292. getlabel_exit:
  1293.         clc
  1294.         ret
  1295. getlabel    endp
  1296.  
  1297. ;-----------------------------------------------------------------------------
  1298. ; EXTERNAL CMD compiles a routine to exexute a program.
  1299. ; Entry:  SI - Pointer to character after the command
  1300. ;      DI - Pointer to end of compiled data.
  1301. ; Exit:   AL - Error code if CF set
  1302. ;      CF - Set if error
  1303. ;      SI,DI updated.
  1304. ;-----------------------------------------------------------------------------
  1305. external_cmd    proc    near
  1306.         assume    cs:code,ds:code
  1307.         mov    dx,di            ;Save ptr to filename
  1308.         sub    dx,databuff_start    ;Compute offset.
  1309.         mov    ah,1
  1310.         call    copy_string        ;Copy filename to COM data.
  1311.         xor    al,al            ;Terminate filename with zero
  1312.         stosb
  1313.         inc    di
  1314.         push    di            ;Save ptr to command line tail
  1315.         xor    ah,ah
  1316.         call    copy_string        ;Copy command line tail.
  1317.         mov    ax,000dh        ;Append CR and zero
  1318.         stosw
  1319.         pop    bp            ;Get ptr to cmd tail
  1320.         mov    [bp-1],cl        ;Save length of command line
  1321.         sub    bp,databuff_start    ;Compute offset.
  1322.         mov    cx,11h
  1323.         or    bx,bx            ;See if translation code needed
  1324.         je    externalcmd_1
  1325.  
  1326.         push    dx
  1327.         mov    dx,bp            ;Get pointer to cmd line tail
  1328.         mov    bx,offset procstr_next    ;Get offset of translate
  1329.         call    include_code        ;  routine.
  1330.         mov    bx,offset str1_buff_ptr - offset data_start
  1331.         mov    cx,0021h        ;Indicate parameter type
  1332.         call    inline_code        ;Insert translate code.
  1333.         mov    cx,21h            ;Use proper parameter type
  1334.         mov    bp,bx
  1335.         pop    dx
  1336. externalcmd_1:
  1337.         mov    bx,offset external_next ;Append prog launch code
  1338.         call    include_code
  1339.         mov    bx,bp            ;Get ptr to filename
  1340.         call    inline_code        ;Add code to COM file.
  1341.         clc
  1342.         ret
  1343. external_cmd    endp
  1344.  
  1345. ;-----------------------------------------------------------------------------
  1346. ; INTERNAL CMD compiles a command internal to command.com
  1347. ; Entry:  SI - Pointer to character after the command
  1348. ;      DI - Pointer to end of compiled data.
  1349. ; Exit:   AL - Error code if CF set
  1350. ;      CF - Set if error
  1351. ;      SI,DI updated.
  1352. ;-----------------------------------------------------------------------------
  1353. internal_cmd    proc    near
  1354.         assume    cs:code,ds:code
  1355.         inc    di            ;Make room for string size.
  1356.         push    di            ;Save ptr to internal command.
  1357.         push    si
  1358.         mov    si,offset internal_cmdsw
  1359.         movsw                ;Copy /C switch to tell
  1360.         movsb                ;  COMMAND.COM to execute and
  1361.         pop    si            ;  terminate.
  1362.         xor    ah,ah
  1363.         call    copy_string        ;Copy internal command
  1364.         mov    ax,000dh        ;Append CR and zero
  1365.         stosw
  1366.         pop    bp
  1367.         add    cl,3            ;Add length of /c switch
  1368.         mov    [bp-1],cl        ;Save length of command line
  1369.  
  1370.         mov    dx,bp            ;Get pointer to internal cmd
  1371.         sub    dx,databuff_start    ;Compute offset.
  1372.         mov    cx,1
  1373.         or    bx,bx            ;See if translation code needed
  1374.         je    internalcmd_1
  1375.  
  1376.         mov    bx,offset procstr_next    ;Get offset of translate
  1377.         call    include_code        ;  routine.
  1378.         mov    bx,offset str1_buff_ptr - offset data_start
  1379.         mov    cx,0021h        ;Indicate parameter type
  1380.         call    inline_code        ;Insert translate code.
  1381.         mov    cx,2            ;Use proper parameter type
  1382.         mov    dx,bx            ;Get input from str1 buffer
  1383. internalcmd_1:
  1384.         mov    bx,offset intcmd_next    ;Append internal cmd routine
  1385.         call    include_code        ;  to code.
  1386.         call    inline_code        ;Add code to COM file.
  1387.         clc
  1388.         ret
  1389. internal_cmd    endp
  1390.  
  1391. ;-----------------------------------------------------------------------------
  1392. ; SET CMD compiles a command to change variables in the evvironment
  1393. ; Entry:  SI - Pointer to character after the command
  1394. ;      DI - Pointer to end of compiled data.
  1395. ; Exit:   CF - Set if error
  1396. ;      DX - Offset to error message if CF set.
  1397. ;      SI,DI updated.
  1398. ;-----------------------------------------------------------------------------
  1399. set_cmd     proc    near
  1400.         assume    cs:code,ds:code
  1401.         xor    bl,bl            ;Find the first nonspace char.
  1402.         call    scan4char
  1403.         mov    dx,di            ;Save ptr to set command.
  1404.         xor    ah,ah
  1405.         call    copy_string        ;Copy string to COM data
  1406.         xor    al,al            ;Append zero
  1407.         stosb
  1408.         sub    dx,databuff_start    ;Compute offset of data.
  1409.         mov    cx,1
  1410.         or    bx,bx            ;See if translation code needed
  1411.         je    setcmd_1
  1412.  
  1413.         mov    bx,offset procstr_next    ;Get offset of translate
  1414.         call    include_code        ;  routine.
  1415.         mov    bx,offset str1_buff_ptr - offset data_start
  1416.         mov    cx,0021h        ;Indicate parameter type
  1417.         call    inline_code        ;Insert translate code.
  1418.         mov    cx,2            ;Use proper parameter type
  1419.         mov    dx,bx            ;Get input from str1 buffer
  1420. setcmd_1:
  1421.         mov    bx,offset setenv_next    ;Append set routine to code.
  1422.         call    include_code
  1423.         call    inline_code        ;Add code to COM file.
  1424.         clc
  1425.         ret
  1426. set_cmd     endp
  1427.  
  1428. ;-----------------------------------------------------------------------------
  1429. ; ECHO CMD compiles an ECHO command.
  1430. ; Entry:  SI - Pointer to character after the ECHO command
  1431. ;      DI - Pointer to end of compiled data.
  1432. ; Exit:   AL - Error code if CF set
  1433. ;      CF - Set if error
  1434. ;      SI,DI updated.
  1435. ;-----------------------------------------------------------------------------
  1436. echo_cmd    proc    near
  1437.         assume    cs:code,ds:code
  1438.         xor    bl,bl            ;Echo can either echo a
  1439.         call    scan4char        ;  string to the keyboard or
  1440.         jc    echo_c0         ;  toggle the echo flag.
  1441.         or    al,20h            ;Check for on or off keyword
  1442.         cmp    al,"o"                  ;  to indicate what type of
  1443.         jne    echo_c0         ;  Echo this is.
  1444.         mov    ax,[si+1]        ;Get next two characters
  1445.         or    ax,2020h        ;Make lower case
  1446.         mov    bl,1
  1447.         cmp    al,"n"                  ;Check for echo on
  1448.         je    echo_c00
  1449.         cmp    ax,"ff"                 ;Check for echo off
  1450.         jne    echo_c0
  1451.         dec    bl
  1452.         mov    ah,[si+3]        ;Get character past word
  1453. echo_c00:
  1454.         cmp    ah," "                  ;Make sure not just the start
  1455.         ja    echo_c0         ;  of another word.
  1456.         mov    fileecho,bl        ;Save status of echo flag
  1457.         mov    bl,2
  1458.         call    scan4char        ;Find end of line.
  1459.         jmp    short echo_exit
  1460. ;
  1461. ;Echo ASCII line, Include code in COM file to echo string.
  1462. ;
  1463. echo_c0:
  1464.         mov    dx,di            ;Save pointer to string start
  1465.         xor    ah,ah
  1466.         call    copy_string        ;Copy string to COM data.
  1467.         mov    ax,0d0ah        ;Terminate line with CRLF
  1468.         stosw
  1469.         xor    al,al            ;Append zero byte
  1470.         stosb
  1471.         mov    cx,1            ;Append runtime routines.
  1472.         sub    dx,databuff_start
  1473.         or    bx,bx            ;Check translate flag, if set
  1474.         je    echo_c21        ;  append translate code 1st.
  1475.         mov    bx,offset procstr_next    ;Append translate string
  1476.         call    include_code        ;  routine to code.
  1477.         mov    bx,offset str1_buff_ptr - offset data_start
  1478.         mov    cx,0021h        ;Indicate parameter type
  1479.         call    inline_code        ;Insert translate code.
  1480.         mov    dx,bx
  1481.         mov    cx,2            ;Use proper parameter type
  1482. echo_c21:
  1483.         mov    bx,offset echo_msg_next ;Append echo string
  1484.         call    include_code        ;  routine to code.
  1485. echo_c3:
  1486.         call    inline_code        ;Add code to COM file.
  1487. echo_cstatus:
  1488. echo_exit:
  1489.         clc
  1490. echo_cmd_exit:
  1491.         ret
  1492. echo_cmd    endp
  1493.  
  1494. ;-----------------------------------------------------------------------------
  1495. ; PAUSE CMD compiles a PAUSE command.
  1496. ; Entry:  SI - Pointer to character after the PAUSE command
  1497. ;      DI - Pointer to end of compiled data.
  1498. ; Exit:   AL - Error code if CF set
  1499. ;      CF - Set if error
  1500. ;      SI,DI updated.
  1501. ;-----------------------------------------------------------------------------
  1502. pause_cmd    proc    near
  1503.         assume    cs:code,ds:code
  1504. ;Append routine if necessary
  1505.         mov    bx,offset pause_next     ;Append PAUSE routine if
  1506.         call    include_code         ;  necessary.
  1507.  
  1508.         mov    cx,0            ;Add inline code with 0 params
  1509.         call    inline_code        ;  to call pause routine.
  1510.  
  1511.         mov    bl,2            ;Scan to end of line
  1512.         call    scan4char
  1513.         clc
  1514. pause_cmd_exit:
  1515.         ret
  1516. pause_cmd    endp
  1517.  
  1518. ;-----------------------------------------------------------------------------
  1519. ; SHIFT CMD compiles a SHIFT command.
  1520. ; Entry:  SI - Pointer to character after the SHIFT command
  1521. ;      DI - Pointer to end of compiled data.
  1522. ; Exit:   AL - Error code if CF set
  1523. ;      CF - Set if error
  1524. ;      SI,DI updated.
  1525. ;-----------------------------------------------------------------------------
  1526. shift_cmd    proc    near
  1527.         assume    cs:code,ds:code
  1528.         mov    bx,offset shift_next     ;Append shift routine if
  1529.         call    include_code         ;  necessary.
  1530.         mov    cx,0            ;Add inline code with 0 params
  1531.         call    inline_code        ;  to call pause routine.
  1532.         mov    bl,2            ;Scan to end of line
  1533.         call    scan4char
  1534.         clc
  1535.         ret
  1536. shift_cmd    endp
  1537.  
  1538. ;-----------------------------------------------------------------------------
  1539. ; REM CMD  Processes remark lines in batch file.
  1540. ; Entry:  SI - pointer to line in BAT file
  1541. ;-----------------------------------------------------------------------------
  1542. rem_cmd     proc near
  1543.         assume    cs:code,ds:code
  1544.         dec    si            ;Back up to make sure we don't
  1545. rem_c1:     lodsb                ;  miss a carrage return.
  1546.         cmp    al,1ah            ;Loop until end of line or end
  1547.         je    rem_exit        ;  of file.
  1548.         cmp    al,13
  1549.         jne    rem_c1
  1550. rem_exit:
  1551.         clc
  1552.         ret
  1553. rem_cmd     endp
  1554.  
  1555. ;-----------------------------------------------------------------------------
  1556. ; COPY STRING copies a string to the com file data buffer.
  1557. ; Entry:  SI - Pointer to 1st character of the string.
  1558. ;      DI - Pointer to end of compiled data.
  1559. ;      AH - 0 = copy until end of line
  1560. ;           1 = copy only one word
  1561. ;           2 = copy until ')'
  1562. ; Exit:   BX - 0 if no environment variables or command line parameters.
  1563. ;      CX - Size of string.
  1564. ;      SI,DI updated.
  1565. ;-----------------------------------------------------------------------------
  1566. copy_string    proc    near
  1567.         assume    cs:code,ds:code
  1568.         push    dx
  1569.         mov    dx,di            ;Copy pointer to string
  1570.         xor    bx,bx            ;Clear param/env flag
  1571.         xor    cx,cx            ;Clear count
  1572. copystr_1:
  1573.         lodsb                ;Get byte
  1574.         cmp    al,9            ;Don't exit if tab
  1575.         je    copystr_2
  1576.         cmp    al,13            ;See if carrage return
  1577.         jbe    copystr_exit        ;Yes, quit.
  1578. copystr_2:
  1579.         cmp    ah,2            ;See if set copy
  1580.         jne    copystr_3        ;No, skip next test.
  1581.         cmp    al,')'                  ;See if end of set
  1582.         je    copystr_exit        ;Yes, quit.
  1583. copystr_3:
  1584.         cmp    ah,1            ;See if phrase or word copy
  1585.         jne    copystr_4        ;Phase, skip next test.
  1586.         cmp    al,' '                  ;See if end of word.
  1587.         jbe    copystr_exit        ;Yes, quit.
  1588.         cmp    al,'='                  ;Equal sign indicates end of
  1589.         je    copystr_exit        ;  word.
  1590. copystr_4:
  1591.         inc    cx
  1592.         cmp    al,'%'                  ;See if translation needed.
  1593.         jne    copystr_6
  1594.         inc    bh
  1595.         or    bl,bl            ;See if already set.
  1596.         mov    bl,0            ;Clear flag
  1597.         jne    copystr_6        ;If set, this must be the
  1598.         cmp    byte ptr [si],7fh    ;Check for For loop var. If
  1599.         jne    copystr_5        ;  found, copy it removing
  1600.         stosb                ;  the extra space.
  1601.         lodsb
  1602.         inc    si
  1603.         jmp    short copystr_6
  1604. copystr_5:
  1605.         cmp    byte ptr [si],'9'       ;  trailing % of an env var.
  1606.         jbe    copystr_6
  1607.         call    capsword        ;Env var, capitialize it.
  1608.         inc    bl
  1609. copystr_6:
  1610.         stosb                ;Save byte
  1611.         jmp    short copystr_1     ;Loop back.
  1612. copystr_exit:
  1613.         pop    dx
  1614.         ret
  1615. copy_string    endp
  1616.  
  1617. ;-----------------------------------------------------------------------------
  1618. ; INLINE CODE  Adds the necessary inline code to call a canned
  1619. ;        routine.
  1620. ; Entry:  AX - Offset of canned routine.
  1621. ;      CL - (low nibble) Method to pass parameter one
  1622. ;      CL - (high nibble) Method to pass parameter two
  1623. ;      CH - (low nibble) Call/Jump method
  1624. ;      DX - Parameter one
  1625. ;      BX - Parameter two
  1626. ;-----------------------------------------------------------------------------
  1627. inline_code    proc    near
  1628.         push    bp
  1629.         push    si            ;Save pointer to input buffer.
  1630.         push    di
  1631.         push    es
  1632.         les    di,codebuff_ptr     ;Point ES:DI to buffer
  1633.         mov    bp,cx
  1634.         and    cl,0fh            ;Look only at SI code nibble
  1635.         cmp    cl,1            ;Check for LEA SI
  1636.         jne    inline_1
  1637.         mov    si,offset code_leasi
  1638.         mov    [si+2],dx        ;Load paramter one
  1639.         mov    cx,code_leasi_size
  1640.         rep    movsb            ;Copy routine into COM file.
  1641.         jmp    short inline_10
  1642. inline_1:
  1643.         cmp    cl,2            ;Check for MOV SI
  1644.         jne    inline_2
  1645.         mov    si,offset code_movsi
  1646.         mov    [si+2],dx        ;Load parameter one
  1647.         mov    cx,code_movsi_size
  1648.         rep    movsb            ;Copy routine into COM file.
  1649.         jmp    short inline_10
  1650. inline_2:
  1651.         cmp    cl,3            ;Check for MOV SI Immediate
  1652.         jne    inline_10
  1653.         mov    si,offset code_movsiim
  1654.         mov    [si+1],dx        ;Load parameter one
  1655.         mov    cx,code_movsiim_size
  1656.         rep    movsb            ;Copy routine into COM file.
  1657. inline_10:
  1658.         mov    cx,bp            ;Get back code
  1659.         and    cl,0f0h
  1660.         cmp    cl,10h            ;Check for LEA DI
  1661.         jne    inline_11
  1662.         mov    si,offset code_leadi
  1663.         mov    [si+2],bx        ;Load paramter two
  1664.         mov    cx,code_leadi_size
  1665.         rep    movsb            ;Copy routine into COM file.
  1666.         jmp    short inline_13
  1667. inline_11:
  1668.         cmp    cl,20h            ;Check for MOV DI
  1669.         jne    inline_12
  1670.         mov    si,offset code_movdi
  1671.         mov    [si+2],bx        ;Load parameter two
  1672.         mov    cx,code_movdi_size
  1673.         rep    movsb            ;Copy routine into COM file.
  1674.         jmp    short inline_13
  1675. inline_12:
  1676.         cmp    cl,30h            ;Check for MOV immed DI
  1677.         jne    inline_13
  1678.         mov    si,offset code_movdiim
  1679.         mov    [si+1],bx        ;Load parameter two
  1680.         mov    cx,code_movdiim_size
  1681.         rep    movsb            ;Copy routine into COM file.
  1682. inline_13:
  1683.         mov    cx,bp
  1684.         and    ch,0fh
  1685.         jne    inline_20
  1686.         mov    si,offset code_call    ;Code to call the canned
  1687.         mov    cx,code_call_size    ;  routine.
  1688.         mov    [si+1],ax        ;Insert the destination offset.
  1689.         rep    movsb            ;Copy routine into COM file.
  1690.         jmp    short inline_30
  1691. inline_20:
  1692.         cmp    ch,01            ;Check for jmp
  1693.         jne    inline_21
  1694.         mov    si,offset code_jmp    ;Code to jmp to destination.
  1695.         mov    cx,code_jmp_size
  1696.         mov    [si+2],ax        ;Insert the destination offset.
  1697.         rep    movsb            ;Copy routine into COM file.
  1698.         jmp    short inline_30
  1699. inline_21:
  1700.         cmp    ch,02            ;Check for jc
  1701.         jne    inline_22
  1702.         mov    si,offset code_jc    ;Code to jc to destination.
  1703.         mov    cx,code_jc_size
  1704.         lea    ax,[di+3]        ;Save offset of JMP to mod
  1705.         rep    movsb            ;Copy routine into COM file.
  1706.         jmp    short inline_30
  1707. inline_22:
  1708.         cmp    ch,03            ;Check for jnc
  1709.         jne    inline_23
  1710.         mov    si,offset code_jnc    ;Code to jnc to destination.
  1711.         mov    cx,code_jnc_size
  1712.         lea    ax,[di+3]        ;Save offset of JMP to mod
  1713.         rep    movsb            ;Copy routine into COM file.
  1714.         jmp    short inline_30
  1715. inline_23:
  1716.         cmp    ch,04            ;Check for jmp displacment
  1717.         jne    inline_30
  1718.         mov    si,offset code_jmpdis    ;Code to jmp IP relative.
  1719.         mov    [si+1],ax
  1720.         mov    cx,code_jmpdis_size
  1721.         rep    movsb            ;Copy routine into COM file.
  1722. inline_30:
  1723.         mov    word ptr cs:codebuff_ptr,di
  1724.         pop    es
  1725.         pop    di
  1726.         pop    si
  1727.         pop    bp
  1728.         ret
  1729. inline_code    endp
  1730.  
  1731. ;-----------------------------------------------------------------------------
  1732. ; INCLUDE CODE - Appends the routine to the append list if necessary and
  1733. ;         returns the offset of the routine in the compiled program.
  1734. ; Entry:  BX - Pointer to header of canned routine to append.
  1735. ; Exit:   AX - Offset of canned routine in COM file.
  1736. ;-----------------------------------------------------------------------------
  1737. include_code    proc    near
  1738.         assume    ds:code,es:nothing
  1739.         push    cx
  1740.         push    dx
  1741.         mov    ax,[bx-4]        ;Get COM file offset
  1742.         or    ax,ax            ;If zero, routine has not
  1743.         jne    include_exit        ;  been appended.
  1744.         mov    cx,bx            ;Save pointer to new routine
  1745. ;
  1746. ;Address the prevous 'last' routine header.  Update that header, then use
  1747. ;information in that header to compute the offset of the new routine.
  1748. ;
  1749.         xchg    bx,last_routine
  1750.         mov    [bx],cx         ;Add code to chain.
  1751.         mov    ax,[bx-2]        ;Compute offset of new routine
  1752.         add    ax,[bx-4]        ;  by adding the offset of the
  1753.         sub    ax,[bx+2]        ;  prevous routine to its size.
  1754.         mov    bx,cx
  1755.  
  1756.         mov    cx,[bx+2]        ;Get number of called routines.
  1757.         add    ax,cx
  1758.         mov    [bx-4],ax        ;Set offset of code.
  1759.         jcxz    include_exit
  1760.         shr    cx,1            ;If this routine needs other
  1761.         add    bx,4            ;  routines, include them in
  1762.         push    ax            ;  the COM file.
  1763. include_1:
  1764.         push    cx
  1765.         push    bx
  1766.         mov    bx,[bx]
  1767.         call    include_code
  1768.         pop    bx
  1769.         mov    [bx],ax
  1770.         add    bx,2
  1771.         pop    cx
  1772.         loop    include_1
  1773.         pop    ax
  1774. include_exit:
  1775.         pop    dx
  1776.         pop    cx
  1777.         ret
  1778. include_code    endp
  1779. ;-----------------------------------------------------------------------------
  1780. ; PRINTMSG prints the message pointed to by DX to the screen.
  1781. ; Entry:  DX - pointer to ASCII message terminated by $
  1782. ;-----------------------------------------------------------------------------
  1783. printmsg    proc    near
  1784.         assume    ds:nothing,es:nothing
  1785.         push    ds
  1786.         push    cs
  1787.         pop    ds
  1788.         assume    ds:code
  1789.         mov    ah,9            ;Print message
  1790.         int    21h
  1791.         pop    ds
  1792.         ret
  1793. printmsg    endp
  1794.  
  1795. ;-----------------------------------------------------------------------------
  1796. ; PRINTMSGCR calls PRINTMSG, then appends a carriage return to the message.
  1797. ; Entry:  DX - pointer to ASCII message terminated by $
  1798. ;-----------------------------------------------------------------------------
  1799. printmsgcr    proc    near
  1800.         assume    ds:nothing,es:nothing
  1801.         push    dx
  1802.         call    printmsg
  1803.         mov    dx,offset endmsg
  1804.         call    printmsg
  1805.         pop    dx
  1806.         ret
  1807. printmsgcr    endp
  1808.  
  1809. ;-----------------------------------------------------------------------------
  1810. ; HEX2ASC converts a binary number to ASCII and prints it to the screen.
  1811. ; Entry:  AX - binary number
  1812. ;-----------------------------------------------------------------------------
  1813. hex2asc     proc near
  1814.         assume    ds:nothing,es:nothing
  1815.         push    bx
  1816.         mov    cx,5            ;Allow max of five digits
  1817. hex_loop1:
  1818.         xor    dx,dx            ;Clear high word
  1819.         mov    bx,10            ;Load number base
  1820.         div    bx            ;Divide by base (10)
  1821.         add    dl,30h            ;Convert to ascii
  1822.         push    dx            ;Save digit on stack
  1823.         loop    hex_loop1
  1824.         mov    cx,5            ;Allow max of five digits
  1825.         mov    bl,"0"                  ;Set leading zero indicator
  1826. hex_loop2:
  1827.         pop    dx            ;Get digit off stack
  1828.         or    bl,dl            ;Don't print leading zeros.
  1829.         cmp    bl,"0"                  ;The first non zero will
  1830.         je    hex_1            ;  change bl to non-zero.
  1831.         mov    ah,2            ;DOS character output
  1832.         int    21h
  1833. hex_1:
  1834.         loop    hex_loop2
  1835. hex_exit:
  1836.         pop    bx
  1837.         ret
  1838. hex2asc     endp
  1839.  
  1840. ;-----------------------------------------------------------------------------
  1841. ; LOADBATFILE loads the input BAT file.
  1842. ; Entry:  DS:SI - pointer to the name of the file to open
  1843. ; Exit:      CF - clear if successful
  1844. ;-----------------------------------------------------------------------------
  1845. loadbatfile    proc    near
  1846.         assume    cs:code,ds:code
  1847.         push    si
  1848.         mov    dx,si            ;Save filename pointer
  1849.         mov    di,offset outfile_name    ;Point DI to buffer to hold
  1850.         mov    cx,8            ;  the output file name.
  1851. loadfile_1:
  1852.         lodsb                ;Copy the name until the
  1853.         cmp    al,' '                  ;  extension is reached.
  1854.         je    loadfile_10
  1855.         cmp    al,'.'
  1856.         je    loadfile_10
  1857.         stosb
  1858.         loop    loadfile_1
  1859. loadfile_10:
  1860.         mov    si,offset com_string    ;Append COM extension to
  1861.         movsb                ;  output file name.
  1862.         movsw
  1863.         movsw
  1864.         mov    file_pointer,0        ;Clear file pointer.
  1865.         mov    si,dx            ;Get back filename pointer
  1866.         mov    bl,1            ;Find end of filename
  1867.         call    scanline
  1868.         dec    si
  1869.         mov    byte ptr [si],0     ;Make filename ASCIIZ.
  1870.         mov    ax,3d00h        ;Open file (Read only)
  1871.         int    21h
  1872.         jc    loadfile_error
  1873.         mov    bx,ax            ;Copy file handle
  1874. ;
  1875. ;Read contents into file buffer.
  1876. ;
  1877.         mov    ah,3fh            ;Read input BAT file into
  1878.         mov    dx,inbuff_ptr        ;  memory above stack space
  1879.         mov    cx,inbuff_size        ;Get size of buffer
  1880.         int    21h
  1881.         cmp    ax,cx            ;Check if complete file read.
  1882.         jbe    loadfile_2
  1883.         std                ;If there is more of the file
  1884.         push    di            ;  to read, scan backwards to
  1885.         push    es            ;  the end of the last line.
  1886.         push    cs
  1887.         pop    es
  1888.         mov    di,ax
  1889.         mov    al,13            ;Scan for last CR
  1890.         repne    scasb
  1891.         mov    ax,di
  1892.         pop    es
  1893.         pop    di
  1894.         mov    file_pointer,ax
  1895.         mov    file_handle,bx
  1896. loadfile_2:
  1897.         mov    word ptr ds:[si],1A0Dh    ;Append CR and EOF bytes
  1898.         mov    cx,ax            ;Save new file size
  1899.         mov    si,dx            ;Reset file pointer.
  1900.         mov    ah,3eh            ;Close file.
  1901.         int    21h
  1902.         mov    cs:[file_linecount],0    ;Reset line counter.
  1903. loadfile_exit:
  1904.         clc
  1905. loadfile_exit1:
  1906.         pop    si
  1907.         ret
  1908. loadfile_error:
  1909.         stc
  1910.         mov    dx,offset errmsg2    ;Bad filename specified.
  1911.         jmp    short loadfile_exit1
  1912. loadbatfile    endp
  1913.  
  1914. ;-----------------------------------------------------------------------------
  1915. ; SCANLINE performs the same function as SCAN4CHAR but keeps track of the
  1916. ; carriage returns.
  1917. ; Entry:  SI - pointer to ASCII string
  1918. ;      BL - 0 = find next char, 1 = find next space
  1919. ; Exit:   AL - first nonspace character
  1920. ;      CF - set if carriage return found
  1921. ;-----------------------------------------------------------------------------
  1922. scanline    proc    near
  1923.         call    scan4char        ;Find the next char.
  1924.         jnc    scanline_exit
  1925.         inc    cs:[file_linecount]    ;Point to next line.
  1926.         stc
  1927. scanline_exit:
  1928.         ret
  1929. scanline    endp
  1930.  
  1931. ;-----------------------------------------------------------------------------
  1932. ; SCAN4CHAR scans a string to find the first character.
  1933. ; Entry:  SI - pointer to ASCII string
  1934. ;      BL - 0 = find next char, 1 = find next space, 2 = find end of line.
  1935. ; Exit:   AL - matching character
  1936. ;      SI - pointer to matching character
  1937. ;      CF - set if carriage return or EOF found
  1938. ;-----------------------------------------------------------------------------
  1939. scan4char    proc near
  1940.         assume    ds:nothing,es:nothing
  1941. scan4loop:
  1942.         lodsb
  1943.         cmp    al,13            ;Check for carriage return.
  1944.         je    scan4_eol
  1945.         cmp    al,1ah            ;Check for end of file char.
  1946.         jne    scan4_1
  1947. scan4_eol:
  1948.         stc
  1949.         jmp    short scan4_exit1
  1950. scan4_1:
  1951.         cmp    bl,1            ;Check if searching for space,
  1952.         je    scan4_2         ;  character, or end of line.
  1953.         ja    scan4loop
  1954.         cmp    al," "                  ;Check for space or other
  1955.         jbe    scan4loop        ;  'white' characters.
  1956.         jmp    short scan4_exit
  1957. scan4_2:
  1958.         cmp    al," "                  ;Check for characters.
  1959.         ja    scan4loop
  1960. scan4_exit:
  1961.         dec    si            ;Back up before character
  1962.         clc
  1963. scan4_exit1:
  1964.         ret
  1965. scan4char    endp
  1966.  
  1967. ;============================================================================
  1968. ;Routines used by compiled program.
  1969. ;============================================================================
  1970. ;!!--------------------------------------------------------------------------
  1971. ;Code fragments used to call canned routines.
  1972. ;----------------------------------------------------------------------------
  1973. code_call    proc    near
  1974.         mov    ax,1234h        ;Set address to call routine.
  1975.         call    ax            ;Call canned routine.
  1976. code_call_end    =    $
  1977. code_call    endp
  1978.  
  1979. code_jmp    proc    near
  1980.         mov    ax,[bp+1234h]        ;Set address to call routine.
  1981.         jmp    ax            ;Jump to new offset.
  1982. code_jmp_end    =    $
  1983. code_jmp    endp
  1984.  
  1985. code_jc     proc    near
  1986.         jnc    code_jc_end        ;Jump over long jmp
  1987.         jmp    initialize        ;This jmp will be modified
  1988. code_jc_end    =    $
  1989. code_jc     endp
  1990.  
  1991. code_jnc    proc    near
  1992.         jc    code_jnc_end        ;Skip over long jmp
  1993.         jmp    initialize        ;This jmp will be modified
  1994. code_jnc_end    =    $
  1995. code_jnc    endp
  1996.  
  1997. code_jmpdis    proc    near
  1998.         jmp    initialize        ;This jmp will be modified
  1999. code_jmpdis_end =    $
  2000. code_jmpdis    endp
  2001.  
  2002. code_leasi    proc    near
  2003.         lea    si,[bp+1234h]        ;Load address of data
  2004. code_leasi_end    =    $
  2005. code_leasi    endp
  2006.  
  2007. code_movsi    proc    near
  2008.         mov    si,[bp+1234h]        ;Load data
  2009. code_movsi_end    =    $
  2010. code_movsi    endp
  2011.  
  2012. code_movsiim    proc    near
  2013.         mov    si,1234h        ;Load immediate data
  2014. code_movsiim_end  =    $
  2015. code_movsiim    endp
  2016.  
  2017. code_leadi    proc    near
  2018.         lea    di,[bp+1234h]        ;Load address of data
  2019. code_leadi_end    =    $
  2020. code_leadi    endp
  2021.  
  2022. code_movdi    proc    near
  2023.         mov    di,[bp+1234h]        ;Load data
  2024. code_movdi_end    =    $
  2025. code_movdi    endp
  2026.  
  2027. code_movdiim    proc    near
  2028.         mov    di,1234h        ;Load immediate data
  2029. code_movdiim_end  =    $
  2030. code_movdiim    endp
  2031.  
  2032. ;----------------------------------------------------------------------------
  2033. ;Predefined data needed for all compiled programs.
  2034. ;----------------------------------------------------------------------------
  2035. data_start    =    $
  2036. code_start    dw    ?            ;Offset of main code routine
  2037. stack_ptr    dw    ?            ;Offset of end of code + stack
  2038. prog_segsize    dw    ?            ;Size of COM prog in paragraphs
  2039. str1_buff_ptr    dw    ?            ;Buffer for parsing strings
  2040. str2_buff_ptr    dw    ?            ;Buffer for parsing strings
  2041. str3_buff_ptr    dw    ?            ;Buffer for For loop variables
  2042. floop_ptr    dw    ?            ;Pointer to for loop string
  2043. file_handle1    dw    ?            ;Saved handle of std output
  2044. file_handle2    dw    ?            ;Handle of output file
  2045. file_handle3    dw    ?            ;Saved handle of std input
  2046. file_handle4    dw    ?            ;Handle of input file
  2047. label_list_strt dw    ?            ;Offset into data of 1st label.
  2048. master_env    dw    ?            ;Segment of environment blk
  2049. version_num    dw    ?            ;DOS version number
  2050. proc_rc     db    ?            ;Return code of last program.
  2051. shift_cnt    db    ?            ;Count of shift parameter
  2052. data_end    =    $
  2053.  
  2054. ;----------------------------------------------------------------------------
  2055. ;INIT CODE Routine at the start of all compiled programs.
  2056. ;----------------------------------------------------------------------------
  2057. init_code_off    dw    100h            ;Pointer to offset in COM file
  2058. init_code_size    dw    offset init_code_end-offset init_code_start
  2059. init_code_next    dw    0            ;Ptr to next routine to append
  2060. init_code_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2061. init_code_start =    $
  2062.  
  2063. init_code    proc    near
  2064.         assume    cs:code,ds:code,es:code,ss:code
  2065.         mov    bp,ds:[offset data_start_ptr - offset init_code + 100h]
  2066.         mov    bp,[bp]
  2067.         mov    sp,com_stack_ptr    ;Move stack pointer
  2068.         mov    bx,com_prog_size    ;Reduce memory allocation
  2069.         mov    ah,4ah            ;Resize memory block
  2070.         int    21h
  2071.         mov    ax,ds:[2ch]        ;Get program environment seg
  2072.         mov    environment_seg,ax    ;  use unless SET cmd used.
  2073.         mov    bx,code_start_ptr    ;Get starting code offset
  2074.         jmp    bx            ;Jump to start of code.
  2075. init_code    endp
  2076. data_start_ptr    dw    ?            ;Offset of data area.
  2077. init_code_end    =    $
  2078.  
  2079. ;----------------------------------------------------------------------------
  2080. ;END CODE Routine appended at the end of all compiled programs.
  2081. ;----------------------------------------------------------------------------
  2082. end_code_off    dw    0            ;Pointer to offset in COM file
  2083. end_code_size    dw    offset end_code_end-offset end_code_start
  2084. end_code_next    dw    0            ;Ptr to next routine to append
  2085. end_code_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2086. end_code_start    =    $
  2087.  
  2088. end_code    proc    near
  2089.         assume    cs:code,ds:code
  2090.         mov    ax,4c00h        ;Terminate program
  2091.         int    21h
  2092. end_code    endp
  2093. end_code_end    =    $
  2094.  
  2095. ;----------------------------------------------------------------------------
  2096. ;ECHO MSG CODE Routine used print a string to the standard output device
  2097. ; Entry:  DS:SI - offset of string to print.
  2098. ;----------------------------------------------------------------------------
  2099. echo_msg_off    dw    0            ;Pointer to offset in COM file
  2100. echo_msg_size    dw    offset echo_msg_end-offset echo_msg_start
  2101. echo_msg_next    dw    0            ;Ptr to next routine to append
  2102. echo_msg_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2103. echo_msg_start    =    $
  2104.  
  2105. echo_msg_code    proc    near
  2106.         assume    cs:code,ds:code
  2107.         mov    dl,[si]         ;Get character
  2108.         inc    si
  2109.         or    dl,dl
  2110.         je    echo_msg_1
  2111.         mov    ah,2            ;Print character
  2112.         int    21h
  2113.         jmp    short echo_msg_code
  2114. echo_msg_1:
  2115.         ret
  2116. echo_msg_code    endp
  2117. echo_msg_end    =    $
  2118.  
  2119. ;----------------------------------------------------------------------------
  2120. ;ECHO STATUS CODE Routine used to report the status of the echo flag.
  2121. ; Entry:  AL - Echo flag.
  2122. ;----------------------------------------------------------------------------
  2123. echo_stat_ptr    dw    0            ;Pointer to offset in COM file
  2124. echo_stat_size    dw    offset echo_stat_end-offset echo_stat_start
  2125. echo_stat_next    dw    0            ;Ptr to next routine to append
  2126. echo_stat_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2127. echo_stat_start =    $
  2128.  
  2129. echo_stat_code    proc    near
  2130.         assume    cs:code,ds:code
  2131.         call    echo_stat_1        ;Push IP on stack
  2132. echo_msg    db    "ECHO is $"
  2133. echo_on     db    "on",10,13,"$"
  2134. echo_off    db    "off",10,13,"$"
  2135. echo_stat_1:
  2136.         pop    dx            ;Pop offset of echo message
  2137.         push    ax            ;Save status of echo flag
  2138.         mov    ah,9
  2139.         int    21h
  2140.         add    dx,offset echo_on-offset echo_msg ;Point to 'on' msg
  2141.         pop    ax
  2142.         or    al,al            ;Check status of echo flag
  2143.         je    echo_report_1
  2144.         add    dx,offset echo_off-offset echo_on ;Point to 'off' msg
  2145.         add    dx,5            ;Point to off message.
  2146. echo_report_1:
  2147.         mov    ah,9            ;Print last part of echo stat
  2148.         int    21h
  2149.         ret
  2150. echo_stat_code    endp
  2151. echo_stat_end    =    $
  2152.  
  2153. ;----------------------------------------------------------------------------
  2154. ;PAUSE CODE Routine used pause execution of the COM file.
  2155. ;----------------------------------------------------------------------------
  2156. pause_ptr    dw    0            ;Pointer to offset in COM file
  2157. pause_size    dw    offset pause_end-offset pause_start
  2158. pause_next    dw    0            ;Ptr to next routine to append
  2159. pause_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2160. pause_start    =    $
  2161.  
  2162. pause_code    proc    near
  2163.         assume    cs:code,ds:code
  2164.         call    pause_1     ;Push IP on stack
  2165. pause_msg    db    "Strike any key when ready...",13,10,"$"
  2166. pause_1:
  2167.         pop    dx            ;Pop offset of message
  2168.         mov    ah,9            ;Print message.
  2169.         int    21h
  2170.  
  2171.         mov    ah,7            ;Keyboard unfiltered input
  2172.         int    21h            ;  without echo.
  2173.         ret
  2174. pause_code    endp
  2175. pause_end    =    $
  2176.  
  2177. ;----------------------------------------------------------------------------
  2178. ;SHIFT CODE Routine used shift the input parameters by one.
  2179. ;----------------------------------------------------------------------------
  2180. shift_ptr    dw    0            ;Pointer to offset in COM file
  2181. shift_size    dw    offset shift_end-offset shift_start
  2182. shift_next    dw    0            ;Ptr to next routine to append
  2183. shift_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2184. shift_start    =    $
  2185.  
  2186. shift_code    proc    near
  2187.         assume    cs:code,ds:code
  2188.         inc    byte ptr shift_count     ;Inc shift count.
  2189.         ret
  2190. shift_code    endp
  2191. shift_end    =    $
  2192.  
  2193. ;-----------------------------------------------------------------------------
  2194. ; SCAN_CHAR scans a string to find the first character.
  2195. ; Entry:  SI - pointer to ASCII string
  2196. ;      DL - 0 = find next char, 1 = find next space
  2197. ;      CX - file length
  2198. ; Exit:   AL - first nonspace character
  2199. ;      CF - set if carriage return found
  2200. ;-----------------------------------------------------------------------------
  2201. scan4_off    dw    0            ;Pointer to offset in COM file
  2202. scan4_size    dw    offset scan4_end - offset scan4_start
  2203. scan4_next    dw    0            ;Ptr to next routine to append
  2204. scan4_lnks    dw    0
  2205. scan4_start    =    $
  2206.  
  2207. scan_char    proc near
  2208.         assume    ds:nothing,es:nothing
  2209. scan_loop:
  2210.         lodsb
  2211.         cmp    al,9            ;See if char is tab
  2212.         je    scan_space        ;If before, end of line
  2213.         cmp    al," "                  ;See if char is space.
  2214.         jb    scan_eol        ;If before, end of line
  2215.         je    scan_space
  2216.         or    dl,dl            ;Not space, if looking
  2217.         jne    scan_loop        ;  for space continue.
  2218.         jmp    short scan_exit
  2219. scan_space:
  2220.         or    dl,dl            ;Space found, see if looking
  2221.         je    scan_loop        ;  for one.
  2222. scan_exit:
  2223.         clc
  2224.         ret
  2225. scan_eol:
  2226.         stc
  2227.         ret
  2228. scan_char    endp
  2229. scan4_end    =    $
  2230.  
  2231. ;-----------------------------------------------------------------------------
  2232. ; GETMEMBER  returns a pointer to the Nth word in a line.
  2233. ; Entry:     SI - pointer to line of words
  2234. ;         DH - number of the word to return
  2235. ; Exit:      SI - pointer to word
  2236. ;         CF - Set if word not in line.
  2237. ;-----------------------------------------------------------------------------
  2238. getmember_scan4 equ    [bx-6]
  2239. getmember_off    dw    0            ;Pointer to offset in COM file
  2240. getmember_size    dw    offset getmember_end - offset getmember_start
  2241. getmember_next    dw    0            ;Ptr to next routine to append
  2242. getmember_lnks    dw    2            ;Bytes in the dependancy header
  2243. getmember_start =    $
  2244.         dw    offset scan4_next    ;Offset of called routine.
  2245.  
  2246. getmember    proc    near
  2247.         assume    cs:code,ds:code,es:code,ss:code
  2248.         push    bx
  2249.         call    getmember_0
  2250. getmember_0:
  2251.         pop    bx
  2252. getmember_1:
  2253.         xor    dl,dl
  2254.         call    getmember_scan4     ;Find next word
  2255.         jc    getmember_notfound
  2256.         dec    dh            ;Dec parameter count
  2257.         jle    getmember_2
  2258.         inc    dl
  2259.         call    getmember_scan4     ;Find next space
  2260.         jc    getmember_exit
  2261.         jmp    short getmember_1    ;If not done, loop back.
  2262. getmember_2:
  2263.         dec    si            ;Backup to 1st char in word.
  2264.         clc
  2265. getmember_exit:
  2266.         pop    bx
  2267.         ret
  2268. getmember_notfound:
  2269.         stc
  2270.         jmp    short getmember_exit
  2271. getmember    endp
  2272. getmember_end    =    $
  2273.  
  2274. ;-----------------------------------------------------------------------------
  2275. ; PROCSTRING processes a string to convert any environment variables or
  2276. ;         command line variables.
  2277. ; Entry:  DS:SI - ASCIIZ string to process
  2278. ;      ES:DI - pointer to output buffer.
  2279. ; Exit:   DS:SI - pointer to beginning of new ASCIIZ string.
  2280. ;     [SI-1] - Length of new string.
  2281. ;-----------------------------------------------------------------------------
  2282. procstr_cmdl    equ    [bx-8]
  2283. procstr_env    equ    [bx-6]
  2284. procstr_off    dw    0            ;Pointer to offset in COM file
  2285. procstr_size    dw    offset procstr_end - offset procstr_start
  2286. procstr_next    dw    0            ;Ptr to next routine to append
  2287. procstr_lnks    dw    4            ;Bytes in the dependancy header
  2288.  
  2289. procstr_start    =    $
  2290.         dw    offset subparm_next    ;Offset of called routines.
  2291.         dw    offset subenv_next
  2292.  
  2293. procstr_code    proc    near
  2294.         assume    cs:code,ds:code,es:code
  2295.         push    bx
  2296.         call    procstr_0
  2297. procstr_0:
  2298.         pop    bx
  2299.         push    di
  2300.         push    si
  2301.         mov    ah,255            ;Set size of buffer
  2302. procstr_1:
  2303.         lodsb                ;Get byte from string
  2304.         or    al,al            ;Check for end of string
  2305.         je    procstr_exit
  2306.         cmp    al,"%"                  ;See if special character
  2307. procstr_jmp:
  2308.         je    procstr_3        ;Yes, process special char.
  2309. procstr_2:
  2310.         stosb                ;Store byte from string
  2311.         dec    ah
  2312.         jne    procstr_1
  2313. procstr_exit:
  2314.         xor    al,al            ;Force zero byte end.
  2315.         stosb
  2316.         pop    si
  2317.         pop    di
  2318.         mov    bl,255
  2319.         sub    bl,ah
  2320.         mov    ds:[di-1],bl        ;Store length of string
  2321.         pop    bx
  2322.         ret
  2323. ;
  2324. ;A percent sign has been found indicating a 'soft' parameter.  Three types of
  2325. ;soft parameters are allowed; command line parameter, environment variable,
  2326. ;and for loop parameter.
  2327. ;
  2328. procstr_3:
  2329.         lodsb                ;Get next character
  2330.         dec    cx
  2331.         cmp    al,"%"                  ;If double %, include one
  2332.         je    procstr_2        ;  in string.
  2333.         cmp    al,7fh            ;See if for loop var
  2334.         jne    procstr_32
  2335.         push    si
  2336.         mov    si,forloop_ptr        ;Get ptr to for loop string
  2337. procstr_30:
  2338.         lodsb
  2339.         cmp    al,0            ;If zero, end of string
  2340.         je    procstr_31
  2341.         stosb
  2342.         dec    ah            ;Dec buffer size counter
  2343.         jne    procstr_30        ;If buffer not full, continue
  2344. procstr_31:
  2345.         pop    si            ;Get back source string pointer
  2346.         jmp    short procstr_4
  2347. procstr_32:
  2348.         mov    dh,al            ;Copy and check to see if
  2349.         sub    dh,"0"                  ;  the next char is a number.
  2350.         jb    procstr_5        ;  If so, assume a line
  2351.         cmp    dh,9            ;  parameter.
  2352.         ja    procstr_5
  2353.         call    procstr_cmdl        ;Call cmd line param routine
  2354. procstr_4:
  2355.         or    ah,ah
  2356.         jne    procstr_1
  2357.         jmp    short procstr_exit    ;If at end of string, done
  2358. procstr_5:
  2359.         dec    si            ;Backup to 1st character
  2360.         inc    cx
  2361.         call    procstr_env
  2362.         jmp    short procstr_4
  2363. procstr_code    endp
  2364. procstr_end    =    $
  2365.  
  2366. ;-----------------------------------------------------------------------------
  2367. ; SUBLINEPARAM substitutes a parameter from the command line.
  2368. ; Entry:  ES:DI - pointer to buffer to copy the line parameter
  2369. ;         DH - binary number of the line parameter
  2370. ;         AH - size of buffer
  2371. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  2372. ;         CX - remaining length of the buffer
  2373. ;-----------------------------------------------------------------------------
  2374. subparm_getmem    equ    [bx-6]
  2375. subparm_off    dw    0            ;Pointer to offset in COM file
  2376. subparm_size    dw    offset subparm_end - offset subparm_start
  2377. subparm_next    dw    0            ;Ptr to next routine to append
  2378. subparm_lnks    dw    2            ;Bytes in the dependancy header
  2379. subparm_start    =    $
  2380.         dw    offset getmember_next    ;Offset of called routine.
  2381.  
  2382. sublineparam    proc    near
  2383.         assume    cs:code,ds:code,es:code,ss:code
  2384.         push    bx
  2385.         call    sublineparam_1
  2386.         db    "DOS2X",0               ;Dummy %0 parameter for DOS 2x
  2387. sublineparam_1:
  2388.         pop    bx
  2389.         push    cx
  2390.         push    si
  2391.         push    ds
  2392.         mov    si,80h            ;Get ptr to cmd line
  2393.         xor    cx,cx
  2394.         mov    cl,[si]         ;Get number of chars in buffer.
  2395.         inc    si            ;Point to data
  2396.         add    dh,ds:shift_count    ;Add in shift count.
  2397.         or    dh,dh            ;Check count of param to find.
  2398.         jnz    sublineparam_12
  2399. ;
  2400. ;For parameter 0, attempt to look in the env block for the name of the prog.
  2401. ;
  2402.         push    ax            ;Save buffer size in AH
  2403.         mov    ah,30h            ;Get DOS version
  2404.         int    21h            ;If DOS 2.x, program nane not
  2405.         cmp    al,2            ;  in the env segment.    Use
  2406.         pop    ax
  2407.         ja    sublineparam_10     ;  dunny name instead.
  2408.         lea    si,[bx]         ;Point to dummy parameter
  2409.         jmp    short sublineparam_2
  2410. sublineparam_10:
  2411.         push    es
  2412.         push    di
  2413.         mov    es,ds:[2ch]        ;Get segment of local env
  2414.         xor    al,al
  2415.         xor    di,di
  2416.         mov    cx,8000h
  2417. sublineparam_11:
  2418.         repne    scasb            ;Find double zero
  2419.         scasb
  2420.         jne    sublineparam_11
  2421.         scasw                ;Scan to name
  2422.         mov    si,di            ;Copy pointer to name
  2423.         pop    di
  2424.         pop    es
  2425.         mov    ds,ds:[2ch]
  2426.         jmp    short sublineparam_2
  2427. sublineparam_12:
  2428.         call    subparm_getmem        ;Get pointer to proper word.
  2429.         jc    sublineparam_exit
  2430. sublineparam_2:
  2431.         lodsb                ;Get character from parameter
  2432.         cmp    al," "                  ;If space, parameter done
  2433.         jbe    sublineparam_exit
  2434.         stosb
  2435.         dec    ah            ;Dec buffer size counter
  2436.         jnz    sublineparam_2
  2437. sublineparam_exit:
  2438.         pop    ds
  2439.         pop    si
  2440.         pop    cx
  2441.         pop    bx
  2442.         ret
  2443. sublineparam    endp
  2444. subparm_end    =    $
  2445. ;-----------------------------------------------------------------------------
  2446. ; SUBENVVAR substitutes a parameter from the program environment block.
  2447. ; Entry:  DS:SI - pointer to enviroment variable.
  2448. ;      ES:DI - pointer to buffer.
  2449. ;         AH - size of buffer.
  2450. ; Exit:   ES:DI - pointer to byte after the parameter in the buffer
  2451. ;      DS:SI - pointer to the character after the line parameter number
  2452. ;         CX - remaining free bytes in the buffer.
  2453. ;-----------------------------------------------------------------------------
  2454. subenv_srchenv    equ    [bx-6]
  2455. subenv_off    dw    0            ;Pointer to offset in COM file
  2456. subenv_size    dw    offset subenv_end-offset subenv_start
  2457. subenv_next    dw    0            ;Ptr to next routine to append
  2458. subenv_lnks    dw    2            ;Bytes in the dependancy header
  2459. subenv_start    =    $
  2460.         dw    offset searchenv_next    ;Call to search environment blk
  2461.  
  2462. subenvvar    proc    near
  2463.         assume    cs:code,ds:code,es:code,ss:code
  2464.         push    bx
  2465.         call    subenvvar_0
  2466. subenvvar_0:
  2467.         pop    bx
  2468.         push    ds
  2469. ;
  2470. ;Compute the length of the variable name.
  2471. ;
  2472.         mov    cx,255
  2473.         push    di            ;Save pointer to internal buff
  2474.         mov    di,si            ;Compute the length of the
  2475.         mov    dx,cx            ;  environment variable by
  2476.         mov    al,"%"                  ;  searching for the trailing
  2477.         repne    scasb            ;  % sign.
  2478.         sub    dx,cx            ;Compute length of variable.
  2479.         dec    dx            ;Subtract % byte from length.
  2480.         mov    cx,di
  2481.         pop    di
  2482.         push    cx            ;Save ptr to end of var
  2483.         call    subenv_srchenv        ;Search environment block.
  2484.         jc    short subenvvar_exit    ;CF set, variable not found.
  2485. ;
  2486. ;Environment variable found. Substitute into string.
  2487. ;
  2488. subenvvar_1:
  2489.         lodsb                ;Get env var character
  2490.         or    al,al            ;Check for end of string
  2491.         je    subenvvar_exit
  2492.         stosb                ;Save character in string
  2493.         dec    ah            ;Dec buffer size count.
  2494.         jne    subenvvar_1        ;If buffer not full, continue
  2495. subenvvar_exit:
  2496.         pop    si            ;Restore string pointer
  2497.         pop    ds            ;Restore segment register
  2498.         pop    bx
  2499.         ret
  2500. subenvvar    endp
  2501. subenv_end    =    $
  2502.  
  2503. ;-----------------------------------------------------------------------------
  2504. ; SEARCH_ENV scans the environment block for a string.
  2505. ; Entry:  DS:SI - pointer to ASCII string
  2506. ;         DX - length of string
  2507. ; Exit:   DS:SI - points to first character of environment string
  2508. ;         CF - clear if string found
  2509. ;-----------------------------------------------------------------------------
  2510. searchenv_off    dw    0               ;Pointer to offset in COM file
  2511. searchenv_size    dw    offset searchenv_end - offset searchenv_start
  2512. searchenv_next    dw    0               ;Ptr to next routine to append
  2513. searchenv_lnks    dw    0
  2514. searchenv_start =    $
  2515.  
  2516. search_env    proc near
  2517.         assume    ds:nothing,es:nothing
  2518.         push    bx
  2519.         push    cx
  2520.         push    di
  2521.         push    es
  2522.         mov    es,environment_seg    ;Get seg of environment blk
  2523.         xor    di,di            ;Point ES:DI to environment.
  2524.         mov    bx,si            ;Save pointer to var name
  2525. search_env_1:
  2526.         mov    si,bx            ;Get back ptr to var name.
  2527.         mov    cx,dx            ;Compare env var to var in
  2528.         repe    cmpsb            ;  string.
  2529.         je    search_env_2        ;Variable found, exit loop
  2530.         xor    al,al            ;Find next environment var.
  2531.         mov    cx,-1            ;Scan the entire segment.
  2532.         repne    scasb
  2533.         cmp    byte ptr es:[di],0    ;If double zero, end of env
  2534.         jne    search_env_1        ;  block. else, loop back.
  2535. search_env_not_found:
  2536.         mov    si,di            ;Point SI to end of env data
  2537.         push    es
  2538.         pop    ds
  2539.         stc
  2540.         jmp    short search_env_exit
  2541. search_env_2:
  2542. ;
  2543. ;Environment variable found. Point DS:SI to the string.
  2544. ;
  2545.         mov    si,di
  2546.         push    es            ;DS:SI points to env string
  2547.         pop    ds
  2548. search_env_3:
  2549.         lodsb                ;Move environment pointer past
  2550.         cmp    al,"="                  ;  the equals sign.
  2551.         jne    search_env_3
  2552.         cmp    byte ptr [si],0
  2553.         je    search_env_not_found
  2554. search_env_4:
  2555.         lodsb                ;Move pointer to first
  2556.         or    al,al            ;  non-space character.
  2557.         jb    search_env_5
  2558.         cmp    al," "
  2559.         jb    search_env_4
  2560. search_env_5:
  2561.         dec    si
  2562.         clc
  2563. search_env_exit:
  2564.         pop    es
  2565.         pop    di
  2566.         pop    cx
  2567.         pop    bx
  2568.         ret
  2569. search_env    endp
  2570. searchenv_end    =    $
  2571.  
  2572. ;----------------------------------------------------------------------------
  2573. ;EXTERNAL CMD  Routine used to launch programs from the COM file.
  2574. ; Entry   DS:SI - Pointer to the ASCIIZ program name
  2575. ;      ES:DI - Pointer to the ASCIIZ command line tail
  2576. ;----------------------------------------------------------------------------
  2577. extern_intcmd    equ    [bx-14]
  2578. extern_echomsg    equ    [bx-12]
  2579. extern_parspath equ    [bx-10]
  2580. extern_launch    equ    [bx-8]
  2581. extern_ifexits    equ    [bx-6]
  2582. extern_pathcnt    equ    [bx]
  2583. extern_path_var equ    [bx+1]
  2584. extern_file_ext equ    [bx+6]
  2585. extern_filename equ    [bx+15]
  2586. extern_filetail equ    [bx+17]
  2587. extern_lostmsg    equ    [bx+19]
  2588. extern_cmdparm    equ    [bx+45]
  2589. external_ptr    dw    0            ;Pointer to offset in COM file
  2590. external_size    dw    offset external_end - offset external_start
  2591. external_next    dw    0            ;Ptr to next routine to append
  2592. external_lnks    dw    10            ;Bytes in the dependancy header ;Number of routines called
  2593. external_start    =    $
  2594.         dw    intcmd_next        ;Call to launch COMMAND.COM
  2595.         dw    echo_msg_next        ;Call to display string
  2596.         dw    parsepath_next        ;Call to get part of path
  2597.         dw    launch_next        ;Call execute file
  2598.         dw    ifexist_next        ;Call to find file
  2599.  
  2600. external_code    proc    near
  2601.         assume    cs:code,ds:code
  2602.         push    bx
  2603.         call    external_0
  2604.         db    0            ;Cnt to track path search.
  2605.         db    "PATH="
  2606.         db    "COMEXEBAT"
  2607.         dw    0            ;Pointer to filename
  2608.         dw    0            ;Pointer to command line tail
  2609.         db    "Bad command or filename",13,10,0
  2610.         db    "/C "
  2611. external_0:
  2612.         pop    bx            ;Get pointer to local vars.
  2613.         mov    extern_filename,si    ;Save ptr to file name
  2614.         mov    extern_filetail,di    ;Save ptr to command line tail
  2615.         mov    dx,string2_buff     ;Get pointer to free buffer.
  2616.         add    dx,4            ;Make room for /C if needed.
  2617. ;Parse path to generate filename.
  2618. external_1:
  2619.         mov    di,dx            ;Get ptr to start of buffer
  2620.         xor    cx,cx            ;Check to see if we need to
  2621.         or    cl,extern_pathcnt    ;  check the directorys in
  2622.         je    external_2        ;  the path.
  2623.         mov    si,extern_filename
  2624.         call    extern_parspath
  2625.         jnc    external_2        ;If we have checked all
  2626.         lea    si,extern_lostmsg    ;  directories in the path,
  2627.         call    extern_echomsg        ;  display file not found msg.
  2628.         jmp    short external_exit
  2629.  
  2630. ;Append filename to the end of the path.
  2631. external_2:
  2632.         mov    cx,8
  2633. external_3:
  2634.         lodsb
  2635.         cmp    al,' '                  ;See if end of word
  2636.         jbe    external_4
  2637.         cmp    al,'.'                  ;See if end of filename
  2638.         je    external_4
  2639.         stosb
  2640.         loop    external_3
  2641. external_4:
  2642.         mov    al,'.'                  ;Append '.' to filename
  2643.         stosb
  2644.         lea    si,extern_file_ext    ;Get pointer to extensions
  2645.         mov    cx,3            ;3 extension types COM EXE BAT
  2646. external_5:
  2647.         movsw                ;Append extension to filename
  2648.         movsb
  2649.         xor    al,al            ;Termainate with zero
  2650.         stosb
  2651.         push    dx
  2652.         push    si
  2653.         push    cx
  2654.         mov    si,dx            ;Get ptr to start of name
  2655.         call    extern_ifexits        ;Search for file
  2656.         pop    cx
  2657.         pop    si
  2658.         pop    dx
  2659.         jnc    external_6
  2660.         sub    di,4            ;Backup to file extension
  2661.         loop    external_5
  2662.         inc    byte ptr extern_pathcnt ;Look in the next path str
  2663.         jmp    short external_1
  2664. external_6:
  2665.         cmp    cx,1            ;See if BAT extension
  2666.         jne    external_8
  2667.         lea    si,extern_cmdparm    ;Get pointer to /C
  2668.         sub    dx,4
  2669.         mov    di,dx            ;Get ptr to string buffer
  2670.         movsw                ;Copy /C param
  2671.         movsb
  2672.         xor    al,al
  2673.         mov    cx,252
  2674.         repne    scasb            ;Find end of filename
  2675.         mov    byte ptr [di-1],' '     ;Fill in zero with space
  2676.         mov    si,extern_filetail    ;Get ptr to command line tail
  2677.         cmp    [si-1],cl
  2678.         ja    external_7
  2679.         mov    cl,[si-1]        ;Get length of cmd line tail
  2680. external_7:
  2681.         rep    movsb
  2682.         mov    byte ptr [di],13    ;Append CR to cmd line.
  2683.         mov    si,dx            ;Get pointer to BAT filename
  2684.         mov    ax,di            ;Compute length of cmd line.
  2685.         sub    ax,dx
  2686.         mov    [si-1],al
  2687.         call    extern_intcmd        ;Launch COMMAND.COM
  2688.         jmp    short external_exit
  2689. external_8:
  2690.         mov    di,extern_filetail    ;Get ptr to command line tail
  2691.         dec    di            ;Back up to buffer length
  2692.         mov    si,dx            ;Get ptr to start of name
  2693.         call    extern_launch        ;Execute program
  2694. external_exit:
  2695.         pop    bx
  2696.         ret
  2697. external_code    endp
  2698. external_end    =    $
  2699.  
  2700. ;-----------------------------------------------------------------------------
  2701. ; PARSEPATH  Parses the PATH and returns a qualified directory from the path.
  2702. ; Entry:  ES:DI - pointer to destination buffer.
  2703. ;         CX - index into the path variable. (zero based.)
  2704. ; Exit:   ES:DI - pointer to ASCIIZ destination filename.
  2705. ;         CF - Set if past end of the path
  2706. ;-----------------------------------------------------------------------------
  2707. parsepath_srenv equ    [bx-6]
  2708. parsepath_off    dw    0             ;Pointer to offset in COM file
  2709. parsepath_size    dw    offset parsepath_end - offset parsepath_start
  2710. parsepath_next    dw    0             ;Ptr to next routine to append
  2711. parsepath_lnks    dw    2
  2712. parsepath_start =    $
  2713.         dw    offset searchenv_next     ;Call to search env block
  2714.  
  2715. parsepath    proc    near
  2716.         assume    cs:code,ds:code,es:code,ss:code
  2717.         push    bx
  2718.         call    parsepath_1
  2719.         db    "PATH"
  2720. parsepath_1:
  2721.         pop    bx
  2722.         push    dx
  2723.         push    si
  2724.         mov    dx,4            ;Length of PATH string
  2725.         mov    si,bx
  2726.         call    getcom_srchenv        ;PATH var ptr return in DS:SI
  2727. parsepath_2:
  2728.         dec    cx            ;Dec path segment count
  2729.         jcxz    parsepath_4
  2730. parsepath_3:
  2731.         lodsb                ;Get character
  2732.         or    al,al            ;See if end of path string
  2733.         je    parsepath_notfound
  2734.         cmp    al,';'                  ;See if end of path segment
  2735.         jne    parsepath_3
  2736.         jmp    short parsepath_2
  2737. parsepath_4:
  2738.         lodsb
  2739.         cmp    al,';'                  ;See if end of path segment
  2740.         je    parsepath_5
  2741.         or    al,al            ;See if end of path
  2742.         je    parsepath_5
  2743.         stosb
  2744.         jmp    short parsepath_4
  2745. parsepath_5:
  2746.         push    cs
  2747.         pop    ds
  2748.         cmp    byte ptr es:[di-1],'\'  ;Append \ if necessary.
  2749.         je    parsepath_6
  2750.         mov    al,'\'
  2751.         stosb
  2752. parsepath_6:
  2753.         clc
  2754. parsepath_exit:
  2755.         pop    si
  2756.         pop    dx
  2757.         pop    bx
  2758.         ret
  2759. parsepath_notfound:
  2760.         stc
  2761.         jmp    short parsepath_exit
  2762. parsepath    endp
  2763. parsepath_end      =      $
  2764.  
  2765. ;-----------------------------------------------------------------------------
  2766. ; INTCMD  Launches the shell ,usually COMMAND.COM, to run an internal command.
  2767. ; Entry   DS:SI - pointer to the ASCIIZ internal command to run.
  2768. ;-----------------------------------------------------------------------------
  2769. intcmd_launch    equ    [bx-8]
  2770. intcmd_getcom    equ    [bx-6]
  2771. intcmd_off    dw     0            ;Pointer to offset in COM file
  2772. intcmd_size    dw     offset intcmd_end - offset intcmd_start
  2773. intcmd_next    dw     0            ;Ptr to next routine to append
  2774. intcmd_lnks    dw     4
  2775. intcmd_start    =      $
  2776.         dw     offset launch_next    ;Call to load and run program.
  2777.         dw     offset getcom_next    ;Call to find shell name.
  2778.  
  2779. intcommand    proc    near
  2780.         assume    cs:code,ds:code,es:code,ss:code
  2781.         push    bx
  2782.         call    intcmd_1
  2783. intcmd_1:
  2784.         pop    bx            ;Get pointer to sub calls.
  2785.         mov    di,si            ;Copy ptr to command
  2786.         dec    di            ;Back up to cmd line size.
  2787.         push    ds
  2788.         call    intcmd_getcom        ;Get comspec string.
  2789.         call    cs:intcmd_launch    ;Run program.
  2790.         pop    ds
  2791.         pop    bx
  2792.         ret
  2793. intcommand    endp
  2794. intcmd_end    =    $
  2795.  
  2796. ;-----------------------------------------------------------------------------
  2797. ; GETCOMSPEC  Gets the name of the shell program running
  2798. ; Exit:   DS:SI - pointer to the ASCIIZ name of the shell porgram.
  2799. ;-----------------------------------------------------------------------------
  2800. getcom_srchenv    equ    [bx-6]
  2801. getcom_off    dw    0             ;Pointer to offset in COM file
  2802. getcom_size    dw    offset getcom_end - offset getcom_start
  2803. getcom_next    dw    0             ;Ptr to next routine to append
  2804. getcom_lnks    dw    2
  2805. getcom_start    =    $
  2806.         dw    offset searchenv_next     ;Call to search environment blk
  2807.  
  2808. getcomspec    proc    near
  2809.         assume    cs:code,ds:code,es:code,ss:code
  2810.         push    bx
  2811.         call    getcom_1
  2812. getcom_str    db    "COMSPEC"
  2813. getcom_1:
  2814.         pop    bx
  2815.         mov    dx,offset getcom_1 - offset getcom_str
  2816.         mov    si,bx
  2817.         call    getcom_srchenv        ;Get pointer to comspec string
  2818.         pop    bx
  2819.         ret
  2820. getcomspec    endp
  2821. getcom_end    =    $
  2822.  
  2823. ;----------------------------------------------------------------------------
  2824. ;LAUNCH PROG  Routine used to load and run programs.
  2825. ; Entry   DS:SI - pointer to the program name to run.
  2826. ;      ES:DI - pointer to the command line tail.
  2827. ; Exit      return code variable set.
  2828. ;----------------------------------------------------------------------------
  2829. launch_fcb    equ    [bx]
  2830. launch_ptr    dw    0            ;Pointer to offset in COM file
  2831. launch_size    dw    offset launch_end - offset launch_start
  2832. launch_next    dw    0            ;Ptr to next routine to append
  2833. launch_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2834. launch_start    =    $
  2835.  
  2836. launch_code    proc    near
  2837.         assume    cs:code,ss:code
  2838.         push    bx
  2839.         call    launch_1        ;Push IP on stack
  2840.         db    0            ;Dummy FCB for program
  2841.         db    "DUMMY   FCB"
  2842.         db    0,0,0,0
  2843. launch_1:
  2844.         pop    bx            ;Get pointer to local vars.
  2845.  
  2846.         push    ds
  2847.         push    es            ;Save stack ptr since it is not
  2848.         mov    com_stack_ptr,sp    ;  saved under DOS 2.x.
  2849.  
  2850.         push    cs            ;Create Parameter block on
  2851.         lea    dx,launch_fcb        ;  the stack. Start with 2nd
  2852.         push    dx            ;  FCB.
  2853.         push    cs            ;Push ptr to 1st FCB
  2854.         push    dx
  2855.         push    cs            ;Push ptr to command line tail.
  2856.         push    di
  2857.         xor    ax,ax            ;Use parent env block.
  2858.         push    ax
  2859.         mov    bx,sp            ;Copy pointer to parameter blk
  2860.  
  2861.         mov    ax,4b00h        ;DOS EXEC program.
  2862.         mov    dx,si            ;Get pointer to filename
  2863.         int    21h
  2864.         mov    bp,offset data_start_ptr - offset init_code + 100h
  2865.         mov    bp,cs:[bp]
  2866.         mov    bx,cs            ;Reload BP to access local data
  2867.         cli
  2868.         mov    ss,bx            ;Restore stack
  2869.         mov    sp,com_stack_ptr
  2870.         sti
  2871.         pop    es
  2872.         pop    ds
  2873. ;Get return code
  2874.         mov    ah,4dh            ;Get return code
  2875.         int    21h
  2876.         mov    process_rc,al        ;Save
  2877.         pop    bx
  2878.         ret
  2879. launch_code    endp
  2880. launch_end    =       $
  2881.  
  2882. ;----------------------------------------------------------------------------
  2883. ;GOTO  Routine to jump to a label pointed to by a cmd line parameter or
  2884. ;      environment variable.
  2885. ; Entry   DS:SI - pointer to label to find.
  2886. ;         DI - Wait flag/ptr. If <> 0, put goto address at pointer.
  2887. ; Exit      This routine does not return unless the label is not found.
  2888. ;----------------------------------------------------------------------------
  2889. goto_echomsg    equ    [bx-7]
  2890. goto_lblsrch    equ    [bx-5]
  2891. goto_ptr    dw    0            ;Pointer to offset in COM file
  2892. goto_size    dw    offset goto_end - offset goto_start
  2893. goto_next    dw    0            ;Ptr to next routine to append
  2894. goto_lnks    dw    4            ;Bytes in the dependancy header ;Number of routines called
  2895. goto_start    =    $
  2896.         dw    echo_msg_next        ;Used to print error msg
  2897.         dw    lblsrch_next        ;Used to find label
  2898.  
  2899. goto_code    proc    near
  2900.         assume    cs:code,ds:code
  2901.         call    goto_1
  2902.         db    8 dup (" ")
  2903.         db    " Label not found",13,10,0
  2904. goto_1:
  2905.         pop    bx
  2906.         push    di            ;Save wait flag/pointer
  2907.         mov    di,bx            ;Load label into error msg
  2908.         xor    dx,dx            ;Get size of label as it is
  2909.         mov    cx,8            ;  copied into error msg.
  2910. goto_2:
  2911.         lodsb
  2912.         cmp    al," "
  2913.         jbe    goto_4
  2914.         cmp    al,'a'
  2915.         jb    goto_3
  2916.         and    al,0dfh         ;Capitalize label
  2917.         cmp    al,'Z'
  2918.         ja    goto_4
  2919. goto_3:
  2920.         stosb
  2921.         inc    dx
  2922.         loop    goto_2
  2923. goto_4:
  2924.         mov    cx,dx            ;Get size of label
  2925.         mov    si,bx            ;Get pointer to label
  2926.         mov    di,com_label_start    ;Get ptr to start of label list
  2927.         add    di,bp            ;Add offset of data
  2928.         push    bx            ;Save ptr to msg
  2929.         call    goto_lblsrch        ;Call search routine
  2930.         pop    dx            ;Restore ptr to message
  2931.         pop    si            ;Restore Wait flag/pointer
  2932.         jc    goto_5            ;CF set, label not found.
  2933.         mov    ax,[bx+2]        ;Get destination ptr
  2934.         or    si,si            ;See if delay flag <> 0
  2935.         je    goto_41         ;If 0, no delay
  2936.         mov    [bp+si],ax        ;Save ret addr at pointer
  2937.         ret
  2938. goto_41:
  2939.         pop    ax            ;Remove return address
  2940.         push    [bx+2]            ;Push new return address
  2941. goto_exit:
  2942.         ret
  2943. goto_5:
  2944.         mov    bx,dx            ;Set addressability to call
  2945.         call    goto_echomsg        ;Print error message.
  2946.         ret
  2947. goto_code    endp
  2948. goto_end    =    $
  2949.  
  2950. ;----------------------------------------------------------------------------
  2951. ;GOTO DLY  Routine used if goto statment is inside a FOR loop.    Since a for
  2952. ;      loop cannot be exited before it ends, this routine checks to see if
  2953. ;      the GOTO statment was ever executed. If so, we now can jump.
  2954. ; Entry   DS:SI - pointer to destination pointer. 0 = no jump.
  2955. ; Exit      This routine does not return unless the ptr = 0
  2956. ;----------------------------------------------------------------------------
  2957. gotodly_ptr    dw    0            ;Pointer to offset in COM file
  2958. gotodly_size    dw    offset gotodly_end - offset gotodly_start
  2959. gotodly_next    dw    0            ;Ptr to next routine to append
  2960. gotodly_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2961. gotodly_start    =    $
  2962.  
  2963. gotodly_code    proc    near
  2964.         assume    cs:code,ds:code
  2965.         xor    ax,ax            ;Get pointer, test if zero.
  2966.         or    ax,[si]         ;If zero, return.  If not
  2967.         je    gotodly_exit        ;  push the new destination
  2968.         pop    bx            ;  on the stack and return.
  2969.         push    ax
  2970. gotodly_exit:
  2971.         ret
  2972. gotodly_code    endp
  2973. gotodly_end    =         $
  2974.  
  2975. ;----------------------------------------------------------------------------
  2976. ;LABEL SEARCH Routine to search list of labels to determine goto destination.
  2977. ; Entry   ES:DI - pointer to the first entry in the list. (Assume ES = DS)
  2978. ;      DS:SI - pointer to label to find.
  2979. ;         CX - Length of label
  2980. ; Exit         BX - pointer to matching list entry, or last entry if not found.
  2981. ;         CF - Set if label not found.
  2982. ;----------------------------------------------------------------------------
  2983. lblsrch_ptr    dw    0            ;Pointer to offset in COM file
  2984. lblsrch_size    dw    offset lblsrch_end - offset lblsrch_start
  2985. lblsrch_next    dw    0            ;Ptr to next routine to append
  2986. lblsrch_lnks    dw    0            ;Bytes in the dependancy header ;Number of routines called
  2987. lblsrch_start    =    $
  2988.  
  2989. lblsrch_code    proc    near
  2990.         assume    cs:code,ds:code
  2991.         push    si
  2992.         mov    dx,si            ;Save ptr to label
  2993.         mov    ax,cx            ;Save label length
  2994.         mov    bx,di            ;Get ptr to list
  2995. lblsrch_1:
  2996.         mov    di,bx
  2997.         add    di,4            ;Move to label string
  2998.         mov    si,dx            ;Get ptr to new label
  2999.         mov    cx,ax            ;Get length of label
  3000.         cmp    [di],cl         ;Compare lengths of the labels
  3001.         jne    lblsrch_2
  3002.         inc    di            ;Skip past length byte
  3003.         repe    cmpsb            ;Compare labels.
  3004.         je    lblsrch_4
  3005. lblsrch_2:
  3006.         cmp    word ptr [bx],-1    ;See if at end of list
  3007.         je    lblsrch_3
  3008.         add    bx,[bx]         ;Point to next label
  3009.         jmp    short lblsrch_1
  3010. lblsrch_3:
  3011.         stc                ;No label found.
  3012.         jmp    short lblsrch_exit
  3013. lblsrch_4:
  3014.         clc                ;Label found
  3015. lblsrch_exit:
  3016.         pop    si
  3017.         ret
  3018. lblsrch_code    endp
  3019. lblsrch_end    =    $
  3020.  
  3021. ;-----------------------------------------------------------------------------
  3022. ; IFEQUAL  Compares two strings.
  3023. ; Entry:  DS:SI - Pointer to first ASCIIZ String
  3024. ;      ES:DI - Pointer to second ASCIIZ String
  3025. ;         CX - Length of strings.
  3026. ; Exit:      CF - Clear if equal
  3027. ;-----------------------------------------------------------------------------
  3028. ifequal_off    dw     0            ;Pointer to offset in COM file
  3029. ifequal_size    dw     offset ifequal_end - offset ifequal_start
  3030. ifequal_next    dw     0            ;Ptr to next routine to append
  3031. ifequal_lnks    dw     0
  3032. ifequal_start    =      $
  3033.  
  3034. ifequal     proc    near
  3035.         assume    cs:code,ds:code,es:code,ss:code
  3036.         xor    cx,cx
  3037.         mov    cl,[si-1]        ;Get size of string
  3038.         cmp    cl,[di-1]        ;Compare sizes of strings
  3039.         jne    ifequal_notequal
  3040.         rep    cmpsb            ;Compare strings
  3041.         jne    ifequal_notequal
  3042.         clc
  3043.         ret
  3044. ifequal_notequal:
  3045.         stc
  3046.         ret
  3047. ifequal     endp
  3048. ifequal_end    =    $
  3049.  
  3050. ;-----------------------------------------------------------------------------
  3051. ; IFEXIST  Determines if a file exists.
  3052. ; Entry:  DS:SI - Pointer to ASCIIZ filename.
  3053. ;         DI - Pointer to buffer for disk transfer area.
  3054. ; Exit:      CF - Clear if file exists
  3055. ;         DI - IF file exists, points to filename.
  3056. ;-----------------------------------------------------------------------------
  3057. ifexist_off    dw     0            ;Pointer to offset in COM file
  3058. ifexist_size    dw     offset ifexist_end - offset ifexist_start
  3059. ifexist_next    dw     0            ;Ptr to next routine to append
  3060. ifexist_lnks    dw     0
  3061. ifexist_start    =      $
  3062.  
  3063. ifexist     proc    near
  3064.         assume    cs:code,ds:code,es:code,ss:code
  3065.         mov    dx,di
  3066.         mov    ah,1ah            ;Set DTA
  3067.         int    21h
  3068.  
  3069.         mov    dx,si            ;Copy pointer to filename
  3070.         xor    cx,cx            ;Normal attributes
  3071.         mov    ah,4eh            ;DOS Find First
  3072.         int    21h
  3073.         jc    ifexist_exit
  3074.         add    di,1eh            ;Point DI to filename in DTA
  3075.         clc
  3076. ifexist_exit:
  3077.         ret
  3078. ifexist     endp
  3079. ifexist_end    =    $
  3080.  
  3081. ;-----------------------------------------------------------------------------
  3082. ; IFERRLEV  Compares the value passed with the return code of the last
  3083. ;        program executed.
  3084. ; Entry:     SI - Pointer to ASCIIZ Error level.
  3085. ; Exit:      CF - Clear if process error level above or equal to SI
  3086. ;-----------------------------------------------------------------------------
  3087. iferrlev_off    dw     0            ;Pointer to offset in COM file
  3088. iferrlev_size    dw     offset iferrlev_end - offset iferrlev_start
  3089. iferrlev_next    dw     0            ;Ptr to next routine to append
  3090. iferrlev_lnks    dw     0
  3091. iferrlev_start    =      $
  3092.  
  3093. iferrlev    proc    near
  3094.         assume    cs:code,ds:code,es:code,ss:code
  3095.         xor    ax,ax            ;Convert ASCIIZ number into
  3096.         mov    bx,ax            ;  decimal
  3097. iferrlev_1:
  3098.         mov    bl,[si]         ;Convert error level number
  3099.         sub    bl,'0'                  ;  from ASCII to decimal.
  3100.         jb    iferrlev_2
  3101.         cmp    bl,9
  3102.         ja    iferrlev_2
  3103.         mov    dx,10
  3104.         mul    dx
  3105.         jc    iferrlev_2
  3106.         add    ax,bx            ;Add in digit
  3107.         inc    si
  3108.         jmp    short iferrlev_1
  3109. iferrlev_2:
  3110.         cmp    process_rc,al        ;Compare to last program
  3111.         ret
  3112. iferrlev    endp
  3113. iferrlev_end    =    $
  3114.  
  3115. ;-----------------------------------------------------------------------------
  3116. ; FORLOOP  Processes commands in a FOR loop.
  3117. ; Entry:     SI - Pointer to ASCIIZ set of parameters.
  3118. ;         DI - Pointer loop structure in data area
  3119. ;          LoopCnt    db     0    Member of the set to use
  3120. ;          FirstFlag    db     0    Indicates Find first/next
  3121. ; Exit:      CF - Set if FOR loop complete.
  3122. ;-----------------------------------------------------------------------------
  3123. forloop_getmem    equ    [bx-6]
  3124. forloop_off    dw    0            ;Pointer to offset in COM file
  3125. forloop_size    dw    offset forloop_end - offset forloop_start
  3126. forloop_next    dw    0            ;Ptr to next routine to append
  3127. forloop_lnks    dw    2
  3128. forloop_start    =    $
  3129.         dw    getmember_next
  3130.  
  3131. forloop     proc    near
  3132.         assume    cs:code,ds:code,es:code,ss:code
  3133.         push    bx
  3134.         call    forloop_0
  3135.         db    43 dup (0)        ;Used for DTA
  3136. forloop_0:
  3137.         pop    bx
  3138. ;
  3139. ;Set DTA. If 2nd time or later time looping on a member, use find next to
  3140. ;determine the string for this time through the loop.
  3141. ;
  3142.         lea    dx,[bx]
  3143.         mov    ah,1ah            ;Set DTA
  3144.         int    21h
  3145.  
  3146.         cmp    byte ptr [di+1],0    ;See if first time for member
  3147.         je    forloop_1
  3148.         mov    ah,4fh            ;Find next file
  3149.         int    21h
  3150.         jc    forloop_1        ;Not found, go to next member
  3151.         lea    dx,[bx+1eh]        ;Point to filename in DTA
  3152.         jmp    short forloop_notdone    ;Execute loop body
  3153. ;
  3154. ;First time with this member of the set, if wildcards are in the member,
  3155. ;use DOS find first to get the loop string.
  3156. ;
  3157. forloop_1:
  3158.         mov    byte ptr [di+1],0    ;Clear first/next flag
  3159.         inc    byte ptr [di]        ;Look at next member of the set
  3160.         mov    dh,[di]         ;Get loop count
  3161.         call    forloop_getmem        ;Get member of set.  If no
  3162.         jc    forloop_done        ;  more members, loop done.
  3163.         mov    dx,si            ;Save pointer to member
  3164.         xor    ah,ah            ;Clear wildcard flag
  3165. forloop_2:
  3166.         lodsb                ;Scan set member to check for
  3167.         cmp    al,' '                  ;  any wildcard chars.
  3168.         jbe    forloop_4
  3169.         cmp    al,'?'
  3170.         jne    forloop_3
  3171.         inc    ah            ;Set wildcard found flag
  3172. forloop_3:
  3173.         cmp    al,'*'
  3174.         jne    forloop_2
  3175.         inc    ah            ;Set wildcard found flag
  3176.         jmp    short forloop_2
  3177. forloop_4:
  3178.         mov    byte ptr [si-1],0    ;Set zero terminator.
  3179.         or    ah,ah            ;If no wildcards, execute
  3180.         je    forloop_notdone     ;Execute loop body
  3181.         mov    byte ptr [di+1],1    ;Set first/next flag
  3182.         xor    cx,cx            ;Normal attributes
  3183.         mov    ah,4eh            ;DOS find first
  3184.         int    21h
  3185.         jc    forloop_1        ;If not found, get next member
  3186.         lea    dx,[bx+1eh]        ;Set ptr to filename in DTA
  3187. forloop_notdone:
  3188.         mov    forloop_ptr,dx        ;Set loop data ptr
  3189.         clc
  3190. forloop_exit:
  3191.         pop    bx
  3192.         ret
  3193. forloop_done:
  3194.         mov    word ptr [di],0     ;Clear loop variables
  3195.         stc
  3196.         jmp    short forloop_exit
  3197. forloop     endp
  3198. forloop_end    =    $
  3199.  
  3200. ;-----------------------------------------------------------------------------
  3201. ; FINDENV  Finds the master environment block.
  3202. ; Exit:    Variable Environment_seg set with segment of master environment.
  3203. ;-----------------------------------------------------------------------------
  3204. findenv_dosver    equ    [bx+7]
  3205. findenv_cmdname equ    [bx]
  3206. findenv_off    dw    0             ;Pointer to offset in COM file
  3207. findenv_size    dw    offset findenv_end - offset findenv_start
  3208. findenv_next    dw    0             ;Ptr to next routine to append
  3209. findenv_lnks    dw    0
  3210. findenv_start    =    $
  3211.  
  3212. findenv     proc    near
  3213.         assume    cs:code,ds:code,es:code,ss:code
  3214.         push    bx
  3215.         call    findenv_0
  3216.  
  3217.         db    "COMMAND"
  3218.         dw    0
  3219. findenv_0:
  3220.         pop    bx
  3221.         push    es
  3222.  
  3223.         mov    ax,ds:[2ch]        ;Get default env
  3224.         cmp    environment_seg,ax    ;Check to see if already
  3225.         jne    findenv_8        ;  found.
  3226.  
  3227.         mov    ah,30h            ;Get dos Version
  3228.         int    21h
  3229.         xchg    al,ah
  3230.         mov    findenv_dosver,ax
  3231.  
  3232.         mov    ah,52h            ;get address of first MCB
  3233.         int    21h
  3234.         mov    ax,es:[bx-2]        ;point ES to MCB
  3235.         mov    cx,20            ;Allow only 20 loops.
  3236. findenv_1:
  3237.         mov    es,ax
  3238.         cmp    byte ptr es:[0],"M"     ;check for mcb signature
  3239.         jne    short findenv_8
  3240.         inc    ax            ;point AX to memory block
  3241.         cmp    ax,es:[1]        ;See if this is a PSP block
  3242.         je    findenv_4
  3243. findenv_2:
  3244.         add    ax,es:[3]        ;Get size of memory block
  3245.         loop    findenv_1
  3246.         jmp    short findenv_8
  3247. findenv_4:
  3248.         cmp    word ptr findenv_dosver,0a00h ;If OS/2, use DOS 3.3 method.
  3249.         jae    findenv_5
  3250.         cmp    word ptr findenv_dosver,0400h;If DOS 4.00 or greater,
  3251.         jb    findenv_5          ;  COMMAND.COM may not be the
  3252.         push    ds              ;  first program loaded.  Look
  3253.         lea    si,findenv_cmdname      ;  at the name of the program
  3254.         mov    di,8              ;  stored in the last 8 bytes
  3255.         mov    cx,7              ;  of the memory control
  3256.         repe    cmpsb              ;  block.  If the string
  3257.         pop    ds              ;  "COMMAND" isn't found,
  3258.         jne    findenv_2          ;  keep looking.
  3259. findenv_5:
  3260.         mov    es,ax
  3261.         mov    bx,es:[2ch]        ;Get seg of prog environment
  3262.         mov    ax,bx
  3263.         dec    bx
  3264.         mov    es,bx
  3265.         cmp    byte ptr es:[0],"M"     ;See if valid memory block
  3266.         je    findenv_7
  3267.         mov    dx,ax            ;Save COMMAND PSP segment
  3268.         dec    ax            ;Point back to mcb
  3269.         mov    es,ax
  3270. findenv_6:
  3271.         add    ax,es:[3]        ;Get size of memory block
  3272.         inc    ax
  3273.         cmp    es:[1],dx        ;See if owned by CMD.COM
  3274.         je    findenv_7
  3275.         mov    es,ax
  3276.         loop    findenv_6
  3277. findenv_7:
  3278.         mov    environment_seg,ax
  3279. findenv_8:
  3280.         pop    es
  3281.         pop    bx
  3282.         ret
  3283. findenv     endp
  3284. findenv_end    =    $
  3285.  
  3286. ;-----------------------------------------------------------------------------
  3287. ; SET_ENV  Sets/resets environment variables.
  3288. ; Entry:  DS:SI - pointer to ASCII string containing the environment variable
  3289. ;          and, optionally, the string to assign.
  3290. ;-----------------------------------------------------------------------------
  3291. setenv_findenv    equ    [bx-10]
  3292. setenv_echo    equ    [bx-8]
  3293. setenv_serchenv equ    [bx-6]
  3294. setenv_fullmsg    equ    [bx]
  3295. setenv_off    dw    0            ;Pointer to offset in COM file
  3296. setenv_size    dw    offset setenv_end - offset setenv_start
  3297. setenv_next    dw    0            ;Ptr to next routine to append
  3298. setenv_lnks    dw    6
  3299. setenv_start    =    $
  3300.         dw    offset findenv_next    ;Call to find the master env
  3301.         dw    offset echo_msg_next    ;Call to print line.
  3302.         dw    offset searchenv_next    ;Call to search environment blk
  3303.  
  3304. set_env     proc near
  3305.         assume    ds:nothing,es:nothing
  3306.         push    bx
  3307.         call    setenv_1
  3308.         db    "Out of environment space",13,10,0
  3309. setenv_1:
  3310.         pop    bx            ;Set up local addressing
  3311.         call    setenv_findenv        ;Find master env block
  3312.         push    bp
  3313.         push    es
  3314.         mov    cx,255
  3315.         xor    dx,dx
  3316.         push    si            ;Save ptr to new env var
  3317.         mov    di,si
  3318. setenv_2:
  3319.         lodsb
  3320.         cmp    al,"="                  ;Scan until end of variable
  3321.         je    setenv_4        ;  found.
  3322.         cmp    al,'a'
  3323.         jb    setenv_3
  3324.         and    al,0dfh         ;Capitalize variable
  3325.         cmp    al,'Z'
  3326.         ja    setenv_4
  3327. setenv_3:
  3328.         stosb
  3329.         inc    dx
  3330.         loop    setenv_2
  3331. setenv_4:
  3332.         pop    si
  3333.         mov    ax,si
  3334.         inc    di
  3335.         cmp    byte ptr cs:[di]," "    ;If nothing past '=' then
  3336.         jae    setenv_41        ;  simply erase var from env.
  3337.         xor    ax,ax
  3338. setenv_41:
  3339.         push    ax
  3340.         call    setenv_serchenv     ;Get pointer to variable
  3341.         pop    dx            ;Save ptr to var
  3342.         push    ds
  3343.         pop    es
  3344.         mov    di,si            ;Copy pointer to variable
  3345.         jc    setenv_61
  3346.  
  3347.         xor    al,al            ;Scan backwards to find start
  3348.         std                ;  of var name
  3349.         mov    cx,256
  3350.         repne    scasb
  3351.         inc    di
  3352.         inc    di
  3353.         push    di
  3354.         cld                ;Scan forward to find end of
  3355.         mov    cx,256            ;  variable.
  3356.         repne    scasb
  3357.         mov    si,di
  3358.         pop    di
  3359.         xor    ah,ah
  3360. setenv_5:
  3361.         lodsb                ;Move byte from past var to
  3362.         stosb                ;  cover up current assignment
  3363.         or    ah,al            ;If two zeros in a row then
  3364.         je    setenv_6        ;  end of env vars.
  3365.         mov    ah,al
  3366.         jmp    short setenv_5
  3367. setenv_6:
  3368.         dec    di            ;Back up before last zero
  3369. setenv_61:
  3370.         push    cs
  3371.         pop    ds
  3372.         mov    si,dx            ;Get back ptr to env var
  3373.         or    si,si            ;See if var assignment
  3374.         je    setenv_9
  3375.  
  3376.         push    es            ;Get size of the environment
  3377.         mov    ax,es            ;  block by reading the size
  3378.         dec    ax            ;  in the memory control block.
  3379.         mov    es,ax
  3380.         mov    bp,es:[3]
  3381.         mov    cl,4
  3382.         shl    bp,cl            ;Convert to bytes.
  3383.         dec    bp
  3384.         dec    bp
  3385.         pop    es
  3386. setenv_7:
  3387.         lodsb                ;Copy new env var
  3388.         stosb
  3389.         or    al,al            ;Check for end of variable.
  3390.         je    setenv_8
  3391.         cmp    di,bp            ;Check for end of env block.
  3392.         jb    setenv_7
  3393.         push    cs
  3394.         pop    ds
  3395.         lea    si,setenv_fullmsg    ;If environment block full,
  3396.         call    setenv_echo        ;  print message.
  3397.         xor    al,al            ;Terminate with zeros.
  3398.         stosb
  3399. setenv_8:
  3400.         xor    al,al
  3401.         stosb
  3402. setenv_9:
  3403.         pop    es
  3404.         pop    bp
  3405.         pop    bx
  3406.         ret
  3407. set_env     endp
  3408. setenv_end    =    $
  3409.  
  3410. ;-----------------------------------------------------------------------------
  3411. ; REDIROO  Opens a file for output redirection.
  3412. ; Entry:  DS:SI - pointer to ASCII filename to open.
  3413. ;         DI - 0  open new file, 1 append to existing file.
  3414. ;-----------------------------------------------------------------------------
  3415. rediroo_off    dw    0            ;Pointer to offset in COM file
  3416. rediroo_size    dw    offset rediroo_end - offset rediroo_start
  3417. rediroo_next    dw    0            ;Ptr to next routine to append
  3418. rediroo_lnks    dw    0
  3419. rediroo_start    =    $
  3420.  
  3421. rediroo     proc near
  3422.         assume    ds:nothing,es:nothing
  3423.  
  3424.         mov    word ptr stdout_hdl,-1    ;Clear handle
  3425.         mov    dx,si            ;Get ptr to outfile file
  3426.         xor    cx,cx            ;Normal attributes
  3427.         mov    ax,3c02h        ;Create file
  3428.         or    di,di            ;See if append or new file
  3429.         je    rediroo_2
  3430.         inc    ah            ;Open file
  3431. rediroo_2:
  3432.         int    21h
  3433.         jc    rediroo_exit
  3434.         mov    bx,ax            ;Copy file handle
  3435.         or    di,di
  3436.         je    rediroo_3
  3437.         mov    ax,4202h        ;Move file ptr to end of file
  3438.         xor    dx,dx
  3439.         mov    cx,dx
  3440.         int    21h
  3441.         jc    rediroo_exit
  3442. rediroo_3:
  3443.         mov    outfile_hdl,bx        ;Save output file handle
  3444.         push    bx
  3445.         mov    ah,45h            ;Duplicate output handle
  3446.         mov    bx,1            ;Std output handle
  3447.         int    21h
  3448.         mov    stdout_hdl,ax        ;Save dup std output handle
  3449.  
  3450.         mov    cx,1
  3451.         pop    bx
  3452.         mov    ah,46h            ;Force dup file handle
  3453.         int    21h
  3454. rediroo_exit:
  3455.         ret
  3456. rediroo     endp
  3457. rediroo_end    =    $
  3458.  
  3459. ;-----------------------------------------------------------------------------
  3460. ; REDIRCO  Closes a file used for output redirection.
  3461. ;-----------------------------------------------------------------------------
  3462. redirco_off    dw    0            ;Pointer to offset in COM file
  3463. redirco_size    dw    offset redirco_end - offset redirco_start
  3464. redirco_next    dw    0            ;Ptr to next routine to append
  3465. redirco_lnks    dw    0
  3466. redirco_start    =    $
  3467.  
  3468. redirco     proc near
  3469.         assume    ds:nothing,es:nothing
  3470.         cmp    word ptr stdout_hdl,-1    ;If error on redirect, skip
  3471.         je    redirco_exit        ;  restore.
  3472.  
  3473.         mov    ah,46h            ;Force restore of std out
  3474.         mov    bx,stdout_hdl
  3475.         mov    cx,1
  3476.         int    21h
  3477.  
  3478.         mov    ah,3eh            ;Close file
  3479.         mov    bx,outfile_hdl        ;Get output file handle
  3480.         int    21h
  3481. redirco_exit:
  3482.         ret
  3483. redirco     endp
  3484. redirco_end    =    $
  3485.  
  3486. ;-----------------------------------------------------------------------------
  3487. ; REDIROI  Opens a file for input redirection.
  3488. ; Entry:  DS:SI - pointer to ASCII filename to open.
  3489. ;         DI - 0  open new file, 1 append to existing file.
  3490. ;-----------------------------------------------------------------------------
  3491. rediroi_off    dw    0            ;Pointer to offset in COM file
  3492. rediroi_size    dw    offset rediroi_end - offset rediroi_start
  3493. rediroi_next    dw    0            ;Ptr to next routine to append
  3494. rediroi_lnks    dw    0
  3495. rediroi_start    =    $
  3496.  
  3497. rediroi     proc near
  3498.         assume    ds:nothing,es:nothing
  3499.  
  3500.         mov    word ptr stdin_hdl,-1    ;Clear handle
  3501.         mov    dx,si            ;Get ptr to outfile file
  3502.         mov    ax,3d00h        ;Open file, Read only
  3503.         int    21h
  3504.         jc    rediroi_exit
  3505.         mov    infile_hdl,ax        ;Save input file handle
  3506.         push    ax
  3507.  
  3508.         mov    ah,45h            ;Duplicate input handle
  3509.         xor    bx,bx
  3510.         int    21h
  3511.         mov    stdin_hdl,ax        ;Save dup std input handle
  3512.  
  3513.         xor    cx,cx
  3514.         pop    bx
  3515.         mov    ah,46h            ;Force dup file handle
  3516.         int    21h
  3517. rediroi_exit:
  3518.         ret
  3519. rediroi     endp
  3520. rediroi_end    =    $
  3521.  
  3522. ;-----------------------------------------------------------------------------
  3523. ; REDIRCI  Closes a file used for input redirection.
  3524. ;-----------------------------------------------------------------------------
  3525. redirci_off    dw    0            ;Pointer to offset in COM file
  3526. redirci_size    dw    offset redirci_end - offset redirci_start
  3527. redirci_next    dw    0            ;Ptr to next routine to append
  3528. redirci_lnks    dw    0
  3529. redirci_start    =    $
  3530.  
  3531. redirci     proc near
  3532.         assume    ds:nothing,es:nothing
  3533.         cmp    word ptr stdin_hdl,-1    ;If error on redirect, skip
  3534.         je    redirci_exit        ;  restore.
  3535.  
  3536.         mov    ah,46h            ;Force restore of std in hdl
  3537.         mov    cx,cx
  3538.         xor    bx,stdin_hdl
  3539.         int    21h
  3540.  
  3541.         mov    ah,3eh            ;Close file
  3542.         mov    bx,infile_hdl        ;Get input file handle
  3543.         int    21h
  3544. redirci_exit:
  3545.         ret
  3546. redirci     endp
  3547. redirci_end    =    $
  3548.  
  3549. ;-----------------------------------------------------------------------------
  3550. ; REDIRDEL Deletes piping file.
  3551. ; Entry:  DS:SI - pointer to ASCII filename to delete.
  3552. ;-----------------------------------------------------------------------------
  3553. redirdel_off    dw    0            ;Pointer to offset in COM file
  3554. redirdel_size    dw    offset redirdel_end - offset redirdel_start
  3555. redirdel_next    dw    0            ;Ptr to next routine to append
  3556. redirdel_lnks    dw    0
  3557. redirdel_start    =    $
  3558.  
  3559. redirdel    proc near
  3560.         assume    ds:nothing,es:nothing
  3561.  
  3562.         mov    dx,si            ;Copy pointer to filename
  3563.         mov    ah,41h            ;Delete file
  3564.         int    21h
  3565.         ret
  3566. redirdel    endp
  3567. redirdel_end    =    $
  3568.  
  3569. initialize    endp
  3570.         even                ;compiler stack on word boundry
  3571. end_of_code    =    $
  3572. code        ends
  3573.  
  3574. end        main
  3575.