/* name... printf purpose... formatted I/O authors... Original program by J. E. Hendrix, floating point functions added by J. R. Van Zandt. history... 11 Sept 84 Calling _outc() rather than putc(), _outc() calls putc() or putchar(). 9 Sept 84 Calling putc() rather than putchar(), 1st parameter can be device #. 11 Aug 84 ftoe() handles argument of 0. 3 Aug 84 Calling putchar() directly rather than through cout(). Aug 84 Added atof() 12 Aug 83 Added 'e' format. 10 Aug 83 changed back to &argcnt+i-1. Added 'f' format. 8 Aug 83 Changed addr of first arg to &argcnt + i + 1. */ #include printf2.h #include iolib.h #include float.h #define NULL 0 #define ERR -1 int device; /* ** printf(controlstring, arg, arg, ...) -- formatted print ** operates as described by Kernighan & Ritchie ** only d, x, c, s, f, e, and u specs are supported. */ printf(argcnt) int argcnt; { int i, width, prec, preclen, len, *nxtarg; char *ctl, *cx, c, right, str[128], *sptr, pad; double *pd; i = argc(); /* fetch arg count from A reg first */ nxtarg = &argcnt + i - 1; ctl = device = *nxtarg; if (device==(device&31)) /* *small* value must be device # */ {ctl=*--nxtarg;} else device=0; while(c=*ctl++) { if(c!='%') {_outc(c); continue;} if(*ctl=='%') {_outc(*ctl++); continue;} cx=ctl; if(*cx=='-') {right=0; ++cx;} else right=1; if(*cx=='0') {pad='0'; ++cx;} else pad=' '; if((i=utoi(cx, &width)) >= 0) cx=cx+i; else continue; if(*cx=='.') { if((preclen=utoi(++cx, &prec)) >= 0) cx=cx+preclen; else continue; } else preclen=0; sptr=str; c=*cx++; i=*(--nxtarg); if(c=='d') itod(i, str, 7); else if(c=='x') itox(i, str, 7); else if(c=='c') {str[0]=i; str[1]=NULL;} else if(c=='s') sptr=i; else if(c=='u') itou(i, str, 7); else {if(preclen==0)prec=6; if(c=='f') {nxtarg=nxtarg-2; pd=nxtarg; ftoa(*pd,prec,str); } else if(c=='e') {nxtarg=nxtarg-2; pd=nxtarg; ftoe(*pd,prec,str); } else continue; } ctl=cx; /* accept conversion spec */ if(c!='s') while(*sptr==' ') ++sptr; len=-1; while(sptr[++len]); /* get length */ if((c=='s')&(len>prec)&(preclen>0)) len=prec; if(right) while(((width--)-len)>0) _outc(pad); while(len) {_outc(*sptr++); --len; --width;} while(((width--)-len)>0) _outc(pad); } } /* ** utoi -- convert unsigned decimal string to integer nbr ** returns field size, else ERR on error */ utoi(decstr, nbr) char *decstr; int *nbr; { int d,t; d=0; *nbr=0; while((*decstr>='0')&(*decstr<='9')) { t=*nbr;t=(10*t) + (*decstr++ - '0'); if ((t>=0)&(*nbr<0)) return ERR; d++; *nbr=t; } return d; } /* ** itod -- convert nbr to signed decimal string of width sz ** right adjusted, blank filled; returns str ** ** if sz > 0 terminate with null byte ** if sz = 0 find end of string ** if sz < 0 use last byte for data */ itod(nbr, str, sz) int nbr; char str[]; int sz; { char sgn; if(nbr<0) {nbr = -nbr; sgn='-';} else sgn=' '; if(sz>0) str[--sz]=NULL; else if(sz<0) sz = -sz; else while(str[sz]!=NULL) ++sz; while(sz) { str[--sz]=(nbr%10+'0'); if((nbr=nbr/10)==0) break; } if(sz) str[--sz]=sgn; while(sz>0) str[--sz]=' '; return str; } /* ** itou -- convert nbr to unsigned decimal string of width sz ** right adjusted, blank filled; returns str ** ** if sz > 0 terminate with null byte ** if sz = 0 find end of string ** if sz < 0 use last byte for data */ itou(nbr, str, sz) int nbr; char str[]; int sz; { int lowbit; if(sz>0) str[--sz]=NULL; else if(sz<0) sz = -sz; else while(str[sz]!=NULL) ++sz; while(sz) { lowbit=nbr&1; nbr=(nbr>>1)&32767; /* divide by 2 */ str[--sz]=((nbr%5)<<1)+lowbit+'0'; if((nbr=nbr/5)==0) break; } while(sz) str[--sz]=' '; return str; } /* ** itox -- converts nbr to hex string of length sz ** right adjusted and blank filled, returns str ** ** if sz > 0 terminate with null byte ** if sz = 0 find end of string ** if sz < 0 use last byte for data */ itox(nbr, str, sz) int nbr; char str[]; int sz; { int digit, offset; if(sz>0) str[--sz]=NULL; else if(sz<0) sz = -sz; else while(str[sz]!=NULL) ++sz; while(sz) { digit=nbr&15; nbr=(nbr>>4)&4095; if(digit<10) offset=48; else offset=55; str[--sz]=digit+offset; if(nbr==0) break; } while(sz) str[--sz]=' '; return str; } /* name... putf purpose... to convert from double precision floating point to ASCII string history... 10 Aug 82 Adapted from 'putf': output into a string, no padding. 11 Oct 82 'int' => 'floor' 4 Oct 82 Using floating point constants, not scaling x down before printing digits before decimal point. */ ftoa(x,f,str) double x; /* the number to be converted */ int f; /* number of digits to follow decimal point */ char *str; /* output string */ { double scale; /* scale factor */ int i, /* copy of f, and # digits before decimal point */ minus, /* nonzero if x<0 */ d; /* a digit */ if(x>=0.) minus=0; else {minus=1; x=-x;} if(minus)*str++ = '-'; /* round off the number */ i=f; scale=2.; while(i--)scale=scale*10.; x=x+1./scale; /* count places before decimal & scale the number */ i=0; scale=1.; while(x>=scale) {scale=scale*10.; i++;} while(i--) /* output digits before decimal */ {scale=floor(.5+scale*.1); d=ifix(x/scale); *str++ = d+'0'; x=x-float(d)*scale; } if(f<=0) {*str=NULL;return;} *str++ = '.'; while(f--) /* output digits after decimal */ {x=x*10.; d=ifix(x); *str++ = d+'0'; x=x-float(d); } *str=NULL; } /* e format conversion */ ftoe(x,prec,str) double x; /* number to be converted */ int prec; /* # digits after decimal place */ char *str; /* output string */ { double scale; /* scale factor */ int i, /* counter */ d, /* a digit */ expon; /* exponent */ scale=1.; /* scale = 10 ** prec */ i=prec; while(i--) scale=scale*10.; if(x==0.) {expon=0; scale=scale*10.;} else {expon=prec; if(x<0.) {*str++='-'; x=-x;} if(x>scale) /* need: scale=scale) {x=x/10.; ++expon;} } else {while(x=scale) {x=x/10.; ++expon;} } i=0; while(i<=prec) {scale=floor(.5+scale*.1); /* now, scale <= x < 10*scale */ d=ifix(x/scale); *str++ = d+'0'; x=x-float(d)*scale; if(i++) continue; *str++ ='.'; } *str++='e'; if(expon<0) {*str++='-'; expon=-expon;} if(expon>9) *str++ ='0'+expon/10; *str++='0'+expon%10; *str=NULL; } /* decimal to (double) binary conversion */ atof(s) char s[]; /* s points to a character string */ { double sum, /* the partial result */ scale; /* scale factor for the next digit */ char *start, /* copy if input pointer */ *end, /* points to end of number */ c; /* character from input line */ int minus, /* nonzero if number is negative */ dot, /* nonzero if *s is decimal point */ decimal; /* nonzero if decimal point found */ if(*s=='-') {minus=1; s++;} else minus=0; start=s; decimal=0; /* no decimal point seen yet */ while(((*s<='9')&(*s>='0'))|(dot=(*s=='.'))) {if(dot)decimal++; s++; /* scan to end of string */ } end=s; sum=0.; /* initialize answer */ if(decimal) /* handle digits to right of decimal */ {s--; while(*s!='.') sum=(sum+float(*(s--)-'0'))/10.; } scale=1.; /* initialize scale factor */ while(--s>=start) /* handle remaining digits */ {sum=sum+scale*float(*s-'0'); scale=scale*10.;} c=*end++; if((c=='e')|(c=='E')) /* interpret exponent */ {int neg, /* nonzero if exp negative */ expon, /* absolute value of exp */ k; /* mask */ neg=expon=0; if(*end=='-') /* negative exponent */ {neg=1; end++;} while(1) /* read an integer */ {if((c=*end++)>='0') {if(c<='9') {expon=expon*10+c-'0'; continue; } } break; } if(expon>38) {puts("overflow"); expon=0;} k=32; /* set one bit in mask */ scale=1.; while(k) {scale=scale*scale; if(k&expon) scale=scale*10.; k=k>>1; } if(neg) sum=sum/scale; else sum=sum*scale; } if(minus)sum=-sum; return sum; } _outc(c) char c; { if(device) putc(c,device); else putchar(c); }  .