home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / plbin.zip / pl / src / pl-fmt.c < prev    next >
C/C++ Source or Header  |  1993-02-23  |  11KB  |  503 lines

  1. /*  pl-fmt.c,v 1.4 1993/02/23 13:16:31 jan Exp
  2.  
  3.     Copyright (c) 1990 Jan Wielemaker. All rights reserved.
  4.     See ../LICENCE to find out about your rights.
  5.     jan@swi.psy.uva.nl
  6.  
  7.     Purpose: Formated write
  8. */
  9.  
  10. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  11. Formatted output (Prolog predicates format/[1,2,3]).   One  day,  the  C
  12. source should also use format() to produce error messages, etc.
  13. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  14.  
  15. #include "pl-incl.h"
  16. #include "pl-ctype.h"
  17. #include "pl-itf.h"
  18. extern int Output;
  19.  
  20. #define BUFSIZE     10240
  21. #define DEFAULT     (-1)
  22. #define SHIFT       { argc--; argv++; }
  23. #define NEED_ARG    { if ( argc <= 0 ) \
  24.               { ERROR("not enough arguments"); \
  25.               } else \
  26.               { deRef2(argv, a); \
  27.               } \
  28.             }
  29. #define ERROR(fmt)    return warning("format/2: %s", fmt)
  30. #define ERROR1(fmt, a)    { char tp[50]; \
  31.               strcpy(tp, "format/2: "); \
  32.               strcat(tp, fmt); \
  33.               return warning(tp, a); \
  34.             }
  35. #define OUTSTRING(s)    { char *q = s; \
  36.               for(; *q; q++) OUTCHR(*q); \
  37.             }
  38. #define OUTCHR(c)    { if ( pending_rubber ) \
  39.                 buffer[index++] = (c); \
  40.               else \
  41.                 Put((Char)(c)); \
  42.               column = update_column(column, c); \
  43.             }
  44.  
  45. #define MAXRUBBER 100
  46.  
  47. struct rubber
  48. { int where;                /* where is rubber in output */
  49.   int size;                /* how big should it be */
  50.   Char pad;                /* padding character */
  51. };
  52.  
  53. static Table format_predicates;        /* Prolog defined fromatting */
  54.  
  55. forwards int    update_column P((int, Char));
  56. forwards bool    do_format P((char *fmt, int argc, Word argv));
  57. forwards void    distribute_rubber P((struct rubber *, int, int));
  58. forwards void    emit_rubber P((char *buf, int, struct rubber *, int));
  59.  
  60.         /********************************
  61.         *       PROLOG CONNECTION    *
  62.         ********************************/
  63.  
  64. word
  65. pl_format_predicate(chr, descr)
  66. Word chr, descr;
  67. { long c;
  68.   Procedure proc;
  69.   Symbol s;
  70.  
  71.   if ( isInteger(*chr) )
  72.   { c = valNum(*chr);
  73.     if ( c < 0 || c > 255 )
  74.       return warning("format_predicate/2: illegal character");
  75.   } else if ( isAtom(*chr) )
  76.   { c = stringAtom(*chr)[0];
  77.   } else
  78.     return warning("format_predicate/2: illegal character");
  79.  
  80.   if ( (proc = findCreateProcedure(descr)) == NULL )
  81.     fail;
  82.   if ( proc->functor->arity == 0 )
  83.     return warning("format_predicate/2: predicate must have at least 1 argument");
  84.  
  85.   if ( format_predicates == NULL )
  86.     format_predicates = newHTable(64);
  87.   
  88.   if ( (s = lookupHTable(format_predicates, (Void)c)) != NULL )
  89.     s->value = (word) proc;
  90.   else
  91.     addHTable(format_predicates, (Void)c, proc);
  92.  
  93.   succeed;
  94. }
  95.  
  96.  
  97. word
  98. pl_format(fmt, args)
  99. Word fmt;
  100. register Word args;
  101. { Word argv;
  102.   word rval;
  103.   int argc = 0;
  104.   char *f;
  105.   mark m;
  106.  
  107.   if ( isAtom(*fmt) )
  108.     f = stringAtom(*fmt);
  109.   else if ( isString(*fmt) )
  110.     f = valString(*fmt);
  111.   else if ( (f = listToString(*fmt)) != NULL )
  112.     f = store_string(f);
  113.   else
  114.     return warning("format/2: format is not an atom or string");
  115.  
  116.   Mark(m);
  117.   deRef(args);
  118.   if ( isNil(*args) )
  119.   { argc = 0;
  120.     argv = NULL;
  121.   } else if ( !isList(*args) )
  122.   { argc = 1;
  123.     argv = args;
  124.   } else
  125.   { Word ap;
  126.  
  127.     if ( (argc = lengthList(args)) < 0 )
  128.       return warning("format/2: argument list is not proper");
  129.     ap = argv = allocGlobal(argc * sizeof(word));
  130.  
  131.     while( isList(*args) )
  132.     { Word a = HeadList(args);
  133.  
  134.       deRef(a);
  135.       *ap++ = (isVar(*a) ? makeRef(a) : *a);
  136.  
  137.       args = TailList(args);
  138.       deRef(args);
  139.     }
  140.   }
  141.  
  142.   rval = do_format(f, argc, argv);
  143.   Undo(m);
  144.  
  145.   return rval;
  146. }
  147.  
  148. word
  149. pl_format3(stream, fmt, args)
  150. Word stream, fmt, args;
  151. { streamOutput(stream, pl_format(fmt, args));
  152. }
  153.  
  154. #if O_C_FORMAT
  155.  
  156.         /********************************
  157.         *          C-CONNECTION        *
  158.         ********************************/
  159.  
  160. static bool
  161. vformat(fm, args)
  162. char *fm;
  163. va_list args;
  164. }
  165.  
  166. #if ANSI
  167. bool
  168. format(char *fm, ...)
  169. { va_list args;
  170.   bool rval;
  171.  
  172.   va_start(args, fm);
  173.   rval = vformat(fm, args);
  174.   va_end(args);
  175.  
  176.   return rval;
  177. }
  178.  
  179. #else
  180.  
  181. bool
  182. format(va_alist)
  183. va_dcl
  184. { va_list args;
  185.   char *fm;
  186.   bool rval;
  187.  
  188.   va_start(args);
  189.   fm = va_arg(args, char *);
  190.   rval = vformat(fm, args);
  191.   va_end(args);
  192.  
  193.   return rval;
  194. }
  195. #endif /* ANSI */
  196.  
  197. #endif /* O_C_FORMAT */
  198.         /********************************
  199.         *       ACTUAL FORMATTING    *
  200.         ********************************/
  201.  
  202. static int
  203. update_column(col, c)
  204. register int col;
  205. register Char c;
  206. { switch(c)
  207.   { case '\n':    return 0;
  208.     case '\t':    return (col + 1) | 0x7;
  209.     case '\b':    return (col <= 0 ? 0 : col - 1);
  210.     default:    return col + 1;
  211.   }
  212. }   
  213.  
  214. static bool
  215. do_format(fmt, argc, argv)
  216. char *fmt;
  217. int argc;
  218. Word argv;
  219. { char buffer[BUFSIZE];            /* to store chars with tabs */
  220.   int index = 0;            /* index in buffer */
  221.   int column = currentLinePosition();    /* current output column */
  222.   int tab_stop = 0;            /* padded tab stop */
  223.   int pending_rubber = 0;        /* number of not-filled ~t's */
  224.   struct rubber rub[MAXRUBBER];
  225.   Symbol s;
  226.  
  227.   while(*fmt)
  228.   { switch(*fmt)
  229.     { case '~':
  230.     { int arg = DEFAULT;        /* Numeric argument */
  231.       Word a;            /* (List) argument */
  232.                     /* Get the numeric argument */
  233.       if ( isDigit(*++fmt) )
  234.       { for( ; isDigit(*fmt); fmt++ )
  235.           arg = (arg == DEFAULT ? arg = *fmt - '0' : arg*10 + *fmt - '0');
  236.       } else if ( *fmt == '*' )
  237.       { NEED_ARG;
  238.         if ( isInteger(*a) && (arg = (int)valNum(*a)) >= 0 )
  239.         { SHIFT;
  240.         } else
  241.           ERROR("no or negative integer for `*' argument");
  242.         fmt++;
  243.       } else if ( *fmt == '`' )
  244.       { arg = *++fmt;
  245.         fmt++;
  246.       }
  247.         
  248.                     /* Check for user defined format */
  249.       if ( format_predicates != NULL &&
  250. #if gould
  251.            (s = lookupHTable(format_predicates, (ulong)*fmt)) != NULL )
  252. #else
  253.            (s = lookupHTable(format_predicates,
  254.                  (Void)((long)*fmt))) != NULL )
  255. #endif
  256.       { Procedure proc = (Procedure) s->value;
  257.         char buf[BUFSIZE];
  258.         mark m;
  259.         word goal;
  260.         Word g;
  261.         int n;
  262.  
  263.         Mark(m);
  264.         goal = globalFunctor(FUNCTOR_module2);
  265.         unifyAtomic(argTermP(goal, 0), proc->definition->module->name);
  266.         unifyAtomic(argTermP(goal, 1), globalFunctor(proc->functor));
  267.         g = argTermP(goal, 1);
  268.         unifyAtomic(argTermP(*g, 0), arg == DEFAULT ? (word)ATOM_default
  269.                                 : consNum(arg));
  270.         for(n = 1; n < proc->functor->arity; n++)
  271.         { NEED_ARG;
  272.           pl_unify(argTermP(*g, n), a);
  273.           SHIFT;
  274.         }
  275.         tellString(buf, BUFSIZE);
  276.         debugstatus.suspendTrace++;
  277.         callGoal(MODULE_user, goal, FALSE);
  278.         debugstatus.suspendTrace--;
  279.         toldString();
  280.         OUTSTRING(buf);
  281.         Undo(m);
  282.  
  283.         fmt++;
  284.       } else
  285.       { switch(*fmt)        /* Build in formatting */
  286.         { case 'a':            /* atomic */
  287.         { char *s;
  288.  
  289.           NEED_ARG;
  290.           if ( (s = primitiveToString(*a, FALSE)) == (char *) NULL )
  291.             ERROR("illegal argument to ~a");
  292.           SHIFT;
  293.           OUTSTRING(s);
  294.           fmt++;
  295.           break;
  296.         }
  297.           case 'c':            /* ascii */
  298.         { NEED_ARG;
  299.           if ( isInteger(*a) )
  300.           { Char c = (int)valNum(*a);
  301.  
  302.             if ( c < 0 || c > 255 )
  303.               ERROR("illegal argument to ~c");
  304.             OUTCHR(c);
  305.             SHIFT;
  306.           } else
  307.             ERROR("illegal argument to ~c");
  308.           fmt++;
  309.           break;
  310.         }
  311.           case 'e':            /* exponential float */
  312.           case 'E':            /* Exponential float */
  313.           case 'f':            /* float */
  314.           case 'g':            /* shortest of 'f' and 'e' */
  315.           case 'G':            /* shortest of 'f' and 'E' */
  316.         { real f;
  317.           char tmp[12];
  318.           char buf[256];
  319.  
  320.           NEED_ARG;
  321.           if ( wordToReal(*a, &f) == FALSE )
  322.             ERROR1("illegal argument to ~%c", *fmt);
  323.           SHIFT;
  324.           sprintf(tmp, "%%.%d%c", arg == DEFAULT ? 6 : arg, *fmt);
  325.           sprintf(buf, tmp, f);
  326.           OUTSTRING(buf);
  327.           fmt++;
  328.           break;
  329.         }
  330.           case 'd':            /* integer */
  331.           case 'D':            /* grouped integer */
  332.           case 'r':            /* radix number */
  333.           case 'R':            /* Radix number */
  334.         { long i;
  335.           char *s;
  336.  
  337.           NEED_ARG;
  338.           if ( wordToInteger(*a, &i) == FALSE )
  339.             ERROR1("illegal argument to ~%c", *fmt);
  340.           SHIFT;
  341.           if ( arg == DEFAULT )
  342.             arg = 0;
  343.           s = ( (*fmt == 'd' || *fmt == 'D')
  344.             ? formatInteger(*fmt == 'D', arg, 10, TRUE, i)
  345.             : formatInteger(FALSE, 0, arg, *fmt == 'r', i)
  346.               );
  347.           OUTSTRING(s);            
  348.           fmt++;
  349.           break;
  350.         }
  351.           case 's':            /* string */
  352.         { char *s;
  353.  
  354.           NEED_ARG;
  355.           if ( (s = listToString(*a)) == (char *)NULL )
  356.             ERROR("illegal argument to ~s");
  357.           OUTSTRING(s);
  358.           SHIFT;
  359.           fmt++;
  360.           break;
  361.         }
  362.           case 'i':            /* ignore */
  363.         { NEED_ARG;
  364.           SHIFT;
  365.           fmt++;
  366.           break;
  367.         }
  368.         { Func f;
  369.           char buf[BUFSIZE];
  370.  
  371.           case 'k':            /* displayq */
  372.           f = pl_displayq;    goto pl_common;
  373.           case 'p':            /* print */
  374.           f = pl_print;        goto pl_common;
  375.           case 'q':            /* writeq */
  376.           f = pl_writeq;    goto pl_common;
  377.           case 'w':            /* write */
  378.           f = pl_write;
  379.           pl_common:
  380.  
  381.           NEED_ARG;
  382.           tellString(buf, BUFSIZE);
  383.           (*f)(a);
  384.           toldString();
  385.           SHIFT;
  386.           OUTSTRING(buf);
  387.           fmt++;
  388.           break;
  389.         }
  390.           case '~':            /* ~ */
  391.         { OUTCHR('~');
  392.           fmt++;
  393.           break;
  394.         }
  395.           case 'n':            /* \n */
  396.           case 'N':            /* \n if not on newline */
  397.         { if ( arg == DEFAULT )
  398.             arg = 1;
  399.           if ( *fmt == 'N' && column == 0 )
  400.             arg--;
  401.           while( arg-- > 0 )
  402.             OUTCHR('\n');
  403.           fmt++;
  404.           break;
  405.         }
  406.           case 't':            /* insert tab */
  407.         { rub[pending_rubber].where = index;
  408.           rub[pending_rubber].pad   = (arg == DEFAULT ? (Char) ' '
  409.                                   : (Char) arg);
  410.           pending_rubber++;
  411.           fmt++;
  412.           break;
  413.         }
  414.           case '|':            /* set tab */
  415.         { int stop;
  416.  
  417.           if ( arg == DEFAULT )
  418.             arg = column;
  419.           case '+':            /* tab relative */
  420.           if ( arg == DEFAULT )
  421.             arg = 8;
  422.           stop = (*fmt == '+' ? tab_stop + arg : arg);
  423.  
  424.           if ( pending_rubber == 0 ) /* nothing to distribute */
  425.           { rub[0].where = index;
  426.             rub[0].pad = ' ';
  427.             pending_rubber++;
  428.           }
  429.           distribute_rubber(rub, pending_rubber, stop - column);
  430.           emit_rubber(buffer, index, rub, pending_rubber);
  431.           index = 0;
  432.           pending_rubber = 0;
  433.  
  434.           column = tab_stop = stop;
  435.           fmt++;
  436.           break;
  437.         }
  438.           default:
  439.         ERROR1("unknown format: %c", *fmt);
  440.         }
  441.       }
  442.       break;            /* the '~' switch */
  443.     }
  444.       default:
  445.     { OUTCHR(*fmt);
  446.       fmt++;
  447.       break;
  448.     }
  449.     }
  450.   }
  451.  
  452.   if ( pending_rubber )            /* not closed ~t: flush out */
  453.     emit_rubber(buffer, index, rub, 0);
  454.  
  455.   succeed;
  456. }
  457.  
  458. static void
  459. distribute_rubber(r, rn, space)
  460. struct rubber *r;
  461. int rn;
  462. int space;
  463. { if ( space > 0 )
  464.   { int s = space / rn;
  465.     int n, m;
  466.  
  467.     for(n=0; n < rn; n++)        /* give them equal size */
  468.       r[n].size = s;
  469.                     /* distribute from the center */
  470.     space -= s*rn;
  471.     for(m = rn / 2, n = 0; space; n++, space--)
  472.     { r[m + (n % 2 ? n : -n)].size++;
  473.     }
  474.   } else
  475.   { int n;
  476.  
  477.     for(n=0; n < rn; n++)        /* set all rubber to 0 */
  478.       r[n].size = 0;
  479.   }
  480. }
  481.  
  482. static void
  483. emit_rubber(buf, i, r, rn)
  484. char *buf;
  485. int i;
  486. struct rubber *r;
  487. int rn;
  488. { int j;
  489.  
  490.   for(j = 0; j <= i; j++)
  491.   { if ( r->where == j && rn )
  492.     { int n;
  493.       for(n=0; n<r->size; n++)
  494.         Put(r->pad);
  495.       r++;
  496.       rn--;
  497.     }
  498.     if ( j < i )
  499.       Put(buf[j]);
  500.   }
  501. }
  502.