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
00563 sp = odp->nextb;
00564 bep = odp->buf_end;
00565
00566 while (*fmt) {
00567 if (*fmt != '%') {
00568 INS_CHAR(*fmt, sp, bep, cc);
00569 } else {
00570
00571
00572
00573 adjust = RIGHT;
00574 alternate_form = print_sign = print_blank = NO;
00575 pad_char = ' ';
00576 prefix_char = NUL;
00577
00578 fmt++;
00579
00580
00581
00582
00583 if (isascii((int)*fmt) && !islower((int)*fmt)) {
00584
00585
00586
00587 for (;; fmt++) {
00588 if (*fmt == '-')
00589 adjust = LEFT;
00590 else if (*fmt == '+')
00591 print_sign = YES;
00592 else if (*fmt == '#')
00593 alternate_form = YES;
00594 else if (*fmt == ' ')
00595 print_blank = YES;
00596 else if (*fmt == '0')
00597 pad_char = '0';
00598 else
00599 break;
00600 }
00601
00602
00603
00604
00605 if (isdigit((int)*fmt)) {
00606 STR_TO_DEC(fmt, min_width);
00607 adjust_width = YES;
00608 } else if (*fmt == '*') {
00609 min_width = va_arg(ap, int);
00610 fmt++;
00611 adjust_width = YES;
00612 if (min_width < 0) {
00613 adjust = LEFT;
00614 min_width = -min_width;
00615 }
00616 } else
00617 adjust_width = NO;
00618
00619
00620
00621
00622
00623
00624
00625
00626 if (*fmt == '.') {
00627 adjust_precision = YES;
00628 fmt++;
00629 if (isdigit((int)*fmt)) {
00630 STR_TO_DEC(fmt, precision);
00631 } else if (*fmt == '*') {
00632 precision = va_arg(ap, int);
00633 fmt++;
00634 if (precision < 0)
00635 precision = 0;
00636 } else
00637 precision = 0;
00638 } else
00639 adjust_precision = NO;
00640 } else
00641 adjust_precision = adjust_width = NO;
00642
00643
00644
00645
00646 if (*fmt == 'l') {
00647 is_long = YES;
00648 fmt++;
00649 } else
00650 is_long = NO;
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663 switch (*fmt) {
00664 case 'u':
00665 if (is_long)
00666 i_num = va_arg(ap, u_wide_int);
00667 else
00668 i_num = (wide_int) va_arg(ap, unsigned int);
00669
00670
00671
00672
00673 case 'd':
00674 case 'i':
00675
00676
00677
00678 if ((*fmt) != 'u') {
00679 if (is_long)
00680 i_num = va_arg(ap, wide_int);
00681 else
00682 i_num = (wide_int) va_arg(ap, int);
00683 };
00684 s = conv_10(i_num, (*fmt) == 'u', &is_negative,
00685 &num_buf[NUM_BUF_SIZE], &s_len);
00686 FIX_PRECISION(adjust_precision, precision, s, s_len);
00687
00688 if (*fmt != 'u') {
00689 if (is_negative)
00690 prefix_char = '-';
00691 else if (print_sign)
00692 prefix_char = '+';
00693 else if (print_blank)
00694 prefix_char = ' ';
00695 }
00696 break;
00697
00698
00699 case 'o':
00700 if (is_long)
00701 ui_num = va_arg(ap, u_wide_int);
00702 else
00703 ui_num = (u_wide_int) va_arg(ap, unsigned int);
00704 s = conv_p2(ui_num, 3, *fmt,
00705 &num_buf[NUM_BUF_SIZE], &s_len);
00706 FIX_PRECISION(adjust_precision, precision, s, s_len);
00707 if (alternate_form && *s != '0') {
00708 *--s = '0';
00709 s_len++;
00710 }
00711 break;
00712
00713
00714 case 'x':
00715 case 'X':
00716 if (is_long)
00717 ui_num = (u_wide_int) va_arg(ap, u_wide_int);
00718 else
00719 ui_num = (u_wide_int) va_arg(ap, unsigned int);
00720 s = conv_p2(ui_num, 4, *fmt,
00721 &num_buf[NUM_BUF_SIZE], &s_len);
00722 FIX_PRECISION(adjust_precision, precision, s, s_len);
00723 if (alternate_form && i_num != 0) {
00724 *--s = *fmt;
00725 *--s = '0';
00726 s_len += 2;
00727 }
00728 break;
00729
00730
00731 case 's':
00732 s = va_arg(ap, char *);
00733 if (s != NULL) {
00734 s_len = strlen(s);
00735 if (adjust_precision && precision < s_len)
00736 s_len = precision;
00737 } else {
00738 s = S_NULL;
00739 s_len = S_NULL_LEN;
00740 }
00741 pad_char = ' ';
00742 break;
00743
00744
00745 case 'f':
00746 case 'e':
00747 case 'E':
00748 fp_num = va_arg(ap, double);
00749
00750 s = conv_fp(*fmt, fp_num, alternate_form,
00751 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
00752 &is_negative, &num_buf[1], &s_len);
00753 if (is_negative)
00754 prefix_char = '-';
00755 else if (print_sign)
00756 prefix_char = '+';
00757 else if (print_blank)
00758 prefix_char = ' ';
00759 break;
00760
00761
00762 case 'g':
00763 case 'G':
00764 if (adjust_precision == NO)
00765 precision = FLOAT_DIGITS;
00766 else if (precision == 0)
00767 precision = 1;
00768
00769
00770
00771 s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]);
00772 if (*s == '-')
00773 prefix_char = *s++;
00774 else if (print_sign)
00775 prefix_char = '+';
00776 else if (print_blank)
00777 prefix_char = ' ';
00778
00779 s_len = strlen(s);
00780
00781 if (alternate_form && (q = strchr(s, '.')) == NULL)
00782 s[s_len++] = '.';
00783 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
00784 *q = 'E';
00785 break;
00786
00787
00788 case 'c':
00789 char_buf[0] = (char) (va_arg(ap, int));
00790 s = &char_buf[0];
00791 s_len = 1;
00792 pad_char = ' ';
00793 break;
00794
00795
00796 case '%':
00797 char_buf[0] = '%';
00798 s = &char_buf[0];
00799 s_len = 1;
00800 pad_char = ' ';
00801 break;
00802
00803
00804 case 'n':
00805 *(va_arg(ap, int *)) = cc;
00806 break;
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816 case 'p':
00817 ui_num = (u_wide_int) va_arg(ap, char *);
00818
00819 if (sizeof(char *) <= sizeof(u_wide_int))
00820 s = conv_p2(ui_num, 4, 'x',
00821 &num_buf[NUM_BUF_SIZE], &s_len);
00822 else {
00823 s = "%p";
00824 s_len = 2;
00825 }
00826 pad_char = ' ';
00827 break;
00828
00829
00830 case NUL:
00831
00832
00833
00834
00835 continue;
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848 default:
00849 char_buf[0] = '%';
00850 char_buf[1] = *fmt;
00851 s = char_buf;
00852 s_len = 2;
00853 pad_char = ' ';
00854 break;
00855 }
00856
00857 if (prefix_char != NUL) {
00858 *--s = prefix_char;
00859 s_len++;
00860 }
00861 if (adjust_width && adjust == RIGHT && min_width > s_len) {
00862 if (pad_char == '0' && prefix_char != NUL) {
00863 INS_CHAR(*s, sp, bep, cc)
00864 s++;
00865 s_len--;
00866 min_width--;
00867 }
00868 PAD(min_width, s_len, pad_char);
00869 }
00870
00871
00872
00873 for (i = s_len; i != 0; i--) {
00874 INS_CHAR(*s, sp, bep, cc);
00875 s++;
00876 }
00877
00878 if (adjust_width && adjust == LEFT && min_width > s_len)
00879 PAD(min_width, s_len, pad_char);
00880 }
00881 fmt++;
00882 }
00883 odp->nextb = sp;
00884 return (cc);
00885 }
00886
00887
00888
00889
00890
00891 static void strx_printv(int *ccp, char *buf, size_t len, const char *format,
00892 va_list ap)
00893 {
00894 buffy od;
00895 int cc;
00896
00897
00898
00899
00900
00901
00902 od.buf_end = len ? &buf[len] : (char *) ~0;
00903 od.nextb = buf;
00904
00905
00906
00907
00908 cc = format_converter(&od, format, ap);
00909 if (len == 0 || od.nextb <= od.buf_end)
00910 *(od.nextb) = '\0';
00911 if (ccp)
00912 *ccp = cc;
00913 }
00914
00915
00916 int ap_snprintf(char *buf, size_t len, const char *format,...)
00917 {
00918 int cc;
00919 va_list ap;
00920
00921 va_start(ap, format);
00922 strx_printv(&cc, buf, (len - 1), format, ap);
00923 va_end(ap);
00924 return (cc);
00925 }
00926
00927
00928 int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap)
00929 {
00930 int cc;
00931
00932 strx_printv(&cc, buf, (len - 1), format, ap);
00933 return (cc);
00934 }
00935
00936 #endif