home *** CD-ROM | disk | FTP | other *** search
/ Aminet 4 / Aminet 4 - November 1994.iso / aminet / dev / gcc / libnix.lha / gnu / lib / libnix / sources.lha / nix / stdio / vfprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-12  |  10.6 KB  |  378 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdarg.h>
  4. #include <limits.h>
  5. #include <ctype.h>
  6. #include <stabs.h>
  7. #include <math.h>
  8. #include <float.h>
  9. #include <strsup.h>
  10.  
  11. /* a little macro to make life easier */
  12.  
  13. #define OUT(c)  do                           \
  14.                 { if(fputc((c),stream)==EOF) \
  15.                     return outcount;         \
  16.                   outcount++;                \
  17.                 }while(0)
  18.  
  19. #define MINFLOATSIZE (sizeof(double)*BITSPERBYTE*302/1000+1)
  20. #define MININTSIZE (sizeof(unsigned long)*BITSPERBYTE/3+1)
  21. #define MINPOINTSIZE (sizeof(void *)*BITSPERBYTE/4+1)
  22. #define REQUIREDBUFFER (MININTSIZE>MINPOINTSIZE? \
  23.                         (MININTSIZE>MINFLOATSIZE?MININTSIZE:MINFLOATSIZE): \
  24.                         (MINPOINTSIZE>MINFLOATSIZE?MINPOINTSIZE:MINFLOATSIZE))
  25.  
  26. #define ALTERNATEFLAG 1  /* '#' is set */
  27. #define ZEROPADFLAG   2  /* '0' is set */
  28. #define LALIGNFLAG    4  /* '-' is set */
  29. #define BLANKFLAG     8  /* ' ' is set */
  30. #define SIGNFLAG      16 /* '+' is set */
  31.  
  32. extern unsigned char *__decimalpoint;
  33. extern unsigned char __undef[][sizeof(double)];
  34.  
  35. int vfprintf(FILE *stream,const char *format,va_list args)
  36.   size_t outcount=0;
  37.  
  38.   while(*format)
  39.   {
  40.     if(*format=='%')
  41.     { 
  42.       static char flagc[]=
  43.       { '#','0','-',' ','+' };
  44.       static char lowertabel[]=
  45.       { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
  46.       static char uppertabel[]=
  47.       { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
  48.       size_t width=0,preci=ULONG_MAX,flags=0; /* Specifications */
  49.       char type,subtype='i';
  50.       char buffer1[2];             /* Signs and that like */
  51.       char buffer[REQUIREDBUFFER]; /* The body */
  52.       char *buffer2=buffer;        /* So we can set this to any other strings */
  53.       size_t size1=0,size2=0;      /* How many chars in buffer? */
  54.       const char *ptr=format+1;    /* pointer to format string */
  55.       size_t i,pad;                /* Some temporary variables */
  56.  
  57.       do /* read flags */
  58.         for(i=0;i<sizeof(flagc);i++)
  59.           if(flagc[i]==*ptr)
  60.           { flags|=1<<i;
  61.             ptr++;
  62.             break; }
  63.       while(i<sizeof(flagc));
  64.  
  65.       if(*ptr=='*') /* read width from arguments */
  66.       { signed int a;
  67.         ptr++;
  68.         a=va_arg(args,signed int);
  69.         if(a<0)
  70.         { flags|=LALIGNFLAG;
  71.           width=-a; }
  72.         else
  73.           width=a;
  74.       }else
  75.         while(isdigit(*ptr))
  76.           width=width*10+(*ptr++-'0');
  77.  
  78.       if(*ptr=='.')
  79.       { ptr++;
  80.         if(*ptr=='*') /* read precision from arguments */
  81.         { signed int a;
  82.           ptr++;
  83.           a=va_arg(args,signed int);
  84.           if(a>=0)
  85.             preci=a;
  86.         }else
  87.         { preci=0;
  88.           while(isdigit(*ptr))
  89.             preci=preci*10+(*ptr++-'0');
  90.         }
  91.       }
  92.  
  93.       if(*ptr=='h'||*ptr=='l'||*ptr=='L')
  94.         subtype=*ptr++;
  95.  
  96.       type=*ptr++;
  97.  
  98.       switch(type)
  99.       { case 'd':
  100.         case 'i':
  101.         case 'o':
  102.         case 'p':
  103.         case 'u':
  104.         case 'x':
  105.         case 'X':
  106.         { unsigned long v;
  107.           char *tabel;
  108.           int base;
  109.  
  110.           if(type=='p')
  111.           { subtype='l'; /* This is written as %#lx */
  112.             type='x';
  113.             flags|=ALTERNATEFLAG; }
  114.  
  115.           if(type=='d'||type=='i') /* These are signed */
  116.           { signed long v2;
  117.             if(subtype=='l')
  118.               v2=va_arg(args,signed long);
  119.             else
  120.               v2=va_arg(args,signed int);
  121.             if(v2<0)
  122.             { buffer1[size1++]='-';
  123.               v=-v2;
  124.             }else
  125.             { if(flags&SIGNFLAG)
  126.                 buffer1[size1++]='+';
  127.               else if(flags&BLANKFLAG)
  128.                 buffer1[size1++]=' ';
  129.               v=v2; }
  130.           }else                    /* These are unsigned */
  131.           { if(subtype=='l')
  132.               v=va_arg(args,unsigned long);
  133.             else
  134.               v=va_arg(args,unsigned int);
  135.             if(flags&ALTERNATEFLAG)
  136.             { if(type=='o'&&(preci||v))
  137.                 buffer1[size1++]='0';
  138.               if((type=='x'||type=='X')&&v)
  139.               { buffer1[size1++]='0';
  140.                 buffer1[size1++]=type; }
  141.             }
  142.           }
  143.  
  144.           buffer2=&buffer[sizeof(buffer)]; /* Calculate body string */
  145.           base=type=='x'||type=='X'?16:(type=='o'?8:10);
  146.           tabel=type!='X'?lowertabel:uppertabel;
  147.           do
  148.           { *--buffer2=tabel[v%base];
  149.             v=v/base;
  150.             size2++;
  151.           }while(v);
  152.           if(preci==ULONG_MAX) /* default */
  153.             preci=0;
  154.           else
  155.             flags&=~ZEROPADFLAG;
  156.           break;
  157.         }
  158.         case 'c':
  159.           if(subtype=='l')
  160.             *buffer2=va_arg(args,long);
  161.           else
  162.             *buffer2=va_arg(args,int);
  163.           size2=1;
  164.           preci=0;
  165.           break;
  166.         case 's':
  167.           buffer2=va_arg(args,char *);
  168.           size2=strlen(buffer2);
  169.           size2=size2<=preci?size2:preci;
  170.           preci=0;
  171.           break;
  172. #ifdef FULL_SPECIFIERS
  173.         case 'f':
  174.         case 'e':
  175.         case 'E':
  176.         case 'g':
  177.         case 'G':
  178.         { double v;
  179.           char killzeros=0,sign=0; /* some flags */
  180.           int ex1,ex2; /* Some temporary variables */
  181.           size_t size,dnum,dreq;
  182.           char *udstr=NULL;
  183.  
  184.           v=va_arg(args,double);
  185.  
  186.           if(v==*(double *)&__undef[0])
  187.             udstr="+inf";
  188.           else if(v==*(double *)&__undef[1])
  189.             udstr="-inf";
  190.           else if(v==*(double *)&__undef[2])
  191.             udstr="NaN";
  192.  
  193.           if(udstr!=NULL)
  194.           { size2=strlen(udstr);
  195.             preci=0;
  196.             buffer2=udstr;
  197.             break; }
  198.  
  199.           if(preci==ULONG_MAX) /* old default */
  200.             preci=6; /* new default */
  201.  
  202.           if(v<0.0)
  203.           { sign='-';
  204.             v=-v;
  205.           }else
  206.           { if(flags&SIGNFLAG)
  207.               sign='+';
  208.             else if(flags&BLANKFLAG)
  209.               sign=' ';
  210.           }
  211.  
  212.           ex1=0;
  213.           if(v!=0.0)
  214.           { ex1=log10(v);
  215.             v=v/pow(10,ex1);
  216.             if(v<1.0) /* adjust if we are too low (log10(.1)=-.999999999) */
  217.             { v*=10.0; /* luckily this cannot happen with FLT_MAX and FLT_MIN */
  218.               ex1--; } /* The case too high (log(10.)=.999999999) is done later */
  219.           }
  220.  
  221.           ex2=preci;
  222.           if(type=='f')
  223.             ex2+=ex1;
  224.           if(tolower(type)=='g')
  225.           { if(ex1<(signed long)preci&&ex1>=-4)
  226.               ex2+=ex1;
  227.             ex2--; /* This is somehow strange, but ANSI requires it */
  228.           }
  229.           v+=.5*pow(.1,ex2); /* Round up */
  230.  
  231.           if(v>=10.0) /* Adjusts log10(10.)=.999999999 too */
  232.           { v/=10.0;
  233.             ex1++; }
  234.  
  235.           if(tolower(type)=='g') /* This changes to one of the other types */
  236.           { if(ex1<(signed long)preci&&ex1>=-4)
  237.               type='f';
  238.             else
  239.               type=type=='g'?'e':'E';
  240.             preci--;   /* Don't know why ANSI does this! */
  241.             if(!(flags&ALTERNATEFLAG))
  242.               killzeros=1; /* set flag to kill trailing zeros */
  243.           }
  244.  
  245.           dreq=preci+1; /* Calculate number of decimal places required */
  246.           if(type=='f')
  247.             dreq+=ex1;   /* even more before the decimal point */
  248.  
  249.           dnum=0;
  250.           while(dnum<dreq&&dnum<MINFLOATSIZE) /* Calculate all decimal places needed */
  251.           { buffer[dnum++]=(char)v+'0';
  252.             v=(v-(double)(char)v)*10.0; }
  253.  
  254.           if(killzeros) /* Kill trailing zeros if possible */
  255.             while(preci&&(dreq-->dnum||buffer[dreq]=='0'))
  256.               preci--;
  257.  
  258.           if(type=='f')/* Calculate actual size of string (without sign) */
  259.           { size=preci+1; /* numbers after decimal point + 1 before */
  260.             if(ex1>0)
  261.               size+=ex1; /* numbers >= 10 */
  262.             if(preci||flags&ALTERNATEFLAG)
  263.               size++; /* 1 for decimal point */
  264.           }else
  265.           { size=preci+5; /* 1 for the number before the decimal point, and 4 for the exponent */
  266.             if(preci||flags&ALTERNATEFLAG)
  267.               size++;
  268.             if(ex1>99||ex1<-99)
  269.               size++; /* exponent needs an extra decimal place */
  270.           }
  271.  
  272.           pad=size+(sign!=0);
  273.           pad=pad>=width?0:width-pad;
  274.  
  275.           if(sign&&flags&ZEROPADFLAG)
  276.             OUT(sign);
  277.  
  278.           if(!(flags&LALIGNFLAG))
  279.             for(i=0;i<pad;i++)
  280.               OUT(flags&ZEROPADFLAG?'0':' ');
  281.  
  282.           if(sign&&!(flags&ZEROPADFLAG))
  283.             OUT(sign);
  284.  
  285.           dreq=0;
  286.           if(type=='f')
  287.           { if(ex1<0)
  288.               OUT('0');
  289.             else
  290.               while(ex1>=0)
  291.               { OUT(dreq<dnum?buffer[dreq++]:'0');
  292.                 ex1--; }
  293.             if(preci||flags&ALTERNATEFLAG)
  294.             { OUT(__decimalpoint[0]);
  295.               while(preci--)
  296.                 if(++ex1<0)
  297.                   OUT('0');
  298.                 else
  299.                   OUT(dreq<dnum?buffer[dreq++]:'0');
  300.             }
  301.           }else
  302.           { OUT(buffer[dreq++]);
  303.             if(preci||flags&ALTERNATEFLAG)
  304.             { OUT(__decimalpoint[0]);
  305.               while(preci--)
  306.                 OUT(dreq<dnum?buffer[dreq++]:'0');
  307.             }
  308.             OUT(type);
  309.             if(ex1<0)
  310.             { OUT('-');
  311.               ex1=-ex1; }
  312.             else
  313.               OUT('+');
  314.             if(ex1>99)
  315.               OUT(ex1/100+'0');
  316.             OUT(ex1/10%10+'0');
  317.             OUT(ex1%10+'0');
  318.           }
  319.  
  320.           if(flags&LALIGNFLAG)
  321.             for(i=0;i<pad;i++)
  322.               OUT(' ');
  323.  
  324.           width=preci=0; /* Everything already done */
  325.           break;
  326.         }
  327. #endif
  328.         case '%':
  329.           buffer2="%";
  330.           size2=1;
  331.           preci=0;
  332.           break;
  333.         case 'n':
  334.           *va_arg(args,int *)=outcount;
  335.           width=preci=0;
  336.           break;
  337.         default:
  338.           if(!type)
  339.             ptr--; /* We've gone too far - step one back */
  340.           buffer2=(char *)format;
  341.           size2=ptr-format;
  342.           width=preci=0;
  343.           break;
  344.       }
  345.       pad=size1+(size2>=preci?size2:preci); /* Calculate the number of characters */
  346.       pad=pad>=width?0:width-pad; /* and the number of resulting pad bytes */
  347.  
  348.       if(flags&ZEROPADFLAG) /* print sign and that like */
  349.         for(i=0;i<size1;i++)
  350.           OUT(buffer1[i]);
  351.  
  352.       if(!(flags&LALIGNFLAG)) /* Pad left */
  353.         for(i=0;i<pad;i++)
  354.           OUT(flags&ZEROPADFLAG?'0':' ');
  355.  
  356.       if(!(flags&ZEROPADFLAG)) /* print sign if not zero padded */
  357.         for(i=0;i<size1;i++)
  358.           OUT(buffer1[i]);
  359.  
  360.       for(i=size2;i<preci;i++) /* extend to precision */
  361.         OUT('0');
  362.  
  363.       for(i=0;i<size2;i++) /* print body */
  364.         OUT(buffer2[i]);
  365.  
  366.       if(flags&LALIGNFLAG) /* Pad right */
  367.         for(i=0;i<pad;i++)
  368.           OUT(' ');
  369.  
  370.       format=ptr;
  371.     }
  372.     else
  373.       OUT(*format++);
  374.   }
  375.   return outcount;
  376. }
  377.