home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / rc / part04 / print.c < prev    next >
C/C++ Source or Header  |  1992-05-30  |  9KB  |  457 lines

  1. /* print.c -- formatted printing routines (Paul Haahr, 12/91) */
  2.  
  3. #include "rc.h"
  4. #include <setjmp.h>
  5.  
  6. #define    PRINT_ALLOCSIZE    ((SIZE_T)64)
  7. #define    SPRINT_BUFSIZ    ((SIZE_T)1024)
  8.  
  9. #define    MAXCONV 256
  10.  
  11. /*
  12.  * conversion functions
  13.  *    true return -> flag changes only, not a conversion
  14.  */
  15.  
  16. #define Flag(name, flag) \
  17. static bool name(Format *format, int c) { \
  18.     format->flags |= flag; \
  19.     return TRUE; \
  20. }
  21.  
  22. Flag(uconv,    FMT_unsigned)
  23. Flag(hconv,    FMT_short)
  24. Flag(lconv,    FMT_long)
  25. Flag(altconv,    FMT_altform)
  26. Flag(leftconv,    FMT_leftside)
  27. Flag(dotconv,    FMT_f2set)
  28.  
  29. static bool digitconv(Format *format, int c) {
  30.     if (format->flags & FMT_f2set)
  31.         format->f2 = 10 * format->f2 + c - '0';
  32.     else {
  33.         format->flags |= FMT_f1set;
  34.         format->f1 = 10 * format->f1 + c - '0';
  35.     }
  36.     return TRUE;
  37. }
  38.  
  39. static bool zeroconv(Format *format, int c) {
  40.     if (format->flags & (FMT_f1set | FMT_f2set))
  41.         return digitconv(format, '0');
  42.     format->flags |= FMT_zeropad;
  43.     return TRUE;
  44. }
  45.  
  46. static void pad(Format *format, SIZE_T len, int c) {
  47.     while (len-- != 0)
  48.         fmtputc(format, c);
  49. }
  50.  
  51. static bool sconv(Format *format, int c) {
  52.     char *s = va_arg(format->args, char *);
  53.     if ((format->flags & FMT_f1set) == 0)
  54.         fmtcat(format, s);
  55.     else {
  56.         SIZE_T len = strlen(s), width = format->f1 - len;
  57.         if (format->flags & FMT_leftside) {
  58.             fmtappend(format, s, len);
  59.             pad(format, width, ' ');
  60.         } else {
  61.             pad(format, width, ' ');
  62.             fmtappend(format, s, len);
  63.         }
  64.     }
  65.     return FALSE;
  66. }
  67.  
  68. static char *utoa(unsigned long u, char *t, unsigned int radix, const char *digit) {
  69.     if (u >= radix) {
  70.         t = utoa(u / radix, t, radix, digit);
  71.         u %= radix;
  72.     }
  73.     *t++ = digit[u];
  74.     return t;
  75. }
  76.  
  77. static void intconv(Format *format, unsigned int radix, int upper, const char *altform) {
  78.     static const char * const table[] = {
  79.         "0123456789abcdefghijklmnopqrstuvwxyz",
  80.         "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  81.     };
  82.     char padchar;
  83.     SIZE_T len, pre, zeroes, padding, width;
  84.     long n, flags;
  85.     unsigned long u;
  86.     char number[64], prefix[20];
  87.  
  88.     if (radix > 36)
  89.         return;
  90.  
  91.     flags = format->flags;
  92.     if (flags & FMT_long)
  93.         n = va_arg(format->args, long);
  94.     else if (flags & FMT_short)
  95.         n = va_arg(format->args, short);
  96.     else
  97.         n = va_arg(format->args, int);
  98.  
  99.     pre = 0;
  100.     if ((flags & FMT_unsigned) || n >= 0)
  101.         u = n;
  102.     else {
  103.         prefix[pre++] = '-';
  104.         u = -n;
  105.     }
  106.  
  107.     if (flags & FMT_altform)
  108.         while (*altform != '\0')
  109.             prefix[pre++] = *altform++;
  110.  
  111.     len = utoa(u, number, radix, table[upper]) - number;
  112.     if ((flags & FMT_f2set) && (SIZE_T) format->f2 > len)
  113.         zeroes = format->f2 - len;
  114.     else
  115.         zeroes = 0;
  116.  
  117.     width = pre + zeroes + len;
  118.     if ((flags & FMT_f1set) && (SIZE_T) format->f1 > width) {
  119.         padding = format->f1 - width;
  120.     } else
  121.         padding = 0;
  122.  
  123.     padchar = ' ';
  124.     if (padding > 0 && flags & FMT_zeropad) {
  125.         padchar = '0';
  126.         if ((flags & FMT_leftside) == 0) {
  127.             zeroes += padding;
  128.             padding = 0;
  129.         }
  130.     }
  131.  
  132.  
  133.     if ((flags & FMT_leftside) == 0)
  134.         pad(format, padding, padchar);
  135.     fmtappend(format, prefix, pre);
  136.     pad(format, zeroes, '0');
  137.     fmtappend(format, number, len);
  138.     if (flags & FMT_leftside)
  139.         pad(format, padding, padchar);
  140. }
  141.  
  142. static bool cconv(Format *format, int c) {
  143.     fmtputc(format, va_arg(format->args, int));
  144.     return FALSE;
  145. }
  146.  
  147. static bool dconv(Format *format, int c) {
  148.     intconv(format, 10, 0, "");
  149.     return FALSE;
  150. }
  151.  
  152. static bool oconv(Format *format, int c) {
  153.     intconv(format, 8, 0, "0");
  154.     return FALSE;
  155. }
  156.  
  157. static bool xconv(Format *format, int c) {
  158.     intconv(format, 16, 0, "0x");
  159.     return FALSE;
  160. }
  161.  
  162. static bool pctconv(Format *format, int c) {
  163.     fmtputc(format, '%');
  164.     return FALSE;
  165. }
  166.  
  167. static bool badconv(Format *format, int c) {
  168.     panic("bad conversion character in printfmt");
  169.     /* NOTREACHED */
  170.     return FALSE; /* hush up gcc -Wall */
  171. }
  172.  
  173.  
  174. /*
  175.  * conversion table management
  176.  */
  177.  
  178. static Conv fmttab[MAXCONV];
  179.  
  180. static void inittab(void) {
  181.     int i;
  182.     for (i = 0; i < MAXCONV; i++)
  183.         fmttab[i] = badconv;
  184.  
  185.     fmttab['s'] = sconv;
  186.     fmttab['c'] = cconv;
  187.     fmttab['d'] = dconv;
  188.     fmttab['o'] = oconv;
  189.     fmttab['x'] = xconv;
  190.     fmttab['%'] = pctconv;
  191.  
  192.     fmttab['u'] = uconv;
  193.     fmttab['h'] = hconv;
  194.     fmttab['l'] = lconv;
  195.     fmttab['#'] = altconv;
  196.     fmttab['-'] = leftconv;
  197.     fmttab['.'] = dotconv;
  198.  
  199.     fmttab['0'] = zeroconv;
  200.     for (i = '1'; i <= '9'; i++)
  201.         fmttab[i] = digitconv;
  202. }
  203.  
  204. extern bool (*fmtinstall(int c, bool (*f)(Format *, int)))(Format *, int) {
  205. /*Conv fmtinstall(int c, Conv f) {*/
  206.     Conv oldf;
  207.     if (fmttab[0] == NULL)
  208.         inittab();
  209.     c &= MAXCONV - 1;
  210.     oldf = fmttab[c];
  211.     if (f != NULL)
  212.         fmttab[c] = f;
  213.     return oldf;
  214. }
  215.  
  216.  
  217. /*
  218.  * functions for inserting strings in the format buffer
  219.  */
  220.  
  221. extern void fmtappend(Format *format, const char *s, SIZE_T len) {
  222.     while (format->buf + len > format->bufend) {
  223.         SIZE_T split = format->bufend - format->buf;
  224.         memcpy(format->buf, s, split);
  225.         format->buf += split;
  226.         s += split;
  227.         len -= split;
  228.         (*format->grow)(format, len);
  229.     }
  230.     memcpy(format->buf, s, len);
  231.     format->buf += len;
  232. }
  233.  
  234. extern void fmtcat(Format *format, const char *s) {
  235.     fmtappend(format, s, strlen(s));
  236. }
  237.  
  238. /*
  239.  * printfmt -- the driver routine
  240.  */
  241.  
  242. extern int printfmt(Format *format, const char *fmt) {
  243.     unsigned const char *s = (unsigned const char *) fmt;
  244.  
  245.     if (fmttab[0] == NULL)
  246.         inittab();
  247.  
  248.     for (;;) {
  249.         int c = *s++;
  250.         switch (c) {
  251.         case '%':
  252.             format->flags = format->f1 = format->f2 = 0;
  253.             do
  254.                 c = *s++;
  255.             while ((*fmttab[c])(format, c));
  256.             break;
  257.         case '\0':
  258.             return format->buf - format->bufbegin + format->flushed;
  259.         default:
  260.             fmtputc(format, c);
  261.             break;
  262.         }
  263.     }
  264. }
  265.  
  266.  
  267. /*
  268.  * the public entry points
  269.  */
  270.  
  271. extern int fmtprint(Format *format, const char *fmt,...) {
  272.     int n = -format->flushed;
  273.     va_list saveargs = format->args;
  274.  
  275.     va_start(format->args, fmt);
  276.     n += printfmt(format, fmt);
  277.     va_end(format->args);
  278.     format->args = saveargs;
  279.  
  280.     return n + format->flushed;
  281. }
  282.  
  283. static void fprint_flush(Format *format, SIZE_T more) {
  284.     SIZE_T n = format->buf - format->bufbegin;
  285.     char *buf = format->bufbegin;
  286.  
  287.     format->flushed += n;
  288.     format->buf = format->bufbegin;
  289.     writeall(format->u.n, buf, n);
  290. }
  291.  
  292. extern int fprint(int fd, const char *fmt,...) {
  293.     char buf[1024];
  294.     Format format;
  295.  
  296.     format.buf    = buf;
  297.     format.bufbegin    = buf;
  298.     format.bufend    = buf + sizeof buf;
  299.     format.grow    = fprint_flush;
  300.     format.flushed    = 0;
  301.     format.u.n    = fd;
  302.  
  303.     va_start(format.args, fmt);
  304.     printfmt(&format, fmt);
  305.     va_end(format.args);
  306.  
  307.     fprint_flush(&format, (SIZE_T) 0);
  308.     return format.flushed;
  309. }
  310.  
  311. static void memprint_grow(Format *format, SIZE_T more) {
  312.     char *buf;
  313.     SIZE_T len = format->bufend - format->bufbegin + 1;
  314.     len = (len >= more)
  315.         ? len * 2
  316.         : ((len + more) + PRINT_ALLOCSIZE) &~ (PRINT_ALLOCSIZE - 1);
  317.     if (format->u.n)
  318.         buf = erealloc(format->bufbegin, len);
  319.     else {
  320.         SIZE_T used = format->buf - format->bufbegin;
  321.         buf = nalloc(len);
  322.         memcpy(buf, format->bufbegin, used);
  323.     }
  324.     format->buf     = buf + (format->buf - format->bufbegin);
  325.     format->bufbegin = buf;
  326.     format->bufend     = buf + len - 1;
  327. }
  328.  
  329. static char *memprint(Format *format, const char *fmt, char *buf, SIZE_T len) {
  330.     format->buf     = buf;
  331.     format->bufbegin = buf;
  332.     format->bufend     = buf + len - 1;
  333.     format->grow     = memprint_grow;
  334.     format->flushed     = 0;
  335.     printfmt(format, fmt);
  336.     *format->buf = '\0';
  337.     return format->bufbegin;
  338. }
  339.  
  340. extern char *mprint(const char *fmt,...) {
  341.     Format format;
  342.     char *result;
  343.     format.u.n = 1;
  344.     va_start(format.args, fmt);
  345.     result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
  346.     va_end(format.args);
  347.     return result;
  348. }
  349.  
  350. extern char *nprint(const char *fmt,...) {
  351.     Format format;
  352.     char *result;
  353.     format.u.n = 0;
  354.     va_start(format.args, fmt);
  355.     result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
  356.     va_end(format.args);
  357.     return result;
  358. }
  359.  
  360.  
  361. /* THESE ARE UNUSED IN rc */
  362.  
  363. #if 0
  364.  
  365. extern int print(const char *fmt,...) {
  366.     char buf[1024];
  367.     Format format;
  368.  
  369.     format.buf    = buf;
  370.     format.bufbegin    = buf;
  371.     format.bufend    = buf + sizeof buf;
  372.     format.grow    = fprint_flush;
  373.     format.flushed    = 0;
  374.     format.u.n    = 1;
  375.  
  376.     va_start(format.args, fmt);
  377.     printfmt(&format, fmt);
  378.     va_end(format.args);
  379.  
  380.     fprint_flush(&format, 0);
  381.     return format.flushed;
  382. }
  383.  
  384. extern int eprint(const char *fmt,...) {
  385.     char buf[1024];
  386.     Format format;
  387.  
  388.     format.buf    = buf;
  389.     format.bufbegin    = buf;
  390.     format.bufend    = buf + sizeof buf;
  391.     format.grow    = fprint_flush;
  392.     format.flushed    = 0;
  393.     format.u.n    = 2;
  394.  
  395.     va_start(format.args, fmt);
  396.     printfmt(&format, fmt);
  397.     va_end(format.args);
  398.  
  399.     fprint_flush(&format, 0);
  400.     return format.flushed;
  401. }
  402.  
  403. static void snprint_grow(Format *format, SIZE_T more) {
  404.     longjmp(format->u.p, 1);
  405. }
  406.  
  407. extern int snprint(char *buf, int buflen, const char *fmt,...) {
  408.     int n;
  409.     jmp_buf jbuf;
  410.     Format format;
  411.  
  412.     if (setjmp(jbuf)) {
  413.         *format.buf = '\0';
  414.         return format.buf - format.bufbegin;
  415.     }
  416.  
  417.     format.buf    = buf;
  418.     format.bufbegin    = buf;
  419.     format.bufend    = buf + buflen - 1;
  420.     format.grow    = snprint_grow;
  421.     format.flushed    = 0;
  422.     format.u.p    = jbuf;
  423.  
  424.     va_start(format.args, fmt);
  425.     n = printfmt(&format, fmt);
  426.     va_end(format.args);
  427.  
  428.     *format.buf = '\0';
  429.     return n;
  430. }
  431.  
  432. extern int sprint(char *buf, const char *fmt,...) {
  433.     int n;
  434.     jmp_buf jbuf;
  435.     Format format;
  436.  
  437.     if (setjmp(jbuf)) {
  438.         *format.buf = '\0';
  439.         return format.buf - format.bufbegin;
  440.     }
  441.  
  442.     format.buf    = buf;
  443.     format.bufbegin    = buf;
  444.     format.bufend    = buf + SPRINT_BUFSIZ - 1;
  445.     format.grow    = snprint_grow;
  446.     format.flushed    = 0;
  447.     format.u.p    = jbuf;
  448.  
  449.     va_start(format.args, fmt);
  450.     n = printfmt(&format, fmt);
  451.     va_end(format.args);
  452.  
  453.     *format.buf = '\0';
  454.     return n;
  455. }
  456. #endif
  457.