Annotation of embedaddon/php/main/spprintf.c, revision 1.1.1.1
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:
19: /* $Id: spprintf.c 321634 2012-01-01 13:15:04Z felipe $ */
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: */
126: #define NUM_BUF_SIZE 2048
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: #if SUHOSIN_PATCH
394: zend_suhosin_log(S_MISC, "'Z' specifier within format string");
395: goto skip_output;
396: #else
397: zvp = (zval*) va_arg(ap, zval*);
398: zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
399: if (free_zcopy) {
400: zvp = &zcopy;
401: }
402: s_len = Z_STRLEN_P(zvp);
403: s = Z_STRVAL_P(zvp);
404: if (adjust_precision && precision < s_len) {
405: s_len = precision;
406: }
407: #endif
408: break;
409: case 'u':
410: switch(modifier) {
411: default:
412: i_num = (wide_int) va_arg(ap, unsigned int);
413: break;
414: case LM_LONG_DOUBLE:
415: goto fmt_error;
416: case LM_LONG:
417: i_num = (wide_int) va_arg(ap, unsigned long int);
418: break;
419: case LM_SIZE_T:
420: i_num = (wide_int) va_arg(ap, size_t);
421: break;
422: #if SIZEOF_LONG_LONG
423: case LM_LONG_LONG:
424: i_num = (wide_int) va_arg(ap, u_wide_int);
425: break;
426: #endif
427: #if SIZEOF_INTMAX_T
428: case LM_INTMAX_T:
429: i_num = (wide_int) va_arg(ap, uintmax_t);
430: break;
431: #endif
432: #if SIZEOF_PTRDIFF_T
433: case LM_PTRDIFF_T:
434: i_num = (wide_int) va_arg(ap, ptrdiff_t);
435: break;
436: #endif
437: }
438: /*
439: * The rest also applies to other integer formats, so fall
440: * into that case.
441: */
442: case 'd':
443: case 'i':
444: /*
445: * Get the arg if we haven't already.
446: */
447: if ((*fmt) != 'u') {
448: switch(modifier) {
449: default:
450: i_num = (wide_int) va_arg(ap, int);
451: break;
452: case LM_LONG_DOUBLE:
453: goto fmt_error;
454: case LM_LONG:
455: i_num = (wide_int) va_arg(ap, long int);
456: break;
457: case LM_SIZE_T:
458: #if SIZEOF_SSIZE_T
459: i_num = (wide_int) va_arg(ap, ssize_t);
460: #else
461: i_num = (wide_int) va_arg(ap, size_t);
462: #endif
463: break;
464: #if SIZEOF_LONG_LONG
465: case LM_LONG_LONG:
466: i_num = (wide_int) va_arg(ap, wide_int);
467: break;
468: #endif
469: #if SIZEOF_INTMAX_T
470: case LM_INTMAX_T:
471: i_num = (wide_int) va_arg(ap, intmax_t);
472: break;
473: #endif
474: #if SIZEOF_PTRDIFF_T
475: case LM_PTRDIFF_T:
476: i_num = (wide_int) va_arg(ap, ptrdiff_t);
477: break;
478: #endif
479: }
480: }
481: s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
482: &num_buf[NUM_BUF_SIZE], &s_len);
483: FIX_PRECISION(adjust_precision, precision, s, s_len);
484:
485: if (*fmt != 'u') {
486: if (is_negative)
487: prefix_char = '-';
488: else if (print_sign)
489: prefix_char = '+';
490: else if (print_blank)
491: prefix_char = ' ';
492: }
493: break;
494:
495:
496: case 'o':
497: switch(modifier) {
498: default:
499: ui_num = (u_wide_int) va_arg(ap, unsigned int);
500: break;
501: case LM_LONG_DOUBLE:
502: goto fmt_error;
503: case LM_LONG:
504: ui_num = (u_wide_int) va_arg(ap, unsigned long int);
505: break;
506: case LM_SIZE_T:
507: ui_num = (u_wide_int) va_arg(ap, size_t);
508: break;
509: #if SIZEOF_LONG_LONG
510: case LM_LONG_LONG:
511: ui_num = (u_wide_int) va_arg(ap, u_wide_int);
512: break;
513: #endif
514: #if SIZEOF_INTMAX_T
515: case LM_INTMAX_T:
516: ui_num = (u_wide_int) va_arg(ap, uintmax_t);
517: break;
518: #endif
519: #if SIZEOF_PTRDIFF_T
520: case LM_PTRDIFF_T:
521: ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
522: break;
523: #endif
524: }
525: s = ap_php_conv_p2(ui_num, 3, *fmt,
526: &num_buf[NUM_BUF_SIZE], &s_len);
527: FIX_PRECISION(adjust_precision, precision, s, s_len);
528: if (alternate_form && *s != '0') {
529: *--s = '0';
530: s_len++;
531: }
532: break;
533:
534:
535: case 'x':
536: case 'X':
537: switch(modifier) {
538: default:
539: ui_num = (u_wide_int) va_arg(ap, unsigned int);
540: break;
541: case LM_LONG_DOUBLE:
542: goto fmt_error;
543: case LM_LONG:
544: ui_num = (u_wide_int) va_arg(ap, unsigned long int);
545: break;
546: case LM_SIZE_T:
547: ui_num = (u_wide_int) va_arg(ap, size_t);
548: break;
549: #if SIZEOF_LONG_LONG
550: case LM_LONG_LONG:
551: ui_num = (u_wide_int) va_arg(ap, u_wide_int);
552: break;
553: #endif
554: #if SIZEOF_INTMAX_T
555: case LM_INTMAX_T:
556: ui_num = (u_wide_int) va_arg(ap, uintmax_t);
557: break;
558: #endif
559: #if SIZEOF_PTRDIFF_T
560: case LM_PTRDIFF_T:
561: ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
562: break;
563: #endif
564: }
565: s = ap_php_conv_p2(ui_num, 4, *fmt,
566: &num_buf[NUM_BUF_SIZE], &s_len);
567: FIX_PRECISION(adjust_precision, precision, s, s_len);
568: if (alternate_form && i_num != 0) {
569: *--s = *fmt; /* 'x' or 'X' */
570: *--s = '0';
571: s_len += 2;
572: }
573: break;
574:
575:
576: case 's':
577: case 'v':
578: s = va_arg(ap, char *);
579: if (s != NULL) {
580: if (!adjust_precision) {
581: s_len = strlen(s);
582: } else {
583: s_len = strnlen(s, precision);
584: }
585: } else {
586: s = S_NULL;
587: s_len = S_NULL_LEN;
588: }
589: pad_char = ' ';
590: break;
591:
592:
593: case 'f':
594: case 'F':
595: case 'e':
596: case 'E':
597: switch(modifier) {
598: case LM_LONG_DOUBLE:
599: fp_num = (double) va_arg(ap, long double);
600: break;
601: case LM_STD:
602: fp_num = va_arg(ap, double);
603: break;
604: default:
605: goto fmt_error;
606: }
607:
608: if (zend_isnan(fp_num)) {
609: s = "nan";
610: s_len = 3;
611: } else if (zend_isinf(fp_num)) {
612: s = "inf";
613: s_len = 3;
614: } else {
615: #ifdef HAVE_LOCALE_H
616: if (!lconv) {
617: lconv = localeconv();
618: }
619: #endif
620: s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
621: (adjust_precision == NO) ? FLOAT_DIGITS : precision,
622: (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
623: &is_negative, &num_buf[1], &s_len);
624: if (is_negative)
625: prefix_char = '-';
626: else if (print_sign)
627: prefix_char = '+';
628: else if (print_blank)
629: prefix_char = ' ';
630: }
631: break;
632:
633:
634: case 'g':
635: case 'k':
636: case 'G':
637: case 'H':
638: switch(modifier) {
639: case LM_LONG_DOUBLE:
640: fp_num = (double) va_arg(ap, long double);
641: break;
642: case LM_STD:
643: fp_num = va_arg(ap, double);
644: break;
645: default:
646: goto fmt_error;
647: }
648:
649: if (zend_isnan(fp_num)) {
650: s = "NAN";
651: s_len = 3;
652: break;
653: } else if (zend_isinf(fp_num)) {
654: if (fp_num > 0) {
655: s = "INF";
656: s_len = 3;
657: } else {
658: s = "-INF";
659: s_len = 4;
660: }
661: break;
662: }
663:
664: if (adjust_precision == NO)
665: precision = FLOAT_DIGITS;
666: else if (precision == 0)
667: precision = 1;
668: /*
669: * * We use &num_buf[ 1 ], so that we have room for the sign
670: */
671: #ifdef HAVE_LOCALE_H
672: if (!lconv) {
673: lconv = localeconv();
674: }
675: #endif
676: s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
677: if (*s == '-')
678: prefix_char = *s++;
679: else if (print_sign)
680: prefix_char = '+';
681: else if (print_blank)
682: prefix_char = ' ';
683:
684: s_len = strlen(s);
685:
686: if (alternate_form && (strchr(s, '.')) == NULL)
687: s[s_len++] = '.';
688: break;
689:
690:
691: case 'c':
692: char_buf[0] = (char) (va_arg(ap, int));
693: s = &char_buf[0];
694: s_len = 1;
695: pad_char = ' ';
696: break;
697:
698:
699: case '%':
700: char_buf[0] = '%';
701: s = &char_buf[0];
702: s_len = 1;
703: pad_char = ' ';
704: break;
705:
706:
707: case 'n':
708: #if SUHOSIN_PATCH
709: zend_suhosin_log(S_MISC, "'n' specifier within format string");
710: #else
711: *(va_arg(ap, int *)) = xbuf->len;
712: #endif
713: goto skip_output;
714:
715: /*
716: * Always extract the argument as a "char *" pointer. We
717: * should be using "void *" but there are still machines
718: * that don't understand it.
719: * If the pointer size is equal to the size of an unsigned
720: * integer we convert the pointer to a hex number, otherwise
721: * we print "%p" to indicate that we don't handle "%p".
722: */
723: case 'p':
724: if (sizeof(char *) <= sizeof(u_wide_int)) {
725: ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
726: s = ap_php_conv_p2(ui_num, 4, 'x',
727: &num_buf[NUM_BUF_SIZE], &s_len);
728: if (ui_num != 0) {
729: *--s = 'x';
730: *--s = '0';
731: s_len += 2;
732: }
733: } else {
734: s = "%p";
735: s_len = 2;
736: }
737: pad_char = ' ';
738: break;
739:
740:
741: case NUL:
742: /*
743: * The last character of the format string was %.
744: * We ignore it.
745: */
746: continue;
747:
748:
749: fmt_error:
750: php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
751: /*
752: * The default case is for unrecognized %'s.
753: * We print %<char> to help the user identify what
754: * option is not understood.
755: * This is also useful in case the user wants to pass
756: * the output of format_converter to another function
757: * that understands some other %<char> (like syslog).
758: * Note that we can't point s inside fmt because the
759: * unknown <char> could be preceded by width etc.
760: */
761: default:
762: char_buf[0] = '%';
763: char_buf[1] = *fmt;
764: s = char_buf;
765: s_len = 2;
766: pad_char = ' ';
767: break;
768: }
769:
770: if (prefix_char != NUL) {
771: *--s = prefix_char;
772: s_len++;
773: }
774: if (adjust_width && adjust == RIGHT && min_width > s_len) {
775: if (pad_char == '0' && prefix_char != NUL) {
776: INS_CHAR(xbuf, *s);
777: s++;
778: s_len--;
779: min_width--;
780: }
781: PAD(xbuf, min_width - s_len, pad_char);
782: }
783: /*
784: * Print the string s.
785: */
786: INS_STRING(xbuf, s, s_len);
787:
788: if (adjust_width && adjust == LEFT && min_width > s_len)
789: PAD(xbuf, min_width - s_len, pad_char);
790: if (free_zcopy) {
791: zval_dtor(&zcopy);
792: }
793: }
794: skip_output:
795: fmt++;
796: }
797: return;
798: }
799: /* }}} */
800:
801: /*
802: * This is the general purpose conversion function.
803: */
804: PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) /* {{{ */
805: {
806: smart_str xbuf = {0};
807:
808: xbuf_format_converter(&xbuf, format, ap);
809:
810: if (max_len && xbuf.len > max_len) {
811: xbuf.len = max_len;
812: }
813: smart_str_0(&xbuf);
814:
815: *pbuf = xbuf.c;
816:
817: return xbuf.len;
818: }
819: /* }}} */
820:
821: PHPAPI int spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ */
822: {
823: int cc;
824: va_list ap;
825:
826: va_start(ap, format);
827: cc = vspprintf(pbuf, max_len, format, ap);
828: va_end(ap);
829: return (cc);
830: }
831: /* }}} */
832:
833: /*
834: * Local variables:
835: * tab-width: 4
836: * c-basic-offset: 4
837: * End:
838: * vim600: sw=4 ts=4 fdm=marker
839: * vim<600: sw=4 ts=4
840: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>