home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / program / 316 / libsrc / pfguts.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-10-20  |  6.9 KB  |  353 lines

  1.  
  2. /* this is based on the DOPRNT distributed by MUN, but extensively
  3.    hacked by jrd.  It's no longer doprnt, rather it's something general,
  4.    purpose, suitable for underlying various printf variants etc */
  5.  
  6. #include    <varargs.h>
  7. #include    <ctype.h>
  8.  
  9. #define    SZ_NORM        0
  10. #define    SZ_SHORT    1
  11. #define    SZ_LONG        2
  12.  
  13. /* the formatter for flona */
  14. char * _flofmt(buf, flags, value, precision, field_width)
  15. char * buf;
  16. int flags;
  17. double value;
  18. int precision, field_width;
  19. {
  20.   char * orig_buf = buf;
  21.   long int_part;
  22.   int place_number;
  23.   double place;
  24.   char digit[32];
  25.   int idx, ndigits;
  26.   int ten = 10;
  27.   int zero = 0;
  28.  
  29. /* sanity check field qualifiers */
  30.   if (field_width < 30) 
  31.     field_width = 30;
  32.   if (precision > field_width)
  33.     precision = field_width;
  34.   if (precision > 30)
  35.     precision = 30;
  36.  
  37.   if (value < zero)
  38.     {
  39.     *buf++ = '-';
  40.     value = -value;
  41.     }
  42.   int_part = (long )value;
  43.   value = value - (double )int_part;
  44.   for (idx = 0 ; (idx == 0) || (int_part > 0) ; idx++)
  45.     {
  46.     digit[idx] = int_part % ten;
  47. /* kludge til we get doubles accurate... */
  48.     if ((digit[idx] > 9) || (digit[idx] < 0))
  49.         digit[idx] = 0;
  50.     int_part = int_part / ten;
  51.     }
  52.   for ( ; idx > 0 ; )
  53.     *buf++ = digit[--idx] + 48;
  54.  
  55. /* now do the decimal places */
  56.   for (idx = 0 ; idx < 30 ; idx++)
  57.     digit[idx] = 0;
  58.   for (idx = 0, ndigits = 0 ; idx < 10 ; idx++)
  59.     {
  60.     value = value * ten;
  61.     int_part = value;
  62.     value = value - int_part;
  63.     digit[idx] = int_part;
  64. /* kludge til we get doubles accurate... */
  65.     if ((digit[idx] > 9) || (digit[idx] < 0))
  66.         digit[idx] = 0;
  67.     if (int_part > 0) ndigits = idx + 1;
  68.     }
  69.   if (precision > -1)            /* he say how many places? */ 
  70.     ndigits = precision;        /* yes, use his */
  71.   if (ndigits > 0)            /* were there any? */
  72.     {
  73.     *buf++ = '.';
  74.     for (idx = 0 ; idx < ndigits ; idx++)
  75.         {
  76.         *buf++ = digit[idx] + 48;
  77.         }
  78.     }
  79.   *buf = '\0';
  80.   return(orig_buf);  
  81. }
  82.  
  83.  
  84. /* and here's the main loop */
  85. void _printf_guts(template, args, fun, funargs)
  86. char    *template;
  87. va_list    args;
  88. void    (* fun)();    /* foo(char, args) */
  89. long    **funargs;
  90. {
  91.   register char        c;
  92.   register char        *s;
  93.   register char        *p;
  94.   register unsigned long    lnum;
  95.   double        dnum;
  96.   register int        tmp;
  97.   register int        field;
  98.   register int        precision;
  99.   int            hash;
  100.   int            pad;
  101.   int            adjust;
  102.   int            signfmt;
  103.   int            size;
  104.   int            upper;
  105.   int            neg;
  106.   char            numbuf[36];
  107.  
  108.   if (!template)
  109.     return;
  110.  
  111.   while (c = *template++) 
  112.     {
  113.     if (c == '%') 
  114.         {
  115.         c = *template++;
  116.         if (c == '#')
  117.             hash = 1, c = *template++;
  118.             else
  119.             hash = 0;
  120.  
  121.         signfmt = 0;
  122.         adjust = 0;
  123.         while (1) 
  124.             {
  125.             if (c == '-')
  126.                 adjust = 1, c = *template++;
  127.             else if (c == '+')
  128.                 signfmt = 1, c = *template++;
  129.             else if (c == ' ') 
  130.                 {
  131.                 if (!signfmt)    /* + take presidence */
  132.                     signfmt = -1;
  133.                 c = *template++;
  134.                 }
  135.                 else
  136.                 break;
  137.             }
  138.  
  139.         pad = ' ';
  140.         field = 0;
  141.         if (c == '0')
  142.             pad = '0', c = *template++;
  143.         if (isdigit(c)) 
  144.             {
  145.             while (isdigit(c)) 
  146.                 {
  147.                 field = field * 10 + c - '0';
  148.                 c = *template++;
  149.                 }
  150.             }
  151.             else
  152.         if (c == '*') 
  153.             {
  154.             field = va_arg(args, int), c = *template++;
  155.             if (field < 0) 
  156.                 {
  157.                 field = -field;
  158.                 adjust = 1;
  159.                 }
  160.             }
  161.  
  162.         precision = 32000;
  163.         if (c == '.') 
  164.             {
  165.             c = *template++;
  166.             if (c == '*') 
  167.                 {
  168.                 precision = va_arg(args, int);
  169.                 c = *template++;
  170.                 }
  171.                 else 
  172.                 {
  173.                 precision = 0;
  174.                 while (isdigit(c)) 
  175.                     {
  176.                     precision = precision * 10
  177.                         + c - '0';
  178.                     c = *template++;
  179.                     }
  180.                 }
  181.             }
  182.  
  183.         size = SZ_NORM;
  184.         if (c == 'l')
  185.             size = SZ_LONG, c = *template++;
  186.         else if (c == 'h')
  187.             size = SZ_SHORT, c = *template++;
  188.         /* This is dodgy - does X mean long hex or
  189.          * use uppercase hex digits?  Does both right
  190.          * now so becareful...
  191.          */
  192.         if (isupper(c))
  193.             upper = 1, size = SZ_LONG, c = tolower(c);
  194.             else
  195.             upper = 0;
  196.  
  197.         if (c == 'd' || c == 'o' || c == 'x' || c == 'u')
  198.             switch (size) 
  199.                 {
  200.             case SZ_NORM:
  201.             case SZ_SHORT:
  202.                 /* What kinda of machine we on?
  203.                  * hopfully the C compiler will
  204.                  * optimize this out...
  205.                  *
  206.                  * For shorts, we want sign extend
  207.                  * for %d but not for %[oxu] -
  208.                  * on 16 bit machines it don't
  209.                  * matter.
  210.                  * Assmumes C compiler has converted
  211.                  * shorts to ints before pushing them.
  212.                  */
  213.                 if (sizeof(int) < sizeof(long))
  214.                     lnum = (c == 'd') ? (long)
  215.                         va_arg(args, int) :
  216.                         va_arg(args, unsigned);
  217.                     else
  218.                     lnum = va_arg(args, unsigned);
  219.                 break;
  220.  
  221.             case SZ_LONG:
  222.                 lnum = va_arg(args, unsigned long);
  223.                 }
  224.  
  225.         else if (c == 'e' || c == 'g' || c == 'f')
  226.             {
  227.             dnum = va_arg(args, double);
  228.             }
  229.  
  230.         switch (c) 
  231.             {
  232.         case 'd':
  233.             if (0 > (long) lnum)
  234.                 lnum = - (long) lnum, neg = 1;
  235.             else
  236.                 neg = 0;
  237.             s = &numbuf[sizeof(numbuf)];
  238.             *--s = '\0';
  239.             do     {
  240.                 *--s = lnum % 10 + '0';
  241.                 lnum /= 10;
  242.                 } while (lnum);
  243.  
  244.             if (neg)
  245.                 *--s = '-';
  246.             else if (signfmt > 0)
  247.                 *--s = '+';
  248.             else if (signfmt < 0)
  249.                 *--s = ' ';
  250.             goto put_string;
  251.  
  252.         case 'o':
  253.             s = &numbuf[sizeof(numbuf)];
  254.             *--s = '\0';
  255.             do     {
  256.                 *--s = (lnum & 0x7) + '0';
  257.                 lnum >>= 3;
  258.                 } while (lnum);
  259.  
  260.             if (hash && s[1])
  261.                 *--s = '0';
  262.             goto put_string;
  263.  
  264.         case 'x':
  265.             s = &numbuf[sizeof(numbuf)];
  266.             *--s = '\0';
  267.             p = upper ? "0123456789ABCDEF" :
  268.                 "0123456789abcdef";
  269.             do     {
  270.                 *--s = p[lnum & 0x0F];
  271.                 lnum >>= 4;
  272.                 } while (lnum);
  273.  
  274.             if (hash && s[1])
  275.                 *--s = upper ? 'X' : 'x', *--s = '0';
  276.             goto put_string;
  277.  
  278.         case 'u':
  279.             s = &numbuf[sizeof(numbuf)];
  280.             *--s = '\0';
  281.             do     {
  282.                 *--s = lnum % 10 + '0';
  283.                 lnum /= 10;
  284.                 } while (lnum);
  285.             goto put_string;
  286.  
  287.         case 'c':
  288.             (* fun)(va_arg(args, int), funargs);
  289.             break;
  290.  
  291.         case '%':
  292.             (* fun)('%', funargs);
  293.             break;
  294.  
  295.         case 'e': case 'g': case 'f':
  296.             {
  297.             {
  298.             char dbuf[64];
  299.  
  300.             if (precision == 32000)
  301.                 precision = -1;
  302.             s = _flofmt(&dbuf, 0, dnum, precision, field);
  303.             if (precision < strlen(s))
  304.                 precision = strlen(s);
  305.                     /* don't confuse string copier. */
  306.             };
  307.             goto put_string;
  308.             };
  309.  
  310.         case 's':
  311.             s = va_arg(args, char *);
  312.             /* fall through */
  313.  
  314. put_string:
  315.             /* we have a string, now format & print it */
  316.             tmp = strlen(s);
  317.             if (tmp < precision)
  318.                 precision = tmp;
  319.             if (field > precision) 
  320.                 {
  321.                 tmp = field - precision;
  322.                 if (adjust)
  323.                     adjust = tmp, pad = ' ';
  324.                 else
  325.                     adjust = -tmp;
  326.                 }
  327.                 else
  328.             if (field == precision)
  329.                 adjust = 0;
  330.             while (adjust < 0) 
  331.                 {
  332.                 if ((*s == '-') && (pad == '0')) 
  333.                     {
  334.                     (* fun)(*s++, funargs);
  335.                     precision--;
  336.                     }
  337.                 (* fun)(pad, funargs);
  338.                 adjust++;
  339.                 }
  340.             while (--precision >= 0)
  341.                 (* fun)(*s++, funargs);
  342.             while (adjust) 
  343.                 {
  344.                 (* fun)(pad, funargs);
  345.                 adjust--;
  346.                 }
  347.             }
  348.         } 
  349.         else
  350.         (* fun)(c, funargs);
  351.     }
  352. }
  353.