stdlib segment para public 'slcode' 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