home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / bss / pup.arc / PRINTF.C < prev    next >
C/C++ Source or Header  |  1987-10-31  |  6KB  |  291 lines

  1.  
  2. /* Formatted string processor.
  3.  
  4.     T. Jennings
  5.     Fido Software
  6.     164 Shipley
  7.     San Francisco CA 94107
  8.     (415)-764-1688
  9.  
  10.     (k) all rights reversed
  11.  
  12. Format string options:
  13.  
  14.     "%-0w.p,l{dux}"
  15.  
  16.         -     left justified (else right)
  17.         0     left zero fill
  18.         w     field width
  19.         .p    precision
  20.         ,    comma separate 1000's (cute, huh?)
  21.         l    long
  22.  
  23. _spr() is a formatted string processor for printf() etc. Gross. Plagiarized 
  24. from Leor Zolman's STDLIB2.C for BDS C 1.42. Brain Damage Software still 
  25. lives on ... what year is this???
  26.  
  27. HARD-CODED ASSUMPTIONS:
  28.  
  29. this uses a pointer to access the variable number of arguments on the
  30. stack instead of complex (to me) structures and unions. Hence, its very
  31. dependent on the ACTUAL SIZE of elements it deals with.
  32.  
  33. MSDOS:
  34.     chars are two bytes on stack
  35.     ints are two bytes on stack
  36.     longs are four bytes on stack
  37.     char *'s are two bytes
  38.  
  39.     For the function call(a,b,c,d,e,f), where all are ints (say)
  40.  
  41.     a is at address N on the stack
  42.     b is at N + 2
  43.     c is at N + 4
  44.     ...
  45.  
  46. It works by keeping a pointer to the arguments on the stack, and using
  47. the %thing string to figure out what kind of arg to pull off.
  48.  
  49.  
  50. KNOWN BUGS:
  51.  
  52. Staunchly refuses to print negative numbers. I've been meaning to get around
  53. to fixing this bug for over four years. It doesnt look like I'll get to it
  54. soon, so if it bugs you fix it yourself. (Id love a copy.) I never could find
  55. a reason to shove negative numbers in the users face anyways.
  56.  
  57. */
  58.  
  59. #define MAXSTR 300        /* size of process buffer */
  60.  
  61. char _spr_sepchar = ',';    /* 1000's seperator character */
  62.  
  63. /* Write a string to the console. */
  64.  
  65. puts(s)
  66. char *s;
  67. {
  68.     while (*s) lconout(*s++);
  69. }
  70. /* Replacements for the overly large Lattice ones. */
  71.  
  72. printf(f)
  73. char *f;
  74. {
  75. char buf[MAXSTR],*p;
  76.  
  77.     _spr(buf,&f);
  78.     puts(buf);
  79. }
  80.  
  81. sprintf(s,f)
  82. char *s,*f;
  83. {
  84.     _spr(s,&f);
  85. }
  86.  
  87. _spr(line,fmt)
  88. char *line, **fmt;
  89. {
  90. char c;
  91. char base;            /* base is 10, 8, 16, etc */
  92. char *sptr;            /* pointer to string argument */
  93. char *format;            /* pointer to format string */
  94. char **s;
  95. char pf;            /* true == doing precision (dot detector) */
  96. char ljflag;            /* true == left justification */
  97. char zfflag;            /* true == zero fill */
  98. char sepflag;            /* true == comma fill, ie 1,000,000,000,000 */
  99. int width;            /* width of current arg (ie. for padding w blanks/zeros) */
  100. int precision;
  101. int sizearg,islong;
  102. long num;
  103.  
  104. unsigned li;            /* index into line, above */
  105.  
  106. char wb[33];            /* room for largest possible digit string (long base 2) */
  107. char sb[MAXSTR];
  108. unsigned si;            /* index to sb[] */
  109. unsigned i,j,l;            /* habits can be hard to break */
  110.  
  111. int *args;            /* ptr to int/char args */
  112. long *longarg;            /* avoids ugly casts */
  113. char **charstararg;        /* ditto */
  114.  
  115.     format = (char *)*fmt++;
  116.     args = (int *)fmt;
  117.     li= 0;                /* total output line length */
  118.  
  119.     while (c = *format++)
  120.         if (c == '%') {
  121.             si= 0;        /* output buffer index */
  122.             precision = 6;
  123.             ljflag = pf = zfflag = sepflag= 0;
  124.  
  125.             if (*format == '-') {
  126.                 format++;
  127.                 ljflag++;
  128.              }
  129.  
  130.             if (*format == '0') zfflag++;    /* test for zero-fill */
  131.  
  132.             width = (isdigit(*format)) ? _gv2(&format) : 0;
  133.  
  134.             c= *format++;
  135.             if (c == '.') {
  136.                 c = *format++;
  137.                 precision = _gv2(&format);
  138.                 pf++;
  139.             }
  140.  
  141.             if (c == ',') {
  142.                 c= *format++;
  143.                 sepflag= 1;
  144.             }
  145.  
  146.             longarg= (long *)args;
  147.             charstararg= (char **)args;
  148.             islong= 0;
  149.  
  150.             if (c == 'l') {            /* if long, */
  151.                 c= *format++;        /* skip the L, */
  152.                 sizearg= sizeof(long);    /* for bumping pointer */
  153.                 longarg= (long *)args;    /* force confusing typing */
  154.                 num= *longarg;        /* get the value, */
  155.                 islong= 1;
  156.  
  157.             } else {
  158.                 sizearg= sizeof(int);
  159.                 num= *args;
  160.             }
  161.             switch(toupper(c)) {
  162.  
  163.                 case 'D':
  164.                     if (num < 0L) {
  165.                         sb[si]= '-';
  166.                         if (si < MAXSTR) ++si;
  167.                         num= - num;
  168.                         width--;
  169.                     }
  170.  
  171.                 case 'U': base = 10; goto val;
  172.                 case 'X': base = 16; goto val;
  173.                 case 'O': base = 8; goto val;
  174.  
  175. /* _uspr() builds the plain digit string in wb, the Work Buffer. If using
  176. comma formatting, then separators are added before the string is moved to
  177. sb, the String Buffer. */
  178.  
  179.                 val:    _uspr(wb,&si,num,base);
  180.                     if ((si > 3) && sepflag) {
  181.                         l = si % 3;
  182. /*
  183.                 si= raw string length
  184.                 wb= raw digit string (ie. "12345")
  185.                 sb= working string (ie. "12,345")
  186.                 l= 100's digits counter, MOD 3
  187.                 i= index into sb[]
  188.                 j= index into wb[]
  189. */
  190.                         for (i= j= 0; j < si;) {
  191.                             sb[i++]= wb[j++];
  192.                             if ((--l == 0) && (j < si))
  193.                                 sb[i++]= _spr_sepchar;
  194.                             if (l <= 0) l= 3;
  195.                         }
  196.                         si= i;        /* see pad: */
  197.  
  198.                     } else for (i= 0; i < si; i++) sb[i]= wb[i];
  199.                     width -= i;
  200.  
  201.                     if (islong) args= (int *) ++longarg;
  202.                     else ++args;
  203.                     goto pad;
  204.  
  205. /* A char on the stack is the same size as an int. */
  206.                 case 'C':
  207.                     sb[si]= *(char *)args;
  208.                     if (si < MAXSTR) ++si;
  209.                     ++args;
  210.                     width--;
  211.                     goto pad;
  212.  
  213.                 case 'S':
  214.                     if (! pf) precision = 200;
  215.                     sptr = *(char **)args;
  216.                     args= (int *) ++charstararg;
  217.  
  218.                     while (*sptr && precision) {
  219.                         sb[si]= *sptr++;
  220.                         if (si < MAXSTR) ++si;
  221.                         precision--;
  222.                         width--;
  223.                     }
  224.  
  225.                 pad:
  226.                     sb[si]= '\0';
  227.                     si= 0;
  228.                     if (! ljflag) {
  229.                         while (width-- > 0) {
  230.                             line[li]= (zfflag ? '0' : ' ');
  231.                             if (li < MAXSTR) ++li;
  232.                         }
  233.                     }
  234.                     while (sb[si]) {
  235.                         line[li]= sb[si++];
  236.                         if (li < MAXSTR) ++li;
  237.                     }
  238.  
  239.                     if (ljflag) {
  240.                         while (width-- > 0) {
  241.                             line[li]= ' ';
  242.                             if (li < MAXSTR) ++li;
  243.                         }
  244.                     }
  245.                     break;
  246.  
  247.                  default:
  248.                     line[li]= c; if (li < MAXSTR) ++li; break;
  249.              }
  250.  
  251.         } else {
  252.             line[li]= c;
  253.             if (li < MAXSTR) ++li;
  254.         }
  255.  
  256.     line[li]= '\0';
  257. }
  258.  
  259. /*
  260.     Internal routine used by "_spr" to perform ascii-
  261.     to-decimal conversion and update an associated pointer:
  262. */
  263.  
  264. int _gv2(sptr)
  265. char **sptr;
  266. {
  267. int n;
  268.     n = 0;
  269.     while (isdigit(**sptr)) n = 10 * n + *(*sptr)++ - '0';
  270.     return(n);
  271. }
  272.  
  273. _uspr(buff, buffi, n, base)
  274. char buff[];
  275. unsigned *buffi;
  276. long n;
  277. int base;
  278. {
  279. int length;
  280.  
  281.     if (n < base) {
  282.         buff[*buffi]= (n < 10L) ? n + 48L : n + 55L;
  283.         if (*buffi < MAXSTR) ++(*buffi);
  284.         buff[*buffi]= '\0';
  285.         return(1);
  286.     }
  287.     length = _uspr(buff, buffi, n / base, base);
  288.     _uspr(buff, buffi, n % base, base);
  289.     return (length + 1);
  290. }
  291.