Category : Files from Magazines
Archive   : VOL8N22.ZIP
Filename : ALIAS.ASM

 
Output of file : ALIAS.ASM contained in archive : VOL8N22.ZIP
page 66,132
;============================================================================
; ALIAS.COM adds a command line stack, a command line editor, and
; an alias function to COMMAND.COM. Syntax is:
;
; ALIAS [alias [command]] [/F filename] [/S nn] [/U]
; [/B] [/E] [/D] [/L] [/U] [/*] [//]
;
; where /B = Set size of buffer for future alias commands
; /D = Disable alias translation
; /E = Enable alias translation
; /F = Filename of file with list of commands
; /L = List aliases currently in list
; /M = Set minimum command length to save
; /S = Size of command line stack where "nn" is the number of commands
; to save
; /U = Uninstall the program
; /* or // = Comment. Ignore remainder of the line.
;
;
; Revision History:
;
; Version 1.0 Initial Release PC Magazine Vol 8 Num 22
;
;============================================================================

code segment
assume cs:code

org 2ch
env_segment dw ? ;Word containing the segment
; of the program's env. block.
org 80h
command_tail db ? ;Offset of the command tail.

org 100h

main: jmp initialize
program db 13,10,"ALIAS 1.0 "
copyright db "(c) 1989 Ziff Communications Co.",10,13
authors db "PC Magazine ",254," Doug Boling and Jeff Prosise"
db 10,13,"$",1Ah

cmdcom_psp dw 0 ;Segment of COMMAND.COM PSP
master_env dw 0 ;Segment of master environment

cef_pointer dd ? ;Pointer to critical err flag
dos_version dw 0 ;DOS Version number

chk_alias db 1 ;Alias enable flag.
aliaslist_ptr dd ? ;Pointer to alias list.
aliaslist_size dw 0f600h ;Pointer to end of list seg
work_buff_ptr dw ? ;Pointer to alias working buff

cmdstack_base dw ?
cmdstack_size dw 16 ;Size of command stack.
minlength db 1 ;Minimum len of cmd to stack

mystack_ptr dw offset end_of_resident + 512 ;Ptr to internal stack
saved_ss dw ?
saved_sp dw ?
int21h dd -1 ;Int 21 vector (DOS)
int2fh dd -1 ;Int 2f vector (DOS MULTIPLEX)

multiplex_id db 0dbh ;Program ID for multiplex int

points dw ? ;Scan lines per character
columns db ? ;Number of screen columns
cursor_mode dw ? ;Cursor mode
bufferptr db ? ;Input buffer pointer
next_ptr dw 0 ;Address where next command
; will be stored
cmd_ptr dw 0 ;Address of current command
; in command stack
insert_flag db 0 ;0 = insert off, 1 = on
exkeys db 71,72,75,77,79,80 ;Extended keycode list
db 82,83,115,116,117
exkeys_end = $

ex_entry dw offset ctrl_end ;Jump table for extended
dw offset ctrl_right ; keycodes
dw offset ctrl_left
dw offset delete
dw offset toggle_ins
dw offset next_cmd
dw offset eol
dw offset move_right
dw offset move_left
dw offset prev_cmd
dw offset home

;============================================================================
; DOSINT processes calls to interrupt 21h
;============================================================================
dosint proc far
assume cs:code,ds:nothing,es:nothing
cmp ah,0ah ;Check for char input
je dosint_1 ;If so, continue
goto_dos:
jmp cs:[int21h] ;else pass the call to DOS
;
;Compare the active PSP with COMMAND.COM PSP.
;
dosint_1:
push ax ;Save registers
push bx
mov ah,51h ;Get active PSP segment
cmp word ptr cs:[dos_version],310h
jb early_dos
pushf
call cs:[int21h]
jmp short chkpsp1
early_dos:
push es ;If before DOS 3.1, set
les bx,cs:[cef_pointer] ; critical error flag to
inc byte ptr es:[bx] ; force DOS to use the aux
pushf ; stack.
call cs:[int21h] ;Get active PSP segment
mov ax,bx
les bx,cs:[cef_pointer] ;Reset critical error flag
dec byte ptr es:[bx]
mov bx,ax
pop es
chkpsp1:
cmp bx,cs:[cmdcom_psp]
je dosint_2
pop bx ;Else, cleanup and goto DOS
pop ax
jmp short goto_dos
dosint_2:
cld ;Set direction flag
mov cs:[saved_ss],ss ;Save SS:SP
mov cs:[saved_sp],sp
cli
push cs ;Move to internal stack
pop ss
mov sp,cs:[mystack_ptr]
sti
push bp ;Save remaining registers.
mov bp,sp ;Set up stack access
push cx
push dx
push di
push si
push ds
push es
;
;The call is from COMMAND.COM. Invoke line editor.
;
push dx
call cmd_input
pop dx
cmp cs:[cmdstack_size],0
je dosint_3
call cmd_record
;
;Check for alias before returning to COMMAND.COM
;
dosint_3:
cmp cs:[chk_alias],0 ;See if alias translation
je dosint_exit ; is enabled.
mov si,[bp-4] ;Get pointer to input buffer
inc si
xor cx,cx
or cl,ds:[si] ;Get length of buffer
je dosint_exit ;If buffer empty, exit.
inc si ;Point to 1st char in buffer
mov ax,cs
mov es,ax ;Set ES to installed code.
call searchalias ;See if an alias is found.
jc dosint_exit ;No, exit.
;
;If alias found, copy it from alias list to internal buffer.
;
mov si,di ;Load SI with alias pointer
mov ax,es
mov ds,ax ;Point DS to alias list seg
xor cx,cx
mov cl,ds:[si+3] ;Get size of alias
call getalias ;Get alias from list
;
;Append remainder of command line to alias if no cmd line parameters were used.
;
or dx,dx ;See if any command line
jne dosint_6 ; parameters were used.
push si ;Save pointer to buffer.
push ds
mov di,si
add di,cx ;Point DI to end of alias
mov dx,cx ;Save length of alias
mov si,[bp-4] ;Point DS:SI to command.com
mov ds,[bp-10] ; data buffer.
xor cx,cx
inc si
mov cl,[si] ;Get length of command line.
cmp ah,cl ;See if enough space in
ja dosint_4 ; internal buffer. If not
mov cl,ah ; copy only until buff full.
dosint_4:
inc si
mov bl,1 ;Skip past alias.
call scan4char
jc dosint_5
dec si ;Back up 1 char
inc cx
add dx,cx ;Add length of command line.
rep movsb ;Copy command line
dosint_5:
mov cx,dx ;Restore length of command
pop ds ;Restore pointer
pop si
;
;Copy alias from internal buffer to COMMAND.COM data buffer.
;
dosint_6:
mov di,[bp-4] ;Point ES:DI to command.com
mov es,[bp-10] ; data buffer.
mov al,es:[di] ;Get size of data buffer
dec al ;If alias longer than buffer,
cmp al,cl ; copy only the enough
ja dosint_7 ; characters to fill the
xor cx,cx ; buffer.
mov cl,al
dosint_7:
inc di ;Move DI past length bytes
mov es:[di],cl ;Save length of command
inc di
rep movsb ;Copy alias.
mov byte ptr es:[di],13 ;Append carriage return
dosint_exit:
mov cx,cs:[cursor_mode] ;Set default cursor
mov ah,1
int 10h
pop es
pop ds
pop si
pop di
pop dx
pop cx
pop bp
cli
mov ss,cs:[saved_ss] ;Restore stack pointer
mov sp,cs:[saved_sp]
pop bx
pop ax
iret ;Return to COMMAND.COM
dosint endp

;-----------------------------------------------------------------------------
; GETALIAS Copies an alias from the alias list while substituting any
; environment variables and command line parameters.
; Entry: DS:SI - pointer to alias
; Exit: DS:SI - pointer to buffer containing translated alias.
; AH - free space in buffer
; CX - length of the alias
;-----------------------------------------------------------------------------
getalias proc near
mov di,work_buff_ptr ;Point DI to internal buffer
xor ax,ax ;Point to command by adding
mov al,ds:[si+2] ; the size of the alias to
add si,ax ; pointer to the entry.
add si,4 ;Move past list data.
mov ah,126 ;AH contains max size of buff
xor dx,dx ;Clear flag for line params
alias_1:
lodsb ;Get byte from alias
cmp al,"%" ;See if special character
je alias_3 ;Yes, process special char.
alias_2:
stosb ;Store byte from alias
dec ah ;Dec buffer size counter
jz alias_6 ;If internal buffer full, done
loop alias_1
jmp short alias_6 ;If at end of alias, done
;
;A percent sign has been found indicating a 'soft' parameter.
;
alias_3:
mov al,ds:[si] ;Get character after %
cmp al,"%" ;If double %, include in one
je alias_4 ; % in alias.
mov bh,al ;Copy and check to see if
sub bh,"0" ; the next char is a number.
jb alias_5 ; If so, assume a line
cmp bh,9 ; parameter.
ja alias_5
call sublineparam ;Substitute a line paramter
inc dx
alias_4:
inc si ;Move SI past number or
dec cx ; trailing % sign.
loop alias_1
jmp short alias_6 ;If at end of alias, done
alias_5:
call subenvvar ;Substitute an environment var
loop alias_1
alias_6:
mov si,work_buff_ptr ;Point SI to internal buffer
mov cx,di ;Compute size of completed
sub cx,si ; alias.
ret
getalias endp

;-----------------------------------------------------------------------------
; SUBLINEPARAM substitutes a parameter from the command line into the alias.
; Entry: DS:SI - pointer to alias
; ES:DI - pointer to buffer to copy the line parameter
; AH - remaining space in the internal buffer
; BH - binary number of the line parameter
; CX - length of the alias
; Exit: ES:DI - pointer to byte after the parameter in the buffer
; DS:SI - pointer to the character after the line parameter number
; CX - remaining length of the alias
;-----------------------------------------------------------------------------
sublineparam proc near
push cx
push si
push ds
mov si,[bp-4] ;Get pointer to command.com
mov ds,[bp-10] ; data buffer.
xor cx,cx
mov cl,ds:[si+1] ;Get number of chars in buffer.
inc si ;Point to the first byte of
inc si ; data.
sublineparam_1:
or bh,bh ;Check count of param to find.
jz sublineparam_2
mov bl,1
call scan4char ;Find next space
jc sublineparam_exit
dec bl
call scan4char ;Find next word
jc sublineparam_exit
dec bh ;Dec parameter count
jne sublineparam_1 ;If not done, loop back.
dec si ;Backup to 1st char in word.
sublineparam_2:
lodsb ;Get character from parameter
cmp al," " ;If space, parameter done
jbe sublineparam_exit
stosb
dec ah ;Dec buffer size counter
jnz sublineparam_2
sublineparam_exit:
pop ds
pop si
pop cx
ret
sublineparam endp

;-----------------------------------------------------------------------------
; SUBENVVAR substitutes an environment variable into alias.
; Entry: DS:SI - pointer to variable to substitute
; ES:DI - pointer to buffer to copy the contents of the variable
; AH - remaining space in internal buffer
; CX - length of alias string
; Exit: DS:SI - pointer to the byte after the variable name
; ES:DI - pointer to the byte after the variable contents
; CF - set if variable not found
;-----------------------------------------------------------------------------
subenvvar proc near
push dx
push ds
push es
;
;Compute the length of the variable name.
;
mov bx,di ;Save pointer to internal buff
mov di,si ;Compute the length of the
mov dx,cx ; environment variable by
mov al,"%" ; searching for the trailing
repne scasb ; % sign.
sub dx,cx ;Compute length of variable.
dec dx ;Subtract % byte fron length.
push di ;Save ptr to end of env var.
;
;Search the Master Environment block for the variable pointed to by DS:SI
;
mov es,cs:[master_env] ;Get segment of master env blk
xor di,di ;Point ES:DI to environment.
push cx ;Save alias size.
push bx ;Save ptr to internal buffer
mov bx,si ;Save pointer to var name
subenvvar_1:
mov si,bx ;Get back ptr to var name.
mov cx,dx ;Compare env var to var in
repe cmpsb ; alias.
je subenvvar_2 ;Variable found, exit loop
xor al,al ;Find next environment var.
mov cx,-1 ;Scan the entire segment.
repne scasb
cmp byte ptr es:[di],0 ;If double zero, end of env
jne subenvvar_1 ; block. else, loop back.
pop di ;Restore DI and exit
jmp short subenvvar_exit
;
;Environment variable found. Substitute into alias.
;
subenvvar_2:
mov si,es ;DS:SI points to env string
mov ds,si ;ES:DI points to internal buff
mov si,cs
mov es,si
mov si,di ;Copy pointer to var contents.
pop di ;Restore ptr to internal buff
subenvvar_3:
lodsb ;Move environment pointer past
cmp al,"=" ; the equals sign.
jne subenvvar_3
subenvvar_4:
lodsb ;Move pointer to first
cmp al," " ; non-space character.
jb subenvvar_4
subenvvar_5:
or al,al ;See if at the end of variable
je subenvvar_exit
stosb ;Save character in command
lodsb ;Get next character
dec ah ;Dec buffer size count.
jne subenvvar_5 ;If buffer not full, continue
subenvvar_exit:
pop cx ;Restore alias length
pop si ;Restore alias pointer
pop es ;Restore segment registers
pop ds
pop dx
ret
subenvvar endp

;-----------------------------------------------------------------------------
; SUBKEY searches the alias list for a key substitution
; Entry: AL - extended key code
; Exit: CF - clear if key found, set if not found
; DX - offset address of matching entry in alias list (if CF = 0)
; CX - length of matching entry (if CF = 0)
;-----------------------------------------------------------------------------
subkey proc near
push bx
push di
push si
push ds
push es
xor ah,ah ;Indicate extended code.
les di,cs:[aliaslist_ptr] ;Get pointer to alias list.
subkey_1:
mov dx,es:[di] ;Get next entry offset
cmp dx,-1 ;See if at the end of the list
je subkey_notfound
cmp es:[di+4],ax ;Check for key code.
je subkey_found ;If found, exit loop
subkey_2:
add di,dx ;Else, point to next entry.
jmp short subkey_1
;
;Copy alias into internal buffer.
;
subkey_found:
mov si,di ;Load SI with alias pointer
mov ax,es
mov ds,ax ;Point DS to alias list seg
xor cx,cx
mov cl,ds:[si+3] ;Get size of alias
call getalias ;Get alias from list
mov dx,si ;Copy pointer to buffer
clc ;Set key found flag
subkey_exit:
pop es
pop ds
pop si
pop di
pop bx
ret
subkey_notfound:
stc ;Set key not found flag
jmp subkey_exit
subkey endp

;-----------------------------------------------------------------------------
; SEARCHALIAS searches the alias list for a matching alias.
; Entry: DS:SI - pointer to alias
; ES - segment of installed code
; CX - length input buffer
; Exit: CF - clear if alias found
; ES:DI - pointer to matching entry in alias list, if CF is clear
;-----------------------------------------------------------------------------
searchalias proc near
push bx ;Save registers
push cx
push si
xor bx,bx
searchalias_1:
lodsb ;Compute the length of the
or al,al ; length of the alias by
je searchalias_2 ; finding the next space.
cmp al," " ;Allow zero byte in alias
jbe searchalias_3 ; for function key labels.
searchalias_2:
inc bx
loop searchalias_1
searchalias_3:
pop si
les di,es:[aliaslist_ptr] ;Get pointer to alias list.
mov cx,bx ;Get length of alias
searchalias_4:
mov bx,es:[di]
cmp bx,-1 ;See if at the end of the list
je searchalias_notfound
cmp es:[di+2],cl ;Compare lengths
jne searchalias_5
push cx ;Save size and starting
push di ; pointers.
push si
add di,4 ;Point to start of alias field.
repe cmpsb ;Compare alias to input string
pop si
pop di
pop cx
je searchalias_6 ;If found, exit loop
searchalias_5:
add di,bx ;Else, point to next entry.
jmp short searchalias_4
searchalias_6:
clc ;Set alias found flag
searchalias_exit:
pop cx
pop bx
ret
searchalias_notfound:
stc
jmp short searchalias_exit
searchalias endp

;-----------------------------------------------------------------------------
; SCAN4CHAR scans a string to find the first character.
; Entry: SI - pointer to ASCII string
; BL - 0 = find next char, 1 = find next space
; CX - file length
; Exit: AL - first nonspace character
; CF - set if carriage return found
;-----------------------------------------------------------------------------
scan4char proc near
assume ds:nothing,es:nothing
scan4loop:
jcxz scan4_eol ;See if at the end of the file.
lodsb
dec cx ;Decrement file length counter.
cmp al,13 ;Check for carriage return.
jne scan4_1
scan4_eol:
stc
jmp short scan4_exit1
scan4_1:
or bl,bl ;Check if searching for space
jne scan4_2 ; or character.
cmp al," " ;Check for space or other
jbe scan4loop ; 'white' characters.
jmp short scan4_exit
scan4_2:
cmp al," " ;Check for characters.
ja scan4loop
scan4_exit:
clc
scan4_exit1:
ret
scan4char endp

;----------------------------------------------------------------------------
; CMD_INPUT replaces DOS' 0Ah text input function.
;----------------------------------------------------------------------------
cmd_input proc near
push ds ;Save DS
xor ax,ax ;Then zero it
mov ds,ax
mov ax,ds:[0485h] ;Get number of scan lines
cmp ax,cs:[points] ; per character and branch
je cmd1 ; if it hasn't changed

mov cs:[points],ax ;Record new number of scan
mov ax,ds:[0460h] ; lines per character and
mov cs:[cursor_mode],ax ; cursor mode
cmd1:
pop ds ;Restore DS
call set_cursor ;Set cursor mode

mov ah,15 ;Get video page and columns
int 10h
dec ah ;Calculate max column number
mov cs:[columns],ah ;Save it
mov ax,ds ;Point ES:DI to buffer
mov es,ax
mov di,dx
add di,2
mov si,dx ;Point DS:SI to character count
inc si
mov byte ptr [si],0 ;Zero initial count
mov cs:[bufferptr],1 ;Set initial index value
cld ;Clear DF
;
;Wait for a keycode to appear in the keyboard buffer.
;
getkey: mov ah,0Bh ;Check buffer for keycode
int 21h
or al,al ;Anything there?
jne getchar ;Yes, then go get it
int 28h ;No, then execute interrupt 28h
jmp getkey ;Loop back for another try
;
;Read the keycode and process it if it's not an extended code.
;
getchar:
mov ah,8 ;Read character from buffer
int 21h
or al,al ;Is it an extended code?
je excode ;Yes, then branch

cmp al,8 ;Backspace key?
jne getc1 ;No, then branch
call backspace ;Rub out a character
jmp getkey ;Return to loop
getc1:
cmp al,9 ;Tab key?
jne getc2 ;No, then branch
call tab ;Tab to next tab boundary
jmp getkey ;Return to loop
getc2:
cmp al,27 ;ESC key?
jne getc3 ;No, then branch
call clear_line ;Yes, then clear input line
mov cs:[cmd_ptr],0 ;Zero current command pointer
jmp getkey
getc3:
cmp al,7Fh ;Ctrl-Backspace?
jne getc4 ;No, then branch
call ctrl_bs ;Yes, then delete word
jmp getkey
getc4:
cmp al,13 ;ENTER key?
je enter ;Yes, then branch
call printchar ;No, then print the character
getc5:
jmp getkey
enter:
call eol ;Place cursor at end-of-line
mov byte ptr es:[di],13 ;Insert carriage return code
mov ah,2 ;Advance to next line
mov dl,13
int 21h
get_exit:
ret
;
;Process extended keycodes.
;
excode:
mov ah,8 ;Read extended code
int 21h

cmp al,3Bh ;See if below F1
jb excode3
cmp al,71h ;See if above Alt-F10
ja excode3
cmp al,54h ;See if above Shift-F1
jae excode1
cmp al,44h ;See if above F10
ja excode3
excode1:
call subkey ;Scan alias list for match
jc getkey ;Exit if no match found
push cx
push dx
call clear_line ;Clear command line
pop dx
pop cx
excode2:
push si
mov si,dx ;Copy offset address into SI
mov al,byte ptr cs:[si] ;Get next character
pop si
cmp al,13 ;Exit and execute command
je enter ; on carriage return
inc dx
push cx
push dx
call printchar ;Print it
pop dx
pop cx
jc getc5
loop excode2 ;Loop until done
jmp getkey ;Return to input loop
excode3:
push es ;Save buffer address
push di
mov cx,cs ;Point ES:DI to list of
mov es,cx ; supported keycodes
mov di,offset exkeys
mov cx,offset exkeys_end - offset exkeys
repne scasb ;Scan list
pop di ;Clear the stack
pop es
jne excode4 ;Ignore if key not found
shl cx,1 ;Convert CX to address
add cx,offset ex_entry
push bx ;Save page number in BH
mov bx,cx ;Get entry address from table
mov ax,cs:[bx]
pop bx ;Restore BH
call ax ;Call handling routine
excode4:
jmp getkey ;Return to input loop
cmd_input endp

;------------------------------------------------------------------------------
; PREV_CMD outputs the previous command in the command stack.
;------------------------------------------------------------------------------
prev_cmd proc near
mov dx,cs:[cmd_ptr] ;Get current stack index
cmp dx,cs:[cmdstack_size] ;Exit if at top of command
je prev_exit ; stack
or dx,dx ;Branch if not at bottom of
jnz prev1 ; command stack
;
;Copy the current contents of the command line to the search buffer.
;
mov cl,[si] ;Get count of characters on
xor ch,ch ; command line in CX
inc cx
push es ;Save registers
push di
push si
mov ax,cs ;Point ES:DI to search text
mov es,ax ; buffer
mov di,offset command_tail
rep movsb ;Copy command line text
pop si ;Restore registers
pop di
pop es
;
;Search for the previous command and output it.
;
prev1:
inc dx ;Increment stack index
mov ax,cs:[next_ptr] ;Get stack base index
sub ax,dx ;Calculate address of previous
cmp ax,0 ; command
jge prev2
add ax,cs:[cmdstack_size]
prev2:
mov cl,7 ;Calculate offset address of
shl ax,cl ; the command
add ax,cs:[cmdstack_base]
cmp byte ptr cs:[command_tail],0 ;Output command if there is
je prev3 ; no search criterion
call check_string ;Compare strings
jz prev3 ;Output command if the strings
cmp dx,cs:[cmdstack_size] ; match
jne prev1
ret ;Exit if at top of stack
prev3:
push si ;Save SI
mov si,ax ;Transfer address to SI
cmp byte ptr cs:[si],0 ;Valid command?
pop si ;Restore SI
je prev_exit ;No, then ignore keypress
mov cs:[cmd_ptr],dx ;Save new command pointer
call write_command ;Output the command string
prev_exit:
ret
prev_cmd endp

;------------------------------------------------------------------------------
; NEXT_CMD outputs the next command in the command stack.
;------------------------------------------------------------------------------
next_cmd proc near
mov dx,cs:[cmd_ptr] ;Get current stack index
or dx,dx ;Exit if it's zero
jz next_exit
next1:
dec dx ;Decrement stack index
mov cs:[cmd_ptr],dx ;Save command pointer
or dx,dx ;Clear line and exit if
jz next3 ; the result is zero
mov ax,cs:[next_ptr] ;Get stack base index
sub ax,dx ;Calculate address of next
cmp ax,0 ; command
jge next2
add ax,cs:[cmdstack_size]
next2:
mov cl,7 ;Calculate offset address of
shl ax,cl ; command
add ax,cs:[cmdstack_base]
cmp byte ptr cs:[command_tail],0 ;Output command if there is
je next4 ; no search criterion
call check_string ;Compare strings
jz next4 ;Output command if the strings
jmp next1 ; match
next3:
call clear_line
cmp byte ptr cs:[command_tail],0
je next_exit
mov ax,offset command_tail
next4:
call write_command ;Output the command string
next_exit:
ret
next_cmd endp

;------------------------------------------------------------------------------
; CHECK_STRING compares the string in the search buffer with another string.
; Entry: AX - string address
; Exit: ZF - set if strings are equivalent, clear if they are not
;------------------------------------------------------------------------------
check_string proc near
push ds ;Save registers
push si
push es
push di
mov cx,cs ;Point DS and ES to
mov ds,cx ; code segment
mov es,cx
mov si,offset command_tail ;Point DS:SI to text in
mov cl,[si] ; search buffer
xor ch,ch
inc si
mov di,ax ;Point DI to other string
inc di ;
repe cmpsb ;Compare strings
pop di ;Restore registers
pop es
pop si
pop ds
ret
check_string endp

;------------------------------------------------------------------------------
; PRINT_STRING writes an ASCII string to the command line.
; Entry: DS:SI - string address
; CX - number of characters
;------------------------------------------------------------------------------
print_string proc near
jcxz ps_exit ;Exit if no characters
push dx
cld
mov ah,2 ;Print the character
ps1:
lodsb ;Get a byte
mov dl,al ;Transfer it to DL
int 21h ;Output character
loop ps1 ;Loop until done
pop dx
ps_exit:
ret
print_string endp

;------------------------------------------------------------------------------
; WRITE_COMMAND outputs a command string.
; Entry: AX - string offset address
; Exit: AL - character after string
;------------------------------------------------------------------------------
write_command proc near
push ax ;Save address
call clear_line ;Clear input line
pop ax ;Retrieve string address
push ds ;Save DS and SI
push si
push cs ;Point DS to string segment
pop ds
mov si,ax ;Point SI to the string
mov cl,[si] ;Get string length
xor ch,ch
mov byte ptr es:[di-1],cl ;Store string length
inc si ;Advance SI to string text
write1:
mov ah,2 ;Print one character
mov dl,[si]
int 21h
movsb ;Transfer character to buffer
inc cs:[bufferptr] ;Advance pointer
loop write1 ;Loop until done
lodsb ;Get first character after string
pop si ;Restore registers
pop ds
ret
write_command endp

;------------------------------------------------------------------------------
; TOGGLE_INS toggles the insert flag.
;------------------------------------------------------------------------------
toggle_ins proc near
xor cs:[insert_flag],1 ;Toggle insert flag
call set_cursor ;Set cursor mode
ret
toggle_ins endp

;------------------------------------------------------------------------------
; TAB tabs to the next tab boundary.
;------------------------------------------------------------------------------
tab proc near
mov al,cs:[bufferptr] ;Calculate number of
dec al ; spaces to insert for
xor ah,ah ; soft tab
mov bl,8
div bl
mov cx,8
sub cl,ah
tab1:
push cx ;Print spaces
mov al,32
call printchar
pop cx
jc tab_exit
loop tab1
tab_exit:
ret
tab endp

;------------------------------------------------------------------------------
; BACKSPACE deletes the character left of the cursor.
;------------------------------------------------------------------------------
backspace proc near
cmp cs:[bufferptr],1 ;At beginning of command line?
je bs_exit ;Yes, then ignore it
mov cl,[si] ;Get count
sub cl,cs:[bufferptr] ;Calculate distance to end-of-line
inc cl
xor ch,ch
push cx ;Save it
jcxz bs1 ;Branch if at end-of-line
;
;Shift all characters right of the cursor in the buffer one slot left.
;
push si ;Save SI and DI
push di
mov si,di ;Position them for shifts
dec di
rep movsb ;Shift characters right of cursor
pop di ;Restore registers
pop si
;
;Display the new string and update input parameters.
;
bs1:
call move_left ;Move cursor left
bs2:
pop cx ;Retrieve shift count
push dx ;Save cursor position
push si ;Save SI
mov si,di ;Point SI to new part of string
call print_string ;Print the new part
mov ah,2 ;Blank the last character
mov dl,32
int 21h
pop si ;Restore registers
pop dx ;Restore cursor address
mov ah,2 ;Reset the cursor
int 10h
dec byte ptr [si] ;Decrement character count
bs_exit:
ret
backspace endp

;------------------------------------------------------------------------------
; PRINTCHAR writes a new character to the input buffer and echoes it.
; Entry: AL - character to print
; Exit: CF clear if character printed
; CF set if buffer full
;------------------------------------------------------------------------------
printchar proc near
cmp cs:[insert_flag],0 ;Insert state on?
jne print3 ;Yes, then branch
;
;Print a character in overstrike mode.
;
mov cl,[si] ;Get count
cmp cl,cs:[bufferptr] ;End-of-line?
jae print2 ;No, then branch
mov cl,[si-1] ;Get maximum length
sub cl,[si] ;Subtract current length
cmp cl,1 ;Buffer full?
je beep ;Yes, then branch
print1:
inc byte ptr [si] ;Increment count
print2:
stosb ;Deposit new character
mov ah,2 ;Then print it
mov dl,al
int 21h
inc cs:[bufferptr] ;Advance buffer pointer
print_exit:
clc ;Clear CF and exit
ret
beep:
mov ax,0E07h ;Print ASCII 7 thru BIOS
int 10h
stc
ret
;
;Print a character in insert mode.
;
print3:
mov cl,[si-1] ;Get maximum length
sub cl,[si] ;Subtract current count
cmp cl,1 ;Buffer full?
je beep ;Yes, then branch
mov cl,[si] ;Get count
cmp cl,cs:[bufferptr] ;End-of-line?
jb print1 ;Yes, then branch
sub cl,cs:[bufferptr] ;Calculate number of shifts
inc cl
xor ch,ch
push cx ;Save shift count
push si ;Save SI
add di,cx ;Position DI to end-of-line
mov si,di ;Position SI just before it
dec si
std ;Set DF for now
rep movsb ;Make room for new character
cld ;Clear DF
pop si ;Restore SI
mov es:[di],al ;Deposit new character
mov ah,3 ;Get cursor position
int 10h
pop cx ;Retrieve shift count
inc cx ;Increment it
push dx ;Save cursor position
push si ;Save SI
mov si,di ;Point SI to current location
call print_string ;Print new part of string
pop si ;Restore SI and DX
pop dx
mov ah,2 ;Reset cursor position
int 10h
inc byte ptr [si] ;Add to character count
call move_right ;Move cursor right
jmp print_exit
printchar endp

;------------------------------------------------------------------------------
; DELETE deletes the character at the cursor.
;------------------------------------------------------------------------------
delete proc near
mov cl,[si] ;Get count
cmp cl,cs:[bufferptr] ;End-of-line?
jb del2 ;Yes, then ignore keypress
sub cl,cs:[bufferptr] ;Calculate number of shifts
xor ch,ch ;Byte to word in CX
push cx ;Save shift count
jcxz del1 ;Branch if no shifts
push si ;Save SI and DI
push di
mov si,di ;Position registers for shift
inc si
rep movsb ;Shift chars right of cursor
pop di ;Restore registers
pop si
del1:
mov ah,3 ;Get cursor position
int 10h

jmp bs2 ;Exit thru BACKSPACE routine
del2:
ret
delete endp

;------------------------------------------------------------------------------
; CTRL_BS deletes the word at the cursor.
;------------------------------------------------------------------------------
lesschars dw ? ;Count of chars deleted
shiftcount dw ? ;Count of chars shifted

ctrl_bs proc near
mov cl,[si] ;Exit now if there is nothing
xor ch,ch ; on the command line
or cx,cx
jnz cbs1
cbs_exit:
ret
cbs1:
cmp cs:[bufferptr],1 ;Exit if the cursor is at the
je cbs3 ; at the end of the command
cmp cl,cs:[bufferptr] ; line or if it is under a
jb cbs_exit ; space; otherwise, move to
cmp byte ptr [di],32 ; the beginning of the
je cbs_exit ; current word
cmp byte ptr [di-1],32
je cbs3
cbs2:
push cx ;Save CX
call ctrl_left ;Move to start of word
pop cx ;Restore CX
cbs3:
inc cx ;Calculate max number of
push cx ; characters to search
mov dl,cs:[bufferptr] ; looking for the next
xor dh,dh ; word or end-of-line
sub cx,dx
push di ;Save DI
cbs4:
inc di ;Search until DI addresses
cmp byte ptr [di],32 ; either the first character
je cbs5 ; in the next word or the
cmp byte ptr [di-1],32 ; end of the command line
je cbs6
cbs5:
loop cbs4
cbs6:
mov dx,di ;Save final value of DI
pop di ;Restore DI
pop cx ;Retrieve count
mov cs:[lesschars],dx ;Calculate number of chars to
sub cs:[lesschars],di ; be deleted
sub cx,dx ;Then calculate how many chars
add cx,si ; must be shifted
mov cs:[shiftcount],cx
jcxz cbs7 ;Branch if no shift
push si ;Save registers
push di
mov si,dx ;Point DS:SI to next word
rep movsb ;Delete current word
pop di ;Restore registers
pop si
cbs7:
mov cx,cs:[lesschars] ;Update character counter
sub [si],cl ; in input buffer
mov ah,3 ;Save the current cursor
int 10h ; position on the stack
push dx
push si ;Update the text on the
mov si,di ; command line
mov cx,cs:[shiftcount]
call print_string
pop si
mov cx,cs:[lesschars]
cbs8:
mov ah,2 ;Print as many spaces as
mov dl,32 ; there were characters
int 21h ; deleted
loop cbs8
pop dx ;Restore cursor position
mov ah,2 ; and exit
int 10h
ret
ctrl_bs endp

;------------------------------------------------------------------------------
; CTRL_END deletes command line text from the cursor to the end of the line.
;------------------------------------------------------------------------------
ctrl_end proc near
mov cl,[si] ;Exit if already at end
cmp cl,cs:[bufferptr] ; of line
jb ce_exit
sub cl,cs:[bufferptr] ;Calculate number of chars
xor ch,ch ; to be deleted
inc cx
sub [si],cl ;Update count in input buffer
push cx
mov ah,3 ;Get and save cursor position
int 10h
pop cx
push dx
ce1:
mov ah,2 ;Print as many spaces as
mov dl,32 ; there are characters
int 21h ; to delete
loop ce1
mov ah,2 ;Reset cursor position and
pop dx ; exit
int 10h
ce_exit:
ret
ctrl_end endp

;------------------------------------------------------------------------------
; MOVE_LEFT moves the cursor one character left.
;------------------------------------------------------------------------------
move_left proc near
cmp cs:[bufferptr],1 ;At beginning of line?
je left2 ;Yes, then ignore keypress
mov ah,3 ;Get cursor position
int 10h
dec dl ;Decrement it by 1
cmp dl,0FFh
jne left1
mov dl,cs:[columns] ;Decrement row number by 1
dec dh ; if cursor wraps around
left1:
mov ah,2 ;Set new position
int 10h
dec di ;Decrement pointers
dec cs:[bufferptr]
left2:
ret
move_left endp

;------------------------------------------------------------------------------
; MOVE_RIGHT moves the cursor one character right.
;------------------------------------------------------------------------------
move_right proc near
mov cl,[si] ;Get count
cmp cl,cs:[bufferptr] ;End-of-line?
jb rt2 ;Yes, then ignore keypress
mov ah,3 ;Get cursor position
int 10h
inc dl ;Increment column number
cmp dl,cs:[columns] ;Increment row number if
jna rt1 ; cursor wraps around
xor dl,dl
inc dh
rt1:
mov ah,2 ;Position cursor
int 10h
inc di ;Advance pointers
inc cs:[bufferptr]
rt2:
ret
move_right endp

;------------------------------------------------------------------------------
; CTRL_LEFT moves the cursor one word left.
;------------------------------------------------------------------------------
ctrl_left proc near
call move_left ;Move one character left
cmp cs:[bufferptr],1 ;Beginning of line?
je cl_exit ;Yes, then exit
cmp byte ptr es:[di],32 ;Loop back if current char
je ctrl_left ; is a space
cmp byte ptr es:[di-1],32 ;Loop back if char to the
jne ctrl_left ; left is not a space
cl_exit:
ret
ctrl_left endp

;------------------------------------------------------------------------------
; CTRL_RIGHT moves the cursor one word right.
;------------------------------------------------------------------------------
ctrl_right proc near
call move_right ;Move one character right
mov cl,[si] ;End-of-line?
cmp cl,cs:[bufferptr] ;Yes, then exit
jb cr_exit
cmp byte ptr es:[di],32 ;Loop back if current char
je ctrl_right ; is a space
cmp byte ptr es:[di-1],32 ;Loop back if char to the
jne ctrl_right ; left is not a space
cr_exit:
ret
ctrl_right endp

;------------------------------------------------------------------------------
; HOME relocates the cursor to the beginning of the command line.
;------------------------------------------------------------------------------
home proc near
mov cl,cs:[bufferptr] ;Get position pointer
dec cl ;Calculate distance from start
xor ch,ch
jcxz home_exit ;Exit if already there
home1:
push cx ;Save count
call move_left ;Move left one space
pop cx ;Retrieve count
loop home1 ;Loop until done
home_exit:
ret
home endp

;------------------------------------------------------------------------------
; EOL advances the cursor to the end of the command line.
;------------------------------------------------------------------------------
eol proc near
mov cl,[si] ;Get count
cmp cl,cs:[bufferptr] ;Already at end?
jb eol_exit ;Yes, then exit
sub cl,cs:[bufferptr] ;Calculate distance from end
inc cl
xor ch,ch ;Byte to word in CX
eol1:
push cx ;Advance right CX times
call move_right
pop cx
loop eol1
eol_exit:
ret
eol endp

;------------------------------------------------------------------------------
; CLEAR_LINE clears the command line.
; Entry: BH - current video page
;------------------------------------------------------------------------------
clear_line proc near
mov cl,[si] ;Get count
xor ch,ch
jcxz cline2 ;Exit if no characters
push cx ;Save count
call home ;Home the cursor
mov ah,3 ;Get cursor position
int 10h
pop cx ;Restore CX
push dx ;Save cursor address
mov ah,2 ;Print ASCII spaces
mov dl,32
cline1:
int 21h
loop cline1
mov ah,2 ;Home cursor again
pop dx
int 10h
mov byte ptr [si],0 ;Reset count
cline2:
ret
clear_line endp

;------------------------------------------------------------------------------
; CMD_RECORD records the latest command in the command stack.
; Entry: DS:DX - input buffer address
;------------------------------------------------------------------------------
cmd_record proc near
mov si,dx ;Point SI to input buffer
mov al,[si+1] ;Get length of input string
cmp al,cs:[minlength] ;Is the length zero?
jb cmd_exit ;Yes, then exit now
inc si ;Advance SI to count byte
push cs ;Point ES to command stack
pop es ; segment
mov di,cs:[next_ptr] ;Get command stack pointer
mov cl,7 ;Convert it to offset address
shl di,cl
add di,cs:[cmdstack_base]
mov cl,al ;Transfer string length to CL
inc cl ;Increment for count byte
xor ch,ch ;Byte to word in CX
cld ;Clear DF
rep movsb ;Copy string to command stack
inc cs:[next_ptr] ;Update pointer
mov ax,cs:[cmdstack_size]
cmp cs:[next_ptr],ax ;Wrap around if necessary
jne cmdrec1
mov cs:[next_ptr],0
cmdrec1:
mov cs:[cmd_ptr],0 ;Zero current command pointer
cmd_exit:
ret
cmd_record endp

;------------------------------------------------------------------------------
; SET_CURSOR sets the cursor mode based on the state of the insert flag.
;------------------------------------------------------------------------------
set_cursor proc near
cmp cs:[insert_flag],0 ;Test state of insert flag
je setc1 ;Branch if not set
mov cx,cs:[cursor_mode] ;Raise top by 2 scan lines
sub ch,2
jns setc2 ;Exit if it wraps around
ret
setc1:
mov cx,cs:[cursor_mode] ;Set default cursor
setc2:
mov ah,1 ;Set cursor mode
int 10h
ret
set_cursor endp

;============================================================================
; MUXINT processes calls to interrupt 2Fh
; Entry: AH - Device ID
; Exit: AL - 0FFh if AH = Alias device ID. Unchanged otherwise.
; ES - Code segment if AH = Alias device ID. Unchanged otherwise.
;============================================================================
muxint proc far
assume cs:code,ds:nothing,es:nothing
cmp ah,cs:[multiplex_id] ;Check for program ID
je muxint_1 ;Its us, indicate installed.
jmp cs:[int2fh] ;else pass the call on
muxint_1:
mov al,-1 ;Indicate Alias installed
push cs ;ES = installed code segment
pop es
iret
muxint endp

even ;Align stack on word boundry
end_of_resident = $
;----------------------------------------------------------------------------
; Start of non-resident code.
;----------------------------------------------------------------------------
final_install:
rep movsb ;Copy alias list
mov di,cmdstack_base ;Initialize command stack
mov cx,cmdstack_size ; area with leading zeroes
jcxz tsr ;Branch if size is zero
xor al,al
cld
final_loop:
stosb
add di,127
loop final_loop
tsr:
mov ax,3100h ;Terminate and stay resident
int 21h

;----------------------------------------------------------------------------
; Non-resident data.
;----------------------------------------------------------------------------
alrdy_installed db 0 ;Installed flag
other_seg dw 0 ;Segment of installed code
databuff_seg dw 0 ;Segment of data buffer.

alias_buffer dw 512 ;Extra buffer for alias list.
aliaslist_end dw 0 ;Offset of end of the list.
alias_inlist db 0 ;Flag used in alias list append

infomsg1 db "ALIAS uninstalled$"
infomsg2 db 13,10,9,"Command stack size: $"
infomsg3 db 13,10,9,"Minimum stacked command length: $"
infomsg4 db 13,10,9,"Bytes free in alias buffer: $"
infomsg5 db 13,10,9,"Alias translation is $"
infomsg5d db "disabled",13,10,"$"
infomsg5e db "enabled",13,10,"$"
infomsg6 db 13,10,9,"FUNCTION KEY DEFINITIONS$"
infomsg7 db 13,10,9,"ALIAS DEFINITIONS$"
infomsg8 db 13,10,"For help type ALIAS ?$"

filemsg1 db 13,10,"Error in line $" ;File identification message.
filemsg2 db " of file: "
filenam_field db 78 dup (0) ;Name of current entry file.

errmsg0 db "Need DOS 2.0 or greater$"
errmsg1 db "ALIAS not installed$"

errmsg2 db 13,10,"Syntax: ALIAS [alias [command]] "
db "[/F filename] [/S nn] [/U]",13,10
db 14 dup (" ")
db "[/B nn] [/E] [/D] [/L] [/M]",13,10,10
db 9,"ALIAS alias command",13,10
db 9,"ALIAS [fn] command",13,10,10
db 9,"/B = Buffer size",13,10
db 9,"/D = Disable alias translation",13,10
db 9,"/E = Enable alias translation",13,10
db 9,"/F = Filename of command file",13,10
db 9,"/L = List aliases",13,10
db 9,"/M = Minimum command length to stack",13,10
db 9,"/S = Size of command stack",13,10
db 9,"/U = Uninstall",13,10,"$"

errmsg3 db "Can",39,"t uninstall$"
errmsg4 db "Can",39,"t change parameter after installation$"
errmsg5 db "Illegal number$"
errmsg6 db "Can",39,"t find alias file$"
errmsg7 db "Can",39,"t find COMMAND.COM$"
errmsg8 db "Not enough memory$"
errmsg9 db "Alias list full$"
errmsg10 db "List and stack too large$"
errmsg11 db "Invalid key assignment$"
errmsg12 db "Number too big$"
errmsg13 db "Alias not in list$"
errmsg14 db "Error using Int 2Fh$"
endmsg db 13,10,"$"

shiftmsg db "S-$"
altmsg db "A-$"
ctlmsg db "C-$"

file_linecount dw 0 ;Line number being processed.
caps_flag db 0
param_found db 0 ;Cmd line parameter found flag
append_cr db 0 ;Append cr to alias flag
cmdcom_name db "COMMAND" ;Name of command.com

cmd_switches db "sfeldbum*/" ;Letters of valid commands.
cmd_switch_end = $
cmd_jmp_tbl dw offset setstacksize ;This jump table is used to
dw offset loadaliasfile ; call the routines that
dw offset enablealias ; process the command line
dw offset listalias ; arguments
dw offset disablealias
dw offset setlistbuffer
dw offset remove
dw offset minstacklen
dw offset comment_line ;Comments can be indicated by
dw offset comment_line ; a /* or a //.

;----------------------------------------------------------------------------
; Initialization routine.
;----------------------------------------------------------------------------
initialize proc near
assume cs:code,ds:code,es:code
cld
mov ah,30h ;Get DOS version
int 21h
xchg al,ah ;Swap major, minor numbers
mov dx,offset errmsg0 ;Bad DOS version
cmp ah,2 ;Run if DOS 2.0 or greater.
jae init1
jmp_disp_error:
jmp disp_error
init1:
mov dos_version,ax ;Save version number

mov ah,4ah ;Reduce memory allocation to
mov bx,1000h ; just this segment.
int 21h

mov ax,offset end_of_code ;Initialize alias list
mov word ptr [aliaslist_ptr],ax ; pointers.
mov ax,cs
mov word ptr [aliaslist_ptr+2],ax
lds di,aliaslist_ptr ;Initialize alias list
mov ax,-1 ; by writing a -1 as
stosw ; an end flag.
mov aliaslist_end,di
;
;See if a copy is already resident in memory. If > DOS 3.0, use int 2Fh.
;
mov byte ptr [main+2],0 ;Initialize fingerprint
cmp dos_version,300h ;See if DOS 3.0 or later
jb find_copy1 ;No, search the old way.
mov cx,16 ;Try 16 different IDs.
find_copy:
xor ax,ax
mov es,ax
mov ah,multiplex_id ;Load ID. Use Int 2Fh to
int 2fh ; reach installed code so
or al,al ; that we are compatible
jne find_copy0 ; with 386 memory managers.
push cs
pop es ;If AL not changed, ALIAS not
jmp short find_copy4 ; installed.
find_copy0:
push cx
call cmpheader ;See if really Alias by
pop cx ; comparing file headers.
je find_copy3
inc multiplex_id ;ID used by another program.
loop find_copy ; Change and try again.
mov dx,offset errmsg14 ;All IDs taken, print error
jmp disp_error ; msg and exit.
;
;For DOS 2.x find the installed code the old fashioned way by scanning
;the memory control blocks.
;
find_copy1:
xor bx,bx ;zero BX for start
mov ax,cs ;keep CS value in AX
find_copy2:
inc bx ;increment search segment value
mov es,bx
assume es:nothing
cmp ax,bx ;not installed if current
je find_copy4 ; segment is found.
call cmpheader
jne find_copy2 ;loop back if not found
find_copy3:
inc alrdy_installed ;Set installed flag
find_copy4:
mov other_seg,es ;Save seg of installed code
;
;Parse the command line for switches.
;
mov ah,48h ;Allocate memory block for
mov bx,0800h ; alias file buffer.
int 21h
mov dx,offset errmsg8 ;Not enough memory msg
jc jmp_disp_error
mov databuff_seg,ax ;Save segment to file buffer.
mov es,ax ;Treat the command line as
xor di,di ; a 1 line file.
mov si,offset command_tail
xor cx,cx
or cl,[si] ;Get command line length
je parse_line_end ;If zero, skip parse routine
inc si ;Copy command line into file
inc cx ; buffer.
push cx
rep movsb
pop cx ;CX = file size.
xor si,si ;Point SI to start of buffer
push es
pop ds ;Set DS to file buffer seg
assume ds:nothing
mov es,cs:[other_seg] ;Set ES to installed code
;
;Parse command line and command files.
;
parse_line_loop:
xor bl,bl
call scanline ;Get 1st character
jc parse_2 ;If carriage return, skip line
cmp al,"/" ;Compare character to switch.
je parse_switch_found
cmp al,"?" ;See if help character
je parse_line_error
call setkey ;Must be alias definition
jc parse_error
mov param_found,1 ;Set parameter found flag
jmp short parse_2 ;Return to parse loop
parse_line_error:
mov dx,offset errmsg2 ;Command not found msg
parse_error: jmp short disp_error
parse_switch_found:
mov param_found,1 ;Set parameter found flag
lodsb ;Get command line switch
dec cx
cmp al,'A' ;Convert to lower case if
jb parse_1 ; necessary.
cmp al,'Z'
ja parse_1
or al,20h
parse_1:
push cx ;Scan the list of allowable
push es ; command switches. If switch
push cs ; found, use its position for
pop es ; an index into the list of
mov di,offset cmd_switches ; routines.
mov cx,offset cmd_switch_end - offset cmd_switches
mov bx,offset cmd_switch_end - offset cmd_switches - 1
repne scasb
mov ax,cx ;Copy index into list
pop es
pop cx
jne parse_line_error
sub bx,ax ;Compute offset into list
shl bx,1 ;Convert to word offset
add bx,offset cmd_jmp_tbl ;Add the start addr of table.
call cs:[bx] ;Call command routine.
jc disp_error ;If error terminate parse.
parse_2:
jcxz parse_line_end ;If at file end, exit parse.
jmp short parse_line_loop
;
;See if installed. If not, install.
;
parse_line_end:
cmp cs:[param_found],1 ;See if any parameters found
je init2 ;If already installed and
cmp cs:[alrdy_installed],0 ; no parameters on the
je init2 ; command line, default to
mov es,cs:[other_seg] ; showing program information
call listalias
init2:
mov ah,49h ;Release memory block used
mov es,cs:[databuff_seg] ; for file buffer.
int 21h
push cs
pop ds
assume ds:code
mov word ptr databuff_seg,0
cmp alrdy_installed,0 ;If not already installed,
je install ; jump to install routine.
exit:
mov ax,4C00h ;Terminate with RC = 0
int 21h
;
;Display error message.
;
disp_error:
xor ax,ax ;If file buffer still
or ax,databuff_seg ; allocated, deallocate it.
jz disp_error0
mov ah,49h ;Release memory block used
mov es,ax ; for file buffer.
int 21h
disp_error0:
push cs
pop ds
assume ds:code
cmp byte ptr filenam_field,0
je disp_error1 ;If processing a file, print
push dx ; a message informing the
mov dx,offset filemsg1 ; user the filename being
call printmsg ; processed and the line
mov ax,file_linecount ; that the error occured.
call hex2asc
mov dx,offset filemsg2
call printmsgcr
pop dx
disp_error1:
call printmsgcr ;print string
mov ax,4c01h ;Terminate with RC = 1
int 21h
;
;Install routine. Find segment of COMMAND.COM, hook into int 21h, 2Fh and TSR.
;
assume ds:code
install:
mov dx,offset program ;Display copyright message
call printmsg

push ds ;Save DS
xor ax,ax ;Then zero it
mov ds,ax
mov cs:[points],ax ;Record number of scan lines
mov ax,ds:[0460h] ; per character and cursor
mov cs:[cursor_mode],ax ; mode
pop ds ;Restore DS

mov byte ptr filenam_field,0 ;Don't callout file on error
mov ah,52h ;get address of first MCB
int 21h
mov ax,es:[bx-2] ;point ES to MCB
mov cx,20 ;Allow only 20 loops.
mcb_loop:
mov es,ax
cmp byte ptr es:[0],"M" ;check for mcb signature
jne mcb_error
inc ax ;point AX to memory block
cmp ax,es:[1] ;See if this is a PSP block
je psp_found
mcb_continue:
add ax,es:[3] ;Get size of memory block
loop mcb_loop
mcb_error:
mov dx,offset errmsg7 ;Can't locate command.com PSP
jmp disp_error
psp_found:
cmp dos_version,0400h ;If DOS 4.00 or greater,
jb psp_found_1 ; COMMAND.COM may not be the
push ds ; first program loaded. Look
mov si,offset cmdcom_name ; at the name of the program
mov di,8 ; stored in the last 8 bytes
mov cx,7 ; of the memory control
repe cmpsb ; block. If the string
pop ds ; "COMMAND" isn't found, keep
jne mcb_continue ; looking.
psp_found_1:
mov cmdcom_psp,ax ;Save segment of cmd.com PSP
mov es,ax
mov ax,es:[2ch] ;Get seg of master environment
mov master_env,ax
;
;Set up pointers to the cmd stack and to move the alias list to the end of the
;command stack so it takes up less space when ALIAS resident.
;
mov di,mystack_ptr ;Get base of internal stack
mov work_buff_ptr,di ;Copy ptr to alias buffer
add di,128 ;Add size of buffer
mov cmdstack_base,di ;Copy for start of cmd stack
mov ax,cmdstack_size ;Get size of command stack
mov ah,128 ;128 bytes for each entry
mul ah
add di,ax ;Add to cmd stack for
mov si,word ptr aliaslist_ptr ; start of the
mov cx,aliaslist_end ; alias list.
mov word ptr aliaslist_ptr,di ;Save new pointer.
sub cx,si ;Compute size of list.
mov dx,di ;See if we have enough room
add dx,cx ; for everything in one seg.
jnc install_1
mov dx,offset errmsg10 ;Not enough memory, exit.
jmp disp_error
install_1:
add dx,alias_buffer ;Add additional space for list
mov aliaslist_size,dx ;Save pointer to end of seg
add dx,15 ;Convert memory needed to
shr dx,1 ; paragraphs.
shr dx,1
shr dx,1
shr dx,1
cmp di,si ;Check for overlap in the move
jb install_2 ;If overlap, copy list from
std ; the top down to avoid
add di,cx ; overwriting the list.
add si,cx
dec si
dec di
;
;Revector interrupts 21h and 2Fh (if necessary).
;
install_2:
mov ax,3521h ;Get interrupt 21 (DOS)
int 21h ; vector.
mov word ptr [int21h],bx
mov word ptr [int21h+2],es
push dx ;Save memory size parameter
mov ax,2521h ;Point int 21 to internal
mov dx,offset dosint ; routine.
int 21h

cmp dos_version,300h ;See if we are using Int 2Fh
jb install_3
mov ax,352fh ;Get interrupt 2F (MUX)
int 21h ; vector.
mov word ptr [int2fh],bx
mov word ptr [int2fh+2],es
mov ax,252fh ;Point int 2F to internal
mov dx,offset muxint ; routine.
int 21h
install_3:
pop dx
push ds ;ES = DS
pop es
jmp final_install ;Jump to safe place for move.
initialize endp

;-----------------------------------------------------------------------------
; CMPHEADER compares the first 16 bytes of this file with the segment
; pointed to by ES.
; Entry: DS - code segment
; ES - pointer to segment to compare
; Exit: ZF - 0 = segments match.
;-----------------------------------------------------------------------------
cmpheader proc near
mov si,offset main+2 ;Search this segment for ASCII
mov di,si ; fingerprint.
mov cx,16
repe cmpsb
ret
cmpheader endp

;-----------------------------------------------------------------------------
; PRINTMSG prints the message pointed to by DX to the screen.
; Entry: DX - pointer to ASCII message terminated by $
;-----------------------------------------------------------------------------
printmsg proc near
assume ds:nothing,es:nothing
push ds
push cs
pop ds
assume ds:code
mov ah,9 ;Print message
int 21h
pop ds
ret
printmsg endp

;-----------------------------------------------------------------------------
; PRINTMSGCR calls PRINTMSG, then appends a carriage return to the message.
; Entry: DX - pointer to ASCII message terminated by $
;-----------------------------------------------------------------------------
printmsgcr proc near
assume ds:nothing,es:nothing
push dx
call printmsg
mov dx,offset endmsg
call printmsg
pop dx
ret
printmsgcr endp

;-----------------------------------------------------------------------------
; SETSTACKSIZE - Sets the size of the command line stack.
; Entry: DS:SI - points to stack size in ascii
; Exit: CF - Clear if sucessful, Set if error, DX points to error msg.
;-----------------------------------------------------------------------------
setstacksize proc near
assume ds:nothing,es:nothing
xor bl,bl ;Check for installed code
call setparameter ;Get num and convert to binary
jc setstack_exit ;Check for error
mov cs:[cmdstack_size],ax ;Save parameter
setstack_exit:
ret
setstacksize endp

;-----------------------------------------------------------------------------
; SETLISTBUFFER - Sets the size of the additional buffer reserved for alias
; list expansion.
; Entry: DS:SI - points to buffer size in ascii
; Exit: CF - Clear if sucessful, Set if error, DX points to error msg.
;-----------------------------------------------------------------------------
setlistbuffer proc near
assume ds:nothing,es:nothing
xor bl,bl ;Check for installed code
call setparameter ;Get num and convert to binary
jc setlistbuffer_exit ;Check for error
mov cs:[alias_buffer],ax ;Save buffer size parameter
setlistbuffer_exit:
ret
setlistbuffer endp

;-----------------------------------------------------------------------------
; MINSTACKLEN - sets the minimum legth of a command to stack.
; Entry: ES - segment of the installed code
; DS:SI - points to buffer size in ascii
; Exit: CF - Clear if sucessful, Set if error, DX points to error msg.
;-----------------------------------------------------------------------------
minstacklen proc near
assume ds:nothing,es:nothing
mov bl,1 ;Don't check for installed code
call asc2bin ;Get num and convert to binary
jc minstacklen_exit ;Check for error
cmp al,126
jb minstacklen_1
mov dx,offset errmsg12 ;Stack length too big
stc
jmp short minstacklen_exit
minstacklen_1:
or al,al ;Make sure min length is not
jne minstacklen_2 ; specified at 0. If so,
inc al ; change to 1.
minstacklen_2:
mov es:[minlength],al ;Save minimum length parameter
minstacklen_exit:
ret
minstacklen endp

;-----------------------------------------------------------------------------
; SETPARAMETER - Common code used by the set stack and set buffer and set
; minimum command length routines.
; Entry: DS:SI - points to ascii number
; BL - Flag to indicate check for installed code, BL=0, check.
; Exit: CF - Clear if sucessful, Set if error.
;-----------------------------------------------------------------------------
setparameter proc near
assume ds:nothing,es:nothing
mov dx,offset errmsg4 ;Can't change parameter msg
cmp cs:[alrdy_installed],1 ;If already installed don't
je setparam_error ; change parameter.
call asc2bin
setparam_exit:
ret
setparam_error:
stc ;Set error flag.
jmp short setparam_exit
setparameter endp

;-----------------------------------------------------------------------------
; SETKEY modifies the alias list to add function key definitions.
; Entry: DS:SI - pointer to string identifing the function key
; ES - pointer to segment of installed code
; Exit: CF - clear if successful
;-----------------------------------------------------------------------------
setkey proc near
assume ds:nothing,es:nothing
push es
cmp al,"[" ;Determine alias or key
je setkey_1
dec si ;Backup before last key
inc cx
jmp short setkey_5
setkey_1:
lodsb ;Get next character
dec cx
jcxz setkey_badkey
mov bx,58 ;Load default F1 keycode
or al,20h ;Convert to lower case
cmp al,"f"
je setkey_3
add bx,25 ;Assume shift F1 keycode
cmp al,"s"
je setkey_2
add bx,10 ;Assume ctl F1 keycode
cmp al,"c"
je setkey_2
add bx,10 ;Assume alt F1 keycode
cmp al,"a"
jne setkey_badkey
setkey_2:
lodsb ;Get next character
dec cx
or al,20h ;Convert to lower case
cmp al,"f" ;Make sure next key is "f"
jne setkey_badkey
setkey_3:
call asc2bin
jc setkey_badkey ;If bad number, exit
or ax,ax
je setkey_badkey ;Make sure not zero
cmp ax,10
ja setkey_badkey ;Make sure less than 10
cmp byte ptr [si-1],"]" ;Check for closing bracket
jne setkey_badkey ; if not found, error
add bx,ax ;Add in function key number
cmp byte ptr [si]," " ;Check to see if a character
jbe setkey_4 ; trails the closing bracket.
cmp byte ptr [si],"*" ;Check to see if an * is
jne setkey_badkey ; appended to the function
lodsb ; key assignment. If so,
dec cx ; remove key and set flag
mov cs:[append_cr],1 ; to append cr to command.
setkey_4:
sub si,2 ;Back up to keycode.
xor bh,bh
mov ds:[si],bx ;Save keycode on command line
add cx,2
setkey_5:
call setalias ;Use SETALIAS to load
setkey_exit:
pop es ;Restore ptr to installed seg
ret
setkey_badkey:
mov dx,offset errmsg11 ;Bad key assignment msg
stc
jmp setkey_exit
setkey endp


;-----------------------------------------------------------------------------
; SETALIAS modifies the alias list according to command line agruments.
; Entry: DS:SI - pointer to string to be inserted into alias list.
; ES - pointer to segment of installed code.
; Exit: CF - clear if successful
;-----------------------------------------------------------------------------
setalias proc near
assume ds:nothing,es:nothing
push es
xor bl,bl ;Find 1st character on
call scanline ; command line.
jnc setalias_1 ;If at end of line, exit
jmp setalias_exit ; routine.
setalias_1:

;
;Get length of alias, then search list for matching alias
;
dec si ;Backup to before 1st char.
inc cx
mov byte ptr cs:[alias_inlist],0 ;Assume not in list
call searchalias ;Is there already an alias?
jc setalias_2 ;No, continue.
inc byte ptr cs:[alias_inlist]
;
;If in list, erase old alias from list.
;
call delete_aliasent ;Delete entry from list
setalias_2:
;
;Append new alias to the end of the list.
;
mov bp,di ;Save ptr to end of list.
add di,4 ;Move past length fields.
push es ;Get max size of alias list.
mov es,cs:[other_seg]
mov dx,es:[aliaslist_size]
pop es
;
;Append alias to list.
;
xor ax,ax ;Clear character counter
setalias_3:
lodsb ;Get byte
dec cx ;Decriment buffer counter.
jcxz setalias_4 ;If at end of file, exit.
cmp al,13 ;See if at end of line.
jne setalias_6 ;No, continue.
setalias_4:
cmp byte ptr cs:[alias_inlist],0
jne setalias_5 ;Was alias in list?
jmp setalias_notnfil ;No, incomplete alias specifed
setalias_5:
jmp setalias_exit ;Yes, alias simply erased.
setalias_6:
cmp al,' ' ;See if at end of tag.
je setalias_8 ;Yes, exit copy loop
cmp al,9 ;Check for tab
je setalias_8
cmp di,dx ;See if alias list is full
jbe setalias_7 ;No, continue
jmp setalias_full ;Yes, exit routine
setalias_7:
stosb ;No, add character to list
inc ah ;Inc size of tag
jmp short setalias_3
setalias_8:
mov es:[bp+2],ah ;Save size of alias
;
;Append command to alias list.
;
mov cs:[caps_flag],0 ;Clear environment var flag.
xor bx,bx ;Find 1st character in
call scanline ; command.
jc setalias_exit ;If no command, exit
xor ah,ah ;Clear character counter
setalias_9:
cmp al,"%" ;Check for environment var
jne setalias_11 ; by checking for % signs.
cmp cs:[caps_flag],0 ;If caps flag set capitialize
jne setalias_10 ; string before saving.
mov bl,ds:[si] ;Get next character
cmp bl,"0" ;If numberic, assume this is
jb setalias_10 ; a line parameter, not an
cmp bl,"9" ; environment variable so
jbe setalias_11 ; don't set caps flag.
cmp bl,"%" ;Don't let double % signs
je setalias_11 ; indicate environment var.
setalias_10:
not byte ptr cs:[caps_flag] ;Toggle caps flag
setalias_11:
cmp cs:[caps_flag],0 ;Capitialize environment
je setalias_12 ; variables so they will
cmp al,"a" ; match when searched for in
jb setalias_12 ; the environment block.
cmp al,"z"
ja setalias_12
and al,0dfh ;Make character uppercase.
setalias_12:
cmp di,dx ;See if alias list is full
ja setalias_full ;Yes, exit routine
stosb ;Append character on list
inc ah ;Inc character counter.
jcxz setalias_13 ;Check for end of file.
lodsb ;Get next character
dec cx ;Dec file counter.
cmp al,13 ;See if carriage return.
jne setalias_9 ;If not continue
setalias_13:
cmp cs:[append_cr],1 ;If flag set, append carrage
jne setalias_14 ; return to command.
mov al,13
inc ah
stosb
mov cs:[append_cr],0 ;Clear flag
setalias_14:
mov es:[bp+3],ah ;Save command size
mov word ptr es:[di],-1 ;Set new end of list flag
mov ax,di ;Save end pointer to list
add ax,2 ;Make room for the end flag.
mov cs:[aliaslist_end],ax
sub di,bp ;Compute size of entry
mov es:[bp],di ;Put size over old end flag.
inc cs:[file_linecount] ;Point counter to next line.
setalias_exit:
clc
setalias_exit1:
pop es ;Restore ptr to installed seg
ret
setalias_full:
mov dx,offset errmsg9 ;Alias list too large msg.
stc
jmp short setalias_exit1
setalias_notnfil:
mov dx,offset errmsg13 ;Alias not in list.
stc
jmp short setalias_exit1
setalias endp

;-----------------------------------------------------------------------------
; DELALIASENTRY - Deletes an alias entry
; Entry: DS:SI - pointer to the entry in the alias list to delete
; Exit: CF - clear if successful
;-----------------------------------------------------------------------------
delete_aliasent proc near
push cx ;Save registers
push si
push ds ;Yes, remove entry from list
push es ; by moving the remainder of
pop ds ; the list over this entry.
mov si,es:[di] ;Point SI to the next list
add si,di ; entry.
delent_1:
cmp word ptr es:[si],-1 ;Check for the end of the list
je delent_2
mov cx,es:[si] ;Get size of entry
rep movsb ;Copy next entry over current
jmp short delent_1 ; entry.
delent_2:
mov word ptr es:[di],-1 ;Set end of list indicator
pop ds ;Get back file buffer pointer
pop si
pop cx
ret
delete_aliasent endp

;-----------------------------------------------------------------------------
; LOADALIASFILE loads a file containing a list of alias commands.
; Entry: DS:SI - pointer to the name of the file to open
; exit: CX - size of the file in bytes
; CF - clear if successful
;-----------------------------------------------------------------------------
loadaliasfile proc near
assume ds:nothing,es:nothing
xor bl,bl
call scanline ;Find 1st char of filename.
mov dx,si ;Copy filename pointer
inc bl ;Find end of filename
call scanline
mov byte ptr [si-1],0 ;Make filename ASCIIZ.
dec dx
mov ax,3d00h ;Open file (Read only)
int 21h
jc loadfile_error
mov bx,ax ;Copy file handle
;
;Save the name of the file for error messages.
;
push si
push es
mov di,offset filenam_field
push cs
pop es
mov si,dx
loadfile_1:
lodsb
stosb
or al,al
jne loadfile_1
mov byte ptr es:[di-1],"$" ;Terminate string with $.
pop es
pop si
;
;Open file and read contents into file buffer.
;
mov ah,3fh ;Read alias file
xor dx,dx ;Pont to base of file buffer.
mov cx,07f00h ;Read up to 32512 bytes.
int 21h
mov si,ax
mov byte ptr ds:[si],13 ;Append a CR to end of file.
mov cx,ax ;Save new file size
xor si,si ;Reset file pointer.
mov ah,3eh ;Close file.
int 21h
mov cs:[file_linecount],1 ;Reset line counter.
loadfile_exit:
clc
loadfile_exit1:
ret
loadfile_error:
stc
mov dx,offset errmsg6 ;Bad filename specified.
jmp short loadfile_exit1
loadaliasfile endp

;-----------------------------------------------------------------------------
; LISTALIAS prints the alias list to screen.
; Entry: ES - segment of the installed code
;-----------------------------------------------------------------------------
listalias proc near
assume ds:nothing,es:nothing
push ds
;
;Print Command stack size and amount of alias buffer space remaining
;
mov dx,offset infomsg2 ;Print size of command stack
call printmsg
mov ax,es:[cmdstack_size] ;Get size of command stack
call hex2asc ;Print size
mov dx,offset infomsg3 ;Print min cmd length
call printmsg
xor ax,ax
mov al,es:[minlength] ;Get min cmd length to stack
call hex2asc ;Print length
mov dx,offset infomsg4 ;Print label to buffer size
call printmsg
lds si,es:[aliaslist_ptr] ;Get pointer to alias list
listalias_1:
cmp word ptr [si],-1 ;Scan through alias list to
je listalias_2 ; find the end of the list.
add si,[si] ;Point to next entry
jmp short listalias_1
listalias_2:
mov ax,es:[aliaslist_size] ;Get offset to end of buffer
sub ax,si ;Subtract end of alias list
sub ax,2 ;Correct for end pointer
call hex2asc ;Print size
mov dx,offset infomsg5 ;Indicate if alias translation
call printmsg ; is enabled or disabled
mov dx,offset infomsg5d ;Disabled message
cmp byte ptr es:[chk_alias],0 ;See if alias enabled
je listalias_3
mov dx,offset infomsg5e ;Enabled message
listalias_3:
call printmsg
;
;Scan through alias list to print function key assignments
;
xor dx,dx ;Clear alias found flag
lds si,es:[aliaslist_ptr] ;Get pointer to alias list
listalias_4:
cmp word ptr [si],-1 ;Check for end of list
jne listalias_5
jmp listalias_11
listalias_5:
mov bx,si ;Save pointer to entry.
cmp byte ptr [si+5],0 ;See if key assignment
je listalias_6 ;If so, skip entry
or dh,1 ;Set alias found flag
add si,[bx] ;Point to next entry
jmp short listalias_4
listalias_6:
;
;Convert scan code into function key label
;
test dh,80h ;See if first time though
jne listalias_7
push dx
mov dx,offset infomsg6 ;If first time print header
call printmsgcr
pop dx
or dh,80h ;Set header printed flag
listalias_7:
call printtab
push dx
add si,4 ;Point SI to command string
mov al,[si] ;Get key code
mov dh,al
cmp al,84 ;Check for base code
jb listalias_9
sub dh,25
mov di,offset shiftmsg ;Assume shift prefix
cmp al,94 ;Check for shift
jb listalias_8
sub dh,10
mov di,offset ctlmsg ;Assume control prefix
cmp al,104 ;Check for ctl
jb listalias_8
mov di,offset altmsg ;Assume alt prefix
sub dh,10
listalias_8:
push dx ;Print prefix identifier
mov dx,di
call printmsg
pop dx
listalias_9:
mov dl,"F" ;Set function key
mov ah,2 ;Character output
int 21h
mov al,dh ;Get modified key code
sub al,58 ;Convert from scan code to hex
xor ah,ah
call hex2asc ;Print function key number
mov cl,[bx+3] ;Get length of command
inc si ;Point SI to command string
inc si
mov di,bx
add di,[bx]
cmp byte ptr [di-1],13 ;Check for carrage return
jne listalias_10 ; after command. If found,
mov dl,'*' ; indicate immediate command
mov ah,2 ; by appending an * to the
int 21h ; end of the function key.
listalias_10:
call printtab
call printtab
call print_string ;Print command to screen
mov dx,offset endmsg ;Append carriage return to
call printmsg ; advance to next line. SI
pop dx ; points to the next entry.
jmp listalias_4
;
;Scan through alias list to print aliases.
;
listalias_11:
test dh,1 ;See if any aliases found
je listalias_exit ;If no aliases, skip remainder
mov dx,offset infomsg7 ;Print header
call printmsgcr
xor cx,cx ;Clear CX
lds si,es:[aliaslist_ptr] ;Get pointer to alias list
listalias_12:
mov bx,si ;Save pointer to entry.
cmp byte ptr [si+5],0 ;See if key definition
jne listalias_13 ;If so, skip entry
add si,[bx]
jmp short listalias_14
listalias_13:
call printtab
add si,4 ;Point SI to alias string
mov cl,[bx+2] ;Get length of alias
call print_string ;Print alias to screen
call printtab
call printtab
mov cl,[bx+3] ;Get length of command
call print_string ;Print command to screen
mov dx,offset endmsg ;Append carriage return to
call printmsg ; advance to next line.
listalias_14:
cmp word ptr [si],-1 ;Check for end of list. SI
jne listalias_12 ; points to the next entry.
listalias_exit:
mov dx,offset infomsg8 ;Print pointer to help msg
call printmsgcr
pop ds
clc
ret
listalias endp

;-----------------------------------------------------------------------------
; PRINTTAB prints a TAB character to the screen.
; Entry: ES - segment of the installed code
;-----------------------------------------------------------------------------
printtab proc near
assume ds:nothing,es:nothing
mov ah,2 ;Character output
mov dl,9 ;Print TAB character
int 21h
ret
printtab endp

;-----------------------------------------------------------------------------
; ENABLEALIAS enables alias translation.
; Entry: ES - segment of the installed code
;-----------------------------------------------------------------------------
enablealias proc near
assume ds:nothing,es:nothing
mov byte ptr es:[chk_alias],1 ;Enable alias
clc
ret
enablealias endp

;-----------------------------------------------------------------------------
; DISABLEALIAS disables alias translation.
; Entry: ES - segment of the installed code
;-----------------------------------------------------------------------------
disablealias proc near
assume ds:nothing,es:nothing
mov byte ptr es:[chk_alias],0 ;Disable alias
clc
ret
disablealias endp

;-----------------------------------------------------------------------------
; REMOVE uninstalls the installed program from memory.
;-----------------------------------------------------------------------------
remove proc near
assume ds:nothing,es:nothing
push ds
mov dx,offset errmsg1 ;Not installed msg
cmp cs:[alrdy_installed],0 ;See if installed
je remove_exit ;Not installed, error

mov cx,cs:[other_seg] ;Get segment of installed code
mov ax,3521h ;Get DOS vector
int 21h
mov ax,es ;Check to make sure DOS
cmp ax,cs:[other_seg] ; vector not modified.
jne remove_error

lds dx,es:[int2fh] ;Get old interrupt 2F vector
cmp dx,-1 ;See if Int used
je remove_1 ;No, skip check of Int 2F
mov ax,352fh ;Get MUX vector
int 21h
mov ax,es ;Check to make sure MUX
cmp ax,cs:[other_seg] ; vector not modified.
jne remove_error
mov ax,252fh ;Set interrupt
int 21h
remove_1:
lds dx,es:[int21h] ;Get old interrupt 21 vector
mov ax,2521h ;Set interrupt
int 21h
mov cx,es:[env_segment]
mov ah,49h ;Free memory block
int 21h
mov es,cx ;Free environment block
mov ah,49h
int 21h
mov dx,offset infomsg1 ;Indicate uninstalled.
mov byte ptr filenam_field,0 ;Clear filename field
remove_exit:
stc
pop ds
remove_exit1: ret
remove_error:
mov dx,offset errmsg3 ;Can't remove error msg
jmp short remove_exit

remove endp

;-----------------------------------------------------------------------------
; COMMENT_LINE allows comments in the alias file by skipping to the next
; carriage return.
; Entry: SI - pointer to ASCII string
; CX - file length
;-----------------------------------------------------------------------------
comment_line proc near
assume ds:nothing,es:nothing
comment_loop:
push es
push ds
pop es
mov di,si ;Copy file pointer
mov al,13 ;Scan for carriage return.
repne scasb
inc cs:[file_linecount] ;Inc file line counter.
mov si,di ;Restore file pointer.
pop es
clc
ret
comment_line endp

;-----------------------------------------------------------------------------
; HEX2ASC converts a binary number to ASCII and prints it to the screen.
; Entry: AX - binary number
;-----------------------------------------------------------------------------
hex2asc proc near
assume ds:nothing,es:nothing
push bx
mov cx,5 ;Allow max of five digits
hex_loop1:
xor dx,dx ;Clear high word
mov bx,10 ;Load number base
div bx ;Divide by base (10)
add dl,30h ;Convert to ascii
push dx ;Save digit on stack
loop hex_loop1
mov cx,5 ;Allow max of five digits
mov bl,"0" ;Set leading zero indicator
hex_loop2:
pop dx ;Get digit off stack
or bl,dl ;Don't print leading zeros.
cmp bl,"0" ;The first non zero will
je hex_1 ; change bl to non-zero.
mov ah,2 ;DOS character output
int 21h
hex_1:
loop hex_loop2
hex_exit:
pop bx
ret
hex2asc endp

;-----------------------------------------------------------------------------
; ASC2BIN - converts an ASCII number of the command line to hex.
; Entry: DS:SI - pointer to ASCII number
;-----------------------------------------------------------------------------
asc2bin proc near
push bx
xor bl,bl
call scanline ;Find next character.
mov di,offset errmsg5 ;Bad number message
jc asc_error ;If no number found, error
mov bl,al ;Copy first digit.
xor ax,ax ;Clear out sum
xor bh,bh ;Clear high byte for word adds
asc_loop:
cmp bl," " ;If space, assume end of
jbe asc_exit ; number.
cmp bl,"]" ;Exit if closing bracket
je asc_exit ; encountered
sub bl,"0" ;Check for valid number then
jb asc_error ; convert to binary.
cmp bl,9
ja asc_error
mov dx,10 ;DX holds base multiplier
mul dx ;Shift over current number
jc asc_overflow ;If overflow, indicate error
add ax,bx ;Add new digit to sum.
jcxz asc_exit ;If end of file, exit.
mov bl,ds:[si] ;Get next ASCII character
inc si ;Point to next character
dec cx ;Dec file size counter
jmp short asc_loop ;Go back for more
asc_exit:
clc ;Clear error flag.
asc_exit1:
pop bx
ret
asc_overflow:
mov di,offset errmsg12 ;Number too large message.
asc_error:
mov dx,di ;Copy message pointer.
stc ;Set error flag.
jmp short asc_exit1
asc2bin endp
;-----------------------------------------------------------------------------
; SCANLINE performs the same function as SCAN4CHAR but keeps track of the
; carriage returns.
; Entry: SI - pointer to ASCII string
; BL - 0 = find next char, 1 = find next space
; CX - file length
; Exit: AL - first nonspace character
; CF - set if carriage return found
;-----------------------------------------------------------------------------
scanline proc near
call scan4char ;Find the next char.
jnc scanline_exit
inc cs:[file_linecount] ;Point to next line.
stc
scanline_exit:
ret
scanline endp

end_of_code = $
code ends

end main


  3 Responses to “Category : Files from Magazines
Archive   : VOL8N22.ZIP
Filename : ALIAS.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/