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