📄 apr_snprintf.c
字号:
else
i_num = (wide_int) va_arg(ap, int);
s = conv_10(i_num, 0, &is_negative,
&num_buf[NUM_BUF_SIZE], &s_len);
}
FIX_PRECISION(adjust_precision, precision, s, s_len);
if (is_negative)
prefix_char = '-';
else if (print_sign)
prefix_char = '+';
else if (print_blank)
prefix_char = ' ';
break;
case 'o':
if (var_type == IS_QUAD) {
ui_quad = va_arg(ap, u_widest_int);
s = conv_p2_quad(ui_quad, 3, *fmt,
&num_buf[NUM_BUF_SIZE], &s_len);
}
else {
if (var_type == IS_LONG)
ui_num = (u_wide_int) va_arg(ap, u_wide_int);
else if (var_type == IS_SHORT)
ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
else
ui_num = (u_wide_int) va_arg(ap, unsigned int);
s = conv_p2(ui_num, 3, *fmt,
&num_buf[NUM_BUF_SIZE], &s_len);
}
FIX_PRECISION(adjust_precision, precision, s, s_len);
if (alternate_form && *s != '0') {
*--s = '0';
s_len++;
}
break;
case 'x':
case 'X':
if (var_type == IS_QUAD) {
ui_quad = va_arg(ap, u_widest_int);
s = conv_p2_quad(ui_quad, 4, *fmt,
&num_buf[NUM_BUF_SIZE], &s_len);
}
else {
if (var_type == IS_LONG)
ui_num = (u_wide_int) va_arg(ap, u_wide_int);
else if (var_type == IS_SHORT)
ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int);
else
ui_num = (u_wide_int) va_arg(ap, unsigned int);
s = conv_p2(ui_num, 4, *fmt,
&num_buf[NUM_BUF_SIZE], &s_len);
}
FIX_PRECISION(adjust_precision, precision, s, s_len);
if (alternate_form && i_num != 0) {
*--s = *fmt; /* 'x' or 'X' */
*--s = '0';
s_len += 2;
}
break;
case 's':
s = va_arg(ap, char *);
if (s != NULL) {
if (!adjust_precision) {
s_len = strlen(s);
}
else {
/* From the C library standard in section 7.9.6.1:
* ...if the precision is specified, no more then
* that many characters are written. If the
* precision is not specified or is greater
* than the size of the array, the array shall
* contain a null character.
*
* My reading is is precision is specified and
* is less then or equal to the size of the
* array, no null character is required. So
* we can't do a strlen.
*
* This figures out the length of the string
* up to the precision. Once it's long enough
* for the specified precision, we don't care
* anymore.
*
* NOTE: you must do the length comparison
* before the check for the null character.
* Otherwise, you'll check one beyond the
* last valid character.
*/
const char *walk;
for (walk = s, s_len = 0;
(s_len < precision) && (*walk != '\0');
++walk, ++s_len);
}
}
else {
s = S_NULL;
s_len = S_NULL_LEN;
}
pad_char = ' ';
break;
case 'f':
case 'e':
case 'E':
fp_num = va_arg(ap, double);
/*
* We use &num_buf[ 1 ], so that we have room for the sign
*/
s = NULL;
#ifdef HAVE_ISNAN
if (isnan(fp_num)) {
s = "nan";
s_len = 3;
}
#endif
#ifdef HAVE_ISINF
if (!s && isinf(fp_num)) {
s = "inf";
s_len = 3;
}
#endif
if (!s) {
s = conv_fp(*fmt, fp_num, alternate_form,
(adjust_precision == NO) ? FLOAT_DIGITS : precision,
&is_negative, &num_buf[1], &s_len);
if (is_negative)
prefix_char = '-';
else if (print_sign)
prefix_char = '+';
else if (print_blank)
prefix_char = ' ';
}
break;
case 'g':
case 'G':
if (adjust_precision == NO)
precision = FLOAT_DIGITS;
else if (precision == 0)
precision = 1;
/*
* * We use &num_buf[ 1 ], so that we have room for the sign
*/
s = apr_gcvt(va_arg(ap, double), precision, &num_buf[1],
alternate_form);
if (*s == '-')
prefix_char = *s++;
else if (print_sign)
prefix_char = '+';
else if (print_blank)
prefix_char = ' ';
s_len = strlen(s);
if (alternate_form && (q = strchr(s, '.')) == NULL) {
s[s_len++] = '.';
s[s_len] = '\0'; /* delimit for following strchr() */
}
if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL)
*q = 'E';
break;
case 'c':
char_buf[0] = (char) (va_arg(ap, int));
s = &char_buf[0];
s_len = 1;
pad_char = ' ';
break;
case '%':
char_buf[0] = '%';
s = &char_buf[0];
s_len = 1;
pad_char = ' ';
break;
case 'n':
if (var_type == IS_QUAD)
*(va_arg(ap, widest_int *)) = cc;
else if (var_type == IS_LONG)
*(va_arg(ap, long *)) = cc;
else if (var_type == IS_SHORT)
*(va_arg(ap, short *)) = cc;
else
*(va_arg(ap, int *)) = cc;
print_something = NO;
break;
/*
* This is where we extend the printf format, with a second
* type specifier
*/
case 'p':
switch(*++fmt) {
/*
* If the pointer size is equal to or smaller than the size
* of the largest unsigned int, we convert the pointer to a
* hex number, otherwise we print "%p" to indicate that we
* don't handle "%p".
*/
case 'p':
#if APR_SIZEOF_VOIDP == 8
if (sizeof(void *) <= sizeof(u_widest_int)) {
ui_quad = (u_widest_int) va_arg(ap, void *);
s = conv_p2_quad(ui_quad, 4, 'x',
&num_buf[NUM_BUF_SIZE], &s_len);
}
#else
if (sizeof(void *) <= sizeof(u_wide_int)) {
ui_num = (u_wide_int) va_arg(ap, void *);
s = conv_p2(ui_num, 4, 'x',
&num_buf[NUM_BUF_SIZE], &s_len);
}
#endif
else {
s = "%p";
s_len = 2;
prefix_char = NUL;
}
pad_char = ' ';
break;
/* print an apr_sockaddr_t as a.b.c.d:port */
case 'I':
{
apr_sockaddr_t *sa;
sa = va_arg(ap, apr_sockaddr_t *);
if (sa != NULL) {
s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len);
if (adjust_precision && precision < s_len)
s_len = precision;
}
else {
s = S_NULL;
s_len = S_NULL_LEN;
}
pad_char = ' ';
}
break;
/* print a struct in_addr as a.b.c.d */
case 'A':
{
struct in_addr *ia;
ia = va_arg(ap, struct in_addr *);
if (ia != NULL) {
s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len);
if (adjust_precision && precision < s_len)
s_len = precision;
}
else {
s = S_NULL;
s_len = S_NULL_LEN;
}
pad_char = ' ';
}
break;
case 'T':
#if APR_HAS_THREADS
{
apr_os_thread_t *tid;
tid = va_arg(ap, apr_os_thread_t *);
if (tid != NULL) {
s = conv_os_thread_t(tid, &num_buf[NUM_BUF_SIZE], &s_len);
if (adjust_precision && precision < s_len)
s_len = precision;
}
else {
s = S_NULL;
s_len = S_NULL_LEN;
}
pad_char = ' ';
}
#else
char_buf[0] = '0';
s = &char_buf[0];
s_len = 1;
pad_char = ' ';
#endif
break;
case NUL:
/* if %p ends the string, oh well ignore it */
continue;
default:
s = "bogus %p";
s_len = 8;
prefix_char = NUL;
(void)va_arg(ap, void *); /* skip the bogus argument on the stack */
break;
}
break;
case NUL:
/*
* The last character of the format string was %.
* We ignore it.
*/
continue;
/*
* The default case is for unrecognized %'s.
* We print %<char> to help the user identify what
* option is not understood.
* This is also useful in case the user wants to pass
* the output of format_converter to another function
* that understands some other %<char> (like syslog).
* Note that we can't point s inside fmt because the
* unknown <char> could be preceded by width etc.
*/
default:
char_buf[0] = '%';
char_buf[1] = *fmt;
s = char_buf;
s_len = 2;
pad_char = ' ';
break;
}
if (prefix_char != NUL && s != S_NULL && s != char_buf) {
*--s = prefix_char;
s_len++;
}
if (adjust_width && adjust == RIGHT && min_width > s_len) {
if (pad_char == '0' && prefix_char != NUL) {
INS_CHAR(*s, sp, bep, cc);
s++;
s_len--;
min_width--;
}
PAD(min_width, s_len, pad_char);
}
/*
* Print the string s.
*/
if (print_something == YES) {
for (i = s_len; i != 0; i--) {
INS_CHAR(*s, sp, bep, cc);
s++;
}
}
if (adjust_width && adjust == LEFT && min_width > s_len)
PAD(min_width, s_len, pad_char);
}
fmt++;
}
vbuff->curpos = sp;
return cc;
}
static int snprintf_flush(apr_vformatter_buff_t *vbuff)
{
/* if the buffer fills we have to abort immediately, there is no way
* to "flush" an apr_snprintf... there's nowhere to flush it to.
*/
return -1;
}
APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len,
const char *format, ...)
{
int cc;
va_list ap;
apr_vformatter_buff_t vbuff;
if (len == 0) {
/* NOTE: This is a special case; we just want to return the number
* of chars that would be written (minus \0) if the buffer
* size was infinite. We leverage the fact that INS_CHAR
* just does actual inserts iff the buffer pointer is non-NULL.
* In this case, we don't care what buf is; it can be NULL, since
* we don't touch it at all.
*/
vbuff.curpos = NULL;
vbuff.endpos = NULL;
} else {
/* save one byte for nul terminator */
vbuff.curpos = buf;
vbuff.endpos = buf + len - 1;
}
va_start(ap, format);
cc = apr_vformatter(snprintf_flush, &vbuff, format, ap);
va_end(ap);
if (len != 0) {
*vbuff.curpos = '\0';
}
return (cc == -1) ? (int)len : cc;
}
APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format,
va_list ap)
{
int cc;
apr_vformatter_buff_t vbuff;
if (len == 0) {
/* See above note */
vbuff.curpos = NULL;
vbuff.endpos = NULL;
} else {
/* save one byte for nul terminator */
vbuff.curpos = buf;
vbuff.endpos = buf + len - 1;
}
cc = apr_vformatter(snprintf_flush, &vbuff, format, ap);
if (len != 0) {
*vbuff.curpos = '\0';
}
return (cc == -1) ? (int)len : cc;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -