00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 #include <libxode.h>
00057 
00058 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
00059 
00060 #include <stdio.h>
00061 #include <ctype.h>
00062 #include <sys/types.h>
00063 #include <stdarg.h>
00064 #include <string.h>
00065 #include <stdlib.h>
00066 #include <math.h>
00067 
00068 
00069 #ifdef HAVE_GCVT
00070 
00071 #define ap_ecvt ecvt
00072 #define ap_fcvt fcvt
00073 #define ap_gcvt gcvt
00074 
00075 #else
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 
00088 
00089 #define NDIG    80
00090 
00091 static char *
00092 ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag)
00093 {
00094     register int r2;
00095     double fi, fj;
00096     register char *p, *p1;
00097     static char buf[NDIG];
00098 
00099     if (ndigits >= NDIG - 1)
00100         ndigits = NDIG - 2;
00101     r2 = 0;
00102     *sign = 0;
00103     p = &buf[0];
00104     if (arg < 0) {
00105         *sign = 1;
00106         arg = -arg;
00107     }
00108     arg = modf(arg, &fi);
00109     p1 = &buf[NDIG];
00110     
00111 
00112 
00113     if (fi != 0) {
00114         p1 = &buf[NDIG];
00115         while (fi != 0) {
00116             fj = modf(fi / 10, &fi);
00117             *--p1 = (int) ((fj + .03) * 10) + '0';
00118             r2++;
00119         }
00120         while (p1 < &buf[NDIG])
00121             *p++ = *p1++;
00122     } else if (arg > 0) {
00123         while ((fj = arg * 10) < 1) {
00124             arg = fj;
00125             r2--;
00126         }
00127     }
00128     p1 = &buf[ndigits];
00129     if (eflag == 0)
00130         p1 += r2;
00131     *decpt = r2;
00132     if (p1 < &buf[0]) {
00133         buf[0] = '\0';
00134         return (buf);
00135     }
00136     while (p <= p1 && p < &buf[NDIG]) {
00137         arg *= 10;
00138         arg = modf(arg, &fj);
00139         *p++ = (int) fj + '0';
00140     }
00141     if (p1 >= &buf[NDIG]) {
00142         buf[NDIG - 1] = '\0';
00143         return (buf);
00144     }
00145     p = p1;
00146     *p1 += 5;
00147     while (*p1 > '9') {
00148         *p1 = '0';
00149         if (p1 > buf)
00150             ++ * --p1;
00151         else {
00152             *p1 = '1';
00153             (*decpt)++;
00154             if (eflag == 0) {
00155                 if (p > buf)
00156                     *p = '0';
00157                 p++;
00158             }
00159         }
00160     }
00161     *p = '\0';
00162     return (buf);
00163 }
00164 
00165 static char *
00166 ap_ecvt(double arg, int ndigits, int *decpt, int *sign)
00167 {
00168     return (ap_cvt(arg, ndigits, decpt, sign, 1));
00169 }
00170 
00171 static char *
00172 ap_fcvt(double arg, int ndigits, int *decpt, int *sign)
00173 {
00174     return (ap_cvt(arg, ndigits, decpt, sign, 0));
00175 }
00176 
00177 
00178 
00179 
00180 
00181 
00182 static char *
00183 ap_gcvt(double number, int ndigit, char *buf)
00184 {
00185     int sign, decpt;
00186     register char *p1, *p2;
00187     int i;
00188 
00189     p1 = ap_ecvt(number, ndigit, &decpt, &sign);
00190     p2 = buf;
00191     if (sign)
00192         *p2++ = '-';
00193     for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
00194         ndigit--;
00195     if ((decpt >= 0 && decpt - ndigit > 4)
00196             || (decpt < 0 && decpt < -3)) {     
00197         decpt--;
00198         *p2++ = *p1++;
00199         *p2++ = '.';
00200         for (i = 1; i < ndigit; i++)
00201             *p2++ = *p1++;
00202         *p2++ = 'e';
00203         if (decpt < 0) {
00204             decpt = -decpt;
00205             *p2++ = '-';
00206         } else
00207             *p2++ = '+';
00208         if (decpt / 100 > 0)
00209             *p2++ = decpt / 100 + '0';
00210         if (decpt / 10 > 0)
00211             *p2++ = (decpt % 100) / 10 + '0';
00212         *p2++ = decpt % 10 + '0';
00213     } else {
00214         if (decpt <= 0) {
00215             if (*p1 != '0')
00216                 *p2++ = '.';
00217             while (decpt < 0) {
00218                 decpt++;
00219                 *p2++ = '0';
00220             }
00221         }
00222         for (i = 1; i <= ndigit; i++) {
00223             *p2++ = *p1++;
00224             if (i == decpt)
00225                 *p2++ = '.';
00226         }
00227         if (ndigit < decpt) {
00228             while (ndigit++ < decpt)
00229                 *p2++ = '0';
00230             *p2++ = '.';
00231         }
00232     }
00233     if (p2[-1] == '.')
00234         p2--;
00235     *p2 = '\0';
00236     return (buf);
00237 }
00238 
00239 #endif                          
00240 
00241 typedef enum {
00242     NO = 0, YES = 1
00243 } boolean_e;
00244 
00245 #define FALSE           0
00246 #define TRUE            1
00247 #define NUL         '\0'
00248 #define INT_NULL        ((int *)0)
00249 #define WIDE_INT        long
00250 
00251 typedef WIDE_INT wide_int;
00252 typedef unsigned WIDE_INT u_wide_int;
00253 typedef int bool_int;
00254 
00255 #define S_NULL          "(null)"
00256 #define S_NULL_LEN      6
00257 
00258 #define FLOAT_DIGITS        6
00259 #define EXPONENT_LENGTH     10
00260 
00261 
00262 
00263 
00264 
00265 
00266 #define NUM_BUF_SIZE        512
00267 
00268 
00269 
00270 
00271 
00272 struct buf_area {
00273     char *buf_end;
00274     char *nextb;                
00275 };
00276 
00277 typedef struct buf_area buffy;
00278 
00279 
00280 
00281 
00282 
00283 
00284 
00285 
00286 
00287 
00288 
00289 #define INS_CHAR( c, sp, bep, cc )  \
00290         {               \
00291         if ( sp < bep )     \
00292         {           \
00293             *sp++ = c ;     \
00294             cc++ ;      \
00295         }           \
00296         }
00297 
00298 #define NUM( c )            ( c - '0' )
00299 
00300 #define STR_TO_DEC( str, num )      \
00301     num = NUM( *str++ ) ;       \
00302     while ( isdigit((int)*str ) )       \
00303     {                   \
00304     num *= 10 ;         \
00305     num += NUM( *str++ ) ;      \
00306     }
00307 
00308 
00309 
00310 
00311 
00312 
00313 
00314 #define FIX_PRECISION( adjust, precision, s, s_len )    \
00315     if ( adjust )                   \
00316     while ( s_len < precision )         \
00317     {                       \
00318         *--s = '0' ;                \
00319         s_len++ ;                   \
00320     }
00321 
00322 
00323 
00324 
00325 
00326 #define PAD( width, len, ch )   do      \
00327     {                   \
00328         INS_CHAR( ch, sp, bep, cc ) ;   \
00329         width-- ;               \
00330     }                   \
00331     while ( width > len )
00332 
00333 
00334 
00335 
00336 
00337 
00338 #define PREFIX( str, length, ch )    *--str = ch ; length++ ; has_prefix = YES
00339 
00340 
00341 
00342 
00343 
00344 
00345 
00346 
00347 
00348 
00349 
00350 
00351 
00352 
00353 static char *
00354 conv_10(register wide_int num, register bool_int is_unsigned,
00355         register bool_int * is_negative, char *buf_end, register int *len)
00356 {
00357     register char *p = buf_end;
00358     register u_wide_int magnitude;
00359 
00360     if (is_unsigned) {
00361         magnitude = (u_wide_int) num;
00362         *is_negative = FALSE;
00363     } else {
00364         *is_negative = (num < 0);
00365 
00366         
00367 
00368 
00369 
00370 
00371 
00372 
00373 
00374 
00375         if (*is_negative) {
00376             wide_int t = num + 1;
00377 
00378             magnitude = ((u_wide_int) - t) + 1;
00379         } else
00380             magnitude = (u_wide_int) num;
00381     }
00382 
00383     
00384 
00385 
00386     do {
00387         register u_wide_int new_magnitude = magnitude / 10;
00388 
00389         *--p = magnitude - new_magnitude * 10 + '0';
00390         magnitude = new_magnitude;
00391     }
00392     while (magnitude);
00393 
00394     *len = buf_end - p;
00395     return (p);
00396 }
00397 
00398 
00399 
00400 
00401 
00402 
00403 
00404 
00405 
00406 static char *
00407 conv_fp(register char format, register double num,
00408         boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
00409 {
00410     register char *s = buf;
00411     register char *p;
00412     int decimal_point;
00413 
00414     if (format == 'f')
00415         p = ap_fcvt(num, precision, &decimal_point, is_negative);
00416     else                        
00417         p = ap_ecvt(num, precision + 1, &decimal_point, is_negative);
00418 
00419     
00420 
00421 
00422     if (isalpha((int)*p)) {
00423         *len = strlen(strcpy(buf, p));
00424         *is_negative = FALSE;
00425         return (buf);
00426     }
00427     if (format == 'f') {
00428         if (decimal_point <= 0) {
00429             *s++ = '0';
00430             if (precision > 0) {
00431                 *s++ = '.';
00432                 while (decimal_point++ < 0)
00433                     *s++ = '0';
00434             } else if (add_dp) {
00435                 *s++ = '.';
00436             }
00437         } else {
00438             while (decimal_point-- > 0) {
00439                 *s++ = *p++;
00440             }
00441             if (precision > 0 || add_dp) {
00442                 *s++ = '.';
00443             }
00444         }
00445     } else {
00446         *s++ = *p++;
00447         if (precision > 0 || add_dp)
00448             *s++ = '.';
00449     }
00450 
00451     
00452 
00453 
00454     while (*p)
00455         *s++ = *p++;
00456 
00457     if (format != 'f') {
00458         char temp[EXPONENT_LENGTH];     
00459         int t_len;
00460         bool_int exponent_is_negative;
00461 
00462         *s++ = format;          
00463         decimal_point--;
00464         if (decimal_point != 0) {
00465             p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
00466                         &temp[EXPONENT_LENGTH], &t_len);
00467             *s++ = exponent_is_negative ? '-' : '+';
00468 
00469             
00470 
00471 
00472             if (t_len == 1)
00473                 *s++ = '0';
00474             while (t_len--)
00475                 *s++ = *p++;
00476         } else {
00477             *s++ = '+';
00478             *s++ = '0';
00479             *s++ = '0';
00480         }
00481     }
00482     *len = s - buf;
00483     return (buf);
00484 }
00485 
00486 
00487 
00488 
00489 
00490 
00491 
00492 
00493 
00494 
00495 
00496 
00497 static char *
00498 conv_p2(register u_wide_int num, register int nbits,
00499         char format, char *buf_end, register int *len)
00500 {
00501     register int mask = (1 << nbits) - 1;
00502     register char *p = buf_end;
00503     static char low_digits[] = "0123456789abcdef";
00504     static char upper_digits[] = "0123456789ABCDEF";
00505     register char *digits = (format == 'X') ? upper_digits : low_digits;
00506 
00507     do {
00508         *--p = digits[num & mask];
00509         num >>= nbits;
00510     }
00511     while (num);
00512 
00513     *len = buf_end - p;
00514     return (p);
00515 }
00516 
00517 
00518 
00519 
00520 
00521 static int format_converter(register buffy * odp, const char *fmt,
00522                             va_list ap)
00523 {
00524     register char *sp;
00525     register char *bep;
00526     register int cc = 0;
00527     register int i;
00528 
00529     register char *s = NULL;
00530     char *q;
00531     int s_len;
00532 
00533     register int min_width = 0;
00534     int precision = 0;
00535     enum {
00536         LEFT, RIGHT
00537     } adjust;
00538     char pad_char;
00539     char prefix_char;
00540 
00541     double fp_num;
00542     wide_int i_num = (wide_int) 0;
00543     u_wide_int ui_num;
00544 
00545     char num_buf[NUM_BUF_SIZE];
00546     char char_buf[2];           
00547 
00548     
00549 
00550 
00551     boolean_e is_long;
00552     boolean_e alternate_form;
00553     boolean_e print_sign;
00554     boolean_e print_blank;
00555     boolean_e adjust_precision;
00556     boolean_e adjust_width;
00557     bool_int is_negative;
00558 
00559     sp = odp->nextb;
00560     bep = odp->buf_end;
00561 
00562     while (*fmt) {
00563         if (*fmt != '%') {
00564             INS_CHAR(*fmt, sp, bep, cc);
00565         } else {
00566             
00567 
00568 
00569             adjust = RIGHT;
00570             alternate_form = print_sign = print_blank = NO;
00571             pad_char = ' ';
00572             prefix_char = NUL;
00573 
00574             fmt++;
00575 
00576             
00577 
00578 
00579             if (isascii((int)*fmt) && !islower((int)*fmt)) {
00580                 
00581 
00582 
00583                 for (;; fmt++) {
00584                     if (*fmt == '-')
00585                         adjust = LEFT;
00586                     else if (*fmt == '+')
00587                         print_sign = YES;
00588                     else if (*fmt == '#')
00589                         alternate_form = YES;
00590                     else if (*fmt == ' ')
00591                         print_blank = YES;
00592                     else if (*fmt == '0')
00593                         pad_char = '0';
00594                     else
00595                         break;
00596                 }
00597 
00598                 
00599 
00600 
00601                 if (isdigit((int)*fmt)) {
00602                     STR_TO_DEC(fmt, min_width);
00603                     adjust_width = YES;
00604                 } else if (*fmt == '*') {
00605                     min_width = va_arg(ap, int);
00606                     fmt++;
00607                     adjust_width = YES;
00608                     if (min_width < 0) {
00609                         adjust = LEFT;
00610                         min_width = -min_width;
00611                     }
00612                 } else
00613                     adjust_width = NO;
00614 
00615                 
00616 
00617 
00618 
00619 
00620 
00621 
00622                 if (*fmt == '.') {
00623                     adjust_precision = YES;
00624                     fmt++;
00625                     if (isdigit((int)*fmt)) {
00626                         STR_TO_DEC(fmt, precision);
00627                     } else if (*fmt == '*') {
00628                         precision = va_arg(ap, int);
00629                         fmt++;
00630                         if (precision < 0)
00631                             precision = 0;
00632                     } else
00633                         precision = 0;
00634                 } else
00635                     adjust_precision = NO;
00636             } else
00637                 adjust_precision = adjust_width = NO;
00638 
00639             
00640 
00641 
00642             if (*fmt == 'l') {
00643                 is_long = YES;
00644                 fmt++;
00645             } else
00646                 is_long = NO;
00647 
00648             
00649 
00650 
00651 
00652 
00653 
00654 
00655 
00656 
00657 
00658 
00659             switch (*fmt) {
00660             case 'u':
00661                 if (is_long)
00662                     i_num = va_arg(ap, u_wide_int);
00663                 else
00664                     i_num = (wide_int) va_arg(ap, unsigned int);
00665                 
00666 
00667 
00668 
00669             case 'd':
00670             case 'i':
00671                 
00672 
00673 
00674                 if ((*fmt) != 'u') {
00675                     if (is_long)
00676                         i_num = va_arg(ap, wide_int);
00677                     else
00678                         i_num = (wide_int) va_arg(ap, int);
00679                 };
00680                 s = conv_10(i_num, (*fmt) == 'u', &is_negative,
00681                             &num_buf[NUM_BUF_SIZE], &s_len);
00682                 FIX_PRECISION(adjust_precision, precision, s, s_len);
00683 
00684                 if (*fmt != 'u') {
00685                     if (is_negative)
00686                         prefix_char = '-';
00687                     else if (print_sign)
00688                         prefix_char = '+';
00689                     else if (print_blank)
00690                         prefix_char = ' ';
00691                 }
00692                 break;
00693 
00694 
00695             case 'o':
00696                 if (is_long)
00697                     ui_num = va_arg(ap, u_wide_int);
00698                 else
00699                     ui_num = (u_wide_int) va_arg(ap, unsigned int);
00700                 s = conv_p2(ui_num, 3, *fmt,
00701                             &num_buf[NUM_BUF_SIZE], &s_len);
00702                 FIX_PRECISION(adjust_precision, precision, s, s_len);
00703                 if (alternate_form && *s != '0') {
00704                     *--s = '0';
00705                     s_len++;
00706                 }
00707                 break;
00708 
00709 
00710             case 'x':
00711             case 'X':
00712                 if (is_long)
00713                     ui_num = (u_wide_int) va_arg(ap, u_wide_int);
00714                 else
00715                     ui_num = (u_wide_int) va_arg(ap, unsigned int);
00716                 s = conv_p2(ui_num, 4, *fmt,
00717                             &num_buf[NUM_BUF_SIZE], &s_len);
00718                 FIX_PRECISION(adjust_precision, precision, s, s_len);
00719                 if (alternate_form && i_num != 0) {
00720                     *--s = *fmt;    
00721                     *--s = '0';
00722                     s_len += 2;
00723                 }
00724                 break;
00725 
00726 
00727             case 's':
00728                 s = va_arg(ap, char *);
00729                 if (s != NULL) {
00730                     s_len = strlen(s);
00731                     if (adjust_precision && precision < s_len)
00732                         s_len = precision;
00733                 } else {
00734                     s = S_NULL;
00735                     s_len = S_NULL_LEN;
00736                 }
00737                 pad_char = ' ';
00738                 break;
00739 
00740 
00741             case 'f':
00742             case 'e':
00743             case 'E':
00744                 fp_num = va_arg(ap, double);
00745 
00746                 s = conv_fp(*fmt, fp_num, alternate_form,
00747                             (adjust_precision == NO) ? FLOAT_DIGITS : precision,
00748                             &is_negative, &num_buf[1], &s_len);
00749                 if (is_negative)
00750                     prefix_char = '-';
00751                 else if (print_sign)
00752                     prefix_char = '+';
00753                 else if (print_blank)
00754                     prefix_char = ' ';
00755                 break;
00756 
00757 
00758             case 'g':
00759             case 'G':
00760                 if (adjust_precision == NO)
00761                     precision = FLOAT_DIGITS;
00762                 else if (precision == 0)
00763                     precision = 1;
00764                 
00765 
00766 
00767                 s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]);
00768                 if (*s == '-')
00769                     prefix_char = *s++;
00770                 else if (print_sign)
00771                     prefix_char = '+';
00772                 else if (print_blank)
00773                     prefix_char = ' ';
00774 
00775                 s_len = strlen(s);
00776 
00777                 if (alternate_form && (q = strchr(s, '.')) == NULL)
00778                     s[s_len++] = '.';
00779                 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
00780                     *q = 'E';
00781                 break;
00782 
00783 
00784             case 'c':
00785                 char_buf[0] = (char) (va_arg(ap, int));
00786                 s = &char_buf[0];
00787                 s_len = 1;
00788                 pad_char = ' ';
00789                 break;
00790 
00791 
00792             case '%':
00793                 char_buf[0] = '%';
00794                 s = &char_buf[0];
00795                 s_len = 1;
00796                 pad_char = ' ';
00797                 break;
00798 
00799 
00800             case 'n':
00801                 *(va_arg(ap, int *)) = cc;
00802                 break;
00803 
00804                 
00805 
00806 
00807 
00808 
00809 
00810 
00811 
00812             case 'p':
00813                 ui_num = (u_wide_int) va_arg(ap, char *);
00814 
00815                 if (sizeof(char *) <= sizeof(u_wide_int))
00816                     s = conv_p2(ui_num, 4, 'x',
00817                                 &num_buf[NUM_BUF_SIZE], &s_len);
00818                 else {
00819                     s = "%p";
00820                     s_len = 2;
00821                 }
00822                 pad_char = ' ';
00823                 break;
00824 
00825 
00826             case NUL:
00827                 
00828 
00829 
00830 
00831                 continue;
00832 
00833 
00834                 
00835 
00836 
00837 
00838 
00839 
00840 
00841 
00842 
00843 
00844             default:
00845                 char_buf[0] = '%';
00846                 char_buf[1] = *fmt;
00847                 s = char_buf;
00848                 s_len = 2;
00849                 pad_char = ' ';
00850                 break;
00851             }
00852 
00853             if (prefix_char != NUL) {
00854                 *--s = prefix_char;
00855                 s_len++;
00856             }
00857             if (adjust_width && adjust == RIGHT && min_width > s_len) {
00858                 if (pad_char == '0' && prefix_char != NUL) {
00859                     INS_CHAR(*s, sp, bep, cc)
00860                     s++;
00861                     s_len--;
00862                     min_width--;
00863                 }
00864                 PAD(min_width, s_len, pad_char);
00865             }
00866             
00867 
00868 
00869             for (i = s_len; i != 0; i--) {
00870                 INS_CHAR(*s, sp, bep, cc);
00871                 s++;
00872             }
00873 
00874             if (adjust_width && adjust == LEFT && min_width > s_len)
00875                 PAD(min_width, s_len, pad_char);
00876         }
00877         fmt++;
00878     }
00879     odp->nextb = sp;
00880     return (cc);
00881 }
00882 
00883 
00884 
00885 
00886 
00887 static void strx_printv(int *ccp, char *buf, size_t len, const char *format,
00888                         va_list ap)
00889 {
00890     buffy od;
00891     int cc;
00892 
00893     
00894 
00895 
00896 
00897 
00898     od.buf_end = len ? &buf[len] : (char *) ~0;
00899     od.nextb = buf;
00900 
00901     
00902 
00903 
00904     cc = format_converter(&od, format, ap);
00905     if (len == 0 || od.nextb <= od.buf_end)
00906         *(od.nextb) = '\0';
00907     if (ccp)
00908         *ccp = cc;
00909 }
00910 
00911 
00912 int ap_snprintf(char *buf, size_t len, const char *format,...)
00913 {
00914     int cc;
00915     va_list ap;
00916 
00917     va_start(ap, format);
00918     strx_printv(&cc, buf, (len - 1), format, ap);
00919     va_end(ap);
00920     return (cc);
00921 }
00922 
00923 
00924 int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap)
00925 {
00926     int cc;
00927 
00928     strx_printv(&cc, buf, (len - 1), format, ap);
00929     return (cc);
00930 }
00931 
00932 #endif