home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 156_01 / printf2.c < prev    next >
Text File  |  1985-08-21  |  9KB  |  336 lines

  1. /*
  2.     name...
  3.         printf
  4.  
  5.     purpose...
  6.         formatted I/O
  7.  
  8.     authors...
  9.         Original program by J. E. Hendrix, floating
  10.         point functions added by J. R. Van Zandt.
  11.  
  12.     history...
  13.         11 Sept 84 Calling _outc() rather than putc(),
  14.             _outc() calls putc() or putchar().
  15.         9 Sept 84  Calling putc() rather than putchar(),
  16.             1st parameter can be device #.
  17.         11 Aug 84  ftoe() handles argument of 0.
  18.         3 Aug 84   Calling putchar() directly rather
  19.             than through cout().
  20.         Aug 84  Added atof()
  21.         12 Aug 83  Added 'e' format.
  22.         10 Aug 83  changed back to &argcnt+i-1.
  23.             Added 'f' format.
  24.         8 Aug 83  Changed addr of first arg to
  25.             &argcnt + i + 1.
  26. */
  27.  
  28. #include printf2.h
  29. #include iolib.h
  30. #include float.h
  31.  
  32. #define NULL 0
  33. #define ERR -1
  34.  
  35. int device;
  36.  
  37. /*
  38. ** printf(controlstring, arg, arg, ...) -- formatted print
  39. **        operates as described by Kernighan & Ritchie
  40. **        only d, x, c, s, f, e, and u specs are supported.
  41. */
  42. printf(argcnt) int argcnt; {
  43.   int i, width, prec, preclen, len, *nxtarg;
  44.   char *ctl, *cx, c, right, str[128], *sptr, pad;
  45.   double *pd;
  46.   i = argc();   /* fetch arg count from A reg first */
  47.   nxtarg = &argcnt + i - 1;
  48.   ctl = device = *nxtarg;
  49.   if (device==(device&31))    /* *small* value must be device # */
  50.     {ctl=*--nxtarg;}
  51.   else device=0;
  52.   while(c=*ctl++) {
  53.     if(c!='%') {_outc(c); continue;}
  54.     if(*ctl=='%') {_outc(*ctl++); continue;}
  55.     cx=ctl;
  56.     if(*cx=='-') {right=0; ++cx;} else right=1;
  57.     if(*cx=='0') {pad='0'; ++cx;} else pad=' ';
  58.     if((i=utoi(cx, &width)) >= 0) cx=cx+i; else continue;
  59.     if(*cx=='.') {
  60.       if((preclen=utoi(++cx, &prec)) >= 0) cx=cx+preclen;
  61.       else continue;
  62.       }
  63.     else preclen=0;
  64.     sptr=str; c=*cx++; i=*(--nxtarg);
  65.     if(c=='d') itod(i, str, 7);
  66.     else if(c=='x') itox(i, str, 7);
  67.     else if(c=='c') {str[0]=i; str[1]=NULL;}
  68.     else if(c=='s') sptr=i;
  69.     else if(c=='u') itou(i, str, 7);
  70.     else
  71.     {if(preclen==0)prec=6;
  72.     if(c=='f')
  73.         {nxtarg=nxtarg-2; pd=nxtarg; ftoa(*pd,prec,str);
  74.         }
  75.     else if(c=='e')
  76.         {nxtarg=nxtarg-2; pd=nxtarg; ftoe(*pd,prec,str);
  77.         }
  78.     else continue;
  79.     }
  80.     ctl=cx; /* accept conversion spec */
  81.     if(c!='s') while(*sptr==' ') ++sptr;
  82.     len=-1; while(sptr[++len]); /* get length */
  83.     if((c=='s')&(len>prec)&(preclen>0)) len=prec;
  84.     if(right) while(((width--)-len)>0) _outc(pad);
  85.     while(len) {_outc(*sptr++); --len; --width;}
  86.     while(((width--)-len)>0) _outc(pad);
  87.     }
  88.   }
  89.  
  90.  
  91. /*
  92. ** utoi -- convert unsigned decimal string to integer nbr
  93. **          returns field size, else ERR on error
  94. */
  95. utoi(decstr, nbr)  char *decstr;  int *nbr;  {
  96.   int d,t; d=0;
  97.   *nbr=0;
  98.   while((*decstr>='0')&(*decstr<='9')) {
  99.     t=*nbr;t=(10*t) + (*decstr++ - '0');
  100.     if ((t>=0)&(*nbr<0)) return ERR;
  101.     d++; *nbr=t;
  102.     }
  103.   return d;
  104.   }
  105.  
  106.  
  107. /*
  108. ** itod -- convert nbr to signed decimal string of width sz
  109. **         right adjusted, blank filled; returns str
  110. **
  111. **        if sz > 0 terminate with null byte
  112. **        if sz = 0 find end of string
  113. **        if sz < 0 use last byte for data
  114. */
  115. itod(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  116.   char sgn;
  117.   if(nbr<0) {nbr = -nbr; sgn='-';}
  118.   else sgn=' ';
  119.   if(sz>0) str[--sz]=NULL;
  120.   else if(sz<0) sz = -sz;
  121.   else while(str[sz]!=NULL) ++sz;
  122.   while(sz) {
  123.     str[--sz]=(nbr%10+'0');
  124.     if((nbr=nbr/10)==0) break;
  125.     }
  126.   if(sz) str[--sz]=sgn;
  127.   while(sz>0) str[--sz]=' ';
  128.   return str;
  129.   }
  130.  
  131.  
  132. /*
  133. ** itou -- convert nbr to unsigned decimal string of width sz
  134. **         right adjusted, blank filled; returns str
  135. **
  136. **        if sz > 0 terminate with null byte
  137. **        if sz = 0 find end of string
  138. **        if sz < 0 use last byte for data
  139. */
  140. itou(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  141.   int lowbit;
  142.   if(sz>0) str[--sz]=NULL;
  143.   else if(sz<0) sz = -sz;
  144.   else while(str[sz]!=NULL) ++sz;
  145.   while(sz) {
  146.     lowbit=nbr&1;
  147.     nbr=(nbr>>1)&32767;  /* divide by 2 */
  148.     str[--sz]=((nbr%5)<<1)+lowbit+'0';
  149.     if((nbr=nbr/5)==0) break;
  150.     }
  151.   while(sz) str[--sz]=' ';
  152.   return str;
  153.   }
  154.  
  155.  
  156. /*
  157. ** itox -- converts nbr to hex string of length sz
  158. **         right adjusted and blank filled, returns str
  159. **
  160. **        if sz > 0 terminate with null byte
  161. **        if sz = 0 find end of string
  162. **        if sz < 0 use last byte for data
  163. */
  164. itox(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  165.   int digit, offset;
  166.   if(sz>0) str[--sz]=NULL;
  167.   else if(sz<0) sz = -sz;
  168.   else while(str[sz]!=NULL) ++sz;
  169.   while(sz) {
  170.     digit=nbr&15; nbr=(nbr>>4)&4095;
  171.     if(digit<10) offset=48; else offset=55;
  172.     str[--sz]=digit+offset;
  173.     if(nbr==0) break;
  174.     }
  175.   while(sz) str[--sz]=' ';
  176.   return str;
  177.   }
  178. /*
  179.     name...
  180.         putf
  181.  
  182.     purpose...
  183.         to convert from double precision floating
  184.         point to ASCII string
  185.  
  186.     history...
  187.         10 Aug 82  Adapted from 'putf': output into
  188.             a string, no padding.
  189.         11 Oct 82 'int' => 'floor'
  190.         4 Oct 82  Using floating point constants,
  191.             not scaling x down before printing
  192.             digits before decimal point.
  193. */
  194. ftoa(x,f,str)
  195. double x;    /* the number to be converted */
  196. int f;        /* number of digits to follow decimal point */
  197. char *str;    /* output string */
  198. {    double scale;    /* scale factor */
  199.     int i,        /* copy of f, and # digits before
  200.             decimal point */
  201.     minus,        /* nonzero if x<0 */
  202.     d;        /* a digit */
  203.     if(x>=0.) minus=0;
  204.     else    {minus=1; x=-x;}
  205.     if(minus)*str++ = '-';
  206.             /* round off the number */
  207.     i=f;
  208.     scale=2.;
  209.     while(i--)scale=scale*10.;
  210.     x=x+1./scale;
  211.     /* count places before decimal & scale the number */
  212.     i=0;
  213.     scale=1.;
  214.     while(x>=scale) {scale=scale*10.; i++;}
  215.     while(i--)    /* output digits before decimal */
  216.         {scale=floor(.5+scale*.1);
  217.         d=ifix(x/scale);
  218.         *str++ = d+'0';
  219.         x=x-float(d)*scale;
  220.         }
  221.     if(f<=0) {*str=NULL;return;}
  222.     *str++ = '.';
  223.     while(f--)    /* output digits after decimal */
  224.         {x=x*10.; d=ifix(x);
  225.         *str++ = d+'0'; x=x-float(d);
  226.         }
  227.     *str=NULL;
  228. }
  229. /*    e format conversion            */
  230. ftoe(x,prec,str)
  231. double x;    /* number to be converted */
  232. int prec;    /* # digits after decimal place */
  233. char *str;    /* output string */
  234. {    double scale;    /* scale factor */
  235.     int i,        /* counter */
  236.     d,        /* a digit */
  237.     expon;        /* exponent */
  238.     scale=1.;        /* scale = 10 ** prec */
  239.     i=prec; while(i--) scale=scale*10.;
  240.     if(x==0.) {expon=0; scale=scale*10.;}
  241.     else    {expon=prec;
  242.         if(x<0.) {*str++='-'; x=-x;}
  243.         if(x>scale)    /* need: scale<x<scale*10 */
  244.             {scale=scale*10.;
  245.             while(x>=scale) {x=x/10.; ++expon;}
  246.             }
  247.         else    {while(x<scale) {x=x*10.; --expon;}
  248.             scale=scale*10.;
  249.             }
  250.         /* at this point, .1*scale <= x < scale */
  251.         x=x+.5;            /* round */
  252.         if(x>=scale) {x=x/10.; ++expon;}
  253.         }
  254.     i=0;
  255.     while(i<=prec)
  256.         {scale=floor(.5+scale*.1);
  257.         /* now, scale <= x < 10*scale */
  258.         d=ifix(x/scale);
  259.         *str++ = d+'0';
  260.         x=x-float(d)*scale;
  261.         if(i++) continue;
  262.         *str++ ='.';
  263.         }
  264.     *str++='e';
  265.     if(expon<0) {*str++='-'; expon=-expon;}
  266.     if(expon>9) *str++ ='0'+expon/10;
  267.     *str++='0'+expon%10;
  268.     *str=NULL;
  269. }
  270.  
  271.     /* decimal to (double) binary conversion */
  272.  
  273. atof(s) char s[]; /* s points to a character string */
  274. {    double sum,    /* the partial result */
  275.     scale;        /* scale factor for the next digit */
  276.     char *start,    /* copy if input pointer */
  277.     *end,        /* points to end of number */
  278.     c;        /* character from input line */
  279.     int minus,    /* nonzero if number is negative */
  280.     dot,        /* nonzero if *s is decimal point */
  281.     decimal;    /* nonzero if decimal point found */
  282.     if(*s=='-') {minus=1; s++;}
  283.     else minus=0;
  284.     start=s;
  285.     decimal=0;  /* no decimal point seen yet */
  286.     while(((*s<='9')&(*s>='0'))|(dot=(*s=='.')))
  287.         {if(dot)decimal++;
  288.         s++;    /* scan to end of string */
  289.         }
  290.     end=s;
  291.     sum=0.;    /* initialize answer */
  292.     if(decimal)  /* handle digits to right of decimal */
  293.         {s--;
  294.         while(*s!='.')
  295.             sum=(sum+float(*(s--)-'0'))/10.;
  296.         }
  297.     scale=1.;    /* initialize scale factor */
  298.     while(--s>=start)    /* handle remaining digits */
  299.         {sum=sum+scale*float(*s-'0'); scale=scale*10.;}
  300.     c=*end++;
  301.     if((c=='e')|(c=='E'))    /* interpret exponent */
  302.         {int neg,    /* nonzero if exp negative */
  303.         expon,        /* absolute value of exp */
  304.         k;        /* mask */
  305.         neg=expon=0;
  306.         if(*end=='-')    /* negative exponent */
  307.             {neg=1; end++;}
  308.         while(1)    /* read an integer */
  309.             {if((c=*end++)>='0')
  310.                 {if(c<='9')
  311.                     {expon=expon*10+c-'0';
  312.                     continue;
  313.                     }
  314.                 }
  315.             break;
  316.             }
  317.         if(expon>38) {puts("overflow"); expon=0;}
  318.         k=32;    /* set one bit in mask */
  319.         scale=1.;
  320.         while(k)
  321.             {scale=scale*scale;
  322.             if(k&expon) scale=scale*10.;
  323.             k=k>>1;
  324.             }
  325.         if(neg) sum=sum/scale;
  326.         else    sum=sum*scale;
  327.         }
  328.     if(minus)sum=-sum;
  329.     return sum;
  330. }
  331.  
  332. _outc(c) char c;
  333. {    if(device) putc(c,device);
  334.     else putchar(c);
  335. }
  336.