Revision: 49344
          http://brlcad.svn.sourceforge.net/brlcad/?rev=49344&view=rev
Author:   n_reed
Date:     2012-02-08 20:18:12 +0000 (Wed, 08 Feb 2012)
Log Message:
-----------
Changed supported vls conversions; new syntax and semantics. Updated related 
tests.

Modified Paths:
--------------
    brlcad/trunk/src/libbu/sscanf.c
    brlcad/trunk/src/libbu/test_sscanf.c

Modified: brlcad/trunk/src/libbu/sscanf.c
===================================================================
--- brlcad/trunk/src/libbu/sscanf.c     2012-02-08 19:51:19 UTC (rev 49343)
+++ brlcad/trunk/src/libbu/sscanf.c     2012-02-08 20:18:12 UTC (rev 49344)
@@ -61,7 +61,7 @@
 #define        SIZET           0x02000 /* z: size_t */
 #define        SHORTSHORT      0x04000 /* hh: char */
 #define        UNSIGNED        0x08000 /* %[oupxX] conversions */
-#define        BUVLS           0x20000 /* V: struct bu_vls */
+#define        ALTERNATE       0x40000 /* # flag for alternate behavior */
 
 /*
  * The following are used in integral conversions only:
@@ -72,9 +72,8 @@
 #define        PFXOK           0x00100 /* 0x prefix is (still) legal */
 #define        NZDIGITS        0x00200 /* no zero digits detected */
 #define        HAVESIGN        0x10000 /* sign detected */
+#define        HAVEWIDTH       0x20000
 
-#define        HAVEWIDTH       0x40000
-
 /*
  * Conversion types.
  */
@@ -83,80 +82,8 @@
 #define        CT_STRING       2       /* %s conversion */
 #define        CT_INT          3       /* %[dioupxX] conversion */
 #define        CT_FLOAT        4       /* %[efgEFG] conversion */
+#define        CT_VLS          5       /* %V and %#V conversion */
 
-#define CCL_TABLE_SIZE 256
-#define CCL_ACCEPT 1
-#define CCL_REJECT 0
-
-static const char*
-get_ccl_table(char *tab, const char *fmt)
-{
-    int i, v, curr, lower, upper;
-
-    BU_ASSERT(tab != NULL);
-    BU_ASSERT(fmt != NULL);
-
-#define SET_CCL_ENTRY(e) tab[e] = v;
-
-    curr = *fmt++;
-    if (curr == '^') {
-       /* accept all chars by default */
-       memset(tab, CCL_ACCEPT, CCL_TABLE_SIZE);
-       v = CCL_REJECT;
-       curr = *fmt++;
-    } else {
-       /* reject all chars by default */
-       memset(tab, CCL_REJECT, CCL_TABLE_SIZE);
-       v = CCL_ACCEPT;
-    }
-
-    if (curr == '\0') {
-       /* format ended before closing ] */
-       return fmt - 1;
-    }
-
-    SET_CCL_ENTRY(curr);
-
-    /* set table entries from fmt */
-    while (1) {
-       lower = curr;
-       curr = *fmt++;
-
-       if (curr == '\0') {
-           return fmt - 1;
-       }
-       if (curr == ']') {
-           return fmt;
-       }
-
-       /* '-' usually used to specify a range */
-       if (curr == '-') {
-           upper = *fmt;
-
-           if (upper == ']' || upper < lower) {
-               /* ordinary '-' */
-               SET_CCL_ENTRY(curr);
-               continue;
-           }
-
-           /* Range. Set everything in the range. */
-           for (i = 0; i < CCL_TABLE_SIZE; ++i) {
-               if (lower < i && i <= upper) {
-                   SET_CCL_ENTRY(i);
-               }
-           }
-
-           /* need to skip upper since it is not an ordinary character */
-           curr = upper;
-           ++fmt;
-       } else {
-           /* ordinary char */
-           SET_CCL_ENTRY(curr);
-       }
-    }
-    /* NOTREACHED */
-}
-
 /* Copy part of a string, everything from srcStart to srcEnd (exclusive),
  * into a new buffer. Returns the allocated buffer.
  */
@@ -193,13 +120,13 @@
 }
 
 /* The basic strategy of this routine is to break the formatted scan into
- * pieces, one for each word of the format string.
+ * pieces, one for each conversion in the format string.
  *
- * New two-word format strings are created by appending "%n" (request to sscanf
- * for consumed char count) to each word of the provided format string. sscanf
- * is called with each two-word format string, followed by an appropriately
- * cast pointer from the vararg list, followed by the local consumed count
- * pointer.
+ * New two-conversion format strings are created by appending "%n" (request to
+ * sscanf for consumed char count) to each conversion of the provided format
+ * string. sscanf is called with each two-conversion format string, followed by
+ * an appropriately cast pointer from the vararg list, followed by the local
+ * consumed count pointer.
  *
  * Each time sscanf successfully returns, the total assignment count and the
  * total consumed character count are updated. The consumed character count is
@@ -218,7 +145,6 @@
     char *partFmt;
     const char *fmt;
     const char *wordStart;
-    char ccl_tab[CCL_TABLE_SIZE];
 
     BU_ASSERT(src != NULL);
     BU_ASSERT(fmt0 != NULL);
@@ -257,6 +183,10 @@
     FREE_FORMAT_PART; \
     return numFieldsAssigned;
 
+#define EXIT_DUE_TO_MISC_ERROR \
+    FREE_FORMAT_PART; \
+    return EOF;
+
     while (1) {
        /* Mark word start, then skip to first non-white char. */
        wordStart = fmt;
@@ -313,6 +243,9 @@
        case '*':
            flags |= SUPPRESS;
            goto again;
+       case '#':
+           flags |= ALTERNATE;
+           goto again;
        case 'j':
            flags |= INTMAXT;
            goto again;
@@ -359,9 +292,6 @@
                flags |= SHORTSHORT;
            }
            goto again;
-       case 'V':
-           flags |= BUVLS;
-           goto again;
 
 
        /* MAXIMUM FIELD WIDTH */
@@ -413,7 +343,35 @@
            c = CT_STRING;
            break;
        case '[':
-           fmt = get_ccl_table(ccl_tab, fmt);
+           /* note that at this point c == '[' == fmt[-1] and so fmt[0] is
+            * either '^' or the first character of the class
+            */
+
+           /* there should be at least one character in between brackets */
+           if (fmt[0] == '\0' || fmt[1] == '\0') {
+               EXIT_DUE_TO_MISC_ERROR;
+           }
+
+           /* skip literal ']' ("[]" or "[^]") */
+           if (fmt[0] == ']') {
+               fmt = &fmt[1];
+           } else if (fmt[0] == '^' && fmt[1] == ']') {
+               fmt = &fmt[2];
+           }
+
+           /* point fmt after character class */
+           while (1) {
+               c = *fmt++;
+               if (c == '\0') {
+                   /* error */
+                   goto exit;
+               }
+               if (c == ']') {
+                   /* found end of character class */
+                   break;
+               }
+           }
+
            flags |= NOSKIP;
            c = CT_CCL;
            break;
@@ -425,6 +383,9 @@
            flags |= NOSKIP;
            c = CT_CHAR;
            break;
+       case 'V':
+           c = CT_VLS;
+           break;
        case 'n':
            if (flags & SUPPRESS) {
                /* This is legal, but doesn't really make sense. Caller
@@ -461,8 +422,7 @@
            /* Format string ends with bare '%'. Returning EOF regardless of
             * successfull assignments is a backwards compatability behavior.
             */
-           FREE_FORMAT_PART;
-           return EOF;
+           EXIT_DUE_TO_MISC_ERROR;
 
        default:
            EXIT_DUE_TO_MATCH_FAILURE;
@@ -493,153 +453,134 @@
 
        switch (c) {
 
-       case CT_CHAR:
-       case CT_CCL:
-       case CT_STRING:
+       case CT_VLS:
+           /* %V %#V conversion */
+       {
+           struct bu_vls *vls = NULL;
 
-           /* %Vc or %V[...] or %Vs conversion */
-           if (flags & BUVLS) {
-               struct bu_vls *vls = NULL;
-               int conversion = c;
+           if (src[numCharsConsumed] == '\0') {
+               EXIT_DUE_TO_INPUT_FAILURE;
+           }
 
-               if (src[numCharsConsumed] == '\0') {
-                   EXIT_DUE_TO_INPUT_FAILURE;
-               }
-
-               /* Input whitespace is skipped for %Vs, and skipped for
-                * %Vc and %V[...] if the conversion specification is
-                * preceeded by at least one whitespace character.
-                */
-               if (isspace(*wordStart) || conversion == CT_STRING) {
-                   while (1) {
-                       c = src[numCharsConsumed];
-                       if (c == '\0' || !isspace(c)) {
-                           break;
-                       }
-                       ++numCharsConsumed;
+           /* Leading input whitespace is skipped for %#V, and for %V iff the
+            * conversion specification is preceeded by at least one whitespace
+            * character.
+            */
+           if (isspace(*wordStart) || flags & ALTERNATE) {
+               while (1) {
+                   c = src[numCharsConsumed];
+                   if (c == '\0' || !isspace(c)) {
+                       break;
                    }
+                   ++numCharsConsumed;
                }
+           }
 
-               /* set default width */
-               if (width == 0 && !(flags & HAVEWIDTH)) {
-                   if (conversion == CT_CHAR) {
-                       width = 1;
-                   } else {
-                       /* infinity */
-                       width = ~(width & 0);
-                   }
-               }
+           /* if no width provided, width is infinity */
+           if (width == 0 && !(flags & HAVEWIDTH)) {
+                   width = ~(width & 0);
+           }
 
-               /* grab vls pointer if we're assigning */
-               if (!(flags & SUPPRESS)) {
-                   vls = va_arg(ap, struct bu_vls*);
-                   bu_vls_trunc(vls, 0);
-               }
+           /* grab vls pointer if we're assigning */
+           if (!(flags & SUPPRESS)) {
+               vls = va_arg(ap, struct bu_vls*);
+           }
 
-               /* if not CT_CCL, character class table isn't initialized */
-               if (conversion != CT_CCL) {
+           /* Copy characters from src to vls. Stop at width, whitespace
+            * character, or EOI.
+            */
+           if (flags & SUPPRESS) {
+               for (i = 0; i < width; ++i) {
+                   c = src[numCharsConsumed + i];
 
-                   /* CT_CHAR accepts all */
-                   memset(ccl_tab, CCL_ACCEPT, sizeof(ccl_tab));
-
-                   /* CT_STRING accepts all except space */
-                   if (conversion == CT_STRING) {
-                       for (c = 0; c < CCL_TABLE_SIZE; ++c) {
-                           if (isspace(c)) {
-                               ccl_tab[c] = CCL_REJECT;
-                           }
-                       }
+                   /* stop at non-matching or EOI */
+                   if (c == '\0') {
+                       break;
                    }
+                   if ((flags & ALTERNATE) && isspace(c)) {
+                       break;
+                   }
+                   ++partConsumed;
                }
+           } else {
+               for (i = 0; i < width; ++i) {
+                   c = src[numCharsConsumed + i];
 
-               /* always break on '\0' */
-               ccl_tab['\0'] = CCL_REJECT;
-
-               /* Copy characters from src to vls. Stop at width, non-matching
-                * character, or EOI.
-                */
-               if (flags & SUPPRESS) {
-                   for (i = 0; i < width; ++i) {
-                       c = src[numCharsConsumed + i];
-
-                       /* stop at non-matching or EOI */
-                       if (ccl_tab[c] == CCL_REJECT) {
-                           break;
-                       }
-                       ++partConsumed;
+                   /* stop at non-matching or EOI */
+                   /* stop at non-matching or EOI */
+                   if (c == '\0') {
+                       break;
                    }
-               } else {
-                   for (i = 0; i < width; ++i) {
-                       c = src[numCharsConsumed + i];
-
-                       /* stop at non-matching or EOI */
-                       if (ccl_tab[c] == CCL_REJECT) {
-                           break;
-                       }
-
-                       /* copy valid char to vls */
-                       bu_vls_putc(vls, c);
-
-                       ++partConsumed;
+                   if ((flags & ALTERNATE) && isspace(c)) {
+                       break;
                    }
 
-                   if (partConsumed > 0) {
-                       /* successful assignment */
-                       ++partAssigned;
-                   }
+                   /* copy valid char to vls */
+                   bu_vls_putc(vls, c);
+                   ++partConsumed;
                }
-           } /* BUVLS */
 
-           else {
-               /* unsupressed %s or %[...] conversion */
-               if (!(flags & SUPPRESS) && c != CT_CHAR) {
+               if (partConsumed > 0) {
+                   /* successful assignment */
+                   ++partAssigned;
+               }
+           }
+           break;
+       } /* CT_VLS */
 
-                   if (width == 0 && !(flags & HAVEWIDTH)) {
-                       struct bu_vls err = BU_VLS_INIT_ZERO;
+       case CT_CHAR:
+       case CT_CCL:
+       case CT_STRING:
 
-                       /* No width was provided by caller.
-                        *
-                        * If the caller is using %s or %[...] without a
-                        * maximum field width, then there is a bug in the
-                        * caller code.
-                        *
-                        * sscanf could easily overrun the provided buffer and
-                        * cause a program crash, so just bomb here and make
-                        * the source of the problem clear.
-                        */
-                       bu_vls_sprintf(&err, "ERROR.\n"
-                                   "  bu_sscanf was called with bad format 
string: \"%s\"\n"
-                                   "  %%s and %%[...] conversions must be 
bounded using "
-                                   "a maximum field width.", fmt0);
-                       bu_bomb(bu_vls_addr(&err));
-                   }
+           /* unsupressed %s or %[...] conversion */
+           if (!(flags & SUPPRESS) && c != CT_CHAR) {
 
-                   if (width == 0) {
-                       /* Caller specified zero width in the format string.
-                        *
-                        * The behavior of sscanf for a zero width is
-                        * undefined, so we provide our own consistent
-                        * behavior here.
-                        *
-                        * The assignment wasn't suppressed, so we'll assume
-                        * the caller provided a pointer and wants us to write
-                        * to it. Just write '\0' and call it a successfull
-                        * assignment.
-                        */
-                       *va_arg(ap, char*) = '\0';
-                       ++partAssigned;
-                       break;
-                   }
-                   
+               if (width == 0 && !(flags & HAVEWIDTH)) {
+                   struct bu_vls err = BU_VLS_INIT_ZERO;
+
+                   /* No width was provided by caller.
+                    *
+                    * If the caller is using %s or %[...] without a
+                    * maximum field width, then there is a bug in the
+                    * caller code.
+                    *
+                    * sscanf could easily overrun the provided buffer and
+                    * cause a program crash, so just bomb here and make
+                    * the source of the problem clear.
+                    */
+                   bu_vls_sprintf(&err, "ERROR.\n"
+                               "  bu_sscanf was called with bad format string: 
\"%s\"\n"
+                               "  %%s and %%[...] conversions must be bounded 
using "
+                               "a maximum field width.", fmt0);
+                   bu_bomb(bu_vls_addr(&err));
                }
 
-               /* ordinary %c or %[...] or %s conversion */
-               if (flags & LONG) {
-                   SSCANF_TYPE(wchar_t*);
-               } else {
-                   SSCANF_TYPE(char*);
+               if (width == 0) {
+                   /* Caller specified zero width in the format string.
+                    * (%0c %0s or %0[...])
+                    *
+                    * The behavior of sscanf for a zero width is
+                    * undefined, so we provide our own consistent
+                    * behavior here.
+                    *
+                    * The assignment wasn't suppressed, so we'll assume
+                    * the caller provided a pointer and wants us to write
+                    * to it. Just write '\0' and call it a successfull
+                    * assignment.
+                    */
+                   *va_arg(ap, char*) = '\0';
+                   ++partAssigned;
+                   break;
                }
+               
            }
+
+           /* ordinary %c or %[...] or %s conversion */
+           if (flags & LONG) {
+               SSCANF_TYPE(wchar_t*);
+           } else {
+               SSCANF_TYPE(char*);
+           }
            break;
 
        /* %[dioupxX] conversion */

Modified: brlcad/trunk/src/libbu/test_sscanf.c
===================================================================
--- brlcad/trunk/src/libbu/test_sscanf.c        2012-02-08 19:51:19 UTC (rev 
49343)
+++ brlcad/trunk/src/libbu/test_sscanf.c        2012-02-08 20:18:12 UTC (rev 
49344)
@@ -733,31 +733,26 @@
     int bu_ret;
     struct bu_vls vls = BU_VLS_INIT_ZERO;
 
-    /* %Vc */
-    test_vls("de mus noc", "%Vc", "d");
-    test_vls(" de mus noc", "%6Vc", " de mu");
-    test_vls(" de mus noc", " %7Vc", "de mus ");
-    test_vls("de mus noc", "%11Vc", "de mus noc");
+    /* %V */
+    test_vls("de mus noc", "%V", "de mus noc");
+    test_vls(" de mus noc", "%6V", " de mu");
+    test_vls(" de mus noc", " %7V", "de mus ");
+    test_vls("de mus noc", "%11V", "de mus noc");
 
-    bu_ret = bu_sscanf("de mus noc", "%*11Vc", &vls);
+    print_src_and_fmt("de mus noc", "%*11V");
+    bu_ret = bu_sscanf("de mus noc", "%*11V", &vls);
     checkReturnVal("bu_sscanf", bu_ret, 0);
 
-    /* %V[...] */
-    test_vls("abcA", "%V[a-z]", "abc");
-    test_vls(" abcA", " %V[a-z]", "abc");
-    test_vls(" abcA", "%3V[ a-z]", " ab");
+    /* %#V */
+    test_vls(" \tabc ABC", "%#V", "abc");
+    test_vls(" \tabc ABC", "%#4V", "abc");
+    test_vls(" \tabc", "%#4Vs", "abc");
 
-    bu_ret = bu_sscanf(" abcA", "%*V[ a-z]", &vls);
+    print_src_and_fmt(" \tabc ABC", "%#*V");
+    bu_vls_trunc(&vls, 0);
+    bu_ret = bu_sscanf(" \tabc ABC", "%#*V", &vls);
     checkReturnVal("bu_sscanf", bu_ret, 0);
 
-    /* %Vs */
-    test_vls(" \tabc ABC", "%Vs", "abc");
-    test_vls(" \tabc ABC", "%4Vs", "abc");
-    test_vls(" \tabc", "%4Vs", "abc");
-
-    bu_ret = bu_sscanf(" abcA", "%*Vs", &vls);
-    checkReturnVal("bu_sscanf", bu_ret, 0);
-
     bu_vls_free(&vls);
 }
 

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Keep Your Developer Skills Current with LearnDevNow!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-d2d
_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to