#ifdef LIBC_SCCS .data _sccsid: .asciz "@(#)doprnt.c 5.4 (Berkeley) 3/9/86" .text #endif LIBC_SCCS # C library -- conversions #include "DEFS.h" .globl __doprnt .globl __flsbuf #define vbit 1 #define flags r10 #define ndfnd 0 #define prec 1 #define zfill 2 #define minsgn 3 #define plssgn 4 #define numsgn 5 #define caps 6 #define blank 7 #define gflag 8 #define dpflag 9 #define width r9 #define ndigit r8 #define llafx r7 #define lrafx r6 #define fdesc -4(fp) #define exp -8(fp) #define sexp -12(fp) #define nchar -16(fp) #define sign -17(fp) .set ch.zer,'0 # cpp doesn't like single appostrophes .align 2 strtab: # translate table for detecting null and percent .byte 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 .byte 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 .byte ' ,'!,'",'#,'$, 0,'&,'','(,'),'*,'+,',,'-,'.,'/ .byte '0,'1,'2,'3,'4,'5,'6,'7,'8,'9,':,';,'<,'=,'>,'? .byte '@,'A,'B,'C,'D,'E,'F,'G,'H,'I,'J,'K,'L,'M,'N,'O .byte 'P,'Q,'R,'S,'T,'U,'V,'W,'X,'Y,'Z,'[,'\,'],'^,'_ .byte '`,'a,'b,'c,'d,'e,'f,'g,'h,'i,'j,'k,'l,'m,'n,'o .byte 'p,'q,'r,'s,'t,'u,'v,'w,'x,'y,'z,'{,'|,'},'~,127 .byte 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143 .byte 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159 .byte 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175 .byte 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191 .byte 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207 .byte 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223 .byte 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239 .byte 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 ENTRY(_doprnt, R6|R7|R8|R9|R10|R11) jbr doit strfoo: clrl r4 # fix interrupt race jbr strok # and try again strout2: # enter here to force out r2; r0,r1 must be set # do some tricks with line buffering (_IOLBF) first movl fdesc,r3 jbc $7,16(r3),0f # not line buffered (unbuffered) addl3 12(r3),8(r3),r4 # fdesc->_base+fdesc->_bufsiz cmpl 4(r3),r4 # buffer full? jgeq 0f # yes cmpl r2,$10 # c == '\n'? jeql 0f # yes movb r2,*4(r3) # line buffered and not buffer full incl 4(r3) # and not newline clrl (r3) # just stuff it and fix _cnt incl nchar # count the char jbr strout # skip __flsbuf 0: pushr $3 # save input descriptor pushl fdesc # FILE pushl r2 # the char calls $2,__flsbuf # please empty the buffer and handle 1 char tstl r0 # successful? jgeq strm1 # yes jbcs $31,nchar,strm1 # turn on sign bit of nchar to signify error strm1: incl nchar # count the char popr $3 # get input descriptor back strout: # enter via bsb with (r0,r1)=input descriptor movab strtab,r3 # table address movq *fdesc,r4 # output descriptor jbs $31,r4,strfoo # negative count is a no no strok: addl2 r0,nchar # we intend to move this many chars /******* Start bogus movtuc workaround *****/ clrl r2 tstl r0 bleq movdon movlp: tstl r4 bleq movdon movzbl (r1)+,r3 tstb strtab[r3] bneq 1f mnegl $1,r2 decl r1 brb movdon 1: movb r3,(r5)+ decl r4 sobgtr r0,movlp /******* End bogus movtuc workaround *** movtuc r0,(r1),$0,(r3),r4,(r5) movpsl r2 /* squirrel away condition codes */ /******* End equally bogus movtuc ****/ movdon: movq r4,*fdesc /* update output descriptor */ subl2 r0,nchar # some chars not moved jbs $vbit,r2,stresc # terminated by escape? sobgeq r0,strmore # no; but out buffer might be full stresc: rsb strmore: movzbl (r1)+,r2 # one char tstb strtab[r2] # translate jneq strout2 # bad guy in disguise (outbuf is full) incl r0 # fix the length decl r1 # and the addr movl $1 .word fmtbad-L5 # ? .word fmtbad-L5 # @ .word fmtbad-L5 # A .word fmtbad-L5 # B .word fmtbad-L5 # C .word decimal-L5 # D .word capital-L5 # E .word fmtbad-L5 # F .word capital-L5 # G .word fmtbad-L5 # H .word fmtbad-L5 # I .word fmtbad-L5 # J .word fmtbad-L5 # K .word fmtbad-L5 # L .word fmtbad-L5 # M .word fmtbad-L5 # N .word octal-L5 # O .word fmtbad-L5 # P .word fmtbad-L5 # Q .word fmtbad-L5 # R .word fmtbad-L5 # S .word fmtbad-L5 # T .word unsigned-L5 # U .word fmtbad-L5 # V .word fmtbad-L5 # W .word capital-L5 # X .word fmtbad-L5 # Y .word fmtbad-L5 # Z .word fmtbad-L5 # [ .word fmtbad-L5 # \ .word fmtbad-L5 # ] .word fmtbad-L5 # ^ .word fmtbad-L5 # _ .word fmtbad-L5 # ` .word fmtbad-L5 # a .word fmtbad-L5 # b .word charac-L5 # c .word decimal-L5 # d .word scien-L5 # e .word float-L5 # f .word general-L5 # g .word short-L5 # h .word fmtbad-L5 # i .word fmtbad-L5 # j .word fmtbad-L5 # k .word longorunsg-L5 # l .word fmtbad-L5 # m .word fmtbad-L5 # n .word octal-L5 # o .word fmtbad-L5 # p .word fmtbad-L5 # q .word fmtbad-L5 # r .word string-L5 # s .word fmtbad-L5 # t .word unsigned-L5 # u .word fmtbad-L5 # v .word fmtbad-L5 # w .word hex-L5 # x fmtbad: movb r0,(r5)+ # print the unfound character jeql errdone # dumb users who end the format with a % jbr prbuf capital: bisl2 $1 subl3 r1,r5,ndigit # raw width subl3 ndigit,width,r0 # pad length jleq padlno # in particular, no left padding jbs $minsgn,flags,padlno # extension for %0 flag causing left zero padding to field width jbs $zfill,flags,padlz # this bsbb needed even if %0 flag extension is removed bsbb padb # blank pad on left jbr padnlz padlz: movl llafx,r0 jleq padnlx # left zero pad requires left affix first subl2 r0,ndigit # part of total length will be transferred subl2 r0,width # and will account for part of minimum width bsbw strout # left affix padnlx: subl3 ndigit,width,r0 # pad length bsbb padz # zero pad on left padnlz: # end of extension for left zero padding padlno: # remaining: root, possible right padding subl2 ndigit,width # root reduces minimum width movl ndigit,r0 # root length p1: bsbw strout # transfer to output buffer p3: jbc $vbit,r2,padnpct # percent sign (or null byte via %c) ? decl r0 # yes; adjust count movzbl (r1)+,r2 # fetch byte movq *fdesc,r4 # output buffer descriptor sobgeq r4,p2 # room at the out [inn] ? bsbw strout2 # no; force it, then try rest jbr p3 # here we go 'round the mullberry bush, ... p2: movb r2,(r5)+ # hand-deposit the percent or null incl nchar # count it movq r4,*fdesc # store output descriptor jbr p1 # what an expensive hiccup! padnpct: movl width,r0 # size of pad jleq loop bsbb padb jbr loop padz: movb $'0,r2 jbr pad padb: movb $' ,r2 pad: subl2 r0,width # pad width decreases minimum width pushl r1 # save non-pad addr movl r0,llafx # remember width of pad subl2 r0,sp # allocate movc5 $0,(r0),r2,llafx,(sp) # create pad string movl llafx,r0 # length movl sp,r1 # addr bsbw strout addl2 llafx,sp # deallocate movl (sp)+,r1 # recover non-pad addr rsb pone: .byte 0x1C # packed 1 charac: movl (ap)+,r0 # word containing the char movb r0,(r5)+ # one byte, that's all prbuf: movl sp,r1 # addr first byte jbr prstr space: bisl2 $1n, e>=n gfmtf: movl r7,r6 subl2 r0,ndigit # n-e-1 movab 16(sp),r1 bsbw fedit g1: jbs $numsgn,flags,g2 jbs $dpflag,flags,g2 # dont strip if no decimal point g3: cmpb -(r5),$'0 # strip trailing zeroes jeql g3 cmpb (r5),$'. # and trailing decimal point jeql g2 incl r5 g2: jbc $gflag,flags,eexp jbr prnum gfmte: movab 16(sp),r1 # packed source bsbw eedit jbsc $gflag,flags,g1 # gflag now means "use %f" [hence no exponent] general: jbs $prec,flags,gn1 movl $6,ndigit # default precision is 6 significant digits gn1: tstl ndigit # cannot allow precision of 0 jgtr gn2 movl $1,ndigit # change 0 to 1, willy-nilly gn2: jbcs $gflag,flags,L23 jbr L23 # safety net # convert double-floating at (ap) to 17-digit packed at (sp), # set 'sign' and 'exp', advance ap. fltcvt: clrb sign movd (ap)+,r5 jeql fzero bgtr fpos mnegd r5,r5 incb sign fpos: extzv $7,$8,r5,r2 # exponent of 2 movab -0200(r2),r2 # unbias mull2 $59,r2 # 59/196: 3rd convergent continued frac of log10(2) jlss eneg movab 196(r2),r2 eneg: movab -98(r2),r2 divl2 $196,r2 bsbw expten cmpd r0,r5 bgtr ceil incl r2 ceil: movl r2,exp mnegl r2,r2 cmpl r2,$29 # 10^(29+9) is all we can handle bleq getman muld2 ten16,r5 subl2 $16,r2 getman: addl2 $9,r2 # -ceil(log10(x)) + 9 jsb expten emodd r0,r4,r5,r0,r5 # (r0+r4)*r5; r0=int, r5=frac fz1: cvtlp r0,$9,16(sp) # leading 9 digits ashp $8,$9,16(sp),$0,$17,4(sp) # as top 9 of 17 emodd ten8,$0,r5,r0,r5 cvtlp r0,$8,16(sp) # trailing 8 digits # if precision >= 17, must round here movl ndigit,r7 # so figure out what precision is pushab scien cmpl (sp)+,(sp) jleq gm1 # who called us? addl2 exp,r7 # float; adjust for exponent gm1: cmpl r7,$17 jlss gm2 cmpd r5,$0d0.5 # must round here; check fraction jlss gm2 bisb2 $0x10,8+4(sp) # increment l.s. digit gm2: # end of "round here" code addp4 $8,16(sp),$17,4(sp) # combine leading and trailing bisb2 sign,12(sp) # and insert sign rsb fzero: clrl r0 movl $1,exp # 0.000e+00 and 0.000 rather than 0.000e-01 and .000 jbr fz1 .align 2 lsb: .long 0x00010000 # lsb in the crazy floating-point format # return 10^r2 as a double float in r0||r1 and 8 extra bits of precision in r4 # preserve r2, r5||r6 expten: movd $0d1.0,r0 # begin computing 10^exp10 clrl r4 # bit counter movad ten1,r3 # table address tstl r2 bgeq e10lp mnegl r2,r2 # get absolute value jbss $6,r2,e10lp # flag as negative e10lp: jbc r4,r2,el1 # want this power? muld2 (r3),r0 # yes el1: addl2 $8,r3 # advance to next power aobleq $5,r4,e10lp # through 10^32 jbcc $6,r2,el2 # correct for negative exponent divd3 r0,$0d1.0,r0 # by taking reciprocal cmpl $28,r2 jneq enm28 addl2 lsb,r1 # 10**-28 needs lsb incremented enm28: mnegl r2,r2 # original exponent of 10 el2: addl3 $5*8,r2,r3 # negative bit positions are illegal? jbc r3,xlsbh-5,eoklsb subl2 lsb,r1 # lsb was too high eoklsb: movzbl xprec[r2],r4 # 8 extra bits rsb # powers of ten .align 2 ten1: .word 0x4220,0,0,0 ten2: .word 0x43c8,0,0,0 ten4: .word 0x471c,0x4000,0,0 ten8: .word 0x4dbe,0xbc20,0,0 ten16: .word 0x5b0e,0x1bc9,0xbf04,0 ten32: .word 0x759d,0xc5ad,0xa82b,0x70b6 # whether lsb is too high or not .byte 1:0,1:0,1:0,1:0,1:1,1:0,1:1,1:0 # -40 thru -33 .byte 1:0,1:1,1:0,1:0,1:0,1:0,1:1,1:0 # -32 thru -25 .byte 1:0,1:0,1:1,1:1,1:1,1:1,1:0,1:0 # -24 thru -17 .byte 1:0,1:1,1:0,1:0,1:1,1:1,1:1,1:1 # -16 thru -9 .byte 1:1,1:1,1:1,1:0,1:0,1:0,1:0,1:1 # -8 thru -1 xlsbh: .byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0 # 0 thru 7 .byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0 # 8 thru 15 .byte 1:0,1:0,1:0,1:0,1:0,1:0,1:0,1:0 # 16 thru 23 .byte 1:0,1:1,1:1,1:0,1:1,1:1,1:1,1:1 # 24 thru 31 .byte 1:1,1:1,1:1,1:1,1:1,1:1,1:1 # 32 thru 38 # bytes of extra precision .byte 0x56,0x76,0xd3,0x88,0xb5,0x62 # -38 thru -33 .byte 0xba,0xf5,0x32,0x3e,0x0e,0x48,0xdb,0x51 # -32 thru -25 .byte 0x53,0x27,0xb1,0xef,0xeb,0xa5,0x07,0x49 # -24 thru -17 .byte 0x5b,0xd9,0x0f,0x13,0xcd,0xff,0xbf,0x97 # -16 thru -9 .byte 0xfd,0xbc,0xb6,0x23,0x2c,0x3b,0x0a,0xcd # -8 thru -1 xprec: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # 0 thru 7 .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # 8 thru 15 .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 # 16 thru 23 .byte 0x00,0xa0,0xc8,0x3a,0x84,0xe4,0xdc,0x92 # 24 thru 31 .byte 0x9b,0x00,0xc0,0x58,0xae,0x18,0xef # 32 thru 38