andrei          Tue Dec 19 18:41:40 2006 UTC

  Modified files:              
    /php-src/ext/standard       formatted_print.c 
  Log:
  Unicode support in *printf() functions. (Antony, Andrei)
  
  
http://cvs.php.net/viewvc.cgi/php-src/ext/standard/formatted_print.c?r1=1.91&r2=1.92&diff_format=u
Index: php-src/ext/standard/formatted_print.c
diff -u php-src/ext/standard/formatted_print.c:1.91 
php-src/ext/standard/formatted_print.c:1.92
--- php-src/ext/standard/formatted_print.c:1.91 Tue Dec 19 13:13:48 2006
+++ php-src/ext/standard/formatted_print.c      Tue Dec 19 18:41:40 2006
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: formatted_print.c,v 1.91 2006/12/19 13:13:48 dmitry Exp $ */
+/* $Id: formatted_print.c,v 1.92 2006/12/19 18:41:40 andrei Exp $ */
 
 #include <math.h>                              /* modf() */
 #include "php.h"
@@ -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 @@
        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_u_sprintf_appendstring() {{{ */
+inline static void
+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,
+php_sprintf_appendint(char **buffer, int *pos, int *size, long number, 
                                                int width, char padding, int 
alignment, 
                                                int always_sign)
 {
@@ -158,7 +224,49 @@
                                                         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_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 @@
 #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_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 @@
                                                         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 @@
        *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 @@
  *  "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 @@
                        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 @@
                                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 @@
 }
 /* }}} */
 
-/* {{{ 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);
-
-       efree(result);
+       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);
 
-       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);
 }
 /* }}} */
 

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to