dos_compilers/Microsoft C v4/STDARGV.ASM
2024-07-01 10:35:17 -07:00

447 lines
8.1 KiB
NASM

title stdargv - standard _setargv routine
;--------------------------------------------------------------------------
;
; Microsoft C Compiler Runtime for MS-DOS
;
; (C)Copyright Microsoft Corporation, 1984, 1986
;
;--------------------------------------------------------------------------
?DF = 1 ; tell cmacros.inc we want to define our own segments
include version.inc
.xlist
include cmacros.inc
include msdos.inc
include brkctl.inc
.list
createSeg _TEXT, code, byte, public, CODE, <>
createSeg _DATA, data, word, public, DATA, DGROUP
createSeg HDR, nhdr, byte, public, MSG, DGROUP
createSeg MSG, nmsg, byte, public, MSG, DGROUP
createSeg PAD, npad, byte, common, MSG, DGROUP
createSeg EPAD, nepad, byte, common, MSG, DGROUP
defGrp DGROUP ; define DGROUP
codeOFFSET equ offset _TEXT:
dataOFFSET equ offset DGROUP:
TAB = 9 ; tab character
sBegin data
assumes ds,data
externW _psp ; psp segment #
externB _osmajor ; os major version #
externDP __argv ; argv address
externW __argc ; argc
externW _abrktb ; break table
externW _asizds ; break table end
globalW __argl,0 ; total length of arguments ( expanded )
staticDP argptr,0
sEnd data
ifdef wildcard
externP _cwild ; the wildcard expander
endif
;msg used by stdargv (wild card version of _setargv)
sBegin nmsg
assumes ds,data
dw 8
db 13,10,'error 2008: Not enough space for arguments',13,10,0
sEnd
sBegin code
assumes cs,code
assumes ds,data
externNP _myalloc ; allocation routine for arguments
cProc _setargv,<PUBLIC>,<>
cBegin
mov ax,1
mov [__argc],ax ; start argc at one for this tacky patch
push ax
call near ptr _wsetargv
inc sp
inc sp
mov ax,2
push ax
call near ptr _wsetargv
inc sp
inc sp
cEnd
cProc _wsetargv,<NEAR>,<>
parmw pass
localW endarg
cBegin
push ds ; save ds, it gets trashed
assumes ds,data
assumes ss,data
cmp pass,2
jne apass1
push bp ; save bp for endarg
mov bp,[__argc]
inc bp
if sizeD
shl bp,1
endif
shl bp,1
mov ax,[__argl]
add ax,bp
; Register usage at this point:
; ax = total # bytes needed for argument ptr table and strings
; bp = # bytes required to store arg ptr table
mov di,8 ; no space for arguments message if death.
call _myalloc
; bp points to arg table
; ax is size of arg table in bytes.
mov word ptr [__argv],bp
mov word ptr [argptr],bp
if sizeD
mov word ptr [__argv+2],ds
mov word ptr [argptr+2],ds
endif
add ax,bp
pop bp ; recover bp for endarg
push ax ; Save pointer to string section
apass1:
; move command line at (psp:80) to memory
cmp __osmajor,3
pushf ; save flags for later if too old to get argv[0]
mov ds,[_psp] ; get psp segment
mov si,DOS_CMDLINE ; point to command line
lodsb ; get length
cbw ; and convert to word
mov endarg,ax ; store length of command line in endarg
add endarg,si ; put last character position of si in
; endarg to stop scan.
popf ; recover flags for age test.
push ax ; save length
jae ageok
pop ax
call saveargptr
jmp tooold ; if < dos 3.0
ageok:
mov es,ds:[DOS_ENVP] ; envp seg addr
xor ax,ax ; 0
mov cx,ax
not cx ; -1
mov di,ax ; 0
again:
repne scasb ; find null
cmp es:[di],al ; env null?
jne again ; no
add di,3 ; to get to argv[0]
mov cx,ax
not cx ; -1
push di
repne scasb ; search for argv[0] null & get length
pop si ; start of argv[0]
inc cx ; cx=-len(argv[0])
inc cx ; cx=-len(argv[0])
neg cx ; cx=+len(argv[0])
pop dx ; len(argv[1]+...+argv[n])
call saveargptr
mov ax,dx
add ax,cx ; +len(argv[0])
add ax,3 ; account for null, and rounding
and ax,not 1 ; rounded even
cmp pass,1 ; size up the total length of all the argv's
jne apass2
mov bx,sp ; get old data pointer back
mov ds,ss:[bx]
add [__argl],ax
mov ds,[_psp]
jmp short epass1
apass2:
mov ds,ds:[DOS_ENVP]
rep movsb ; move argv[0]
xor al,al ; space & null following argv[0]
stosb
mov cx,dx ; len(argv[1]+...+argv[n])
call recoverds
mov ds,[_psp]
mov bx,ax
epass1:
mov si,DOS_CMDLINE+1 ; restore si for command line move
jmp short nextarg
tooold:
cmp pass,1
jne bpass2
mov cx,ax ; save length
add al,4 ; pad for 'C ', term and rounding
and al,not 1 ; round even
mov bx,sp ; get old data pointer back
mov ds,ss:[bx]
mov es,ss:[bx]
add [__argl],ax ; increment length of the string section
mov ds,[_psp] ; recover psp segment
jmp short nextarg
bpass2:
mov ax,'C'shl 8 + ' '
stosw
xor ax,ax
stosb
; crack command line arguments onto stack
nextarg:
xor cx,cx
lodsb ; get next char
cmp si,endarg ; check for eoln
jbe cont ; eoln not found
jmp endline ; eoln found
cont:
call iswhite ; is it white space
jz nextarg ; yes - keep skipping
dec si ; point to 1st character
ifdef wildcard
mov dx,si ; save beginning of arg for wildcard
endif
cmp pass,2 ; put entry in argv array
jne gpass1
mov es:[bx],di ; argv entry is es:di
add bx,2
if sizeD
mov es:[bx],es
add bx,2
endif
jmp short notspace
gpass1:
call recoverds
inc [__argc] ; bump arg count
mov ds,[_psp] ; and ds back again
mov bx,ax
notspace:
lodsb ; get next char
ifdef wildcard
call iswild
endif
call isquote
cmp pass,2
jne hpass1
stosb
hpass1:
cmp si,endarg ; check for end of line
ja eoln ; yes
call iswhite ; is it white space
jnz notspace ; no - keep skipping
eoln:
cmp pass,2
jne ipass1
mov byte ptr es:[di-1],0 ; zero terminate arg
ipass1:
ifdef wildcard
cmp cx,100h ; only valid wildcard expansion
jne nowild
call recoverds
mov bx,ax
push ds:[_psp] ; pass [_psp]:si
push dx
push pass ; pass pass number
if sizeD
push ds ; pass char for argv
sub bx,4
else
sub bx,2
endif
mov word ptr [argptr],bx
push bx ; ignored for pass 1
call _cwild ; wildcard expander
if sizeD ; Clean up stack
add sp,10
mov es,dx
else
add sp,8
endif
mov bx,sp ; get old data pointer back
mov es,ss:[bx]
mov bx,ax ; get next available argument vect.
mov di,es:[bx] ; get next available string section
mov ds,[_psp]
nowild:
endif
jmp nextarg
endline:
cmp pass,2
jne zpass1
mov byte ptr es:[di-1],0 ; zero terminate arg
if sizeD ; end argv array with a null
mov word ptr es:[bx+2],0000
endif
mov word ptr es:[bx],0000
zpass1:
pop ds
cEnd
ifdef wildcard
iswild:
cmp al,'*' ; is it a star
je iswldret ; yes - exit
cmp al,'?' ; is it a question mark
jne wldret
iswldret:
mov ch,1
wldret:
ret ; return
endif
iswhite:
cmp al,TAB ; is it a TAB
je iswret ; yes - exit
cmp al,' ' ; is it a space
iswret:
ret ; return
isquote:
cmp al, '\' ; is this a backslash
jne normquote
cmp byte ptr ds:[si],'"' ; check for \" must do this this way to avoid
jne normquote ; a first char quote with the byte before it
ifdef wildcard
mov cl,1 ; disable wildcard
endif
lodsb ; just happening to be a backslash.
jmp short isqret
normquote:
cmp al, '"' ; is it a quote
jne isqret
ifdef wildcard
mov cl,1 ; disable wildcard
endif
notquote:
lodsb ; get next char
cmp al,13 ; check for eol
je isqret ; yes - early termination
cmp al,'"' ; ending quote
jne storeb ; no - keep scanning
cmp byte ptr ds:[si-2],'\' ; check for \"
jne endquote ; yes
dec di
storeb:
cmp pass,2
jne kpass1
stosb ; stuff char
kpass1:
jmp short notquote
endquote:
lodsb
jmp short isquote ; done with quotes
isqret:
ret ; return
saveargptr:
cmp pass,2
jne vpass1
mov bx,sp ; get old data pointer back
add bx,4
mov ds,ss:[bx]
pop es ; save return address
pop di
push es ; recover return address
mov es,ss:[bx]
mov bx,word ptr [argptr]
mov [bx],di
add bx,2
if sizeD
mov [bx],ds
add bx,2
endif
mov ds,[_psp] ; restore ds to _psp
vpass1:
ret
recoverds:
mov ax,bx
mov bx,sp ; get old data pointer back
mov ds,ss:[bx+2]
ret
sEnd code
end