home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / dev / lang / sgmls / src / xfprintf.c < prev   
Encoding:
C/C++ Source or Header  |  1994-07-10  |  10.3 KB  |  565 lines

  1. /* xfprintf.c -
  2.    X/Open extended v?fprintf implemented in terms of v?fprintf.
  3.  
  4.      Written by James Clark (jjc@jclark.com).
  5. */
  6.  
  7. /* Compile with:
  8.  
  9.    -DVARARGS            to use varargs.h instead of stdarg.h
  10.    -DLONG_DOUBLE_MISSING     if your compiler doesn't like `long double'
  11.    -DFP_SUPPORT                 to include floating point stuff
  12. */
  13.  
  14. #include "config.h"
  15.  
  16. #ifndef HAVE_EXTENDED_PRINTF
  17.  
  18. #include "std.h"
  19.  
  20. #ifdef lint
  21. /* avoid stupid lint warnings */
  22. #undef va_arg
  23. #define va_arg(ap, type) (ap, (type)0)
  24. #endif
  25.  
  26. #ifdef FP_SUPPORT
  27. #ifdef LONG_DOUBLE_MISSING
  28. typedef double long_double;
  29. #else
  30. typedef long double long_double;
  31. #endif
  32. #endif /* FP_SUPPORT */
  33.  
  34. #ifdef USE_PROTOTYPES
  35. #define P(parms) parms
  36. #else
  37. #define P(parms) ()
  38. #endif
  39.  
  40. #ifdef VARARGS
  41. typedef int (*printer)();
  42. #else
  43. typedef int (*printer)(UNIV, const char *, ...);
  44. #endif
  45.  
  46. enum arg_type {
  47.   NONE,
  48.   INT,
  49.   UNSIGNED,
  50.   LONG,
  51.   UNSIGNED_LONG,
  52. #ifdef FP_SUPPORT
  53.   DOUBLE,
  54.   LONG_DOUBLE,
  55. #endif /* FP_SUPPORT */
  56.   PCHAR,
  57.   PINT,
  58.   PLONG,
  59.   PSHORT
  60. };
  61.  
  62. union arg {
  63.   int i;
  64.   unsigned u;
  65.   long l;
  66.   unsigned long ul;
  67. #ifdef FP_SUPPORT
  68.   double d;
  69.   long_double ld;
  70. #endif /* FP_SUPPORT */
  71.   char *pc;
  72.   UNIV pv;
  73.   int *pi;
  74.   short *ps;
  75.   long *pl;
  76. };
  77.  
  78. #define NEXT 0
  79. #define MISSING 10
  80.  
  81. struct spec {
  82.   enum arg_type type;
  83.   char pos;
  84.   char field_width;
  85.   char precision;
  86. };
  87.  
  88. #define FLAG_CHARS "-+ #0"
  89.  
  90. static int parse_spec P((const char **, struct spec *));
  91. static int find_arg_types P((const char *, enum arg_type *));
  92. static void get_arg P((enum arg_type, va_list *, union arg *));
  93. static int do_arg P((UNIV, printer, const char *, enum arg_type, union arg *));
  94. static int xdoprt P((UNIV, printer, const char *, va_list));
  95. static int printit P((UNIV, printer, const char *, va_list, int, union arg *));
  96. static int maybe_positional P((const char *));
  97.  
  98. /* Return 1 if sucessful, 0 otherwise. **pp points to character after % */
  99.  
  100. static int parse_spec(pp, sp)
  101. const char **pp;
  102. struct spec *sp;
  103. {
  104.   char modifier = 0;
  105.   sp->pos = NEXT;
  106.   if (isdigit((unsigned char)(**pp)) && (*pp)[1] == '$') {
  107.     if (**pp == '0')
  108.       return 0;
  109.     sp->pos = **pp - '0';
  110.     *pp += 2;
  111.   }
  112.  
  113.   while (**pp != '\0' && strchr(FLAG_CHARS, **pp))
  114.     *pp += 1;
  115.  
  116.   /* handle the field width */
  117.  
  118.   sp->field_width = MISSING;
  119.   if (**pp == '*') {
  120.     *pp += 1;
  121.     if (isdigit((unsigned char)**pp) && (*pp)[1] == '$') {
  122.       if (**pp == '0')
  123.     return 0;
  124.       sp->field_width = **pp - '0';
  125.       *pp += 2;
  126.     }
  127.     else
  128.       sp->field_width = NEXT;
  129.   }
  130.   else {
  131.     while (isdigit((unsigned char)**pp))
  132.       *pp += 1;
  133.   }
  134.  
  135.   /* handle the precision */
  136.   sp->precision = MISSING;
  137.   if (**pp == '.') {
  138.     *pp += 1;
  139.     if (**pp == '*') {
  140.       *pp += 1;
  141.       if (isdigit((unsigned char)**pp) && (*pp)[1] == '$') {
  142.     if (**pp == '0')
  143.       return 0;
  144.     sp->precision = **pp - '0';
  145.     *pp += 2;
  146.       }
  147.       else
  148.     sp->precision = NEXT;
  149.     }
  150.     else {
  151.       while (isdigit((unsigned char)**pp))
  152.     *pp += 1;
  153.     }
  154.   }
  155.   /* handle h l or L */
  156.  
  157.   if (**pp == 'h' || **pp == 'l' || **pp == 'L') {
  158.     modifier = **pp;
  159.     *pp += 1;
  160.   }
  161.  
  162.   switch (**pp) {
  163.   case 'd':
  164.   case 'i':
  165.     sp->type = modifier == 'l' ? LONG : INT;
  166.     break;
  167.   case 'o':
  168.   case 'u':
  169.   case 'x':
  170.   case 'X':
  171.     sp->type = modifier == 'l' ? UNSIGNED_LONG : UNSIGNED;
  172.     break;
  173. #ifdef FP_SUPPORT
  174.   case 'e':
  175.   case 'E':
  176.   case 'f':
  177.   case 'g':
  178.   case 'G':
  179.     sp->type = modifier == 'L' ? LONG_DOUBLE : DOUBLE;
  180.     break;
  181. #endif /* FP_SUPPORT */
  182.   case 'c':
  183.     sp->type = INT;
  184.     break;
  185.   case 's':
  186.     sp->type = PCHAR;
  187.     break;
  188.   case 'p':
  189.     /* a pointer to void has the same representation as a pointer to char */
  190.     sp->type = PCHAR;
  191.     break;
  192.   case 'n':
  193.     if (modifier == 'h')
  194.       sp->type = PSHORT;
  195.     else if (modifier == 'l')
  196.       sp->type = PLONG;
  197.     else
  198.       sp->type = PINT;
  199.     break;
  200.   case '%':
  201.     sp->type = NONE;
  202.     break;
  203.   default:
  204.     return 0;
  205.   }
  206.   *pp += 1;
  207.   return 1;
  208. }
  209.  
  210.  
  211. static int find_arg_types(format, arg_type)
  212.      const char *format;
  213.      enum arg_type *arg_type;
  214. {
  215.   int i, pos;
  216.   const char *p;
  217.   struct spec spec;
  218.  
  219.   for (i = 0; i < 9; i++)
  220.     arg_type[i] = NONE;
  221.  
  222.   pos = 0;
  223.  
  224.   p = format;
  225.   while (*p)
  226.     if (*p == '%') {
  227.       p++;
  228.       if (!parse_spec(&p, &spec))
  229.     return 0;
  230.       if (spec.type != NONE) {
  231.     int n;
  232.     if (spec.pos == NEXT)
  233.       n = pos++;
  234.     else
  235.       n = spec.pos - 1;
  236.     if (n < 9) {
  237.       enum arg_type t = arg_type[n];
  238.       if (t != NONE && t != spec.type)
  239.         return 0;
  240.       arg_type[n] = spec.type;
  241.     }
  242.       }
  243.       if (spec.field_width != MISSING) {
  244.     int n;
  245.     if (spec.field_width == NEXT)
  246.       n = pos++;
  247.     else
  248.       n = spec.field_width - 1;
  249.     if (n < 9) {
  250.       enum arg_type t = arg_type[n];
  251.       if (t != NONE && t != INT)
  252.         return 0;
  253.       arg_type[n] = INT;
  254.     }
  255.       }
  256.       if (spec.precision != MISSING) {
  257.     int n;
  258.     if (spec.precision == NEXT)
  259.       n = pos++;
  260.     else
  261.       n = spec.precision - 1;
  262.     if (n < 9) {
  263.       enum arg_type t = arg_type[n];
  264.       if (t != NONE && t != INT)
  265.         return 0;
  266.       arg_type[n] = INT;
  267.     }
  268.       }
  269.     }
  270.     else
  271.       p++;
  272.   return 1;
  273. }
  274.  
  275. static void get_arg(arg_type, app, argp)
  276.      enum arg_type arg_type;
  277.      va_list *app;
  278.      union arg *argp;
  279. {
  280.   switch (arg_type) {
  281.   case NONE:
  282.     break;
  283.   case INT:
  284.     argp->i = va_arg(*app, int);
  285.     break;
  286.   case UNSIGNED:
  287.     argp->u = va_arg(*app, unsigned);
  288.     break;
  289.   case LONG:
  290.     argp->l = va_arg(*app, long);
  291.     break;
  292.   case UNSIGNED_LONG:
  293.     argp->ul = va_arg(*app, unsigned long);
  294.     break;
  295. #ifdef FP_SUPPORT
  296.   case DOUBLE:
  297.     argp->d = va_arg(*app, double);
  298.     break;
  299.   case LONG_DOUBLE:
  300.     argp->ld = va_arg(*app, long_double);
  301.     break;
  302. #endif /* FP_SUPPORT */
  303.   case PCHAR:
  304.     argp->pc = va_arg(*app, char *);
  305.     break;
  306.   case PINT:
  307.     argp->pi = va_arg(*app, int *);
  308.     break;
  309.   case PSHORT:
  310.     argp->ps = va_arg(*app, short *);
  311.     break;
  312.   case PLONG:
  313.     argp->pl = va_arg(*app, long *);
  314.     break;
  315.   default:
  316.     abort();
  317.   }
  318. }
  319.  
  320. static int do_arg(handle, func, buf, arg_type, argp)
  321.      UNIV handle;
  322.      printer func;
  323.      const char *buf;
  324.      enum arg_type arg_type;
  325.      union arg *argp;
  326. {
  327.   switch (arg_type) {
  328.   case NONE:
  329.     return (*func)(handle, buf);
  330.   case INT:
  331.     return (*func)(handle, buf, argp->i);
  332.   case UNSIGNED:
  333.     return (*func)(handle, buf, argp->u);
  334.   case LONG:
  335.     return (*func)(handle, buf, argp->l);
  336.   case UNSIGNED_LONG:
  337.     return (*func)(handle, buf, argp->ul);
  338. #ifdef FP_SUPPORT
  339.   case DOUBLE:
  340.     return (*func)(handle, buf, argp->d);
  341.   case LONG_DOUBLE:
  342.     return (*func)(handle, buf, argp->ld);
  343. #endif /* FP_SUPPORT */
  344.   case PCHAR:
  345.     return (*func)(handle, buf, argp->pc);
  346.   case PINT:
  347.     return (*func)(handle, buf, argp->pi);
  348.   case PSHORT:
  349.     return (*func)(handle, buf, argp->ps);
  350.   case PLONG:
  351.     return (*func)(handle, buf, argp->pl);
  352.   default:
  353.     abort();
  354.   }
  355.   /* NOTREACHED */
  356. }
  357.  
  358. static int printit(handle, func, p, ap, nargs, arg)
  359.      UNIV handle;
  360.      printer func;
  361.      const char *p;
  362.      va_list ap;
  363.      int nargs;
  364.      union arg *arg;
  365. {
  366.   char buf[512];        /* enough for a spec */
  367.   int count = 0;
  368.   int pos = 0;
  369.  
  370.   while (*p)
  371.     if (*p == '%') {
  372.       char *q;
  373.       struct spec spec;
  374.       const char *start;
  375.       int had_field_width;
  376.       union arg *argp;
  377.       union arg a;
  378.       int res;
  379.  
  380.       start = ++p;
  381.       if (!parse_spec(&p, &spec))
  382.     abort();        /* should have caught it in find_arg_types */
  383.  
  384.       buf[0] = '%';
  385.       q = buf + 1;
  386.  
  387.       if (spec.pos != NEXT)
  388.     start += 2;
  389.  
  390.       /* substitute in precision and field width if necessary */
  391.       had_field_width = 0;
  392.       while (start < p) {
  393.     if (*start == '*') {
  394.       char c;
  395.       int n, val;
  396.  
  397.       start++;
  398.       if (!had_field_width && spec.field_width != MISSING) {
  399.         c = spec.field_width;
  400.         had_field_width = 1;
  401.       }
  402.       else
  403.         c = spec.precision;
  404.       if (c == NEXT)
  405.         n = pos++;
  406.       else {
  407.         start += 2;
  408.         n = c - 1;
  409.       }
  410.       if (n >= nargs)
  411.         val = va_arg(ap, int);
  412.       else
  413.         val = arg[n].i;
  414.  
  415.       /* ignore negative precision */
  416.       if (val >= 0 || q[-1] != '.') {
  417.         (void)sprintf(q, "%d", val);
  418.         q = strchr(q, '\0');
  419.       }
  420.     }
  421.     else
  422.       *q++ = *start++;
  423.       }
  424.       *q++ = '\0';
  425.  
  426.       argp = 0;
  427.       if (spec.type != NONE) {
  428.     int n = spec.pos == NEXT ? pos++ : spec.pos - 1;
  429.     if (n >= nargs) {
  430.       get_arg(spec.type, &ap, &a);
  431.       argp = &a;
  432.     }
  433.     else
  434.       argp = arg + n;
  435.       }
  436.  
  437.       res = do_arg(handle, func, buf, spec.type, argp);
  438.       if (res < 0)
  439.     return -1;
  440.       count += res;
  441.     }
  442.     else {
  443.       if ((*func)(handle, "%c", *p++) < 0)
  444.     return -1;
  445.       count++;
  446.     }
  447.   return count;
  448. }
  449.  
  450. /* Do a quick check to see if it may contains any positional thingies. */
  451.  
  452. static int maybe_positional(format)
  453.      const char *format;
  454. {
  455.   const char *p;
  456.  
  457.   p = format;
  458.   for (;;) {
  459.     p = strchr(p, '$');
  460.     if (!p)
  461.       return 0;
  462.     if (p - format >= 2
  463.     && isdigit((unsigned char)p[-1])
  464.     && (p[-2] == '%' || p[-2] == '*'))
  465.       break;            /* might be a positional thingy */
  466.   }
  467.   return 1;
  468. }
  469.  
  470. static int xdoprt(handle, func, format, ap)
  471.      UNIV handle;
  472.      printer func;
  473.      const char *format;
  474.      va_list ap;
  475. {
  476.   enum arg_type arg_type[9];
  477.   union arg arg[9];
  478.   int nargs, i;
  479.  
  480.   if (!find_arg_types(format, arg_type))
  481.     return -1;
  482.  
  483.   for (nargs = 0; nargs < 9; nargs++)
  484.     if (arg_type[nargs] == NONE)
  485.       break;
  486.  
  487.   for (i = nargs; i < 9; i++)
  488.     if (arg_type[i] != NONE)
  489.       return -1;
  490.  
  491.   for (i = 0; i < nargs; i++)
  492.     get_arg(arg_type[i], &ap, arg + i);
  493.  
  494.   return printit(handle, func, format, ap, nargs, arg);
  495. }
  496.  
  497. #ifdef VARARGS
  498. static int do_fprintf(va_alist) va_dcl
  499. #else
  500. static int do_fprintf(UNIV p, const char *format,...)
  501. #endif
  502. {
  503. #ifdef VARARGS
  504.   UNIV p;
  505.   const char *format;
  506. #endif
  507.   va_list ap;
  508.   int res;
  509.  
  510. #ifdef VARARGS
  511.   va_start(ap);
  512.   p = va_arg(ap, UNIV);
  513.   format = va_arg(ap, char *);
  514. #else
  515.   va_start(ap, format);
  516. #endif
  517.  
  518.   res = vfprintf((FILE *)p, format, ap);
  519.   va_end(ap);
  520.   return res;
  521. }
  522.  
  523. #ifdef VARARGS
  524. int xfprintf(va_alist) va_dcl
  525. #else
  526. int xfprintf(FILE *fp, const char *format, ...)
  527. #endif
  528. {
  529. #ifdef VARARGS
  530.   FILE *fp;
  531.   char *format;
  532. #endif
  533.   va_list ap;
  534.   int res;
  535.  
  536. #ifdef VARARGS
  537.   va_start(ap);
  538.   fp = va_arg(ap, FILE *);
  539.   format = va_arg(ap, char *);
  540. #else
  541.   va_start(ap, format);
  542. #endif
  543.   if (maybe_positional(format))
  544.     res = xdoprt((UNIV)fp, do_fprintf, format, ap);
  545.   else
  546.     res = vfprintf(fp, format, ap);
  547.   va_end(ap);
  548.   return res;
  549. }
  550.  
  551. int xvfprintf(FILE *fp, const char *format, va_list ap)
  552.  
  553.  
  554.  
  555. {
  556.   int res;
  557.   if (maybe_positional(format))
  558.     res = xdoprt((UNIV)fp, do_fprintf, format, ap);
  559.   else
  560.     res = vfprintf(fp, format, ap);
  561.   return res;
  562. }
  563.  
  564. #endif /* not HAVE_EXTENDED_PRINTF */
  565.