home *** CD-ROM | disk | FTP | other *** search
- #include <varargs.h>
-
- /*
- * format converts and formats its args under control of the format.
- * The format is a character string that contains two types of
- * objects: plain characters, which are simply passed one at a time
- * to putfn, and conversion specifications, each of which results in
- * fetching of zero or more args. The results are undefined if
- * there are insufficient args for the format. If the format
- * is exhausted while args remain, the excess args are simply
- * ignored.
- *
- * Each conversion specification is introduced by the character
- * %. After the %, any of the following may appear in sequence:
- *
- * A set of flags, which modify the meaning of the
- * conversion specification.
- *
- * A zero digit (0) specifying the pad character as 0.
- *
- * A decimal digit string specifying a minimum field width.
- *
- * A period (.) followed by a decimal digit string specifying a precision.
- *
- * An l (ell) specifying that a following conversion character
- * applies to a long arg.
- *
- * A character that indicates the type of conversion to be
- * applied.
- */
-
- #define doit(c, v) sprintf(&a[0], mkfmt((c)), (v)), outstring(&a[0])
-
- static int (*putfn)();
- static int flag_minus;
- static int flag_plus;
- static int flag_blank;
- static int flag_hash;
- static char pad_character;
- static int have_width;
- static int minimum_field_width;
- static int have_precision;
- static int precision;
- static int use_short_form;
- static int use_long_form;
- static char a[256];
-
- static
- char *
- mkfmt(c)
- char c;
- {
- extern int strlen();
- static char a[32];
-
- (void)sprintf
- (
- &a[0],
- "%%%s%s%s%s%s",
- flag_minus ? "-" : "",
- flag_plus ? "+" : "",
- flag_blank ? " " : "",
- flag_hash ? "#" : "",
- (pad_character == '0') ? "0" : ""
- );
-
- if (have_width)
- (void)sprintf(&a[strlen(&a[0])], "%d", minimum_field_width);
-
- if (have_precision)
- (void)sprintf(&a[strlen(&a[0])], ".%d", precision);
-
- (void)sprintf
- (
- &a[strlen(&a[0])],
- "%s%s%c",
- use_short_form ? "h" : "",
- use_long_form ? "l" : "",
- c
- );
-
- return &a[0];
- }
-
- static
- void
- outstring(s)
- register char *s;
- {
- while (*s != '\0')
- (*putfn)(*s++);
- }
-
- void
- format(uputfn, app)
- register int (*uputfn)();
- register va_list *app;
- {
- register char *formatp; /* Pointer to current */
- /* format character. */
- register char fc; /* Current format */
- /* character. */
-
- formatp = va_arg(*app, char *);
-
- putfn = uputfn;
-
- while ((fc = *formatp++) != '\0')
- {
- if (fc != '%')
- {
- (*uputfn)(fc);
- continue;
- }
-
- flag_minus = 0;
- flag_plus = 0;
- flag_blank = 0;
- flag_hash = 0;
- pad_character = ' ';
- have_width = 0;
- minimum_field_width = 0;
- have_precision = 0;
- precision = 1;
- use_short_form = 0;
- use_long_form = 0;
-
- /*
- * Read some optional flags.
- */
- for (;;)
- {
- switch (fc = *formatp++)
- {
- case '-':
- flag_minus = 1;
- continue;
-
- case '+':
- flag_plus = 1;
- flag_blank = 0;
- continue;
-
- case ' ':
- if (flag_plus == 0)
- flag_blank = 1;
- continue;
-
- case '#':
- flag_hash = 1;
- continue;
-
- default:
- break;
- }
- break;
- }
-
- /*
- * Read an optional '0' pad character specification.
- */
- if (fc == '0')
- {
- pad_character = '0';
- fc = *formatp++;
- }
-
- /*
- * Read an optional minimum field width.
- */
- for (;;)
- {
- if (fc == '*')
- minimum_field_width = va_arg(*app, int);
- else if (fc >= '0' && fc <= '9')
- {
- minimum_field_width *= 10;
- minimum_field_width += fc - '0';
- }
- else
- break;
-
- have_width = 1;
-
- fc = *formatp++;
- }
-
- /*
- * Read an optional precision specifier.
- */
- if (fc == '.')
- {
- fc = *formatp++;
-
- have_precision = 1;
-
- precision = 0;
-
- for (;;)
- {
- if (fc == '*')
- precision = va_arg(*app, int);
- else if (fc >= '0' && fc <= '9')
- {
- precision *= 10;
- precision += fc - '0';
- }
- else
- break;
-
- fc = *formatp++;
- }
- }
-
- if (precision < 0)
- precision = 0;
-
- /*
- * Read an optional 'short field' specifier.
- */
- if (fc == 'h')
- {
- use_short_form = 1;
- fc = *formatp++;
- }
-
- /*
- * Read an optional 'long field' specifier.
- */
- if (fc == 'l')
- {
- use_long_form = 1;
- fc = *formatp++;
- }
-
- /*
- * Read the conversion character.
- * Do the formatting.
- */
- switch (fc)
- {
- case 'c':
- doit(fc, (char)va_arg(*app, int));
- break;
-
- case 'd':
- case 'i':
- if (use_short_form)
- doit(fc, (short)va_arg(*app, int));
- else if (use_long_form)
- doit(fc, va_arg(*app, long));
- else
- doit(fc, va_arg(*app, int));
- break;
-
- case 'E':
- case 'e':
- case 'f':
- case 'G':
- case 'g':
- doit(fc, va_arg(*app, double));
- break;
-
- case 's':
- doit(fc, va_arg(*app, char *));
- break;
-
- case 'o':
- case 'u':
- case 'X':
- case 'x':
- if (use_short_form)
- doit(fc, (unsigned short)va_arg(*app, unsigned int));
- else if (use_long_form)
- doit(fc, va_arg(*app, unsigned long));
- else
- doit(fc, va_arg(*app, unsigned int));
- break;
-
- case '\0':
- formatp--;
- fc = '%';
- /* and fall thru. */
- case '%':
- default:
- (*uputfn)(fc);
- break;
- }
- }
- }
-