home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sa104os2.zip / SATHR104.ZIP / SATHER / SYSTEM / GC / CORD / CORDPRNT.C < prev    next >
C/C++ Source or Header  |  1994-10-03  |  11KB  |  390 lines

  1. /* 
  2.  * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
  3.  *
  4.  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  5.  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  6.  *
  7.  * Permission is hereby granted to use or copy this program
  8.  * for any purpose,  provided the above notices are retained on all copies.
  9.  * Permission to modify the code and to distribute modified code is granted,
  10.  * provided the above notices are retained, and a notice that the code was
  11.  * modified is included with the above copyright notice.
  12.  */
  13. /* An sprintf implementation that understands cords.  This is probably    */
  14. /* not terribly portable.  It assumes an ANSI stdarg.h.  It further    */
  15. /* assumes that I can make copies of va_list variables, and read     */
  16. /* arguments repeatedly by applyting va_arg to the copies.  This    */
  17. /* could be avoided at some performance cost.                */
  18. /* We also assume that unsigned and signed integers of various kinds    */
  19. /* have the same sizes, and can be cast back and forth.            */
  20. /* We assume that void * and char * have the same size.            */
  21. /* All this cruft is needed because we want to rely on the underlying    */
  22. /* sprintf implementation whenever possible.                */
  23. /* Boehm, October 3, 1994 5:15 pm PDT */
  24.  
  25. #include "cord.h"
  26. #include "ec.h"
  27. #include <stdio.h>
  28. #include <stdarg.h>
  29. #include <string.h>
  30. #include "gc.h"
  31.  
  32. #define CONV_SPEC_LEN 50    /* Maximum length of a single    */
  33.                 /* conversion specification.    */
  34. #define CONV_RESULT_LEN 50    /* Maximum length of any     */
  35.                 /* conversion with default    */
  36.                 /* width and prec.        */
  37.  
  38.  
  39. static int ec_len(CORD_ec x)
  40. {
  41.     return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
  42. }
  43.  
  44. /* Possible nonumeric precision values.    */
  45. # define NONE -1
  46. # define VARIABLE -2
  47. /* Copy the conversion specification from CORD_pos into the buffer buf    */
  48. /* Return negative on error.                        */
  49. /* Source initially points one past the leading %.            */
  50. /* It is left pointing at the conversion type.                */
  51. /* Assign field width and precision to *width and *prec.        */
  52. /* If width or prec is *, VARIABLE is assigned.                */
  53. /* Set *left to 1 if left adjustment flag is present.            */
  54. /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to    */
  55. /* -1 if 'h' is present.                        */
  56. static int extract_conv_spec(CORD_pos source, char *buf,
  57.                  int * width, int *prec, int *left, int * long_arg)
  58. {
  59.     register int result = 0;
  60.     register int current_number = 0;
  61.     register int saw_period = 0;
  62.     register int saw_number;
  63.     register int chars_so_far = 0;
  64.     register char current;
  65.     
  66.     *width = NONE;
  67.     buf[chars_so_far++] = '%';
  68.     while(CORD_pos_valid(source)) {
  69.         if (chars_so_far >= CONV_SPEC_LEN) return(-1);
  70.         current = CORD_pos_fetch(source);
  71.         buf[chars_so_far++] = current;
  72.         switch(current) {
  73.       case '*':
  74.         saw_number = 1;
  75.         current_number = VARIABLE;
  76.         break;
  77.           case '0':
  78.             if (!saw_number) {
  79.                 /* Zero fill flag; ignore */
  80.                 break;
  81.             } /* otherwise fall through: */
  82.           case '1':
  83.       case '2':
  84.       case '3':
  85.       case '4':
  86.       case '5':
  87.           case '6':
  88.       case '7':
  89.       case '8':
  90.       case '9':
  91.         saw_number = 1;
  92.         current_number *= 10;
  93.         current_number += current - '0';
  94.         break;
  95.       case '.':
  96.         saw_period = 1;
  97.         if(saw_number) {
  98.             *width = current_number;
  99.             saw_number = 0;
  100.         }
  101.         current_number = 0;
  102.         break;
  103.       case 'l':
  104.       case 'L':
  105.         *long_arg = 1;
  106.         current_number = 0;
  107.         break;
  108.       case 'h':
  109.         *long_arg = -1;
  110.         current_number = 0;
  111.         break;
  112.       case ' ':
  113.       case '+':
  114.       case '#':
  115.         current_number = 0;
  116.         break;
  117.       case '-':
  118.         *left = 1;
  119.         current_number = 0;
  120.         break;
  121.       case 'd':
  122.       case 'i':
  123.       case 'o':
  124.       case 'u':
  125.       case 'x':
  126.       case 'X':
  127.       case 'f':
  128.       case 'e':
  129.       case 'E':
  130.       case 'g':
  131.       case 'G':
  132.       case 'c':
  133.       case 'C':
  134.       case 's':
  135.       case 'S':
  136.       case 'p':
  137.       case 'n':
  138.       case 'r':
  139.         goto done;          
  140.           default:
  141.             return(-1);
  142.         }
  143.         CORD_next(source);
  144.     }
  145.     return(-1);
  146.   done:
  147.     if (saw_number) {
  148.         if (saw_period) {
  149.             *prec = current_number;
  150.         } else {
  151.             *prec = NONE;
  152.             *width = current_number;
  153.         }
  154.     } else {
  155.         *prec = NONE;
  156.     }
  157.     buf[chars_so_far] = '\0';
  158.     return(result);
  159. }
  160.  
  161. int CORD_vsprintf(CORD * out, CORD format, va_list args)
  162. {
  163.     CORD_ec result;
  164.     register int count;
  165.     register char current;
  166.     CORD_pos pos;
  167.     char conv_spec[CONV_SPEC_LEN + 1];
  168.     
  169.     CORD_ec_init(result);
  170.     for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
  171.            current = CORD_pos_fetch(pos);
  172.            if (current == '%') {
  173.             CORD_next(pos);
  174.             if (!CORD_pos_valid(pos)) return(-1);
  175.             current = CORD_pos_fetch(pos);
  176.             if (current == '%') {
  177.                    CORD_ec_append(result, current);
  178.             } else {
  179.                  int width, prec;
  180.                  int left_adj = 0;
  181.                  int long_arg = 0;
  182.         CORD arg;
  183.         size_t len;
  184.                
  185.                   if (extract_conv_spec(pos, conv_spec,
  186.                                 &width, &prec,
  187.                                 &left_adj, &long_arg) < 0) {
  188.                       return(-1);
  189.                   }
  190.                   current = CORD_pos_fetch(pos);
  191.                 switch(current) {
  192.                     case 'n':
  193.                         /* Assign length to next arg */
  194.                         if (long_arg == 0) {
  195.                             int * pos_ptr;
  196.                             pos_ptr = va_arg(args, int *);
  197.                             *pos_ptr = ec_len(result);
  198.                         } else if (long_arg > 0) {
  199.                             long * pos_ptr;
  200.                             pos_ptr = va_arg(args, long *);
  201.                             *pos_ptr = ec_len(result);
  202.                         } else {
  203.                             short * pos_ptr;
  204.                             pos_ptr = va_arg(args, short *);
  205.                             *pos_ptr = ec_len(result);
  206.                         }
  207.                         goto done;
  208.                     case 'r':
  209.                         /* Append cord and any padding    */
  210.                         if (width == VARIABLE) width = va_arg(args, int);
  211.                         if (prec == VARIABLE) prec = va_arg(args, int);
  212.             arg = va_arg(args, CORD);
  213.             len = CORD_len(arg);
  214.             if (prec != NONE && len > prec) {
  215.               if (prec < 0) return(-1);
  216.               arg = CORD_substr(arg, 0, prec);
  217.               len = prec;
  218.             }
  219.             if (width != NONE && len < width) {
  220.               char * blanks = GC_MALLOC_ATOMIC(width-len+1);
  221.  
  222.               memset(blanks, ' ', width-len);
  223.               blanks[width-len] = '\0';
  224.               if (left_adj) {
  225.                 arg = CORD_cat(arg, blanks);
  226.               } else {
  227.                 arg = CORD_cat(blanks, arg);
  228.               }
  229.             }
  230.             CORD_ec_append_cord(result, arg);
  231.                         goto done;
  232.             case 'c':
  233.             if (width == NONE && prec == NONE) {
  234.                 register char c = va_arg(args, char);
  235.  
  236.                 CORD_ec_append(result, c);
  237.                 goto done;
  238.             }
  239.             break;
  240.             case 's':
  241.                 if (width == NONE && prec == NONE) {
  242.                 char * str = va_arg(args, char *);
  243.                 register char c;
  244.  
  245.                 while (c = *str++) {
  246.                     CORD_ec_append(result, c);
  247.                 }
  248.                 goto done;
  249.             }
  250.             break;
  251.                     default:
  252.                         break;
  253.                 }
  254.                 /* Use standard sprintf to perform conversion */
  255.                 {
  256.                     register char * buf;
  257.                     va_list vsprintf_args = args;
  258.                         /* The above does not appear to be sanctioned    */
  259.                         /* by the ANSI C standard.            */
  260.                     int max_size = 0;
  261.                     int res;
  262.                         
  263.                     if (width == VARIABLE) width = va_arg(args, int);
  264.                     if (prec == VARIABLE) prec = va_arg(args, int);
  265.                     if (width != NONE) max_size = width;
  266.                     if (prec != NONE && prec > max_size) max_size = prec;
  267.                     max_size += CONV_RESULT_LEN;
  268.                     if (max_size >= CORD_BUFSZ) {
  269.                         buf = GC_MALLOC_ATOMIC(max_size + 1);
  270.                     } else {
  271.                         if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
  272.                             < max_size) {
  273.                             CORD_ec_flush_buf(result);
  274.                         }
  275.                         buf = result[0].ec_bufptr;
  276.                     }
  277.                     switch(current) {
  278.                         case 'd':
  279.                         case 'i':
  280.                         case 'o':
  281.                         case 'u':
  282.                         case 'x':
  283.                         case 'X':
  284.                         case 'c':
  285.                             if (long_arg <= 0) {
  286.                               (void) va_arg(args, int);
  287.                             } else if (long_arg > 0) {
  288.                               (void) va_arg(args, long);
  289.                             }
  290.                             break;
  291.                         case 's':
  292.                         case 'p':
  293.                             (void) va_arg(args, char *);
  294.                             break;
  295.                         case 'f':
  296.                         case 'e':
  297.                         case 'E':
  298.                         case 'g':
  299.                         case 'G':
  300.                             (void) va_arg(args, double);
  301.                             break;
  302.                         default:
  303.                             return(-1);
  304.                     }
  305.                     res = vsprintf(buf, conv_spec, vsprintf_args);
  306.                     len = (size_t)res;
  307.                     if ((char *)res == buf) {
  308.                         /* old style vsprintf */
  309.                         len = strlen(buf);
  310.                     } else if (res < 0) {
  311.                         return(-1);
  312.                     }
  313.                     if (buf != result[0].ec_bufptr) {
  314.                         register char c;
  315.  
  316.             while (c = *buf++) {
  317.                 CORD_ec_append(result, c);
  318.                 }
  319.             } else {
  320.                 result[0].ec_bufptr = buf + len;
  321.             }
  322.                 }
  323.               done:;
  324.             }
  325.         } else {
  326.             CORD_ec_append(result, current);
  327.         }
  328.     }
  329.     count = ec_len(result);
  330.     *out = CORD_balance(CORD_ec_to_cord(result));
  331.     return(count);
  332. }
  333.  
  334. int CORD_sprintf(CORD * out, CORD format, ...)
  335. {
  336.     va_list args;
  337.     int result;
  338.     
  339.     va_start(args, format);
  340.     result = CORD_vsprintf(out, format, args);
  341.     va_end(args);
  342.     return(result);
  343. }
  344.  
  345. int CORD_fprintf(FILE * f, CORD format, ...)
  346. {
  347.     va_list args;
  348.     int result;
  349.     CORD out;
  350.     
  351.     va_start(args, format);
  352.     result = CORD_vsprintf(&out, format, args);
  353.     va_end(args);
  354.     if (result > 0) CORD_put(out, f);
  355.     return(result);
  356. }
  357.  
  358. int CORD_vfprintf(FILE * f, CORD format, va_list args)
  359. {
  360.     int result;
  361.     CORD out;
  362.     
  363.     result = CORD_vsprintf(&out, format, args);
  364.     if (result > 0) CORD_put(out, f);
  365.     return(result);
  366. }
  367.  
  368. int CORD_printf(CORD format, ...)
  369. {
  370.     va_list args;
  371.     int result;
  372.     CORD out;
  373.     
  374.     va_start(args, format);
  375.     result = CORD_vsprintf(&out, format, args);
  376.     va_end(args);
  377.     if (result > 0) CORD_put(out, stdout);
  378.     return(result);
  379. }
  380.  
  381. int CORD_vprintf(CORD format, va_list args)
  382. {
  383.     int result;
  384.     CORD out;
  385.     
  386.     result = CORD_vsprintf(&out, format, args);
  387.     if (result > 0) CORD_put(out, stdout);
  388.     return(result);
  389. }
  390.