#include <ctype.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <sys/types.h>Include dependency graph for snprintf.c:

Go to the source code of this file.
Defines | |
| #define | SCOPE |
| #define | WIDE_INT long |
| #define | FALSE 0 |
| #define | TRUE 1 |
| #define | NUL '\0' |
| #define | S_NULL "(null)" |
| #define | S_NULL_LEN 6 |
| #define | FLOAT_DIGITS 6 |
| #define | EXPONENT_LENGTH 10 |
| #define | NUM_BUF_SIZE 512 |
| #define | INS_CHAR(c, sp, bep, cc) |
| #define | NUM(c) ( c - '0' ) |
| #define | STR_TO_DEC(str, num) |
| #define | FIX_PRECISION(adjust, precision, s, s_len) |
| #define | PAD(width, len, ch) |
| #define | PREFIX(str, length, ch) *--str = ch ; length++ ; has_prefix = YES |
Typedefs | |
| typedef WIDE_INT | wide_int |
| typedef unsigned WIDE_INT | u_wide_int |
| typedef int | bool_int |
Enumerations | |
| enum | boolean_e { NO = 0, YES = 1 } |
Functions | |
| static char * | conv_10 (wide_int num, bool_int is_unsigned, bool_int *is_negative, char *buf_end, int *len) |
| SCOPE int | vsnprintf (char *str, size_t size, const char *fmt, va_list ap) |
| SCOPE int | snprintf (char *str, size_t size, const char *fmt,...) |
| static char * | conv_fp (char format, double num, boolean_e add_dp, int precision, bool_int *is_negative, char buf[], int *len) |
| static char * | conv_p2 (u_wide_int num, int nbits, char format, char *buf_end, int *len) |
| #define EXPONENT_LENGTH 10 |
| #define FALSE 0 |
Definition at line 83 of file snprintf.c.
| #define FIX_PRECISION | ( | adjust, | |||
| precision, | |||||
| s, | |||||
| s_len | ) |
Value:
if ( adjust ) \ while ( s_len < precision ) { \ *--s = '0' ; \ s_len++ ; \ }
Definition at line 137 of file snprintf.c.
Referenced by vsnprintf().
| #define FLOAT_DIGITS 6 |
| #define INS_CHAR | ( | c, | |||
| sp, | |||||
| bep, | |||||
| cc | ) |
| #define NUL '\0' |
Definition at line 87 of file snprintf.c.
Referenced by display_string(), move_left(), move_right(), strip_blank(), and vsnprintf().
| #define NUM | ( | c | ) | ( c - '0' ) |
Definition at line 122 of file snprintf.c.
| #define NUM_BUF_SIZE 512 |
Definition at line 159 of file snprintf.c.
| #define S_NULL "(null)" |
| #define S_NULL_LEN 6 |
| #define SCOPE |
Definition at line 71 of file snprintf.c.
| #define STR_TO_DEC | ( | str, | |||
| num | ) |
| #define TRUE 1 |
Definition at line 84 of file snprintf.c.
| #define WIDE_INT long |
Definition at line 75 of file snprintf.c.
Definition at line 80 of file snprintf.c.
| typedef unsigned WIDE_INT u_wide_int |
Definition at line 79 of file snprintf.c.
| typedef WIDE_INT wide_int |
Definition at line 78 of file snprintf.c.
| enum boolean_e |
| static char * conv_10 | ( | wide_int | num, | |
| bool_int | is_unsigned, | |||
| bool_int * | is_negative, | |||
| char * | buf_end, | |||
| int * | len | |||
| ) | [static] |
Definition at line 310 of file snprintf.c.
Referenced by conv_fp(), and vsnprintf().
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 * On a 2's complement machine, negating the most negative integer 00324 * results in a number that cannot be represented as a signed integer. 00325 * Here is what we do to obtain the number's magnitude: 00326 * a. add 1 to the number 00327 * b. negate it (becomes positive) 00328 * c. convert it to unsigned 00329 * d. add 1 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 * We use a do-while loop so that we write at least 1 digit 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 }
Here is the caller graph for this function:

| static char* conv_fp | ( | char | format, | |
| double | num, | |||
| boolean_e | add_dp, | |||
| int | precision, | |||
| bool_int * | is_negative, | |||
| char | buf[], | |||
| int * | len | |||
| ) | [static] |
Definition at line 193 of file snprintf.c.
References conv_10(), EXPONENT_LENGTH, FALSE, p, and s.
Referenced by vsnprintf().
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 /* either e or E format */ 00203 p = ecvt(num, precision + 1, &decimal_point, is_negative); 00204 00205 /* 00206 * Check for Infinity and NaN 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 * copy the rest of p, the NUL is NOT copied 00235 */ 00236 while (*p) 00237 *s++ = *p++; 00238 00239 if (format != 'f') { 00240 char temp[EXPONENT_LENGTH]; /* for exponent conversion */ 00241 int t_len; 00242 bool_int exponent_is_negative; 00243 00244 *s++ = format; /* either e or E */ 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 * Make sure the exponent has at least 2 digits 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 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static char* conv_p2 | ( | u_wide_int | num, | |
| int | nbits, | |||
| char | format, | |||
| char * | buf_end, | |||
| int * | len | |||
| ) | [static] |
Definition at line 279 of file snprintf.c.
References p.
Referenced by vsnprintf().
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 }
Here is the caller graph for this function:

| SCOPE int snprintf | ( | char * | str, | |
| size_t | size, | |||
| const char * | fmt, | |||
| ... | ||||
| ) |
Definition at line 175 of file snprintf.c.
References vsnprintf().
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 }
Here is the call graph for this function:

| SCOPE int vsnprintf | ( | char * | str, | |
| size_t | size, | |||
| const char * | fmt, | |||
| va_list | ap | |||
| ) |
Definition at line 358 of file snprintf.c.
References conv_10(), conv_fp(), conv_p2(), FIX_PRECISION, FLOAT_DIGITS, i, INS_CHAR, LEFT, NO, NUL, NULL, NUM_BUF_SIZE, PAD, RIGHT, s, S_NULL, S_NULL_LEN, sp(), STR_TO_DEC, strchr(), and YES.
Referenced by C2F(), LOGGER_log(), PLD_dprintf(), sciprint(), sciprint2(), sciprint_full(), sciprint_l(), sciprint_nd(), snprintf(), and XmuSnprintf().
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]; /* for printing %% and %<unknown> */ 00383 00384 /* 00385 * Flag variables 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 * Default variable settings 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 * Try to avoid checking for flags, width or precision 00417 */ 00418 if (isascii(*fmt) && !islower(*fmt)) { 00419 /* 00420 * Recognize flags: -, #, BLANK, + 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 * Check if a width was specified 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 * Check if a precision was specified 00457 * 00458 * XXX: an unreasonable amount of precision may be specified 00459 * resulting in overflow of num_buf. Currently we 00460 * ignore this possibility. 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 * Modifier check 00482 */ 00483 if (*fmt == 'l') { 00484 is_long = YES; 00485 fmt++; 00486 } else 00487 is_long = NO; 00488 00489 /* 00490 * Argument extraction and printing. 00491 * First we determine the argument type. 00492 * Then, we convert the argument to a string. 00493 * On exit from the switch, s points to the string that 00494 * must be printed, s_len has the length of the string 00495 * The precision requirements, if any, are reflected in s_len. 00496 * 00497 * NOTE: pad_char may be set to '0' because of the 0 flag. 00498 * It is reset to ' ' by non-numeric formats 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; /* 'x' or 'X' */ 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 * We use &num_buf[ 1 ], so that we have room for the sign 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 * If the pointer size is equal to the size of an unsigned 00633 * integer we convert the pointer to a hex number, otherwise 00634 * we print "%p" to indicate that we don't handle "%p". 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 * The last character of the format string was %. 00653 * We ignore it. 00654 */ 00655 continue; 00656 00657 /* 00658 * The default case is for unrecognized %'s. 00659 * We print %<char> to help the user identify what 00660 * option is not understood. 00661 * This is also useful in case the user wants to pass 00662 * the output of __sio_converter to another function 00663 * that understands some other %<char> (like syslog). 00664 * Note that we can't point s inside fmt because the 00665 * unknown <char> could be preceded by width etc. 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 * Print the string s. 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 }
Here is the call graph for this function:

Here is the caller graph for this function:

1.5.1