1999-04-17 00:37:12 +00:00
|
|
|
|
/*
|
|
|
|
|
+----------------------------------------------------------------------+
|
2019-01-30 09:03:12 +00:00
|
|
|
|
| Copyright (c) The PHP Group |
|
1999-04-17 00:37:12 +00:00
|
|
|
|
+----------------------------------------------------------------------+
|
2006-01-01 12:51:34 +00:00
|
|
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
1999-07-16 13:13:16 +00:00
|
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
2003-06-10 20:04:29 +00:00
|
|
|
|
| available through the world-wide-web at the following url: |
|
2021-05-06 10:16:35 +00:00
|
|
|
|
| https://www.php.net/license/3_01.txt |
|
1999-07-16 13:13:16 +00:00
|
|
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
|
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
|
|
|
| license@php.net so we can mail you a copy immediately. |
|
1999-04-17 00:37:12 +00:00
|
|
|
|
+----------------------------------------------------------------------+
|
2014-12-30 08:16:21 +00:00
|
|
|
|
| Author: Stig S<EFBFBD>ther Bakken <ssb@php.net> |
|
1999-04-17 00:37:12 +00:00
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <math.h> /* modf() */
|
|
|
|
|
#include "php.h"
|
|
|
|
|
#include "zend_execute.h"
|
|
|
|
|
|
2002-06-17 11:50:25 +00:00
|
|
|
|
#include <locale.h>
|
2014-12-06 10:59:43 +00:00
|
|
|
|
#ifdef ZTS
|
2024-06-01 16:12:42 +00:00
|
|
|
|
#include "ext/standard/php_string.h" /* for localeconv_r() */
|
2014-12-06 10:59:43 +00:00
|
|
|
|
#define LCONV_DECIMAL_POINT (*lconv.decimal_point)
|
|
|
|
|
#else
|
2006-12-19 13:13:29 +00:00
|
|
|
|
#define LCONV_DECIMAL_POINT (*lconv->decimal_point)
|
2014-12-06 10:59:43 +00:00
|
|
|
|
#endif
|
2002-06-17 11:50:25 +00:00
|
|
|
|
|
1999-04-17 00:37:12 +00:00
|
|
|
|
#define ALIGN_LEFT 0
|
|
|
|
|
#define ALIGN_RIGHT 1
|
|
|
|
|
#define ADJ_WIDTH 1
|
|
|
|
|
#define ADJ_PRECISION 2
|
|
|
|
|
#define NUM_BUF_SIZE 500
|
|
|
|
|
#define FLOAT_PRECISION 6
|
2010-11-19 16:36:10 +00:00
|
|
|
|
#define MAX_FLOAT_PRECISION 53
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* trick to control varargs functions through cpp */
|
1999-08-02 19:17:14 +00:00
|
|
|
|
# define PRINTF_DEBUG(arg) php_printf arg
|
1999-04-17 00:37:12 +00:00
|
|
|
|
#else
|
|
|
|
|
# define PRINTF_DEBUG(arg)
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-12-14 19:14:36 +00:00
|
|
|
|
static const char hexchars[] = "0123456789abcdef";
|
|
|
|
|
static const char HEXCHARS[] = "0123456789ABCDEF";
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* php_spintf_appendchar() {{{ */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
inline static void
|
2014-12-13 22:06:14 +00:00
|
|
|
|
php_sprintf_appendchar(zend_string **buffer, size_t *pos, char add)
|
1999-04-17 00:37:12 +00:00
|
|
|
|
{
|
2018-11-06 20:11:28 +00:00
|
|
|
|
if ((*pos + 1) >= ZSTR_LEN(*buffer)) {
|
2015-06-30 01:05:24 +00:00
|
|
|
|
PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer)));
|
|
|
|
|
*buffer = zend_string_extend(*buffer, ZSTR_LEN(*buffer) << 1, 0);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
|
|
|
|
PRINTF_DEBUG(("sprintf: appending '%c', pos=\n", add, *pos));
|
2015-06-30 01:05:24 +00:00
|
|
|
|
ZSTR_VAL(*buffer)[(*pos)++] = add;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
/* php_spintf_appendchar() {{{ */
|
|
|
|
|
inline static void
|
|
|
|
|
php_sprintf_appendchars(zend_string **buffer, size_t *pos, char *add, size_t len)
|
|
|
|
|
{
|
|
|
|
|
if ((*pos + len) >= ZSTR_LEN(*buffer)) {
|
|
|
|
|
size_t nlen = ZSTR_LEN(*buffer);
|
|
|
|
|
|
|
|
|
|
PRINTF_DEBUG(("%s(): ereallocing buffer to %d bytes\n", get_active_function_name(), ZSTR_LEN(*buffer)));
|
|
|
|
|
do {
|
|
|
|
|
nlen = nlen << 1;
|
|
|
|
|
} while ((*pos + len) >= nlen);
|
|
|
|
|
*buffer = zend_string_extend(*buffer, nlen, 0);
|
|
|
|
|
}
|
|
|
|
|
PRINTF_DEBUG(("sprintf: appending \"%s\", pos=\n", add, *pos));
|
|
|
|
|
memcpy(ZSTR_VAL(*buffer) + (*pos), add, len);
|
|
|
|
|
*pos += len;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* php_spintf_appendstring() {{{ */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
inline static void
|
2014-08-25 18:22:49 +00:00
|
|
|
|
php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add,
|
|
|
|
|
size_t min_width, size_t max_width, char padding,
|
2021-07-14 17:59:51 +00:00
|
|
|
|
size_t alignment, size_t len, bool neg, int expprec, int always_sign)
|
1999-04-17 00:37:12 +00:00
|
|
|
|
{
|
2021-05-14 12:38:01 +00:00
|
|
|
|
size_t npad;
|
2014-08-25 18:22:49 +00:00
|
|
|
|
size_t req_size;
|
|
|
|
|
size_t copy_len;
|
|
|
|
|
size_t m_width;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2003-02-15 15:57:31 +00:00
|
|
|
|
copy_len = (expprec ? MIN(max_width, len) : len);
|
2014-08-16 10:55:13 +00:00
|
|
|
|
npad = (min_width < copy_len) ? 0 : min_width - copy_len;
|
2000-07-18 16:34:30 +00:00
|
|
|
|
|
1999-04-17 00:37:12 +00:00
|
|
|
|
PRINTF_DEBUG(("sprintf: appendstring(%x, %d, %d, \"%s\", %d, '%c', %d)\n",
|
2015-06-30 01:05:24 +00:00
|
|
|
|
*buffer, *pos, ZSTR_LEN(*buffer), add, min_width, padding, alignment));
|
2008-03-17 23:06:32 +00:00
|
|
|
|
m_width = MAX(min_width, copy_len);
|
2003-02-15 15:57:31 +00:00
|
|
|
|
|
2008-03-17 23:06:32 +00:00
|
|
|
|
if(m_width > INT_MAX - *pos - 1) {
|
2016-06-21 13:00:37 +00:00
|
|
|
|
zend_error_noreturn(E_ERROR, "Field width %zd is too long", m_width);
|
2008-03-17 23:06:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req_size = *pos + m_width + 1;
|
2003-02-15 15:57:31 +00:00
|
|
|
|
|
2018-11-06 20:11:28 +00:00
|
|
|
|
if (req_size > ZSTR_LEN(*buffer)) {
|
2015-06-30 01:05:24 +00:00
|
|
|
|
size_t size = ZSTR_LEN(*buffer);
|
2014-02-13 13:54:23 +00:00
|
|
|
|
while (req_size > size) {
|
2014-08-16 10:55:13 +00:00
|
|
|
|
if (size > ZEND_SIZE_MAX/2) {
|
2015-01-03 09:22:58 +00:00
|
|
|
|
zend_error_noreturn(E_ERROR, "Field width %zd is too long", req_size);
|
2008-03-17 23:06:32 +00:00
|
|
|
|
}
|
2014-02-13 13:54:23 +00:00
|
|
|
|
size <<= 1;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2014-02-13 13:54:23 +00:00
|
|
|
|
PRINTF_DEBUG(("sprintf ereallocing buffer to %d bytes\n", size));
|
2015-03-19 23:02:42 +00:00
|
|
|
|
*buffer = zend_string_extend(*buffer, size, 0);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
|
|
|
|
if (alignment == ALIGN_RIGHT) {
|
2004-01-21 04:00:07 +00:00
|
|
|
|
if ((neg || always_sign) && padding=='0') {
|
2015-06-30 01:05:24 +00:00
|
|
|
|
ZSTR_VAL(*buffer)[(*pos)++] = (neg) ? '-' : '+';
|
2000-07-18 16:34:30 +00:00
|
|
|
|
add++;
|
|
|
|
|
len--;
|
2003-05-30 13:49:33 +00:00
|
|
|
|
copy_len--;
|
2000-07-18 16:34:30 +00:00
|
|
|
|
}
|
1999-04-17 00:37:12 +00:00
|
|
|
|
while (npad-- > 0) {
|
2015-06-30 01:05:24 +00:00
|
|
|
|
ZSTR_VAL(*buffer)[(*pos)++] = padding;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PRINTF_DEBUG(("sprintf: appending \"%s\"\n", add));
|
2015-06-30 01:05:24 +00:00
|
|
|
|
memcpy(&ZSTR_VAL(*buffer)[*pos], add, copy_len + 1);
|
2003-02-15 15:57:31 +00:00
|
|
|
|
*pos += copy_len;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
if (alignment == ALIGN_LEFT) {
|
|
|
|
|
while (npad--) {
|
2015-06-30 01:05:24 +00:00
|
|
|
|
ZSTR_VAL(*buffer)[(*pos)++] = padding;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* php_spintf_appendint() {{{ */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
inline static void
|
2014-08-25 18:22:49 +00:00
|
|
|
|
php_sprintf_appendint(zend_string **buffer, size_t *pos, zend_long number,
|
2015-01-03 09:22:58 +00:00
|
|
|
|
size_t width, char padding, size_t alignment,
|
2002-09-21 15:08:59 +00:00
|
|
|
|
int always_sign)
|
1999-04-17 00:37:12 +00:00
|
|
|
|
{
|
|
|
|
|
char numbuf[NUM_BUF_SIZE];
|
2021-05-14 12:38:01 +00:00
|
|
|
|
zend_ulong magn, nmagn;
|
|
|
|
|
unsigned int i = NUM_BUF_SIZE - 1, neg = 0;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
|
|
|
|
PRINTF_DEBUG(("sprintf: appendint(%x, %x, %x, %d, %d, '%c', %d)\n",
|
2015-06-30 01:05:24 +00:00
|
|
|
|
*buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment));
|
1999-04-17 00:37:12 +00:00
|
|
|
|
if (number < 0) {
|
|
|
|
|
neg = 1;
|
2014-08-25 17:24:55 +00:00
|
|
|
|
magn = ((zend_ulong) -(number + 1)) + 1;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
} else {
|
2014-08-25 17:24:55 +00:00
|
|
|
|
magn = (zend_ulong) number;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-08-03 20:08:33 +00:00
|
|
|
|
/* Can't right-pad 0's on integers */
|
|
|
|
|
if(alignment==0 && padding=='0') padding=' ';
|
|
|
|
|
|
1999-04-17 00:37:12 +00:00
|
|
|
|
numbuf[i] = '\0';
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
nmagn = magn / 10;
|
|
|
|
|
|
2001-07-19 08:12:12 +00:00
|
|
|
|
numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
|
1999-04-17 00:37:12 +00:00
|
|
|
|
magn = nmagn;
|
|
|
|
|
}
|
2014-12-30 08:16:21 +00:00
|
|
|
|
while (magn > 0 && i > 1);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
if (neg) {
|
|
|
|
|
numbuf[--i] = '-';
|
2002-09-21 15:08:59 +00:00
|
|
|
|
} else if (always_sign) {
|
|
|
|
|
numbuf[--i] = '+';
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
|
|
|
|
PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n",
|
|
|
|
|
number, &numbuf[i], i));
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0,
|
2000-07-18 16:34:30 +00:00
|
|
|
|
padding, alignment, (NUM_BUF_SIZE - 1) - i,
|
2004-01-21 04:00:07 +00:00
|
|
|
|
neg, 0, always_sign);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* php_spintf_appenduint() {{{ */
|
2001-05-20 00:23:49 +00:00
|
|
|
|
inline static void
|
2014-08-25 18:22:49 +00:00
|
|
|
|
php_sprintf_appenduint(zend_string **buffer, size_t *pos,
|
2014-08-25 17:24:55 +00:00
|
|
|
|
zend_ulong number,
|
2014-08-25 18:22:49 +00:00
|
|
|
|
size_t width, char padding, size_t alignment)
|
2001-05-20 00:23:49 +00:00
|
|
|
|
{
|
|
|
|
|
char numbuf[NUM_BUF_SIZE];
|
2021-05-14 12:38:01 +00:00
|
|
|
|
zend_ulong magn, nmagn;
|
|
|
|
|
unsigned int i = NUM_BUF_SIZE - 1;
|
2001-05-20 00:23:49 +00:00
|
|
|
|
|
|
|
|
|
PRINTF_DEBUG(("sprintf: appenduint(%x, %x, %x, %d, %d, '%c', %d)\n",
|
2015-06-30 01:05:24 +00:00
|
|
|
|
*buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment));
|
2014-08-25 17:24:55 +00:00
|
|
|
|
magn = (zend_ulong) number;
|
2001-05-20 00:23:49 +00:00
|
|
|
|
|
|
|
|
|
/* Can't right-pad 0's on integers */
|
|
|
|
|
if (alignment == 0 && padding == '0') padding = ' ';
|
|
|
|
|
|
|
|
|
|
numbuf[i] = '\0';
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
nmagn = magn / 10;
|
|
|
|
|
|
2001-07-19 08:12:12 +00:00
|
|
|
|
numbuf[--i] = (unsigned char)(magn - (nmagn * 10)) + '0';
|
2001-05-20 00:23:49 +00:00
|
|
|
|
magn = nmagn;
|
2002-09-21 15:08:59 +00:00
|
|
|
|
} while (magn > 0 && i > 0);
|
|
|
|
|
|
2001-05-20 00:23:49 +00:00
|
|
|
|
PRINTF_DEBUG(("sprintf: appending %d as \"%s\", i=%d\n", number, &numbuf[i], i));
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0,
|
2021-07-14 17:59:51 +00:00
|
|
|
|
padding, alignment, (NUM_BUF_SIZE - 1) - i, /* neg */ false, 0, 0);
|
2001-05-20 00:23:49 +00:00
|
|
|
|
}
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* php_spintf_appenddouble() {{{ */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
inline static void
|
2014-08-25 18:22:49 +00:00
|
|
|
|
php_sprintf_appenddouble(zend_string **buffer, size_t *pos,
|
2014-02-13 13:54:23 +00:00
|
|
|
|
double number,
|
2014-08-25 18:22:49 +00:00
|
|
|
|
size_t width, char padding,
|
|
|
|
|
size_t alignment, int precision,
|
2002-09-21 15:08:59 +00:00
|
|
|
|
int adjust, char fmt,
|
2002-10-11 04:44:14 +00:00
|
|
|
|
int always_sign
|
2014-12-13 22:06:14 +00:00
|
|
|
|
)
|
1999-04-17 00:37:12 +00:00
|
|
|
|
{
|
2006-12-06 09:52:51 +00:00
|
|
|
|
char num_buf[NUM_BUF_SIZE];
|
2006-12-19 11:54:38 +00:00
|
|
|
|
char *s = NULL;
|
2014-08-25 18:22:49 +00:00
|
|
|
|
size_t s_len = 0;
|
2021-07-14 17:59:51 +00:00
|
|
|
|
bool is_negative = false;
|
2014-12-06 10:59:43 +00:00
|
|
|
|
#ifdef ZTS
|
|
|
|
|
struct lconv lconv;
|
|
|
|
|
#else
|
2006-12-19 11:54:38 +00:00
|
|
|
|
struct lconv *lconv;
|
2006-12-19 13:13:29 +00:00
|
|
|
|
#endif
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
|
|
|
|
PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n",
|
2015-06-30 01:05:24 +00:00
|
|
|
|
*buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment, fmt));
|
1999-04-17 00:37:12 +00:00
|
|
|
|
if ((adjust & ADJ_PRECISION) == 0) {
|
|
|
|
|
precision = FLOAT_PRECISION;
|
|
|
|
|
} else if (precision > MAX_FLOAT_PRECISION) {
|
2014-12-13 22:06:14 +00:00
|
|
|
|
php_error_docref(NULL, E_NOTICE, "Requested precision of %d digits was truncated to PHP maximum of %d digits", precision, MAX_FLOAT_PRECISION);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
precision = MAX_FLOAT_PRECISION;
|
|
|
|
|
}
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
2000-08-20 06:08:14 +00:00
|
|
|
|
if (zend_isnan(number)) {
|
2006-12-06 09:52:51 +00:00
|
|
|
|
is_negative = (number<0);
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appendstring(buffer, pos, "NaN", 3, 0, padding,
|
2009-11-02 17:37:32 +00:00
|
|
|
|
alignment, 3, is_negative, 0, always_sign);
|
2000-08-14 10:02:14 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-08-20 06:08:14 +00:00
|
|
|
|
if (zend_isinf(number)) {
|
2006-12-06 09:52:51 +00:00
|
|
|
|
is_negative = (number<0);
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appendstring(buffer, pos, "INF", 3, 0, padding,
|
2009-11-02 17:37:32 +00:00
|
|
|
|
alignment, 3, is_negative, 0, always_sign);
|
2000-08-14 10:02:14 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-03 09:22:58 +00:00
|
|
|
|
switch (fmt) {
|
2006-12-06 09:52:51 +00:00
|
|
|
|
case 'e':
|
|
|
|
|
case 'E':
|
|
|
|
|
case 'f':
|
2006-12-18 09:26:54 +00:00
|
|
|
|
case 'F':
|
2014-12-06 10:59:43 +00:00
|
|
|
|
#ifdef ZTS
|
|
|
|
|
localeconv_r(&lconv);
|
|
|
|
|
#else
|
2006-12-19 11:54:38 +00:00
|
|
|
|
lconv = localeconv();
|
2006-12-19 13:13:29 +00:00
|
|
|
|
#endif
|
2006-12-19 11:54:38 +00:00
|
|
|
|
s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision,
|
2006-12-19 13:13:29 +00:00
|
|
|
|
(fmt == 'f')?LCONV_DECIMAL_POINT:'.',
|
2006-12-06 09:52:51 +00:00
|
|
|
|
&is_negative, &num_buf[1], &s_len);
|
|
|
|
|
if (is_negative) {
|
|
|
|
|
num_buf[0] = '-';
|
|
|
|
|
s = num_buf;
|
|
|
|
|
s_len++;
|
|
|
|
|
} else if (always_sign) {
|
|
|
|
|
num_buf[0] = '+';
|
|
|
|
|
s = num_buf;
|
|
|
|
|
s_len++;
|
2002-10-15 12:07:36 +00:00
|
|
|
|
}
|
2006-12-06 09:52:51 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'g':
|
|
|
|
|
case 'G':
|
2020-04-22 13:02:21 +00:00
|
|
|
|
case 'h':
|
|
|
|
|
case 'H':
|
|
|
|
|
{
|
2006-12-06 09:52:51 +00:00
|
|
|
|
if (precision == 0)
|
|
|
|
|
precision = 1;
|
2020-04-22 13:02:21 +00:00
|
|
|
|
|
|
|
|
|
char decimal_point = '.';
|
|
|
|
|
if (fmt == 'g' || fmt == 'G') {
|
2014-12-06 10:59:43 +00:00
|
|
|
|
#ifdef ZTS
|
2020-04-22 13:02:21 +00:00
|
|
|
|
localeconv_r(&lconv);
|
2014-12-06 10:59:43 +00:00
|
|
|
|
#else
|
2020-04-22 13:02:21 +00:00
|
|
|
|
lconv = localeconv();
|
2006-12-19 13:13:29 +00:00
|
|
|
|
#endif
|
2020-04-22 13:02:21 +00:00
|
|
|
|
decimal_point = LCONV_DECIMAL_POINT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char exp_char = fmt == 'G' || fmt == 'H' ? 'E' : 'e';
|
|
|
|
|
/* We use &num_buf[ 1 ], so that we have room for the sign. */
|
2021-08-02 12:40:01 +00:00
|
|
|
|
s = zend_gcvt(number, precision, decimal_point, exp_char, &num_buf[1]);
|
2006-12-06 09:52:51 +00:00
|
|
|
|
is_negative = 0;
|
|
|
|
|
if (*s == '-') {
|
|
|
|
|
is_negative = 1;
|
|
|
|
|
s = &num_buf[1];
|
|
|
|
|
} else if (always_sign) {
|
|
|
|
|
num_buf[0] = '+';
|
|
|
|
|
s = num_buf;
|
2003-02-13 17:25:31 +00:00
|
|
|
|
}
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2006-12-06 09:52:51 +00:00
|
|
|
|
s_len = strlen(s);
|
|
|
|
|
break;
|
2020-04-22 13:02:21 +00:00
|
|
|
|
}
|
2006-12-06 09:52:51 +00:00
|
|
|
|
}
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appendstring(buffer, pos, s, width, 0, padding,
|
2006-12-06 09:52:51 +00:00
|
|
|
|
alignment, s_len, is_negative, 0, always_sign);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* php_spintf_appendd2n() {{{ */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
inline static void
|
2014-08-25 18:22:49 +00:00
|
|
|
|
php_sprintf_append2n(zend_string **buffer, size_t *pos, zend_long number,
|
|
|
|
|
size_t width, char padding, size_t alignment, int n,
|
2017-12-14 19:14:36 +00:00
|
|
|
|
const char *chartable, int expprec)
|
1999-04-17 00:37:12 +00:00
|
|
|
|
{
|
|
|
|
|
char numbuf[NUM_BUF_SIZE];
|
2021-05-14 12:38:01 +00:00
|
|
|
|
zend_ulong num;
|
|
|
|
|
zend_ulong i = NUM_BUF_SIZE - 1;
|
|
|
|
|
int andbits = (1 << n) - 1;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
|
|
|
|
PRINTF_DEBUG(("sprintf: append2n(%x, %x, %x, %d, %d, '%c', %d, %d, %x)\n",
|
2015-06-30 01:05:24 +00:00
|
|
|
|
*buffer, pos, &ZSTR_LEN(*buffer), number, width, padding, alignment, n,
|
1999-04-17 00:37:12 +00:00
|
|
|
|
chartable));
|
|
|
|
|
PRINTF_DEBUG(("sprintf: append2n 2^%d andbits=%x\n", n, andbits));
|
|
|
|
|
|
2014-08-25 17:24:55 +00:00
|
|
|
|
num = (zend_ulong) number;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
numbuf[i] = '\0';
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
numbuf[--i] = chartable[(num & andbits)];
|
|
|
|
|
num >>= n;
|
|
|
|
|
}
|
|
|
|
|
while (num > 0);
|
|
|
|
|
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0,
|
2000-07-18 16:34:30 +00:00
|
|
|
|
padding, alignment, (NUM_BUF_SIZE - 1) - i,
|
2021-07-14 17:59:51 +00:00
|
|
|
|
/* neg */ false, expprec, 0);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* php_spintf_getnumber() {{{ */
|
2007-01-13 16:31:17 +00:00
|
|
|
|
inline static int
|
2018-11-06 23:40:15 +00:00
|
|
|
|
php_sprintf_getnumber(char **buffer, size_t *len)
|
1999-04-17 00:37:12 +00:00
|
|
|
|
{
|
|
|
|
|
char *endptr;
|
2021-05-14 12:38:01 +00:00
|
|
|
|
zend_long num = ZEND_STRTOL(*buffer, &endptr, 10);
|
|
|
|
|
size_t i;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
|
|
|
|
if (endptr != NULL) {
|
2018-11-06 23:40:15 +00:00
|
|
|
|
i = (endptr - *buffer);
|
2019-03-08 12:23:07 +00:00
|
|
|
|
*len -= i;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
*buffer = endptr;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
|
|
|
|
PRINTF_DEBUG(("sprintf_getnumber: number was %d bytes long\n", i));
|
2007-01-13 16:31:17 +00:00
|
|
|
|
|
|
|
|
|
if (num >= INT_MAX || num < 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
return (int) num;
|
|
|
|
|
}
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2020-04-21 14:54:22 +00:00
|
|
|
|
#define ARG_NUM_NEXT -1
|
|
|
|
|
#define ARG_NUM_INVALID -2
|
|
|
|
|
|
|
|
|
|
int php_sprintf_get_argnum(char **format, size_t *format_len) {
|
|
|
|
|
char *temppos = *format;
|
|
|
|
|
while (isdigit((int) *temppos)) temppos++;
|
|
|
|
|
if (*temppos != '$') {
|
|
|
|
|
return ARG_NUM_NEXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int argnum = php_sprintf_getnumber(format, format_len);
|
|
|
|
|
if (argnum <= 0) {
|
2021-09-25 15:43:53 +00:00
|
|
|
|
zend_value_error("Argument number specifier must be greater than zero and less than %d", INT_MAX);
|
2020-04-21 14:54:22 +00:00
|
|
|
|
return ARG_NUM_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*format)++; /* skip the '$' */
|
|
|
|
|
(*format_len)--;
|
|
|
|
|
return argnum - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-09 21:19:38 +00:00
|
|
|
|
/* php_formatted_print() {{{
|
1999-04-17 00:37:12 +00:00
|
|
|
|
* New sprintf implementation for PHP.
|
|
|
|
|
*
|
|
|
|
|
* Modifiers:
|
|
|
|
|
*
|
|
|
|
|
* " " pad integers with spaces
|
|
|
|
|
* "-" left adjusted field
|
|
|
|
|
* n field size
|
|
|
|
|
* "."n precision (floats only)
|
2002-09-21 15:08:59 +00:00
|
|
|
|
* "+" Always place a sign (+ or -) in front of a number
|
1999-04-17 00:37:12 +00:00
|
|
|
|
*
|
|
|
|
|
* Type specifiers:
|
|
|
|
|
*
|
|
|
|
|
* "%" literal "%", modifiers are ignored.
|
|
|
|
|
* "b" integer argument is printed as binary
|
|
|
|
|
* "c" integer argument is printed as a single character
|
|
|
|
|
* "d" argument is an integer
|
|
|
|
|
* "f" the argument is a float
|
|
|
|
|
* "o" integer argument is printed as octal
|
|
|
|
|
* "s" argument is a string
|
|
|
|
|
* "x" integer argument is printed as lowercase hexadecimal
|
|
|
|
|
* "X" integer argument is printed as uppercase hexadecimal
|
|
|
|
|
*
|
2019-10-15 15:51:39 +00:00
|
|
|
|
* nb_additional_parameters is used for throwing errors:
|
|
|
|
|
* - -1: ValueError is thrown (for vsprintf where args originates from an array)
|
|
|
|
|
* - 0 or more: ArgumentCountError is thrown
|
1999-04-17 00:37:12 +00:00
|
|
|
|
*/
|
2014-02-13 13:54:23 +00:00
|
|
|
|
static zend_string *
|
2019-11-15 19:31:19 +00:00
|
|
|
|
php_formatted_print(char *format, size_t format_len, zval *args, int argc, int nb_additional_parameters)
|
1999-04-17 00:37:12 +00:00
|
|
|
|
{
|
2018-11-06 23:40:15 +00:00
|
|
|
|
size_t size = 240, outpos = 0;
|
2007-01-13 16:31:17 +00:00
|
|
|
|
int alignment, currarg, adjusting, argnum, width, precision;
|
2019-11-15 19:31:19 +00:00
|
|
|
|
char *temppos, padding;
|
2014-02-13 13:54:23 +00:00
|
|
|
|
zend_string *result;
|
2002-09-21 15:08:59 +00:00
|
|
|
|
int always_sign;
|
2020-04-21 15:00:12 +00:00
|
|
|
|
int max_missing_argnum = -1;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2014-08-25 17:24:55 +00:00
|
|
|
|
result = zend_string_alloc(size, 0);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
currarg = 0;
|
2019-10-15 15:51:39 +00:00
|
|
|
|
argnum = 0;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
while (format_len) {
|
|
|
|
|
int expprec;
|
2014-06-05 12:04:11 +00:00
|
|
|
|
zval *tmp;
|
2000-07-18 16:34:30 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
temppos = memchr(format, '%', format_len);
|
|
|
|
|
if (!temppos) {
|
|
|
|
|
php_sprintf_appendchars(&result, &outpos, format, format_len);
|
|
|
|
|
break;
|
|
|
|
|
} else if (temppos != format) {
|
|
|
|
|
php_sprintf_appendchars(&result, &outpos, format, temppos - format);
|
|
|
|
|
format_len -= temppos - format;
|
|
|
|
|
format = temppos;
|
|
|
|
|
}
|
|
|
|
|
format++; /* skip the '%' */
|
|
|
|
|
format_len--;
|
|
|
|
|
|
|
|
|
|
if (*format == '%') {
|
2014-12-13 22:06:14 +00:00
|
|
|
|
php_sprintf_appendchar(&result, &outpos, '%');
|
2018-11-06 23:40:15 +00:00
|
|
|
|
format++;
|
|
|
|
|
format_len--;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
} else {
|
|
|
|
|
/* starting a new format specifier, reset variables */
|
|
|
|
|
alignment = ALIGN_RIGHT;
|
|
|
|
|
adjusting = 0;
|
|
|
|
|
padding = ' ';
|
2002-09-21 15:08:59 +00:00
|
|
|
|
always_sign = 0;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
expprec = 0;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
|
|
|
|
PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n",
|
2018-11-06 23:40:15 +00:00
|
|
|
|
*format, format - Z_STRVAL_P(z_format)));
|
|
|
|
|
if (isalpha((int)*format)) {
|
|
|
|
|
width = precision = 0;
|
2020-04-21 14:54:22 +00:00
|
|
|
|
argnum = ARG_NUM_NEXT;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
} else {
|
2001-04-09 15:44:24 +00:00
|
|
|
|
/* first look for argnum */
|
2020-04-21 14:54:22 +00:00
|
|
|
|
argnum = php_sprintf_get_argnum(&format, &format_len);
|
|
|
|
|
if (argnum == ARG_NUM_INVALID) {
|
|
|
|
|
goto fail;
|
2001-04-09 15:44:24 +00:00
|
|
|
|
}
|
2003-01-09 17:29:31 +00:00
|
|
|
|
|
2001-04-09 15:44:24 +00:00
|
|
|
|
/* after argnum comes modifiers */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
PRINTF_DEBUG(("sprintf: looking for modifiers\n"
|
|
|
|
|
"sprintf: now looking at '%c', inpos=%d\n",
|
2018-11-06 23:40:15 +00:00
|
|
|
|
*format, format - Z_STRVAL_P(z_format)));
|
|
|
|
|
for (;; format++, format_len--) {
|
|
|
|
|
if (*format == ' ' || *format == '0') {
|
|
|
|
|
padding = *format;
|
|
|
|
|
} else if (*format == '-') {
|
1999-04-17 00:37:12 +00:00
|
|
|
|
alignment = ALIGN_LEFT;
|
|
|
|
|
/* space padding, the default */
|
2018-11-06 23:40:15 +00:00
|
|
|
|
} else if (*format == '+') {
|
2002-09-21 15:08:59 +00:00
|
|
|
|
always_sign = 1;
|
2020-04-22 08:11:58 +00:00
|
|
|
|
} else if (*format == '\'') {
|
|
|
|
|
if (format_len > 1) {
|
|
|
|
|
format++;
|
|
|
|
|
format_len--;
|
|
|
|
|
padding = *format;
|
|
|
|
|
} else {
|
|
|
|
|
zend_value_error("Missing padding character");
|
2020-04-22 08:13:25 +00:00
|
|
|
|
goto fail;
|
2020-04-22 08:11:58 +00:00
|
|
|
|
}
|
1999-04-17 00:37:12 +00:00
|
|
|
|
} else {
|
|
|
|
|
PRINTF_DEBUG(("sprintf: end of modifiers\n"));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PRINTF_DEBUG(("sprintf: padding='%c'\n", padding));
|
|
|
|
|
PRINTF_DEBUG(("sprintf: alignment=%s\n",
|
|
|
|
|
(alignment == ALIGN_LEFT) ? "left" : "right"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* after modifiers comes width */
|
2020-04-21 14:54:22 +00:00
|
|
|
|
if (*format == '*') {
|
|
|
|
|
format++;
|
|
|
|
|
format_len--;
|
|
|
|
|
|
|
|
|
|
int width_argnum = php_sprintf_get_argnum(&format, &format_len);
|
|
|
|
|
if (width_argnum == ARG_NUM_INVALID) {
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
if (width_argnum == ARG_NUM_NEXT) {
|
|
|
|
|
width_argnum = currarg++;
|
|
|
|
|
}
|
|
|
|
|
if (width_argnum >= argc) {
|
|
|
|
|
max_missing_argnum = MAX(max_missing_argnum, width_argnum);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
tmp = &args[width_argnum];
|
|
|
|
|
ZVAL_DEREF(tmp);
|
|
|
|
|
if (Z_TYPE_P(tmp) != IS_LONG) {
|
|
|
|
|
zend_value_error("Width must be an integer");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
if (Z_LVAL_P(tmp) < 0 || Z_LVAL_P(tmp) > INT_MAX) {
|
|
|
|
|
zend_value_error("Width must be greater than zero and less than %d", INT_MAX);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
width = Z_LVAL_P(tmp);
|
|
|
|
|
adjusting |= ADJ_WIDTH;
|
|
|
|
|
} else if (isdigit((int)*format)) {
|
1999-04-17 00:37:12 +00:00
|
|
|
|
PRINTF_DEBUG(("sprintf: getting width\n"));
|
2018-11-06 23:40:15 +00:00
|
|
|
|
if ((width = php_sprintf_getnumber(&format, &format_len)) < 0) {
|
2019-10-15 15:51:39 +00:00
|
|
|
|
zend_value_error("Width must be greater than zero and less than %d", INT_MAX);
|
2020-04-22 08:13:25 +00:00
|
|
|
|
goto fail;
|
2007-01-13 16:31:17 +00:00
|
|
|
|
}
|
1999-04-17 00:37:12 +00:00
|
|
|
|
adjusting |= ADJ_WIDTH;
|
|
|
|
|
} else {
|
|
|
|
|
width = 0;
|
|
|
|
|
}
|
|
|
|
|
PRINTF_DEBUG(("sprintf: width=%d\n", width));
|
|
|
|
|
|
2001-04-09 15:44:24 +00:00
|
|
|
|
/* after width and argnum comes precision */
|
2018-11-06 23:40:15 +00:00
|
|
|
|
if (*format == '.') {
|
|
|
|
|
format++;
|
|
|
|
|
format_len--;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
PRINTF_DEBUG(("sprintf: getting precision\n"));
|
2020-04-21 14:54:22 +00:00
|
|
|
|
if (*format == '*') {
|
|
|
|
|
format++;
|
|
|
|
|
format_len--;
|
|
|
|
|
|
|
|
|
|
int prec_argnum = php_sprintf_get_argnum(&format, &format_len);
|
|
|
|
|
if (prec_argnum == ARG_NUM_INVALID) {
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
if (prec_argnum == ARG_NUM_NEXT) {
|
|
|
|
|
prec_argnum = currarg++;
|
|
|
|
|
}
|
|
|
|
|
if (prec_argnum >= argc) {
|
|
|
|
|
max_missing_argnum = MAX(max_missing_argnum, prec_argnum);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
tmp = &args[prec_argnum];
|
|
|
|
|
ZVAL_DEREF(tmp);
|
|
|
|
|
if (Z_TYPE_P(tmp) != IS_LONG) {
|
|
|
|
|
zend_value_error("Precision must be an integer");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
if (Z_LVAL_P(tmp) < -1 || Z_LVAL_P(tmp) > INT_MAX) {
|
|
|
|
|
zend_value_error("Precision must be between -1 and %d", INT_MAX);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
precision = Z_LVAL_P(tmp);
|
|
|
|
|
adjusting |= ADJ_PRECISION;
|
|
|
|
|
expprec = 1;
|
|
|
|
|
} else if (isdigit((int)*format)) {
|
2018-11-06 23:40:15 +00:00
|
|
|
|
if ((precision = php_sprintf_getnumber(&format, &format_len)) < 0) {
|
2019-10-15 15:51:39 +00:00
|
|
|
|
zend_value_error("Precision must be greater than zero and less than %d", INT_MAX);
|
2020-04-22 08:13:25 +00:00
|
|
|
|
goto fail;
|
2007-01-13 16:31:17 +00:00
|
|
|
|
}
|
1999-04-17 00:37:12 +00:00
|
|
|
|
adjusting |= ADJ_PRECISION;
|
2000-07-18 16:34:30 +00:00
|
|
|
|
expprec = 1;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
} else {
|
|
|
|
|
precision = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
precision = 0;
|
|
|
|
|
}
|
|
|
|
|
PRINTF_DEBUG(("sprintf: precision=%d\n", precision));
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
if (*format == 'l') {
|
|
|
|
|
format++;
|
|
|
|
|
format_len--;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2018-11-06 23:40:15 +00:00
|
|
|
|
PRINTF_DEBUG(("sprintf: format character='%c'\n", *format));
|
2019-10-15 15:51:39 +00:00
|
|
|
|
|
2020-04-21 14:54:22 +00:00
|
|
|
|
if (argnum == ARG_NUM_NEXT) {
|
|
|
|
|
argnum = currarg++;
|
|
|
|
|
}
|
2019-10-15 15:51:39 +00:00
|
|
|
|
if (argnum >= argc) {
|
2020-04-21 15:00:12 +00:00
|
|
|
|
max_missing_argnum = MAX(max_missing_argnum, argnum);
|
2019-10-15 15:51:39 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-21 14:54:22 +00:00
|
|
|
|
if (expprec && precision == -1
|
|
|
|
|
&& *format != 'g' && *format != 'G' && *format != 'h' && *format != 'H') {
|
|
|
|
|
zend_value_error("Precision -1 is only supported for %%g, %%G, %%h and %%H");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-17 00:37:12 +00:00
|
|
|
|
/* now we expect to find a type specifier */
|
2014-06-05 12:04:11 +00:00
|
|
|
|
tmp = &args[argnum];
|
2018-11-06 23:40:15 +00:00
|
|
|
|
switch (*format) {
|
2003-12-29 22:26:48 +00:00
|
|
|
|
case 's': {
|
2017-11-16 14:09:32 +00:00
|
|
|
|
zend_string *t;
|
|
|
|
|
zend_string *str = zval_get_tmp_string(tmp, &t);
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appendstring(&result, &outpos,
|
2015-06-30 01:05:24 +00:00
|
|
|
|
ZSTR_VAL(str),
|
2002-10-26 22:18:40 +00:00
|
|
|
|
width, precision, padding,
|
2000-07-18 16:34:30 +00:00
|
|
|
|
alignment,
|
2015-06-30 01:05:24 +00:00
|
|
|
|
ZSTR_LEN(str),
|
2021-07-14 17:59:51 +00:00
|
|
|
|
/* neg */ false, expprec, 0);
|
2017-11-16 14:09:32 +00:00
|
|
|
|
zend_tmp_string_release(t);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
break;
|
2003-12-29 22:26:48 +00:00
|
|
|
|
}
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
|
|
|
|
case 'd':
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appendint(&result, &outpos,
|
2014-08-25 17:24:55 +00:00
|
|
|
|
zval_get_long(tmp),
|
2002-09-21 15:08:59 +00:00
|
|
|
|
width, padding, alignment,
|
|
|
|
|
always_sign);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2001-05-20 00:23:49 +00:00
|
|
|
|
case 'u':
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appenduint(&result, &outpos,
|
2014-08-25 17:24:55 +00:00
|
|
|
|
zval_get_long(tmp),
|
2004-01-21 04:00:07 +00:00
|
|
|
|
width, padding, alignment);
|
2001-05-20 00:23:49 +00:00
|
|
|
|
break;
|
|
|
|
|
|
1999-04-17 00:37:12 +00:00
|
|
|
|
case 'e':
|
2006-12-06 09:52:51 +00:00
|
|
|
|
case 'E':
|
1999-04-17 00:37:12 +00:00
|
|
|
|
case 'f':
|
2004-11-15 13:42:22 +00:00
|
|
|
|
case 'F':
|
2020-04-22 13:02:21 +00:00
|
|
|
|
case 'g':
|
|
|
|
|
case 'G':
|
|
|
|
|
case 'h':
|
|
|
|
|
case 'H':
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appenddouble(&result, &outpos,
|
2014-06-05 12:04:11 +00:00
|
|
|
|
zval_get_double(tmp),
|
2000-07-18 16:34:30 +00:00
|
|
|
|
width, padding, alignment,
|
|
|
|
|
precision, adjusting,
|
2018-11-06 23:40:15 +00:00
|
|
|
|
*format, always_sign
|
2014-12-13 22:06:14 +00:00
|
|
|
|
);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
break;
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
1999-04-17 00:37:12 +00:00
|
|
|
|
case 'c':
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_appendchar(&result, &outpos,
|
2014-12-13 22:06:14 +00:00
|
|
|
|
(char) zval_get_long(tmp));
|
1999-04-17 00:37:12 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'o':
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_append2n(&result, &outpos,
|
2014-08-25 17:24:55 +00:00
|
|
|
|
zval_get_long(tmp),
|
2000-07-18 16:34:30 +00:00
|
|
|
|
width, padding, alignment, 3,
|
|
|
|
|
hexchars, expprec);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'x':
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_append2n(&result, &outpos,
|
2014-08-25 17:24:55 +00:00
|
|
|
|
zval_get_long(tmp),
|
2000-07-18 16:34:30 +00:00
|
|
|
|
width, padding, alignment, 4,
|
|
|
|
|
hexchars, expprec);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'X':
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_append2n(&result, &outpos,
|
2014-08-25 17:24:55 +00:00
|
|
|
|
zval_get_long(tmp),
|
2000-07-18 16:34:30 +00:00
|
|
|
|
width, padding, alignment, 4,
|
|
|
|
|
HEXCHARS, expprec);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'b':
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_sprintf_append2n(&result, &outpos,
|
2014-08-25 17:24:55 +00:00
|
|
|
|
zval_get_long(tmp),
|
2000-07-18 16:34:30 +00:00
|
|
|
|
width, padding, alignment, 1,
|
|
|
|
|
hexchars, expprec);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '%':
|
2014-12-13 22:06:14 +00:00
|
|
|
|
php_sprintf_appendchar(&result, &outpos, '%');
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
|
|
|
|
break;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
|
|
|
|
|
case '\0':
|
|
|
|
|
if (!format_len) {
|
2020-04-22 10:53:34 +00:00
|
|
|
|
zend_value_error("Missing format specifier at end of string");
|
|
|
|
|
goto fail;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
}
|
2020-09-29 22:25:49 +00:00
|
|
|
|
ZEND_FALLTHROUGH;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
|
1999-04-17 00:37:12 +00:00
|
|
|
|
default:
|
2020-05-26 12:10:57 +00:00
|
|
|
|
zend_value_error("Unknown format specifier \"%c\"", *format);
|
2020-04-21 16:18:21 +00:00
|
|
|
|
goto fail;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2018-11-06 23:40:15 +00:00
|
|
|
|
format++;
|
|
|
|
|
format_len--;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-03-06 10:06:41 +00:00
|
|
|
|
|
2020-04-21 15:00:12 +00:00
|
|
|
|
if (max_missing_argnum >= 0) {
|
2019-10-15 15:51:39 +00:00
|
|
|
|
if (nb_additional_parameters == -1) {
|
2020-04-21 15:00:12 +00:00
|
|
|
|
zend_value_error("The arguments array must contain %d items, %d given", max_missing_argnum + 1, argc);
|
2019-10-15 15:51:39 +00:00
|
|
|
|
} else {
|
2020-08-16 19:49:20 +00:00
|
|
|
|
zend_argument_count_error("%d arguments are required, %d given", max_missing_argnum + nb_additional_parameters + 1, argc + nb_additional_parameters);
|
2019-10-15 15:51:39 +00:00
|
|
|
|
}
|
2020-04-22 08:13:25 +00:00
|
|
|
|
goto fail;
|
2019-10-15 15:51:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-17 00:37:12 +00:00
|
|
|
|
/* possibly, we have to make sure we have room for the terminating null? */
|
2015-06-30 01:05:24 +00:00
|
|
|
|
ZSTR_VAL(result)[outpos]=0;
|
|
|
|
|
ZSTR_LEN(result) = outpos;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
return result;
|
2020-04-22 08:13:25 +00:00
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
zend_string_efree(result);
|
|
|
|
|
return NULL;
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2001-06-06 13:06:12 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
/* php_formatted_print_get_array() {{{ */
|
2020-05-25 15:29:46 +00:00
|
|
|
|
static zval *php_formatted_print_get_array(zend_array *array, int *argc)
|
2018-11-06 23:40:15 +00:00
|
|
|
|
{
|
|
|
|
|
zval *args, *zv;
|
|
|
|
|
int n;
|
|
|
|
|
|
2020-05-25 15:29:46 +00:00
|
|
|
|
n = zend_hash_num_elements(array);
|
2018-11-06 23:40:15 +00:00
|
|
|
|
args = (zval *)safe_emalloc(n, sizeof(zval), 0);
|
|
|
|
|
n = 0;
|
2020-05-25 15:29:46 +00:00
|
|
|
|
ZEND_HASH_FOREACH_VAL(array, zv) {
|
2018-11-06 23:40:15 +00:00
|
|
|
|
ZVAL_COPY_VALUE(&args[n], zv);
|
|
|
|
|
n++;
|
|
|
|
|
} ZEND_HASH_FOREACH_END();
|
|
|
|
|
|
|
|
|
|
*argc = n;
|
|
|
|
|
return args;
|
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2020-07-01 13:32:55 +00:00
|
|
|
|
/* {{{ Return a formatted string */
|
2020-02-21 14:33:58 +00:00
|
|
|
|
PHP_FUNCTION(sprintf)
|
1999-04-17 00:37:12 +00:00
|
|
|
|
{
|
2014-02-13 13:54:23 +00:00
|
|
|
|
zend_string *result;
|
2019-11-15 19:31:19 +00:00
|
|
|
|
char *format;
|
|
|
|
|
size_t format_len;
|
|
|
|
|
zval *args;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
int argc;
|
|
|
|
|
|
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, -1)
|
2019-11-15 19:31:19 +00:00
|
|
|
|
Z_PARAM_STRING(format, format_len)
|
2018-11-06 23:40:15 +00:00
|
|
|
|
Z_PARAM_VARIADIC('*', args, argc)
|
2019-05-29 13:30:06 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
2019-11-15 19:31:19 +00:00
|
|
|
|
result = php_formatted_print(format, format_len, args, argc, 1);
|
2018-11-06 23:40:15 +00:00
|
|
|
|
if (result == NULL) {
|
2020-12-06 15:02:57 +00:00
|
|
|
|
RETURN_THROWS();
|
2001-08-07 19:44:45 +00:00
|
|
|
|
}
|
2014-02-13 13:54:23 +00:00
|
|
|
|
RETVAL_STR(result);
|
2001-08-07 19:44:45 +00:00
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2020-07-01 13:32:55 +00:00
|
|
|
|
/* {{{ Return a formatted string */
|
2001-08-07 19:44:45 +00:00
|
|
|
|
PHP_FUNCTION(vsprintf)
|
|
|
|
|
{
|
2014-02-13 13:54:23 +00:00
|
|
|
|
zend_string *result;
|
2019-11-15 19:31:19 +00:00
|
|
|
|
char *format;
|
|
|
|
|
size_t format_len;
|
2020-05-25 15:29:46 +00:00
|
|
|
|
zval *args;
|
|
|
|
|
zend_array *array;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
int argc;
|
|
|
|
|
|
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
2019-11-15 19:31:19 +00:00
|
|
|
|
Z_PARAM_STRING(format, format_len)
|
2020-05-25 15:29:46 +00:00
|
|
|
|
Z_PARAM_ARRAY_HT(array)
|
2019-05-29 13:30:06 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
args = php_formatted_print_get_array(array, &argc);
|
|
|
|
|
|
2019-11-15 19:31:19 +00:00
|
|
|
|
result = php_formatted_print(format, format_len, args, argc, -1);
|
2018-11-06 23:40:15 +00:00
|
|
|
|
efree(args);
|
|
|
|
|
if (result == NULL) {
|
2020-12-06 15:02:57 +00:00
|
|
|
|
RETURN_THROWS();
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2014-02-13 13:54:23 +00:00
|
|
|
|
RETVAL_STR(result);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
1999-10-18 20:00:42 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2020-07-01 13:32:55 +00:00
|
|
|
|
/* {{{ Output a formatted string */
|
2020-02-21 14:33:58 +00:00
|
|
|
|
PHP_FUNCTION(printf)
|
1999-04-17 00:37:12 +00:00
|
|
|
|
{
|
2014-02-13 13:54:23 +00:00
|
|
|
|
zend_string *result;
|
2014-08-25 18:22:49 +00:00
|
|
|
|
size_t rlen;
|
2019-11-15 19:31:19 +00:00
|
|
|
|
char *format;
|
|
|
|
|
size_t format_len;
|
|
|
|
|
zval *args;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
int argc;
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, -1)
|
2019-11-15 19:31:19 +00:00
|
|
|
|
Z_PARAM_STRING(format, format_len)
|
2018-11-06 23:40:15 +00:00
|
|
|
|
Z_PARAM_VARIADIC('*', args, argc)
|
2019-05-29 13:30:06 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-11-06 23:40:15 +00:00
|
|
|
|
|
2019-11-15 19:31:19 +00:00
|
|
|
|
result = php_formatted_print(format, format_len, args, argc, 1);
|
2018-11-06 23:40:15 +00:00
|
|
|
|
if (result == NULL) {
|
2020-12-06 15:02:57 +00:00
|
|
|
|
RETURN_THROWS();
|
2001-08-07 19:44:45 +00:00
|
|
|
|
}
|
2015-06-30 01:05:24 +00:00
|
|
|
|
rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result));
|
2018-11-06 23:40:15 +00:00
|
|
|
|
zend_string_efree(result);
|
2014-08-25 17:24:55 +00:00
|
|
|
|
RETURN_LONG(rlen);
|
2001-08-07 19:44:45 +00:00
|
|
|
|
}
|
|
|
|
|
/* }}} */
|
|
|
|
|
|
2020-07-01 13:32:55 +00:00
|
|
|
|
/* {{{ Output a formatted string */
|
2001-08-07 19:44:45 +00:00
|
|
|
|
PHP_FUNCTION(vprintf)
|
|
|
|
|
{
|
2014-02-13 13:54:23 +00:00
|
|
|
|
zend_string *result;
|
2014-08-25 18:22:49 +00:00
|
|
|
|
size_t rlen;
|
2019-11-15 19:31:19 +00:00
|
|
|
|
char *format;
|
|
|
|
|
size_t format_len;
|
2020-05-25 15:29:46 +00:00
|
|
|
|
zval *args;
|
|
|
|
|
zend_array *array;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
int argc;
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
2019-11-15 19:31:19 +00:00
|
|
|
|
Z_PARAM_STRING(format, format_len)
|
2020-05-25 15:29:46 +00:00
|
|
|
|
Z_PARAM_ARRAY_HT(array)
|
2019-05-29 13:30:06 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2018-11-06 23:40:15 +00:00
|
|
|
|
|
|
|
|
|
args = php_formatted_print_get_array(array, &argc);
|
|
|
|
|
|
2019-11-15 19:31:19 +00:00
|
|
|
|
result = php_formatted_print(format, format_len, args, argc, -1);
|
2018-11-06 23:40:15 +00:00
|
|
|
|
efree(args);
|
|
|
|
|
if (result == NULL) {
|
2020-12-06 15:02:57 +00:00
|
|
|
|
RETURN_THROWS();
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
2015-06-30 01:05:24 +00:00
|
|
|
|
rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result));
|
2018-11-06 23:40:15 +00:00
|
|
|
|
zend_string_efree(result);
|
2014-08-25 17:24:55 +00:00
|
|
|
|
RETURN_LONG(rlen);
|
1999-04-17 00:37:12 +00:00
|
|
|
|
}
|
1999-10-18 20:00:42 +00:00
|
|
|
|
/* }}} */
|
1999-04-17 00:37:12 +00:00
|
|
|
|
|
2020-07-01 13:32:55 +00:00
|
|
|
|
/* {{{ Output a formatted string into a stream */
|
2003-01-09 17:29:31 +00:00
|
|
|
|
PHP_FUNCTION(fprintf)
|
|
|
|
|
{
|
|
|
|
|
php_stream *stream;
|
2019-11-15 19:31:19 +00:00
|
|
|
|
char *format;
|
|
|
|
|
size_t format_len;
|
|
|
|
|
zval *arg1, *args;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
int argc;
|
2014-02-13 13:54:23 +00:00
|
|
|
|
zend_string *result;
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, -1)
|
2016-12-30 16:54:55 +00:00
|
|
|
|
Z_PARAM_RESOURCE(arg1)
|
2019-11-15 19:31:19 +00:00
|
|
|
|
Z_PARAM_STRING(format, format_len)
|
2018-11-06 23:40:15 +00:00
|
|
|
|
Z_PARAM_VARIADIC('*', args, argc)
|
2019-05-29 13:30:06 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_stream_from_zval(stream, arg1);
|
2003-01-09 17:29:31 +00:00
|
|
|
|
|
2019-11-15 19:31:19 +00:00
|
|
|
|
result = php_formatted_print(format, format_len, args, argc, 2);
|
2018-11-06 23:40:15 +00:00
|
|
|
|
if (result == NULL) {
|
2020-12-06 15:02:57 +00:00
|
|
|
|
RETURN_THROWS();
|
2003-01-09 17:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-30 01:05:24 +00:00
|
|
|
|
php_stream_write(stream, ZSTR_VAL(result), ZSTR_LEN(result));
|
2003-01-09 17:29:31 +00:00
|
|
|
|
|
2015-06-30 01:05:24 +00:00
|
|
|
|
RETVAL_LONG(ZSTR_LEN(result));
|
2018-11-06 23:40:15 +00:00
|
|
|
|
zend_string_efree(result);
|
2003-01-09 17:29:31 +00:00
|
|
|
|
}
|
2006-06-26 18:48:56 +00:00
|
|
|
|
/* }}} */
|
2003-01-09 17:29:31 +00:00
|
|
|
|
|
2020-07-01 13:32:55 +00:00
|
|
|
|
/* {{{ Output a formatted string into a stream */
|
2003-01-09 17:29:31 +00:00
|
|
|
|
PHP_FUNCTION(vfprintf)
|
|
|
|
|
{
|
|
|
|
|
php_stream *stream;
|
2019-11-15 19:31:19 +00:00
|
|
|
|
char *format;
|
|
|
|
|
size_t format_len;
|
2020-05-25 15:29:46 +00:00
|
|
|
|
zval *arg1, *args;
|
|
|
|
|
zend_array *array;
|
2018-11-06 23:40:15 +00:00
|
|
|
|
int argc;
|
2014-02-13 13:54:23 +00:00
|
|
|
|
zend_string *result;
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_START(3, 3)
|
2016-12-30 16:54:55 +00:00
|
|
|
|
Z_PARAM_RESOURCE(arg1)
|
2019-11-15 19:31:19 +00:00
|
|
|
|
Z_PARAM_STRING(format, format_len)
|
2020-05-25 15:29:46 +00:00
|
|
|
|
Z_PARAM_ARRAY_HT(array)
|
2019-05-29 13:30:06 +00:00
|
|
|
|
ZEND_PARSE_PARAMETERS_END();
|
2015-01-03 09:22:58 +00:00
|
|
|
|
|
2014-02-13 13:54:23 +00:00
|
|
|
|
php_stream_from_zval(stream, arg1);
|
2003-01-09 17:29:31 +00:00
|
|
|
|
|
2018-11-06 23:40:15 +00:00
|
|
|
|
args = php_formatted_print_get_array(array, &argc);
|
|
|
|
|
|
2019-11-15 19:31:19 +00:00
|
|
|
|
result = php_formatted_print(format, format_len, args, argc, -1);
|
2018-11-06 23:40:15 +00:00
|
|
|
|
efree(args);
|
|
|
|
|
if (result == NULL) {
|
2020-12-06 15:02:57 +00:00
|
|
|
|
RETURN_THROWS();
|
2003-01-09 17:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-30 01:05:24 +00:00
|
|
|
|
php_stream_write(stream, ZSTR_VAL(result), ZSTR_LEN(result));
|
2003-01-09 17:29:31 +00:00
|
|
|
|
|
2015-06-30 01:05:24 +00:00
|
|
|
|
RETVAL_LONG(ZSTR_LEN(result));
|
2018-11-06 23:40:15 +00:00
|
|
|
|
zend_string_efree(result);
|
2003-01-09 17:29:31 +00:00
|
|
|
|
}
|
2006-06-26 18:48:56 +00:00
|
|
|
|
/* }}} */
|