You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stdcxx.apache.org by se...@apache.org on 2008/02/18 18:09:03 UTC
svn commit: r628817 - in /stdcxx/trunk/tests: include/rw_braceexp.h
self/0.braceexp.cpp src/braceexp.cpp
Author: sebor
Date: Mon Feb 18 09:09:00 2008
New Revision: 628817
URL: http://svn.apache.org/viewvc?rev=628817&view=rev
Log:
2008-02-18 Martin Sebor <se...@roguewave.com>
* tests/include/rw_braceexp.h: Set svn:eol-style and svn:keywords
properties.
* tests/src/braceexp.cpp: Ditto.
* tests/self/0.braceexp.cpp: Ditto.
Modified:
stdcxx/trunk/tests/include/rw_braceexp.h (props changed)
stdcxx/trunk/tests/self/0.braceexp.cpp (contents, props changed)
stdcxx/trunk/tests/src/braceexp.cpp (contents, props changed)
Propchange: stdcxx/trunk/tests/include/rw_braceexp.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: stdcxx/trunk/tests/include/rw_braceexp.h
------------------------------------------------------------------------------
svn:keywords = Id
Modified: stdcxx/trunk/tests/self/0.braceexp.cpp
URL: http://svn.apache.org/viewvc/stdcxx/trunk/tests/self/0.braceexp.cpp?rev=628817&r1=628816&r2=628817&view=diff
==============================================================================
--- stdcxx/trunk/tests/self/0.braceexp.cpp (original)
+++ stdcxx/trunk/tests/self/0.braceexp.cpp Mon Feb 18 09:09:00 2008
@@ -1,121 +1,121 @@
-/************************************************************************
- *
- * 0.braceexp.cpp - tests exercising the rw_brace_expand() helper
- *
- * $Id$
- *
- ************************************************************************
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed
- * with this work for additional information regarding copyright
- * ownership. The ASF licenses this file to you under the Apache
- * License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * permissions and limitations under the License.
- *
- **************************************************************************/
-
-#include <rw_braceexp.h>
-
-#include <stdio.h> // for fprintf(), stderr
-#include <stdlib.h> // for free()
-#include <string.h> // for strcmp()
-
-// the number of failed tests
-static int nerrors;
-
-static void
-test (int line, const char* brace_expr, const char* expect)
-{
- char buf [128];
-
- char* result = rw_brace_expand (brace_expr, buf, sizeof (buf), ' ');
-
- const bool equal = (expect && result)
- ? !strcmp (expect, result)
- : expect == result;
-
- if (!equal) {
-
- ++nerrors;
-
- fprintf (stderr,
- "%d. rw_brace_expand(\"%s\", ...) failed. "
- "expected \"%s\" got \"%s\"\n",
- line, brace_expr,
- expect ? expect : "(null)",
- result ? result : "(null)");
- }
-
- if (result != buf)
- free (result);
-}
-
-int main ()
-{
-#define TEST(s,e) test (__LINE__, s, e)
-
- TEST ("a", "a");
- TEST ("a\\b", "ab");
-
- TEST ("{0}" , "{0}");
- TEST ("\\{0}", "{0}");
- TEST ("{\\0}", "{0}");
- TEST ("{0\\}", "{0}");
-
- TEST ("{0..1}", "0 1");
- TEST ("\\{0..1}", "{0..1}");
- TEST ("{\\0..1}", "{0..1}");
- TEST ("{0\\..1}", "{0..1}");
- TEST ("{0..\\1}", "{0..1}");
- TEST ("{0..1\\}", "{0..1}");
-
- TEST ("a{0}", "a{0}");
- TEST ("a{0}b", "a{0}b");
- TEST ("a\\{0\\}b", "a{0}b");
- TEST ("a\\{0,123,4\\}b", "a{0,123,4}b");
-
- TEST ("{0..a}", "{0..a}");
- TEST ("{a..0}", "{a..0}");
-
- TEST ("{0..0}", "0");
- TEST ("{0..5}", "0 1 2 3 4 5");
- TEST ("{4..2}", "4 3 2");
- TEST ("{a..g}", "a b c d e f g");
- TEST ("{g..c}", "g f e d c");
- TEST ("{A..G}", "A B C D E F G");
- TEST ("{G..C}", "G F E D C");
-
- TEST ("{,}", "");
- TEST ("{abc,def}", "abc def");
- TEST ("{ab\\c,d\\ef}", "abc def");
- TEST ("abc{d,e,f}", "abcd abce abcf");
-
- TEST ("z{c,a{d..f}a,c}z", "zcz zadaz zaeaz zafaz zcz");
- TEST ("z{c,a{d,e,f}a,c}z", "zcz zadaz zaeaz zafaz zcz");
-
- TEST ("{abc,{,d,e,f,}}", "abc d e f");
- TEST ("{abc,{,d,e,f,}}{x,y}", "abcx abcy x y dx dy ex ey fx fy x y");
- TEST ("{abc,{,d\\,e\\,f,}}", "abc d,e,f");
-
- TEST ("A{0..3}", "A0 A1 A2 A3");
- TEST ("A{0..2}{6..7}", "A06 A07 A16 A17 A26 A27");
- TEST ("A{A}{0..3}", "A{A}{0..3}");
- TEST ("A{0..3}{A}", "A0{A} A1{A} A2{A} A3{A}");
-
- TEST ("A{0,{4..7}{,}}", "A0 A4 A4 A5 A5 A6 A6 A7 A7");
- TEST ("a{1,3,x{5..9}y}b", "a1b a3b ax5yb ax6yb ax7yb ax8yb ax9yb");
- TEST ("{en,es}_{US,MX}.*", "en_US.* en_MX.* es_US.* es_MX.*");
-
- // return 0 on success, 1 on failure
- return !(0 == nerrors);
-}
+/************************************************************************
+ *
+ * 0.braceexp.cpp - tests exercising the rw_brace_expand() helper
+ *
+ * $Id$
+ *
+ ************************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ *
+ **************************************************************************/
+
+#include <rw_braceexp.h>
+
+#include <stdio.h> // for fprintf(), stderr
+#include <stdlib.h> // for free()
+#include <string.h> // for strcmp()
+
+// the number of failed tests
+static int nerrors;
+
+static void
+test (int line, const char* brace_expr, const char* expect)
+{
+ char buf [128];
+
+ char* result = rw_brace_expand (brace_expr, buf, sizeof (buf), ' ');
+
+ const bool equal = (expect && result)
+ ? !strcmp (expect, result)
+ : expect == result;
+
+ if (!equal) {
+
+ ++nerrors;
+
+ fprintf (stderr,
+ "%d. rw_brace_expand(\"%s\", ...) failed. "
+ "expected \"%s\" got \"%s\"\n",
+ line, brace_expr,
+ expect ? expect : "(null)",
+ result ? result : "(null)");
+ }
+
+ if (result != buf)
+ free (result);
+}
+
+int main ()
+{
+#define TEST(s,e) test (__LINE__, s, e)
+
+ TEST ("a", "a");
+ TEST ("a\\b", "ab");
+
+ TEST ("{0}" , "{0}");
+ TEST ("\\{0}", "{0}");
+ TEST ("{\\0}", "{0}");
+ TEST ("{0\\}", "{0}");
+
+ TEST ("{0..1}", "0 1");
+ TEST ("\\{0..1}", "{0..1}");
+ TEST ("{\\0..1}", "{0..1}");
+ TEST ("{0\\..1}", "{0..1}");
+ TEST ("{0..\\1}", "{0..1}");
+ TEST ("{0..1\\}", "{0..1}");
+
+ TEST ("a{0}", "a{0}");
+ TEST ("a{0}b", "a{0}b");
+ TEST ("a\\{0\\}b", "a{0}b");
+ TEST ("a\\{0,123,4\\}b", "a{0,123,4}b");
+
+ TEST ("{0..a}", "{0..a}");
+ TEST ("{a..0}", "{a..0}");
+
+ TEST ("{0..0}", "0");
+ TEST ("{0..5}", "0 1 2 3 4 5");
+ TEST ("{4..2}", "4 3 2");
+ TEST ("{a..g}", "a b c d e f g");
+ TEST ("{g..c}", "g f e d c");
+ TEST ("{A..G}", "A B C D E F G");
+ TEST ("{G..C}", "G F E D C");
+
+ TEST ("{,}", "");
+ TEST ("{abc,def}", "abc def");
+ TEST ("{ab\\c,d\\ef}", "abc def");
+ TEST ("abc{d,e,f}", "abcd abce abcf");
+
+ TEST ("z{c,a{d..f}a,c}z", "zcz zadaz zaeaz zafaz zcz");
+ TEST ("z{c,a{d,e,f}a,c}z", "zcz zadaz zaeaz zafaz zcz");
+
+ TEST ("{abc,{,d,e,f,}}", "abc d e f");
+ TEST ("{abc,{,d,e,f,}}{x,y}", "abcx abcy x y dx dy ex ey fx fy x y");
+ TEST ("{abc,{,d\\,e\\,f,}}", "abc d,e,f");
+
+ TEST ("A{0..3}", "A0 A1 A2 A3");
+ TEST ("A{0..2}{6..7}", "A06 A07 A16 A17 A26 A27");
+ TEST ("A{A}{0..3}", "A{A}{0..3}");
+ TEST ("A{0..3}{A}", "A0{A} A1{A} A2{A} A3{A}");
+
+ TEST ("A{0,{4..7}{,}}", "A0 A4 A4 A5 A5 A6 A6 A7 A7");
+ TEST ("a{1,3,x{5..9}y}b", "a1b a3b ax5yb ax6yb ax7yb ax8yb ax9yb");
+ TEST ("{en,es}_{US,MX}.*", "en_US.* en_MX.* es_US.* es_MX.*");
+
+ // return 0 on success, 1 on failure
+ return !(0 == nerrors);
+}
Propchange: stdcxx/trunk/tests/self/0.braceexp.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: stdcxx/trunk/tests/self/0.braceexp.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Modified: stdcxx/trunk/tests/src/braceexp.cpp
URL: http://svn.apache.org/viewvc/stdcxx/trunk/tests/src/braceexp.cpp?rev=628817&r1=628816&r2=628817&view=diff
==============================================================================
--- stdcxx/trunk/tests/src/braceexp.cpp (original)
+++ stdcxx/trunk/tests/src/braceexp.cpp Mon Feb 18 09:09:00 2008
@@ -1,717 +1,717 @@
-#include <stdlib.h>
-#include <string.h>
-
-
-static int _rw_is_digit (int ch)
-{
- return !(ch < '0' || '9' < ch);
-}
-
-static int _rw_is_lower (int ch)
-{
- return !(ch < 'a' || 'z' < ch);
-}
-
-static int _rw_is_upper (int ch)
-{
- return !(ch < 'A' || 'Z' < ch);
-}
-
-// search `beg' to `end' for the next unescaped open brace . if `end'
-// is 0 then the search will terminate at the end of string. returns 0
-// on failure.
-static const char* _rw_find_open_brace (const char* beg,
- const char* end)
-{
- bool is_escaped = false;
-
- for (/**/; *beg; ++beg)
- {
- if (end && !(beg < end))
- break;
-
- const bool is_match = (*beg == '{');
- if (!is_escaped && is_match) {
- return beg;
- }
-
- is_escaped = !is_escaped && (*beg == '\\');
- }
-
- return 0;
-}
-
-// search `beg' to `end' for the next close brace at the current brace
-// depth. if `end' is 0, the search will continue until a match or end
-// of string. returns 0 on failure.
-static const char* _rw_find_close_brace (const char* beg,
- const char* end)
-{
- bool is_escaped = false;
-
- // nested brace depth
- for (int depth = 1; *beg; ++beg)
- {
- if (end && !(beg < end))
- break;
-
- const bool is_open_brace = (*beg == '{');
- if (!is_escaped && is_open_brace) {
- ++depth;
- }
-
- const bool is_close_brace = (*beg == '}');
- if (!is_escaped && is_close_brace) {
- --depth;
- }
-
- is_escaped = !is_escaped && (*beg == '\\');
-
- if (depth == 0)
- return beg;
- }
-
- return 0;
-}
-
-// search `beg' to `end' for the next unescaped comma at the current
-// brace depth. if `end' is 0, the search will continue until a match
-// or end of string. returns 0 on failure.
-static const char* _rw_find_next_comma (const char* beg,
- const char* end)
-{
- bool is_escaped = false;
-
- // nested brace depth
- for (int depth = 0; *beg; ++beg)
- {
- if (end && !(beg < end))
- break;
-
- const bool is_open_brace = (*beg == '{');
- if (!is_escaped && is_open_brace) {
- ++depth;
- }
-
- const bool is_close_brace = (*beg == '}');
- if (!is_escaped && is_close_brace) {
- --depth;
- }
-
- const bool is_comma = (*beg == ',');
- if (!is_escaped && is_comma) {
- if (depth == 0)
- return beg;
- }
-
- is_escaped = !is_escaped && (*beg == '\\');
- }
-
- return 0;
-}
-
-
-
-// this is where most of the work is done.
-struct _rw_brace_graph
-{
- //
- _rw_brace_graph ();
-
- //
- ~_rw_brace_graph ();
-
- // expand `brace_expr' into `len' bytes of `buf'. if it won't fit, we
- // allocate a buffer with malloc() and return that. so the user needs
- // to free() the return buffer if it is not equal to `buf'.
- char* _C_build_and_expand (const char* brace_expr,
- char* buf, int len, int sep);
-
-private:
-
- // node for a directed-acyclic-graph that we build from the original
- // brace expression
- struct _rw_brace_node
- {
- const char* str_;
- int len_;
-
- _rw_brace_node* sibling_;
- _rw_brace_node* child_;
- };
-
- // retrieve a new node. nodes are allocated in large blocks. those
- // blocks are deallocated when this graph instance is destroyed.
- _rw_brace_node* _C_get_new_node ();
-
- // this function generates a dag from an arbitrary brace expression.
- // the format is `prefix{body}suffix'. prefix, and suffix can both
- // be the empty string. body may be a comma seperated list of tokens,
- // a range of tokens, or arbitrary literal text. escapes on commas
- // and braces are ignored, and left intact otherwise.
- _rw_brace_node* _C_build_anything (const char* beg, const char* end);
-
- // generates a dag from an arbitrary range brace expression. the
- // format is `{?..?}suffix' where both ? are alphanumeric digits
- // of the same character class.
- _rw_brace_node* _C_build_range (const char* beg, const char* end);
-
- // generates a dag from an arbitrary list brace expression. the
- // format is `{a,b[,c]}suffix', where `a', `b' and `c' are full
- // brace expansions that would be processed by _C_build_anything.
- _rw_brace_node* _C_build_list (const char* beg, const char* end);
-
- // generates a dag from literal text. no brace expansion is done
- // on the literal text.
- _rw_brace_node* _C_build_literal (const char* beg, const char* end);
-
- // the number of nodes held by each brace buffer [see below]
- enum { _C_size = 64 };
-
- // buffer to avoid many small allocations
- struct _rw_brace_buffer
- {
- _rw_brace_node nodes_ [_C_size];
- _rw_brace_buffer* next_;
- };
-
- // the initial set of nodes is preallocated as part of this graph
- // object instance. additional blocks of nodes will be allocated
- // as is necessary by the _C_get_new_node() member.
- _rw_brace_buffer node_cache_;
-
- int used_; // number of nodes used in the last buffer
- _rw_brace_buffer* nodes_; // pointer to last allocated node buffer
-
- // code for generating the string
-
- bool _C_append (const char* beg, int n);
-
- char* user_buf_; // this is the buffer
- char* string_buf_;
- int string_cap_;
- int string_len_;
-
- // we use this to walk the stack. we need to walk from the root
- // of the tree to each leaf. when we reach a leaf, we need a way
- // to see the path that we took to get where we are. we use this
- // path to write out each part of the full expansion.
- struct _rw_recursion_context
- {
- _rw_recursion_context (_rw_brace_node* node)
- : parent_ (0), node_ (node)
- {
- }
-
- _rw_recursion_context (_rw_recursion_context* parent)
- : parent_ (parent), node_ (parent->node_->child_)
- {
- }
-
- _rw_recursion_context* parent_;
- _rw_brace_node* node_;
- };
-
- // this function walks the dag, leaving a trail of context
- // objects so we can walk back to the root and write the data
- // at each level in the graph.
- bool _C_brace_expand (_rw_recursion_context* self, char sep);
-
- // this function writes the data at each level of the dag
- // to our internal buffer.
- bool _C_brace_expand_write (_rw_recursion_context* context);
-};
-
-_rw_brace_graph::_rw_brace_graph ()
- : used_ (0)
- , nodes_ (&node_cache_)
- , user_buf_ (0)
- , string_buf_ (0)
- , string_cap_ (0)
- , string_len_ (0)
-{
- node_cache_.next_ = 0;
-}
-
-_rw_brace_graph::~_rw_brace_graph ()
-{
- _rw_brace_buffer* nodes = node_cache_.next_;
- while (nodes)
- {
- _rw_brace_buffer* next = nodes->next_;
- nodes->next_ = 0;
-
- // deallocate this buffer
- free (nodes);
-
- // setup to deallocate next one
- nodes = next;
- }
-}
-
-
-
-char*
-_rw_brace_graph::_C_build_and_expand (const char* brace_expr,
- char* buf, int len, int sep)
-{
- const int brace_expr_len = strlen (brace_expr);
-
- _rw_brace_node* root = _C_build_anything (brace_expr,
- brace_expr + brace_expr_len);
- if (!root)
- return 0;
-
- // setup for the expansion
- user_buf_ = buf;
- string_buf_ = buf;
- string_cap_ = len;
- string_len_ = 0;
-
- // this helps us do the building of the output string
- _rw_recursion_context context (root);
-
- if (!_C_brace_expand (&context, sep))
- {
- if (string_buf_ != user_buf_)
- free (string_buf_);
- string_buf_ = 0;
- }
-
- // kill the last seperator with a null terminator
- else if (string_buf_)
- {
- const int pos = string_len_ < 1 ? 0 : string_len_ - 1;
- string_buf_ [pos] = '\0';
- }
-
- return string_buf_;
-}
-
-_rw_brace_graph::_rw_brace_node*
-_rw_brace_graph::_C_get_new_node ()
-{
- used_ += 1;
-
- // if we run out of space, grab a new block
- if (! (used_ < _C_size))
- {
- nodes_->next_
- = (_rw_brace_buffer*)malloc (sizeof (_rw_brace_buffer));
- if (!nodes_->next_)
- return 0;
-
- nodes_ = nodes_->next_;
- nodes_->next_ = 0;
-
- used_ -= _C_size;
- }
-
- _rw_brace_node* node = &nodes_->nodes_ [used_ - 1];
- node->str_ = 0;
- node->len_ = 0;
- node->sibling_ = 0;
- node->child_ = 0;
-
- return node;
-}
-
-_rw_brace_graph::_rw_brace_node*
-_rw_brace_graph::_C_build_anything (const char* beg, const char* end)
-{
- //
- const char* open_brace = _rw_find_open_brace (beg, end);
- if (open_brace)
- {
- // build a node for the prefix if there is one
- _rw_brace_node* prefix = _C_get_new_node ();
- prefix->str_ = beg;
- prefix->len_ = (open_brace - beg);
-
- // try to build a range expansion
- _rw_brace_node* child = 0;
-
- child = _C_build_range (open_brace, end);
- if (!child) {
-
- // try to do a list expansion
- child = _C_build_list (open_brace, end);
- if (!child) {
-
- // try to do a literal expansion
- child = _C_build_literal (open_brace, end);
- if (!child) {
- return 0;
- }
- }
- }
-
- // we must have a valid child pointer at this point
- prefix->child_ = child;
-
- return prefix;
- }
-
- // there was no open brace, so the entire text from beg to end
- // is a literal
- _rw_brace_node* prefix = _C_get_new_node ();
- if (!prefix)
- return 0;
-
- prefix->str_ = beg;
- prefix->len_ = (end - beg);
-
- return prefix;
-}
-
-_rw_brace_graph::_rw_brace_node*
-_rw_brace_graph::_C_build_literal (const char* beg, const char* end)
-{
- _rw_brace_node* prefix = _C_get_new_node ();
- if (!prefix)
- return 0;
-
- prefix->str_ = beg;
- prefix->len_ = (end - beg);
-
- return prefix;
-}
-
-_rw_brace_graph::_rw_brace_node*
-_rw_brace_graph::_C_build_range (const char* beg, const char* end)
-{
- // check for {a..z} type range expression. make sure not to
- // reference past the end of the string.
- if ( beg [0] != '{'
- || beg [1] == '\0'
- || beg [2] != '.'
- || beg [3] != '.'
- || beg [4] == '\0'
- || beg [5] != '}')
- return 0;
-
- // grab characters that represent the start and end of the range
- char cbeg = beg [1];
- char cend = beg [4];
-
- // only works if range characters are both digit, lower or upper.
- const int both_are_digit = _rw_is_digit (cbeg) && _rw_is_digit (cend);
- const int both_are_lower = _rw_is_lower (cbeg) && _rw_is_lower (cend);
- const int both_are_upper = _rw_is_upper (cbeg) && _rw_is_upper (cend);
-
- if (! (both_are_digit || both_are_lower || both_are_upper))
- return false;
-
- // these must live for duration of program
- static const char* table [] =
- {
- "0123456789", // 0
- "abcdefghijklmnopqrstuvwxyz", // 1
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ", // 2
- };
-
- const int idx = (both_are_lower << 0) +
- (both_are_upper << 1);
-
- const int dir = (cbeg < cend) ? 1 : -1;
-
- // build the suffix
- _rw_brace_node* suffix = _C_build_anything (beg + 6, end);
- if (!suffix)
- return false; // failed to parse suffix
-
- _rw_brace_node* first_child = 0;
- _rw_brace_node* final_child = 0;
-
- // build a list of children, associate each with suffix
- for (/**/; cbeg != cend; cbeg += dir) {
-
- // create a child from whatever is between beg and end. that childs
- // next pointer will be the suffix we created above.
- _rw_brace_node* child = _C_get_new_node ();
- if (!child) {
- return false;
- }
-
- // this finds beg in our array, we could have used strchr
- child->str_ = table [idx] + (cbeg - table [idx][0]);
- child->len_ = 1;
-
- // track children we have created
- if (!first_child)
- first_child = child;
-
- if (final_child)
- final_child->sibling_ = child;
- final_child = child;
-
- // suffix is the suffix of the child expression
- while (child->child_)
- child = child->child_;
- child->child_ = suffix;
- }
-
- // create the last node in the range.
- _rw_brace_node* child = _C_get_new_node ();
- if (!child) {
- return false;
- }
-
- child->str_ = table [idx] + (cbeg - table [idx][0]);
- child->len_ = 1;
-
- // trach child
- if (!first_child)
- first_child = child;
-
- if (final_child)
- final_child->sibling_ = child;
- final_child = child;
-
- // suffix is the suffix of the child expression
- while (child->child_)
- child = child->child_;
- child->child_ = suffix;
-
- return first_child;
-}
-
-_rw_brace_graph::_rw_brace_node*
-_rw_brace_graph::_C_build_list (const char* beg, const char* end)
-{
- //
- // {abc,d{1..3}e}f
- // ^ ^
- //
- // prefix ''
- // suffix 'f'
- // middle '{abc,d{1..3}e}'
-
- // generate node for prefix [which is a literal, and is handled by the caller
- // generate node for the suffix [which is anything]
-
- // generate list of nodes for the middle [each of which are anything]
- // set the next pointer of each to the suffix, and set next pointer
- // of the prefix to the first list item.
-
- // d{1..3}e{1..3}
- //
- // root -> d -> 1 -> e -> 1 -> EMPTY
- // 2 // 2 //
- // 3 / 3 /
-
- // {1..3}{4..6} 14 15 16 24 25 26 34 35 36
- //
- // root -> 1 -> 4
- // 2 // 5
- // 3 / 6
-
- // we really expect that the first token is an open paren the
- // caller should have consumed the prefix before calling this
- if (*beg++ != '{')
- return false;
-
- // now fill in the middle, each child we create directly will
- // have a child pointer to the suffix node
-
- // all of the nodes in the list are children of `parent'. the
- // graph from nodes after the list are
- const char* mid = _rw_find_next_comma (beg, end);
- if (!mid)
- return false; // no comma, then no list
-
- // find the end of th list expression
- const char* eol = _rw_find_close_brace (mid, end);
- if (!eol)
- return false; // no list terminator
-
- // build a node for the suffix.
- _rw_brace_node* suffix = _C_build_anything (eol+1, end);
- if (!suffix)
- return false; // failed to parse end
-
- _rw_brace_node* first_child = 0;
- _rw_brace_node* final_child = 0;
-
- while (mid) {
-
- // create a child from whatever is between beg and end. that childs
- // next pointer will be the suffix we created above.
- _rw_brace_node* child = _C_build_anything (beg, mid);
- if (!child) {
- return false;
- }
-
- if (!first_child)
- first_child = child;
-
- // append new child to end of chain
- if (final_child)
- final_child->sibling_ = child;
- final_child = child;
-
- // the nex pointer for this child is the suffix
-
- // suffix is the suffix of the child expression
- while (child->child_)
- child = child->child_;
- child->child_ = suffix;
-
- beg = mid + 1;
- mid = _rw_find_next_comma (beg, eol);
- }
-
- // okay, we have a pointer to the last comma in the list. create an
- // item for the data between the comma and the list terminator
-
- // '{abc,d{1..3}e}a'
- // ^ ^ ^
- // beg eol end
-
- // build nodes from the last entry in the list
- _rw_brace_node* child = _C_build_anything (beg, eol);
- if (!child) {
- return false;
- }
-
- // append last child to end of chain
- final_child->sibling_ = child;
- final_child = child;
-
- // suffix is the suffix of the child expression
- while (child->child_)
- child = child->child_;
- child->child_ = suffix;
-
- // success, return first child in this expansion
- return first_child;
-}
-
-bool _rw_brace_graph::_C_append (const char* s, int n)
-{
- const int new_len = string_len_ + n;
-
- // not enough space, grow buf
- if (! (new_len < string_cap_)) {
-
- // buf grows in 256 byte blocks
- int new_cap = string_cap_;
- while (! (new_len < new_cap))
- new_cap += 256;
-
- char* new_buf = (char*)malloc (new_cap);
- if (!new_buf)
- return false;
-
- // copy the old data
- memcpy (new_buf, string_buf_, string_len_);
-
- // copy the new data
- memcpy (new_buf + string_len_, s, n);
- new_buf [new_len] = '\0';
-
- // don't free until after append because `s' may
- // be in string_buf_
- if (string_buf_ != user_buf_)
- free (string_buf_);
-
- string_cap_ = new_cap;
- string_len_ = new_len;
- string_buf_ = new_buf;
- }
-
- // just copy the data
- else {
- memcpy (string_buf_ + string_len_, s, n);
- string_buf_ [new_len] = '\0';
-
- string_len_ = new_len;
- }
-
- return true;
-}
-
-
-bool _rw_brace_graph::_C_brace_expand_write (_rw_recursion_context* context)
-{
- if (context->parent_) {
- if (!_C_brace_expand_write (context->parent_))
- return false;
- }
-
- // write the data at this level
- //return _C_append (context->node_->str_, context->node_->len_);
-
- bool is_escaped = false;
-
- const char* beg = context->node_->str_;
- for (int n = 0; n < context->node_->len_; ++n, ++beg) {
-
- is_escaped = !is_escaped && (*beg == '\\');
- if (!is_escaped) {
- if (!_C_append (beg, 1))
- return false;
- }
- }
-
- return true;
-}
-
-bool _rw_brace_graph::_C_brace_expand (_rw_recursion_context* self, char sep)
-{
- // if this node has no children or siblings, we have found a full
- // expansion.
- if (!self->node_ ||
- !self->node_->sibling_ && !self->node_->child_) {
-
- const int length_before = string_len_;
-
- // use recursion again to walk back to the root the graph and
- // write each contexts data as we unwind back toward the leaf
- if (!_C_brace_expand_write (self))
- return false;
-
- const int length_after = string_len_;
-
- // don't write a seperator if we wrote no data
- if (length_before != length_after && !_C_append (&sep, 1))
- return false;
-
- return true;
- }
-
- // iterate through all of the children of the node, thus finding all
- // other combinations
- _rw_recursion_context context (self);
- while (context.node_) {
-
- if (!_C_brace_expand (&context, sep))
- return false;
-
- context.node_ = context.node_->sibling_;
- }
-
- return true;
-}
-
-//
-// returns 0 if brace_expr is not a valid brace expression, else a
-// pointer to the buf that stores the expanded expression. if the
-// returned value is not the same pointer as the input parameter
-// expanded, then the user must deallocate the pointer with a call
-// to free().
-char* rw_brace_expand (const char* brace_expr, char* s, int n, int sep)
-{
- if (!brace_expr)
- return 0;
-
- _rw_brace_graph graph;
-
- // build the graph, and then expand it into buf
- char* buf = graph._C_build_and_expand (brace_expr, s, n, sep);
- if (!buf)
- return 0;
-
- return buf;
-}
-
+#include <stdlib.h>
+#include <string.h>
+
+
+static int _rw_is_digit (int ch)
+{
+ return !(ch < '0' || '9' < ch);
+}
+
+static int _rw_is_lower (int ch)
+{
+ return !(ch < 'a' || 'z' < ch);
+}
+
+static int _rw_is_upper (int ch)
+{
+ return !(ch < 'A' || 'Z' < ch);
+}
+
+// search `beg' to `end' for the next unescaped open brace . if `end'
+// is 0 then the search will terminate at the end of string. returns 0
+// on failure.
+static const char* _rw_find_open_brace (const char* beg,
+ const char* end)
+{
+ bool is_escaped = false;
+
+ for (/**/; *beg; ++beg)
+ {
+ if (end && !(beg < end))
+ break;
+
+ const bool is_match = (*beg == '{');
+ if (!is_escaped && is_match) {
+ return beg;
+ }
+
+ is_escaped = !is_escaped && (*beg == '\\');
+ }
+
+ return 0;
+}
+
+// search `beg' to `end' for the next close brace at the current brace
+// depth. if `end' is 0, the search will continue until a match or end
+// of string. returns 0 on failure.
+static const char* _rw_find_close_brace (const char* beg,
+ const char* end)
+{
+ bool is_escaped = false;
+
+ // nested brace depth
+ for (int depth = 1; *beg; ++beg)
+ {
+ if (end && !(beg < end))
+ break;
+
+ const bool is_open_brace = (*beg == '{');
+ if (!is_escaped && is_open_brace) {
+ ++depth;
+ }
+
+ const bool is_close_brace = (*beg == '}');
+ if (!is_escaped && is_close_brace) {
+ --depth;
+ }
+
+ is_escaped = !is_escaped && (*beg == '\\');
+
+ if (depth == 0)
+ return beg;
+ }
+
+ return 0;
+}
+
+// search `beg' to `end' for the next unescaped comma at the current
+// brace depth. if `end' is 0, the search will continue until a match
+// or end of string. returns 0 on failure.
+static const char* _rw_find_next_comma (const char* beg,
+ const char* end)
+{
+ bool is_escaped = false;
+
+ // nested brace depth
+ for (int depth = 0; *beg; ++beg)
+ {
+ if (end && !(beg < end))
+ break;
+
+ const bool is_open_brace = (*beg == '{');
+ if (!is_escaped && is_open_brace) {
+ ++depth;
+ }
+
+ const bool is_close_brace = (*beg == '}');
+ if (!is_escaped && is_close_brace) {
+ --depth;
+ }
+
+ const bool is_comma = (*beg == ',');
+ if (!is_escaped && is_comma) {
+ if (depth == 0)
+ return beg;
+ }
+
+ is_escaped = !is_escaped && (*beg == '\\');
+ }
+
+ return 0;
+}
+
+
+
+// this is where most of the work is done.
+struct _rw_brace_graph
+{
+ //
+ _rw_brace_graph ();
+
+ //
+ ~_rw_brace_graph ();
+
+ // expand `brace_expr' into `len' bytes of `buf'. if it won't fit, we
+ // allocate a buffer with malloc() and return that. so the user needs
+ // to free() the return buffer if it is not equal to `buf'.
+ char* _C_build_and_expand (const char* brace_expr,
+ char* buf, int len, int sep);
+
+private:
+
+ // node for a directed-acyclic-graph that we build from the original
+ // brace expression
+ struct _rw_brace_node
+ {
+ const char* str_;
+ int len_;
+
+ _rw_brace_node* sibling_;
+ _rw_brace_node* child_;
+ };
+
+ // retrieve a new node. nodes are allocated in large blocks. those
+ // blocks are deallocated when this graph instance is destroyed.
+ _rw_brace_node* _C_get_new_node ();
+
+ // this function generates a dag from an arbitrary brace expression.
+ // the format is `prefix{body}suffix'. prefix, and suffix can both
+ // be the empty string. body may be a comma seperated list of tokens,
+ // a range of tokens, or arbitrary literal text. escapes on commas
+ // and braces are ignored, and left intact otherwise.
+ _rw_brace_node* _C_build_anything (const char* beg, const char* end);
+
+ // generates a dag from an arbitrary range brace expression. the
+ // format is `{?..?}suffix' where both ? are alphanumeric digits
+ // of the same character class.
+ _rw_brace_node* _C_build_range (const char* beg, const char* end);
+
+ // generates a dag from an arbitrary list brace expression. the
+ // format is `{a,b[,c]}suffix', where `a', `b' and `c' are full
+ // brace expansions that would be processed by _C_build_anything.
+ _rw_brace_node* _C_build_list (const char* beg, const char* end);
+
+ // generates a dag from literal text. no brace expansion is done
+ // on the literal text.
+ _rw_brace_node* _C_build_literal (const char* beg, const char* end);
+
+ // the number of nodes held by each brace buffer [see below]
+ enum { _C_size = 64 };
+
+ // buffer to avoid many small allocations
+ struct _rw_brace_buffer
+ {
+ _rw_brace_node nodes_ [_C_size];
+ _rw_brace_buffer* next_;
+ };
+
+ // the initial set of nodes is preallocated as part of this graph
+ // object instance. additional blocks of nodes will be allocated
+ // as is necessary by the _C_get_new_node() member.
+ _rw_brace_buffer node_cache_;
+
+ int used_; // number of nodes used in the last buffer
+ _rw_brace_buffer* nodes_; // pointer to last allocated node buffer
+
+ // code for generating the string
+
+ bool _C_append (const char* beg, int n);
+
+ char* user_buf_; // this is the buffer
+ char* string_buf_;
+ int string_cap_;
+ int string_len_;
+
+ // we use this to walk the stack. we need to walk from the root
+ // of the tree to each leaf. when we reach a leaf, we need a way
+ // to see the path that we took to get where we are. we use this
+ // path to write out each part of the full expansion.
+ struct _rw_recursion_context
+ {
+ _rw_recursion_context (_rw_brace_node* node)
+ : parent_ (0), node_ (node)
+ {
+ }
+
+ _rw_recursion_context (_rw_recursion_context* parent)
+ : parent_ (parent), node_ (parent->node_->child_)
+ {
+ }
+
+ _rw_recursion_context* parent_;
+ _rw_brace_node* node_;
+ };
+
+ // this function walks the dag, leaving a trail of context
+ // objects so we can walk back to the root and write the data
+ // at each level in the graph.
+ bool _C_brace_expand (_rw_recursion_context* self, char sep);
+
+ // this function writes the data at each level of the dag
+ // to our internal buffer.
+ bool _C_brace_expand_write (_rw_recursion_context* context);
+};
+
+_rw_brace_graph::_rw_brace_graph ()
+ : used_ (0)
+ , nodes_ (&node_cache_)
+ , user_buf_ (0)
+ , string_buf_ (0)
+ , string_cap_ (0)
+ , string_len_ (0)
+{
+ node_cache_.next_ = 0;
+}
+
+_rw_brace_graph::~_rw_brace_graph ()
+{
+ _rw_brace_buffer* nodes = node_cache_.next_;
+ while (nodes)
+ {
+ _rw_brace_buffer* next = nodes->next_;
+ nodes->next_ = 0;
+
+ // deallocate this buffer
+ free (nodes);
+
+ // setup to deallocate next one
+ nodes = next;
+ }
+}
+
+
+
+char*
+_rw_brace_graph::_C_build_and_expand (const char* brace_expr,
+ char* buf, int len, int sep)
+{
+ const int brace_expr_len = strlen (brace_expr);
+
+ _rw_brace_node* root = _C_build_anything (brace_expr,
+ brace_expr + brace_expr_len);
+ if (!root)
+ return 0;
+
+ // setup for the expansion
+ user_buf_ = buf;
+ string_buf_ = buf;
+ string_cap_ = len;
+ string_len_ = 0;
+
+ // this helps us do the building of the output string
+ _rw_recursion_context context (root);
+
+ if (!_C_brace_expand (&context, sep))
+ {
+ if (string_buf_ != user_buf_)
+ free (string_buf_);
+ string_buf_ = 0;
+ }
+
+ // kill the last seperator with a null terminator
+ else if (string_buf_)
+ {
+ const int pos = string_len_ < 1 ? 0 : string_len_ - 1;
+ string_buf_ [pos] = '\0';
+ }
+
+ return string_buf_;
+}
+
+_rw_brace_graph::_rw_brace_node*
+_rw_brace_graph::_C_get_new_node ()
+{
+ used_ += 1;
+
+ // if we run out of space, grab a new block
+ if (! (used_ < _C_size))
+ {
+ nodes_->next_
+ = (_rw_brace_buffer*)malloc (sizeof (_rw_brace_buffer));
+ if (!nodes_->next_)
+ return 0;
+
+ nodes_ = nodes_->next_;
+ nodes_->next_ = 0;
+
+ used_ -= _C_size;
+ }
+
+ _rw_brace_node* node = &nodes_->nodes_ [used_ - 1];
+ node->str_ = 0;
+ node->len_ = 0;
+ node->sibling_ = 0;
+ node->child_ = 0;
+
+ return node;
+}
+
+_rw_brace_graph::_rw_brace_node*
+_rw_brace_graph::_C_build_anything (const char* beg, const char* end)
+{
+ //
+ const char* open_brace = _rw_find_open_brace (beg, end);
+ if (open_brace)
+ {
+ // build a node for the prefix if there is one
+ _rw_brace_node* prefix = _C_get_new_node ();
+ prefix->str_ = beg;
+ prefix->len_ = (open_brace - beg);
+
+ // try to build a range expansion
+ _rw_brace_node* child = 0;
+
+ child = _C_build_range (open_brace, end);
+ if (!child) {
+
+ // try to do a list expansion
+ child = _C_build_list (open_brace, end);
+ if (!child) {
+
+ // try to do a literal expansion
+ child = _C_build_literal (open_brace, end);
+ if (!child) {
+ return 0;
+ }
+ }
+ }
+
+ // we must have a valid child pointer at this point
+ prefix->child_ = child;
+
+ return prefix;
+ }
+
+ // there was no open brace, so the entire text from beg to end
+ // is a literal
+ _rw_brace_node* prefix = _C_get_new_node ();
+ if (!prefix)
+ return 0;
+
+ prefix->str_ = beg;
+ prefix->len_ = (end - beg);
+
+ return prefix;
+}
+
+_rw_brace_graph::_rw_brace_node*
+_rw_brace_graph::_C_build_literal (const char* beg, const char* end)
+{
+ _rw_brace_node* prefix = _C_get_new_node ();
+ if (!prefix)
+ return 0;
+
+ prefix->str_ = beg;
+ prefix->len_ = (end - beg);
+
+ return prefix;
+}
+
+_rw_brace_graph::_rw_brace_node*
+_rw_brace_graph::_C_build_range (const char* beg, const char* end)
+{
+ // check for {a..z} type range expression. make sure not to
+ // reference past the end of the string.
+ if ( beg [0] != '{'
+ || beg [1] == '\0'
+ || beg [2] != '.'
+ || beg [3] != '.'
+ || beg [4] == '\0'
+ || beg [5] != '}')
+ return 0;
+
+ // grab characters that represent the start and end of the range
+ char cbeg = beg [1];
+ char cend = beg [4];
+
+ // only works if range characters are both digit, lower or upper.
+ const int both_are_digit = _rw_is_digit (cbeg) && _rw_is_digit (cend);
+ const int both_are_lower = _rw_is_lower (cbeg) && _rw_is_lower (cend);
+ const int both_are_upper = _rw_is_upper (cbeg) && _rw_is_upper (cend);
+
+ if (! (both_are_digit || both_are_lower || both_are_upper))
+ return false;
+
+ // these must live for duration of program
+ static const char* table [] =
+ {
+ "0123456789", // 0
+ "abcdefghijklmnopqrstuvwxyz", // 1
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", // 2
+ };
+
+ const int idx = (both_are_lower << 0) +
+ (both_are_upper << 1);
+
+ const int dir = (cbeg < cend) ? 1 : -1;
+
+ // build the suffix
+ _rw_brace_node* suffix = _C_build_anything (beg + 6, end);
+ if (!suffix)
+ return false; // failed to parse suffix
+
+ _rw_brace_node* first_child = 0;
+ _rw_brace_node* final_child = 0;
+
+ // build a list of children, associate each with suffix
+ for (/**/; cbeg != cend; cbeg += dir) {
+
+ // create a child from whatever is between beg and end. that childs
+ // next pointer will be the suffix we created above.
+ _rw_brace_node* child = _C_get_new_node ();
+ if (!child) {
+ return false;
+ }
+
+ // this finds beg in our array, we could have used strchr
+ child->str_ = table [idx] + (cbeg - table [idx][0]);
+ child->len_ = 1;
+
+ // track children we have created
+ if (!first_child)
+ first_child = child;
+
+ if (final_child)
+ final_child->sibling_ = child;
+ final_child = child;
+
+ // suffix is the suffix of the child expression
+ while (child->child_)
+ child = child->child_;
+ child->child_ = suffix;
+ }
+
+ // create the last node in the range.
+ _rw_brace_node* child = _C_get_new_node ();
+ if (!child) {
+ return false;
+ }
+
+ child->str_ = table [idx] + (cbeg - table [idx][0]);
+ child->len_ = 1;
+
+ // trach child
+ if (!first_child)
+ first_child = child;
+
+ if (final_child)
+ final_child->sibling_ = child;
+ final_child = child;
+
+ // suffix is the suffix of the child expression
+ while (child->child_)
+ child = child->child_;
+ child->child_ = suffix;
+
+ return first_child;
+}
+
+_rw_brace_graph::_rw_brace_node*
+_rw_brace_graph::_C_build_list (const char* beg, const char* end)
+{
+ //
+ // {abc,d{1..3}e}f
+ // ^ ^
+ //
+ // prefix ''
+ // suffix 'f'
+ // middle '{abc,d{1..3}e}'
+
+ // generate node for prefix [which is a literal, and is handled by the caller
+ // generate node for the suffix [which is anything]
+
+ // generate list of nodes for the middle [each of which are anything]
+ // set the next pointer of each to the suffix, and set next pointer
+ // of the prefix to the first list item.
+
+ // d{1..3}e{1..3}
+ //
+ // root -> d -> 1 -> e -> 1 -> EMPTY
+ // 2 // 2 //
+ // 3 / 3 /
+
+ // {1..3}{4..6} 14 15 16 24 25 26 34 35 36
+ //
+ // root -> 1 -> 4
+ // 2 // 5
+ // 3 / 6
+
+ // we really expect that the first token is an open paren the
+ // caller should have consumed the prefix before calling this
+ if (*beg++ != '{')
+ return false;
+
+ // now fill in the middle, each child we create directly will
+ // have a child pointer to the suffix node
+
+ // all of the nodes in the list are children of `parent'. the
+ // graph from nodes after the list are
+ const char* mid = _rw_find_next_comma (beg, end);
+ if (!mid)
+ return false; // no comma, then no list
+
+ // find the end of th list expression
+ const char* eol = _rw_find_close_brace (mid, end);
+ if (!eol)
+ return false; // no list terminator
+
+ // build a node for the suffix.
+ _rw_brace_node* suffix = _C_build_anything (eol+1, end);
+ if (!suffix)
+ return false; // failed to parse end
+
+ _rw_brace_node* first_child = 0;
+ _rw_brace_node* final_child = 0;
+
+ while (mid) {
+
+ // create a child from whatever is between beg and end. that childs
+ // next pointer will be the suffix we created above.
+ _rw_brace_node* child = _C_build_anything (beg, mid);
+ if (!child) {
+ return false;
+ }
+
+ if (!first_child)
+ first_child = child;
+
+ // append new child to end of chain
+ if (final_child)
+ final_child->sibling_ = child;
+ final_child = child;
+
+ // the nex pointer for this child is the suffix
+
+ // suffix is the suffix of the child expression
+ while (child->child_)
+ child = child->child_;
+ child->child_ = suffix;
+
+ beg = mid + 1;
+ mid = _rw_find_next_comma (beg, eol);
+ }
+
+ // okay, we have a pointer to the last comma in the list. create an
+ // item for the data between the comma and the list terminator
+
+ // '{abc,d{1..3}e}a'
+ // ^ ^ ^
+ // beg eol end
+
+ // build nodes from the last entry in the list
+ _rw_brace_node* child = _C_build_anything (beg, eol);
+ if (!child) {
+ return false;
+ }
+
+ // append last child to end of chain
+ final_child->sibling_ = child;
+ final_child = child;
+
+ // suffix is the suffix of the child expression
+ while (child->child_)
+ child = child->child_;
+ child->child_ = suffix;
+
+ // success, return first child in this expansion
+ return first_child;
+}
+
+bool _rw_brace_graph::_C_append (const char* s, int n)
+{
+ const int new_len = string_len_ + n;
+
+ // not enough space, grow buf
+ if (! (new_len < string_cap_)) {
+
+ // buf grows in 256 byte blocks
+ int new_cap = string_cap_;
+ while (! (new_len < new_cap))
+ new_cap += 256;
+
+ char* new_buf = (char*)malloc (new_cap);
+ if (!new_buf)
+ return false;
+
+ // copy the old data
+ memcpy (new_buf, string_buf_, string_len_);
+
+ // copy the new data
+ memcpy (new_buf + string_len_, s, n);
+ new_buf [new_len] = '\0';
+
+ // don't free until after append because `s' may
+ // be in string_buf_
+ if (string_buf_ != user_buf_)
+ free (string_buf_);
+
+ string_cap_ = new_cap;
+ string_len_ = new_len;
+ string_buf_ = new_buf;
+ }
+
+ // just copy the data
+ else {
+ memcpy (string_buf_ + string_len_, s, n);
+ string_buf_ [new_len] = '\0';
+
+ string_len_ = new_len;
+ }
+
+ return true;
+}
+
+
+bool _rw_brace_graph::_C_brace_expand_write (_rw_recursion_context* context)
+{
+ if (context->parent_) {
+ if (!_C_brace_expand_write (context->parent_))
+ return false;
+ }
+
+ // write the data at this level
+ //return _C_append (context->node_->str_, context->node_->len_);
+
+ bool is_escaped = false;
+
+ const char* beg = context->node_->str_;
+ for (int n = 0; n < context->node_->len_; ++n, ++beg) {
+
+ is_escaped = !is_escaped && (*beg == '\\');
+ if (!is_escaped) {
+ if (!_C_append (beg, 1))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool _rw_brace_graph::_C_brace_expand (_rw_recursion_context* self, char sep)
+{
+ // if this node has no children or siblings, we have found a full
+ // expansion.
+ if (!self->node_ ||
+ !self->node_->sibling_ && !self->node_->child_) {
+
+ const int length_before = string_len_;
+
+ // use recursion again to walk back to the root the graph and
+ // write each contexts data as we unwind back toward the leaf
+ if (!_C_brace_expand_write (self))
+ return false;
+
+ const int length_after = string_len_;
+
+ // don't write a seperator if we wrote no data
+ if (length_before != length_after && !_C_append (&sep, 1))
+ return false;
+
+ return true;
+ }
+
+ // iterate through all of the children of the node, thus finding all
+ // other combinations
+ _rw_recursion_context context (self);
+ while (context.node_) {
+
+ if (!_C_brace_expand (&context, sep))
+ return false;
+
+ context.node_ = context.node_->sibling_;
+ }
+
+ return true;
+}
+
+//
+// returns 0 if brace_expr is not a valid brace expression, else a
+// pointer to the buf that stores the expanded expression. if the
+// returned value is not the same pointer as the input parameter
+// expanded, then the user must deallocate the pointer with a call
+// to free().
+char* rw_brace_expand (const char* brace_expr, char* s, int n, int sep)
+{
+ if (!brace_expr)
+ return 0;
+
+ _rw_brace_graph graph;
+
+ // build the graph, and then expand it into buf
+ char* buf = graph._C_build_and_expand (brace_expr, s, n, sep);
+ if (!buf)
+ return 0;
+
+ return buf;
+}
+
Propchange: stdcxx/trunk/tests/src/braceexp.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: stdcxx/trunk/tests/src/braceexp.cpp
------------------------------------------------------------------------------
svn:keywords = Id