Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
braceexp.cpp
Go to the documentation of this file.
1
27// expand _TEST_EXPORT macros
28#define _RWSTD_TEST_SRC
29
30#include <stdlib.h> // for malloc(), free()
31#include <string.h> // for memcpy()
32#include <ctype.h> // for isspace()
33#include <assert.h> // for assert()
34
35#include <rw_braceexp.h>
36
37
38// for convenience
39typedef unsigned char UChar;
40
41
42// search `beg' to `end' for a character that `fn'
43// returns non-zero.
44static const char*
45_rw_find_match (const char* beg,
46 const char* end,
47 bool match_space)
48{
49 bool is_escaped = false;
50
51 for (; beg < end; ++beg) {
52
53 const bool is_space = 0 != isspace (UChar (*beg));
54
55 if (!is_escaped && match_space == is_space) {
56 return beg;
57 }
58
59 is_escaped = !is_escaped && (*beg == '\\');
60 }
61
62 return 0;
63}
64
65// similar to sprintf (buffer, "%ld", value), but the output
66// is not locale dependent. we choose not to use code from
67// the test harness because we may need to move this around.
68static int _rw_itoa_10 (char* buffer, long value)
69{
70 const bool neg = value < 0;
71
72 if (neg)
73 value = 0 - value;
74
75 // write it out in reverse
76 int n = 0;
77 do {
78
79 const long q = value / 10;
80 const long r = value - (q * 10);
81 value = q;
82
83 switch (r)
84 {
85 case 0: buffer [n] = '0'; break;
86 case 1: buffer [n] = '1'; break;
87 case 2: buffer [n] = '2'; break;
88 case 3: buffer [n] = '3'; break;
89 case 4: buffer [n] = '4'; break;
90 case 5: buffer [n] = '5'; break;
91 case 6: buffer [n] = '6'; break;
92 case 7: buffer [n] = '7'; break;
93 case 8: buffer [n] = '8'; break;
94 case 9: buffer [n] = '9'; break;
95 default: break;
96 }
97
98 n += 1;
99
100 } while (value != 0);
101
102 // write the sign
103 if (neg)
104 buffer [n++] = '-';
105
106 // then reverse it
107 for (int i = 0, j = n - 1; i < j; ++i, --j)
108 {
109 const char c = buffer [i];
110 buffer [i] = buffer [j];
111 buffer [j] = c;
112 }
113
114 return n;
115}
116
117
118// search `beg' to `end' for the next unescaped open brace . if `end'
119// is 0 then the search will terminate at the end of string. returns 0
120// on failure.
121//
122// this function ignores escaped braces and those that look like they
123// belong to a shell variable expansion. this is for consistency with
124// bash. i.e. there is no open brace in a\{b\}c or a${b}c.
125static const char* _rw_find_open_brace (const char* beg,
126 const char* end)
127{
128 bool is_escaped = false;
129 bool is_shelled = false;
130
131 for (; beg < end; ++beg) {
132
133 const bool is_match = (*beg == '{');
134 if (!is_escaped && !is_shelled && is_match) {
135 return beg;
136 }
137
138 is_shelled = !is_shelled && (*beg == '$');
139 is_escaped = !is_escaped && (*beg == '\\');
140 }
141
142 return 0;
143}
144
145// search `beg' to `end' for the next close brace at the current brace
146// depth. if `end' is 0, the search will continue until a match or end
147// of string. returns 0 on failure.
148static const char* _rw_find_close_brace (const char* beg,
149 const char* end)
150{
151 bool is_escaped = false;
152
153 // nested brace depth
154 for (int depth = 1; beg < end; ++beg) {
155
156 const bool is_open_brace = (*beg == '{');
157 if (!is_escaped && is_open_brace) {
158 ++depth;
159 }
160
161 const bool is_close_brace = (*beg == '}');
162 if (!is_escaped && is_close_brace) {
163 --depth;
164 }
165
166 is_escaped = !is_escaped && (*beg == '\\');
167
168 if (depth == 0)
169 return beg;
170 }
171
172 return 0;
173}
174
175// search `beg' to `end' for the next unescaped comma at the current
176// brace depth. if `end' is 0, the search will continue until a match
177// or end of string. returns 0 on failure.
178static const char* _rw_find_next_comma (const char* beg,
179 const char* end)
180{
181 bool is_escaped = false;
182
183 // nested brace depth
184 for (int depth = 0; beg < end; ++beg) {
185
186 const bool is_open_brace = (*beg == '{');
187 if (!is_escaped && is_open_brace) {
188 ++depth;
189 }
190
191 const bool is_close_brace = (*beg == '}');
192 if (!is_escaped && is_close_brace) {
193 --depth;
194 }
195
196 const bool is_comma = (*beg == ',');
197 if (!is_escaped && is_comma) {
198 if (depth == 0)
199 return beg;
200 }
201
202 is_escaped = !is_escaped && (*beg == '\\');
203 }
204
205 return 0;
206}
207
209{
210 _rw_string_buffer (char* s, size_t n)
211 : capacity_ (n)
212 , length_ (0)
213 , buffer_ (s)
214 , owned_ (false)
215 {
216 }
217
218 // destructor does not deallocate memory
219 // user expected to do that
220
221 size_t capacity_;
222 size_t length_;
223 char* buffer_;
224 bool owned_;
225
226 bool append (const char* s, size_t n);
227
228private:
229 // not implemented
231 _rw_string_buffer& operator= (const _rw_string_buffer&);
232};
233
234// this is where most of the work is done.
236{
237 //
239
240 //
242
243 // expand brace expression from `beg' to `end' into `len' bytes of
244 // `buf'. if it won't fit, we allocate a buffer with malloc() and
245 // return that. so the caller needs to free() the return buffer if
246 // it is not equal to `buf'.
247 char* build_and_expand (const char* beg,
248 const char* end,
249 char* buf, size_t len, char sep);
250
251
252private:
253
254 // not implemented
256 _rw_brace_graph& operator= (const _rw_brace_graph&);
257
258 // node for a directed-acyclic-graph that we build from the original
259 // brace expression
260 struct _rw_brace_node
261 {
262 const char* str_;
263 size_t len_;
264
265 _rw_brace_node* sibling_;
266 _rw_brace_node* child_;
267 };
268
269 // retrieve a new node. nodes are allocated in large blocks. those
270 // blocks are deallocated when this graph instance is destroyed.
271 // and they are reused for every build_and_expand() call.
272 _rw_brace_node* get_new_node ();
273
274 // this function generates a dag from an arbitrary brace expression.
275 // the format is `prefix{body}suffix'. prefix, and suffix can both
276 // be the empty string. body may be a comma seperated list of tokens,
277 // a sequence of tokens, or arbitrary literal text. escapes on commas
278 // and braces are ignored, and left intact otherwise.
279 _rw_brace_node* build_anything (const char* beg, const char* end);
280
281 // generates a dag from an arbitrary sequence brace expression. the
282 // format is `{?..?}suffix' where both ? are alphabetic characters
283 // of the same character class [upper/lower].
284 _rw_brace_node* build_character_sequence (const char* beg,
285 const char* end);
286
287 // generates a dag from an arbitrary sequence brace expression. the
288 // format is `{?..?}suffix' where both ? are integer expressions.
289 _rw_brace_node* build_integer_sequence (const char* beg,
290 const char* end);
291
292 // generates a dag from an arbitrary list brace expression. the
293 // format is `{a,b[,c]}suffix', where `a', `b' and `c' are full
294 // brace expansions that would be processed by build_anything.
295 _rw_brace_node* build_list (const char* beg, const char* end);
296
297 // the number of nodes held by each brace buffer [see below]
298 enum { size = 64 };
299
300#ifdef _RWSTD_NO_NESTED_CLASS_ACCESS
301
302 // allow _rw_brace_node_buffer access to _rw_brace_graph's private
303 // type(s) if the resolution of cwg issue 45 is not yet implemented
304 struct _rw_brace_node_buffer;
305 friend struct _rw_brace_node_buffer;
306
307 // allow _rw_recursion_context access to _rw_brace_graph's private
308 // type(s) if the resolution of cwg issue 45 is not yet implemented
309 struct _rw_recursion_context;
310 friend struct _rw_recursion_context;
311
312#endif // _RWSTD_NO_NESTED_CLASS_ACCESS
313
314 // this is essentially a rope with a fixed length payload of
315 // brace nodes
316 struct _rw_brace_node_buffer
317 {
318 _rw_brace_node nodes_ [size];
319 size_t used_; // number of nodes_ used in this buffer
320 _rw_brace_node_buffer* next_;
321 };
322
323 // the initial set of nodes is preallocated as part of this graph
324 // object instance. additional blocks of nodes will be allocated
325 // as is necessary by the get_new_node() member.
326 _rw_brace_node_buffer node_cache_;
327 _rw_brace_node_buffer* nodes_; // pointer to last allocated node buffer
328
329 // code for handling integer ranges
330
331 void reset_for_reuse (char* buf, size_t len);
332 void free_range_buffers ();
333
334 // this is essentially a rope with a variable length payload
335 struct _rw_range_buffer
336 {
337 _rw_range_buffer* next_;
338 };
339
340 _rw_range_buffer* ranges_;
341
342 // code for generating the string
343
344 _rw_string_buffer string_;
345
346 // we use this to walk the stack. we need to walk from the root
347 // of the tree to each leaf. when we reach a leaf, we need a way
348 // to see the path that we took to get where we are. we use this
349 // path to write out each part of the full expansion.
350 struct _rw_recursion_context
351 {
352 _rw_recursion_context (_rw_brace_node* pnode)
353 : parent_ (0), node_ (pnode)
354 {
355 }
356
357 _rw_recursion_context (_rw_recursion_context* parent)
358 : parent_ (parent), node_ (parent->node_->child_)
359 {
360 }
361
362 _rw_recursion_context* parent_;
363 _rw_brace_node* node_;
364 };
365
366 // this function walks the dag, leaving a trail of context
367 // objects so we can walk back to the root and write the data
368 // at each level in the graph.
369 bool brace_expand (_rw_recursion_context* self, char sep);
370
371 // this function writes the data at each level of the dag
372 // to our internal buffer.
373 bool brace_expand_write (_rw_recursion_context* context);
374};
375
377 : nodes_ (&node_cache_)
378 , ranges_ (0)
379 , string_ (0, 0)
380{
381 node_cache_.next_ = 0;
382}
383
385{
386 _rw_brace_node_buffer* nodes = node_cache_.next_;
387 while (nodes) {
388
389 _rw_brace_node_buffer* next = nodes->next_;
390 nodes->next_ = 0;
391
392 // deallocate this buffer
393 free (nodes);
394
395 // setup to deallocate next one
396 nodes = next;
397 }
398
399 reset_for_reuse (0, 0);
400}
401
402
403
404char*
406 const char* end,
407 char* buf, size_t len, char sep)
408{
409 assert (beg != 0);
410 assert (end != 0);
411
412 if (!beg || !end)
413 return 0;
414
415 // reset member data so we can reuse allocated buffers
416 // if there are any
417 reset_for_reuse (buf, len);
418
419 _rw_brace_node* root
420 = build_anything (beg, end);
421 if (!root)
422 return 0;
423
424 // this helps us do the building of the output string
425 _rw_recursion_context context (root);
426
427 if (!brace_expand (&context, sep)) {
428 if (string_.owned_)
429 free (string_.buffer_);
430 string_.buffer_ = 0;
431 }
432
433 // kill the last seperator with a null terminator
434 else if (string_.buffer_) {
435 const size_t pos = string_.length_ < 1 ? 0 : string_.length_ - 1;
436 string_.buffer_ [pos] = '\0';
437 }
438
439 return string_.buffer_;
440}
441
442_rw_brace_graph::_rw_brace_node*
443_rw_brace_graph::get_new_node ()
444{
445 nodes_->used_ += 1;
446
447 // if we run out of space, move to the next buffer
448 if (! (nodes_->used_ < size)) {
449
450 // if we have got a buffer, reuse it
451 if (nodes_->next_) {
452
453 nodes_ = nodes_->next_;
454 }
455
456 // otherwise we allocate one
457 else {
458
459 const size_t sz = sizeof (_rw_brace_node_buffer);
460
461 nodes_->next_ = (_rw_brace_node_buffer*)malloc (sz);
462 if (!nodes_->next_)
463 return 0;
464
465 nodes_ = nodes_->next_;
466 nodes_->next_ = 0;
467 }
468
469 nodes_->used_ = 1;
470 }
471
472 _rw_brace_node* node = &nodes_->nodes_ [nodes_->used_ - 1];
473 node->str_ = 0;
474 node->len_ = 0;
475 node->sibling_ = 0;
476 node->child_ = 0;
477
478 return node;
479}
480
481_rw_brace_graph::_rw_brace_node*
482_rw_brace_graph::build_anything (const char* beg, const char* end)
483{
484 //
485 const char* open_brace = _rw_find_open_brace (beg, end);
486 if (open_brace) {
487
488 // build a node for the prefix if there is one
489 _rw_brace_node* prefix = get_new_node ();
490 if (!prefix)
491 return 0;
492
493 prefix->str_ = beg;
494 prefix->len_ = (open_brace - beg);
495
496 _rw_brace_node* child = 0;
497
498 // try to build a character sequence expansion like {a..g}
499 child = build_character_sequence (open_brace, end);
500 if (!child) {
501
502 // try to do an integer sequence expansion like {-19..+72}
503 child = build_integer_sequence (open_brace, end);
504 if (!child) {
505
506 // try to do a list expansion like {a,b,cd}
507 child = build_list (open_brace, end);
508 if (!child) {
509
510 // we can't figure out what to do, so we fail
511 return 0;
512 }
513 }
514 }
515
516 // we must have a valid child pointer at this point
517 prefix->child_ = child;
518
519 return prefix;
520 }
521
522 // there was no open brace, so the entire text from beg to end
523 // is a literal
524 _rw_brace_node* prefix = get_new_node ();
525 if (!prefix)
526 return 0;
527
528 prefix->str_ = beg;
529 prefix->len_ = beg < end ? (end - beg) : 0;
530
531 return prefix;
532}
533
534_rw_brace_graph::_rw_brace_node*
535_rw_brace_graph::build_integer_sequence (const char* beg, const char* end)
536{
537 // check for {-10..100} type sequence expression. make sure not to
538 // reference past the end of the string.
539 if (*beg++ != '{')
540 return 0;
541
542 // this should point to first character after the integer value
543 char* pend;
544
545 // parse the first integer
546 long ibeg = strtol (beg, &pend, 10);
547 if (!ibeg && (pend == beg))
548 return 0; // failed to parse an integer value
549
550 // number of characters needed to represent ibeg
551 const size_t ibeg_dig = (pend - beg);
552
553 // make sure we have two dots
554 beg = pend;
555 if (! (beg [0] == '.' && beg [1] == '.'))
556 return 0;
557
558 // skip the two dots
559 beg += 2;
560
561 // parse the second integer
562 long iend = strtol (beg, &pend, 10);
563 if (!iend && (pend == beg))
564 return 0; // failed to parse an integer value
565
566 // number of characters needed to represent iend
567 const size_t iend_dig = (pend - beg);
568
569 // make sure we have an end brace
570 beg = pend;
571 if (beg [0] != '}')
572 return 0;
573 beg += 1;
574
575 // build the suffix
576 _rw_brace_node* suffix = build_anything (beg, end);
577 if (!suffix)
578 return 0; // failed to parse suffix
579
580 // direction the range goes, +1 for increasing, -1 for decreasing
581 const int dir = (ibeg < iend) ? 1 : -1;
582
583 // maximum length of the string representation of a single
584 // integer in the range
585 const size_t len = (ibeg_dig < iend_dig ? iend_dig : ibeg_dig);
586
587 // number of integers in the range [ibeg, iend]
588 const size_t num = 1 + (iend - ibeg) * dir;
589
590 // maximum number of bytes needed to represent all of the numbers
591 // and a single null
592 const size_t cnt = 1 + (num * len);
593
594 // number of bytes we have to allocate, cnt of which is data
595 // and the rest is to allow us to chain these buffers together
596 const size_t bsz = cnt + sizeof (_rw_range_buffer);
597
598 // allocate a rope segment big enough for all of the strings
599 // we need to keep.
600 _rw_range_buffer* buffer
601 = (_rw_range_buffer*)malloc (bsz);
602 if (!buffer)
603 return 0;
604
605 // add buffer to our list so we can free it later
606 buffer->next_ = ranges_;
607 ranges_ = buffer;
608
609 // pointer to the current write position in the buffer
610 char* ranges = (char*)&buffer [1];
611
612 _rw_brace_node* first_child = 0;
613 _rw_brace_node* final_child = 0;
614
615 // build a list of children, associate each with suffix
616 for (; ibeg != iend; ibeg += dir) {
617
618 // create a child from whatever is between beg and end. that childs
619 // next pointer will be the suffix we created above.
620 _rw_brace_node* child = get_new_node ();
621 if (!child)
622 return 0;
623
624 // add a representation of cbeg to the ranges buffer
625 child->len_ = _rw_itoa_10 (ranges, ibeg);
626 child->str_ = ranges;
627
628 // step past number of written characters
629 ranges += child->len_;
630
631 // track children we have created
632 if (!first_child)
633 first_child = child;
634
635 if (final_child)
636 final_child->sibling_ = child;
637 final_child = child;
638
639 // suffix is the suffix of the child expression
640 while (child->child_)
641 child = child->child_;
642 child->child_ = suffix;
643 }
644
645 // create the last node in the sequence.
646 _rw_brace_node* child = get_new_node ();
647 if (!child)
648 return 0;
649
650 // add a representation of cbeg to the ranges buffer
651 child->len_ = _rw_itoa_10 (ranges, ibeg);
652 child->str_ = ranges;
653
654 // trach child
655 if (!first_child)
656 first_child = child;
657
658 if (final_child)
659 final_child->sibling_ = child;
660 final_child = child;
661
662 // suffix is the suffix of the child expression
663 while (child->child_)
664 child = child->child_;
665 child->child_ = suffix;
666
667 return first_child;
668}
669
670_rw_brace_graph::_rw_brace_node*
671_rw_brace_graph::build_character_sequence (const char* beg, const char* end)
672{
673 // check for {a..z} type sequence expression. make sure not to
674 // reference past the end of the string.
675 if ( beg [0] != '{'
676 || beg [1] == '\0'
677 || beg [2] != '.'
678 || beg [3] != '.'
679 || beg [4] == '\0'
680 || beg [5] != '}')
681 return 0;
682
683 // grab characters that represent the start and end of the sequence
684 char cbeg = beg [1];
685 char cend = beg [4];
686
687 // only works if sequence characters are both lowercase or uppercase.
688 const int both_are_lower =
689 islower (UChar (cbeg)) && islower (UChar (cend));
690 const int both_are_upper =
691 isupper (UChar (cbeg)) && isupper (UChar (cend));
692
693 if (! (both_are_lower || both_are_upper))
694 return 0;
695
696 // these must live for duration of program
697 static const char* alpha_table [] =
698 {
699 "abcdefghijklmnopqrstuvwxyz",
700 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
701 };
702
703 const char* sequence = alpha_table [both_are_upper];
704
705 const int dir = (cbeg < cend) ? 1 : -1;
706
707 // build the suffix
708 _rw_brace_node* suffix = build_anything (beg + 6, end);
709 if (!suffix)
710 return 0; // failed to parse suffix
711
712 _rw_brace_node* first_child = 0;
713 _rw_brace_node* final_child = 0;
714
715 // build a list of children, associate each with suffix
716 for (; cbeg != cend; cbeg += dir) {
717
718 // create a child from whatever is between beg and end. that childs
719 // next pointer will be the suffix we created above.
720 _rw_brace_node* child = get_new_node ();
721 if (!child)
722 return 0;
723
724 // this finds beg in our array, we could have used strchr
725 child->str_ = sequence + (cbeg - sequence [0]);
726 child->len_ = 1;
727
728 // track children we have created
729 if (!first_child)
730 first_child = child;
731
732 if (final_child)
733 final_child->sibling_ = child;
734 final_child = child;
735
736 // suffix is the suffix of the child expression
737 while (child->child_)
738 child = child->child_;
739 child->child_ = suffix;
740 }
741
742 // create the last node in the sequence.
743 _rw_brace_node* child = get_new_node ();
744 if (!child)
745 return 0;
746
747 child->str_ = sequence + (cbeg - sequence [0]);
748 child->len_ = 1;
749
750 // trach child
751 if (!first_child)
752 first_child = child;
753
754 if (final_child)
755 final_child->sibling_ = child;
756 final_child = child;
757
758 // suffix is the suffix of the child expression
759 while (child->child_)
760 child = child->child_;
761 child->child_ = suffix;
762
763 return first_child;
764}
765
766_rw_brace_graph::_rw_brace_node*
767_rw_brace_graph::build_list (const char* beg, const char* end)
768{
769 // we really expect that the first token is an open paren the
770 // caller should have consumed the prefix before calling this
771 if (*beg++ != '{')
772 return nullptr;
773
774 // now fill in the middle, each child we create directly will
775 // have a child pointer to the suffix node
776
777 // special case {}?
778
779 // find the end of the brace list
780 const char* end_of_list = _rw_find_close_brace (beg, end);
781 if (!end_of_list)
782 return nullptr; // no list terminator
783
784 // build a node for the suffix.
785 _rw_brace_node* suffix = build_anything (end_of_list + 1, end);
786 if (!suffix)
787 return nullptr; // failed to parse end
788
789 // find the end of the first comma seperated token
790 const char* mid = _rw_find_next_comma (beg, end_of_list);
791
792 _rw_brace_node* first_child = 0;
793 _rw_brace_node* final_child = 0;
794
795 while (mid) {
796
797 // create a child from whatever is between beg and end. that childs
798 // next pointer will be the suffix we created above.
799 _rw_brace_node* child = build_anything (beg, mid);
800 if (!child)
801 return nullptr;
802
803 if (!first_child)
804 first_child = child;
805
806 // append new child to end of chain
807 if (final_child)
808 final_child->sibling_ = child;
809 final_child = child;
810
811 // the nex pointer for this child is the suffix
812
813 // suffix is the suffix of the child expression
814 while (child->child_)
815 child = child->child_;
816 child->child_ = suffix;
817
818 beg = mid + 1;
819 mid = _rw_find_next_comma (beg, end_of_list);
820 }
821
822 // okay, we have a pointer to the last comma in the list. create an
823 // item for the data between the comma and the list terminator
824
825 // '{abc,d{1..3}e}a'
826 // ^ ^ ^
827 // beg eol end
828
829 // build nodes from the last entry in the list
830 _rw_brace_node* child = build_anything (beg, end_of_list);
831 if (!child)
832 return nullptr;
833
834 if (!first_child)
835 first_child = child;
836
837 if (final_child)
838 final_child->sibling_ = child;
839 final_child = child;
840
841 while (child->child_)
842 child = child->child_;
843 child->child_ = suffix;
844
845 // success, return first child in this expansion
846 return first_child;
847}
848
849void _rw_brace_graph::reset_for_reuse (char* buf, size_t len)
850{
851 node_cache_.used_ = 0;
852 nodes_ = &node_cache_;
853
854 string_.buffer_ = buf;
855 string_.capacity_ = len;
856 string_.length_ = 0;
857
858 // we free these buffers because the size of the buffer
859 // depends on the expression we are evaluating
860 free_range_buffers ();
861}
862
863void _rw_brace_graph::free_range_buffers ()
864{
865 _rw_range_buffer* ranges = ranges_;
866 while (ranges) {
867
868 _rw_range_buffer* next = ranges->next_;
869 ranges->next_ = 0;
870
871 free (ranges);
872
873 ranges = next;
874 }
875
876 ranges_ = 0;
877}
878
879
880bool _rw_brace_graph::brace_expand_write (_rw_recursion_context* context)
881{
882 if (context->parent_) {
883 if (!brace_expand_write (context->parent_))
884 return false;
885 }
886
887 bool is_escaped = false;
888
889 const char* beg = context->node_->str_;
890 const size_t len = context->node_->len_;
891
892 for (size_t n = 0; n < len; ++n, ++beg) {
893
894 is_escaped = !is_escaped && (*beg == '\\');
895 if (!is_escaped) {
896 if (!string_.append (beg, 1))
897 return false;
898 }
899 }
900
901 return true;
902}
903
904bool _rw_brace_graph::brace_expand (_rw_recursion_context* self, char sep)
905{
906 // if this node has no children or siblings, we have found a full
907 // expansion.
908 if (!self->node_ ||
909 !self->node_->sibling_ && !self->node_->child_) {
910
911 const size_t length_before = string_.length_;
912
913 // use recursion again to walk back to the root the graph and
914 // write each contexts data as we unwind back toward the leaf
915 if (!brace_expand_write (self))
916 return false;
917
918 const size_t length_after = string_.length_;
919
920 // don't write a seperator if we wrote no data
921 if (length_before != length_after && !string_.append (&sep, 1))
922 return false;
923
924 return true;
925 }
926
927 // iterate through all of the children of the node, thus finding all
928 // other combinations
929 _rw_recursion_context context (self);
930 while (context.node_) {
931
932 if (!brace_expand (&context, sep))
933 return false;
934
935 context.node_ = context.node_->sibling_;
936 }
937
938 return true;
939}
940
941bool _rw_string_buffer::append (const char* s, size_t n)
942{
943 const size_t new_len = length_ + n;
944
945 // not enough space, grow buf
946 if (! (new_len < capacity_)) {
947
948 // buf grows in 256 byte blocks
949 size_t new_cap = capacity_;
950 while (! (new_len < new_cap))
951 new_cap += 256;
952
953 char* new_buf = (char*)malloc (new_cap);
954 if (!new_buf)
955 return false;
956
957 // copy the old data
958 memcpy (new_buf, buffer_, length_);
959
960 // copy the new data
961 memcpy (new_buf + length_, s, n);
962 new_buf [new_len] = '\0';
963
964 // don't free until after append because `s' may
965 // be in string_buf_
966 if (owned_)
967 free (buffer_);
968
969 capacity_ = new_cap;
970 length_ = new_len;
971 buffer_ = new_buf;
972 owned_ = true;
973 }
974
975 // just copy the data
976 else {
977 memcpy (buffer_ + length_, s, n);
978 buffer_ [new_len] = '\0';
979 length_ = new_len;
980 }
981
982 return true;
983}
984
985//
986char* rw_brace_expand (const char* brace_expr,
987 size_t sz,
988 char* s, size_t n, char sep)
989{
990 if (!brace_expr)
991 return 0;
992
993 // if the length isn't provided, assume entire string
994 if (!sz)
995 sz = strlen (brace_expr);
996
998
999 // build the graph, and then expand it into buf
1000 char* buf = graph.build_and_expand (brace_expr,
1001 brace_expr + sz, s, n, sep);
1002 if (!buf)
1003 return 0;
1004
1005 return buf;
1006}
1007
1008
1009//
1010char* rw_shell_expand (const char* shell_expr, size_t sz,
1011 char* s, size_t n, char sep)
1012{
1013 if (!shell_expr)
1014 return 0;
1015
1016 // if the length isn't provided, assume entire string
1017 if (!sz)
1018 sz = strlen (shell_expr);
1019
1020 // assume shell_expr is null terminated
1021 const char* beg = shell_expr;
1022 const char* end = shell_expr + sz;
1023
1024 // helper for output
1026
1027 // helper for expanding braces
1029
1030 // first non-whitespace character
1031 const char* tok_beg = _rw_find_match (beg, end, false);
1032 if (!tok_beg) {
1033
1034 if (!result.append ("\0", 1))
1035 return 0;
1036
1037 return result.buffer_;
1038 }
1039
1040 bool is_first_expand = true;
1041
1042 while (tok_beg)
1043 {
1044 // first whitespace character
1045 const char* tok_end = _rw_find_match (tok_beg, end, true);
1046 if (!tok_end)
1047 tok_end = end;
1048
1049 // expand from tok_beg to tok_end into buf
1050 char buf [256];
1051
1052 char* exp =
1053 graph.build_and_expand (tok_beg, tok_end, buf, sizeof (buf), sep);
1054
1055 // apptok_end space, then expansion, expansion
1056
1057 bool app = false;
1058
1059 if (exp) {
1060
1061 // in case user uses a null seperator
1062 const char* term = exp;
1063 for (; *term; term += strlen (term) + 1)
1064 ;
1065
1066 const size_t len = exp < term ? (term - exp) - 1 : 0;
1067
1068 if (is_first_expand)
1069 app = result.append (exp, len);
1070 else if (result.append (&sep, 1))
1071 app = result.append (exp, len);
1072 }
1073
1074 is_first_expand = false;
1075
1076 if (exp != buf)
1077 free (exp);
1078
1079 // if we didn't append, or we failed to append
1080 // then this function fails
1081 if (!app) {
1082
1083 if (result.owned_)
1084 free (result.buffer_);
1085
1086 return 0;
1087 }
1088
1089 // bail if we're at the end of string
1090 if (!tok_end)
1091 break;
1092
1093 // fid next nonwhitespace, which is the start of the next token
1094 tok_beg = _rw_find_match (tok_end, end, false);
1095 }
1096
1097 return result.buffer_;
1098}
const char graph[]
#define i
Definition 17.names.cpp:126
#define cnt
Definition 17.names.cpp:459
#define q
Definition 17.names.cpp:133
#define r
Definition 17.names.cpp:134
#define neg
Definition 17.names.cpp:503
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define buffer
Definition 17.names.cpp:453
#define sz
Definition 17.names.cpp:550
#define c
Definition 17.names.cpp:111
#define pend
Definition 17.names.cpp:523
#define s
#define len
Definition 17.names.cpp:488
#define n
Definition 17.names.cpp:130
#define num
Definition 17.names.cpp:505
#define pos
Definition 17.names.cpp:518
volatile int result
T value(const T &val)
const int end
#define assert(expr)
Definition _cassert.h:40
unsigned char UChar
Definition braceexp.cpp:39
char * rw_brace_expand(const char *brace_expr, size_t sz, char *s, size_t n, char sep)
Definition braceexp.cpp:986
char * rw_shell_expand(const char *shell_expr, size_t sz, char *s, size_t n, char sep)
unsigned char UChar
Definition collate.cpp:122
#define false
Definition stdbool.h:26
char * build_and_expand(const char *beg, const char *end, char *buf, size_t len, char sep)
Definition braceexp.cpp:405
bool append(const char *s, size_t n)
Definition braceexp.cpp:941
_rw_string_buffer(char *s, size_t n)
Definition braceexp.cpp:210
long prefix(const entry_type &entry)
Definition tele.cpp:58