home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / QSPRINTF.ZIP / QSPRINTF.C
C/C++ Source or Header  |  1989-02-04  |  8KB  |  268 lines

  1. /*
  2. ** qsprintf()
  3. ** Copyright (C) 1988, 1989, William B. McCormick
  4. ** Released to public domain on 01 February 1989.
  5. **
  6. ** Reentrant sprintf() replacement.  Quick-and-dirty but duplicates most
  7. ** of the sprintf() functionality.
  8. **
  9. ** History:
  10. **      07/28/88        William B. McCormick
  11. **              Quick printf() for OS/2 multi-threaded programs.
  12. **      02/01/89        William B. McCormick
  13. **              Changed to sprintf().  Added '*' specification.  Released
  14. **              to public domain.
  15. **
  16. ** Properly formats:
  17. **      % [flags] [width ] [.precision] [size] type
  18. **          flags:
  19. **              -       left justify the result within field.
  20. **              0       pad with '0' instead of ' '
  21. **          width:
  22. **              Controls the minimum # of characters printed.  If value is
  23. **              less than specified width, padding is added.  The width
  24. **              may be '*', in which case an integer argument from the
  25. **              argument list supplies the value.
  26. **          precision:
  27. **              Specifies the maximum # of characters printed.  The precision
  28. **              may be '*', in which case an integer argument from the
  29. **              argument list supplies the value.
  30. **          size:
  31. **              F       Specifies 's' is FAR
  32. **              N       Specifies 's' is NEAR
  33. **              l       Specifies 'd', 'x', 'u' is long
  34. **              B       Followed by integer (or '*') from 2-36.  Specifies
  35. **                      base of number to be printed with 'd', 'i', or 'u'.
  36. **          type:
  37. **              s       string
  38. **              d       signed integer
  39. **              i       signed integer
  40. **              u       unsigned integer
  41. **              x       unsigned hexadecimal integer ('abcdef')
  42. **              n       Number of characters written to destination so far
  43. **                      is stored in the integer whose address is given as
  44. **                      the argument
  45. */
  46.  
  47. #include <stdlib.h>
  48. #include <stdarg.h>
  49. #include <limits.h>
  50.  
  51.  
  52.         /* comment out these lines for strict ANSI compatibility */
  53. #define FAR     far
  54. #define NEAR    near
  55.  
  56.  
  57.         /* prototype */
  58. int qsprintf( char *dest, const char *fmt, ... );
  59.  
  60.  
  61. #define TRUE 1
  62. #define FALSE 0
  63.  
  64. #ifndef isdigit
  65. #       define isdigit(c) ((c)>='0' && (c)<='9')
  66. #endif
  67.  
  68.  
  69. #define w_char( dest, ch )      (*(dest)++ = ch)
  70. #define w_str( dest, str, len ) for ( ; (len)>0; (len)--, (str)++ ) \
  71.                                         w_char( (dest), *(str) )
  72.         
  73.  
  74. static void
  75. w_string( char **pdest,
  76.           register const char FAR *str,
  77.           int minlen,
  78.           int maxlen,
  79.           char fill )
  80. {
  81. unsigned count, c2;
  82. register const char FAR *p;
  83. char    *dest;
  84.         dest = *pdest;
  85.  
  86.         count = 0;
  87.         p = str;
  88.         while ( *p++ )
  89.                 if ( ++count == maxlen )
  90.                         break;
  91.  
  92.         if ( minlen > 0 ) {
  93.                 for ( ; minlen>count; --minlen )
  94.                         w_char( dest, fill );
  95.         }
  96.  
  97.         c2 = count;
  98.         w_str( dest, str, c2 );
  99.  
  100.         if ( minlen < 0 ) {
  101.                 for ( minlen=-minlen; minlen>count; --minlen )
  102.                         w_char( dest, fill );
  103.         }
  104.         *pdest = dest;
  105. }
  106.  
  107.  
  108. static char
  109. get_int( va_list *parg, const char **pp, int *vp )
  110. {
  111. register const char *p;
  112. register int val;
  113. int sign;
  114. char firstc;
  115.         p = *pp;
  116.  
  117.         if ( *p=='-' ) {
  118.                 ++p;
  119.                 sign = -1;
  120.         }
  121.         else
  122.                 sign = 1;
  123.         firstc = *p;
  124.  
  125.         if ( *p=='0' )          /* skip zero in case '0*' */
  126.                 ++ p;
  127.  
  128.         if ( *p=='*' ) {        /* get the value */
  129.                 ++ p;
  130.                 val = va_arg( *parg, int );
  131.         }
  132.         else {
  133.                 val = 0;
  134.                 for ( ; isdigit(*p); p++ )
  135.                         val = val * 10 + *p - '0';
  136.         }
  137.         *vp = val * sign;
  138.         *pp = p;
  139.         return firstc;
  140. }
  141.  
  142.  
  143.  
  144.  
  145. int cdecl
  146. qsprintf( char *dest, const char *fmt, ... )
  147. {
  148. va_list                 arg;
  149. register const char     *reg_p;
  150. const char              *auto_p;
  151. char                    buf[ CHAR_BIT * sizeof(long) + 1 ];
  152. int                     val, val2;
  153. int                     base;
  154. int                     islong, isfar, isnear;
  155. char                    fill;
  156. char                    *org_dest;
  157.  
  158.     org_dest = dest;
  159.  
  160.     va_start(arg,fmt);
  161.     reg_p = fmt;
  162.  
  163.     for ( ;*reg_p; reg_p++ ) {
  164.         if ( *reg_p=='%' ) {
  165.             isnear = isfar = islong = FALSE;
  166.             val = val2 = 0;
  167.             base = 10;
  168.             fill = ' ';
  169.             auto_p = reg_p + 1;
  170.             if ( get_int( &arg, &auto_p, &val ) == '0' )
  171.                 fill = '0';
  172.             if ( *auto_p=='.' ) {
  173.                 ++auto_p;
  174.                 (void) get_int( &arg, &auto_p, &val2 );
  175.             }
  176.             reg_p = auto_p-1;
  177. next_fmt:
  178.             switch ( *++reg_p ) {
  179.  
  180.                 case 'l':
  181.                     islong = TRUE;
  182.                     goto next_fmt;
  183.  
  184.                 case 'F':
  185.                     isfar = TRUE;
  186.                     goto next_fmt;
  187.  
  188.                 case 'N':
  189.                     isnear = TRUE;
  190.                     goto next_fmt;
  191.  
  192.                 case 'B':
  193.                     auto_p = reg_p+1;
  194.                     (void) get_int( &arg, &auto_p, &base );
  195.                     reg_p = auto_p-1;
  196.                     goto next_fmt;
  197.  
  198.                 case 'n':
  199.                     *va_arg( arg, int * ) = dest - org_dest;
  200.                     break;
  201.  
  202.                 case 's':
  203.                     w_string( &dest,
  204.                               isfar ?
  205.                                 va_arg(arg,const char FAR *) :
  206.                                 (isnear ?
  207.                                  (const char FAR *)va_arg(arg,
  208.                                                           const char NEAR *) :
  209.                                  (const char FAR *)va_arg(arg, const char *)),
  210.                               val,
  211.                               val2,
  212.                               fill );
  213.                     break;
  214.                                     
  215.                 case 'u':
  216.                     w_string( &dest,
  217.                               ltoa( islong ?
  218.                                      va_arg(arg,unsigned long) :
  219.                                      (unsigned long)va_arg(arg,unsigned),
  220.                                     buf,
  221.                                     base ),
  222.                               val,
  223.                               INT_MAX,
  224.                               fill );
  225.                     break;
  226.  
  227.                 case 'd':
  228.                 case 'i':
  229.                     w_string( &dest,
  230.                               ltoa( islong ?
  231.                                      va_arg(arg,long) :
  232.                                      (long) va_arg(arg,int),
  233.                                     buf,
  234.                                     base ),
  235.                               val,
  236.                               INT_MAX,
  237.                               fill );
  238.                     break;
  239.  
  240.                 case 'x':
  241.                     w_string( &dest,
  242.                               ltoa( islong ?
  243.                                      va_arg(arg,long) :
  244.                                      (long) va_arg(arg,int),
  245.                                     buf,
  246.                                     16 ),
  247.                               val,
  248.                               INT_MAX,
  249.                               fill );
  250.                     break;
  251.                                     
  252.                 default:
  253.                     w_char( dest, *reg_p );
  254.             }
  255.         }
  256.         else {
  257.             w_char( dest, *reg_p );
  258.         }
  259.     }
  260.     w_char( dest, '\0' );
  261.     return dest - org_dest - 1;         /* length of string */
  262. }
  263.  
  264.  
  265.  
  266.  
  267.  
  268.