home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / jove-4.16-src.tgz / tar.out / bsd / jove / fmt.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  8KB  |  450 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986-1996 by Jonathan Payne.  JOVE is  *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include "chars.h"
  10. #include "fp.h"
  11. #include "jctype.h"
  12. #include "disp.h"
  13. #include "extend.h"
  14. #include "fmt.h"
  15.  
  16. #ifdef MAC
  17. # include  "mac.h"
  18. #endif
  19.  
  20. private void
  21.     doformat proto((File *, const char *, va_list)),
  22.     outld proto((long, int)),
  23.     pad proto((DAPchar, int));
  24.  
  25. char    mesgbuf[MESG_SIZE];
  26.  
  27. /* Formatting codes supported:
  28.  *
  29.  * %%: => '%'
  30.  * %O, %D, %X: long => octal, decimal, or hex
  31.  * %lo, %ld, %lx: long => octal, decimal, or hex
  32.  * %o, %d, %x: int => octal, decimal, or hex
  33.  * %c: char => character
  34.  * %s: char* => string
  35.  *
  36.  * %b: buffer pointer => buffer's name
  37.  * %f: void => current command's name
  38.  * %n: int => int == 1? "" : "s"
  39.  * %p: char => visible rep
  40.  */
  41.  
  42. #ifdef ZTCDOS
  43. /* ZTCDOS only accepts va_list in a prototype */
  44. void
  45. format(char *buf, size_t len, const char *fmt, va_list ap)
  46. #else
  47. void
  48. format(buf, len, fmt, ap)
  49. char    *buf;
  50. size_t    len;
  51. const char    *fmt;
  52. va_list    ap;
  53. #endif
  54. {
  55.     File    strbuf;
  56.  
  57.     strbuf.f_ptr = strbuf.f_base = buf;
  58.     strbuf.f_fd = -1;        /* Not legit for files */
  59.     strbuf.f_bufsize = strbuf.f_cnt = len;
  60.     strbuf.f_flags = F_STRING;
  61.  
  62.     doformat(&strbuf, fmt, ap);
  63.     f_putc('\0', &strbuf);    /* f_putc will place this, even if overflow */
  64. }
  65.  
  66. /* pretty-print character c into buffer cp (up to PPWIDTH bytes) */
  67.  
  68. void
  69. PPchar(c, cp)
  70. ZXchar    c;
  71. char    *cp;
  72. {
  73.     if (jisprint(c)) {
  74.         cp[0] = c;
  75.         cp[1] = '\0';
  76.     } else if (c < DEL) {
  77.         strcpy(cp, "^?");
  78.         cp[1] = c +'@';
  79.     } else if (c == DEL) {
  80.         strcpy(cp, "^?");
  81.     } else {
  82.         cp[0] = '\\';
  83.         cp[1] = '0'+(c >> 6);
  84.         cp[2] = '0'+((c >> 3) & 07);
  85.         cp[3] = '0'+(c & 07);
  86.         cp[4] = '\0';
  87.     }
  88. }
  89.  
  90. private struct fmt_state {
  91.     int    precision,
  92.         width;
  93.     bool    leftadj;
  94.     char    padc;
  95.     File    *iop;
  96. } current_fmt;
  97.  
  98. private void
  99. putld(d, base)
  100. long    d;
  101. int    base;
  102. {
  103.     int    len = 1;
  104.     long    tmpd = d;
  105.  
  106.     if (current_fmt.width == 0 && current_fmt.precision) {
  107.         current_fmt.width = current_fmt.precision;
  108.         current_fmt.padc = '0';
  109.     }
  110.     while ((tmpd = (tmpd / base)) != 0)
  111.         len += 1;
  112.     if (d < 0)
  113.         len += 1;
  114.     if (!current_fmt.leftadj)
  115.         pad(current_fmt.padc, current_fmt.width - len);
  116.     if (d < 0) {
  117.         f_putc('-', current_fmt.iop);
  118.         d = -d;
  119.     }
  120.     outld(d, base);
  121.     if (current_fmt.leftadj)
  122.         pad(current_fmt.padc, current_fmt.width - len);
  123. }
  124.  
  125. private void
  126. outld(d, base)
  127. long    d;
  128. int    base;
  129. {
  130.     register long    n;
  131.     static const char    chars[] = {'0', '1', '2', '3', '4', '5', '6',
  132.                     '7', '8', '9', 'a', 'b', 'c', 'd',
  133.                     'e', 'f'};
  134.  
  135.     if ((n = (d / base)) != 0)
  136.         outld(n, base);
  137.     f_putc((int) (chars[(int) (d % base)]), current_fmt.iop);
  138. }
  139.  
  140. private void
  141. fmt_puts(str)
  142. char    *str;
  143. {
  144.     int    len;
  145.     register char    *cp;
  146.  
  147.     if (str == NULL)
  148.         str = "(null)";
  149.     len = strlen(str);
  150.     if (current_fmt.precision == 0 || len < current_fmt.precision)
  151.         current_fmt.precision = len;
  152.     else
  153.         len = current_fmt.precision;
  154.     cp = str;
  155.     if (!current_fmt.leftadj)
  156.         pad(' ', current_fmt.width - len);
  157.     while (--current_fmt.precision >= 0)
  158.         f_putc(*cp++, current_fmt.iop);
  159.     if (current_fmt.leftadj)
  160.         pad(' ', current_fmt.width - len);
  161. }
  162.  
  163. private void
  164. pad(c, amount)
  165. register char    c;
  166. register int    amount;
  167. {
  168.     while (--amount >= 0)
  169.         f_putc(c, current_fmt.iop);
  170. }
  171.  
  172. #ifdef ZTCDOS
  173. /* ZTCDOS only accepts va_list in a prototype */
  174. private void
  175. doformat(register File *sp, register const char *fmt, va_list ap)
  176. #else
  177. private void
  178. doformat(sp, fmt, ap)
  179. register File    *sp;
  180. register const char    *fmt;
  181. va_list    ap;
  182. #endif
  183. {
  184.     register char    c;
  185.     struct fmt_state    prev_fmt;
  186.  
  187.     prev_fmt = current_fmt;
  188.     current_fmt.iop = sp;
  189.  
  190.     while ((c = *fmt++) != '\0') {
  191.         if (c != '%') {
  192.             f_putc(c, current_fmt.iop);
  193.             continue;
  194.         }
  195.  
  196.         current_fmt.padc = ' ';
  197.         current_fmt.precision = current_fmt.width = 0;
  198.         current_fmt.leftadj = NO;
  199.         c = *fmt++;
  200.         if (c == '-') {
  201.             current_fmt.leftadj = YES;
  202.             c = *fmt++;
  203.         }
  204.         if (c == '0') {
  205.             current_fmt.padc = '0';
  206.             c = *fmt++;
  207.         }
  208.         while (c >= '0' && c <= '9') {
  209.             current_fmt.width = current_fmt.width * 10 + (c - '0');
  210.             c = *fmt++;
  211.         }
  212.         if (c == '*') {
  213.             current_fmt.width = va_arg(ap, int);
  214.             c = *fmt++;
  215.         }
  216.         if (c == '.') {
  217.             c = *fmt++;
  218.             while (c >= '0' && c <= '9') {
  219.                 current_fmt.precision = current_fmt.precision * 10 + (c - '0');
  220.                 c = *fmt++;
  221.             }
  222.             if (c == '*') {
  223.                 current_fmt.precision = va_arg(ap, int);
  224.                 c = *fmt++;
  225.             }
  226.         }
  227.     reswitch:
  228.         /* At this point, fmt points at one past the format letter. */
  229.         switch (c) {
  230.         case '%':
  231.             f_putc('%', current_fmt.iop);
  232.             break;
  233.  
  234.         case 'O':
  235.         case 'D':
  236.         case 'X':
  237.             putld(va_arg(ap, long), (c == 'O') ? 8 :
  238.                         (c == 'D') ? 10 : 16);
  239.             break;
  240.  
  241.         case 'b':
  242.             {
  243.             Buffer    *b = va_arg(ap, Buffer *);
  244.  
  245.             fmt_puts(b->b_name);
  246.             break;
  247.             }
  248.  
  249.         case 'c':
  250.             f_putc(va_arg(ap, DAPchar), current_fmt.iop);
  251.             break;
  252.  
  253.         case 'o':
  254.         case 'd':
  255.         case 'x':
  256.             putld((long) va_arg(ap, int), (c == 'o') ? 8 :
  257.                         (c == 'd') ? 10 : 16);
  258.             break;
  259.  
  260.         case 'f':    /* current command name gets inserted here! */
  261.             fmt_puts(LastCmd->Name);
  262.             break;
  263.  
  264.         case 'l':
  265.             c = CharUpcase(*++fmt);
  266.             goto reswitch;
  267.  
  268.         case 'n':
  269.             if (va_arg(ap, int) != 1)
  270.                 fmt_puts("s");
  271.             break;
  272.  
  273.         case 'p':
  274.             {
  275.             ZXchar    cc = ZXC(va_arg(ap, DAPchar));
  276.  
  277.             if (cc == ESC) {
  278.                 fmt_puts("ESC");
  279.             } else {
  280.                 char    cbuf[PPWIDTH];
  281.  
  282.                 PPchar(cc, cbuf);
  283.                 fmt_puts(cbuf);
  284.             }
  285.             }
  286.             break;
  287.  
  288.         case 's':
  289.             fmt_puts(va_arg(ap, char *));
  290.             break;
  291.  
  292.         default:
  293.             complain("Unknown format directive: \"%%%c\"", c);
  294.         }
  295.     }
  296.     current_fmt = prev_fmt;
  297. }
  298.  
  299. #ifdef STDARGS
  300. char *
  301. sprint(const char *fmt, ...)
  302. #else
  303. /*VARARGS1*/ char *
  304. sprint(fmt, va_alist)
  305.     const char    *fmt;
  306.     va_dcl
  307. #endif
  308. {
  309.     va_list    ap;
  310.     static char    line[LBSIZE];
  311.  
  312.     va_init(ap, fmt);
  313.     format(line, sizeof line, fmt, ap);
  314.     va_end(ap);
  315.     return line;
  316. }
  317.  
  318. #ifdef STDARGS
  319. void
  320. writef(const char *fmt, ...)
  321. #else
  322. /*VARARGS1*/ void
  323. writef(fmt, va_alist)
  324.     const char    *fmt;
  325.     va_dcl
  326. #endif
  327. {
  328.     va_list    ap;
  329.  
  330.     va_init(ap, fmt);
  331. #ifdef NO_JSTDOUT
  332.     /* Can't use sprint because caller might have
  333.      * passed the result of sprint as an arg.
  334.      */
  335.     {
  336.         char    line[100];
  337.  
  338.         format(line, sizeof(line), fmt, ap);
  339.         putstr(line);
  340.     }
  341. #else /* !NO_JSTDOUT */
  342.     doformat(jstdout, fmt, ap);
  343. #endif /* !NO_JSTDOUT */
  344.     va_end(ap);
  345. }
  346.  
  347. #ifdef STDARGS
  348. void
  349. fwritef(File *fp, const char *fmt, ...)
  350. #else
  351. /*VARARGS2*/ void
  352. fwritef(fp, fmt, va_alist)
  353.     File    *fp;
  354.     const char    *fmt;
  355.     va_dcl
  356. #endif
  357. {
  358.     va_list    ap;
  359.  
  360.     va_init(ap, fmt);
  361.     doformat(fp, fmt, ap);
  362.     va_end(ap);
  363. }
  364.  
  365. #ifdef STDARGS
  366. void
  367. swritef(char *str, size_t size, const char *fmt, ...)
  368. #else
  369. /*VARARGS3*/ void
  370. swritef(str, size, fmt, va_alist)
  371.     char    *str;
  372.     size_t    size;
  373.     const char    *fmt;
  374.     va_dcl
  375. #endif
  376. {
  377.     va_list    ap;
  378.  
  379.     va_init(ap, fmt);
  380.     format(str, size, fmt, ap);
  381.     va_end(ap);
  382. }
  383.  
  384. /* send a message (supressed if input pending) */
  385.  
  386. #ifdef STDARGS
  387. void
  388. s_mess(const char *fmt, ...)
  389. #else
  390. /*VARARGS1*/ void
  391. s_mess(fmt, va_alist)
  392.     const char    *fmt;
  393.     va_dcl
  394. #endif
  395. {
  396.     va_list    ap;
  397.  
  398.     if (InJoverc)
  399.         return;
  400.     va_init(ap, fmt);
  401.     format(mesgbuf, sizeof mesgbuf, fmt, ap);
  402.     va_end(ap);
  403.     message(mesgbuf);
  404. }
  405.  
  406. /* force a message: display it now no matter what.
  407.  * If you wish it to stick, set stickymsg on after calling f_mess.
  408.  */
  409.  
  410. #ifdef STDARGS
  411. void
  412. f_mess(const char *fmt, ...)
  413. #else
  414. /*VARARGS1*/ void
  415. f_mess(fmt, va_alist)
  416.     const char    *fmt;
  417.     va_dcl
  418. #endif
  419. {
  420.     va_list    ap;
  421.  
  422.     va_init(ap, fmt);
  423.     format(mesgbuf, sizeof mesgbuf, fmt, ap);
  424.     va_end(ap);
  425.     DrawMesg(NO);
  426.     stickymsg = NO;
  427.     UpdMesg = YES;    /* still needs updating (for convenience) */
  428. }
  429.  
  430. #ifdef STDARGS
  431. void
  432. add_mess(const char *fmt, ...)
  433. #else
  434. /*VARARGS1*/ void
  435. add_mess(fmt, va_alist)
  436.     const char    *fmt;
  437.     va_dcl
  438. #endif
  439. {
  440.     int    mesg_len = strlen(mesgbuf);
  441.     va_list    ap;
  442.  
  443.     if (InJoverc)
  444.         return;
  445.     va_init(ap, fmt);
  446.     format(&mesgbuf[mesg_len], (sizeof mesgbuf) - mesg_len, fmt, ap);
  447.     va_end(ap);
  448.     message(mesgbuf);
  449. }
  450.