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