]> granicus.if.org Git - php/commitdiff
- Initial support of easy way to generate unicode strings: [v]uspprinf()
authorMarcus Boerger <helly@php.net>
Sun, 14 Aug 2005 17:14:42 +0000 (17:14 +0000)
committerMarcus Boerger <helly@php.net>
Sun, 14 Aug 2005 17:14:42 +0000 (17:14 +0000)
# Same semantics as [v]spprintf, only it prints unicode strings instead of
# native strings. Atm it has a little problem since it length doesn't take
# the difference between UTF-16 code points vs units into account. But as
# long as no 4 byte codes are involved it should already run everything.

ext/standard/php_smart_str.h
main/spprintf.c
main/spprintf.h

index 69a79c760b53f33d2e8f87e304e90421092a45a7..c6d0dbbbaf4ae902cb72e4eca49d833040a9a9e9 100644 (file)
 #define smart_str_appends(dest, src) \
        smart_str_appendl((dest), (src), strlen(src))
 
+/* normall character appending */
 #define smart_str_appendc(dest, c) \
        smart_str_appendc_ex((dest), (c), 0)
+
+/* appending of a single UTF-16 code unit (2 byte)*/
+#define smart_str_append2c(dest, c) while (0) {        \
+       smart_str_appendc_ex((dest), (c&0xFF), 0);      \
+       smart_str_appendc_ex((dest), (c&0xFF00 ? c>>8 : '\0'), 0);      \
+}
+
 #define smart_str_free(s) \
        smart_str_free_ex((s), 0)
 #define smart_str_appendl(dest, src, len) \
index 0af4257cadb591204d69ad7ffd2904dca7973f14..d5a8a39ffd807f3aff29421f347a46ed48ceae91 100644 (file)
  *
  * NOTE: Evaluation of the ch argument should not have any side-effects
  */
-#define INS_CHAR_NR(xbuf, ch) do {     \
-       smart_str_appendc(xbuf, ch);    \
+#define INS_CHAR_NR(unicode, xbuf, ch) do {                    \
+       if (unicode) {                                                                  \
+               smart_str_append2c(xbuf, ch);                           \
+       } else {                                                                                \
+               smart_str_appendc(xbuf, ch);                            \
+       }                                                                                               \
 } while (0)
 
-#define INS_STRING(xbuf, s, slen) do {         \
-       smart_str_appendl(xbuf, s, slen);       \
+#define INS_STRING(unicode, xbuf, s, slen) do {        \
+       if (unicode) {                                                                  \
+               smart_str_appendl(xbuf, s, slen);                       \
+       } else {                                                                                \
+               size_t newlen, sz = 2*(slen);                           \
+               smart_str_alloc(xbuf, (sz), 0);                         \
+               memcpy(xbuf->c + xbuf->len, s, (sz));           \
+               xbuf->len += (sz);                                                      \
+       }                                                                                               \
 } while (0)
        
-#define INS_CHAR(xbuf, ch)          \
-       INS_CHAR_NR(xbuf, ch)
+#define INS_CHAR(unicode, xbuf, ch)                                    \
+       INS_CHAR_NR(unicode, xbuf, ch)
 
 /*
  * Macro that does padding. The padding is done by printing
  * the character ch.
  */
-#define PAD(xbuf, count, ch) do {                                      \
+#define PAD(unicode, xbuf, count, ch) do {                     \
        if ((count) > 0) {                                      \
-               size_t newlen;                                                          \
-               smart_str_alloc(xbuf, (count), 0);                      \
-               memset(xbuf->c + xbuf->len, ch, (count));       \
-               xbuf->len += (count);                           \
+               size_t newlen, p, sz = (count);                         \
+               if (unicode) {                                                          \
+                       p = sz;                                                                 \
+                       sz <<= 1;                                                               \
+                       smart_str_alloc(xbuf, sz, 0);                   \
+                       while(p--) smart_str_appendc(xbuf, ch); \
+               } else {                                                                        \
+                       smart_str_alloc(xbuf, sz, 0);                   \
+                       memset(xbuf->c + xbuf->len, ch, sz);    \
+               }                                                                                       \
+               xbuf->len += sz;                                                        \
        }                                                                                               \
 } while (0)
 
 #define NUM(c) (c - '0')
 
-#define STR_TO_DEC(str, num) do {                      \
-       num = NUM(*str++);                      \
-       while (isdigit((int)*str)) {            \
-               num *= 10;                              \
-               num += NUM(*str++);                     \
-               if (num >= INT_MAX / 10) {                      \
-                       while (isdigit((int)*str++));   \
-                       break;                                                  \
-               }                                                                       \
-    }                                                                          \
+#define STR_TO_DEC(str, num) do {                                      \
+       num = NUM(*str++);                                      \
+       while (isdigit((int)*str)) {                            \
+               num *= 10;                                              \
+               num += NUM(*str++);                                     \
+               if (num >= INT_MAX / 10) {                                      \
+                       while (isdigit((int)*str++));                   \
+                       break;                                                                  \
+               }                                                                                       \
+    }                                                                                          \
 } while (0)
 
 /*
  * adding '0's to the left of the string that is going
  * to be printed.
  */
-#define FIX_PRECISION(adjust, precision, s, s_len) do {        \
-    if (adjust)                                                                \
-               while (s_len < precision) {                     \
-                       *--s = '0';                                     \
-                       s_len++;                                        \
-               }                                                                                               \
+#define FIX_PRECISION(adjust, precision, s, s_len)  \
+       do {                                                                                    \
+    if (adjust)                                                                                \
+               while (s_len < precision) {                                     \
+                       *--s = '0';                                                             \
+                       s_len++;                                                                \
+               }                                                                                       \
 } while (0)
 
 
 /*
  * Do format conversion placing the output in buffer
  */
-static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap)
+static void xbuf_format_converter(int unicode, smart_str *xbuf, const char *fmt, va_list ap)
 {
        register char *s = NULL;
        register UChar *u = NULL;
        char *q;
-       int s_len;
+       int s_len, s_unicode;
        int32_t u_len;
 
        register int min_width = 0;
@@ -214,7 +233,7 @@ static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap)
 
        while (*fmt) {
                if (*fmt != '%') {
-                       INS_CHAR(xbuf, *fmt);
+                       INS_CHAR(unicode, xbuf, *fmt);
                } else {
                        /*
                         * Default variable settings
@@ -224,6 +243,7 @@ static void xbuf_format_converter(smart_str *xbuf, const char *fmt, va_list ap)
                        pad_char = ' ';
                        prefix_char = NUL;
                        free_s = 0;
+                       s_unicode = 0;
 
                        fmt++;
 
@@ -556,13 +576,20 @@ fmt_unicode:
                                        }
 
                                        u_len = u_strlen(u);
-                                       zend_convert_from_unicode(conv, &res, &s_len, u, u_len, &status);
-                                       if (U_FAILURE(status)) {
-                                               php_error(E_WARNING, "Could not convert Unicode to printable form in s[np]printf call");
-                                               return;
+                                       if (unicode) {
+                                               s_len = u_len; /* UTODO actually we think of 2bytes each atm */
+                                               s = (char*)u;
+                                               s_unicode = 1;
+                                       } else {
+                                               zend_convert_from_unicode(conv, &res, &s_len, u, u_len, &status);
+                                               if (U_FAILURE(status)) {
+                                                       php_error(E_WARNING, "Could not convert Unicode to printable form in s[np]printf call");
+                                                       return;
+                                               }
+                                               s = res;
+                                               free_s = 1;
                                        }
-                                       s = res;
-                                       free_s = 1;
+                                               
                                        pad_char = ' ';
                                        break;
                                }
@@ -747,23 +774,24 @@ fmt_error:
                                *--s = prefix_char;
                                s_len++;
                        }
-                       if (adjust_width && adjust == RIGHT && min_width > s_len) {
+                       if (adjust_width && adjust == RIGHT && min_width > u_len) {
                                if (pad_char == '0' && prefix_char != NUL) {
-                                       INS_CHAR(xbuf, *s);
+                                       INS_CHAR(unicode, xbuf, *s);
                                        s++;
                                        s_len--;
                                        min_width--;
                                }
-                               PAD(xbuf, min_width - s_len, pad_char);
+                               PAD(unicode, xbuf, min_width - s_len, pad_char);
                        }
                        /*
                         * Print the string s. 
                         */
-                       INS_STRING(xbuf, s, s_len);
+                       INS_STRING(s_unicode, xbuf, s, s_len);
                        if (free_s) efree(s);
 
-                       if (adjust_width && adjust == LEFT && min_width > s_len)
-                               PAD(xbuf, min_width - s_len, pad_char);
+                       if (adjust_width && adjust == LEFT && min_width > s_len) {
+                               PAD(unicode, xbuf, min_width - s_len, pad_char);
+                       }
                }
                fmt++;
        }
@@ -778,7 +806,7 @@ PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap
 {
        smart_str xbuf = {0};
 
-       xbuf_format_converter(&xbuf, format, ap);
+       xbuf_format_converter(0, &xbuf, format, ap);
        
        if (max_len && xbuf.len > max_len) {
                xbuf.len = max_len;
@@ -802,6 +830,34 @@ PHPAPI int spprintf(char **pbuf, size_t max_len, const char *format, ...)
        return (cc);
 }
 
+PHPAPI int vuspprintf(char **pbuf, size_t max_len, const char *format, va_list ap)
+{
+       smart_str xbuf = {0};
+
+       xbuf_format_converter(1, &xbuf, format, ap);
+       
+       if (max_len && xbuf.len > max_len) {
+               xbuf.len = max_len;
+       }
+       smart_str_0(&xbuf);
+               
+       *pbuf = xbuf.c;
+       
+       return xbuf.len;
+}
+
+
+PHPAPI int uspprintf(char **pbuf, size_t max_len, const char *format, ...)
+{
+       int cc;
+       va_list ap;
+
+       va_start(ap, format);
+       cc = vuspprintf(pbuf, max_len, format, ap);
+       va_end(ap);
+       return (cc);
+}
+
 /*
  * Local variables:
  * tab-width: 4
index d578331670a3ca19be4dd90f7d5e495b8ab1c66c..e48681ca1d2a93e962ca7cacf53f3c227eec8830 100644 (file)
@@ -38,8 +38,9 @@ There is also snprintf: See difference explained in snprintf.h
 
 BEGIN_EXTERN_C()
 PHPAPI int spprintf( char **pbuf, size_t max_len, const char *format, ...);
-
 PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap);
+PHPAPI int uspprintf( char **pbuf, size_t max_len, const char *format, ...);
+PHPAPI int vuspprintf(char **pbuf, size_t max_len, const char *format, va_list ap);
 END_EXTERN_C()
 
 #endif /* SNPRINTF_H */