home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 4 / DATAFILE_PDCD4.iso / unix / unixlib36d / src / stdio / c / print < prev    next >
Text File  |  1994-03-08  |  18KB  |  1,046 lines

  1. static char sccs_id[] = "@(#) print.c 3.3 " __DATE__ " HJR";
  2.  
  3. /* print.c (c) Copyright 1990 H.Rogers */
  4.  
  5. /* Implements __printf(buf,format,argp) which is called by
  6.  * all printf() functions to perform formatted output. */
  7.  
  8. /* A conversion is of the form "%[flags][width][.prec][size]function".
  9.  * For full details RTFM for printf(3). */
  10.  
  11. #include <stddef.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <stdarg.h>
  16. #include <stdio.h>
  17.  
  18. __STDIOLIB__
  19.  
  20. /* To avoid truncation PRBUFSIZ should be 256+.
  21.  * This library will *not* buffer overflow unless PRBUFSIZ < 4.
  22.  * ANSI requires at least 509 - 512 sounds sensible (SJC). */
  23.  
  24. #define PRBUFSIZ    4096
  25.  
  26.  
  27. /* The floating point functions are the most efficient they can be without
  28.  * resorting to assuming IEEE 'D' or some other internal representation. */
  29.  
  30. /* Unfortunately most software FP units are *inaccurate* - it
  31.  * is probably worth changing these constants for architectures
  32.  * with built in hardware FP units - make MAXPREC larger &
  33.  * FPERR smaller for higher quality. Note that MAXPREC = 16
  34.  * corresponds to the limits of IEEE Packed Decimal format. */
  35.  
  36. #define MAXPREC     16    /* max. decimal precision for %feEgG */
  37. #define FPERR        1e-14    /* cutoff value for zero test */
  38.  
  39. /* It's probably best to leave POINT alone... It works. */
  40.  
  41. #define POINT        0.01    /* offset to compensate for rounding errors */
  42.  
  43.  
  44. /* the prototypes for the output functions */
  45.  
  46. static char *__p_nout (char *, va_list *);
  47.  
  48. static char *__p_char (char *, va_list *);
  49. static char *__p_str (char *, va_list *);
  50. static char *__p_sdec (char *, va_list *);
  51. static char *__p_uoct (char *, va_list *);
  52. static char *__p_udec (char *, va_list *);
  53. static char *__p_uhex (char *, va_list *);
  54. static char *__p_ffix (char *, va_list *);
  55. static char *__p_fexp (char *, va_list *);
  56. static char *__p_fmin (char *, va_list *);
  57. static char *__p_ptr (char *, va_list *);
  58.  
  59.  
  60. /* the buffer __prpad has to be prior to __prbuf in memory -
  61.  * __prjust() avoids having to do any buffer copying by being
  62.  * able to back into the __prpad area from __prbuf */
  63.  
  64. static char __prpad[(PRBUFSIZ << 1) + 2];
  65. static char *__prbuf = __prpad + PRBUFSIZ + 1;
  66.  
  67.  
  68. /* __prebuf is set to the start of the output buffer passed to __printf() and
  69.  * is used by __p_nout() to calculate the number of characters output */
  70.  
  71. static char *__prebuf;
  72.  
  73.  
  74. #define P_FLAG0     0x0001    /* '-' */
  75. #define P_FLAG1     0x0002    /* '0' */
  76. #define P_FLAG2     0x0004    /* '+' */
  77. #define P_FLAG3     0x0008    /* ' ' */
  78. #define P_FLAG4     0x0010    /* '#' */
  79. #define P_FLAG5     0x0020    /* 'h' */
  80. #define P_FLAG6     0x0040    /* 'l' */
  81. #define P_FLAG7     0x0080    /* 'L' */
  82.  
  83. static int __prflag;
  84. static unsigned int __prwidth;    /* width */
  85. static int __prprec;        /* -1 = unspecified; precision */
  86. static char __prfc;        /* function character */
  87.  
  88. static signed char __prfnc[32] =    /* conversions */
  89. {
  90.   -1, -1,
  91.   1,                /* %c */
  92.   3,                /* %d */
  93.   9,                /* %eE */
  94.   8,                /* %f */
  95.   10,                /* %gG */
  96.   -1,
  97.   4,                /* %i */
  98.   -1, -1, -1, -1,
  99.   0,                /* %n */
  100.   5,                /* %o */
  101.   11,                /* %p */
  102.   -1, -1,
  103.   2,                /* %s */
  104.   -1,
  105.   6,                /* %u */
  106.   -1, -1,
  107.   7,                /* %xX */
  108.   -1, -1, -1, -1, -1, -1, -1, -1
  109. };
  110.  
  111. /* __prfn[] is the array of output functions called by __printf() -
  112.  * they return a pointer to the end of the string (which is *not*
  113.  * necessarily 0 terminated) */
  114.  
  115. static char *(*__prfn[]) (char *, va_list *) =
  116. {
  117.   __p_nout,            /* %n no. of characters output so far */
  118.     __p_char,            /* %c character */
  119.     __p_str,            /* %s string */
  120.     __p_sdec,            /* %d signed decimal */
  121.     __p_sdec,            /* %i signed decimal */
  122.     __p_uoct,            /* %o unsigned octal */
  123.     __p_udec,            /* %u unsigned decimal */
  124.     __p_uhex,            /* %xX unsigned hex */
  125.     __p_ffix,            /* %f fixed notation double */
  126.     __p_fexp,            /* %eE exponential notation double */
  127.     __p_fmin,            /* %gG minimised space notation double */
  128.     __p_ptr            /* %p unsigned hex value of pointer */
  129. };
  130.  
  131.  
  132. /* __printf() */
  133.  
  134. int
  135. __printf (char *buf, const char *format, va_list ap)
  136. {
  137.   register const char *s1 = format;
  138.   register char *s2 = buf;
  139.  
  140.   __prebuf = buf;        /* for __p_nout() */
  141.  
  142.   while (*s1)
  143.     {
  144.       if (*s1 != '%' || *++s1 == '%')    /* left to right evaluation */
  145.     {
  146.       *s2++ = *s1++;
  147.       continue;
  148.     }
  149.  
  150.       {                /* we now have a % conversion */
  151.     register int i;
  152.     char *s;
  153.  
  154. /* looking for "%[flags][width][.prec][size]function" */
  155.  
  156. /* set flags */
  157.  
  158.     __prflag = 0;
  159.       flag:
  160.     if (*s1 == '-')
  161.       {
  162.         __prflag |= P_FLAG0, s1++;
  163.         goto flag;
  164.       }
  165.     if (*s1 == '0')
  166.       {
  167.         __prflag |= P_FLAG1, s1++;
  168.         goto flag;
  169.       }
  170.     if (*s1 == '+')
  171.       {
  172.         __prflag |= P_FLAG2, s1++;
  173.         goto flag;
  174.       }
  175.     if (*s1 == ' ')
  176.       {
  177.         __prflag |= P_FLAG3, s1++;
  178.         goto flag;
  179.       }
  180.     if (*s1 == '#')
  181.       {
  182.         __prflag |= P_FLAG4, s1++;
  183.         goto flag;
  184.       }
  185.  
  186. /* set __prwidth */
  187.  
  188.     __prwidth = 0;
  189.     if (isdigit (*s1))
  190.       {
  191.         __prwidth = (unsigned int) strtoul (s1, &s, 0);
  192.         s1 = s;
  193.       }
  194.     else
  195.       {
  196.         if (*s1 == '*')
  197.           {
  198.         __prwidth = va_arg (ap, int);
  199.         s1++;
  200.           }
  201.       }
  202.     if (__prwidth > PRBUFSIZ)
  203.       __prwidth = PRBUFSIZ;
  204.  
  205. /* set __prprec */
  206.  
  207.     __prprec = -1;
  208.     if (*s1 == '.')
  209.       {
  210.         s1++;
  211.         if (isdigit (*s1))
  212.           {
  213.         __prprec = (int) strtol (s1, &s, 0);
  214.         s1 = s;
  215.           }
  216.         else
  217.           {
  218.         if (*s1 == '*')
  219.           {
  220.             __prprec = va_arg (ap, int);
  221.             s1++;
  222.           }
  223.           }
  224.       }
  225.  
  226. /* set size */
  227.  
  228.     if (*s1 == 'h')
  229.       __prflag |= P_FLAG5, s1++;
  230.     else if (*s1 == 'l')
  231.       __prflag |= P_FLAG6, s1++;
  232.     else if (*s1 == 'L')
  233.       __prflag |= P_FLAG7, s1++;
  234.  
  235. /* call appropriate output function */
  236.  
  237.     i = __prfnc[(_tolower (*s1) - 'a') & 31];
  238.  
  239.     if (i >= 0)
  240.       {
  241.         __prfc = *s1;
  242.         s2 = (*__prfn[i]) (s2, (va_list *) (&ap));
  243.       }
  244.  
  245.     s1++;
  246.       }
  247.     }
  248.  
  249.   *s2 = 0;
  250.  
  251.   return ((size_t) (s2 - buf));    /* number of characters output */
  252. }
  253.  
  254.  
  255. /* __prjust() */
  256.  
  257. /* __prjust() justifies the string at __prbuf according to __prwidth etc.
  258.  * it's argument is the *end* of the string at __prbuf - it returns the
  259.  * start of the justified string. */
  260.  
  261. static char *
  262. __prjust (register char *e)
  263. {
  264.   register char *s1, *s2;
  265.   register char p;
  266.  
  267.   s1 = __prbuf;
  268.  
  269.   p = (__prflag & P_FLAG1) ? '0' : ' ';
  270.  
  271.   if (__prflag & P_FLAG0)
  272.     {
  273.       s2 = s1 + __prwidth;
  274.       while (e < s2)
  275.     *e++ = ' ';
  276.       *e = 0;
  277.       return (s1);
  278.     }
  279.   else
  280.     {
  281.       if ((e -= __prwidth) < s1)
  282.     {
  283.       s2 = e;
  284.       while (e < s1)
  285.         *e++ = p;
  286.       return (s2);
  287.     }
  288.       return (s1);
  289.     }
  290. }
  291.  
  292. /* __prdec() */
  293.  
  294. /* __prdec() is a subroutine (called by __p_...() functions) that writes
  295.  * a decimal number <x> backwards from <e> towards <b>, digit by digit */
  296.  
  297. static char *
  298. __prdec (register char *b, register char *e, register unsigned int x)
  299. {
  300.   *e = 0;
  301.   do
  302.     {
  303.       *--e = (x % 10) + '0';
  304.       x /= 10;
  305.     }
  306.   while (x && e > b);
  307.  
  308.   return (e);
  309. }
  310.  
  311. /* __prexp() */
  312.  
  313. /* __prexp() normalises <x> to a number of the form n.nnnn...
  314.  * and stores the exponent in *<e> */
  315.  
  316. static double
  317. __prexp (register double x, register int *e)
  318. {
  319.   register int h;
  320.  
  321.   h = 0;
  322.  
  323.   if (x != 0)
  324.     {
  325.       if (x >= 10)
  326.     {
  327.       register double l = 0, m = 10;
  328.  
  329.       while (x >= m)
  330.         {
  331.           l = m, m *= 10;
  332.           h++;
  333.         }
  334.       if (l)
  335.         x /= l;
  336.     }
  337.       else
  338.     {
  339.       while (x < 1)
  340.         {
  341.           x *= 10;
  342.           h--;
  343.         }
  344.     }
  345.     }
  346.  
  347. /* x is now n.nnnn... */
  348.  
  349.   *e = h;
  350.   return (x);
  351. }
  352.  
  353.  
  354. /* __p_nout() */
  355.  
  356. static char *
  357. __p_nout (register char *s, register va_list * ap)    /* %n */
  358. {
  359.   if (__prflag & P_FLAG5)
  360.     *va_arg (*ap, short *) = (short) (s - __prebuf);
  361.   else if (__prflag & P_FLAG6)
  362.     *va_arg (*ap, long *) = (long) (s - __prebuf);
  363.   else
  364.     *va_arg (*ap, int *) = (int) (s - __prebuf);
  365.  
  366.   return (s);
  367. }
  368.  
  369. /* __p_char() */
  370.  
  371. static char *
  372. __p_char (register char *s, register va_list * ap)    /* %c */
  373. {
  374.   register char *b;
  375.  
  376.   if (!__prwidth)
  377.     *s++ = va_arg (*ap, char);
  378.   else
  379.     {
  380.       b = __prbuf;
  381.       *b++ = va_arg (*ap, char);
  382.       *b = 0;
  383.       b = __prjust (b);
  384.       while (*s = *b)
  385.     s++, b++;
  386.     }
  387.  
  388.   return (s);
  389. }
  390.  
  391. /* __p_str() */
  392.  
  393. static char *
  394. __p_str (register char *s, register va_list * ap)    /* %s */
  395. {
  396.   register char *_s;
  397.   register char *b, *e;
  398.   register int p;
  399.  
  400.   p = (__prprec < 0) ? 0 : __prprec;
  401.   if (p > PRBUFSIZ)
  402.     p = PRBUFSIZ;
  403.  
  404.   _s = va_arg (*ap, char *);
  405.  
  406. /* tolerance */
  407.  
  408.   if (!