snprintf.c File Reference

#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 Documentation

#define EXPONENT_LENGTH   10

Definition at line 93 of file snprintf.c.

Referenced by conv_fp().

#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

Definition at line 92 of file snprintf.c.

Referenced by vsnprintf().

#define INS_CHAR ( c,
sp,
bep,
cc   ) 

Value:

{                                                               \
            if ( sp < bep )                                             \
                *sp++ = c ;                                             \
            cc++ ;                                                      \
        }

Definition at line 115 of file snprintf.c.

Referenced by vsnprintf().

#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 - '0' )

Definition at line 122 of file snprintf.c.

#define NUM_BUF_SIZE   512

Definition at line 102 of file snprintf.c.

Referenced by vsnprintf().

#define PAD ( width,
len,
ch   ) 

Value:

do {                                                            \
                INS_CHAR( ch, sp, bep, cc ) ;                           \
                width-- ;                                               \
        } while ( width > len )

Definition at line 148 of file snprintf.c.

Referenced by vsnprintf().

#define PREFIX ( str,
length,
ch   )     *--str = ch ; length++ ; has_prefix = YES

Definition at line 159 of file snprintf.c.

#define S_NULL   "(null)"

Definition at line 89 of file snprintf.c.

Referenced by vsnprintf().

#define S_NULL_LEN   6

Definition at line 90 of file snprintf.c.

Referenced by vsnprintf().

#define SCOPE

Definition at line 71 of file snprintf.c.

#define STR_TO_DEC ( str,
num   ) 

Value:

num = NUM( *str++ ) ;                                           \
        while ( isdigit( *str ) ) {                                     \
                num *= 10 ;                                             \
                num += NUM( *str++ ) ;                                  \
        }

Definition at line 124 of file snprintf.c.

Referenced by vsnprintf().

#define TRUE   1

Definition at line 84 of file snprintf.c.

#define WIDE_INT   long

Definition at line 75 of file snprintf.c.


Typedef Documentation

typedef int bool_int

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.


Enumeration Type Documentation

enum boolean_e

Enumerator:
NO 
YES 

Definition at line 95 of file snprintf.c.

00095 { NO = 0, YES = 1 } boolean_e ;


Function Documentation

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.

References FALSE, p, and t.

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:


Generated on Sun Mar 4 16:04:19 2007 for Scilab [trunk] by  doxygen 1.5.1