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