home *** CD-ROM | disk | FTP | other *** search
- ; CMDMACRO.ASM
- ; (c) 1989, 1990 Ashok P. Nadkarni
- ;
- ; Module implementing macro and symbol feature for CMDEDIT.
- ;
- ; Symbols :
- ; CMDEDIT symbols can be defined either from the command line or read
- ; from a file during initialization. The syntax is given by
- ; defs symbolname expansion
- ; When the defined symbol appears as the first word in the line, it is
- ; replaced by its expansion. The rest of the line is unchanged. The
- ; following line defines a symbol called 'ed' that runs my editor.
- ;
- ; defs ed c:\util\editor
- ;
- ; Now if you type
- ;
- ; ed newfile
- ;
- ; the command
- ;
- ; c:\util\editor newfile
- ;
- ; will be executed.
- ;
- ; Symbols are expanded recursively.
- ;
- ; Macros :
- ;
- ; CMDEDIT macros can be defined either from the command line or read
- ; from a macro file when CMDEDIT is installed. In both cases, macros
- ; are defined using the same syntax. Macros may expand into multiple
- ; lines. In the latter case, each line of the expansion in passed to
- ; the calling application one at a time.
- ;
- ; Macros are defined using the CMDEDIT command 'defm' followed by the
- ; macro name. The macro name is separated from the 'defm' keyword by one
- ; or more spaces/tabs. Any characters after the name of the macro are ignored.
- ; Each line of the macro expansion is defined on a separate line. The
- ; expansion may contain any number of lines (limited by buffer space)
- ; and is terminated by a line that begins with the keyword 'endm'. For
- ; example, the following lines define a macro that will change the
- ; current directory from any disk:
- ; defm gotc
- ; c:
- ; cd \TURBOC
- ; endm
- ; Macro keywords are case-insensitive.
- ;
- ; Macro Parameters:
- ; Similar to batch files, macros can be passed parameters. (Read
- ; your DOS manual to find out about parameters). Although the
- ; concept is similar to DOS batch files, CMDEDIT parameters behave a
- ; little differently. Upto 9 parameters can be defined. These are
- ; indicated in macro definitions as '%n' where n is a digit from 1 to 9.
- ; A parameter can appear anywhere in the definition and need
- ; not be surrounded by whitespace. Also, the character % itself can be
- ; placed anywhere in the definition as long as it is not followed by a
- ; digit. If you do want a '%n' sequence in the expansion, indicate the '%'
- ; character as '%%'.
- ; For example, consider
- ; defm bf
- ; copy %1 a:\%1\%%1
- ; endm
- ; Then, when you type
- ; "bf myfile"
- ; the macro will expand to
- ; "copy myfile a:\myfile\%1"
- ; Note how %1 has been replaced by 'myfile' in two places but not the third.
- ;
- ; A macro cannot call another macro except if the call is the last
- ; line in the macro. Macros anywhere else are not expanded and the line
- ; is passed to the calling application without modification.
- ;
- ; Note that the macro name can be null as well. In this case, hitting
- ; carraige return on an blank line will result in that macro being run.
-
- INCLUDE common.inc
- INCLUDE general.inc
- INCLUDE ascii.inc
- INCLUDE dos.inc
-
- PUBLIC macro_init
- PUBLIC symbol_init
- PUBLIC execute_defm
- PUBLIC execute_defs
- PUBLIC execute_delm
- PUBLIC execute_dels
- PUBLIC execute_rstsym
- PUBLIC execute_rstmac
- PUBLIC execute_cmdstat
- PUBLIC get_macro_line
- PUBLIC expand_macro
- PUBLIC expand_symbol
- PUBLIC expand_var
- PUBLIC get_symbol
- PUBLIC mac_stk
- PUBLIC sym_stk
- PUBLIC ismacsym
-
- PLACEHOLDER equ PERCENT ;Placeholder character
-
- INCLUDE buffers.inc
-
- CSEG SEGMENT PARA PUBLIC 'CODE'
- DGROUP GROUP CSEG
-
- EXTRN endm_cmd:BYTE
- EXTRN defm:BYTE
- EXTRN defs:BYTE
- EXTRN get_kbd_line:ABS
- EXTRN source:WORD
- EXTRN macro_level:WORD
- EXTRN macro_ignore_char:BYTE
- EXTRN lastchar:WORD
- EXTRN linebuf:BYTE
- EXTRN dot:WORD
- EXTRN LINEBUF_END:ABS
- EXTRN cur_macro:BYTE
- EXTRN cur_macro_len:WORD
-
- mac_stk $string_stack <> ;Descriptor for macro buffer
- sym_stk $string_stack <> ;Descriptor for sym buffer
- separator db 13 ;Separator string between macros
- sep_len equ $-separator ;Length of separator string
- macro_noroom_msg db 'Table full. Definition ignored.',CR,LF,DOLLAR
- macro_prompt db CR,LF,'DEFM>',DOLLAR
-
-
- EXTRN push_word:PROC
- EXTRN push_string:PROC
- EXTRN get_next_line:PROC
- EXTRN reset_line:PROC
- EXTRN abort_processing:PROC
- EXTRN getargs:PROC
- EXTRN stre_cmp:PROC
- EXTRN set_disp_marks:PROC
- EXTRN isspace:PROC
- EXTRN isdelim:PROC
- EXTRN skip_whitespace:PROC
- EXTRN skip_nonwhite:PROC
- EXTRN skip_nondelim:PROC
- EXTRN makeroom:PROC
- EXTRN remove_chars:PROC
- EXTRN insert_chars:PROC
- EXTRN output_counted_string:PROC
- EXTRN output_newline:PROC
- EXTRN locate_dosenv:PROC
-
- ASSUME CS:DGROUP,DS:DGROUP,ES:DGROUP,SS:DGROUP
-
-
- ;+
- ; FUNCTION : macro_init,symbol_init
- ;
- ; Initializes the various data structures associated with the
- ; macro /symbol buffer. CALLER MUST ENSURE PASSED ADDRESSES ARE VALID
- ; AND BUFFER IS LARGE ENOUGH.
- ;
- ; Parameters:
- ; AX - length of buffer in bytes
- ; BX - address of buffer
- ;
- ; Returns:
- ; Nothing.
- ; Registers destroyed :
- ; BX
- ;-
- macro_init proc near
- push bx
- mov bx,offset DGROUP:mac_stk ;bx := address of buffer descriptors
- jmp short @macsym_init
- symbol_init LABEL near
- push bx
- mov bx,offset DGROUP:sym_stk ;bx := address of buffer descriptors
- @macsym_init:
- xchg ax,cx ;CX = buffer size
- pop ax ;AX = Buffer address
- ;BX points to appropriate descriptor
- call near ptr strstk_init ;Initialize buffer and descriptor
-
- ;Store a separator into the macro buffer
- call near ptr separate
-
- ret
- macro_init endp
-
-
-
-
-
- ;+
- ; FUNCTION : execute_rstmac, execute_rstsym
- ;
- ; Resets the various data structures associated with the
- ; macro /symbol buffer.
- ;
- ; Parameters:
- ; None.
- ;
- ; Returns:
- ; Nothing.
- ;
- ; Registers destroyed :
- ; AX,CX,BX,DX
- ;-
- rst_macsym proc near
- execute_rstmac LABEL near
- ; mov macro_level,0
- mov bx,offset DGROUP:mac_stk ;bx := address of buffer descriptors
- jmp short @rst_macsym
- execute_rstsym LABEL near
- mov bx,offset DGROUP:sym_stk ;bx := address of buffer descriptors
- @rst_macsym:
- call near ptr strstk_reset ;Re-initialize buffer and descriptor
-
- ;Store a separator into the macro buffer
- call near ptr separate
- ret
- rst_macsym endp
-
-
-
-
- ;+
- ; FUNCTION : ismacsym
- ;
- ; Called to check if the passed string is a valid symbol or macro
- ; name. If found, the symbol/macro string stack pointer is set to the
- ; first line of the expansion of the symbol/macro.
- ;
- ; Parameters:
- ; AX - length of symbol name to be checked
- ; BX - address of the string stack descriptor (symbol or macro)
- ; SI - pointer to the symbol to be checked.
- ;
- ; Returns:
- ; CF - 1 if symbol not found, the string stack current pointer
- ; is undefined
- ; 0 if symbol found. The string stack pointer points to the
- ; first line of the expansion of the found symbol/macro.
- ; Register(s) destroyed:
- ; AX,CX,DX
- ;-
- ismacsym proc near
- @save si,di
-
- mov di,ax ;DI<-length of symbol
- call near ptr strstk_settop ;Reset macro stack pointer
-
- @ismacsym_20:
- ; Loop start, DI = num chars in word, SI->start of word
-
- mov ax,si ;AX->word
- mov cx,di ;CX<-length of word
- call near ptr strstk_bck_find ;Look backward for string
- ; Params AX,BX,CX
- ; BX unchanged
- jc @ismacsym_98 ;Not found so return with CF set
- ; The name matched. Now make sure it is a macro name by ensuring
- ; previous string is a separator.
- xor cx,cx ;cx<-length of pattern
- call near ptr strstk_bck_match ;Set current to previous string
- ; BX unchanged
- jc @ismacsym_98 ;start of buffer so return
- ; with CF set
- push bx
- call near ptr check_separator
- pop bx
- je @ismacsym_50 ;This is the one
- ; Wasn't a separator. Move back over it to start the hunt again.
- xor cx,cx
- call near ptr strstk_fwd_match
- jmp short @ismacsym_20
-
- @ismacsym_50:
- ; The macro/symbol has been found.
- xor cx,cx ;CX<-match length
- call near ptr strstk_fwd_match ;Skip over separator
- xor cx,cx ;CX<-match length
- call near ptr strstk_fwd_match ;Skip over macro/symbol name
- clc ;Clear return flag
- @ismacsym_98:
- @restore
- ret
- ismacsym endp
-
-
-
- ;+
- ; FUNCTION : execute_dels, execute_delm
- ;
- ; execute_dels and execute_delm respectively delete symbols and
- ; macros from the appropriate stack. All symbols/macros listed on the
- ; line are deleted. If a particular symbol/macro is not defined, no
- ; error is generated.
- ;
- ; Parameters:
- ; SI -> first char in linebuf following this command
- ; CX == remaining num chars in the line
- ;
- ; Returns:
- ; Nothing.
- ;
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- del_macsym proc near
- execute_dels LABEL near
- mov bx,offset DGROUP:sym_stk
- jmp short @del_macsym_5
- execute_delm LABEL near
- cmp macro_level,1
- jne @execute_delm_1
- mov ax,E_NESTED_DELM
- jmp near ptr abort_processing
- @execute_delm_1:
- mov bx,offset DGROUP:mac_stk
- @del_macsym_5:
- @save si,di
- push bp
- mov bp,sp
- sub sp,2
- num_remain equ <word ptr [bp-2]>
- ;
- @del_macsym_10:
- ; At this point, SI->remaining chars in line, CX is number of chars
- jcxz @del_macsym_99 ;No more chars in line
- ; Find first word
- push bx ;Save buffer descriptor addr
- call near ptr skip_whitespace ;SI->first non blank
- mov di,si ;DI->start of word
- call near ptr skip_nondelim ;SI->char after word
- mov ax,si ;
- xchg si,di ;SI->word, DI->rest of line
- sub ax,si ;AX<-num chars in word
- pop bx ;BX->buffer descriptor
- push cx ;Save remaining count
- call near ptr ismacsym ;Is it in macro/symbol stack ?
- pop cx ;Restore remaining count
- mov si,di ;SI->rest of line
- jc @del_macsym_10 ;Not found so go onto next
- ; symbol
- ; The macro or symbol has been found. The current stack pointer is the
- ; first line of the expansion. Move it down to the separator just before
- ; the macro or symbol name itself. Then keep deleting strings from the
- ; stack until we hit another separator.
- push cx ;Save remaining count
- xor cx,cx
- call near ptr strstk_bck_match ;Point to name
- xor cx,cx
- call near ptr strstk_bck_match ;Point to separator
- @del_macsym_20:
- call near ptr strstk_kill ;Delete the string
- ; Check if separator
- call near ptr check_separator ;Is new 'current' a
- ; separator ?
- jne @del_macsym_20 ;No, so keep deleting
- ; Reached a separator.
- pop cx ;Restore count
- jmp short @del_macsym_10 ;Keep looping for rest of line
-
- @del_macsym_99:
- mov sp,bp
- pop bp
- @restore
- ret
- del_macsym endp
-
-
-
- ;+
- ; FUNCTION : expand_macro, expand_symbol
- ;
- ; expand_macro and expand_symbol attempt expand the first word in
- ; linebuf as a macro name and symbol respectively. If no macro
- ; expansion is going on, the expand_macro routine will attempt to
- ; expand the first word in the line buffer as a macro (leading
- ; whitespace is ignored). If an expansion is found, it is stored
- ; in the line buffer with the parameters (if any) filled in. If
- ; there is already a macro expansion going on or no macro is
- ; found, the line buffer is unchanged.
- ;
- ; In contrast, the expand_symbol routine always tries to
- ; expand the first word as a symbol.
- ;
- ; If the first character of the line is a macro_ignore_char, the
- ; character is removed, the rest of the line moved up and no
- ; expansions are done.
- ;
- ; Parameters:
- ;
- ; Returns:
- ; CF = 0 if line buffer changed
- ; 1 otherwise (no macro/symbol or ongoing macro expansion)
- ;
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- expand_macro proc near
- mov bx,offset DGROUP:mac_stk ;BX->macro descriptor
- jmp short @expand
- expand_symbol LABEL near
- mov bx,offset DGROUP:sym_stk ;BX->symbol descriptor
- @expand:
- push si
- push di
- push bp
- mov bp,sp
- sub sp,2
- num_remain equ <word ptr [bp-2]>
-
- cmp bx,offset DGROUP:mac_stk
- jne @expand_10 ;If symbol, don't worry about
- ; whether any macro expansions
- ; are ongoing
- cmp macro_level,0 ;Already expanding a macro?
- je @expand_10 ;No macro expansion currently ongoing
- stc ;set CF to indicate no expansion
- jmp @expand_98 ;Yes, exit with carry flag set
-
- @expand_10:
- ; Look back through the macro/symbol stack buffer for a macro definition.
-
- ; Find first word of line.
- push bx ;Save buffer descriptor addr
- mov cx,lastchar ;End of line
- mov si,offset DGROUP:linebuf ;SI->line buffer
- sub cx,si ;CX<-length of line
- call near ptr skip_whitespace ;SI->first non blank
- mov di,si ;DI->start of word
- call near ptr skip_nondelim ;SI->char after word
- mov num_remain,cx ;Remember num chars remaining
- ; in line
- mov ax,si ;
- mov si,di ;SI->word
- sub ax,si ;AX<-num chars in word
- pop bx ;BX->buffer descriptor
- call near ptr ismacsym ;Is it in macro/symbol stack ?
- jc @expand_98 ;Not found so return with CF set
- ; The macro or symbol has been found.
-
- ; CHeck if it is the macro/symbol string stack
- cmp bx,offset DGROUP:mac_stk ;Expanding a macro ?
- jne @expand_50 ;No, expanding symbol
-
- mov macro_level,1 ;Indicate expansion going on
- ; Copy linebuf into cur_macro (to remember arguments)
- mov di,offset DGROUP:cur_macro
- mov si,offset DGROUP:linebuf
- mov cx,lastchar
- sub cx,si ;CX<-length of linebuf
- mov cur_macro_len,cx ;Store length of invocation line
- rep movsb ;Remember macro invocation line
- ; The current stack string is the first expansion line of the macro
- mov sp,bp ;clean up stack
- pop bp ;restore registers
- pop di
- pop si
- jmp short get_macro_line ;Yes, copy it into the linebuf buffer
- ; get_macro_line will return to caller with the appropriate value
- ; of the carry flag.
-
- @expand_50:
- ; We are expanding a symbol.
- ; num_remain = num chars in linebuf after symbol
- ; First we move these characters to the end of the buffer
-
- mov cx,num_remain ;CX<-number of chars to move back
-
- call near ptr makeroom ;Make room in buffer
- mov si,di ;SI->chars copied to the back
- ; Now copy the string
- mov ax,offset DGROUP:linebuf ;AX->line buffer
- mov cx,LINEBUF_SIZE ;CX<-size of line buffer
- call near ptr strstk_copy ;Copy line. Never mind if end
- ; string overwritten.
- ; AX<-length of expanded string
- mov di,offset DGROUP:linebuf
- add di,ax ;DI->location after expansion
- mov cx,num_remain ;CX<-num chars to copy after expansion
- add ax,cx ;ax<-total length of line
- cmp ax,LINEBUF_SIZE ;End chars overwritten ?
- jbe @expand_60
- mov ax,E_TRUNCATE ;Truncation error
- jmp near ptr abort_processing
- @expand_60:
- ; Copy trailing chars to end of expansion
- rep movsb
- mov lastchar,di
- mov dot,di
- clc ;Indicate expansion took place
- @expand_98:
- ; MUST NOT CHANGE CARRY FLAG AFTER THIS POINT.
- mov sp,bp ;clean up stack
- pop bp ;restore registers
- pop di
- pop si
- ret
- expand_macro endp
-
-
-
-
- ;+
- ; FUNCTION : get_macro_line
- ;
- ; Copies a line from the macro stack to linebuf. All parameters
- ; codes (%1, %2 etc.) are replaced with their corresponding
- ; parameters. If this line is the last in the macro definition,
- ; the macro_level flag is reset. This allows the last line in a
- ; macro definition to be treated as a macro itself. In case of
- ; any errors( eg. expansion too long), the macro expansion is
- ; aborted and the input is directed to the keyboard.
- ;
- ; Parameters:
- ; None.
- ;
- ; Returns:
- ; CF = 0 if a line copied to linebuf
- ; 1 if no more lines in expansion or no ongoing expansion
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- get_macro_line proc near
- cmp macro_level,0 ;Expanding a macro ?
- jne @get_macro_line_1 ;Yes
- stc ;CF = 1 for no expansion
- ret
- @get_macro_line_1:
- push si
- push di
- push bp
- mov bp,sp
- sub sp,LINEBUF_SIZE
- tempbuf equ <byte ptr [bp-LINEBUF_SIZE]>
-
- ; Copy the current string from the macro buffer into temp buffer.
- mov bx,offset DGROUP:mac_stk ;BX->address of buffer descriptors
- lea ax,tempbuf ;AX->destination address
- mov cx,LINEBUF_SIZE ;CX<-size of buffer
- call near ptr strstk_copy ;Copy macro into temp buffer
- ;AX<-length of expansion
- ; No error possible
- ; Replace any placeholders in the macro line by the corresponding paramters.
- ; copy all chars until first placeholder. Copy argument.
- ; Repeat for whole expansion. If at any time there is no place in
- ; buffer, then abort.
- xchg cx,ax ;CX<-length of expansion
- lea si,tempbuf ;SI->tempbuf (macro expansion)
- mov di,offset DGROUP:linebuf ;DI->linebuf
- @get_macro_line_38:
- jcxz @get_macro_line_60 ;Jump if no more expansion
-
- @get_macro_line_40:
- ; At the start of the loop, the following hold :
- ; DI->next empty location in the linebuf
- ; SI->next char of macro expansion to be examined (in tempbuf)
- ; CX = remaining number of chars in expansion (> 0)
- mov al,PLACEHOLDER ;Going to search for placeholder
- mov dx,cx ;DX<-length of remaining expansion
- push di ;Save DI
- mov di,si ;DI->start point for
- ; placeholder scan
- repne scasb ;Look for placeholder
- ;assumes! (ES == SS)
- ; CX is number of chars after placeholder
- sub dx,cx ;DX<-num chars to be copied
- xchg dx,cx ;CX<-num chars to be copied
- ;DX<-num chars after placeholder
- pop di ;DI->destination in linebuf
- rep movsb ;Move chars from tempbuf to linebuf
- ;assumes! (ES == SS)
- ; Note we don't care if the characters at the end of the linebuf
- ; are overwritten.
- mov cx,dx ;CX<-remaining number of chars
- jcxz @get_macro_line_60 ;All chars copied (placeholder
- ; not found or last char in line)
- ; We have found a placeholder character in tempbuf. SI points to the
- ; character AFTER the placeholder. Based on the JCXZ above, there
- ; is at least one character after the placeholder. If it is a
- ; char between '0' and '9' then it is a genuine placeholder. If
- ; it is another placeholder character, then a single placeholder
- ; is stored. Else both the placeholder as well as the character
- ; will be stored into linebuf.
- mov al,[si] ;AL<-char after placeholder
- cmp al,PLACEHOLDER ;Is it a placeholder ?
- jne @get_macro_line_45 ;No
- ; Skip over second placeholder
- inc si
- loop @get_macro_line_40
- jmp short @get_macro_line_60 ;No more chars in expansion
- @get_macro_line_45:
- cmp al,'9'
- ja @get_macro_line_40 ;Not a digit
- sub al,'0'-1 ;Compaer with '0'. At the same
- ; time translate '0'->1,'1'->2
- ; ..and so on to '9'->10 since
- ; getargs counts from 1, not 0.
- jbe @get_macro_line_40 ;Not a digit
- dec di ;Cancel stored PLACEHOLDER char
- push cx ;Save CX
- mov bx,di ;BX->destination for argument
- mov dx,LINEBUF_END
- sub dx,bx ;DX<-remaining space in buffer
- mov di,si ;Save SI in DI
- mov si,offset DGROUP:cur_macro ;SI->current macro being expanded
- xor ah,ah ;AX<-arg number (AL already
- ; holds actual arg number)
- mov cx,cur_macro_len ;Length of original macro string
- call near ptr getargs ;Get the argument into linebuf
- ;AX<-num chars copied, BX unchanged
- ;CF indicates error condition
- pop cx ;Restore CX (num remaining
- ; chars in macro expansion)
- mov si,di ;Restore SI
- ; (SI->char AFTER placeholder char)
- mov di,bx ;Start of copied characters
- jc @get_macro_line_101 ;Jump if getargs returned error
- @get_macro_line_50:
- add di,ax ;DI->next destination char in linebuf
- inc si ;SI->next char of macro expansion
- loop @get_macro_line_40 ;Decrement remaing characters
-
- @get_macro_line_60:
-
- mov lastchar,di ;Update end of line
- mov dot,di ;Update cursor
- ; Set the lastchar and display end pointers
- IF 0
- Currently no need to set display pointers since macro lines are
- not displayed
- mov ax,di ;AX->Potential disp_end
- mov dx,offset DGROUP:linebuf ;Potential disp_begin
- call near ptr set_disp_marks ;Set the marks
- ENDIF
-
- ; Finally check to see if this line is the last in the macro expansion.
- mov bx,offset DGROUP:mac_stk ;BX->macro stack descriptor
- xor cx,cx ;Move to next string in stack
- call near ptr strstk_fwd_match
- call near ptr check_separator ;Is this the last line of
- ; expansion ?
- jne @get_macro_line_90 ;No
-
- ; This was the last line in the macro expansion. Reset macro flag
- mov macro_level,0 ;Reset flag
- @get_macro_line_90:
- ; @unlink
- mov sp,bp ;clean up stack
- pop bp ;restore registers
- pop di
- pop si
- clc ;Return macro expanded
- ret
-
- @get_macro_line_101:
- ; truncation error
- mov ax,E_TRUNCATE ;Indicate truncation of line
- jmp near ptr abort_processing
-
- get_macro_line endp
-
-
-
-
- ;+
- ; FUNCTION : check_separator
- ;
- ; Checks to see if the current macro/symbol buffer line is a
- ; separator.
- ;
- ; Parameters:
- ; BX = address of macro/symbol stack descriptor
- ;
- ; Returns:
- ; ZF = 1 if current buffer line is the separator string
- ; 0 otherwise.
- ;
- ; Register(s) destroyed:
- ; AX,CX
- ;-
- check_separator proc near
- mov ax,offset DGROUP:separator
- mov cx,sep_len
- call near ptr strstk_compare ;Is it the separator ?
- ; strstk_comapre sets ZF.
- ret
- check_separator endp
-
-
-
-
- ;+
- ; FUNCTION : execute_defs
- ;
- ; Called to define a symbol.
- ;
- ; Parameters:
- ; SI -> first char in linebuf following this command
- ; CX == remaining num chars in the line
- ;
- ; Returns:
- ; Nothing.
- ;
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- execute_defs proc near
- mov bx,offset DGROUP:sym_stk ;BX->stack descriptor
- ; Push macro name
- call near ptr push_word ;Push first word onto
- ; the stack. Params :
- ; SI->string
- ; CX=num chars
- ; Returns:
- ; AX<-status code
- ; SI->char after word
- ; CX<-num remaining chars
- cmp ax,0 ;Check status
- jg @execute_defs_99 ;No word on line,
- ; ignore command
- jl @execute_defs_109 ;No room in stack
-
- ; Now push the rest of the string as is except that leading whitespace
- ; is compressed.
- call near ptr skip_whitespace ;Skip leading whitespace
- ;Params SI, CX
- ;Returns SI->first
- ; non-white space char
- ; CX<-remaining chars
- ; (maybe 0)
- call near ptr push_string ;Push string onto stack
- ; (maybe null string)
- jc @execute_defs_109 ;No room in stack
- call near ptr cmdsym_separate ;Push separator onto stack
- jc @execute_defs_109 ;No room in stack
- @execute_defs_99:
- ret
-
- @execute_defs_109:
- ; Error. No room in macro stack.
- call near ptr cmdsym_cleanup ;Clear out partial definition
- call near ptr disp_noroom ;Display error
- ret
- execute_defs endp
-
-
- ;+
- ; FUNCTION : execute_defm
- ;
- ; Called to define a multiple line macro. This function will
- ; keep reading from the current input source and storing it in
- ; the macro buffer until an `endm' is seen. The ENDM directive
- ; can be followed by any characters (eg. macro name)
- ;
- ; Parameters:
- ; SI -> first char in linebuf following this command
- ; CX == remaining num chars in the line
- ;
- ; Returns:
- ; Nothing.
- ;
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- execute_defm proc near
- mov ax,E_NESTED_MACRO ;Assume error
- cmp macro_level,0 ;Expanding a macro ?
- je @execute_defm_1 ;No, jump
- jmp near ptr abort_processing ;Yes, nested macro error
- @execute_defm_1:
- @save si,di
- push bp
- mov bp,sp
- sub sp,2
- err_flag equ <word ptr [bp-2]>
- mov bx,offset DGROUP:mac_stk ;BX->stack descriptor
- mov err_flag,0 ;Initially no errors
-
- ; If expanding a macro, ignore all lines until an endm
- cmp macro_level,0
- jnz @execute_defm_5 ;Go set error flag
-
- ; Push macro name
- call near ptr push_word ;Push first word onto
- ; the stack. Params :
- ; SI->string
- ; CX=num chars
- ; Returns:
- ; AX<-status code
- ; SI->char after word
- ; CX<-num remaining chars
- cmp ax,0 ;Check status
- jb @execute_defm_5 ;No room in stack
- je @execute_defm_40 ;No errors
- ; No name for macro. Push a 0 length macro name. Macro can be called by
- ; a blank line
- xor cx,cx ;CX<-0 (length of string)
- call near ptr push_string ;Push onto stack
- jnc @execute_defm_40 ;No errors
-
- @execute_defm_5:
- mov err_flag,1 ;Indicate error
- call near ptr cmdmacro_cleanup ;Cleanup macro fragments
-
- @execute_defm_40:
- ; Keep reading lines from the input and store in macro buffer unless an error
- ; has been previously seen.
-
- ; Prompt is displayed only if reading from the keyboard.
- cmp source,offset DGROUP:get_kbd_line
- jne @execute_defm_42
- @DispStr macro_prompt
- call near ptr reset_line
- @execute_defm_42:
- call near ptr get_next_line
- mov si,offset DGROUP:linebuf ;SI->String to push
- mov cx,lastchar
- sub cx,si ;CX<-length of line
- push si ;Remember SI and CX
- push cx
- call near ptr skip_whitespace ;SI->first non-white
- ;CX<-num remaining chars
- jcxz @execute_defm_50 ;Blank line so go store it
- mov di,si ;DI->start of word
- call near ptr skip_nonwhite
- mov cx,si
- sub cx,di ;CX<-length of word
- xor ah,ah
- mov si,offset DGROUP:endm_cmd
- lodsb ;AX<-length of endm command
- cmp cx,ax
- jne @execute_defm_50 ;Not ENDM
- call near ptr stre_cmp ;Compare strings
- jnz @execute_defm_50
- ; ENDM seen.
- cmp err_flag,1 ;Had we seen an error ?
- jne @execute_defm_45 ;No
- call near ptr disp_noroom ;Display error
- jmp short @execute_defm_99
- @execute_defm_45:
- ; End of macro seen. Store macro separator
- call near ptr cmdmacro_separate
- jmp short @execute_defm_99
-
- @execute_defm_50:
- ; Store line in macro buffer
- pop cx ;CX<-length of line
- pop si ;SI->linebuf
- mov bx,offset DGROUP:mac_stk ;BX->stack descriptor
- call near ptr push_string
- jnc @execute_defm_40 ;No error
- jmp short @execute_defm_5 ;Indicate error
-
- @execute_defm_99:
-
- mov sp,bp
- pop bp
- @restore
- ret
- execute_defm endp
-
-
-
-
- ;+
- ; FUNCTION : cmdmacro_separate,cmdsym_separate,separate
- ;
- ; Pushes a separator string onto the stack.
- ;
- ; Parameters:
- ; None for cmdmacro_separate and cmdsym_separate
- ; BX->buffer descriptor for routine separate
- ; Returns:
- ; CF = 1 if no room in stack
- ; 0 otherwise
- ;
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- cmdmacro_separate proc near
- mov bx,offset DGROUP:mac_stk ;BX->stack descriptor
- jmp short separate
- cmdsym_separate LABEL near
- mov bx,offset DGROUP:sym_stk ;BX->stack descriptor
- separate LABEL near
- mov ax,sep_len ;AX<-length of separaot string
- mov dx,offset DGROUP:separator ;DX->separator string
- mov cx,1 ;Force push onto stack
- call near ptr strstk_push ;Returns status in CF
- ret
- cmdmacro_separate endp
-
-
-
-
- ;+
- ; FUNCTION : cmdmacro_cleanup,cmdsym_cleanup
- ;
- ; This function is called to clean up the top of the macro or symbol
- ; stacks when a complete definition cannot be pushed onto the
- ; stack due to lack of space. The routine keeps deleting strings
- ; from the top of the macro stack until it finds a separator string.
- ;
- ; Parameters:
- ; None.
- ;
- ; Returns:
- ; Nothing.
- ;
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- cmdmacro_cleanup proc near
- mov bx,offset DGROUP:mac_stk ;BX->stack descriptor
- jmp short @cleanup_5
- cmdsym_cleanup LABEL near
- mov bx,offset DGROUP:sym_stk ;BX->stack descriptor
- @cleanup_5:
- call near ptr strstk_settop ;Reset cur pointer
- ; BX unchanged
- ; While the top of stack is not a separator, keep killing strings.
- @cleanup_10:
- call near ptr check_separator
- ; mov ax,offset DGROUP:separator ;AX->separator string
- ; mov cx,sep_len ;CX<-length of separator
- ; call near ptr strstk_compare ;Is this a separator ?
- je @cleanup_99 ;Yes, then all done
- call near ptr strstk_kill ;Kill string
- jmp short @cleanup_10 ;Keep going
- @cleanup_99:
- ret
- cmdmacro_cleanup endp
-
-
-
-
- ;+
- ; FUNCTION : disp_noroom
- ;
- ; Displays a message saying there is no room in the macro buffer.
- ;
- ; Parameters:
- ; None.
- ;
- ; Returns:
- ; Nothing.
- ; Register(s) destroyed:
- ; AX,DX
- ;-
- disp_noroom proc near
- @DispStr macro_noroom_msg
- ret
- disp_noroom endp
-
-
-
-
-
-
-
- ;+
- ; FUNCTION : search_variable
- ;
- ; Called to search the passed string for a variable. A variable is a
- ; sequence of characters starting with the VAR_MARKER character
- ; followed by another VAR_MARKER character. Two marker characters in
- ; succession are left untouched. (This is so that this routine can be
- ; called again to check for more variables.)
- ;
- ; Parameters:
- ; SI - points to the string.
- ; AX - length of the string.
- ;
- ; Returns:
- ; SI - Points to first marker character of variable if AX is not 0
- ; else points to end of string.
- ; AX - length of variable (including marker chars) if
- ; variable is present, else 0
- ; Register(s) destroyed:
- ; CX
- ;-
- search_variable proc near
- @save di
- mov cx,ax
-
- @search_variable_10:
- mov di,si ;DI->string to search
- ; CX is number of chars
- ; Note we are OK if length of line is already 0.
- mov al,VAR_MARKER
- repne scasb ;Search for marker
- ; If marker not found or found in last position, CX will be 0.
- jcxz @search_variable_99
- ; DI->char after first marker, CX is remaining number of characters
- mov si,di
- @search_variable_20:
- lodsb ;AL<-next char
- dec cx
- jcxz @search_variable_99 ;If there was only one char
- ; after the marker, variable
- ; not possible
- cmp al,VAR_MARKER ;Is it a marker ?
- je @search_variable_10 ;Yes, found a marker, just
- ; ignore the pair and keep
- ; looking
- ; We have found the start of a variable. Look for its end.
- inc di ;Move past first char of var
- mov al,VAR_MARKER
- repne scasb ;Look for it
- jne @search_variable_99 ;Not found (CX is 0)
- ; Found a variable
- dec si
- dec si ;SI->start marker of var
- mov cx,di
- sub cx,si ;CX<-length of var
-
- @search_variable_99:
- xchg ax,cx ;AX<-length of var
- @restore
- ret
- search_variable endp
-
-
-
-
- ;+
- ; FUNCTION : get_symbol
- ;
- ; Hunts through the symbol stack looking for a match for the passed
- ; symbol. If found, it is returned in passed buffer.
- ;
- ; Parameters:
- ; SI - points to the symbol
- ; AX - length of symbol
- ; DI - points to the expansion buffer
- ; DX - size of buffer
- ;
- ; Returns:
- ; CF - 1 symbol not found (AX set to 0) or [DI] buffer to small
- ; to hold expansion (AX contains actual length of expansion).
- ; 0 symbol found. Its expansion is stored in [DI] with
- ; length in AX.
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- get_symbol proc near
- @save si
- mov bx,offset DGROUP:sym_stk ;BX->symbol stack
- push dx ;Save DX
- call near ptr ismacsym ;Is it a symbol ?
- pop cx ;CX<-size of buffer
- jnc @get_symbol_20 ;Yes, go on
- xor ax,ax ;No, not a symbol
- stc ;Set CF to indicate error
- jmp short @get_symbol_99
-
- @get_symbol_20:
- ; Symbol has been found. The current symbol stack pointer has been set to
- ; its expansion string.
- mov ax,di ;AX->buffer
- call near ptr strstk_copy ;Params
- ; BX->stack descriptor
- ; AX->buffer
- ; CX->size of buffer
- ; Returns CF set if
- ; truncation error.
- ; AX always set to length of
- ; actual expansion.
- ; CF set/reset by strstk_copy
-
- @get_symbol_99:
- @restore
- ret
- get_symbol endp
-
-
-
-
-
- ;+
- ; FUNCTION : get_dosenv
- ;
- ; Hunts through the DOS environment looking for a match for the passed
- ; string. If found, it is returned in passed buffer.
- ;
- ; Assumes passed string does NOT contain a NULL byte.
- ;
- ; Parameters:
- ; SI - points to the string
- ; AX - length of string
- ; DI - points to the expansion buffer
- ; DX - size of buffer
- ;
- ; Returns:
- ; CF - 1 string not found (AX set to 0) or [DI] buffer too small
- ; to hold expansion (AX contains actual length of expansion).
- ; 0 symbol found. Its expansion is stored in [DI] with
- ; length in AX.
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- get_dosenv proc near
- @save si,di,es
- push bp
- mov bp,sp
- sub sp,6
- var_len equ <word ptr [bp-2]>
- exp_buf equ <word ptr [bp-4]>
- exp_buf_len equ <word ptr [bp-6]>
- mov var_len,ax ;Save length of string
- mov exp_buf,di ;Save expansion buf address
- mov exp_buf_len,dx ;Save expansion buf length
-
- call near ptr locate_dosenv ;AX->DOS environment segment
- or ax,ax ;Is it 0?
- je @get_dosenv_90 ;Yes, we do not know DOS env
-
- ; We have the DOS segment
- mov es,ax ;ES->environment segment
- xor di,di ;ES:DI->base of environment
- mov cx,8000h ;Max possible environ size
- ; is 32K
-
- @get_dosenv_10:
- ; Top of env search loop. DI contains offset into environment. SI points to
- ; string. DI actually points to start of an env var name if any. CX is
- ; remaining bytes in environment (> 0)
- cmp byte ptr es:[di],0 ;End of environment?
- je @get_dosenv_89 ;Yes
-
- ; We are just going to call stre_cmp to compare strings. Does not matter if
- ; the environment or environment var ends before then since the comparison
- ; will fail since we are assuming a null byte does not occur in the string
- ; that was passed to us.
- push cx ;Remember how much
- ; environment left
- mov cx,var_len ;CX<-length to compare
- call near ptr stre_cmp ;Params DS:SI, ES:DI, CX
- pop cx ;CX<-remaining environment size
- je @get_dosenv_50 ;Match so far
-
- ; No match. Hunt for the next null byte or end of environment.
- @get_dosenv_40:
- xor al,al
- repne scasb
- jcxz @get_dosenv_89 ;If no match for null or
- ; match in last byte, exit
- jmp short @get_dosenv_10 ;Keep looking
-
- @get_dosenv_50:
- ; We have a match so far. The next char in the environ must be a '='.
- mov ax,var_len
- add di,ax
- sub cx,ax
- cmp byte ptr es:[di],'='
- jne @get_dosenv_40 ;No match
-
- ; We have a match.
- inc di ;DI->start of env expansion
- push di ;Save DI
- dec cx ;CX<-remaining length of env
- xor ax,ax
- repne scasb ;Hunt for expansion end
- mov ax,di
- pop di ;DI->start of expansion
- sub ax,di
- dec ax ;AX<-length of expansion
- mov cx,exp_buf_len ;CX<-size of expansion buffer
- cmp cx,ax ;Is it too small?
- pushf ;Remember flags
- jb @get_dosenv_60 ;Copy only that many bytes
- mov cx,ax ;Copy all bytes of expansion
- @get_dosenv_60:
- ; AX contains number of bytes so do not change it after this.
- push ds ;Save DS
- push es
- pop ds
- pop es
- mov si,di ;DS:SI->expansion of env var
- mov di,exp_buf ;ES:DI->expansion buffer
- rep movsb
- push es
- pop ds ;Restore DS. ES is restored
- ; at end of routine.
- popf ;Restore status in CF.
- ; AX already contains
- ; expansion actual byte count
- jmp short @get_dosenv_99
- @get_dosenv_89:
- ; Not found in environment
- xor ax,ax
- @get_dosenv_90:
- ; Error. AX must have been already set appropriately.
- stc
- @get_dosenv_99:
- mov sp,bp
- pop bp
- @restore
- ret
- get_dosenv endp
-
-
-
- ;+
- ; FUNCTION: replace_var_markers
- ;
- ; Replaces all double VAR_MARKER characters with single VAR_MARKERs.
- ; Any solo VAR_MARKERs are deleted (as in DOS batch files).
- ;
- ; Parameters:
- ; DI - points to string
- ; CX - length of string
- ;
- ; Returns:
- ; AX - new length of string
- ;
- ; Registers destroyed:
- ; AX,CX,DX
- ;-
- replace_var_markers proc near
- @save si,di
- mov dx,cx
- mov al,VAR_MARKER
- @replace_var_markers_9:
- jcxz @replace_var_markers_99
- @replace_var_markers_10:
- ; CX must not be 0 at this point! Else calculation of DX goes wrong.
- repne scasb ;Look for marker
- jne @replace_var_markers_99 ;No more markers in string
- ; Found a marker. Move remaining characters up by 1.
- ; DI->first char to be moved up, CX is number of chars to move up
- dec dx ;Deleted one char
- jcxz @replace_var_markers_99 ;No more bytes
- push cx ;Sace byte count
- push di ;Save di
- mov si,di
- dec di
- rep movsb ;Move chars up
- pop di ;DI->next pos to start hunt
- pop cx ;remaining bytes
- dec cx ;jump over character that
- ; now occupies the original
- ; marker position.
- jmp short @replace_var_markers_9
-
- @replace_var_markers_99:
- mov ax,dx ;AX<-new string length
- @restore
- ret
- replace_var_markers endp
-
-
-
-
-
- ;+
- ; FUNCTION : expand_var
- ;
- ; Expands the variables (if any) present in the current line. A
- ; variable consists of a series of non-delimiter characters
- ; between two 'VAR_MARKER' characters. The DOS environment block is
- ; first checked for the presence of the first such variable in the
- ; line and if it is present, it is replaced with its value. Otherwise
- ; the CMDEDIT symbols are checked for match. If there is a match, it
- ; is replaced with the value of the symbol else, it is replaced by a
- ; null string. This procedure is repeated until there are no symbols
- ; in the line. Note that the replacements may themselves contain
- ; variables which will be replaced in turn.
- ;
- ; Parameters:
- ; None.
- ;
- ; Returns:
- ; CF = 0 if no errors.
- ; CF = 1 if errors (line too long). AX contains error code.
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- expand_var proc near
- @save si,di
- push bp
- mov bp,sp
- sub sp,LINEBUF_SIZE
- var_exp equ <byte ptr [bp-LINEBUF_SIZE]>
-
- @expand_var_10:
- mov si,offset DGROUP:linebuf ;SI->current line
- mov ax,lastchar
- sub ax,si ;AX<-length of line
- call near ptr search_variable ;Look for a var
- ; AX<-length of var
- ; SI-> var
- or ax,ax ;AX is length of var
- je @expand_var_60 ;No more vars,
- ; First check the DOS environment for the presence of this variable.
- mov var_len,ax ;Store var len in var_len
- inc si ;Move SI past the VAR_MARKER
- dec ax
- dec ax ;Do not count the two
- ; VAR_MARKER characters
- lea di,var_exp ;DI->buffer
- mov dx,LINEBUF_SIZE ;DX<-size of expansion buffer
- call near ptr get_dosenv ;Params SI->var, AX length
- ; DI->var_exp
- ; Returns expansion in [DI]
- ; AX length of expansion
- or ax,ax ;Any expansion ?
- jne @expand_var_50 ;Yes - go store in line
- ; DOS environment did not have the var, now try the CMDEDIT symbol stack.
- mov ax,var_len
- dec ax
- dec ax ;Do not count the two
- mov dx,LINEBUF_SIZE ;DX<-size of expansion buffer
- call near ptr get_symbol ;Params SI,AX,DI,DX
- ; Returns expansion in [DI],
- ; length in AX
- ; Even if expansion was null, fall thru and replace var with the
- ; expansion (possibly null)
-
- @expand_var_50:
- ; Replace the var pointed to by SI of length var_len by the expansion given
- ; in var_exp (with length in AX).
- dec si ;SI->points to marker
- mov di,ax ;Store AX in DI
- mov ax,var_len
- call near ptr remove_chars ;SI,AX parameters
- mov ax,di ;Restore length of expansion
- mov di,si ;DI->destination
- lea si,var_exp
- ; push dot ;Save position
- call near ptr insert_chars ;SI,DI,AX parameters
- ; pop dot
- jnc @expand_var_10 ;No error
- mov ax,E_TRUNCATE ;Truncation error
- jmp short @expand_var_99 ;Exit, CF already has status
-
-
- @expand_var_60:
- ; All variables have been replaced. Now change all double marker characters
- ; to single and delete all solo markers (similar to DOS)
- mov di,offset DGROUP:linebuf ;DI->string
- mov cx,lastchar
- sub cx,di ;CX<-length of string
- call near ptr replace_var_markers
- add ax,di
- mov lastchar,ax
- cmp dot,ax
- jb @expand_var_80
- mov dot,ax
- @expand_var_80:
- mov dx,offset DGROUP:linebuf
- call near ptr set_disp_marks ;Assume all chars changed.
- clc ;CF<-0 (no errors)
-
- @expand_var_99:
- ; CF has status
- mov sp,bp
- pop bp
- @restore
- ret
- expand_var endp
-
-
-
- ;+
- ; FUNCTION: disp_until_sep
- ;
- ; This function outputs the contents of the specified stack until the
- ; separator is seen. Each element of the stack is followed by a
- ; CR-LF. The current pointer is left pointing to the separator.
- ;
- ; Parameters:
- ; BX - pointer to stack descriptor
- ;-
- disp_until_sep proc near
- @save si,di
- push bp
- mov bp,sp
- sub sp,LINEBUF_SIZE+2
- display_buf equ <byte ptr [bp-LINEBUF_SIZE]>
- sym_kluge equ <byte ptr [bp-LINEBUF_SIZE-2]> ;Kluge to not output extra
- ; space after defs line
- mov sym_kluge,1
-
- @disp_until_sep_10:
- ; Start of loop. Check if the current entry is a separator. If so exit.
- ; Else display the line.
- call near ptr check_separator
- je @disp_until_sep_99 ;Yes, all done
- ; Copy the string into the display buffer and display it.
- lea ax,display_buf
- mov cx,LINEBUF_SIZE
- call near ptr strstk_copy
- xchg cx,ax ;CX<-length of string
- push bx ;Save BX
- lea dx,display_buf ;DX->string, CX is count
- call near ptr output_counted_string
- pop bx
- cmp bx,offset DGROUP:mac_stk
- jne @disp_until_sep_30
- call near ptr output_newline
- jmp short @disp_until_sep_32
- @disp_until_sep_30:
- cmp sym_kluge,0
- je @disp_until_sep_32
- @DispCh ' '
- @disp_until_sep_32:
- xor cx,cx
- call near ptr strstk_fwd_match
- mov sym_kluge,0
- jmp short @disp_until_sep_10
-
- @disp_until_sep_99:
- mov sp,bp
- pop bp
- @restore
- ret
- disp_until_sep endp
-
-
-
- ;+
- ; FUNCTION: output_symbols,output_macros
- ;
- ; Outputs to standard output the current buffer contents of
- ; the symbol/macro buffer.
- ;
- ; Parameters:
- ; None.
- ;-
- output_macsym proc near
- output_symbols LABEL near
- mov bx,offset DGROUP:sym_stk
- mov ax,offset DGROUP:defs
- jmp short @output_macsym_5
- output_macros LABEL near
- mov bx,offset DGROUP:mac_stk
- mov ax,offset DGROUP:defm
- @output_macsym_5:
- @save si,di
- mov di,ax ;DI->'defs' or 'defm'
- call near ptr strstk_save_cur ;Save current pointer.
- ; Probably not necessary for
- ; symbols, but do anyway
- call near ptr strstk_setbot ;Go to bottom of stack
-
- call near ptr output_newline
-
- @output_macsym_10:
- ; Start of loop. One entire macro or symbol has been processed so far.
- ; The current stack pointer is at the separator. First skip over the separator.
- xor cx,cx
- call near ptr strstk_fwd_match
- ; Try to move one more to make sure there is another string
- xor cx,cx
- call near ptr strstk_fwd_match
- jc @output_macsym_99 ;End of buffer
- ; OK move back to get the name of the symbol / macro.
- xor cx,cx
- call near ptr strstk_bck_match
- ; Now output either 'defs' or 'defm'
- mov dx,di
- inc dx ;Point to string
- xor cx,cx
- mov cl,[di] ;Length of string
- push bx ;Save BX
- call near ptr output_counted_string ;Show command string
- @DispCh ' ' ;followed by a space
- pop bx
- ; Now display all strings until a separator is seen
- call near ptr disp_until_sep
-
- ; Now if we are showing a macro, output the 'endm', else a newline
- cmp bx,offset DGROUP:mac_stk ;Macro ?
- jne @output_macsym_70 ;No, repeat loop
- ; Output the 'endm'
- push bx
- mov bx,offset DGROUP:endm_cmd
- xor cx,cx
- mov cl,[bx]
- mov dx,bx
- inc dx
- call near ptr output_counted_string ;AX,BX,CX,DX destroyed
- pop bx
- call near ptr output_newline ;Separate each macro with a
- ; newline
-
- @output_macsym_70:
- call near ptr output_newline
- jmp @output_macsym_10
-
- @output_macsym_99:
- call near ptr strstk_restore_cur ;Restore the current pointer
- @restore
- ret
- output_macsym endp
-
-
-
- ;+
- ; FUNCTION: execute_cmdstat
- ;
- ; Displays the current macro and symbol buffer contents.
- ;
- ;
- ; Parameters:
- ; SI -> first char in linebuf following this command
- ; CX == remaining num chars in the line
- ;
- ; Returns:
- ; Nothing.
- ;
- ; Register(s) destroyed:
- ; AX,BX,CX,DX
- ;-
- execute_cmdstat proc near
- call near ptr output_symbols
- call near ptr output_macros
- call near ptr output_newline
- ret
- execute_cmdstat endp
-
-
- CSEG ENDS
-
- END
-
-