xprintf.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:29k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*
  2. ** It turns out that the printf functions in the stock MIT pthread library
  3. ** is busted.  It isn't thread safe.  If two threads try to do a printf
  4. ** of a floating point value at the same time, a core-dump might result.
  5. ** So this code is substituted.
  6. */
  7. /*
  8. ** NAME:    $Source$
  9. ** VERSION: $Revision$
  10. ** DATE:    $Date$
  11. **
  12. ** ONELINER:   A replacement for formatted printing programs.
  13. **
  14. ** COPYRIGHT:
  15. **   Copyright (c) 1990 by D. Richard Hipp.  This code is an original
  16. **   work and has been prepared without reference to any prior
  17. **   implementations of similar functions.  No part of this code is
  18. **   subject to licensing restrictions of any telephone company or
  19. **   university.
  20. **
  21. **   This copyright was released and the code placed in the public domain
  22. **   by the author, D. Richard Hipp, on October 3, 1996.
  23. **
  24. ** DESCRIPTION:
  25. **   This program is an enhanced replacement for the "printf" programs
  26. **   found in the standard library.  The following enhancements are
  27. **   supported:
  28. **
  29. **      +  Additional functions.  The standard set of "printf" functions
  30. **         includes printf, fprintf, sprintf, vprintf, vfprintf, and
  31. **         vsprintf.  This module adds the following:
  32. **
  33. **           *  snprintf -- Works like sprintf, but has an extra argument
  34. **                          which is the size of the buffer written to.
  35. **
  36. **           *  mprintf --  Similar to sprintf.  Writes output to memory
  37. **                          obtained from mem_alloc.
  38. **
  39. **           *  xprintf --  Calls a function to dispose of output.
  40. **
  41. **           *  nprintf --  No output, but returns the number of characters
  42. **                          that would have been output by printf.
  43. **
  44. **           *  A v- version (ex: vsnprintf) of every function is also
  45. **              supplied.
  46. **
  47. **      +  A few extensions to the formatting notation are supported:
  48. **
  49. **           *  The "=" flag (similar to "-") causes the output to be
  50. **              be centered in the appropriately sized field.
  51. **
  52. **           *  The %b field outputs an integer in binary notation.
  53. **
  54. **           *  The %c field now accepts a precision.  The character output
  55. **              is repeated by the number of times the precision specifies.
  56. **
  57. **           *  The %' field works like %c, but takes as its character the
  58. **              next character of the format string, instead of the next
  59. **              argument.  For example,  printf("%.78'-")  prints 78 minus
  60. **              signs, the same as  printf("%.78c",'-').
  61. **
  62. **      +  When compiled using GCC on a SPARC, this version of printf is
  63. **         faster than the library printf for SUN OS 4.1.
  64. **
  65. **      +  All functions are fully reentrant.
  66. **
  67. */
  68. /*
  69. ** Undefine COMPATIBILITY to make some slight changes in the way things
  70. ** work.  I think the changes are an improvement, but they are not
  71. ** backwards compatible.
  72. */
  73. /* #define COMPATIBILITY       / * Compatible with SUN OS 4.1 */
  74. #include <stdio.h>
  75. #include <stdarg.h>
  76. #include <ctype.h>
  77. #include <math.h>
  78. #include <stdlib.h>
  79. #include <string.h>
  80. /*
  81. ** The maximum number of digits of accuracy in a floating-point conversion.
  82. */
  83. #define MAXDIG 20
  84. /*
  85. ** Conversion types fall into various categories as defined by the
  86. ** following enumeration.
  87. */
  88. enum e_type {    /* The type of the format field */
  89.    RADIX,            /* Integer types.  %d, %x, %o, and so forth */
  90.    FLOAT,            /* Floating point.  %f */
  91.    EXP,              /* Exponentional notation. %e and %E */
  92.    GENERIC,          /* Floating or exponential, depending on exponent. %g */
  93.    SIZE,             /* Return number of characters processed so far. %n */
  94.    STRING,           /* Strings. %s */
  95.    PERCENT,          /* Percent symbol. %% */
  96.    CHAR,             /* Characters. %c */
  97.    ERROR,            /* Used to indicate no such conversion type */
  98. /* The rest are extensions, not normally found in printf() */
  99.    CHARLIT,          /* Literal characters.  %' */
  100.    SEEIT,            /* Strings with visible control characters. %S */
  101.    MEM_STRING,       /* A string which should be deleted after use. %z */
  102.    ORDINAL,          /* 1st, 2nd, 3rd and so forth */
  103. };
  104. /*
  105. ** Each builtin conversion character (ex: the 'd' in "%d") is described
  106. ** by an instance of the following structure
  107. */
  108. typedef struct s_info {   /* Information about each format field */
  109.   int  fmttype;              /* The format field code letter */
  110.   int  base;                 /* The base for radix conversion */
  111.   char *charset;             /* The character set for conversion */
  112.   int  flag_signed;          /* Is the quantity signed? */
  113.   char *prefix;              /* Prefix on non-zero values in alt format */
  114.   enum e_type type;          /* Conversion paradigm */
  115. } info;
  116. /*
  117. ** The following table is searched linearly, so it is good to put the
  118. ** most frequently used conversion types first.
  119. */
  120. static info fmtinfo[] = {
  121.   { 'd',  10,  "0123456789",       1,    0, RADIX,      },
  122.   { 's',   0,  0,                  0,    0, STRING,     }, 
  123.   { 'S',   0,  0,                  0,    0, SEEIT,      },
  124.   { 'z',   0,  0,                  0,    0, MEM_STRING, },
  125.   { 'c',   0,  0,                  0,    0, CHAR,       },
  126.   { 'o',   8,  "01234567",         0,  "0", RADIX,      },
  127.   { 'u',  10,  "0123456789",       0,    0, RADIX,      },
  128.   { 'x',  16,  "0123456789abcdef", 0, "x0", RADIX,      },
  129.   { 'X',  16,  "0123456789ABCDEF", 0, "X0", RADIX,      },
  130.   { 'r',  10,  "0123456789",       0,    0, ORDINAL,    },
  131.   { 'f',   0,  0,                  1,    0, FLOAT,      },
  132.   { 'e',   0,  "e",                1,    0, EXP,        },
  133.   { 'E',   0,  "E",                1,    0, EXP,        },
  134.   { 'g',   0,  "e",                1,    0, GENERIC,    },
  135.   { 'G',   0,  "E",                1,    0, GENERIC,    },
  136.   { 'i',  10,  "0123456789",       1,    0, RADIX,      },
  137.   { 'n',   0,  0,                  0,    0, SIZE,       },
  138.   { 'S',   0,  0,                  0,    0, SEEIT,      },
  139.   { '%',   0,  0,                  0,    0, PERCENT,    },
  140.   { 'b',   2,  "01",               0, "b0", RADIX,      }, /* Binary notation */
  141.   { 'p',  10,  "0123456789",       0,    0, RADIX,      }, /* Pointers */
  142.   { ''',  0,  0,                  0,    0, CHARLIT,    }, /* Literal char */
  143. };
  144. #define NINFO  (sizeof(fmtinfo)/sizeof(info))  /* Size of the fmtinfo table */
  145. /*
  146. ** If NOFLOATINGPOINT is defined, then none of the floating point
  147. ** conversions will work.
  148. */
  149. #ifndef NOFLOATINGPOINT
  150. /*
  151. ** "*val" is a double such that 0.1 <= *val < 10.0
  152. ** Return the ascii code for the leading digit of *val, then
  153. ** multiply "*val" by 10.0 to renormalize.
  154. **
  155. ** Example:
  156. **     input:     *val = 3.14159
  157. **     output:    *val = 1.4159    function return = '3'
  158. **
  159. ** The counter *cnt is incremented each time.  After counter exceeds
  160. ** 16 (the number of significant digits in a 64-bit float) '0' is
  161. ** always returned.
  162. */
  163. static int getdigit(long double *val, int *cnt){
  164.   int digit;
  165.   long double d;
  166.   if( (*cnt)++ >= MAXDIG ) return '0';
  167.   digit = (int)*val;
  168.   d = digit;
  169.   digit += '0';
  170.   *val = (*val - d)*10.0;
  171.   return digit;
  172. }
  173. #endif
  174. /*
  175. ** Setting the size of the BUFFER involves trade-offs.  No %d or %f
  176. ** conversion can have more than BUFSIZE characters.  If the field
  177. ** width is larger than BUFSIZE, it is silently shortened.  On the
  178. ** other hand, this routine consumes more stack space with larger
  179. ** BUFSIZEs.  If you have some threads for which you want to minimize
  180. ** stack space, you should keep BUFSIZE small.
  181. */
  182. #define BUFSIZE 100  /* Size of the output buffer */
  183. /*
  184. ** The root program.  All variations call this core.
  185. **
  186. ** INPUTS:
  187. **   func   This is a pointer to a function taking three arguments
  188. **            1. A pointer to the list of characters to be output
  189. **               (Note, this list is NOT null terminated.)
  190. **            2. An integer number of characters to be output.
  191. **               (Note: This number might be zero.)
  192. **            3. A pointer to anything.  Same as the "arg" parameter.
  193. **
  194. **   arg    This is the pointer to anything which will be passed as the
  195. **          third argument to "func".  Use it for whatever you like.
  196. **
  197. **   fmt    This is the format string, as in the usual print.
  198. **
  199. **   ap     This is a pointer to a list of arguments.  Same as in
  200. **          vfprint.
  201. **
  202. ** OUTPUTS:
  203. **          The return value is the total number of characters sent to
  204. **          the function "func".  Returns -1 on a error.
  205. **
  206. ** Note that the order in which automatic variables are declared below
  207. ** seems to make a big difference in determining how fast this beast
  208. ** will run.
  209. */
  210. static int vxprintf(func,arg,format,ap)
  211.   void (*func)(char*,int,void*);
  212.   void *arg;
  213.   const char *format;
  214.   va_list ap;
  215. {
  216.   register const char *fmt; /* The format string. */
  217.   register int c;           /* Next character in the format string */
  218.   register char *bufpt;     /* Pointer to the conversion buffer */
  219.   register int  precision;  /* Precision of the current field */
  220.   register int  length;     /* Length of the field */
  221.   register int  idx;        /* A general purpose loop counter */
  222.   int count;                /* Total number of characters output */
  223.   int width;                /* Width of the current field */
  224.   int flag_leftjustify;     /* True if "-" flag is present */
  225.   int flag_plussign;        /* True if "+" flag is present */
  226.   int flag_blanksign;       /* True if " " flag is present */
  227.   int flag_alternateform;   /* True if "#" flag is present */
  228.   int flag_zeropad;         /* True if field width constant starts with zero */
  229.   int flag_long;            /* True if "l" flag is present */
  230.   int flag_center;          /* True if "=" flag is present */
  231.   unsigned long longvalue;  /* Value for integer types */
  232.   long double realvalue;    /* Value for real types */
  233.   info *infop;              /* Pointer to the appropriate info structure */
  234.   char buf[BUFSIZE];        /* Conversion buffer */
  235.   char prefix;              /* Prefix character.  "+" or "-" or " " or ''. */
  236.   int  errorflag = 0;       /* True if an error is encountered */
  237.   enum e_type xtype;        /* Conversion paradigm */
  238.   char *zMem;               /* String to be freed */
  239.   static char spaces[] = 
  240.      "                                                    ";
  241. #define SPACESIZE (sizeof(spaces)-1)
  242. #ifndef NOFLOATINGPOINT
  243.   int  exp;                 /* exponent of real numbers */
  244.   long double rounder;      /* Used for rounding floating point values */
  245.   int flag_dp;              /* True if decimal point should be shown */
  246.   int flag_rtz;             /* True if trailing zeros should be removed */
  247.   int flag_exp;             /* True to force display of the exponent */
  248.   int nsd;                  /* Number of significant digits returned */
  249. #endif
  250.   fmt = format;                     /* Put in a register for speed */
  251.   count = length = 0;
  252.   bufpt = 0;
  253.   for(; (c=(*fmt))!=0; ++fmt){
  254.     if( c!='%' ){
  255.       register int amt;
  256.       bufpt = (char *)fmt;
  257.       amt = 1;
  258.       while( (c=(*++fmt))!='%' && c!=0 ) amt++;
  259.       (*func)(bufpt,amt,arg);
  260.       count += amt;
  261.       if( c==0 ) break;
  262.     }
  263.     if( (c=(*++fmt))==0 ){
  264.       errorflag = 1;
  265.       (*func)("%",1,arg);
  266.       count++;
  267.       break;
  268.     }
  269.     /* Find out what flags are present */
  270.     flag_leftjustify = flag_plussign = flag_blanksign = 
  271.      flag_alternateform = flag_zeropad = flag_center = 0;
  272.     do{
  273.       switch( c ){
  274.         case '-':   flag_leftjustify = 1;     c = 0;   break;
  275.         case '+':   flag_plussign = 1;        c = 0;   break;
  276.         case ' ':   flag_blanksign = 1;       c = 0;   break;
  277.         case '#':   flag_alternateform = 1;   c = 0;   break;
  278.         case '0':   flag_zeropad = 1;         c = 0;   break;
  279.         case '=':   flag_center = 1;          c = 0;   break;
  280.         default:                                       break;
  281.       }
  282.     }while( c==0 && (c=(*++fmt))!=0 );
  283.     if( flag_center ) flag_leftjustify = 0;
  284.     /* Get the field width */
  285.     width = 0;
  286.     if( c=='*' ){
  287.       width = va_arg(ap,int);
  288.       if( width<0 ){
  289.         flag_leftjustify = 1;
  290.         width = -width;
  291.       }
  292.       c = *++fmt;
  293.     }else{
  294.       while( isdigit(c) ){
  295.         width = width*10 + c - '0';
  296.         c = *++fmt;
  297.       }
  298.     }
  299.     if( width > BUFSIZE-10 ){
  300.       width = BUFSIZE-10;
  301.     }
  302.     /* Get the precision */
  303.     if( c=='.' ){
  304.       precision = 0;
  305.       c = *++fmt;
  306.       if( c=='*' ){
  307.         precision = va_arg(ap,int);
  308. #ifndef COMPATIBILITY
  309.         /* This is sensible, but SUN OS 4.1 doesn't do it. */
  310.         if( precision<0 ) precision = -precision;
  311. #endif
  312.         c = *++fmt;
  313.       }else{
  314.         while( isdigit(c) ){
  315.           precision = precision*10 + c - '0';
  316.           c = *++fmt;
  317.         }
  318.       }
  319.       /* Limit the precision to prevent overflowing buf[] during conversion */
  320.       if( precision>BUFSIZE-40 ) precision = BUFSIZE-40;
  321.     }else{
  322.       precision = -1;
  323.     }
  324.     /* Get the conversion type modifier */
  325.     if( c=='l' ){
  326.       flag_long = 1;
  327.       c = *++fmt;
  328.     }else{
  329.       flag_long = 0;
  330.     }
  331.     /* Fetch the info entry for the field */
  332.     infop = 0;
  333.     for(idx=0; idx<NINFO; idx++){
  334.       if( c==fmtinfo[idx].fmttype ){
  335.         infop = &fmtinfo[idx];
  336.         break;
  337.       }
  338.     }
  339.     /* No info entry found.  It must be an error. */
  340.     if( infop==0 ){
  341.       xtype = ERROR;
  342.     }else{
  343.       xtype = infop->type;
  344.     }
  345.     /*
  346.     ** At this point, variables are initialized as follows:
  347.     **
  348.     **   flag_alternateform          TRUE if a '#' is present.
  349.     **   flag_plussign               TRUE if a '+' is present.
  350.     **   flag_leftjustify            TRUE if a '-' is present or if the
  351.     **                               field width was negative.
  352.     **   flag_zeropad                TRUE if the width began with 0.
  353.     **   flag_long                   TRUE if the letter 'l' (ell) prefixed
  354.     **                               the conversion character.
  355.     **   flag_blanksign              TRUE if a ' ' is present.
  356.     **   width                       The specified field width.  This is
  357.     **                               always non-negative.  Zero is the default.
  358.     **   precision                   The specified precision.  The default
  359.     **                               is -1.
  360.     **   xtype                       The class of the conversion.
  361.     **   infop                       Pointer to the appropriate info struct.
  362.     */
  363.     switch( xtype ){
  364.       case ORDINAL:
  365.       case RADIX:
  366.         if( flag_long )  longvalue = va_arg(ap,long);
  367. else             longvalue = va_arg(ap,int);
  368. #ifdef COMPATIBILITY
  369.         /* For the format %#x, the value zero is printed "0" not "0x0".
  370.         ** I think this is stupid. */
  371.         if( longvalue==0 ) flag_alternateform = 0;
  372. #else
  373.         /* More sensible: turn off the prefix for octal (to prevent "00"),
  374.         ** but leave the prefix for hex. */
  375.         if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
  376. #endif
  377.         if( infop->flag_signed ){
  378.           if( *(long*)&longvalue<0 ){
  379.             longvalue = -*(long*)&longvalue;
  380.             prefix = '-';
  381.           }else if( flag_plussign )  prefix = '+';
  382.           else if( flag_blanksign )  prefix = ' ';
  383.           else                       prefix = 0;
  384.         }else                        prefix = 0;
  385.         if( flag_zeropad && precision<width-(prefix!=0) ){
  386.           precision = width-(prefix!=0);
  387. }
  388.         bufpt = &buf[BUFSIZE];
  389.         if( xtype==ORDINAL ){
  390.           long a,b;
  391.           a = longvalue%10;
  392.           b = longvalue%100;
  393.           bufpt -= 2;
  394.           if( a==0 || a>3 || (b>10 && b<14) ){
  395.             bufpt[0] = 't';
  396.             bufpt[1] = 'h';
  397.           }else if( a==1 ){
  398.             bufpt[0] = 's';
  399.             bufpt[1] = 't';
  400.           }else if( a==2 ){
  401.             bufpt[0] = 'n';
  402.             bufpt[1] = 'd';
  403.           }else if( a==3 ){
  404.             bufpt[0] = 'r';
  405.             bufpt[1] = 'd';
  406.           }
  407.         }
  408.         {
  409.           register char *cset;      /* Use registers for speed */
  410.           register int base;
  411.           cset = infop->charset;
  412.           base = infop->base;
  413.           do{                                           /* Convert to ascii */
  414.             *(--bufpt) = cset[longvalue%base];
  415.             longvalue = longvalue/base;
  416.           }while( longvalue>0 );
  417. }
  418.         length = (int)(&buf[BUFSIZE]-bufpt);
  419.         for(idx=precision-length; idx>0; idx--){
  420.           *(--bufpt) = '0';                             /* Zero pad */
  421. }
  422.         if( prefix ) *(--bufpt) = prefix;               /* Add sign */
  423.         if( flag_alternateform && infop->prefix ){      /* Add "0" or "0x" */
  424.           char *pre, x;
  425.           pre = infop->prefix;
  426.           if( *bufpt!=pre[0] ){
  427.             for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
  428.   }
  429.         }
  430.         length = (int)(&buf[BUFSIZE]-bufpt);
  431.         break;
  432.       case FLOAT:
  433.       case EXP:
  434.       case GENERIC:
  435.         realvalue = va_arg(ap,double);
  436. #ifndef NOFLOATINGPOINT
  437.         if( precision<0 ) precision = 6;         /* Set default precision */
  438.         if( precision>BUFSIZE-10 ) precision = BUFSIZE-10;
  439.         if( realvalue<0.0 ){
  440.           realvalue = -realvalue;
  441.           prefix = '-';
  442. }else{
  443.           if( flag_plussign )          prefix = '+';
  444.           else if( flag_blanksign )    prefix = ' ';
  445.           else                         prefix = 0;
  446. }
  447.         if( infop->type==GENERIC && precision>0 ) precision--;
  448.         rounder = 0.0;
  449. #ifdef COMPATIBILITY
  450.         /* Rounding works like BSD when the constant 0.4999 is used.  Wierd! */
  451.         for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
  452. #else
  453.         /* It makes more sense to use 0.5 */
  454.         if( precision>MAXDIG-1 ) idx = MAXDIG-1;
  455.         else                     idx = precision;
  456.         for(rounder=0.5; idx>0; idx--, rounder*=0.1);
  457. #endif
  458.         if( infop->type==FLOAT ) realvalue += rounder;
  459.         /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
  460.         exp = 0;
  461.         if( realvalue>0.0 ){
  462.           int k = 0;
  463.           while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; }
  464.           while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; }
  465.           while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; }
  466.           while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; }
  467.           if( k>=100 ){
  468.             bufpt = "NaN";
  469.             length = 3;
  470.             break;
  471.           }
  472. }
  473.         bufpt = buf;
  474.         /*
  475.         ** If the field type is GENERIC, then convert to either EXP
  476.         ** or FLOAT, as appropriate.
  477.         */
  478.         flag_exp = xtype==EXP;
  479.         if( xtype!=FLOAT ){
  480.           realvalue += rounder;
  481.           if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
  482.         }
  483.         if( xtype==GENERIC ){
  484.           flag_rtz = !flag_alternateform;
  485.           if( exp<-4 || exp>precision ){
  486.             xtype = EXP;
  487.           }else{
  488.             precision = precision - exp;
  489.             xtype = FLOAT;
  490.           }
  491. }else{
  492.           flag_rtz = 0;
  493. }
  494.         /*
  495.         ** The "exp+precision" test causes output to be of type EXP if
  496.         ** the precision is too large to fit in buf[].
  497.         */
  498.         nsd = 0;
  499.         if( xtype==FLOAT && exp+precision<BUFSIZE-30 ){
  500.           flag_dp = (precision>0 || flag_alternateform);
  501.           if( prefix ) *(bufpt++) = prefix;         /* Sign */
  502.           if( exp<0 )  *(bufpt++) = '0';            /* Digits before "." */
  503.           else for(; exp>=0; exp--) *(bufpt++) = getdigit(&realvalue,&nsd);
  504.           if( flag_dp ) *(bufpt++) = '.';           /* The decimal point */
  505.           for(exp++; exp<0 && precision>0; precision--, exp++){
  506.             *(bufpt++) = '0';
  507.           }
  508.           while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd);
  509.           *(bufpt--) = 0;                           /* Null terminate */
  510.           if( flag_rtz && flag_dp ){     /* Remove trailing zeros and "." */
  511.             while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
  512.             if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
  513.           }
  514.           bufpt++;                            /* point to next free slot */
  515. }else{    /* EXP or GENERIC */
  516.           flag_dp = (precision>0 || flag_alternateform);
  517.           if( prefix ) *(bufpt++) = prefix;   /* Sign */
  518.           *(bufpt++) = getdigit(&realvalue,&nsd);  /* First digit */
  519.           if( flag_dp ) *(bufpt++) = '.';     /* Decimal point */
  520.           while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd);
  521.           bufpt--;                            /* point to last digit */
  522.           if( flag_rtz && flag_dp ){          /* Remove tail zeros */
  523.             while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
  524.             if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
  525.           }
  526.           bufpt++;                            /* point to next free slot */
  527.           if( exp || flag_exp ){
  528.             *(bufpt++) = infop->charset[0];
  529.             if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
  530.             else       { *(bufpt++) = '+'; }
  531.             if( exp>=100 ){
  532.               *(bufpt++) = (exp/100)+'0';                /* 100's digit */
  533.               exp %= 100;
  534.        }
  535.             *(bufpt++) = exp/10+'0';                     /* 10's digit */
  536.             *(bufpt++) = exp%10+'0';                     /* 1's digit */
  537.           }
  538. }
  539.         /* The converted number is in buf[] and zero terminated. Output it.
  540.         ** Note that the number is in the usual order, not reversed as with
  541.         ** integer conversions. */
  542.         length = (int)(bufpt-buf);
  543.         bufpt = buf;
  544.         /* Special case:  Add leading zeros if the flag_zeropad flag is
  545.         ** set and we are not left justified */
  546.         if( flag_zeropad && !flag_leftjustify && length < width){
  547.           int i;
  548.           int nPad = width - length;
  549.           for(i=width; i>=nPad; i--){
  550.             bufpt[i] = bufpt[i-nPad];
  551.           }
  552.           i = prefix!=0;
  553.           while( nPad-- ) bufpt[i++] = '0';
  554.           length = width;
  555.         }
  556. #endif
  557.         break;
  558.       case SIZE:
  559.         *(va_arg(ap,int*)) = count;
  560.         length = width = 0;
  561.         break;
  562.       case PERCENT:
  563.         buf[0] = '%';
  564.         bufpt = buf;
  565.         length = 1;
  566.         break;
  567.       case CHARLIT:
  568.       case CHAR:
  569.         c = buf[0] = (xtype==CHAR ? va_arg(ap,int) : *++fmt);
  570.         if( precision>=0 ){
  571.           for(idx=1; idx<precision; idx++) buf[idx] = c;
  572.           length = precision;
  573. }else{
  574.           length =1;
  575. }
  576.         bufpt = buf;
  577.         break;
  578.       case STRING:
  579.       case MEM_STRING:
  580.         zMem = bufpt = va_arg(ap,char*);
  581.         if( bufpt==0 ) bufpt = "(null)";
  582.         length = strlen(bufpt);
  583.         if( precision>=0 && precision<length ) length = precision;
  584.         break;
  585.       case SEEIT:
  586.         {
  587.           int i;
  588.           int c;
  589.           char *arg = va_arg(ap,char*);
  590.           for(i=0; i<BUFSIZE-1 && (c = *arg++)!=0; i++){
  591.             if( c<0x20 || c>=0x7f ){
  592.               buf[i++] = '^';
  593.               buf[i] = (c&0x1f)+0x40;
  594.             }else{
  595.               buf[i] = c;
  596.             }
  597.           }
  598.           bufpt = buf;
  599.           length = i;
  600.           if( precision>=0 && precision<length ) length = precision;
  601.         }
  602.         break;
  603.       case ERROR:
  604.         buf[0] = '%';
  605.         buf[1] = c;
  606.         errorflag = 0;
  607.         idx = 1+(c!=0);
  608.         (*func)("%",idx,arg);
  609.         count += idx;
  610.         if( c==0 ) fmt--;
  611.         break;
  612.     }/* End switch over the format type */
  613.     /*
  614.     ** The text of the conversion is pointed to by "bufpt" and is
  615.     ** "length" characters long.  The field width is "width".  Do
  616.     ** the output.
  617.     */
  618.     if( !flag_leftjustify ){
  619.       register int nspace;
  620.       nspace = width-length;
  621.       if( nspace>0 ){
  622.         if( flag_center ){
  623.           nspace = nspace/2;
  624.           width -= nspace;
  625.           flag_leftjustify = 1;
  626. }
  627.         count += nspace;
  628.         while( nspace>=SPACESIZE ){
  629.           (*func)(spaces,SPACESIZE,arg);
  630.           nspace -= SPACESIZE;
  631.         }
  632.         if( nspace>0 ) (*func)(spaces,nspace,arg);
  633.       }
  634.     }
  635.     if( length>0 ){
  636.       (*func)(bufpt,length,arg);
  637.       count += length;
  638.     }
  639.     if( xtype==MEM_STRING && zMem ){
  640.       free(zMem);
  641.     }
  642.     if( flag_leftjustify ){
  643.       register int nspace;
  644.       nspace = width-length;
  645.       if( nspace>0 ){
  646.         count += nspace;
  647.         while( nspace>=SPACESIZE ){
  648.           (*func)(spaces,SPACESIZE,arg);
  649.           nspace -= SPACESIZE;
  650.         }
  651.         if( nspace>0 ) (*func)(spaces,nspace,arg);
  652.       }
  653.     }
  654.   }/* End for loop over the format string */
  655.   return errorflag ? -1 : count;
  656. } /* End of function */
  657. /*
  658. ** This non-standard function is still occasionally useful....
  659. */
  660. int xprintf(
  661.   void (*func)(char*,int,void*),
  662.   void *arg,
  663.   const char *format,
  664.   ...
  665. ){
  666.   va_list ap;
  667.   va_start(ap,format);
  668.   return vxprintf(func,arg,format,ap);
  669. }
  670. /*
  671. ** Now for string-print, also as found in any standard library.
  672. ** Add to this the snprint function which stops added characters
  673. ** to the string at a given length.
  674. **
  675. ** Note that snprint returns the length of the string as it would
  676. ** be if there were no limit on the output.
  677. */
  678. struct s_strargument {    /* Describes the string being written to */
  679.   char *next;                   /* Next free slot in the string */
  680.   char *last;                   /* Last available slot in the string */
  681. };
  682. static void sout(txt,amt,arg)
  683.   char *txt;
  684.   int amt;
  685.   void *arg;
  686. {
  687.   register char *head;
  688.   register const char *t;  
  689.   register int a;
  690.   register char *tail;
  691.   a = amt;
  692.   t = txt;
  693.   head = ((struct s_strargument*)arg)->next;
  694.   tail = ((struct s_strargument*)arg)->last;
  695.   if( tail ){
  696.     while( a-- >0 && head<tail ) *(head++) = *(t++);
  697.   }else{
  698.     while( a-- >0 ) *(head++) = *(t++);
  699.   }
  700.   *head = 0;
  701.   ((struct s_strargument*)arg)->next = head;
  702. }
  703. int sprintf(char *buf, const char *fmt, ...){
  704.   int rc;
  705.   va_list ap;
  706.   struct s_strargument arg;
  707.   va_start(ap,fmt);
  708.   arg.next = buf;
  709.   arg.last = 0;
  710.   *arg.next = 0;
  711.   rc = vxprintf(sout,&arg,fmt,ap);
  712.   va_end(ap);
  713. }
  714. int vsprintf(char *buf,const char *fmt,va_list ap){
  715.   struct s_strargument arg;
  716.   arg.next = buf;
  717.   arg.last = 0;
  718.   *buf = 0;
  719.   return vxprintf(sout,&arg,fmt,ap);
  720. }
  721. int snprintf(char *buf, size_t n, const char *fmt, ...){
  722.   int rc;
  723.   va_list ap;
  724.   struct s_strargument arg;
  725.   va_start(ap,fmt);
  726.   arg.next = buf;
  727.   arg.last = &arg.next[n-1];
  728.   *arg.next = 0;
  729.   rc = vxprintf(sout,&arg,fmt,ap);
  730.   va_end(ap);
  731. }  
  732. int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap){
  733.   struct s_strargument arg;
  734.   arg.next = buf;
  735.   arg.last = &buf[n-1];
  736.   *buf = 0;
  737.   return vxprintf(sout,&arg,fmt,ap);
  738. }
  739. /*
  740. ** The following section of code handles the mprintf routine, that
  741. ** writes to memory obtained from malloc().
  742. */
  743. /* This structure is used to store state information about the
  744. ** write in progress
  745. */
  746. struct sgMprintf {
  747.   char *zBase;     /* A base allocation */
  748.   char *zText;     /* The string collected so far */
  749.   int  nChar;      /* Length of the string so far */
  750.   int  nAlloc;     /* Amount of space allocated in zText */
  751. };
  752. /* The xprintf callback function. */
  753. static void mout(zNewText,nNewChar,arg)
  754.   char *zNewText;
  755.   int nNewChar;
  756.   void *arg;
  757. {
  758.   struct sgMprintf *pM = (struct sgMprintf*)arg;
  759.   if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
  760.     pM->nAlloc = pM->nChar + nNewChar*2 + 1;
  761.     if( pM->zText==pM->zBase ){
  762.       pM->zText = malloc(pM->nAlloc);
  763.       if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar);
  764.     }else{
  765.       pM->zText = realloc(pM->zText, pM->nAlloc);
  766.     }
  767.   }
  768.   if( pM->zText ){
  769.     memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
  770.     pM->nChar += nNewChar;
  771.     pM->zText[pM->nChar] = 0;
  772.   }
  773. }
  774. /*
  775. ** mprintf() works like printf(), but allocations memory to hold the
  776. ** resulting string and returns a pointer to the allocated memory.
  777. **
  778. ** We changed the name to TclMPrint() to conform with the Tcl private
  779. ** routine naming conventions.
  780. */
  781. char *mprintf(const char *zFormat, ...){
  782.   va_list ap;
  783.   struct sgMprintf sMprintf;
  784.   char *zNew;
  785.   char zBuf[200];
  786.   va_start(ap,zFormat);
  787.   sMprintf.nChar = 0;
  788.   sMprintf.nAlloc = sizeof(zBuf);
  789.   sMprintf.zText = zBuf;
  790.   sMprintf.zBase = zBuf;
  791.   vxprintf(mout,&sMprintf,zFormat,ap);
  792.   va_end(ap);
  793.   if( sMprintf.zText==sMprintf.zBase ){
  794.     zNew = malloc( sMprintf.nChar+1 );
  795.     if( zNew ) strcpy(zNew,zBuf);
  796.   }else{
  797.     zNew = realloc(sMprintf.zText,sMprintf.nChar+1);
  798.   }
  799.   return zNew;
  800. }
  801. /* This is the varargs version of mprintf.  
  802. **
  803. ** The name is changed to TclVMPrintf() to conform with Tcl naming
  804. ** conventions.
  805. */
  806. char *vmprintf(const char *zFormat,va_list ap){
  807.   struct sgMprintf sMprintf;
  808.   char zBuf[200];
  809.   sMprintf.nChar = 0;
  810.   sMprintf.zText = zBuf;
  811.   sMprintf.nAlloc = sizeof(zBuf);
  812.   sMprintf.zBase = zBuf;
  813.   vxprintf(mout,&sMprintf,zFormat,ap);
  814.   if( sMprintf.zText==sMprintf.zBase ){
  815.     sMprintf.zText = malloc( strlen(zBuf)+1 );
  816.     if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf);
  817.   }else{
  818.     sMprintf.zText = realloc(sMprintf.zText,sMprintf.nChar+1);
  819.   }
  820.   return sMprintf.zText;
  821. }
  822. /*
  823. ** The following section of code handles the standard fprintf routines
  824. ** for pthreads.
  825. */
  826. /* The xprintf callback function. */
  827. static void fout(zNewText,nNewChar,arg)
  828.   char *zNewText;
  829.   int nNewChar;
  830.   void *arg;
  831. {
  832.   fwrite(zNewText,1,nNewChar,(FILE*)arg);
  833. }
  834. /* The public interface routines */
  835. int fprintf(FILE *pOut, const char *zFormat, ...){
  836.   va_list ap;
  837.   int retc;
  838.   va_start(ap,zFormat);  
  839.   retc = vxprintf(fout,pOut,zFormat,ap);
  840.   va_end(ap);
  841.   return retc;
  842. }
  843. int vfprintf(FILE *pOut, const char *zFormat, va_list ap){
  844.   return vxprintf(fout,pOut,zFormat,ap);
  845. }
  846. int printf(const char *zFormat, ...){
  847.   va_list ap;
  848.   int retc;
  849.   va_start(ap,zFormat);
  850.   retc = vxprintf(fout,stdout,zFormat,ap);
  851.   va_end(ap);
  852.   return retc;
  853. }
  854. int vprintf(const char *zFormat, va_list ap){
  855.   return vxprintf(fout,stdout,zFormat,ap);
  856. }