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
00059
00060
00061
00062
00063
00064 #include <ctype.h>
00065 #include <stdlib.h>
00066 #include <stdarg.h>
00067 #include <string.h>
00068 #include <sys/types.h>
00069
00070 #ifndef SCOPE
00071 #define SCOPE
00072 #endif
00073
00074 #ifndef WIDE_INT
00075 #define WIDE_INT long
00076 #endif
00077
00078 typedef WIDE_INT wide_int;
00079 typedef unsigned WIDE_INT u_wide_int;
00080 typedef int bool_int;
00081
00082 #ifndef FALSE
00083 #define FALSE 0
00084 #define TRUE 1
00085 #endif
00086
00087 #define NUL '\0'
00088
00089 #define S_NULL "(null)"
00090 #define S_NULL_LEN 6
00091
00092 #define FLOAT_DIGITS 6
00093 #define EXPONENT_LENGTH 10
00094
00095 typedef enum { NO = 0, YES = 1 } boolean_e ;
00096
00097
00098
00099
00100
00101
00102 #define NUM_BUF_SIZE 512
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 #define INS_CHAR( c, sp, bep, cc ) \
00116 { \
00117 if ( sp < bep ) \
00118 *sp++ = c ; \
00119 cc++ ; \
00120 }
00121
00122 #define NUM( c ) ( c - '0' )
00123
00124 #define STR_TO_DEC( str, num ) \
00125 num = NUM( *str++ ) ; \
00126 while ( isdigit( *str ) ) { \
00127 num *= 10 ; \
00128 num += NUM( *str++ ) ; \
00129 }
00130
00131
00132
00133
00134
00135
00136
00137 #define FIX_PRECISION( adjust, precision, s, s_len ) \
00138 if ( adjust ) \
00139 while ( s_len < precision ) { \
00140 *--s = '0' ; \
00141 s_len++ ; \
00142 }
00143
00144
00145
00146
00147
00148 #define PAD( width, len, ch ) \
00149 do { \
00150 INS_CHAR( ch, sp, bep, cc ) ; \
00151 width-- ; \
00152 } while ( width > len )
00153
00154
00155
00156
00157
00158
00159 #define PREFIX( str, length, ch ) \
00160 *--str = ch ; length++ ; has_prefix = YES
00161
00162 static char *conv_10(wide_int num, bool_int is_unsigned,
00163 bool_int * is_negative, char *buf_end, int *len);
00164 SCOPE int vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 SCOPE int
00175 snprintf(char *str, size_t size, const char *fmt, ...)
00176 {
00177 int cc;
00178 va_list ap;
00179
00180 va_start(ap, fmt);
00181 cc = vsnprintf(str, size, fmt, ap);
00182 va_end(ap);
00183 return cc;
00184 }
00185
00186
00187
00188
00189
00190
00191
00192 static char *
00193 conv_fp(char format, double num, boolean_e add_dp, int precision,
00194 bool_int *is_negative, char buf[], int *len)
00195 {
00196 char *s = buf;
00197 char *p;
00198 int decimal_point;
00199
00200 if (format == 'f')
00201 p = fcvt(num, precision, &decimal_point, is_negative);
00202 else
00203 p = ecvt(num, precision + 1, &decimal_point, is_negative);
00204
00205
00206
00207
00208 if (isalpha(*p)) {
00209 *len = strlen(strcpy(buf, p));
00210 *is_negative = FALSE;
00211 return (buf);
00212 }
00213 if (format == 'f')
00214 if (decimal_point <= 0) {
00215 *s++ = '0';
00216 if (precision > 0) {
00217 *s++ = '.';
00218 while (decimal_point++ < 0)
00219 *s++ = '0';
00220 } else if (add_dp)
00221 *s++ = '.';
00222 } else {
00223 while (decimal_point-- > 0)
00224 *s++ = *p++;
00225 if (precision > 0 || add_dp)
00226 *s++ = '.';
00227 } else {
00228 *s++ = *p++;
00229 if (precision > 0 || add_dp)
00230 *s++ = '.';
00231 }
00232
00233
00234
00235
00236 while (*p)
00237 *s++ = *p++;
00238
00239 if (format != 'f') {
00240 char temp[EXPONENT_LENGTH];
00241 int t_len;
00242 bool_int exponent_is_negative;
00243
00244 *s++ = format;
00245 decimal_point--;
00246 if (decimal_point != 0) {
00247 p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative,
00248 &temp[EXPONENT_LENGTH], &t_len);
00249 *s++ = exponent_is_negative ? '-' : '+';
00250
00251
00252
00253
00254 if (t_len == 1)
00255 *s++ = '0';
00256 while (t_len--)
00257 *s++ = *p++;
00258 } else {
00259 *s++ = '+';
00260 *s++ = '0';
00261 *s++ = '0';
00262 }
00263 }
00264 *len = s - buf;
00265 return (buf);
00266 }
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 static char *
00279 conv_p2(u_wide_int num, int nbits, char format, char *buf_end, int *len)
00280 {
00281 int mask = (1 << nbits) - 1;
00282 char *p = buf_end;
00283 static char low_digits[] = "0123456789abcdef";
00284 static char upper_digits[] = "0123456789ABCDEF";
00285 char *digits = (format == 'X') ? upper_digits : low_digits;
00286
00287 do {
00288 *--p = digits[num & mask];
00289 num >>= nbits;
00290 }
00291 while (num);
00292
00293 *len = buf_end - p;
00294 return (p);
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 static char *
00310 conv_10(wide_int num, bool_int is_unsigned, bool_int *is_negative,
00311 char *buf_end, int *len)
00312 {
00313 char *p = buf_end;
00314 u_wide_int magnitude;
00315
00316 if (is_unsigned) {
00317 magnitude = (u_wide_int) num;
00318 *is_negative = FALSE;
00319 } else {
00320 *is_negative = (num < 0);
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 if (*is_negative) {
00332 wide_int t = num + 1;
00333
00334 magnitude = ((u_wide_int) - t) + 1;
00335 } else
00336 magnitude = (u_wide_int) num;
00337 }
00338
00339
00340
00341
00342 do {
00343 register u_wide_int new_magnitude = magnitude / 10;
00344
00345 *--p = magnitude - new_magnitude * 10 + '0';
00346 magnitude = new_magnitude;
00347 }
00348 while (magnitude);
00349
00350 *len = buf_end - p;
00351 return (p);
00352 }
00353
00354
00355
00356
00357 SCOPE int
00358 vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
00359 {
00360 char *sp;
00361 char *bep;
00362 int cc = 0;
00363 int i;
00364
00365 char *s;
00366 char *q;
00367 int s_len;
00368
00369 int min_width;
00370 int precision;
00371 enum {
00372 LEFT, RIGHT
00373 } adjust;
00374 char pad_char;
00375 char prefix_char;
00376
00377 double fp_num;
00378 wide_int i_num;
00379 u_wide_int ui_num;
00380
00381 char num_buf[NUM_BUF_SIZE];
00382 char char_buf[2];
00383
00384
00385
00386
00387 boolean_e is_long;
00388 boolean_e alternate_form;
00389 boolean_e print_sign;
00390 boolean_e print_blank;
00391 boolean_e adjust_precision;
00392 boolean_e adjust_width;
00393 bool_int is_negative;
00394
00395 if (size == 0)
00396 return 0;
00397
00398 sp = str;
00399 bep = str + size - 1;
00400
00401 while (*fmt) {
00402 if (*fmt != '%') {
00403 INS_CHAR(*fmt, sp, bep, cc);
00404 } else {
00405
00406
00407
00408 adjust = RIGHT;
00409 alternate_form = print_sign = print_blank = NO;
00410 pad_char = ' ';
00411 prefix_char = NUL;
00412
00413 fmt++;
00414
00415
00416
00417
00418 if (isascii(*fmt) && !islower(*fmt)) {
00419
00420
00421
00422 for (;; fmt++) {
00423 if (*fmt == '-')
00424 adjust = LEFT;
00425 else if (*fmt == '+')
00426 print_sign = YES;
00427 else if (*fmt == '#')
00428 alternate_form = YES;
00429 else if (*fmt == ' ')
00430 print_blank = YES;
00431 else if (*fmt == '0')
00432 pad_char = '0';
00433 else
00434 break;
00435 }
00436
00437
00438
00439
00440 if (isdigit(*fmt)) {
00441 STR_TO_DEC(fmt, min_width);
00442 adjust_width = YES;
00443 } else if (*fmt == '*') {
00444 min_width = va_arg(ap, int);
00445
00446 fmt++;
00447 adjust_width = YES;
00448 if (min_width < 0) {
00449 adjust = LEFT;
00450 min_width = -min_width;
00451 }
00452 } else
00453 adjust_width = NO;
00454
00455
00456
00457
00458
00459
00460
00461
00462 if (*fmt == '.') {
00463 adjust_precision = YES;
00464 fmt++;
00465 if (isdigit(*fmt)) {
00466 STR_TO_DEC(fmt, precision);
00467 } else if (*fmt == '*') {
00468 precision = va_arg(ap, int);
00469
00470 fmt++;
00471 if (precision < 0)
00472 precision = 0;
00473 } else
00474 precision = 0;
00475 } else
00476 adjust_precision = NO;
00477 } else
00478 adjust_precision = adjust_width = NO;
00479
00480
00481
00482
00483 if (*fmt == 'l') {
00484 is_long = YES;
00485 fmt++;
00486 } else
00487 is_long = NO;
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500 switch (*fmt) {
00501 case 'd':
00502 case 'i':
00503 case 'u':
00504 if (is_long)
00505 i_num = va_arg(ap, wide_int);
00506 else
00507 i_num = (wide_int) va_arg(ap, int);
00508
00509 s = conv_10(i_num, (*fmt) == 'u', &is_negative,
00510 &num_buf[NUM_BUF_SIZE], &s_len);
00511 FIX_PRECISION(adjust_precision, precision, s, s_len);
00512
00513 if (*fmt != 'u') {
00514 if (is_negative)
00515 prefix_char = '-';
00516 else if (print_sign)
00517 prefix_char = '+';
00518 else if (print_blank)
00519 prefix_char = ' ';
00520 }
00521 break;
00522
00523 case 'o':
00524 if (is_long)
00525 ui_num = va_arg(ap, u_wide_int);
00526 else
00527 ui_num = (u_wide_int) va_arg(ap, unsigned int);
00528
00529 s = conv_p2(ui_num, 3, *fmt,
00530 &num_buf[NUM_BUF_SIZE], &s_len);
00531 FIX_PRECISION(adjust_precision, precision, s, s_len);
00532 if (alternate_form && *s != '0') {
00533 *--s = '0';
00534 s_len++;
00535 }
00536 break;
00537
00538 case 'x':
00539 case 'X':
00540 if (is_long)
00541 ui_num = (u_wide_int) va_arg(ap, u_wide_int);
00542 else
00543 ui_num = (u_wide_int) va_arg(ap, unsigned int);
00544
00545 s = conv_p2(ui_num, 4, *fmt,
00546 &num_buf[NUM_BUF_SIZE], &s_len);
00547 FIX_PRECISION(adjust_precision, precision, s, s_len);
00548 if (alternate_form && i_num != 0) {
00549 *--s = *fmt;
00550 *--s = '0';
00551 s_len += 2;
00552 }
00553 break;
00554
00555 case 's':
00556 s = va_arg(ap, char *);
00557
00558 if (s != NULL) {
00559 s_len = strlen(s);
00560 if (adjust_precision && precision < s_len)
00561 s_len = precision;
00562 } else {
00563 s = S_NULL;
00564 s_len = S_NULL_LEN;
00565 }
00566 pad_char = ' ';
00567 break;
00568
00569 case 'f':
00570 case 'e':
00571 case 'E':
00572 fp_num = va_arg(ap, double);
00573
00574 s = conv_fp(*fmt, fp_num, alternate_form,
00575 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
00576 &is_negative, &num_buf[1], &s_len);
00577 if (is_negative)
00578 prefix_char = '-';
00579 else if (print_sign)
00580 prefix_char = '+';
00581 else if (print_blank)
00582 prefix_char = ' ';
00583 break;
00584
00585 case 'g':
00586 case 'G':
00587 if (adjust_precision == NO)
00588 precision = FLOAT_DIGITS;
00589 else if (precision == 0)
00590 precision = 1;
00591
00592
00593
00594 s = gcvt(va_arg(ap, double), precision, &num_buf[1]);
00595
00596 if (*s == '-')
00597 prefix_char = *s++;
00598 else if (print_sign)
00599 prefix_char = '+';
00600 else if (print_blank)
00601 prefix_char = ' ';
00602
00603 s_len = strlen(s);
00604
00605 if (alternate_form && (q = strchr(s, '.')) == NULL)
00606 s[s_len++] = '.';
00607 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
00608 *q = 'E';
00609 break;
00610
00611 case 'c':
00612 char_buf[0] = (char)(va_arg(ap, int));
00613
00614 s = &char_buf[0];
00615 s_len = 1;
00616 pad_char = ' ';
00617 break;
00618
00619 case '%':
00620 char_buf[0] = '%';
00621 s = &char_buf[0];
00622 s_len = 1;
00623 pad_char = ' ';
00624 break;
00625
00626 case 'n':
00627 *(va_arg(ap, int *)) = cc;
00628
00629 break;
00630
00631
00632
00633
00634
00635
00636 case 'p':
00637 ui_num = (u_wide_int) va_arg(ap, void *);
00638
00639 if (sizeof(void *) <= sizeof(u_wide_int))
00640 s = conv_p2(ui_num, 4, 'x',
00641 &num_buf[NUM_BUF_SIZE], &s_len);
00642
00643 else {
00644 s = "%p";
00645 s_len = 2;
00646 }
00647 pad_char = ' ';
00648 break;
00649
00650 case NUL:
00651
00652
00653
00654
00655 continue;
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 default:
00668 char_buf[0] = '%';
00669 char_buf[1] = *fmt;
00670 s = char_buf;
00671 s_len = 2;
00672 pad_char = ' ';
00673 break;
00674 }
00675
00676 if (prefix_char != NUL) {
00677 *--s = prefix_char;
00678 s_len++;
00679 }
00680 if (adjust_width && adjust == RIGHT && min_width > s_len) {
00681 if (pad_char == '0' && prefix_char != NUL) {
00682 INS_CHAR(*s, sp, bep, cc)
00683 s++;
00684 s_len--;
00685 min_width--;
00686 }
00687 PAD(min_width, s_len, pad_char);
00688 }
00689
00690
00691
00692 for (i = s_len; i != 0; i--) {
00693 INS_CHAR(*s, sp, bep, cc);
00694 s++;
00695 }
00696
00697 if (adjust_width && adjust == LEFT && min_width > s_len)
00698 PAD(min_width, s_len, pad_char);
00699 }
00700 fmt++;
00701 }
00702 if (cc < size)
00703 str[cc] = NUL;
00704 else
00705 str[size - 1] = NUL;
00706 return cc;
00707 }
00708