📄 cmdmacro.asm
字号:
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -