~ubuntu-branches/ubuntu/quantal/php5/quantal

« back to all changes in this revision

Viewing changes to main/snprintf.c

  • Committer: Bazaar Package Importer
  • Author(s): Sean Finney
  • Date: 2009-07-01 09:12:10 UTC
  • mto: (0.9.1) (1.1.17 upstream)
  • mto: This revision was merged to the branch mainline in revision 58.
  • Revision ID: james.westby@ubuntu.com-20090701091210-go0h6506p62on17r
Tags: upstream-5.3.0
ImportĀ upstreamĀ versionĀ 5.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  +----------------------------------------------------------------------+
 
3
  | PHP Version 5                                                        |
 
4
  +----------------------------------------------------------------------+
 
5
  | Copyright (c) 1997-2009 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:                                                              |
 
16
  +----------------------------------------------------------------------+
 
17
*/
 
18
 
 
19
/* $Id: snprintf.c,v 1.37.2.4.2.14.2.8 2008/12/31 11:15:48 sebastian Exp $ */
 
20
 
 
21
 
 
22
#include "php.h"
 
23
 
 
24
#include <zend_strtod.h>
 
25
 
 
26
#include <stddef.h>
 
27
#include <stdio.h>
 
28
#include <ctype.h>
 
29
#include <sys/types.h>
 
30
#include <stdarg.h>
 
31
#include <string.h>
 
32
#include <stdlib.h>
 
33
#include <math.h>
 
34
 
 
35
#ifdef HAVE_INTTYPES_H
 
36
#include <inttypes.h>
 
37
#endif
 
38
 
 
39
#ifdef HAVE_LOCALE_H
 
40
#include <locale.h>
 
41
#define LCONV_DECIMAL_POINT (*lconv->decimal_point)
 
42
#else
 
43
#define LCONV_DECIMAL_POINT '.'
 
44
#endif
 
45
 
 
46
/*
 
47
 * Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
 
48
 *
 
49
 * Permission to use, copy, modify, and distribute this software for any
 
50
 * purpose with or without fee is hereby granted, provided that the above
 
51
 * copyright notice and this permission notice appear in all copies.
 
52
 *
 
53
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 
54
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 
55
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 
56
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
57
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
58
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 
59
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
60
 *
 
61
 * Sponsored in part by the Defense Advanced Research Projects
 
62
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
 
63
 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
 
64
 */
 
65
 
 
66
static char * __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad) /* {{{ */
 
67
{
 
68
        register char *s = NULL;
 
69
        char *p, *rve, c;
 
70
        size_t siz;
 
71
 
 
72
        if (ndigit < 0) {
 
73
                siz = -ndigit + 1;
 
74
        } else {
 
75
                siz = ndigit + 1;
 
76
        }
 
77
 
 
78
        /* __dtoa() doesn't allocate space for 0 so we do it by hand */
 
79
        if (value == 0.0) {
 
80
                *decpt = 1 - fmode; /* 1 for 'e', 0 for 'f' */
 
81
                *sign = 0;
 
82
                if ((rve = s = (char *)malloc(ndigit?siz:2)) == NULL) {
 
83
                        return(NULL);
 
84
                }
 
85
                *rve++ = '0';
 
86
                *rve = '\0';
 
87
                if (!ndigit) {
 
88
                        return(s);
 
89
                }
 
90
        } else {
 
91
                p = zend_dtoa(value, fmode + 2, ndigit, decpt, sign, &rve);
 
92
                if (*decpt == 9999) {
 
93
                        /* Infinity or Nan, convert to inf or nan like printf */
 
94
                        *decpt = 0;
 
95
                        c = *p;
 
96
                        zend_freedtoa(p);
 
97
                        return(c == 'I' ? "INF" : "NAN");
 
98
                }
 
99
                /* Make a local copy and adjust rve to be in terms of s */
 
100
                if (pad && fmode) {
 
101
                        siz += *decpt;
 
102
                }
 
103
                if ((s = (char *)malloc(siz+1)) == NULL) {
 
104
                        zend_freedtoa(p);
 
105
                        return(NULL);
 
106
                }
 
107
                (void) strlcpy(s, p, siz);
 
108
                rve = s + (rve - p);
 
109
                zend_freedtoa(p);
 
110
        }
 
111
 
 
112
        /* Add trailing zeros */
 
113
        if (pad) {
 
114
                siz -= rve - s;
 
115
                while (--siz) {
 
116
                        *rve++ = '0';
 
117
                }
 
118
                *rve = '\0';
 
119
        }
 
120
 
 
121
        return(s);
 
122
}
 
123
/* }}} */
 
124
 
 
125
static inline char *php_ecvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
 
126
{
 
127
        return(__cvt(value, ndigit, decpt, sign, 0, 1));
 
128
}
 
129
/* }}} */
 
130
 
 
131
static inline char *php_fcvt(double value, int ndigit, int *decpt, int *sign) /* {{{ */
 
132
{
 
133
    return(__cvt(value, ndigit, decpt, sign, 1, 1));
 
134
}
 
135
/* }}} */
 
136
 
 
137
PHPAPI char *php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf) /* {{{ */
 
138
{
 
139
        char *digits, *dst, *src;
 
140
        int i, decpt, sign;
 
141
 
 
142
        digits = zend_dtoa(value, 2, ndigit, &decpt, &sign, NULL);
 
143
        if (decpt == 9999) {
 
144
                /*
 
145
                 * Infinity or NaN, convert to inf or nan with sign.
 
146
                 * We assume the buffer is at least ndigit long.
 
147
                 */
 
148
                snprintf(buf, ndigit + 1, "%s%s", (sign && *digits == 'I') ? "-" : "", *digits == 'I' ? "INF" : "NAN");
 
149
                zend_freedtoa(digits);
 
150
                return (buf);
 
151
        }
 
152
 
 
153
        dst = buf;
 
154
        if (sign) {
 
155
                *dst++ = '-';
 
156
        }
 
157
 
 
158
        if ((decpt >= 0 && decpt > ndigit) || decpt < -3) { /* use E-style */
 
159
                /* exponential format (e.g. 1.2345e+13) */
 
160
                if (--decpt < 0) {
 
161
                        sign = 1;
 
162
                        decpt = -decpt;
 
163
                } else {
 
164
                        sign = 0;
 
165
                }
 
166
                src = digits;
 
167
                *dst++ = *src++;
 
168
                *dst++ = dec_point;
 
169
                if (*src == '\0') {
 
170
                        *dst++ = '0';
 
171
                } else {
 
172
                        do {
 
173
                                *dst++ = *src++;
 
174
                        } while (*src != '\0');
 
175
                }
 
176
                *dst++ = exponent;
 
177
                if (sign) {
 
178
                        *dst++ = '-';
 
179
                } else {
 
180
                        *dst++ = '+';
 
181
                }
 
182
                if (decpt < 10) {
 
183
                        *dst++ = '0' + decpt;
 
184
                        *dst = '\0';
 
185
                } else {
 
186
                        /* XXX - optimize */
 
187
                        for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
 
188
                                continue;
 
189
                        dst[i + 1] = '\0';
 
190
                        while (decpt != 0) {
 
191
                                dst[i--] = '0' + decpt % 10;
 
192
                                decpt /= 10;
 
193
                        }
 
194
                }
 
195
        } else if (decpt < 0) {
 
196
                /* standard format 0. */
 
197
                *dst++ = '0';   /* zero before decimal point */
 
198
                *dst++ = dec_point;
 
199
                do {
 
200
                        *dst++ = '0';
 
201
                } while (++decpt < 0);
 
202
                src = digits;
 
203
                while (*src != '\0') {
 
204
                        *dst++ = *src++;
 
205
                }
 
206
                *dst = '\0';
 
207
        } else {
 
208
                /* standard format */
 
209
                for (i = 0, src = digits; i < decpt; i++) {
 
210
                        if (*src != '\0') {
 
211
                                *dst++ = *src++;
 
212
                        } else {
 
213
                                *dst++ = '0';
 
214
                        }
 
215
                }
 
216
                if (*src != '\0') {
 
217
                        if (src == digits) {
 
218
                                *dst++ = '0';   /* zero before decimal point */
 
219
                        }
 
220
                        *dst++ = dec_point;
 
221
                        for (i = decpt; digits[i] != '\0'; i++) {
 
222
                *dst++ = digits[i];
 
223
            }
 
224
        }
 
225
        *dst = '\0';
 
226
    }
 
227
    zend_freedtoa(digits);
 
228
    return (buf);
 
229
}
 
230
/* }}} */
 
231
 
 
232
/* {{{ Apache license */
 
233
/* ====================================================================
 
234
 * Copyright (c) 1995-1998 The Apache Group.  All rights reserved.
 
235
 *
 
236
 * Redistribution and use in source and binary forms, with or without
 
237
 * modification, are permitted provided that the following conditions
 
238
 * are met:
 
239
 *
 
240
 * 1. Redistributions of source code must retain the above copyright
 
241
 *    notice, this list of conditions and the following disclaimer.
 
242
 *
 
243
 * 2. Redistributions in binary form must reproduce the above copyright
 
244
 *    notice, this list of conditions and the following disclaimer in
 
245
 *    the documentation and/or other materials provided with the
 
246
 *    distribution.
 
247
 *
 
248
 * 3. All advertising materials mentioning features or use of this
 
249
 *    software must display the following acknowledgment:
 
250
 *    "This product includes software developed by the Apache Group
 
251
 *    for use in the Apache HTTP server project (http://www.apache.org/)."
 
252
 *
 
253
 * 4. The names "Apache Server" and "Apache Group" must not be used to
 
254
 *    endorse or promote products derived from this software without
 
255
 *    prior written permission.
 
256
 *
 
257
 * 5. Redistributions of any form whatsoever must retain the following
 
258
 *    acknowledgment:
 
259
 *    "This product includes software developed by the Apache Group
 
260
 *    for use in the Apache HTTP server project (http://www.apache.org/)."
 
261
 *
 
262
 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
 
263
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
264
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
265
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
 
266
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
267
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
268
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
269
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
270
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
271
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
272
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 
273
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 
274
 * ====================================================================
 
275
 *
 
276
 * This software consists of voluntary contributions made by many
 
277
 * individuals on behalf of the Apache Group and was originally based
 
278
 * on public domain software written at the National Center for
 
279
 * Supercomputing Applications, University of Illinois, Urbana-Champaign.
 
280
 * For more information on the Apache Group and the Apache HTTP server
 
281
 * project, please see <http://www.apache.org/>.
 
282
 *
 
283
 * This code is based on, and used with the permission of, the
 
284
 * SIO stdio-replacement strx_* functions by Panos Tsirigotis
 
285
 * <panos@alumni.cs.colorado.edu> for xinetd.
 
286
 */
 
287
/* }}} */
 
288
 
 
289
#define FALSE                   0
 
290
#define TRUE                    1
 
291
#define NUL                     '\0'
 
292
#define INT_NULL                ((int *)0)
 
293
 
 
294
#define S_NULL                  "(null)"
 
295
#define S_NULL_LEN              6
 
296
 
 
297
#define FLOAT_DIGITS            6
 
298
#define EXPONENT_LENGTH         10
 
299
 
 
300
 
 
301
/*
 
302
 * Convert num to its decimal format.
 
303
 * Return value:
 
304
 *   - a pointer to a string containing the number (no sign)
 
305
 *   - len contains the length of the string
 
306
 *   - is_negative is set to TRUE or FALSE depending on the sign
 
307
 *     of the number (always set to FALSE if is_unsigned is TRUE)
 
308
 *
 
309
 * The caller provides a buffer for the string: that is the buf_end argument
 
310
 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
 
311
 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
 
312
 */
 
313
/* char * ap_php_conv_10() {{{ */
 
314
char * ap_php_conv_10(register wide_int num, register bool_int is_unsigned,
 
315
           register bool_int * is_negative, char *buf_end, register int *len)
 
316
{
 
317
        register char *p = buf_end;
 
318
        register u_wide_int magnitude;
 
319
 
 
320
        if (is_unsigned) {
 
321
                magnitude = (u_wide_int) num;
 
322
                *is_negative = FALSE;
 
323
        } else {
 
324
                *is_negative = (num < 0);
 
325
 
 
326
                /*
 
327
                 * On a 2's complement machine, negating the most negative integer
 
328
                 * results in a number that cannot be represented as a signed integer.
 
329
                 * Here is what we do to obtain the number's magnitude:
 
330
                 *      a. add 1 to the number
 
331
                 *      b. negate it (becomes positive)
 
332
                 *      c. convert it to unsigned
 
333
                 *      d. add 1
 
334
                 */
 
335
                if (*is_negative) {
 
336
                        wide_int t = num + 1;
 
337
                        magnitude = ((u_wide_int) - t) + 1;
 
338
                } else {
 
339
                        magnitude = (u_wide_int) num;
 
340
                }
 
341
        }
 
342
 
 
343
        /*
 
344
         * We use a do-while loop so that we write at least 1 digit
 
345
         */
 
346
        do {
 
347
                register u_wide_int new_magnitude = magnitude / 10;
 
348
 
 
349
                *--p = (char)(magnitude - new_magnitude * 10 + '0');
 
350
                magnitude = new_magnitude;
 
351
        }
 
352
        while (magnitude);
 
353
 
 
354
        *len = buf_end - p;
 
355
        return (p);
 
356
}
 
357
/* }}} */
 
358
 
 
359
/* If you change this value then also change bug24640.phpt.
 
360
 * Also NDIG must be reasonable smaller than NUM_BUF_SIZE.
 
361
 */
 
362
#define NDIG    320
 
363
 
 
364
 
 
365
/*
 
366
 * Convert a floating point number to a string formats 'f', 'e' or 'E'.
 
367
 * The result is placed in buf, and len denotes the length of the string
 
368
 * The sign is returned in the is_negative argument (and is not placed
 
369
 * in buf).
 
370
 */
 
371
/* PHPAPI char * php_conv_fp() {{{ */
 
372
PHPAPI char * php_conv_fp(register char format, register double num,
 
373
                 boolean_e add_dp, int precision, char dec_point, bool_int * is_negative, char *buf, int *len)
 
374
{
 
375
        register char *s = buf;
 
376
        register char *p, *p_orig;
 
377
        int decimal_point;
 
378
 
 
379
        if (precision >= NDIG - 1) {
 
380
                precision = NDIG - 2;
 
381
        }
 
382
 
 
383
        if (format == 'F') {
 
384
                p_orig = p = php_fcvt(num, precision, &decimal_point, is_negative);
 
385
        } else {                                                /* either e or E format */
 
386
                p_orig = p = php_ecvt(num, precision + 1, &decimal_point, is_negative);
 
387
        }
 
388
 
 
389
        /*
 
390
         * Check for Infinity and NaN
 
391
         */
 
392
        if (isalpha((int)*p)) {
 
393
                *len = strlen(p);
 
394
                memcpy(buf, p, *len + 1);
 
395
                *is_negative = FALSE;
 
396
                free(p_orig);
 
397
                return (buf);
 
398
        }
 
399
        if (format == 'F') {
 
400
                if (decimal_point <= 0) {
 
401
                        if (num != 0 || precision > 0) {
 
402
                                *s++ = '0';
 
403
                                if (precision > 0) {
 
404
                                        *s++ = dec_point;
 
405
                                        while (decimal_point++ < 0) {
 
406
                                                *s++ = '0';
 
407
                                        }
 
408
                                } else if (add_dp) {
 
409
                                        *s++ = dec_point;
 
410
                                }
 
411
                        }
 
412
                } else {
 
413
                        int addz = decimal_point >= NDIG ? decimal_point - NDIG + 1 : 0;
 
414
                        decimal_point -= addz;
 
415
                        while (decimal_point-- > 0) {
 
416
                                *s++ = *p++;
 
417
                        }
 
418
                        while (addz-- > 0) {
 
419
                                *s++ = '0';
 
420
                        }
 
421
                        if (precision > 0 || add_dp) {
 
422
                                *s++ = dec_point;
 
423
                        }
 
424
                }
 
425
        } else {
 
426
                *s++ = *p++;
 
427
                if (precision > 0 || add_dp) {
 
428
                        *s++ = '.';
 
429
                }
 
430
        }
 
431
 
 
432
        /*
 
433
         * copy the rest of p, the NUL is NOT copied
 
434
         */
 
435
        while (*p) {
 
436
                *s++ = *p++;
 
437
        }
 
438
 
 
439
        if (format != 'F') {
 
440
                char temp[EXPONENT_LENGTH];             /* for exponent conversion */
 
441
                int t_len;
 
442
                bool_int exponent_is_negative;
 
443
 
 
444
                *s++ = format;                  /* either e or E */
 
445
                decimal_point--;
 
446
                if (decimal_point != 0) {
 
447
                        p = ap_php_conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, &temp[EXPONENT_LENGTH], &t_len);
 
448
                        *s++ = exponent_is_negative ? '-' : '+';
 
449
 
 
450
                        /*
 
451
                         * Make sure the exponent has at least 2 digits
 
452
                         */
 
453
                        while (t_len--) {
 
454
                                *s++ = *p++;
 
455
                        }
 
456
                } else {
 
457
                        *s++ = '+';
 
458
                        *s++ = '0';
 
459
                }
 
460
        }
 
461
        *len = s - buf;
 
462
        free(p_orig);
 
463
        return (buf);
 
464
}
 
465
/* }}} */
 
466
 
 
467
/*
 
468
 * Convert num to a base X number where X is a power of 2. nbits determines X.
 
469
 * For example, if nbits is 3, we do base 8 conversion
 
470
 * Return value:
 
471
 *      a pointer to a string containing the number
 
472
 *
 
473
 * The caller provides a buffer for the string: that is the buf_end argument
 
474
 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer
 
475
 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ])
 
476
 */
 
477
char * ap_php_conv_p2(register u_wide_int num, register int nbits, char format, char *buf_end, register int *len) /* {{{ */
 
478
{
 
479
        register int mask = (1 << nbits) - 1;
 
480
        register char *p = buf_end;
 
481
        static char low_digits[] = "0123456789abcdef";
 
482
        static char upper_digits[] = "0123456789ABCDEF";
 
483
        register char *digits = (format == 'X') ? upper_digits : low_digits;
 
484
 
 
485
        do {
 
486
                *--p = digits[num & mask];
 
487
                num >>= nbits;
 
488
        }
 
489
        while (num);
 
490
 
 
491
        *len = buf_end - p;
 
492
        return (p);
 
493
}
 
494
/* }}} */
 
495
 
 
496
/*
 
497
 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
 
498
 *
 
499
 * XXX: this is a magic number; do not decrease it
 
500
 */
 
501
#define NUM_BUF_SIZE            512
 
502
 
 
503
 
 
504
/*
 
505
 * Descriptor for buffer area
 
506
 */
 
507
struct buf_area {
 
508
        char *buf_end;
 
509
        char *nextb;                            /* pointer to next byte to read/write   */
 
510
};
 
511
 
 
512
typedef struct buf_area buffy;
 
513
 
 
514
/*
 
515
 * The INS_CHAR macro inserts a character in the buffer and writes
 
516
 * the buffer back to disk if necessary
 
517
 * It uses the char pointers sp and bep:
 
518
 *      sp points to the next available character in the buffer
 
519
 *      bep points to the end-of-buffer+1
 
520
 * While using this macro, note that the nextb pointer is NOT updated.
 
521
 *
 
522
 * NOTE: Evaluation of the c argument should not have any side-effects
 
523
 */
 
524
#define INS_CHAR(c, sp, bep, cc) \
 
525
        {                            \
 
526
                if (sp < bep)            \
 
527
                {                        \
 
528
                        *sp++ = c;           \
 
529
                }                        \
 
530
                cc++;                    \
 
531
        }
 
532
 
 
533
#define NUM( c )                        ( c - '0' )
 
534
 
 
535
#define STR_TO_DEC( str, num )          \
 
536
    num = NUM( *str++ ) ;               \
 
537
    while ( isdigit((int)*str ) )               \
 
538
    {                                   \
 
539
        num *= 10 ;                     \
 
540
        num += NUM( *str++ ) ;          \
 
541
    }
 
542
 
 
543
/*
 
544
 * This macro does zero padding so that the precision
 
545
 * requirement is satisfied. The padding is done by
 
546
 * adding '0's to the left of the string that is going
 
547
 * to be printed.
 
548
 */
 
549
#define FIX_PRECISION( adjust, precision, s, s_len )    \
 
550
    if ( adjust )                                       \
 
551
        while ( s_len < precision )                     \
 
552
        {                                               \
 
553
            *--s = '0' ;                                \
 
554
            s_len++ ;                                   \
 
555
        }
 
556
 
 
557
/*
 
558
 * Macro that does padding. The padding is done by printing
 
559
 * the character ch.
 
560
 */
 
561
#define PAD( width, len, ch )   do              \
 
562
        {                                       \
 
563
            INS_CHAR( ch, sp, bep, cc ) ;       \
 
564
            width-- ;                           \
 
565
        }                                       \
 
566
        while ( width > len )
 
567
 
 
568
/*
 
569
 * Prefix the character ch to the string str
 
570
 * Increase length
 
571
 * Set the has_prefix flag
 
572
 */
 
573
#define PREFIX( str, length, ch )        *--str = ch ; length++ ; has_prefix = YES
 
574
 
 
575
 
 
576
/*
 
577
 * Do format conversion placing the output in buffer
 
578
 */
 
579
static int format_converter(register buffy * odp, const char *fmt, va_list ap) /* {{{ */
 
580
{
 
581
        char *sp;
 
582
        char *bep;
 
583
        int cc = 0;
 
584
        int i;
 
585
 
 
586
        char *s = NULL;
 
587
        char *q;
 
588
        int s_len, free_zcopy;
 
589
        zval *zvp, zcopy;
 
590
 
 
591
        int min_width = 0;
 
592
        int precision = 0;
 
593
        enum {
 
594
                LEFT, RIGHT
 
595
        } adjust;
 
596
        char pad_char;
 
597
        char prefix_char;
 
598
 
 
599
        double fp_num;
 
600
        wide_int i_num = (wide_int) 0;
 
601
        u_wide_int ui_num;
 
602
 
 
603
        char num_buf[NUM_BUF_SIZE];
 
604
        char char_buf[2];                       /* for printing %% and %<unknown> */
 
605
 
 
606
#ifdef HAVE_LOCALE_H
 
607
        struct lconv *lconv = NULL;
 
608
#endif
 
609
 
 
610
        /*
 
611
         * Flag variables
 
612
         */
 
613
        length_modifier_e modifier;
 
614
        boolean_e alternate_form;
 
615
        boolean_e print_sign;
 
616
        boolean_e print_blank;
 
617
        boolean_e adjust_precision;
 
618
        boolean_e adjust_width;
 
619
        bool_int is_negative;
 
620
 
 
621
        sp = odp->nextb;
 
622
        bep = odp->buf_end;
 
623
 
 
624
        while (*fmt) {
 
625
                if (*fmt != '%') {
 
626
                        INS_CHAR(*fmt, sp, bep, cc);
 
627
                } else {
 
628
                        /*
 
629
                         * Default variable settings
 
630
                         */
 
631
                        adjust = RIGHT;
 
632
                        alternate_form = print_sign = print_blank = NO;
 
633
                        pad_char = ' ';
 
634
                        prefix_char = NUL;
 
635
                        free_zcopy = 0;
 
636
 
 
637
                        fmt++;
 
638
 
 
639
                        /*
 
640
                         * Try to avoid checking for flags, width or precision
 
641
                         */
 
642
                        if (isascii((int)*fmt) && !islower((int)*fmt)) {
 
643
                                /*
 
644
                                 * Recognize flags: -, #, BLANK, +
 
645
                                 */
 
646
                                for (;; fmt++) {
 
647
                                        if (*fmt == '-')
 
648
                                                adjust = LEFT;
 
649
                                        else if (*fmt == '+')
 
650
                                                print_sign = YES;
 
651
                                        else if (*fmt == '#')
 
652
                                                alternate_form = YES;
 
653
                                        else if (*fmt == ' ')
 
654
                                                print_blank = YES;
 
655
                                        else if (*fmt == '0')
 
656
                                                pad_char = '0';
 
657
                                        else
 
658
                                                break;
 
659
                                }
 
660
 
 
661
                                /*
 
662
                                 * Check if a width was specified
 
663
                                 */
 
664
                                if (isdigit((int)*fmt)) {
 
665
                                        STR_TO_DEC(fmt, min_width);
 
666
                                        adjust_width = YES;
 
667
                                } else if (*fmt == '*') {
 
668
                                        min_width = va_arg(ap, int);
 
669
                                        fmt++;
 
670
                                        adjust_width = YES;
 
671
                                        if (min_width < 0) {
 
672
                                                adjust = LEFT;
 
673
                                                min_width = -min_width;
 
674
                                        }
 
675
                                } else
 
676
                                        adjust_width = NO;
 
677
 
 
678
                                /*
 
679
                                 * Check if a precision was specified
 
680
                                 *
 
681
                                 * XXX: an unreasonable amount of precision may be specified
 
682
                                 * resulting in overflow of num_buf. Currently we
 
683
                                 * ignore this possibility.
 
684
                                 */
 
685
                                if (*fmt == '.') {
 
686
                                        adjust_precision = YES;
 
687
                                        fmt++;
 
688
                                        if (isdigit((int)*fmt)) {
 
689
                                                STR_TO_DEC(fmt, precision);
 
690
                                        } else if (*fmt == '*') {
 
691
                                                precision = va_arg(ap, int);
 
692
                                                fmt++;
 
693
                                                if (precision < 0)
 
694
                                                        precision = 0;
 
695
                                        } else
 
696
                                                precision = 0;
 
697
                                } else
 
698
                                        adjust_precision = NO;
 
699
                        } else
 
700
                                adjust_precision = adjust_width = NO;
 
701
 
 
702
                        /*
 
703
                         * Modifier check
 
704
                         */
 
705
                        switch (*fmt) {
 
706
                                case 'L':
 
707
                                        fmt++;
 
708
                                        modifier = LM_LONG_DOUBLE;
 
709
                                        break;
 
710
                                case 'I':
 
711
                                        fmt++;
 
712
#if SIZEOF_LONG_LONG
 
713
                                        if (*fmt == '6' && *(fmt+1) == '4') {
 
714
                                                fmt += 2;
 
715
                                                modifier = LM_LONG_LONG;
 
716
                                        } else
 
717
#endif
 
718
                                                if (*fmt == '3' && *(fmt+1) == '2') {
 
719
                                                        fmt += 2;
 
720
                                                        modifier = LM_LONG;
 
721
                                                } else {
 
722
#ifdef _WIN64
 
723
                                                        modifier = LM_LONG_LONG;
 
724
#else
 
725
                                                        modifier = LM_LONG;
 
726
#endif
 
727
                                                }
 
728
                                        break;
 
729
                                case 'l':
 
730
                                        fmt++;
 
731
#if SIZEOF_LONG_LONG
 
732
                                        if (*fmt == 'l') {
 
733
                                                fmt++;
 
734
                                                modifier = LM_LONG_LONG;
 
735
                                        } else
 
736
#endif
 
737
                                                modifier = LM_LONG;
 
738
                                        break;
 
739
                                case 'z':
 
740
                                        fmt++;
 
741
                                        modifier = LM_SIZE_T;
 
742
                                        break;
 
743
                                case 'j':
 
744
                                        fmt++;
 
745
#if SIZEOF_INTMAX_T
 
746
                                        modifier = LM_INTMAX_T;
 
747
#else
 
748
                                        modifier = LM_SIZE_T;
 
749
#endif
 
750
                                        break;
 
751
                                case 't':
 
752
                                        fmt++;
 
753
#if SIZEOF_PTRDIFF_T
 
754
                                        modifier = LM_PTRDIFF_T;
 
755
#else
 
756
                                        modifier = LM_SIZE_T;
 
757
#endif
 
758
                                        break;
 
759
                                case 'h':
 
760
                                        fmt++;
 
761
                                        if (*fmt == 'h') {
 
762
                                                fmt++;
 
763
                                        }
 
764
                                        /* these are promoted to int, so no break */
 
765
                                default:
 
766
                                        modifier = LM_STD;
 
767
                                        break;
 
768
                        }
 
769
 
 
770
                        /*
 
771
                         * Argument extraction and printing.
 
772
                         * First we determine the argument type.
 
773
                         * Then, we convert the argument to a string.
 
774
                         * On exit from the switch, s points to the string that
 
775
                         * must be printed, s_len has the length of the string
 
776
                         * The precision requirements, if any, are reflected in s_len.
 
777
                         *
 
778
                         * NOTE: pad_char may be set to '0' because of the 0 flag.
 
779
                         *   It is reset to ' ' by non-numeric formats
 
780
                         */
 
781
                        switch (*fmt) {
 
782
                                case 'Z':
 
783
                                        zvp = (zval*) va_arg(ap, zval*);
 
784
                                        zend_make_printable_zval(zvp, &zcopy, &free_zcopy);
 
785
                                        if (free_zcopy) {
 
786
                                                zvp = &zcopy;
 
787
                                        }
 
788
                                        s_len = Z_STRLEN_P(zvp);
 
789
                                        s = Z_STRVAL_P(zvp);
 
790
                                        if (adjust_precision && precision < s_len) {
 
791
                                                s_len = precision;
 
792
                                        }
 
793
                                        break;
 
794
                                case 'u':
 
795
                                        switch(modifier) {
 
796
                                                default:
 
797
                                                        i_num = (wide_int) va_arg(ap, unsigned int);
 
798
                                                        break;
 
799
                                                case LM_LONG_DOUBLE:
 
800
                                                        goto fmt_error;
 
801
                                                case LM_LONG:
 
802
                                                        i_num = (wide_int) va_arg(ap, unsigned long int);
 
803
                                                        break;
 
804
                                                case LM_SIZE_T:
 
805
                                                        i_num = (wide_int) va_arg(ap, size_t);
 
806
                                                        break;
 
807
#if SIZEOF_LONG_LONG
 
808
                                                case LM_LONG_LONG:
 
809
                                                        i_num = (wide_int) va_arg(ap, u_wide_int);
 
810
                                                        break;
 
811
#endif
 
812
#if SIZEOF_INTMAX_T
 
813
                                                case LM_INTMAX_T:
 
814
                                                        i_num = (wide_int) va_arg(ap, uintmax_t);
 
815
                                                        break;
 
816
#endif
 
817
#if SIZEOF_PTRDIFF_T
 
818
                                                case LM_PTRDIFF_T:
 
819
                                                        i_num = (wide_int) va_arg(ap, ptrdiff_t);
 
820
                                                        break;
 
821
#endif
 
822
                                        }
 
823
                                        /*
 
824
                                         * The rest also applies to other integer formats, so fall
 
825
                                         * into that case.
 
826
                                         */
 
827
                                case 'd':
 
828
                                case 'i':
 
829
                                        /*
 
830
                                         * Get the arg if we haven't already.
 
831
                                         */
 
832
                                        if ((*fmt) != 'u') {
 
833
                                                switch(modifier) {
 
834
                                                        default:
 
835
                                                                i_num = (wide_int) va_arg(ap, int);
 
836
                                                                break;
 
837
                                                        case LM_LONG_DOUBLE:
 
838
                                                                goto fmt_error;
 
839
                                                        case LM_LONG:
 
840
                                                                i_num = (wide_int) va_arg(ap, long int);
 
841
                                                                break;
 
842
                                                        case LM_SIZE_T:
 
843
#if SIZEOF_SSIZE_T
 
844
                                                                i_num = (wide_int) va_arg(ap, ssize_t);
 
845
#else
 
846
                                                                i_num = (wide_int) va_arg(ap, size_t);
 
847
#endif
 
848
                                                                break;
 
849
#if SIZEOF_LONG_LONG
 
850
                                                        case LM_LONG_LONG:
 
851
                                                                i_num = (wide_int) va_arg(ap, wide_int);
 
852
                                                                break;
 
853
#endif
 
854
#if SIZEOF_INTMAX_T
 
855
                                                        case LM_INTMAX_T:
 
856
                                                                i_num = (wide_int) va_arg(ap, intmax_t);
 
857
                                                                break;
 
858
#endif
 
859
#if SIZEOF_PTRDIFF_T
 
860
                                                        case LM_PTRDIFF_T:
 
861
                                                                i_num = (wide_int) va_arg(ap, ptrdiff_t);
 
862
                                                                break;
 
863
#endif
 
864
                                                }
 
865
                                        }
 
866
                                        s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative,
 
867
                                                                &num_buf[NUM_BUF_SIZE], &s_len);
 
868
                                        FIX_PRECISION(adjust_precision, precision, s, s_len);
 
869
 
 
870
                                        if (*fmt != 'u') {
 
871
                                                if (is_negative) {
 
872
                                                        prefix_char = '-';
 
873
                                                } else if (print_sign) {
 
874
                                                        prefix_char = '+';
 
875
                                                } else if (print_blank) {
 
876
                                                        prefix_char = ' ';
 
877
                                                }
 
878
                                        }
 
879
                                        break;
 
880
 
 
881
 
 
882
                                case 'o':
 
883
                                        switch(modifier) {
 
884
                                                default:
 
885
                                                        ui_num = (u_wide_int) va_arg(ap, unsigned int);
 
886
                                                        break;
 
887
                                                case LM_LONG_DOUBLE:
 
888
                                                        goto fmt_error;
 
889
                                                case LM_LONG:
 
890
                                                        ui_num = (u_wide_int) va_arg(ap, unsigned long int);
 
891
                                                        break;
 
892
                                                case LM_SIZE_T:
 
893
                                                        ui_num = (u_wide_int) va_arg(ap, size_t);
 
894
                                                        break;
 
895
#if SIZEOF_LONG_LONG
 
896
                                                case LM_LONG_LONG:
 
897
                                                        ui_num = (u_wide_int) va_arg(ap, u_wide_int);
 
898
                                                        break;
 
899
#endif
 
900
#if SIZEOF_INTMAX_T
 
901
                                                case LM_INTMAX_T:
 
902
                                                        ui_num = (u_wide_int) va_arg(ap, uintmax_t);
 
903
                                                        break;
 
904
#endif
 
905
#if SIZEOF_PTRDIFF_T
 
906
                                                case LM_PTRDIFF_T:
 
907
                                                        ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
 
908
                                                        break;
 
909
#endif
 
910
                                        }
 
911
                                        s = ap_php_conv_p2(ui_num, 3, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
 
912
                                        FIX_PRECISION(adjust_precision, precision, s, s_len);
 
913
                                        if (alternate_form && *s != '0') {
 
914
                                                *--s = '0';
 
915
                                                s_len++;
 
916
                                        }
 
917
                                        break;
 
918
 
 
919
 
 
920
                                case 'x':
 
921
                                case 'X':
 
922
                                        switch(modifier) {
 
923
                                                default:
 
924
                                                        ui_num = (u_wide_int) va_arg(ap, unsigned int);
 
925
                                                        break;
 
926
                                                case LM_LONG_DOUBLE:
 
927
                                                        goto fmt_error;
 
928
                                                case LM_LONG:
 
929
                                                        ui_num = (u_wide_int) va_arg(ap, unsigned long int);
 
930
                                                        break;
 
931
                                                case LM_SIZE_T:
 
932
                                                        ui_num = (u_wide_int) va_arg(ap, size_t);
 
933
                                                        break;
 
934
#if SIZEOF_LONG_LONG
 
935
                                                case LM_LONG_LONG:
 
936
                                                        ui_num = (u_wide_int) va_arg(ap, u_wide_int);
 
937
                                                        break;
 
938
#endif
 
939
#if SIZEOF_INTMAX_T
 
940
                                                case LM_INTMAX_T:
 
941
                                                        ui_num = (u_wide_int) va_arg(ap, uintmax_t);
 
942
                                                        break;
 
943
#endif
 
944
#if SIZEOF_PTRDIFF_T
 
945
                                                case LM_PTRDIFF_T:
 
946
                                                        ui_num = (u_wide_int) va_arg(ap, ptrdiff_t);
 
947
                                                        break;
 
948
#endif
 
949
                                        }
 
950
                                        s = ap_php_conv_p2(ui_num, 4, *fmt, &num_buf[NUM_BUF_SIZE], &s_len);
 
951
                                        FIX_PRECISION(adjust_precision, precision, s, s_len);
 
952
                                        if (alternate_form && i_num != 0) {
 
953
                                                *--s = *fmt;    /* 'x' or 'X' */
 
954
                                                *--s = '0';
 
955
                                                s_len += 2;
 
956
                                        }
 
957
                                        break;
 
958
 
 
959
 
 
960
                                case 's':
 
961
                                case 'v':
 
962
                                        s = va_arg(ap, char *);
 
963
                                        if (s != NULL) {
 
964
                                                s_len = strlen(s);
 
965
                                                if (adjust_precision && precision < s_len) {
 
966
                                                        s_len = precision;
 
967
                                                }
 
968
                                        } else {
 
969
                                                s = S_NULL;
 
970
                                                s_len = S_NULL_LEN;
 
971
                                        }
 
972
                                        pad_char = ' ';
 
973
                                        break;
 
974
 
 
975
 
 
976
                                case 'f':
 
977
                                case 'F':
 
978
                                case 'e':
 
979
                                case 'E':
 
980
                                        switch(modifier) {
 
981
                                                case LM_LONG_DOUBLE:
 
982
                                                        fp_num = (double) va_arg(ap, long double);
 
983
                                                        break;
 
984
                                                case LM_STD:
 
985
                                                        fp_num = va_arg(ap, double);
 
986
                                                        break;
 
987
                                                default:
 
988
                                                        goto fmt_error;
 
989
                                        }
 
990
 
 
991
                                        if (zend_isnan(fp_num)) {
 
992
                                                s = "NAN";
 
993
                                                s_len = 3;
 
994
                                        } else if (zend_isinf(fp_num)) {
 
995
                                                s = "INF";
 
996
                                                s_len = 3;
 
997
                                        } else {
 
998
#ifdef HAVE_LOCALE_H
 
999
                                                if (!lconv) {
 
1000
                                                        lconv = localeconv();
 
1001
                                                }
 
1002
#endif
 
1003
                                                s = php_conv_fp((*fmt == 'f')?'F':*fmt, fp_num, alternate_form,
 
1004
                                                 (adjust_precision == NO) ? FLOAT_DIGITS : precision,
 
1005
                                                 (*fmt == 'f')?LCONV_DECIMAL_POINT:'.',
 
1006
                                                                        &is_negative, &num_buf[1], &s_len);
 
1007
                                                if (is_negative)
 
1008
                                                        prefix_char = '-';
 
1009
                                                else if (print_sign)
 
1010
                                                        prefix_char = '+';
 
1011
                                                else if (print_blank)
 
1012
                                                        prefix_char = ' ';
 
1013
                                        }
 
1014
                                        break;
 
1015
 
 
1016
 
 
1017
                                case 'g':
 
1018
                                case 'k':
 
1019
                                case 'G':
 
1020
                                case 'H':
 
1021
                                        switch(modifier) {
 
1022
                                                case LM_LONG_DOUBLE:
 
1023
                                                        fp_num = (double) va_arg(ap, long double);
 
1024
                                                        break;
 
1025
                                                case LM_STD:
 
1026
                                                        fp_num = va_arg(ap, double);
 
1027
                                                        break;
 
1028
                                                default:
 
1029
                                                        goto fmt_error;
 
1030
                                        }
 
1031
 
 
1032
                                        if (zend_isnan(fp_num)) {
 
1033
                                                s = "NAN";
 
1034
                                                s_len = 3;
 
1035
                                                break;
 
1036
                                        } else if (zend_isinf(fp_num)) {
 
1037
                                                if (fp_num > 0) {
 
1038
                                                        s = "INF";
 
1039
                                                        s_len = 3;
 
1040
                                                } else {
 
1041
                                                        s = "-INF";
 
1042
                                                        s_len = 4;
 
1043
                                                }
 
1044
                                                break;
 
1045
                                        }
 
1046
 
 
1047
                                        if (adjust_precision == NO) {
 
1048
                                                precision = FLOAT_DIGITS;
 
1049
                                        } else if (precision == 0) {
 
1050
                                                precision = 1;
 
1051
                                        }
 
1052
                                        /*
 
1053
                                         * * We use &num_buf[ 1 ], so that we have room for the sign
 
1054
                                         */
 
1055
#ifdef HAVE_LOCALE_H
 
1056
                                        if (!lconv) {
 
1057
                                                lconv = localeconv();
 
1058
                                        }
 
1059
#endif
 
1060
                                        s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
 
1061
                                        if (*s == '-') {
 
1062
                                                prefix_char = *s++;
 
1063
                                        } else if (print_sign) {
 
1064
                                                prefix_char = '+';
 
1065
                                        } else if (print_blank) {
 
1066
                                                prefix_char = ' ';
 
1067
                                        }
 
1068
 
 
1069
                                        s_len = strlen(s);
 
1070
 
 
1071
                                        if (alternate_form && (q = strchr(s, '.')) == NULL) {
 
1072
                                                s[s_len++] = '.';
 
1073
                                        }
 
1074
                                        break;
 
1075
 
 
1076
 
 
1077
                                case 'c':
 
1078
                                        char_buf[0] = (char) (va_arg(ap, int));
 
1079
                                        s = &char_buf[0];
 
1080
                                        s_len = 1;
 
1081
                                        pad_char = ' ';
 
1082
                                        break;
 
1083
 
 
1084
 
 
1085
                                case '%':
 
1086
                                        char_buf[0] = '%';
 
1087
                                        s = &char_buf[0];
 
1088
                                        s_len = 1;
 
1089
                                        pad_char = ' ';
 
1090
                                        break;
 
1091
 
 
1092
 
 
1093
                                case 'n':
 
1094
                                        *(va_arg(ap, int *)) = cc;
 
1095
                                        goto skip_output;
 
1096
 
 
1097
                                        /*
 
1098
                                         * Always extract the argument as a "char *" pointer. We
 
1099
                                         * should be using "void *" but there are still machines
 
1100
                                         * that don't understand it.
 
1101
                                         * If the pointer size is equal to the size of an unsigned
 
1102
                                         * integer we convert the pointer to a hex number, otherwise
 
1103
                                         * we print "%p" to indicate that we don't handle "%p".
 
1104
                                         */
 
1105
                                case 'p':
 
1106
                                        if (sizeof(char *) <= sizeof(u_wide_int)) {
 
1107
                                                ui_num = (u_wide_int)((size_t) va_arg(ap, char *));
 
1108
                                                s = ap_php_conv_p2(ui_num, 4, 'x',
 
1109
                                                                &num_buf[NUM_BUF_SIZE], &s_len);
 
1110
                                                if (ui_num != 0) {
 
1111
                                                        *--s = 'x';
 
1112
                                                        *--s = '0';
 
1113
                                                        s_len += 2;
 
1114
                                                }
 
1115
                                        } else {
 
1116
                                                s = "%p";
 
1117
                                                s_len = 2;
 
1118
                                        }
 
1119
                                        pad_char = ' ';
 
1120
                                        break;
 
1121
 
 
1122
 
 
1123
                                case NUL:
 
1124
                                        /*
 
1125
                                         * The last character of the format string was %.
 
1126
                                         * We ignore it.
 
1127
                                         */
 
1128
                                        continue;
 
1129
 
 
1130
 
 
1131
fmt_error:
 
1132
                                php_error(E_ERROR, "Illegal length modifier specified '%c' in s[np]printf call", *fmt);
 
1133
                                        /*
 
1134
                                         * The default case is for unrecognized %'s.
 
1135
                                         * We print %<char> to help the user identify what
 
1136
                                         * option is not understood.
 
1137
                                         * This is also useful in case the user wants to pass
 
1138
                                         * the output of format_converter to another function
 
1139
                                         * that understands some other %<char> (like syslog).
 
1140
                                         * Note that we can't point s inside fmt because the
 
1141
                                         * unknown <char> could be preceded by width etc.
 
1142
                                         */
 
1143
                                default:
 
1144
                                        char_buf[0] = '%';
 
1145
                                        char_buf[1] = *fmt;
 
1146
                                        s = char_buf;
 
1147
                                        s_len = 2;
 
1148
                                        pad_char = ' ';
 
1149
                                        break;
 
1150
                        }
 
1151
 
 
1152
                        if (prefix_char != NUL) {
 
1153
                                *--s = prefix_char;
 
1154
                                s_len++;
 
1155
                        }
 
1156
                        if (adjust_width && adjust == RIGHT && min_width > s_len) {
 
1157
                                if (pad_char == '0' && prefix_char != NUL) {
 
1158
                                        INS_CHAR(*s, sp, bep, cc)
 
1159
                                                s++;
 
1160
                                        s_len--;
 
1161
                                        min_width--;
 
1162
                                }
 
1163
                                PAD(min_width, s_len, pad_char);
 
1164
                        }
 
1165
                        /*
 
1166
                         * Print the string s.
 
1167
                         */
 
1168
                        for (i = s_len; i != 0; i--) {
 
1169
                                INS_CHAR(*s, sp, bep, cc);
 
1170
                                s++;
 
1171
                        }
 
1172
 
 
1173
                        if (adjust_width && adjust == LEFT && min_width > s_len)
 
1174
                                PAD(min_width, s_len, pad_char);
 
1175
                        if (free_zcopy) {
 
1176
                                zval_dtor(&zcopy);
 
1177
                        }
 
1178
                }
 
1179
skip_output:
 
1180
                fmt++;
 
1181
        }
 
1182
        odp->nextb = sp;
 
1183
        return (cc);
 
1184
}
 
1185
/* }}} */
 
1186
 
 
1187
/*
 
1188
 * This is the general purpose conversion function.
 
1189
 */
 
1190
static void strx_printv(int *ccp, char *buf, size_t len, const char *format, va_list ap) /* {{{ */
 
1191
{
 
1192
        buffy od;
 
1193
        int cc;
 
1194
 
 
1195
        /*
 
1196
         * First initialize the descriptor
 
1197
         * Notice that if no length is given, we initialize buf_end to the
 
1198
         * highest possible address.
 
1199
         */
 
1200
        if (len == 0) {
 
1201
                od.buf_end = (char *) ~0;
 
1202
                od.nextb   = (char *) ~0;
 
1203
        } else {
 
1204
                od.buf_end = &buf[len-1];
 
1205
                od.nextb   = buf;
 
1206
        }
 
1207
 
 
1208
        /*
 
1209
         * Do the conversion
 
1210
         */
 
1211
        cc = format_converter(&od, format, ap);
 
1212
        if (len != 0 && od.nextb <= od.buf_end) {
 
1213
                *(od.nextb) = '\0';
 
1214
        }
 
1215
        if (ccp) {
 
1216
                *ccp = cc;
 
1217
        }
 
1218
}
 
1219
/* }}} */
 
1220
 
 
1221
PHPAPI int ap_php_slprintf(char *buf, size_t len, const char *format,...) /* {{{ */
 
1222
{
 
1223
        int cc;
 
1224
        va_list ap;
 
1225
 
 
1226
        va_start(ap, format);
 
1227
        strx_printv(&cc, buf, len, format, ap);
 
1228
        va_end(ap);
 
1229
        if (cc >= len) {
 
1230
                cc = len -1;
 
1231
                buf[cc] = '\0';
 
1232
        }
 
1233
        return cc;
 
1234
}
 
1235
/* }}} */
 
1236
 
 
1237
PHPAPI int ap_php_vslprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
 
1238
{
 
1239
        int cc;
 
1240
 
 
1241
        strx_printv(&cc, buf, len, format, ap);
 
1242
        if (cc >= len) {
 
1243
                cc = len -1;
 
1244
                buf[cc] = '\0';
 
1245
        }
 
1246
        return cc;
 
1247
}
 
1248
/* }}} */
 
1249
 
 
1250
PHPAPI int ap_php_snprintf(char *buf, size_t len, const char *format,...) /* {{{ */
 
1251
{
 
1252
        int cc;
 
1253
        va_list ap;
 
1254
 
 
1255
        va_start(ap, format);
 
1256
        strx_printv(&cc, buf, len, format, ap);
 
1257
        va_end(ap);
 
1258
        return (cc);
 
1259
}
 
1260
/* }}} */
 
1261
 
 
1262
PHPAPI int ap_php_vsnprintf(char *buf, size_t len, const char *format, va_list ap) /* {{{ */
 
1263
{
 
1264
        int cc;
 
1265
 
 
1266
        strx_printv(&cc, buf, len, format, ap);
 
1267
        return (cc);
 
1268
}
 
1269
/* }}} */
 
1270
 
 
1271
PHPAPI int ap_php_vasprintf(char **buf, const char *format, va_list ap) /* {{{ */
 
1272
{
 
1273
        va_list ap2;
 
1274
        int cc;
 
1275
 
 
1276
        va_copy(ap2, ap);
 
1277
        cc = ap_php_vsnprintf(NULL, 0, format, ap2);
 
1278
        va_end(ap2);
 
1279
 
 
1280
        *buf = NULL;
 
1281
 
 
1282
        if (cc >= 0) {
 
1283
                if ((*buf = malloc(++cc)) != NULL) {
 
1284
                        if ((cc = ap_php_vsnprintf(*buf, cc, format, ap)) < 0) {
 
1285
                                free(*buf);
 
1286
                                *buf = NULL;
 
1287
                        }
 
1288
                }
 
1289
        }
 
1290
 
 
1291
        return cc;
 
1292
}
 
1293
/* }}} */
 
1294
 
 
1295
PHPAPI int ap_php_asprintf(char **buf, const char *format, ...) /* {{{ */
 
1296
{
 
1297
        int cc;
 
1298
        va_list ap;
 
1299
 
 
1300
        va_start(ap, format);
 
1301
        cc = vasprintf(buf, format, ap);
 
1302
        va_end(ap);
 
1303
        return cc;
 
1304
}
 
1305
/* }}} */
 
1306
 
 
1307
/*
 
1308
 * Local variables:
 
1309
 * tab-width: 4
 
1310
 * c-basic-offset: 4
 
1311
 * End:
 
1312
 * vim600: sw=4 ts=4 fdm=marker
 
1313
 * vim<600: sw=4 ts=4
 
1314
 */