Annotation of embedaddon/php/main/spprintf.c, revision 1.1.1.2
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 The PHP Group |
6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Author: Marcus Boerger <helly@php.net> |
16: +----------------------------------------------------------------------+
17: */
18:
1.1.1.2 ! misho 19: /* $Id$ */
1.1 misho 20:
21: /* This is the spprintf implementation.
22: * It has emerged from apache snprintf. See original header:
23: */
24:
25: /* ====================================================================
26: * Copyright (c) 1995-1998 The Apache Group. All rights reserved.
27: *
28: * Redistribution and use in source and binary forms, with or without
29: * modification, are permitted provided that the following conditions
30: * are met:
31: *
32: * 1. Redistributions of source code must retain the above copyright
33: * notice, this list of conditions and the following disclaimer.
34: *
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in
37: * the documentation and/or other materials provided with the
38: * distribution.
39: *
40: * 3. All advertising materials mentioning features or use of this
41: * software must display the following acknowledgment:
42: * "This product includes software developed by the Apache Group
43: * for use in the Apache HTTP server project (http://www.apache.org/)."
44: *
45: * 4. The names "Apache Server" and "Apache Group" must not be used to
46: * endorse or promote products derived from this software without
47: * prior written permission.
48: *
49: * 5. Redistributions of any form whatsoever must retain the following
50: * acknowledgment:
51: * "This product includes software developed by the Apache Group
52: * for use in the Apache HTTP server project (http://www.apache.org/)."
53: *
54: * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
55: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
58: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
60: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
63: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
64: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
65: * OF THE POSSIBILITY OF SUCH DAMAGE.
66: * ====================================================================
67: *
68: * This software consists of voluntary contributions made by many
69: * individuals on behalf of the Apache Group and was originally based
70: * on public domain software written at the National Center for
71: * Supercomputing Applications, University of Illinois, Urbana-Champaign.
72: * For more information on the Apache Group and the Apache HTTP server
73: * project, please see <http://www.apache.org/>.
74: *
75: * This code is based on, and used with the permission of, the
76: * SIO stdio-replacement strx_* functions by Panos Tsirigotis
77: * <panos@alumni.cs.colorado.edu> for xinetd.
78: */
79: #define _GNU_SOURCE
80: #include "php.h"
81:
82: #include <stddef.h>
83: #include <stdio.h>
84: #include <ctype.h>
85: #include <sys/types.h>
86: #include <stdarg.h>
87: #include <string.h>
88: #include <stdlib.h>
89: #include <math.h>
90: #ifdef HAVE_INTTYPES_H
91: #include <inttypes.h>
92: #endif
93:
94: #ifdef HAVE_LOCALE_H
95: #include <locale.h>
96: #define LCONV_DECIMAL_POINT (*lconv->decimal_point)
97: #else
98: #define LCONV_DECIMAL_POINT '.'
99: #endif
100:
101: #include "snprintf.h"
102:
103: #define FALSE 0
104: #define TRUE 1
105: #define NUL '\0'
106: #define INT_NULL ((int *)0)
107:
108: #define S_NULL "(null)"
109: #define S_NULL_LEN 6
110:
111: #define FLOAT_DIGITS 6
112: #define EXPONENT_LENGTH 10
113:
114: #include "ext/standard/php_smart_str.h"
115:
116: /* {{{ macros */
117:
118: /*
119: * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
120: *
121: * XXX: this is a magic number; do not decrease it
122: * Emax = 1023
123: * NDIG = 320
124: * NUM_BUF_SIZE >= strlen("-") + Emax + strlrn(".") + NDIG + strlen("E+1023") + 1;
125: */
1.1.1.2 ! misho 126: #define NUM_BUF_SIZE 2048
1.1 misho 127:
128: /*
129: * The INS_CHAR macro inserts a character in the buffer.
130: *
131: * NOTE: Evaluation of the ch argument should not have any side-effects
132: */
133: #define INS_CHAR_NR(xbuf, ch) do { \
134: smart_str_appendc(xbuf, ch); \
135: } while (0)
136:
137: #define INS_STRING(xbuf, s, slen) do { \
138: smart_str_appendl(xbuf, s, slen); \
139: } while (0)
140:
141: #define INS_CHAR(xbuf, ch) \
142: INS_CHAR_NR(xbuf, ch)
143:
144: /*
145: * Macro that does padding. The padding is done by printing
146: * the character ch.
147: */
148: #define PAD(xbuf, count, ch) do { \
149: if ((count) > 0) { \
150: size_t newlen; \
151: smart_str_alloc(xbuf, (count), 0); \
152: memset(xbuf->c + xbuf->len, ch, (count)); \
153: xbuf->len += (count); \
154: } \
155: } while (0)
156:
157: #define NUM(c) (c - '0')
158:
159: #define STR_TO_DEC(str, num) do { \
160: num = NUM(*str++); \
161: while (isdigit((int)*str)) { \
162: num *= 10; \
163: num += NUM(*str++); \
164: if (num >= INT_MAX / 10) { \
165: while (isdigit((int)*str++)); \
166: break; \
167: } \
168: } \
169: } while (0)
170:
171: /*
172: * This macro does zero padding so that the precision
173: * requirement is satisfied. The padding is done by
174: * adding '0's to the left of the string that is going
175: * to be printed.
176: */
177: #define FIX_PRECISION(adjust, precision, s, s_len) do { \
178: if (adjust) \
179: while (s_len < precision) { \
180: *--s = '0'; \
181: s_len++; \
182: } \
183: } while (0)
184:
185: /* }}} */
186:
187:
188: #if !HAVE_STRNLEN
189: static size_t strnlen(const char *s, size_t maxlen) {
190: char *r = memchr(s, '\0', maxlen);
191: return r ? r-s : maxlen;
192: }
193: #endif
194:
195: /*
196: * Do format conversion placing the output in buffer
197: */
198: static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap) /* {{{ */
199: {
200: char *s = NULL;
201: int s_len, free_zcopy;
202: zval *zvp, zcopy;
203:
204: int min_width = 0;
205: int precision = 0;
206: enum {
207: LEFT, RIGHT
208: } adjust;
209: char pad_char;
210: char prefix_char;
211:
212: double fp_num;
213: wide_int i_num = (wide_int) 0;
214: u_wide_int ui_num;
215:
216: char num_buf[NUM_BUF_SIZE];
217: char char_buf[2]; /* for printing %% and %<unknown> */
218:
219: #ifdef HAVE_LOCALE_H
220: struct lconv *lconv = NULL;
221: #endif
222:
223: /*
224: * Flag variables
225: */
226: length_modifier_e modifier;
227: boolean_e alternate_form;
228: boolean_e print_sign;
229: boolean_e print_blank;
230: boolean_e adjust_precision;
231: boolean_e adjust_width;
232: bool_int is_negative;
233:
234: while (*fmt) {
235: if (*fmt != '%') {
236: INS_CHAR(xbuf, *fmt);
237: } else {
238: /*
239: * Default variable settings
240: */
241: adjust = RIGHT;
242: alternate_form = print_sign = print_blank = NO;
243: pad_char = ' ';
244: prefix_char = NUL;
245: free_zcopy = 0;
246:
247: fmt++;
248:
249: /*
250: * Try to avoid checking for flags, width or precision
251: */
252: if (isascii((int)*fmt) && !islower((int)*fmt)) {
253: /*
254: * Recognize flags: -, #, BLANK, +
255: */
256: for (;; fmt++) {
257: if (*fmt == '-')
258: adjust = LEFT;
259: else if (*fmt == '+')
260: print_sign = YES;
261: else if (*fmt == '#')
262: alternate_form = YES;
263: else if (*fmt == ' ')
264: print_blank = YES;
265: else if (*fmt == '0')
266: pad_char = '0';
267: else
268: break;
269: }
270:
271: /*
272: * Check if a width was specified
273: */
274: if (isdigit((int)*fmt)) {
275: STR_TO_DEC(fmt, min_width);
276: adjust_width = YES;
277: } else if (*fmt == '*') {
278: min_width = va_arg(ap, int);
279: fmt++;
280: adjust_width = YES;
281: if (min_width < 0) {
282: adjust = LEFT;
283: min_width = -min_width;
284: }
285: } else
286: adjust_width = NO;
287:
288: /*
289: * Check if a precision was specified
290: */
291: if (*fmt == '.') {
292: adjust_precision = YES;
293: fmt++;
294: if (isdigit((int)*fmt)) {
295: STR_TO_DEC(fmt, precision);
296: } else if (*fmt == '*') {
297: precision = va_arg(ap, int);
298: fmt++;
299: if (precision < 0)
300: precision = 0;
301: } else
302: precision = 0;
303:
304: if (precision > FORMAT_CONV_MAX_PRECISION) {
305: precision = FORMAT_CONV_MAX_PRECISION;
306: }
307: } else
308: adjust_precision = NO;
309: } else
310: adjust_precision = adjust_width = NO;
311:
312: /*
313: * Modifier check
314: */
315: switch (*fmt) {
316: case 'L':
317: fmt++;
318: modifier = LM_LONG_DOUBLE;
319: break;
320: case 'I':
321: fmt++;
322: #if SIZEOF_LONG_LONG
323: if (*fmt == '6' && *(fmt+1) == '4') {
324: fmt += 2;
325: modifier = LM_LONG_LONG;
326: } else
327: #endif
328: if (*fmt == '3' && *(fmt+1) == '2') {
329: fmt += 2;
330: modifier = LM_LONG;
331: } else {
332: #ifdef _WIN64
333: modifier = LM_LONG_LONG;
334: #else
335: modifier = LM_LONG;
336: #endif
337: }
338: break;
339: case 'l':
340: fmt++;
341: #if SIZEOF_LONG_LONG
342: if (*fmt == 'l') {
343: fmt++;
344: modifier = LM_LONG_LONG;
345: } else
346: #endif
347: modifier = LM_LONG;
348: break;
349: case 'z':
350: fmt++;
351: modifier = LM_SIZE_T;
352: break;
353: case 'j':
354: fmt++;
355: #if SIZEOF_INTMAX_T
356: modifier = LM_INTMAX_T;
357: #else
358: modifier = LM_SIZE_T;
359: #endif
360: break;
361: case 't':
362: fmt++;
363: #if SIZEOF_PTRDIFF_T
364: modifier = LM_PTRDIFF_T;
365: #else
366: modifier = LM_SIZE_T;
367: #endif
368: break;
369: case 'h':
370: fmt++;
371: if (*fmt == 'h') {
372: fmt++;
373: }
374: /* these are promoted to int, so no break */
375: default:
376: modifier = LM_STD;
377: break;
378: }
379:
380: /*
381: * Argument extraction and printing.
382: * First we determine the argument type.
383: * Then, we convert the argument to a string.
384: * On exit from the switch, s points to the string that
385: * must be printed, s_len has the length of the string
386: * The precision requirements, if any, are reflected in s_len.
387: *
388: * NOTE: pad_char may be set to '0' because of the 0 flag.
389: * It is reset to ' ' by non-numeric formats
390: */
391: switch (*fmt) {
392: case 'Z':
393: zvp = (zval*) va_arg(ap, zval*);
394: zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
395: if (free_zcopy) {
396: zvp = &zcopy;
397: }
398: s_len = Z_STRLEN_P(zvp);
399: s = Z_STRVAL_P(zvp);
400: if (adjust_precision && precision < s_len) {
401: s_len = precision;
402: }
403: break;
404: case 'u':
405: switch(modifier) {
406: default:
407: i_num = (wide_int) va_arg(ap, unsigned int);
408: break;
409: case LM_LONG_DOUBLE:
410: goto fmt_error;
411: case LM_LONG:
412: i_num = (wide_int) va_arg(ap, unsigned long int);
413: break;
414: case LM_SIZE_T:
415: i_num = (wide_int) va_arg(ap, size_t);
416: break;
417: #if SIZEOF_LONG_LONG
418: case LM_LONG_LONG:
419: i_num = (wide_int) va_arg(ap, u_wide_int);
420: break;
421: #endif
422: #if SIZEOF_INTMAX_T
423: case LM_INTMAX_T:
424: i_num = (wide_int) va_arg(ap, uintmax_t);
425: break;
426: #endif
427: #if SIZEOF_PTRDIFF_T
428: case LM_PTRDIFF_T:
429: i_num = (wide_int) va_arg(ap, ptrdiff_t);
430: break;
431: #endif
432: }
433: /*
434: * The rest also applies to other integer formats, so fall
435: * into that case.
436: */
437: case 'd':
438: case 'i':
439: /*
440: * Get the arg if we haven't already.
441: */
442: if ((*fmt) != 'u') {
443: switch(modifier) {
444: default:
445: i_num = (wide_int) va_arg(ap, int);
446: break;
447: case LM_LONG_DOUBLE:
448: goto fmt_error;
449: case LM_LONG:
450: i_num = (wide_int) va_arg(ap, long int);
451: break;
452: case LM_SIZE_T:
453: #if SIZEOF_SSIZE_T
454: i_num = (wide_int) va_arg(ap, ssize_t);
455: #else
456: i_num = (wide_int) va_arg(ap, size_t);
457: #endif
458: break;
459: #if SIZEOF_LONG_LONG
460: case LM_LONG_LONG:
461: i_num = (wide_int) va_arg(ap, wide_int);
462: break;
463: #endif
464: #if SIZEOF_INTMAX_T
465: case LM_INTMAX_T:
466: i_num = (wide_int) va_arg(ap, intmax_t);
467: break;
468: #endif
469: #if SIZEOF_PTRDIFF_T
470: case LM_PTRDIFF_T:
471: i_num = (wide_int) va_arg(ap, ptrdiff_t);
472: break;
473: #endif
474: }
475: }
476: s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
477: &num_buf[NUM_BUF_SIZE], &s_len);
478: FIX_PRECISION(adjust_precision, precision, s, s_len);
479:
480: if (*fmt != 'u') {
481: if (is_negative)
482: prefix_char = '-';
483: else if (print_sign)
484: prefix_char = '+';
485: else if (print_blank)
486: prefix_char = ' ';
487: }
488: break;
489:
490:
491: case 'o':
492: switch(modifier) {
493: default:
494: ui_num = (u_wide_int) va_arg(ap, unsigned int);
495: break;
496: case LM_LONG_DOUBLE:
497: goto fmt_error;
498: case LM_LONG:
499: ui_num = (u_wide_int) va_arg(ap, unsigned long int);
500: break;
501: case LM_SIZE_T:
502: ui_num = (u_wide_int) va_arg(ap, size_t);
503: break;
504: #if SIZEOF_LONG_LONG
505: case LM_LONG_LONG:
506: ui_num = (u_wide_int) va_arg(ap, u_wide_int);
507: break;
508: #endif
509: #if SIZEOF_INTMAX_T
510: case LM_INTMAX_T:
511: ui_num = (u_wide_int) va_arg(ap, uintmax_t);
512: break;
513: #endif
514: #if SIZEOF_PTRDIFF_T
515: case LM_PTRDIFF_T:
516: ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
517: break;
518: #endif
519: }
520: s = ap_php_conv_p2(ui_num, 3, *fmt,
521: &num_buf[NUM_BUF_SIZE], &s_len);
522: FIX_PRECISION(adjust_precision, precision, s, s_len);
523: if (alternate_form && *s != '0') {
524: *--s = '0';
525: s_len++;
526: }
527: break;
528:
529:
530: case 'x':
531: case 'X':
532: switch(modifier) {
533: default:
534: ui_num = (u_wide_int) va_arg(ap, unsigned int);
535: break;
536: case LM_LONG_DOUBLE:
537: goto fmt_error;
538: case LM_LONG:
539: ui_num = (u_wide_int) va_arg(ap, unsigned long int);
540: break;
541: case LM_SIZE_T:
542: ui_num = (u_wide_int) va_arg(ap, size_t);
543: break;
544: #if SIZEOF_LONG_LONG
545: case LM_LONG_LONG:
546: ui_num = (u_wide_int) va_arg(ap, u_wide_int);
547: break;
548: #endif
549: #if SIZEOF_INTMAX_T
550: case LM_INTMAX_T:
551: ui_num = (u_wide_int) va_arg(ap, uintmax_t);
552: break;
553: #endif
554: #if SIZEOF_PTRDIFF_T
555: case LM_PTRDIFF_T:
556: ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
557: break;
558: #endif
559: }
560: s = ap_php_conv_p2(ui_num, 4, *fmt,
561: &num_buf[NUM_BUF_SIZE], &s_len);
562: FIX_PRECISION(adjust_precision, precision, s, s_len);
563: if (alternate_form && i_num != 0) {
564: *--s = *fmt; /* 'x' or 'X' */
565: *--s = '0';
566: s_len += 2;
567: }
568: break;
569:
570:
571: case 's':
572: case 'v':
573: s = va_arg(ap, char *);
574: if (s != NULL) {
575: if (!adjust_precision) {
576: s_len = strlen(s);
577: } else {
578: s_len = strnlen(s, precision);
579: }
580: } else {
581: s = S_NULL;
582: s_len = S_NULL_LEN;
583: }
584: pad_char = ' ';
585: break;
586:
587:
588: case 'f':
589: case 'F':
590: case 'e':
591: case 'E':
592: switch(modifier) {
593: case LM_LONG_DOUBLE:
594: fp_num = (double) va_arg(ap, long double);
595: break;
596: case LM_STD:
597: fp_num = va_arg(ap, double);
598: break;
599: default:
600: goto fmt_error;
601: }
602:
603: if (zend_isnan(fp_num)) {
604: s = "nan";
605: s_len = 3;
606: } else if (zend_isinf(fp_num)) {
607: s = "inf";
608: s_len = 3;
609: } else {
610: #ifdef HAVE_LOCALE_H
611: if (!lconv) {
612: lconv = localeconv();
613: }
614: #endif
615: s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
616: (adjust_precision == NO) ? FLOAT_DIGITS : precision,
617: (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
618: &is_negative, &num_buf[1], &s_len);
619: if (is_negative)
620: prefix_char = '-';
621: else if (print_sign)
622: prefix_char = '+';
623: else if (print_blank)
624: prefix_char = ' ';
625: }
626: break;
627:
628:
629: case 'g':
630: case 'k':
631: case 'G':
632: case 'H':
633: switch(modifier) {
634: case LM_LONG_DOUBLE:
635: fp_num = (double) va_arg(ap, long double);
636: break;
637: case LM_STD:
638: fp_num = va_arg(ap, double);
639: break;
640: default:
641: goto fmt_error;
642: }
643:
644: if (zend_isnan(fp_num)) {
645: s = "NAN";
646: s_len = 3;
647: break;
648: } else if (zend_isinf(fp_num)) {
649: if (fp_num > 0) {
650: s = "INF";
651: s_len = 3;
652: } else {
653: s = "-INF";
654: s_len = 4;
655: }
656: break;
657: }
658:
659: if (adjust_precision == NO)
660: precision = FLOAT_DIGITS;
661: else if (precision == 0)
662: precision = 1;
663: /*
664: * * We use &num_buf[ 1 ], so that we have room for the sign
665: */
666: #ifdef HAVE_LOCALE_H
667: if (!lconv) {
668: lconv = localeconv();
669: }
670: #endif
671: s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
672: if (*s == '-')
673: prefix_char = *s++;
674: else if (print_sign)
675: prefix_char = '+';
676: else if (print_blank)
677: prefix_char = ' ';
678:
679: s_len = strlen(s);
680:
681: if (alternate_form && (strchr(s, '.')) == NULL)
682: s[s_len++] = '.';
683: break;
684:
685:
686: case 'c':
687: char_buf[0] = (char) (va_arg(ap, int));
688: s = &char_buf[0];
689: s_len = 1;
690: pad_char = ' ';
691: break;
692:
693:
694: case '%':
695: char_buf[0] = '%';
696: s = &char_buf[0];
697: s_len = 1;
698: pad_char = ' ';
699: break;
700:
701:
702: case 'n':
703: *(va_arg(ap, int *)) = xbuf->len;
704: goto skip_output;
705:
706: /*
707: * Always extract the argument as a "char *" pointer. We
708: * should be using "void *" but there are still machines
709: * that don't understand it.
710: * If the pointer size is equal to the size of an unsigned
711: * integer we convert the pointer to a hex number, otherwise
712: * we print "%p" to indicate that we don't handle "%p".
713: */
714: case 'p':
715: if (sizeof(char *) <= sizeof(u_wide_int)) {
716: ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
717: s = ap_php_conv_p2(ui_num, 4, 'x',
718: &num_buf[NUM_BUF_SIZE], &s_len);
719: if (ui_num != 0) {
720: *--s = 'x';
721: *--s = '0';
722: s_len += 2;
723: }
724: } else {
725: s = "%p";
726: s_len = 2;
727: }
728: pad_char = ' ';
729: break;
730:
731:
732: case NUL:
733: /*
734: * The last character of the format string was %.
735: * We ignore it.
736: */
737: continue;
738:
739:
740: fmt_error:
741: php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
742: /*
743: * The default case is for unrecognized %'s.
744: * We print %<char> to help the user identify what
745: * option is not understood.
746: * This is also useful in case the user wants to pass
747: * the output of format_converter to another function
748: * that understands some other %<char> (like syslog).
749: * Note that we can't point s inside fmt because the
750: * unknown <char> could be preceded by width etc.
751: */
752: default:
753: char_buf[0] = '%';
754: char_buf[1] = *fmt;
755: s = char_buf;
756: s_len = 2;
757: pad_char = ' ';
758: break;
759: }
760:
761: if (prefix_char != NUL) {
762: *--s = prefix_char;
763: s_len++;
764: }
765: if (adjust_width && adjust == RIGHT && min_width > s_len) {
766: if (pad_char == '0' && prefix_char != NUL) {
767: INS_CHAR(xbuf, *s);
768: s++;
769: s_len--;
770: min_width--;
771: }
772: PAD(xbuf, min_width - s_len, pad_char);
773: }
774: /*
775: * Print the string s.
776: */
777: INS_STRING(xbuf, s, s_len);
778:
779: if (adjust_width && adjust == LEFT && min_width > s_len)
780: PAD(xbuf, min_width - s_len, pad_char);
781: if (free_zcopy) {
782: zval_dtor(&zcopy);
783: }
784: }
785: skip_output:
786: fmt++;
787: }
788: return;
789: }
790: /* }}} */
791:
792: /*
793: * This is the general purpose conversion function.
794: */
795: PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */
796: {
797: smart_str xbuf = {0};
798:
799: xbuf_format_converter(&xbuf, format, ap);
800:
801: if (max_len && xbuf.len > max_len) {
802: xbuf.len = max_len;
803: }
804: smart_str_0(&xbuf);
805:
806: *pbuf = xbuf.c;
807:
808: return xbuf.len;
809: }
810: /* }}} */
811:
812: PHPAPI int spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ */
813: {
814: int cc;
815: va_list ap;
816:
817: va_start(ap, format);
818: cc = vspprintf(pbuf, max_len, format, ap);
819: va_end(ap);
820: return (cc);
821: }
822: /* }}} */
823:
824: /*
825: * Local variables:
826: * tab-width: 4
827: * c-basic-offset: 4
828: * End:
829: * vim600: sw=4 ts=4 fdm=marker
830: * vim<600: sw=4 ts=4
831: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>