[vlc-commits] variables: improve rational values parsing

Rémi Denis-Courmont git at videolan.org
Sat Apr 2 18:15:44 CEST 2016


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sat Apr  2 19:13:57 2016 +0300| [8af0d6b579b44bb0e50ccf4c7ac15750e52b72d3] | committer: Rémi Denis-Courmont

variables: improve rational values parsing

 - handle fractions with slash or colon,
 - return exact value for decimal (but non-binary) number,
 - do not treat leading zeroes as octal value indicator,
 - handle and reduce corner cases.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=8af0d6b579b44bb0e50ccf4c7ac15750e52b72d3
---

 src/misc/variables.c |   85 ++++++++++++++++++++++++++++----------------------
 1 file changed, 47 insertions(+), 38 deletions(-)

diff --git a/src/misc/variables.c b/src/misc/variables.c
index d480ebd..65163d5 100644
--- a/src/misc/variables.c
+++ b/src/misc/variables.c
@@ -32,7 +32,6 @@
 # include <search.h>
 #endif
 #include <assert.h>
-#include <float.h>
 #include <math.h>
 #include <limits.h>
 
@@ -1290,56 +1289,66 @@ int (var_InheritURational)(vlc_object_t *object,
                            unsigned *num, unsigned *den,
                            const char *var)
 {
-    /* */
-    *num = 0;
-    *den = 0;
-
-    /* */
-    char *tmp = var_InheritString(object, var);
-    if (!tmp)
+    char *str = var_InheritString(object, var);
+    if (str == NULL)
         goto error;
 
-    char *next;
-    unsigned n = strtol(tmp,  &next, 0);
-    unsigned d = strtol(*next ? &next[1] : "0", NULL, 0);
+    char *sep;
+    unsigned n = strtoul(str, &sep, 10);
+    unsigned d;
 
-    if (*next == '.') {
-        /* Interpret as a (finite positive) float number */
-        const int ubits = CHAR_BIT * sizeof (unsigned);
-        int exp;
-        double f = frexp(us_atof(tmp), &exp);
+    switch (*sep) {
+        case '\0':
+            /* Decimal integer */
+            d = 1;
+            break;
 
-        if (!isgreaterequal(f, 0.))
-            goto error; /* negative or not a number */
+        case ':':
+        case '/':
+            /* Decimal fraction */
+            d = strtoul(sep + 1, &sep, 10);
+            if (*sep != '\0')
+                goto error;
+            break;
+
+        case '.': {
+            /* Decimal number */
+            unsigned char c;
 
-        if (exp <= 1 - ubits) {
-            n = 0; /* too small */
             d = 1;
-        } else if (exp <= 0) {
-            n = floor(scalbn(f, ubits - 1 + exp));
-#if (FLT_RADIX != 2)
-# error Floating point configuration not supported.
-#endif
-            d = 1u << (ubits - 1);
-        } else if (exp <= ubits) {
-            n = floor(scalbn(f, ubits));
-            d = 1u << (ubits - exp);
-        } else
-            goto error; /* too big */
-    } else if ( *next == '\0' ) {
-        /* plain integer given */
-        *num = n;
-        *den = 1;
+            while ((c = *(++sep)) != '\0') {
+                c -= '0';
+
+                if (c >= 10)
+                    goto error;
+
+                n = n * 10 + c;
+                d *= 10;
+            }
+            break;
+        }
+
+        default:
+            goto error;
     }
 
-    if (n > 0 && d > 0)
+    free(str);
+
+    if (n == 0) {
+        *num = 0;
+        *den = d ? 1 : 0;
+    } else if (d == 0) {
+        *num = 1;
+        *den = 0;
+    } else
         vlc_ureduce(num, den, n, d, 0);
 
-    free(tmp);
     return VLC_SUCCESS;
 
 error:
-    free(tmp);
+    free(str);
+    *num = 0;
+    *den = 0;
     return VLC_EGENERIC;
 }
 



More information about the vlc-commits mailing list