[svn:parrot] r48873 - in trunk: include/parrot src

Paul at osuosl.org Paul at osuosl.org
Wed Sep 8 23:43:44 UTC 2010


Author: Paul C. Anagnostopoulos
Date: Wed Sep  8 23:43:44 2010
New Revision: 48873
URL: https://trac.parrot.org/parrot/changeset/48873

Log:
sprintf() trims exponents to 2 digits if possible

Modified:
   trunk/include/parrot/misc.h
   trunk/src/spf_render.c

Modified: trunk/include/parrot/misc.h
==============================================================================
--- trunk/include/parrot/misc.h	Wed Sep  8 22:21:54 2010	(r48872)
+++ trunk/include/parrot/misc.h	Wed Sep  8 23:43:44 2010	(r48873)
@@ -259,6 +259,11 @@
      */
 #  define PARROT_SPRINTF_MAX_PREC 3 * PARROT_SPRINTF_BUFFER_SIZE / 4
 
+    /* Floats formatted in exponent notation should have this number
+     * of exponent digits unless they need more.
+     */
+#  define PARROT_SPRINTF_EXP_DIGITS 2
+
 #  define cstr2pstr(cstr) Parrot_str_new_init(interp, (cstr), strlen(cstr), \
         Parrot_ascii_encoding_ptr, 0)
 #  define char2pstr(ch)   Parrot_str_new_init(interp, &(ch), 1, \

Modified: trunk/src/spf_render.c
==============================================================================
--- trunk/src/spf_render.c	Wed Sep  8 22:21:54 2010	(r48872)
+++ trunk/src/spf_render.c	Wed Sep  8 23:43:44 2010	(r48873)
@@ -56,6 +56,14 @@
 /* HEADERIZER BEGIN: static */
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 
+static void canonicalize_exponent (PARROT_INTERP,
+    ARGMOD(char *tc),
+    ARGIN(SpfInfo *info))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2)
+        __attribute__nonnull__(3)
+        FUNC_MODIFIES(*tc);
+
 static void gen_sprintf_call(
     ARGOUT(char *out),
     ARGMOD(SpfInfo *info),
@@ -89,6 +97,10 @@
         FUNC_MODIFIES(*dest)
         FUNC_MODIFIES(*src);
 
+#define ASSERT_ARGS_canonicalize_exponent  __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp) \
+    , PARROT_ASSERT_ARG(tc) \
+    , PARROT_ASSERT_ARG(info))
 #define ASSERT_ARGS_gen_sprintf_call __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(out) \
     , PARROT_ASSERT_ARG(info))
@@ -292,6 +304,88 @@
     *p = '\0';
 }
 
+/* This function is called to canonicalize any exponent in a formatted
+   float. PARROT_SPRINTF_EXP_DIGITS specifies the standard number of
+   exponent digits that we want. Remember that the exponent has the
+   form '...Esddd ', where 's' is the sign, 'ddd' is some number of digits,
+   and there may be trailing spaces. */
+
+static void
+canonicalize_exponent (PARROT_INTERP, ARGMOD(char *tc),
+                                      ARGIN(SpfInfo *info))
+{
+    ASSERT_ARGS(canonicalize_exponent)
+
+    const size_t exp_digits = PARROT_SPRINTF_EXP_DIGITS;
+    size_t len      = strlen(tc),
+           last_pos = len,
+           non0_pos = len,
+           sign_pos = 0,
+           e_pos    = 0;
+    int i;
+
+    /* Scan the formatted number backward to find the positions of the
+       last digit, leftmost non-0 exponent digit, sign, and E. */
+
+    for (i = len-1; i >= 0 && e_pos == 0; --i) {
+        switch (tc[i]) {
+            case '1': case '2': case '3':
+            case '4': case '5': case '6':
+            case '7': case '8': case '9':   non0_pos = i;
+                                            /* fall through */
+
+            case '0':                       if (last_pos == len) last_pos = i;
+                                            break;
+
+            case '+': case '-':             sign_pos = i;
+                                            break;
+
+            case 'E': case 'e':             e_pos = i;
+                                            break;
+
+            default:                        break;
+        }
+    }
+
+    /* If there is an E, and it is followed by a sign, and there are
+       leading zeroes on the exponent, and there are more than the
+       standard number of exponent digits, then we have work to do. */
+
+    if (e_pos != 0 && sign_pos == e_pos + 1 &&
+        non0_pos > sign_pos + 1 &&
+        last_pos - sign_pos > exp_digits) {
+
+        /* Close up to eliminate excess exponent digits and
+           adjust the length. Don't forget to move the NUL. */
+
+        size_t keep = (last_pos - non0_pos + 1 > exp_digits)
+                        ? len - non0_pos
+                        : exp_digits + (len - last_pos - 1);
+
+        mem_sys_memmove(&tc[sign_pos+1], &tc[len - keep], keep+1);
+        len = sign_pos + 1 + keep;
+
+        /* If it's a fixed-width field and we're too short now,
+           we have more work to do. If the field is left-justified,
+           pad the number on the right. Otherwise pad the number on
+           the left, possibly with leading zeroes. */
+
+        if ((info->flags & FLAG_WIDTH) && len < info->width) {
+            if (info->flags & FLAG_MINUS) {
+                while (len < info->width) {
+                    strcat(tc, " ");
+                    ++len;
+                }
+            }
+            else {
+                size_t i;
+                mem_sys_memmove(&tc[info->width - len], &tc[0], len+1);
+                for (i = 0; i < info->width - len; ++i)
+                    tc[i] = (info->flags & FLAG_ZERO) ? '0' : ' ';
+            }
+        }
+    }
+}
 
 /*
 
@@ -759,45 +853,9 @@
                                 Parrot_str_free_cstring(tempstr);
                             }
 
-#ifdef WIN32
-
-                            /* Microsoft defaults to three digits for
-                             * exponents, even when fewer digits would suffice.
-                             * For the sake of portability, we will here
-                             * attempt to hide that.  */
-                            if (ch == 'g' || ch == 'G'
-                             || ch == 'e' || ch == 'E') {
-                                const size_t tclen = strlen(tc);
-                                size_t j;
-                                for (j = 0; j < tclen; ++j) {
-                                    if ((tc[j] == 'e' || tc[j] == 'E')
-                                        && (tc[j+1] == '+' || tc[j+1] == '-')
-                                        && tc[j+2] == '0'
-                                        && isdigit((unsigned char)tc[j+3])
-                                        && isdigit((unsigned char)tc[j+4]))
-                                    {
-                                        mem_sys_memmove(&tc[j+2], &tc[j+3],
-                                            strlen(&tc[j+2]));
-
-                                        /* now fix any broken length */
-
-                                        if ((info.flags & FLAG_WIDTH)
-                                          && strlen(tc) < info.width) {
-                                            if (info.flags & FLAG_MINUS)
-                                                strcat(tc, " ");
-                                            else {
-                                                mem_sys_memmove(&tc[1], &tc[0],
-                                                    strlen(tc) + 1);
-                                                tc[0] = (info.flags & FLAG_ZERO) ? '0' : ' ';
-                                            }
-                                        }
-
-                                        /* only one fix required per string */
-                                        break;
-                                    }
-                                }
-                            }
-#endif /* WIN32 */
+                            if (ch == 'e' || ch == 'E' ||
+                                ch == 'g' || ch == 'G')
+                              canonicalize_exponent(interp, tc, &info);
 
                             targ = Parrot_str_concat(interp, targ, cstr2pstr(tc));
                             }


More information about the parrot-commits mailing list