Category : Assembly Language Source Code
Archive   : RHSTDLIB.ZIP
Filename : SCANF.ASM
assume cs:stdlib
extrn sl_print:far,sl_putw:far, sl_putcr:far
print macro
call sl_print
endm
;
extrn sl_gets:far, sl_free:far, sl_atoi2:far
extrn sl_atou2:far, sl_atol2:far, sl_atoul2:far
extrn sl_atoh2:far
;
;
; Scanf- Like the "C" routine by the same name. Calling sequence:
;
; call scanf
; db "format string",0
; dd item1, item2, ..., itemn
;
; The format string is identical to "C". Item1..Itemn are pointers to
; values to print for this string. Each item must be matched by the
; corresponding "%xxx" item in the format string.
;
; Format string format:
;
; 1) If a non-whitespace character in the format string matches the next
; input character, scanf eats that input character; otherwise scanf
; ignores the character in the format string. If any whitespace char-
; acter appears, scanf ignores all leading whitespace characters (new-
; line not included) before an item. If there is no whitespace on the
; input, scanf ignores the whitespace characters in the input stream.
;
; 2) Format Control Strings:
;
; General format: "%^f" where:
;
; ^ = ^
; f = a format character
;
; The "^" is optional.
;
; ^ present The address associated with f is the address of a
; pointer to the object, not the address of
; the object itself. The pointer is a far ptr.
;
; f is one of the following
;
; d - Read a signed integer in decimal notation.
; i - Read a signed integer in decimal notation.
; x - Read a word value in hexadecimal notation.
; h - Read a byte value in hexadecimal notation.
; u - Read an unsigned integer in decimal notation.
; c - Read a character.
; s - Read a string.
;
; ld- Read a long signed integer.
; li- Read a long signed integer.
; lx- Read a long hexadecimal number.
; lu- Read a long unsigned number.
;
;
; Calling Sequence:
;
; call Scanf
; db "Format String",0
; dd adrs1, adrs2, ..., adrsn
;
; Where the format string is ala "C" (and the descriptions above)
; and adrs1..adrsn are addresses (far ptr) to the items to print.
; Unless the "^" modifier is present, these addresses are the actual
; addresses of the objects to print.
;
; Note: Scanf always calls GETS to read a new string from the standard
; input device. Reading a string variable always reads all input
; from the current position to the end of the current line.
;
;
cr equ 0dh
ff equ 0ch
lf equ 0ah
tab equ 09h
bs equ 08h
;
RtnAdrs equ 2[bp]
OprndPtr equ -4[bp]
InputPtr equ -8[bp]
InpIndex equ -10[bp]
;
public sl_scanf
sl_scanf proc far
;
; Read a line from the standard input and save away a pointer to it.
;
push bp
mov bp, sp
sub sp, 10 ;Save ptr to operands here.
pushf
push ax
push bx
push cx
push dx
push di
push si
push es
push ds
;
call sl_gets
call scanf
les di, InputPtr
call sl_free
mov di, OprndPtr
mov RtnAdrs, di ;Put out new return address.
;
pop ds
pop es
pop si
pop di
pop dx
pop cx
pop bx
pop ax
popf
mov sp, bp ;Remove local variables.
pop bp
ret
;
sl_scanf endp
;
;
; SSCANF- Just like SCANF except you pass a pointer to the data
; string in es:di rather than having scanf read it from
; the keyboard.
;
public sl_sscanf
sl_sscanf proc far
push bp
mov bp, sp
sub sp, 10 ;Save ptr to operands here.
pushf
push ax
push bx
push cx
push dx
push di
push si
push es
push ds
;
call scanf
mov di, OprndPtr
mov RtnAdrs, di ;Put out new return address.
;
pop ds
pop es
pop si
pop di
pop dx
pop cx
pop bx
pop ax
popf
mov sp, bp ;Remove local variables.
pop bp
ret
sl_sscanf endp
;
;
; "Guts" of the scanf routines.
;
scanf proc near
mov InputPtr+2, es ;Sock away ptr to string.
mov InputPtr, di
mov word ptr InpIndex, 0
;
;
; Get pointers to the return address (format string).
;
cld
les di, RtnAdrs
lds si, RtnAdrs
;
; Okay, search for the end of the format string. After these instructions,
; di points just beyond the zero byte at the end of the format string. This,
; of course, points at the first address beyond the format string.
;
mov al, 0
mov cx, 65535
repne scasb
mov OprndPtr, di
mov OprndPtr+2, es
;
ScanItems: lodsb ;Get char si points at.
ScanItems2: cmp al, 0 ;EOS?
jz ScanfDone
cmp al, "%" ;Start of a format string?
jz FmtItem
SkipIt: cmp al, " "
jz SkipWS
les di, InputPtr
mov bx, InpIndex
cmp al, es:[di][bx]
jnz ScanItems
inc word ptr InpIndex
jmp ScanItems
;
SkipWS: les di, InputPtr
mov bx, InpIndex
SkipWSLp: cmp byte ptr es:[di][bx], ' '
jnz DoneSkip
inc bx
jmp SkipWSLp
;
DoneSkip: mov InpIndex, bx
Skip2: lodsb
cmp al, ' ' ;Skip additional whitespace
jz Skip2 ; in the format string.
dec si
jmp ScanItems
;
;
FmtItem: call GetFmtItem ;Process the format item here.
jmp ScanItems
;
;
ScanfDone: ret
scanf endp
;
;
;
; If we just saw a "%", come down here to handle the format item.
;
GetFmtItem proc near
;
lodsb ;Get char beyond "%"
;
; See if the user wants to specify a handle rather than a straight pointer
;
cmp al, '^'
jne ChkFmtChars
mov ah, al
lodsb ;Skip "^" character
;
; Okay, process the format characters down here.
;
ChkFmtChars: and al, 05fh ;l.c. -> U.C.
cmp al, 'D'
je GetDec
cmp al, 'I'
je GetDec
cmp al, 'C'
je GetChar
;
cmp al, 'X'
jne TryH
jmp GetHexWord
;
TryH: cmp al, 'H'
jne TryU
jmp GetHexByte
;
TryU: cmp al, 'U'
jne TryString
jmp GetUDec
;
TryString: cmp al, 'S'
jne TryLong
jmp GetString
;
TryLong: cmp al, 'L'
jne Default
;
; If we've got the "L" modifier, this is a long value to print, get the
; data type character as the next value:
;
lodsb
and al, 05fh ;l.c. -> U.C.
cmp al, 'D'
je JmpDec
cmp al, 'I'
jne TryLU
JmpDec: jmp LongDec
;
TryLU: cmp al, 'U'
jne Default
jmp LongU
;
;
;
; If none of the above, simply return without printing anything.
;
Default: ret
;
;
;
;
;
; Get a signed decimal value here.
;
GetDec: call GetPtr ;Get next pointer into ES:BX
push ax ;Save possible "^" char in ah
push es
les di, InputPtr
add di, InpIndex ;Point SI at integer.
cmp byte ptr es:[di], 0 ;At end of string?
jz QuitGetDec
call sl_atoi2 ;Convert to integer in AX.
sub di, InputPtr
mov InpIndex, di
pop es ; Ignore overflow or error.
mov es:[bx], ax
;
pop ax
ret
;
QuitGetDec: pop es
pop ax
ret ;We're done!
;
;
;
; Print a character variable here.
;
GetChar: call GetPtr ;Get next pointer into ES:BX
push ax ;Save possible "^" char in ah
push es
les di, InputPtr
add di, InpIndex ;Point SI at char.
mov al, es:[di] ;Get char
cmp al, 0 ;See if at EOS.
jz QuitGetChar
inc word ptr InpIndex ;Bump up index.
pop es
mov es:[bx], al
;
pop ax
ret
;
QuitGetChar: pop es
pop ax
ret ;We're done!
;
;
;
; Print a hexadecimal word value here.
;
GetHexWord: call GetPtr ;Get next pointer into ES:BX
push ax ;Save possible "^" char in ah
push es
les di, InputPtr
add di, InpIndex ;Point SI at integer.
cmp byte ptr es:[di], 0 ;Check for EOS
jz QuitGetHexWord
call sl_atoh2 ;Convert to integer in AX.
sub di, InputPtr
mov InpIndex, di
pop es ; Ignore overflow or error.
mov es:[bx], ax
;
pop ax
ret
;
QuitGetHexWord: pop es
pop ax
ret ;We're done!
;
;
;
;
; Print hex bytes here.
;
;
GetHexByte: call GetPtr ;Get next pointer into ES:BX
push ax ;Save possible "^" char in ah
push es
les di, InputPtr
add di, InpIndex ;Point SI at integer.
cmp byte ptr es:[di], 0 ;Check for EOS.
jz QuitGetHexByte
call sl_atoh2 ;Convert to integer in AX.
sub di, InputPtr
mov InpIndex, di
pop es ; Ignore overflow or error.
mov es:[bx], al
;
pop ax
ret
;
QuitGetHexByte: pop es
pop ax
ret ;We're done!
;
;
;
; Output unsigned decimal numbers here:
;
GetUDec: call GetPtr ;Get next pointer into ES:BX
push ax ;Save possible "^" char in ah
push es
les di, InputPtr
add di, InpIndex ;Point SI at integer.
cmp byte ptr es:[di], 0 ;Check for EOS.
jz QuitGetUDec
call sl_atou2 ;Convert to integer in AX.
sub di, InputPtr
mov InpIndex, di
pop es ; Ignore overflow or error.
mov es:[bx], ax
;
pop ax
ret
;
QuitGetUDec: pop es
pop ax
ret ;We're done!
;
;
; Output a string here:
;
GetString: push ax
push si
push es
push ds
;
call GetPtr
mov di, bx
lds si, InputPtr
add si, InpIndex
GetStrLp: lodsb ;Get next char
stosb
cmp al, 0
jnz GetStrLp
sub si, InputPtr
dec si
mov InpIndex, si
;
pop ds
pop es
pop si
pop ax
ret ;We're done!
;
;
;
; Print a signed long decimal value here.
;
LongDec: push dx
call GetPtr ;Get next pointer into ES:BX
push ax ;Save possible "^" char in ah
push es
les di, InputPtr
add di, InpIndex ;Point SI at integer.
cmp byte ptr es:[di], 0 ;Check for EOS.
jz QuitLongDec
call sl_atol2 ;Convert to integer in AX.
sub di, InputPtr
mov InpIndex, di
pop es ; Ignore overflow or error.
mov es:[bx], ax
mov es:2[bx], dx
;
pop ax
pop dx
ret ;We're done!
;
QuitLongDec: pop es
pop ax
pop dx
ret
;
;
;
; Print an unsigned long decimal value here.
;
LongU: push dx
call GetPtr ;Get next pointer into ES:BX
push ax ;Save possible "^" char in ah
push es
les di, InputPtr
add di, InpIndex ;Point SI at integer.
cmp byte ptr es:[di], 0
je QuitLongU
call sl_atoul2 ;Convert to integer in AX.
sub di, InputPtr
mov InpIndex, di
pop es ; Ignore overflow or error.
mov es:[bx], ax
mov es:2[bx], dx
;
pop ax
pop dx
ret ;We're done!
;
QuitLongU: pop es
pop ax
pop dx
ret
;
GetFmtItem endp
;
;
;
;
;
;
; GetPtr- Grabs the next pointer which OprndPtr points at and returns this
; far pointer in ES:BX.
;
GetPtr proc near
les di, OprndPtr
les bx, es:[di]
add word ptr OprndPtr, 4
;
; See if this is a handle rather than a pointer.
;
cmp ah, '^'
jne NotHandle
les bx, es:[bx]
NotHandle: ret
GetPtr endp
;
;
;
;
stdlib ends
end
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
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/