home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume29 / parseargs / part03 / vprintf.c < prev    next >
C/C++ Source or Header  |  1992-05-19  |  8KB  |  353 lines

  1. /* Portable vsprintf  by Robert A. Larson <blarson@skat.usc.edu> */
  2.  
  3. /* Copyright 1989 Robert A. Larson.
  4.  * Distribution in any form is allowed as long as the author
  5.  * retains credit, changes are noted by their author and the
  6.  * copyright message remains intact.  This program comes as-is
  7.  * with no warentee of fitness for any purpose.
  8.  *
  9.  * Thanks to Doug Gwyn, Chris Torek, and others who helped clarify
  10.  * the ansi printf specs.
  11.  *
  12.  * Please send any bug fixes and improvements to blarson@skat.usc.edu .
  13.  * The use of goto is NOT a bug.
  14.  */
  15.  
  16. /* Feb    7, 1989        blarson        First usenet release */
  17. /* Oct 20, 1990     Brad Appleton -- enclosed in #ifdef BSD for parseargs */
  18. /* Oct 21, 1990     Brad Appleton -- added test in #ifdef VPRINTF_TEST */
  19. /* Feb 25, 1990     Brad Appleton -- #included "useful.h" and added #ifdefs
  20.  *                                   to compile for ANSI-C as well as K&R
  21.  */
  22.  
  23.  
  24. /* This code implements the vsprintf function, without relying on
  25.  * the existance of _doprint or other system specific code.
  26.  *
  27.  * Define NOVOID if void * is not a supported type.
  28.  *
  29.  * Two compile options are available for efficency:
  30.  *    INTSPRINTF    should be defined if sprintf is int and returns
  31.  *                the number of chacters formated.
  32.  *    LONGINT        should be defined if sizeof(long) == sizeof(int)
  33.  *
  34.  *    They only make the code smaller and faster, they need not be
  35.  *    defined.
  36.  *
  37.  * UNSIGNEDSPECIAL should be defined if unsigned is treated differently
  38.  * than int in argument passing.  If this is definded, and LONGINT is not,
  39.  * the compiler must support the type unsingned long.
  40.  *
  41.  * Most quirks and bugs of the available sprintf fuction are duplicated,
  42.  * however * in the width and precision fields will work correctly
  43.  * even if sprintf does not support this, as will the n format.
  44.  *
  45.  * Bad format strings, or those with very long width and precision
  46.  * fields (including expanded * fields) will cause undesired results.
  47.  */
  48.  
  49.    /* Parseargs only needs this stuff for BSD Unix  -- Brad Appleton */
  50. #include <useful.h>
  51.  
  52. #ifdef BSD
  53. #include <stdio.h>
  54. #include <ctype.h>
  55.  
  56. #ifdef OSK        /* os9/68k can take advantage of both */
  57. # define LONGINT
  58. # define INTSPRINTF
  59. #endif
  60.  
  61. /* This must be a typedef not a #define! */
  62. #ifdef NOVOID
  63.   typedef char *pointer;
  64. #else
  65.   typedef void *pointer;
  66. #endif
  67.  
  68. #ifdef    INTSPRINTF
  69. # define Sprintf(string,format,arg)    (sprintf((string),(format),(arg)))
  70. #else
  71. # define Sprintf(string,format,arg)    (\
  72.    sprintf((string),(format),(arg)),\
  73.    strlen(string)\
  74. )
  75. #endif
  76.  
  77. typedef int *intp;
  78.  
  79. #ifdef __ANSI_C__
  80.   int vsprintf(char *dest, register const char *format, va_list args)
  81. #else
  82.   int vsprintf(dest, format, args)
  83.   char *dest;
  84.   register char *format;
  85.   va_list args;
  86. #endif
  87. {
  88.       register char *dp = dest;
  89.       register char c;
  90.       register char *tp;
  91.       char tempfmt[64];
  92. #ifndef LONGINT
  93.       int longflag;
  94. #endif
  95.  
  96.       tempfmt[0] = '%';
  97.       while( (c = *format++) != 0) {
  98.    if(c=='%') {
  99.        tp = &tempfmt[1];
  100. #ifndef LONGINT
  101.        longflag = 0;
  102. #endif
  103. continue_format:
  104.        switch(c = *format++) {
  105.       case 's':
  106.           *tp++ = c;
  107.           *tp = '\0';
  108.           dp += Sprintf(dp, tempfmt, VA_ARG(args, char *));
  109.           break;
  110.       case 'u':
  111.       case 'x':
  112.       case 'o':
  113.       case 'X':
  114. #ifdef UNSIGNEDSPECIAL
  115.           *tp++ = c;
  116.           *tp = '\0';
  117. #ifndef LONGINT
  118.           if(longflag)
  119.          dp += Sprintf(dp, tempfmt, VA_ARG(args, unsigned long));
  120.           else
  121. #endif
  122.          dp += Sprintf(dp, tempfmt, VA_ARG(args, unsigned));
  123.           break;
  124. #endif
  125.       case 'd':
  126.       case 'c':
  127.       case 'i':
  128.           *tp++ = c;
  129.           *tp = '\0';
  130. #ifndef LONGINT
  131.           if(longflag)
  132.          dp += Sprintf(dp, tempfmt, VA_ARG(args, long));
  133.           else
  134. #endif
  135.          dp += Sprintf(dp, tempfmt, VA_ARG(args, int));
  136.           break;
  137.       case 'f':
  138.       case 'e':
  139.       case 'E':
  140.       case 'g':
  141.       case 'G':
  142.           *tp++ = c;
  143.           *tp = '\0';
  144.           dp += Sprintf(dp, tempfmt, VA_ARG(args, double));
  145.           break;
  146.       case 'p':
  147.           *tp++ = c;
  148.           *tp = '\0';
  149.           dp += Sprintf(dp, tempfmt, VA_ARG(args, pointer));
  150.           break;
  151.       case '-':
  152.       case '+':
  153.       case '0':
  154.       case '1':
  155.       case '2':
  156.       case '3':
  157.       case '4':
  158.       case '5':
  159.       case '6':
  160.       case '7':
  161.       case '8':
  162.       case '9':
  163.       case '.':
  164.       case ' ':
  165.       case '#':
  166.       case 'h':
  167.           *tp++ = c;
  168.           goto continue_format;
  169.       case 'l':
  170. #ifndef LONGINT
  171.           longflag = 1;
  172.           *tp++ = c;
  173. #endif
  174.           goto continue_format;
  175.       case '*':
  176.           tp += Sprintf(tp, "%d", VA_ARG(args, int));
  177.           goto continue_format;
  178.       case 'n':
  179.           *VA_ARG(args, intp) = dp - dest;
  180.           break;
  181.       case '%':
  182.       default:
  183.           *dp++ = c;
  184.           break;
  185.        }
  186.    } else *dp++ = c;
  187.       }
  188.       *dp = '\0';
  189.       return dp - dest;
  190. }
  191.  
  192.  
  193. #ifdef __ANSI_C__
  194.   int vfprintf(FILE *dest, register const char *format, va_list args)
  195. #else
  196.   int vfprintf(dest, format, args)
  197.   FILE *dest;
  198.   register char *format;
  199.   va_list args;
  200. #endif
  201. {
  202.       register char c;
  203.       register char *tp;
  204.       register int count = 0;
  205.       char tempfmt[64];
  206. #ifndef LONGINT
  207.       int longflag;
  208. #endif
  209.  
  210.       tempfmt[0] = '%';
  211.       while(c = *format++) {
  212.    if(c=='%') {
  213.        tp = &tempfmt[1];
  214. #ifndef LONGINT
  215.        longflag = 0;
  216. #endif
  217. continue_format:
  218.        switch(c = *format++) {
  219.       case 's':
  220.           *tp++ = c;
  221.           *tp = '\0';
  222.           count += fprintf(dest, tempfmt, VA_ARG(args, char *));
  223.           break;
  224.       case 'u':
  225.       case 'x':
  226.       case 'o':
  227.       case 'X':
  228. #ifdef UNSIGNEDSPECIAL
  229.           *tp++ = c;
  230.           *tp = '\0';
  231. #ifndef LONGINT
  232.           if(longflag)
  233.          count += fprintf(dest, tempfmt, VA_ARG(args, unsigned long));
  234.           else
  235. #endif
  236.          count += fprintf(dest, tempfmt, VA_ARG(args, unsigned));
  237.           break;
  238. #endif
  239.       case 'd':
  240.       case 'c':
  241.       case 'i':
  242.           *tp++ = c;
  243.           *tp = '\0';
  244. #ifndef LONGINT
  245.           if(longflag)
  246.          count += fprintf(dest, tempfmt, VA_ARG(args, long));
  247.           else
  248. #endif
  249.          count += fprintf(dest, tempfmt, VA_ARG(args, int));
  250.           break;
  251.       case 'f':
  252.       case 'e':
  253.       case 'E':
  254.       case 'g':
  255.       case 'G':
  256.           *tp++ = c;
  257.           *tp = '\0';
  258.           count += fprintf(dest, tempfmt, VA_ARG(args, double));
  259.           break;
  260.       case 'p':
  261.           *tp++ = c;
  262.           *tp = '\0';
  263.           count += fprintf(dest, tempfmt, VA_ARG(args, pointer));
  264.           break;
  265.       case '-':
  266.       case '+':
  267.       case '0':
  268.       case '1':
  269.       case '2':
  270.       case '3':
  271.       case '4':
  272.       case '5':
  273.       case '6':
  274.       case '7':
  275.       case '8':
  276.       case '9':
  277.       case '.':
  278.       case ' ':
  279.       case '#':
  280.       case 'h':
  281.           *tp++ = c;
  282.           goto continue_format;
  283.       case 'l':
  284. #ifndef LONGINT
  285.           longflag = 1;
  286.           *tp++ = c;
  287. #endif
  288.           goto continue_format;
  289.       case '*':
  290.           tp += Sprintf(tp, "%d", VA_ARG(args, int));
  291.           goto continue_format;
  292.       case 'n':
  293.           *VA_ARG(args, intp) = count;
  294.           break;
  295.       case '%':
  296.       default:
  297.           putc(c, dest);
  298.           count++;
  299.           break;
  300.        }
  301.    } else {
  302.        putc(c, dest);
  303.        count++;
  304.    }
  305.       }
  306.       return count;
  307. }
  308.  
  309. #ifdef __ANSI_C__
  310.   int vprintf(const char *format, va_list args)
  311. #else
  312.   int vprintf(format, args)
  313.   char *format;
  314.   va_list args;
  315. #endif
  316. {
  317.       return vfprintf(stdout, format, args);
  318. }
  319. #endif  /* BSD Unix ONLY */
  320.  
  321.     /* use a VERY SIMPLE test case to test this out -- Brad Appleton */
  322. #ifdef VPRINTF_TEST
  323.  
  324. /*VARARGS1*/
  325. #ifdef __ANSI_C__
  326.   int vtest( char *fmt, ... )
  327. #else
  328.   int vtest( fmt, va_alist )
  329.   char *fmt;
  330.   va_dcl
  331. #endif
  332. {
  333.    va_list   ap;
  334.    int   rc;
  335.  
  336.    VA_START(ap, fmt);
  337.    rc = vprintf( fmt, ap );
  338.    VA_END(ap);
  339.  
  340.    return   rc;
  341. }
  342.  
  343. void main()
  344. {
  345.    printf( "its a %s %% day in the %d neighborhood for %*s\n",
  346.           "pitiful", 4, 8, "fun" );
  347.  
  348.    vtest( "its a %s %% day in the %d neighborhood for %*s\n",
  349.           "pitiful", 4, 8, "fun" );
  350. }
  351.  
  352. #endif  /* VPRINTF_TEST */
  353.