home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD2.bin / bbs / gnu / libnix-0.8-src.lha / libnix-0.8 / sources / nix / stdio / vfprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-12  |  10.5 KB  |  379 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 (DBL_DIG+1) /* Why not 1 more - it's 97% reliable */
  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.  
  34. int vfprintf(FILE *stream,const char *format,va_list args)
  35.   size_t outcount=0;
  36.  
  37.   while(*format)
  38.   {
  39.     if(*format=='%')
  40.     { 
  41.       static char flagc[]=
  42.       { '#','0','-',' ','+' };
  43.       static char lowertabel[]=
  44.       { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
  45.       static char uppertabel[]=
  46.       { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
  47.       size_t width=0,preci=ULONG_MAX,flags=0; /* Specifications */
  48.       char type,subtype='i';
  49.       char buffer1[2];             /* Signs and that like */
  50.       char buffer[REQUIREDBUFFER]; /* The body */
  51.       char *buffer2=buffer;        /* So we can set this to any other strings */
  52.       size_t size1=0,size2=0;      /* How many chars in buffer? */
  53.       const char *ptr=format+1;    /* pointer to format string */
  54.       size_t i,pad;                /* Some temporary variables */
  55.  
  56.       do /* read flags */
  57.         for(i=0;i<sizeof(flagc);i++)
  58.           if(flagc[i]==*ptr)
  59.           { flags|=1<<i;
  60.             ptr++;
  61.             break; }
  62.       while(i<sizeof(flagc));
  63.  
  64.       if(*ptr=='*') /* read width from arguments */
  65.       { signed int a;
  66.         ptr++;
  67.         a=va_arg(args,signed int);
  68.         if(a<0)
  69.         { flags|=LALIGNFLAG;
  70.           width=-a; }
  71.         else
  72.           width=a;
  73.       }else
  74.         while(isdigit(*ptr))
  75.           width=width*10+(*ptr++-'0');
  76.  
  77.       if(*ptr=='.')
  78.       { ptr++;
  79.         if(*ptr=='*') /* read precision from arguments */
  80.         { signed int a;
  81.           ptr++;
  82.           a=va_arg(args,signed int);
  83.           if(a>=0)
  84.             preci=a;
  85.         }else
  86.         { preci=0;
  87.           while(isdigit(*ptr))
  88.             preci=preci*10+(*ptr++-'0');
  89.         }
  90.       }
  91.  
  92.       if(*ptr=='h'||*ptr=='l'||*ptr=='L')
  93.         subtype=*ptr++;
  94.  
  95.       type=*ptr++;
  96.  
  97.       switch(type)
  98.       { case 'd':
  99.         case 'i':
  100.         case 'o':
  101.         case 'p':
  102.         case 'u':
  103.         case 'x':
  104.         case 'X':
  105.         { unsigned long v;
  106.           char *tabel;
  107.           int base;
  108.  
  109.           if(type=='p')
  110.           { subtype='l'; /* This is written as %#lx */
  111.             type='x';
  112.             flags|=ALTERNATEFLAG; }
  113.  
  114.           if(type=='d'||type=='i') /* These are signed */
  115.           { signed long v2;
  116.             if(subtype=='l')
  117.               v2=va_arg(args,signed long);
  118.             else
  119.               v2=va_arg(args,signed int);
  120.             if(v2<0)
  121.             { buffer1[size1++]='-';
  122.               v=-v2;
  123.             }else
  124.             { if(flags&SIGNFLAG)
  125.                 buffer1[size1++]='+';
  126.               else if(flags&BLANKFLAG)
  127.                 buffer1[size1++]=' ';
  128.               v=v2; }
  129.           }else                    /* These are unsigned */
  130.           { if(subtype=='l')
  131.               v=va_arg(args,unsigned long);
  132.             else
  133.               v=va_arg(args,unsigned int);
  134.             if(flags&ALTERNATEFLAG)
  135.             { if(type=='o'&&(preci||v))
  136.                 buffer1[size1++]='0';
  137.               if((type=='x'||type=='X')&&v)
  138.               { buffer1[size1++]='0';
  139.                 buffer1[size1++]=type; }
  140.             }
  141.           }
  142.  
  143.           buffer2=&buffer[sizeof(buffer)]; /* Calculate body string */
  144.           base=type=='x'||type=='X'?16:(type=='o'?8:10);
  145.           tabel=type!='X'?lowertabel:uppertabel;
  146.           do
  147.           { *--buffer2=tabel[v%base];
  148.             v=v/base;
  149.             size2++;
  150.           }while(v);
  151.           if(preci==ULONG_MAX) /* default */
  152.             preci=0;
  153.           else
  154.             flags&=~ZEROPADFLAG;
  155.           break;
  156.         }
  157.         case 'c':
  158.           if(subtype=='l')
  159.             *buffer2=va_arg(args,long);
  160.           else
  161.             *buffer2=va_arg(args,int);
  162.           size2=1;
  163.           preci=0;
  164.           break;
  165.         case 's':
  166.           buffer2=va_arg(args,char *);
  167.           size2=strlen(buffer2);
  168.           size2=size2<=preci?size2:preci;
  169.           preci=0;
  170.           break;
  171. #ifdef FULL_SPECIFIERS
  172.         case 'f':
  173.         case 'e':
  174.         case 'E':
  175.         case 'g':
  176.         case 'G':
  177.         { double v;
  178.           char killzeros=0,sign=0; /* some flags */
  179.           int ex1,ex2; /* Some temporary variables */
  180.           size_t size,dnum,dreq;
  181.           char *udstr=NULL;
  182.  
  183.           v=va_arg(args,double);
  184.  
  185.           if(isinf(v))
  186.           { if(v>0)
  187.               udstr="+inf";
  188.             else
  189.               udstr="-inf";
  190.           }else if(isnan(v))
  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.             if(v<1.0)
  216.               v=v*pow(10,- --ex1); /* Caution: (int)log10(.5)!=-1 */
  217.             else
  218.               v=v/pow(10,ex1);
  219.             if(v<1.0) /* adjust if we are too low (log10(.1)=-.999999999) */
  220.             { v*=10.0; /* luckily this cannot happen with FLT_MAX and FLT_MIN */
  221.               ex1--; } /* The case too high (log(10.)=.999999999) is done later */
  222.           }
  223.  
  224.           ex2=preci;
  225.           if(type=='f')
  226.             ex2+=ex1;
  227.           if(tolower(type)=='g')
  228.             ex2--;
  229.           v+=.5/pow(10,ex2<MINFLOATSIZE?ex2:MINFLOATSIZE); /* 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.               preci-=ex1;
  239.             }else
  240.               type=type=='g'?'e':'E';
  241.             preci--;
  242.             if(!(flags&ALTERNATEFLAG))
  243.               killzeros=1; /* set flag to kill trailing zeros */
  244.           }
  245.  
  246.           dreq=preci+1; /* Calculate number of decimal places required */
  247.           if(type=='f')
  248.             dreq+=ex1;   /* even more before the decimal point */
  249.  
  250.           dnum=0;
  251.           while(dnum<dreq&&dnum<MINFLOATSIZE) /* Calculate all decimal places needed */
  252.           { buffer[dnum++]=(char)v+'0';
  253.             v=(v-(double)(char)v)*10.0; }
  254.  
  255.           if(killzeros) /* Kill trailing zeros if possible */
  256.             while(preci&&(dreq-->dnum||buffer[dreq]=='0'))
  257.               preci--;
  258.  
  259.           if(type=='f')/* Calculate actual size of string (without sign) */
  260.           { size=preci+1; /* numbers after decimal point + 1 before */
  261.             if(ex1>0)
  262.               size+=ex1; /* numbers >= 10 */
  263.             if(preci||flags&ALTERNATEFLAG)
  264.               size++; /* 1 for decimal point */
  265.           }else
  266.           { size=preci+5; /* 1 for the number before the decimal point, and 4 for the exponent */
  267.             if(preci||flags&ALTERNATEFLAG)
  268.               size++;
  269.             if(ex1>99||ex1<-99)
  270.               size++; /* exponent needs an extra decimal place */
  271.           }
  272.  
  273.           pad=size+(sign!=0);
  274.           pad=pad>=width?0:width-pad;
  275.  
  276.           if(sign&&flags&ZEROPADFLAG)
  277.             OUT(sign);
  278.  
  279.           if(!(flags&LALIGNFLAG))
  280.             for(i=0;i<pad;i++)
  281.               OUT(flags&ZEROPADFLAG?'0':' ');
  282.  
  283.           if(sign&&!(flags&ZEROPADFLAG))
  284.             OUT(sign);
  285.  
  286.           dreq=0;
  287.           if(type=='f')
  288.           { if(ex1<0)
  289.               OUT('0');
  290.             else
  291.               while(ex1>=0)
  292.               { OUT(dreq<dnum?buffer[dreq++]:'0');
  293.                 ex1--; }
  294.             if(preci||flags&ALTERNATEFLAG)
  295.             { OUT(__decimalpoint[0]);
  296.               while(preci--)
  297.                 if(++ex1<0)
  298.                   OUT('0');
  299.                 else
  300.                   OUT(dreq<dnum?buffer[dreq++]:'0');
  301.             }
  302.           }else
  303.           { OUT(buffer[dreq++]);
  304.             if(preci||flags&ALTERNATEFLAG)
  305.             { OUT(__decimalpoint[0]);
  306.               while(preci--)
  307.                 OUT(dreq<dnum?buffer[dreq++]:'0');
  308.             }
  309.             OUT(type);
  310.             if(ex1<0)
  311.             { OUT('-');
  312.               ex1=-ex1; }
  313.             else
  314.               OUT('+');
  315.             if(ex1>99)
  316.               OUT(ex1/100+'0');
  317.             OUT(ex1/10%10+'0');
  318.             OUT(ex1%10+'0');
  319.           }
  320.  
  321.           if(flags&LALIGNFLAG)
  322.             for(i=0;i<pad;i++)
  323.               OUT(' ');
  324.  
  325.           width=preci=0; /* Everything already done */
  326.           break;
  327.         }
  328. #endif
  329.         case '%':
  330.           buffer2="%";
  331.           size2=1;
  332.           preci=0;
  333.           break;
  334.         case 'n':
  335.           *va_arg(args,int *)=outcount;
  336.           width=preci=0;
  337.           break;
  338.         default:
  339.           if(!type)
  340.             ptr--; /* We've gone too far - step one back */
  341.           buffer2=(char *)format;
  342.           size2=ptr-format;
  343.           width=preci=0;
  344.           break;
  345.       }
  346.       pad=size1+(size2>=preci?size2:preci); /* Calculate the number of characters */
  347.       pad=pad>=width?0:width-pad; /* and the number of resulting pad bytes */
  348.  
  349.       if(flags&ZEROPADFLAG) /* print sign and that like */
  350.         for(i=0;i<size1;i++)
  351.           OUT(buffer1[i]);
  352.  
  353.       if(!(flags&LALIGNFLAG)) /* Pad left */
  354.         for(i=0;i<pad;i++)
  355.           OUT(flags&ZEROPADFLAG?'0':' ');
  356.  
  357.       if(!(flags&ZEROPADFLAG)) /* print sign if not zero padded */
  358.         for(i=0;i<size1;i++)
  359.           OUT(buffer1[i]);
  360.  
  361.       for(i=size2;i<preci;i++) /* extend to precision */
  362.         OUT('0');
  363.  
  364.       for(i=0;i<size2;i++) /* print body */
  365.         OUT(buffer2[i]);
  366.  
  367.       if(flags&LALIGNFLAG) /* Pad right */
  368.         for(i=0;i<pad;i++)
  369.           OUT(' ');
  370.  
  371.       format=ptr;
  372.     }
  373.     else
  374.       OUT(*format++);
  375.   }
  376.   return outcount;
  377. }
  378.