mirror of
https://github.com/php/php-src.git
synced 2025-08-18 06:58:55 +02:00
Unicode support in *printf() functions. (Antony, Andrei)
This commit is contained in:
parent
3945428c9f
commit
7d966063f6
1 changed files with 731 additions and 57 deletions
|
@ -43,6 +43,9 @@
|
|||
#define MAX_FLOAT_DIGITS 38
|
||||
#define MAX_FLOAT_PRECISION 40
|
||||
|
||||
#define PHP_OUTPUT 0
|
||||
#define PHP_RUNTIME 1
|
||||
|
||||
#if 0
|
||||
/* trick to control varargs functions through cpp */
|
||||
# define PRINTF_DEBUG(arg) php_printf arg
|
||||
|
@ -53,7 +56,10 @@
|
|||
static char hexchars[] = "0123456789abcdef";
|
||||
static char HEXCHARS[] = "0123456789ABCDEF";
|
||||
|
||||
static UChar u_hexchars[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
|
||||
static UChar u_HEXCHARS[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
|
||||
|
||||
/* php_sprintf_appendchar() {{{ */
|
||||
inline static void
|
||||
php_sprintf_appendchar(char **buffer, int *pos, int *size, char add TSRMLS_DC)
|
||||
{
|
||||
|
@ -65,8 +71,21 @@ php_sprintf_appendchar(char **buffer, int *pos, int *size, char add TSRMLS_DC)
|
|||
PRINTF_DEBUG(("sprintf: appending '%c', pos=\n", add, *pos));
|
||||
(*buffer)[(*pos)++] = add;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_u_sprintf_appendchar() {{{ */
|
||||
inline static void
|
||||
php_u_sprintf_appendchar(UChar **buffer, int *pos, int *size, UChar add TSRMLS_DC)
|
||||
{
|
||||
if ((*pos + 1) >= *size) {
|
||||
*size <<= 1;
|
||||
*buffer = eurealloc(*buffer, *size);
|
||||
}
|
||||
(*buffer)[(*pos)++] = add;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_sprintf_appendstring() {{{ */
|
||||
inline static void
|
||||
php_sprintf_appendstring(char **buffer, int *pos, int *size, char *add,
|
||||
int min_width, int max_width, char padding,
|
||||
|
@ -115,10 +134,57 @@ php_sprintf_appendstring(char **buffer, int *pos, int *size, char *add,
|
|||
}
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* php_u_sprintf_appendstring() {{{ */
|
||||
inline static void
|
||||
php_sprintf_appendint(char **buffer, int *pos, int *size, long number,
|
||||
php_u_sprintf_appendstring(UChar **buffer, int *pos, int *size, UChar *add,
|
||||
int min_width, int max_width, UChar padding,
|
||||
int alignment, int len, int neg, int expprec, int always_sign)
|
||||
{
|
||||
register int npad;
|
||||
int req_size;
|
||||
int copy_len;
|
||||
|
||||
copy_len = (expprec ? MIN(max_width, len) : len);
|
||||
npad = min_width - copy_len;
|
||||
|
||||
if (npad < 0) {
|
||||
npad = 0;
|
||||
}
|
||||
|
||||
req_size = *pos + MAX(min_width, copy_len) + 1;
|
||||
|
||||
if (req_size > *size) {
|
||||
while (req_size > *size) {
|
||||
*size <<= 1;
|
||||
}
|
||||
*buffer = eurealloc(*buffer, *size);
|
||||
}
|
||||
if (alignment == ALIGN_RIGHT) {
|
||||
if ((neg || always_sign) && padding == 0x30 /* '0' */) {
|
||||
(*buffer)[(*pos)++] = (neg) ? 0x2D /* '-' */ : 0x2B /* '+' */;
|
||||
add++;
|
||||
len--;
|
||||
copy_len--;
|
||||
}
|
||||
while (npad-- > 0) {
|
||||
(*buffer)[(*pos)++] = padding;
|
||||
}
|
||||
}
|
||||
u_memcpy(&(*buffer)[*pos], add, copy_len + 1);
|
||||
*pos += copy_len;
|
||||
if (alignment == ALIGN_LEFT) {
|
||||
while (npad--) {
|
||||
(*buffer)[(*pos)++] = padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_sprintf_appendint() {{{ */
|
||||
inline static void
|
||||
php_sprintf_appendint(char **buffer, int *pos, int *size, long number,
|
||||
int width, char padding, int alignment,
|
||||
int always_sign)
|
||||
{
|
||||
|
@ -158,7 +224,49 @@ php_sprintf_appendint(char **buffer, int *pos, int *size, long number,
|
|||
padding, alignment, (NUM_BUF_SIZE - 1) - i,
|
||||
neg, 0, always_sign);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_u_sprintf_appendint() {{{ */
|
||||
inline static void
|
||||
php_u_sprintf_appendint(UChar **buffer, int *pos, int *size, long number,
|
||||
int width, UChar padding, int alignment,
|
||||
int always_sign)
|
||||
{
|
||||
UChar numbuf[NUM_BUF_SIZE];
|
||||
register unsigned long magn, nmagn;
|
||||
register unsigned int i = NUM_BUF_SIZE - 1, neg = 0;
|
||||
|
||||
if (number < 0) {
|
||||
neg = 1;
|
||||
magn = ((unsigned long) -(number + 1)) + 1;
|
||||
} else {
|
||||
magn = (unsigned long) number;
|
||||
}
|
||||
|
||||
/* Can't right-pad 0's on integers */
|
||||
if (alignment==0 && padding== 0x30 /* '0' */) padding = 0x20 /* ' ' */;
|
||||
|
||||
numbuf[i] = 0x0A /* '\0' */;
|
||||
|
||||
do {
|
||||
nmagn = magn / 10;
|
||||
|
||||
numbuf[--i] = (UChar)(magn - (nmagn * 10)) + 0x30 /* '0' */;
|
||||
magn = nmagn;
|
||||
}
|
||||
while (magn > 0 && i > 0);
|
||||
if (neg) {
|
||||
numbuf[--i] = 0x2D /* '-' */;
|
||||
} else if (always_sign) {
|
||||
numbuf[--i] = 0x2B /* '+' */;
|
||||
}
|
||||
php_u_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
|
||||
padding, alignment, (NUM_BUF_SIZE - 1) - i,
|
||||
neg, 0, always_sign);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_sprintf_appenduint() {{{ */
|
||||
inline static void
|
||||
php_sprintf_appenduint(char **buffer, int *pos, int *size,
|
||||
unsigned long number,
|
||||
|
@ -188,7 +296,38 @@ php_sprintf_appenduint(char **buffer, int *pos, int *size,
|
|||
php_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
|
||||
padding, alignment, (NUM_BUF_SIZE - 1) - i, 0, 0, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_u_sprintf_appenduint() {{{ */
|
||||
inline static void
|
||||
php_u_sprintf_appenduint(UChar **buffer, int *pos, int *size,
|
||||
unsigned long number,
|
||||
int width, UChar padding, int alignment)
|
||||
{
|
||||
UChar numbuf[NUM_BUF_SIZE];
|
||||
register unsigned long magn, nmagn;
|
||||
register unsigned int i = NUM_BUF_SIZE - 1;
|
||||
|
||||
magn = (unsigned int) number;
|
||||
|
||||
/* Can't right-pad 0's on integers */
|
||||
if (alignment == 0 && padding == 0x30 /* '0' */) padding = 0x20 /* ' ' */;
|
||||
|
||||
numbuf[i] = 0x0A /* '\0' */;
|
||||
|
||||
do {
|
||||
nmagn = magn / 10;
|
||||
|
||||
numbuf[--i] = (UChar)(magn - (nmagn * 10)) + 0x30 /* '0' */;
|
||||
magn = nmagn;
|
||||
} while (magn > 0 && i > 0);
|
||||
|
||||
php_u_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
|
||||
padding, alignment, (NUM_BUF_SIZE - 1) - i, 0, 0, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_sprintf_appenddouble() {{{ */
|
||||
inline static void
|
||||
php_sprintf_appenddouble(char **buffer, int *pos,
|
||||
int *size, double number,
|
||||
|
@ -238,9 +377,9 @@ php_sprintf_appenddouble(char **buffer, int *pos,
|
|||
#ifdef HAVE_LOCALE_H
|
||||
lconv = localeconv();
|
||||
#endif
|
||||
s = php_conv_fp((fmt == 'f')?'F':fmt, number, 0, precision,
|
||||
(fmt == 'f')?LCONV_DECIMAL_POINT:'.',
|
||||
&is_negative, &num_buf[1], &s_len);
|
||||
s = php_conv_fp((fmt == 'f')?'F':fmt, number, NO, precision,
|
||||
(fmt == 'f')?LCONV_DECIMAL_POINT:'.',
|
||||
&is_negative, &num_buf[1], &s_len);
|
||||
if (is_negative) {
|
||||
num_buf[0] = '-';
|
||||
s = num_buf;
|
||||
|
@ -279,8 +418,133 @@ php_sprintf_appenddouble(char **buffer, int *pos,
|
|||
php_sprintf_appendstring(buffer, pos, size, s, width, 0, padding,
|
||||
alignment, s_len, is_negative, 0, always_sign);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_u_sprintf_appenddouble() {{{ */
|
||||
inline static void
|
||||
php_u_sprintf_appenddouble(UChar **buffer, int *pos,
|
||||
int *size, double number,
|
||||
int width, UChar padding,
|
||||
int alignment, int precision,
|
||||
int adjust, UChar fmt,
|
||||
int always_sign
|
||||
TSRMLS_DC)
|
||||
{
|
||||
char num_buf[NUM_BUF_SIZE];
|
||||
char *s = NULL, *q, s_fmt;
|
||||
UChar *uni_s;
|
||||
int s_len = 0, is_negative = 0;
|
||||
#ifdef HAVE_LOCALE_H
|
||||
struct lconv *lconv;
|
||||
#endif
|
||||
|
||||
if ((adjust & ADJ_PRECISION) == 0) {
|
||||
precision = FLOAT_PRECISION;
|
||||
} else if (precision > MAX_FLOAT_PRECISION) {
|
||||
precision = MAX_FLOAT_PRECISION;
|
||||
}
|
||||
|
||||
if (zend_isnan(number)) {
|
||||
UChar *nan = USTR_MAKE("NaN");
|
||||
is_negative = (number<0);
|
||||
php_u_sprintf_appendstring(buffer, pos, size, nan, 3, 0, padding,
|
||||
alignment, precision, is_negative, 0, always_sign);
|
||||
efree(nan);
|
||||
return;
|
||||
}
|
||||
|
||||
if (zend_isinf(number)) {
|
||||
UChar *inf = USTR_MAKE("INF");
|
||||
is_negative = (number<0);
|
||||
php_u_sprintf_appendstring(buffer, pos, size, inf, 3, 0, padding,
|
||||
alignment, precision, is_negative, 0, always_sign);
|
||||
efree(inf);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (fmt) {
|
||||
case 0x66 /* 'f' */:
|
||||
s_fmt = 'f';
|
||||
break;
|
||||
case 0x46 /* 'F' */:
|
||||
s_fmt = 'F';
|
||||
break;
|
||||
case 0x65 /* 'e' */:
|
||||
s_fmt = 'e';
|
||||
break;
|
||||
case 0x45 /* 'E' */:
|
||||
s_fmt = 'E';
|
||||
break;
|
||||
case 0x67 /* 'g' */:
|
||||
s_fmt = 'g';
|
||||
break;
|
||||
case 0x47 /* 'G' */:
|
||||
s_fmt = 'G';
|
||||
break;
|
||||
}
|
||||
|
||||
switch (fmt) {
|
||||
case 0x65 /* 'e' */:
|
||||
if (precision) {
|
||||
precision--;
|
||||
}
|
||||
case 0x45 /* 'E' */:
|
||||
case 0x46 /* 'F' */:
|
||||
case 0x66 /* 'f' */:
|
||||
#ifdef HAVE_LOCALE_H
|
||||
lconv = localeconv();
|
||||
#endif
|
||||
s = php_conv_fp((s_fmt == 'f')?'F':s_fmt, number, NO, precision,
|
||||
(s_fmt == 'f')?LCONV_DECIMAL_POINT:'.',
|
||||
&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++;
|
||||
}
|
||||
s[s_len] = '\0';
|
||||
break;
|
||||
|
||||
case 0x67 /* 'g' */:
|
||||
case 0x47 /* 'G' */:
|
||||
if (precision == 0)
|
||||
precision = 1;
|
||||
/*
|
||||
* * We use &num_buf[ 1 ], so that we have room for the sign
|
||||
*/
|
||||
#ifdef HAVE_LOCALE_H
|
||||
lconv = localeconv();
|
||||
#endif
|
||||
s = php_gcvt(number, precision, LCONV_DECIMAL_POINT, (s_fmt == 'G')?'E':'e', &num_buf[1]);
|
||||
is_negative = 0;
|
||||
if (*s == '-') {
|
||||
is_negative = 1;
|
||||
s = &num_buf[1];
|
||||
} else if (always_sign) {
|
||||
num_buf[0] = '+';
|
||||
s = num_buf;
|
||||
}
|
||||
|
||||
s_len = strlen(s);
|
||||
|
||||
if (fmt == 0x47 /* 'G' */ && (q = strchr(s, 'e')) != NULL) {
|
||||
*q = 'E';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
uni_s = zend_ascii_to_unicode(s, s_len + 1 ZEND_FILE_LINE_CC);
|
||||
php_u_sprintf_appendstring(buffer, pos, size, uni_s, width, 0, padding,
|
||||
alignment, s_len, is_negative, 0, always_sign);
|
||||
efree(uni_s);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_sprintf_append2n() {{{ */
|
||||
inline static void
|
||||
php_sprintf_append2n(char **buffer, int *pos, int *size, long number,
|
||||
int width, char padding, int alignment, int n,
|
||||
|
@ -309,8 +573,35 @@ php_sprintf_append2n(char **buffer, int *pos, int *size, long number,
|
|||
padding, alignment, (NUM_BUF_SIZE - 1) - i,
|
||||
0, expprec, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_u_sprintf_append2n() {{{ */
|
||||
inline static void
|
||||
php_u_sprintf_append2n(UChar **buffer, int *pos, int *size, long number,
|
||||
int width, UChar padding, int alignment, int n,
|
||||
UChar *chartable, int expprec)
|
||||
{
|
||||
UChar numbuf[NUM_BUF_SIZE];
|
||||
register unsigned long num;
|
||||
register unsigned int i = NUM_BUF_SIZE - 1;
|
||||
register int andbits = (1 << n) - 1;
|
||||
|
||||
num = (unsigned long) number;
|
||||
numbuf[i] = '\0';
|
||||
|
||||
do {
|
||||
numbuf[--i] = chartable[(num & andbits)];
|
||||
num >>= n;
|
||||
}
|
||||
while (num > 0);
|
||||
|
||||
php_u_sprintf_appendstring(buffer, pos, size, &numbuf[i], width, 0,
|
||||
padding, alignment, (NUM_BUF_SIZE - 1) - i,
|
||||
0, expprec, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* php_sprintf_getnumber() {{{ */
|
||||
inline static long
|
||||
php_sprintf_getnumber(char *buffer, int *pos)
|
||||
{
|
||||
|
@ -325,8 +616,25 @@ php_sprintf_getnumber(char *buffer, int *pos)
|
|||
*pos += i;
|
||||
return num;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_formatted_print
|
||||
/* php_u_sprintf_getnumber() {{{ */
|
||||
inline static long
|
||||
php_u_sprintf_getnumber(UChar *buffer, int *pos)
|
||||
{
|
||||
UChar *endptr;
|
||||
register long num = zend_u_strtol(&buffer[*pos], &endptr, 10);
|
||||
register int i = 0;
|
||||
|
||||
if (endptr != NULL) {
|
||||
i = (endptr - &buffer[*pos]);
|
||||
}
|
||||
*pos += i;
|
||||
return num;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_formatted_print()
|
||||
* New sprintf implementation for PHP.
|
||||
*
|
||||
* Modifiers:
|
||||
|
@ -350,8 +658,7 @@ php_sprintf_getnumber(char *buffer, int *pos)
|
|||
* "X" integer argument is printed as uppercase hexadecimal
|
||||
*
|
||||
*/
|
||||
static char *
|
||||
php_formatted_print(int ht, int *len, int use_array, int format_offset TSRMLS_DC)
|
||||
static char * php_formatted_print(int ht, int *len, int use_array, int format_offset, int type TSRMLS_DC)
|
||||
{
|
||||
zval ***args, **z_format;
|
||||
int argc, size = 240, inpos = 0, outpos = 0, temppos;
|
||||
|
@ -525,9 +832,26 @@ php_formatted_print(int ht, int *len, int use_array, int format_offset TSRMLS_DC
|
|||
switch (format[inpos]) {
|
||||
case 's': {
|
||||
zval *var, var_copy;
|
||||
int use_copy;
|
||||
int use_copy = 0;
|
||||
|
||||
zend_make_printable_zval(tmp, &var_copy, &use_copy);
|
||||
if (Z_TYPE_P(tmp) != IS_UNICODE) {
|
||||
zend_make_printable_zval(tmp, &var_copy, &use_copy);
|
||||
} else {
|
||||
var_copy = *tmp;
|
||||
zval_copy_ctor(&var_copy);
|
||||
INIT_PZVAL(&var_copy);
|
||||
use_copy = 1;
|
||||
|
||||
switch (type) {
|
||||
case PHP_OUTPUT:
|
||||
convert_to_string_with_converter(&var_copy, ZEND_U_CONVERTER(UG(output_encoding_conv)));
|
||||
break;
|
||||
case PHP_RUNTIME:
|
||||
default:
|
||||
convert_to_string_with_converter(&var_copy, ZEND_U_CONVERTER(UG(runtime_encoding_conv)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (use_copy) {
|
||||
var = &var_copy;
|
||||
} else {
|
||||
|
@ -566,7 +890,6 @@ php_formatted_print(int ht, int *len, int use_array, int format_offset TSRMLS_DC
|
|||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
/* XXX not done */
|
||||
convert_to_double(tmp);
|
||||
php_sprintf_appenddouble(&result, &outpos, &size,
|
||||
Z_DVAL_P(tmp),
|
||||
|
@ -637,125 +960,476 @@ php_formatted_print(int ht, int *len, int use_array, int format_offset TSRMLS_DC
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string sprintf(string format [, mixed arg1 [, mixed ...]])
|
||||
/* php_u_formatted_print() {{{ */
|
||||
static zstr php_u_formatted_print(int ht, int *len, int use_array, int format_offset, int type TSRMLS_DC)
|
||||
{
|
||||
zval ***args, **z_format;
|
||||
int argc, size = 240, inpos = 0, outpos = 0, temppos;
|
||||
int alignment, width, precision, currarg, adjusting, argnum;
|
||||
UChar *format, *result, padding;
|
||||
int always_sign;
|
||||
zstr result_str;
|
||||
|
||||
argc = ZEND_NUM_ARGS();
|
||||
|
||||
/* verify the number of args */
|
||||
if ((use_array && argc != (2 + format_offset))
|
||||
|| (!use_array && argc < (1 + format_offset))) {
|
||||
WRONG_PARAM_COUNT_WITH_RETVAL(NULL_ZSTR);
|
||||
}
|
||||
args = (zval ***)safe_emalloc(argc, sizeof(zval *), 0);
|
||||
|
||||
if (zend_get_parameters_array_ex(argc, args) == FAILURE) {
|
||||
efree(args);
|
||||
WRONG_PARAM_COUNT_WITH_RETVAL(NULL_ZSTR);
|
||||
}
|
||||
|
||||
if (use_array) {
|
||||
int i = 1;
|
||||
zval ***newargs;
|
||||
zval **array;
|
||||
|
||||
z_format = args[format_offset];
|
||||
array = args[1 + format_offset];
|
||||
|
||||
SEPARATE_ZVAL(array);
|
||||
convert_to_array_ex(array);
|
||||
|
||||
argc = 1 + zend_hash_num_elements(Z_ARRVAL_PP(array));
|
||||
newargs = (zval ***)safe_emalloc(argc, sizeof(zval *), 0);
|
||||
newargs[0] = z_format;
|
||||
|
||||
for (zend_hash_internal_pointer_reset(Z_ARRVAL_PP(array));
|
||||
zend_hash_get_current_data(Z_ARRVAL_PP(array), (void **)&newargs[i++]) == SUCCESS;
|
||||
zend_hash_move_forward(Z_ARRVAL_PP(array)));
|
||||
|
||||
efree(args);
|
||||
args = newargs;
|
||||
format_offset = 0;
|
||||
}
|
||||
|
||||
convert_to_unicode_ex(args[format_offset]);
|
||||
format = Z_USTRVAL_PP(args[format_offset]);
|
||||
result = eumalloc(size);
|
||||
|
||||
currarg = 1;
|
||||
|
||||
while (inpos<Z_USTRLEN_PP(args[format_offset])) {
|
||||
int expprec = 0, multiuse = 0;
|
||||
zval *tmp;
|
||||
|
||||
if (format[inpos] != 0x25 /* '%' */) {
|
||||
php_u_sprintf_appendchar(&result, &outpos, &size, format[inpos++] TSRMLS_CC);
|
||||
} else if (format[inpos + 1] == 0x25 /* '%' */) {
|
||||
php_u_sprintf_appendchar(&result, &outpos, &size, 0x25 /* '%' */ TSRMLS_CC);
|
||||
inpos += 2;
|
||||
} else {
|
||||
/* starting a new format specifier, reset variables */
|
||||
alignment = ALIGN_RIGHT;
|
||||
adjusting = 0;
|
||||
padding = 0x20 /* ' ' */;
|
||||
always_sign = 0;
|
||||
inpos++; /* skip the '%' */
|
||||
|
||||
if ((format[inpos] < 0x7f) && !u_isalpha(format[inpos])) {
|
||||
/* first look for argnum */
|
||||
temppos = inpos;
|
||||
while (format[temppos] >= 0x30 /* '0' */ && format[temppos] <= 0x39 /* '9' */) temppos++;
|
||||
if (format[temppos] == 0x24 /* '$' */) {
|
||||
argnum = php_u_sprintf_getnumber(format, &inpos);
|
||||
|
||||
if (argnum == 0) {
|
||||
efree(result);
|
||||
efree(args);
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero is not a valid argument number");
|
||||
return NULL_ZSTR;
|
||||
}
|
||||
|
||||
multiuse = 1;
|
||||
inpos++; /* skip the '$' */
|
||||
} else {
|
||||
argnum = currarg++;
|
||||
}
|
||||
|
||||
argnum += format_offset;
|
||||
|
||||
/* after argnum comes modifiers */
|
||||
for (;; inpos++) {
|
||||
if (u_isspace(format[inpos]) || format[inpos] == 0x30 /* '0' */) {
|
||||
padding = format[inpos];
|
||||
} else if (format[inpos] == 0x2D /* '-' */) {
|
||||
alignment = ALIGN_LEFT;
|
||||
/* space padding, the default */
|
||||
} else if (format[inpos] == 0x2B /* '+' */) {
|
||||
always_sign = 1;
|
||||
} else if (format[inpos] == 0x27 /* '\'' */) {
|
||||
padding = format[++inpos];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* after modifiers comes width */
|
||||
if (isdigit((int)format[inpos])) {
|
||||
width = php_u_sprintf_getnumber(format, &inpos);
|
||||
adjusting |= ADJ_WIDTH;
|
||||
} else {
|
||||
width = 0;
|
||||
}
|
||||
|
||||
/* after width and argnum comes precision */
|
||||
if (format[inpos] == 0x2E /* '.' */) {
|
||||
inpos++;
|
||||
if (format[inpos] >= 0x30 /* '0' */ && format[inpos] <= 0x39 /* '9' */) {
|
||||
precision = php_u_sprintf_getnumber(format, &inpos);
|
||||
adjusting |= ADJ_PRECISION;
|
||||
expprec = 1;
|
||||
} else {
|
||||
precision = 0;
|
||||
}
|
||||
} else {
|
||||
precision = 0;
|
||||
}
|
||||
} else {
|
||||
width = precision = 0;
|
||||
argnum = currarg++ + format_offset;
|
||||
}
|
||||
|
||||
if (argnum >= argc) {
|
||||
efree(result);
|
||||
efree(args);
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too few arguments");
|
||||
return NULL_ZSTR;
|
||||
}
|
||||
|
||||
if (format[inpos] == 0x6C /* 'l' */) {
|
||||
inpos++;
|
||||
}
|
||||
/* now we expect to find a type specifier */
|
||||
if (multiuse) {
|
||||
MAKE_STD_ZVAL(tmp);
|
||||
*tmp = **(args[argnum]);
|
||||
INIT_PZVAL(tmp);
|
||||
zval_copy_ctor(tmp);
|
||||
} else {
|
||||
SEPARATE_ZVAL(args[argnum]);
|
||||
tmp = *(args[argnum]);
|
||||
}
|
||||
|
||||
switch (format[inpos]) {
|
||||
case 0x73 /* 's' */: {
|
||||
zval *var, var_copy;
|
||||
int use_copy;
|
||||
|
||||
zend_make_unicode_zval(tmp, &var_copy, &use_copy);
|
||||
if (use_copy) {
|
||||
var = &var_copy;
|
||||
} else {
|
||||
var = tmp;
|
||||
}
|
||||
php_u_sprintf_appendstring(&result, &outpos, &size,
|
||||
Z_USTRVAL_P(var),
|
||||
width, precision, padding,
|
||||
alignment,
|
||||
Z_USTRLEN_P(var),
|
||||
0, expprec, 0);
|
||||
if (use_copy) {
|
||||
zval_dtor(&var_copy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x64 /* 'd' */:
|
||||
convert_to_long(tmp);
|
||||
php_u_sprintf_appendint(&result, &outpos, &size,
|
||||
Z_LVAL_P(tmp),
|
||||
width, padding, alignment,
|
||||
always_sign);
|
||||
break;
|
||||
|
||||
case 0x75 /* 'u' */:
|
||||
convert_to_long(tmp);
|
||||
php_u_sprintf_appenduint(&result, &outpos, &size,
|
||||
Z_LVAL_P(tmp),
|
||||
width, padding, alignment);
|
||||
break;
|
||||
|
||||
case 0x67 /* 'g' */:
|
||||
case 0x47 /* 'G' */:
|
||||
case 0x65 /* 'e' */:
|
||||
case 0x45 /* 'E' */:
|
||||
case 0x66 /* 'f' */:
|
||||
case 0x46 /* 'F' */:
|
||||
convert_to_double(tmp);
|
||||
php_u_sprintf_appenddouble(&result, &outpos, &size,
|
||||
Z_DVAL_P(tmp),
|
||||
width, padding, alignment,
|
||||
precision, adjusting,
|
||||
format[inpos], always_sign
|
||||
TSRMLS_CC);
|
||||
break;
|
||||
|
||||
case 0x63 /* 'c' */:
|
||||
convert_to_long(tmp);
|
||||
php_u_sprintf_appendchar(&result, &outpos, &size,
|
||||
(char) Z_LVAL_P(tmp) TSRMLS_CC);
|
||||
break;
|
||||
|
||||
case 0x6F /* 'o' */:
|
||||
convert_to_long(tmp);
|
||||
php_u_sprintf_append2n(&result, &outpos, &size,
|
||||
Z_LVAL_P(tmp),
|
||||
width, padding, alignment, 3,
|
||||
u_hexchars, expprec);
|
||||
break;
|
||||
|
||||
case 0x78 /* 'x' */:
|
||||
convert_to_long(tmp);
|
||||
php_u_sprintf_append2n(&result, &outpos, &size,
|
||||
Z_LVAL_P(tmp),
|
||||
width, padding, alignment, 4,
|
||||
u_hexchars, expprec);
|
||||
break;
|
||||
|
||||
case 0x58 /* 'X' */:
|
||||
convert_to_long(tmp);
|
||||
php_u_sprintf_append2n(&result, &outpos, &size,
|
||||
Z_LVAL_P(tmp),
|
||||
width, padding, alignment, 4,
|
||||
u_HEXCHARS, expprec);
|
||||
break;
|
||||
|
||||
case 0x62 /* 'b' */:
|
||||
convert_to_long(tmp);
|
||||
php_u_sprintf_append2n(&result, &outpos, &size,
|
||||
Z_LVAL_P(tmp),
|
||||
width, padding, alignment, 1,
|
||||
u_hexchars, expprec);
|
||||
break;
|
||||
|
||||
case 0x25 /* '%' */:
|
||||
php_u_sprintf_appendchar(&result, &outpos, &size, 0x25 /* '%' */ TSRMLS_CC);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (multiuse) {
|
||||
zval_ptr_dtor(&tmp);
|
||||
}
|
||||
inpos++;
|
||||
}
|
||||
}
|
||||
|
||||
efree(args);
|
||||
|
||||
/* possibly, we have to make sure we have room for the terminating null? */
|
||||
result[outpos] = 0;
|
||||
*len = outpos;
|
||||
result_str.u = result;
|
||||
|
||||
switch (type) {
|
||||
case PHP_OUTPUT:
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
char *s;
|
||||
int s_len;
|
||||
|
||||
zend_unicode_to_string_ex(ZEND_U_CONVERTER(UG(output_encoding_conv)), &s, &s_len, result, outpos, &status);
|
||||
if(U_FAILURE(status)) {
|
||||
efree(s);
|
||||
efree(result);
|
||||
return NULL_ZSTR;
|
||||
}
|
||||
|
||||
efree(result_str.v);
|
||||
result_str.s = s;
|
||||
*len = s_len;
|
||||
break;
|
||||
}
|
||||
case PHP_RUNTIME:
|
||||
default:
|
||||
/* nothing to be done */
|
||||
break;
|
||||
}
|
||||
|
||||
return result_str;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string sprintf(string format [, mixed arg1 [, mixed ...]]) U
|
||||
Return a formatted string */
|
||||
PHP_FUNCTION(user_sprintf)
|
||||
{
|
||||
char *result;
|
||||
int len;
|
||||
|
||||
if ((result=php_formatted_print(ht, &len, 0, 0 TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
zstr result;
|
||||
|
||||
if (!UG(unicode)) {
|
||||
if ((result.s = php_formatted_print(ht, &len, 0, 0, PHP_RUNTIME TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
RETVAL_STRINGL(result.s, len, 0);
|
||||
} else {
|
||||
result = php_u_formatted_print(ht, &len, 0, 0, PHP_RUNTIME TSRMLS_CC);
|
||||
if (result.v == NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
RETVAL_UNICODEL(result.u, len, 0);
|
||||
}
|
||||
RETVAL_STRINGL(result, len, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto string vsprintf(string format, array args)
|
||||
/* {{{ proto string vsprintf(string format, array args) U
|
||||
Return a formatted string */
|
||||
PHP_FUNCTION(vsprintf)
|
||||
{
|
||||
char *result;
|
||||
int len;
|
||||
|
||||
if ((result=php_formatted_print(ht, &len, 1, 0 TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
zstr result;
|
||||
|
||||
if (!UG(unicode)) {
|
||||
if ((result.s = php_formatted_print(ht, &len, 1, 0, PHP_RUNTIME TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
RETVAL_STRINGL(result.s, len, 0);
|
||||
} else {
|
||||
result = php_u_formatted_print(ht, &len, 1, 0, PHP_RUNTIME TSRMLS_CC);
|
||||
if (result.v == NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
RETVAL_UNICODEL(result.u, len, 0);
|
||||
}
|
||||
RETVAL_STRINGL(result, len, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int printf(string format [, mixed arg1 [, mixed ...]])
|
||||
/* {{{ proto int printf(string format [, mixed arg1 [, mixed ...]]) U
|
||||
Output a formatted string */
|
||||
PHP_FUNCTION(user_printf)
|
||||
{
|
||||
char *result;
|
||||
int len;
|
||||
|
||||
if ((result=php_formatted_print(ht, &len, 0, 0 TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
zstr result;
|
||||
|
||||
if (!UG(unicode)) {
|
||||
if ((result.s = php_formatted_print(ht, &len, 0, 0, PHP_OUTPUT TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
} else {
|
||||
result = php_u_formatted_print(ht, &len, 0, 0, PHP_OUTPUT TSRMLS_CC);
|
||||
if (result.v == NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
PHPWRITE(result, len);
|
||||
efree(result);
|
||||
|
||||
PHPWRITE(result.s, len);
|
||||
efree(result.v);
|
||||
RETURN_LONG(len);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int vprintf(string format, array args)
|
||||
/* {{{ proto int vprintf(string format, array args) U
|
||||
Output a formatted string */
|
||||
PHP_FUNCTION(vprintf)
|
||||
{
|
||||
char *result;
|
||||
int len;
|
||||
zstr result;
|
||||
|
||||
if ((result=php_formatted_print(ht, &len, 1, 0 TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
if (!UG(unicode)) {
|
||||
if ((result.s = php_formatted_print(ht, &len, 1, 0, PHP_OUTPUT TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
} else {
|
||||
result = php_u_formatted_print(ht, &len, 1, 0, PHP_OUTPUT TSRMLS_CC);
|
||||
if (result.v == NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
PHPWRITE(result, len);
|
||||
efree(result);
|
||||
|
||||
PHPWRITE(result.s, len);
|
||||
efree(result.v);
|
||||
RETURN_LONG(len);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int fprintf(resource stream, string format [, mixed arg1 [, mixed ...]])
|
||||
/* {{{ proto int fprintf(resource stream, string format [, mixed arg1 [, mixed ...]]) U
|
||||
Output a formatted string into a stream */
|
||||
PHP_FUNCTION(fprintf)
|
||||
{
|
||||
php_stream *stream;
|
||||
zval **arg1;
|
||||
char *result;
|
||||
int len;
|
||||
zval **arg1, **arg2;
|
||||
zstr result;
|
||||
int len, ret;
|
||||
|
||||
if (ZEND_NUM_ARGS() < 2) {
|
||||
WRONG_PARAM_COUNT;
|
||||
}
|
||||
|
||||
if (zend_get_parameters_ex(1, &arg1)==FAILURE) {
|
||||
if (zend_get_parameters_ex(2, &arg1, &arg2)==FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
php_stream_from_zval(stream, arg1);
|
||||
|
||||
if ((result=php_formatted_print(ht, &len, 0, 1 TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
if (Z_TYPE_PP(arg2) != IS_STRING && Z_TYPE_PP(arg2) != IS_UNICODE) {
|
||||
convert_to_text_ex(arg2);
|
||||
}
|
||||
|
||||
php_stream_write(stream, result, len);
|
||||
if (Z_TYPE_PP(arg2) == IS_STRING) {
|
||||
if ((result.s = php_formatted_print(ht, &len, 0, 1, PHP_RUNTIME TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
ret = php_stream_write(stream, result.s, len);
|
||||
} else {
|
||||
result = php_u_formatted_print(ht, &len, 0, 1, PHP_RUNTIME TSRMLS_CC);
|
||||
if (result.v == NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
ret = php_stream_write_unicode(stream, result.u, len);
|
||||
}
|
||||
|
||||
efree(result.v);
|
||||
|
||||
efree(result);
|
||||
|
||||
RETURN_LONG(len);
|
||||
RETURN_LONG(ret);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int vfprintf(resource stream, string format, array args)
|
||||
/* {{{ proto int vfprintf(resource stream, string format, array args) U
|
||||
Output a formatted string into a stream */
|
||||
PHP_FUNCTION(vfprintf)
|
||||
{
|
||||
php_stream *stream;
|
||||
zval **arg1;
|
||||
char *result;
|
||||
int len;
|
||||
zval **arg1, **arg2;
|
||||
zstr result;
|
||||
int len, ret;
|
||||
|
||||
if (ZEND_NUM_ARGS() != 3) {
|
||||
WRONG_PARAM_COUNT;
|
||||
}
|
||||
|
||||
if (zend_get_parameters_ex(1, &arg1)==FAILURE) {
|
||||
if (zend_get_parameters_ex(2, &arg1, &arg2)==FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
php_stream_from_zval(stream, arg1);
|
||||
|
||||
if ((result=php_formatted_print(ht, &len, 1, 1 TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
if (Z_TYPE_PP(arg2) != IS_STRING && Z_TYPE_PP(arg2) != IS_UNICODE) {
|
||||
convert_to_text_ex(arg2);
|
||||
}
|
||||
|
||||
php_stream_write(stream, result, len);
|
||||
if (Z_TYPE_PP(arg2) == IS_STRING) {
|
||||
if ((result.s = php_formatted_print(ht, &len, 1, 1, PHP_RUNTIME TSRMLS_CC))==NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
ret = php_stream_write(stream, result.s, len);
|
||||
} else {
|
||||
result = php_u_formatted_print(ht, &len, 1, 1, PHP_RUNTIME TSRMLS_CC);
|
||||
if (result.v == NULL) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
ret = php_stream_write_unicode(stream, result.u, len);
|
||||
}
|
||||
|
||||
efree(result);
|
||||
efree(result.v);
|
||||
|
||||
RETURN_LONG(len);
|
||||
RETURN_LONG(ret);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue