home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / trash / part02 / format.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-22  |  5.0 KB  |  291 lines

  1. #include    <varargs.h>
  2.  
  3. /*
  4.  * format converts and formats its args under control of the format.
  5.  * The format is a character string that contains two types of
  6.  * objects:  plain characters, which are simply passed one at a time
  7.  * to putfn, and conversion specifications, each of which results in
  8.  * fetching of zero or more args.  The results are undefined if
  9.  * there are insufficient args for the format.  If the format
  10.  * is exhausted while args remain, the excess args are simply
  11.  * ignored.
  12.  * 
  13.  * Each conversion specification is introduced by the character
  14.  * %.  After the %, any of the following may appear in sequence:
  15.  * 
  16.  * A set of flags, which modify the meaning of the
  17.  * conversion specification.
  18.  * 
  19.  * A zero digit (0) specifying the pad character as 0.
  20.  * 
  21.  * A decimal digit string specifying a minimum field width.
  22.  * 
  23.  * A period (.) followed by a decimal digit string specifying a precision.
  24.  * 
  25.  * An l (ell) specifying that a following conversion character
  26.  * applies to a long arg.
  27.  * 
  28.  * A character that indicates the type of conversion to be
  29.  * applied.
  30.  */
  31.  
  32. #define    doit(c, v)    sprintf(&a[0], mkfmt((c)), (v)), outstring(&a[0])
  33.  
  34. static int    (*putfn)();
  35. static int    flag_minus;
  36. static int    flag_plus;
  37. static int    flag_blank;
  38. static int    flag_hash;
  39. static char    pad_character;
  40. static int    have_width;
  41. static int    minimum_field_width;
  42. static int    have_precision;
  43. static int    precision;
  44. static int    use_short_form;
  45. static int    use_long_form;
  46. static char    a[256];
  47.  
  48. static
  49. char    *
  50. mkfmt(c)
  51. char    c;
  52. {
  53.     extern int    strlen();
  54.     static char    a[32];
  55.  
  56.     (void)sprintf
  57.     (
  58.         &a[0],
  59.         "%%%s%s%s%s%s",
  60.         flag_minus ? "-" : "",
  61.         flag_plus ? "+" : "",
  62.         flag_blank ? " " : "",
  63.         flag_hash ? "#" : "",
  64.         (pad_character == '0') ? "0" : ""
  65.     );
  66.  
  67.     if (have_width)
  68.         (void)sprintf(&a[strlen(&a[0])], "%d", minimum_field_width);
  69.  
  70.     if (have_precision)
  71.         (void)sprintf(&a[strlen(&a[0])], ".%d", precision);
  72.  
  73.     (void)sprintf
  74.     (
  75.         &a[strlen(&a[0])],
  76.         "%s%s%c",
  77.         use_short_form ? "h" : "",
  78.         use_long_form ? "l" : "",
  79.         c
  80.     );
  81.  
  82.     return &a[0];
  83. }
  84.  
  85. static
  86. void
  87. outstring(s)
  88. register char    *s;
  89. {
  90.     while (*s != '\0')
  91.         (*putfn)(*s++);
  92. }
  93.  
  94. void
  95. format(uputfn, app)
  96. register int        (*uputfn)();
  97. register va_list    *app;
  98. {
  99.     register char    *formatp;    /* Pointer to current    */
  100.                     /* format character.    */
  101.     register char    fc;        /* Current format    */
  102.                     /* character.        */
  103.  
  104.     formatp = va_arg(*app, char *);
  105.  
  106.     putfn = uputfn;
  107.  
  108.     while ((fc = *formatp++) != '\0')
  109.     {
  110.         if (fc != '%')
  111.         {
  112.             (*uputfn)(fc);
  113.             continue;
  114.         }
  115.  
  116.         flag_minus = 0;
  117.         flag_plus = 0;
  118.         flag_blank = 0;
  119.         flag_hash = 0;
  120.         pad_character = ' ';
  121.         have_width = 0;
  122.         minimum_field_width = 0;
  123.         have_precision = 0;
  124.         precision = 1;
  125.         use_short_form = 0;
  126.         use_long_form = 0;
  127.  
  128.         /*
  129.          * Read some optional flags.
  130.          */
  131.         for (;;)
  132.         {
  133.             switch (fc = *formatp++)
  134.             {
  135.             case '-':
  136.                 flag_minus = 1;
  137.                 continue;
  138.  
  139.             case '+':
  140.                 flag_plus = 1;
  141.                 flag_blank = 0;
  142.                 continue;
  143.  
  144.             case ' ':
  145.                 if (flag_plus == 0)
  146.                     flag_blank = 1;
  147.                 continue;
  148.  
  149.             case '#':
  150.                 flag_hash = 1;
  151.                 continue;
  152.  
  153.             default:
  154.                 break;
  155.             }
  156.             break;
  157.         }
  158.  
  159.         /*
  160.          * Read an optional '0' pad character specification.
  161.          */
  162.         if (fc == '0')
  163.         {
  164.             pad_character = '0';
  165.             fc = *formatp++;
  166.         }
  167.  
  168.         /*
  169.          * Read an optional minimum field width.
  170.          */
  171.         for (;;)
  172.         {
  173.             if (fc == '*')
  174.                 minimum_field_width = va_arg(*app, int);
  175.             else if (fc >= '0' && fc <= '9')
  176.             {
  177.                 minimum_field_width *= 10;
  178.                 minimum_field_width += fc - '0';
  179.             }
  180.             else
  181.                 break;
  182.  
  183.             have_width = 1;
  184.  
  185.             fc = *formatp++;
  186.         }
  187.  
  188.         /*
  189.          * Read an optional precision specifier.
  190.          */
  191.         if (fc == '.')
  192.         {
  193.             fc = *formatp++;
  194.  
  195.             have_precision = 1;
  196.  
  197.             precision = 0;
  198.  
  199.             for (;;)
  200.             {
  201.                 if (fc == '*')
  202.                     precision = va_arg(*app, int);
  203.                 else if (fc >= '0' && fc <= '9')
  204.                 {
  205.                     precision *= 10;
  206.                     precision += fc - '0';
  207.                 }
  208.                 else
  209.                     break;
  210.  
  211.                 fc = *formatp++;
  212.             }
  213.         }
  214.  
  215.         if (precision < 0)
  216.             precision = 0;
  217.  
  218.         /*
  219.          * Read an optional 'short field' specifier.
  220.          */
  221.         if (fc == 'h')
  222.         {
  223.             use_short_form = 1;
  224.             fc = *formatp++;
  225.         }
  226.  
  227.         /*
  228.          * Read an optional 'long field' specifier.
  229.          */
  230.         if (fc == 'l')
  231.         {
  232.             use_long_form = 1;
  233.             fc = *formatp++;
  234.         }
  235.  
  236.         /*
  237.          * Read the conversion character.
  238.          * Do the formatting.
  239.          */
  240.         switch (fc)
  241.         {
  242.         case 'c':
  243.             doit(fc, (char)va_arg(*app, int));
  244.             break;
  245.  
  246.         case 'd':
  247.         case 'i':
  248.             if (use_short_form)
  249.                 doit(fc, (short)va_arg(*app, int));
  250.             else if (use_long_form)
  251.                 doit(fc, va_arg(*app, long));
  252.             else
  253.                 doit(fc, va_arg(*app, int));
  254.             break;
  255.  
  256.         case 'E':
  257.         case 'e':
  258.         case 'f':
  259.         case 'G':
  260.         case 'g':
  261.             doit(fc, va_arg(*app, double));
  262.             break;
  263.  
  264.         case 's':
  265.             doit(fc, va_arg(*app, char *));
  266.             break;
  267.  
  268.         case 'o':
  269.         case 'u':
  270.         case 'X':
  271.         case 'x':
  272.             if (use_short_form)
  273.                 doit(fc, (unsigned short)va_arg(*app, unsigned int));
  274.             else if (use_long_form)
  275.                 doit(fc, va_arg(*app, unsigned long));
  276.             else
  277.                 doit(fc, va_arg(*app, unsigned int));
  278.             break;
  279.  
  280.         case '\0':
  281.             formatp--;
  282.             fc = '%';
  283.             /* and fall thru. */
  284.         case '%':
  285.         default:
  286.             (*uputfn)(fc);
  287.             break;
  288.         }
  289.     }
  290. }
  291.