Category : Files from Magazines
Archive   : TINYLIB.ZIP
Filename : _FMT.ASM

 
Output of file : _FMT.ASM contained in archive : TINYLIB.ZIP
include compiler.inc

ttl _FMT, 1.05, 10-21-86, jwk

;support printf etc - original size 07de bytes

; BITS in FLG byte
ljust equ 1
sign equ 2
blank equ 4
altern equ 8
zfill equ 16
islong equ 32
issgnd equ 64

dseg

flch db '-+0 #', 0 ;flag chars
flgbits db ljust, sign, zfill, blank, altern

cch db 'sc' ;runs on with 'nch'

nch db 'iXoxud%', 0 ;numeric conversions

cseg

incptr macro bump
ifdef bump&_v
inc word ptr bump&_v
else
inc word ptr bump
endif
endm

leads macro dest,ofst
fixds
lea dest,ofst
endm

fixds macro
ifdef LONGPTR
mov ds,saveds
endif
endm

setds macro
ifdef LONGPTR
mov saveds,ds
endif
endm

xtfs

; int _fmt (rtn, arglst)
; int *(rtn)(), **arglst;

procdef _fmt, <, >
dclv ctl, ptr ; char ptr to control string
dclv ctlchr, byte ; current control character
dclv sent, word ; number of bytes sent out
dclv pad, word ; number of bytes padding required
dclv tnum, word ; total size of prefix+string
dclv prec, word ; precision specified
dclv minwid, word ; minimum field width
dclv nbr, word ; work area
dclv prefix, baray, 128
dclv str, baray, 64 ; working string buffer
dclv flg, byte ; flag byte for prefix formatting
dclv op, ptr ; char ptr to working buffer
dclv saveds, word ; save word for data segment
locs <> ; pointer to output string (str or %s)
pushreg
pushds
setds
xor ax, ax ; sent = 0;
mov sent, ax
ptrcpyinc arglst, ctl ; ctl = *arglst++;
outer: ldptr si, ctl ; while (*ctl) /*main loop*/
mov al, byte ptr [si]
or al, al
jnz chrok
jmp fini
chrok: caseb '%', parse ; { if (*ctl != '%')
call sndout ; { if ((*rtn)(*ctl)==EOF)return EOF;++sent;
jmp bmpctl ; } /*go step CTL*/
parse: ; else
incptr ctl ; { ++ctl;
xor ax, ax ; flg = 0;
mov flg, al
dec ax ; prec = -1;
mov prec, ax
setptr strp, str, ss ; strp = str;
setptr op, prefix, ss ; op = prefix;
flglp: ldptr si, ctl ; while (regax=index("-+0 #",*ctl))
mov al, byte ptr [si]
xor ah, ah
leads dx, flch
callit index, <, >
dec ax
js setwd
incptr ctl ; { ++ctl;
mov bx, ax ; flg |= flgbits[regax-1];
mov al, 7[bx]
or flg, al
jmp flglp ; }
setwd: call getval ; minwid = getval(ctl,arglst);
mov minwid, ax
cmp ax, 0 ; if (minwid<0)
jge setpre
mov minwid, 1 ; minwid = 1;
setpre: ldptr si, ctl ; if (*ctl=='.')
cmp byte ptr [si], '.'
jne doltr
incptr ctl ; { ++ctl;
call getval ; prec = getval(ctl,arglst);
cmp ax, 0 ; if (prec<0)
jge sprec
xor ax, ax ; prec = 0;
sprec: mov prec, ax ; }
doltr: ldptr si, ctl ; ctlchr = *ctl;
mov al, byte ptr [si]
mov ctlchr, al
or al, 32 ; switch(tolower(ctlchr))
caseb 'l', casel ; {
caseb 'i', csisi
caseb 'd', cased
jmp cx1 ; /*chain the switch tests*/
casel: ; case 'l':
or flg, islong ; flg |= islong;
incptr ctl ; ++ctl;
jmp doltr ; goto doltr;

csisi: mov al, 'd' ; case 'i':
mov ctlchr, al ; ctlchr = 'd';

cased: ; case 'd':
or flg, issgnd ; flg |= issgnd
call gtrg ; nbr = getarg();
mov nbr, dx
cmp dx, 0 ; if (nbr<0)
jge absdn
xor dx, -1 ; nbr = -nbr;
xor ax, -1
add ax, 1
adc dx, 0
absdn: ; _xd(nbr, strp);
callit _xd, <, , >
cmp nbr, 0 ; if ( nbr < 0 )
jge noneg
mov al, '-' ; *op++ = '-';
jmp setpfx ; else
noneg: test flg, sign ; if (flg & sign)
jz nosgn
mov al, '+' ; *op++ = '+';
jmp setpfx ; else
nosgn: test flg, blank ; if (flg & blank)
jz endcsd
mov al, ' ' ; *op++ = ' ';
setpfx: pci op
endcsd: jmp chrdon ; break;

cx1: caseb 'u', caseu ; more CASE tests
caseb 'o', caseo
caseb 'x', casex
jmp cx2
caseu: ; case 'u':
call gtrg ; _xd(getarg(), strp);
callit _xd, <, , >
jmp chrdon ; break;

caseo: ; case 'o':
call gtrg ; _xo(getarg(), strp);
callit _xo, <, , >
mov al, flg ; if (flg & altern)
and al, altern
jz endcso
mov al, '0' ; *op++ = '0';
pci op
endcso: jmp chrdon ; break;

casex: ; case 'x':
call gtrg ; _xh(getarg(), strp);
callit _xh, <, , >
mov al, flg ; if (flg & altern)
and al, altern
jz endcsx
mov al, '0' ; { *op++ = '0';
pci op
mov al, 'x' ; *op++ = 'x';
pci op
endcsx: jmp short chrdon ; break;

cx2: caseb 'c', casec
caseb 's', cases
caseb '%', cpct
jmp dflt

casec: ; case 'c':
gwi arglst ; strp[0] = *arglst++;
jmp short stch ; strp[1] = 0; break;

cases: ; case 's':
ptrcpyinc arglst, strp ; strp = *arglst++;
mov ax, prec ; if (prec<0)
cmp ax, 0
jge endcss
callit strlen <>
mov prec, ax ; prec = strlen(strp);
endcss: jmp short chrdon ; break;

cpct: ; case '%':
mov al, '%' ; strp[0] = '%'; strp[1] = 0;
jmp short stch ; break;

dflt: ; default:
ldptr si, ctl ; strp[0] = *ctl;
mov al, byte ptr [si]
stch:
xor ah, ah ; strp[1] = 0;
ldptr di, strp, es
stosw
; jmp short chrdon ; break;
chrdon: ; } /*end of SWITCH on CTLCHR */
ldptr si, op ; *op = 0;
mov byte ptr [si], 0
lea ax, prefix ; tnum = strlen(prefix)+strlen(strp);
callit strlen <>
mov di, ax
callit strlen <>
add ax, di
mov tnum, ax
leads di, nch ; if (index (nch, ctlchr))
callit index <, >
or ax, ax
jz notnum
flwhl: mov ax, tnum ; { while (tnum cmp ax, prec
jge chkpre
test flg, zfill ; { *op++ = (flg & zfill) ? '0' : ' ';
jz fw1
mov al, '0'
jmp short fw2
fw1: mov al, ' '
fw2: pci op
xor al, al ; *op = 0;
mov byte ptr [di], al
inc tnum ; ++tnum;
jmp flwhl ; } /* end of WHILE */
notnum: ; } else
mov ax, prec ; { if (prec < 0)
cmp ax, 0
jge chkpre
mov ax, 1 ; prec = 1;
mov prec, ax ; }
chkpre: mov ax, prec ; nbr = max (prec, minwid);
cmp ax, minwid
jg svnum
mov ax, minwid
svnum: mov nbr, ax
sub ax, tnum ; pad = (tnum jns svpad
xor ax, ax
svpad: mov pad, ax
mov al, ctlchr ; if (ctlchr=='x')
cmp al, 'x'
jnz chkch2
setptr op, prefix, ss ; { op = prefix;
lcpfx: ldptr si, op ; while (*op)
mov al, byte ptr [si]
xor ah, ah
or ax, ax
jz lcpex
callit tolower, <>
pci op ; *op++ = tolower(*op);
jmp lcpfx
lcpex: setptr op, str, ss ; op = str;
lcstr: ldptr si, op ; while (*op)
mov al, byte ptr [si]
xor ah, ah
or ax, ax
jz chkch2
callit tolower, <>
pci op ; *op++ = tolower(*op);
jmp lcstr ; } /* end IF(CTLCHR.. */
chkch2: leads di, cch ; if (index(cch, ctlchr))
callit index <, >
or ax, ax
jnz cc2a
jmp notctch
cc2a: test flg, zfill ; { nbr = (flg & zfill ? '0' : ' ');
jz cc2b
mov al, '0'
jmp short cc2c
cc2b: mov al, ' '
cc2c: mov nbr, ax
test flg, ljust ; if (!(flg & ljust)) /* pad on left */
jnz lpadx
padlft: dec pad ; while (--pad >= 0)
js lpadx
mov ax, nbr ; sndout(nbr);
call sndout
jmp padlft
lpadx: setptr op, prefix, ss ; op = prefix; /* out prefix */
outpfx: ldptr si, op ; while (*op)
cmp byte ptr [si], 0
je outstg
lodsb ; sndout(*op++);
svptr si, op
call sndout
jmp outpfx
outstg: ldptr si, strp ; while (*strp) /* out string */
cmp byte ptr [si], 0
je ckrpad
cmp ctlchr, 's' ; { if ( ctlchr == 's'
jnz notstg
dec prec ; && --prec < 0 )
js ckrpad ; break;
notstg: gci strp ; sndout(*strp++);
call sndout
jmp outstg ; } /* end WHILE */
ckrpad: test flg, ljust ; if (flg & ljust) /* pad right */
jz bmpctl
dorpad: dec pad ; while ( --pad >= 0 )
js bmpctl
mov al, ' ' ; sndout(' ');
call sndout
jmp dorpad
notctch: ; } else /*end of IF(INDEX... */
ldptr si, ctl ; sndout(*ctl);
mov al, byte ptr [si]
call sndout
bmpctl: incptr ctl ; ++ctl;
jmp outer ; } /* main control loop ends here */
fini: mov ax, sent ; return (sent);
fmtqt: pret ; } /* end of function */
pend _fmt

internal gtrg ;uses _FMT's BP and offsets
cld ;get "long" from arg list
push ds
ldptr si,arglst ;grab the pointer
lodsw
mov cl, flg ;check for sign extension
test cl, issgnd
jnz sxt
xor dx, dx ;unsigned
jmp short tstlg
sxt: cwd ;assume it's int
tstlg: and cl, islong
jz gtrgx ;not a long, done
xchg dx, ax ;was a long, so...
lodsw ;get hi word
xchg dx, ax
gtrgx: svptr si,arglst ;update ARGLST pointer
pop ds
ret
iend gtrg

internal sndout ;uses _FMT's BP and offsets
xor ah, ah
push ax
fixds
call rtn
inc sp
inc sp
cmp ax, -1 ;error?
jne sndok ;no
inc sp ;yes, flush ret address
inc sp
jmp fmtqt ;and get out of _fmt()
sndok: inc sent ;bump SENT count
ret ;to caller inside _fmt
iend sndout

internal getval ;must reference from main BP
push ds
mov cx, -1 ;initialize accumulator
ldptr si, ctl
mov al, byte ptr [si]
cmp al, '*'
jne gv_ckn
gwi arglst ;get an argument
jmp gv_lx
gv_ckn: sub al, '0'
jb gv_lr ;not numeric either
cmp al, 9
ja gv_lr ;so return -1
cbw
mov cx, ax ;re-initialize accumulator
mov di, 10
gv_dgl: inc si
mov al, [si]
sub al, '0'
jb gv_ls ;out of digits, return acc
cmp al, 9
ja gv_ls
cbw
xchg ax, cx ;swap for multiply by 10
cwd
mul di
add cx, ax ;accumulate it
jmp gv_dgl
gv_ls: svptr si, ctl ;update CTL pointer
gv_lr: mov ax, cx ;get return value
gv_lx: pop ds
ret
iend getval

finish


  3 Responses to “Category : Files from Magazines
Archive   : TINYLIB.ZIP
Filename : _FMT.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/