1 
2 #include <reflex/boostmatcher.h>
3 
4 // #define INTERACTIVE // for interactive mode testing
5 
banner(const char * title)6 static void banner(const char *title)
7 {
8   int i;
9   printf("\n\n/");
10   for (i = 0; i < 78; i++)
11     putchar('*');
12   printf("\\\n *%76s*\n * %-75s*\n *%76s*\n\\", "", title, "");
13   for (i = 0; i < 78; i++)
14     putchar('*');
15   printf("/\n\n");
16 }
17 
error(const char * text)18 static void error(const char *text)
19 {
20   std::cout << "FAILED: " << text << std::endl;
21   exit(EXIT_FAILURE);
22 }
23 
24 using namespace reflex;
25 
26 class WrappedMatcher : public BoostPosixMatcher {
27  public:
WrappedMatcher()28   WrappedMatcher() : BoostPosixMatcher(), source(0)
29   { }
30  private:
wrap()31   virtual bool wrap()
32   {
33     switch (source++)
34     {
35       case 0: in = "Hello World!";
36 	      return true;
37       case 1: in = "How now brown cow.";
38 	      return true;
39       case 2: in = "An apple a day.";
40 	      return true;
41     }
42     return false;
43   }
44   int source;
45 };
46 
47 struct Test {
48   const char *pattern;
49   const char *popts;
50   const char *mopts;
51   const char *cstring;
52   size_t accepts[32];
53 };
54 
55 Test tests[] = {
56   { "ab", "", "", "ab", { 1 } },
57   { "ab", "", "", "abab", { 1, 1 } },
58   { "ab|xy", "", "", "abxy", { 1, 2 } },
59   { "a(p|q)z", "", "", "apzaqz", { 1, 1 } },
60   // DFA edge compaction test (only applicable to RE/flex)
61   { "[a-cg-ik]z|d|[e-g]|j|y|[x-z]|.|\\n", "", "", "azz", { 1, 6 } },
62   // POSIX character classes
63   {
64     "\\x7E-"
65     "[[:space:]]-"
66     "[[:xdigit:]]-"
67     "[[:cntrl:]]-"
68     "[[:print:]]-"
69     "[[:alnum:]]-"
70     "[[:alpha:]]-"
71     "[[:blank:]]-"
72     "[[:digit:]]-"
73     "[[:graph:]]-"
74     "[[:lower:]]-"
75     "[[:punct:]]-"
76     "[[:upper:]]-"
77     "[[:word:]]", "", "", "\x7E-\r-F-\x01-&-0-A-\t-0-#-l-.-U-_", { 1 } },
78   {
79     "\\x7E-"
80     "\\p{Space}-"
81     "\\p{XDigit}-"
82     "\\p{Cntrl}-"
83     "\\p{Print}-"
84     "\\p{Alnum}-"
85     "\\p{Alpha}-"
86     "\\p{Blank}-"
87     "\\p{Digit}-"
88     "\\p{Graph}-"
89     "\\p{Lower}-"
90     "\\p{Punct}-"
91     "\\p{Upper}-"
92     "\\p{Word}", "", "", "\x7E-\r-F-\x01-&-0-A-\t-0-#-l-.-U-_", { 1 } },
93   // Pattern option i
94   { "(?i:abc)", "", "", "abcABC", { 1, 1 } },
95   { "(?i)abc|xyz", "", "", "abcABCxyzXYZ", { 1, 1, 2, 2 } },
96   { "(?i:abc)|xyz", "", "", "abcABCxyz", { 1, 1, 2 } },
97   { "(?i:abc)|(?i:xyz)", "", "", "abcABCxyzXYZ", { 1, 1, 2, 2 } },
98   { "(?i)abc|(?-i:xyz)|(?-i:XYZ)", "", "", "abcABCxyzXYZ", { 1, 1, 2, 3 } },
99   { "(?i:abc(?-i:xyz))|ABCXYZ", "", "", "abcxyzABCxyzABCXYZ", { 1, 1, 2 } },
100   // Pattern option x
101   { "(?x) a\tb\n c | ( xy ) z ?", "", "", "abcxy", { 1, 2 } },
102   { "(?x: a b\n c)", "", "", "abc", { 1 } },
103   { "(?x) a b c\n|\n# COMMENT\n x y z", "", "", "abcxyz", { 1, 2 } },
104   // { "(?x) a b c\n|\n/* COMMENT\n*/ x y z", "", "", "abcxyz", { 1, 2 } }, // Boost does not support /*...*/
105   { "(?# test option (?x:... )(?x: a b c)|x y z", "", "", "abcx y z", { 1, 2 } },
106   // Pattern option s
107   { "(?s).", "", "", "a\n", { 1, 1 } },
108   { "(?s:.)", "", "", "a\n", { 1, 1 } },
109   { "(?s).", "", "", "a\n", { 1, 1 } },
110   // Anchors \A, \Z, ^, and $ (Boost.Regex matches \n, \r and \f as newlines)
111   { "\\Aa\\Z", "", "", "a", { 1 } },
112   { "^a$", "", "", "a", { 1 } },
113   { "(?m)^a$|\\n", "m", "", "a\na", { 1, 2, 1 } },
114   { "(?m)^a|a$|a|\\n", "m", "", "aa\naaa", { 1, 2, 4, 1, 3, 2 } },
115 #ifndef INTERACTIVE
116   { "(?m)\\Aa\\Z|\\Aa|a\\Z|^a$|^a|a$|a|^ab$|^ab|ab$|ab|\\n", "m", "", "a\na\naa\naaa\nab\nabab\nababab\na", { 2, 12, 4, 12, 5, 6, 12, 5, 7, 6, 12, 8, 12, 9, 10, 12, 9, 11, 10, 12, 3 } },  // boost has a partial match bug when interactive() blk=1
117 #endif
118   // Optional X?
119   { "a?z", "", "", "azz", { 1, 1 } },
120   // Closure X*
121   { "a*z", "", "", "azaazz", { 1, 1, 1 } },
122   // Positive closure X+
123   { "a+z", "", "", "azaaz", { 1, 1 } },
124   // Combi ? * +
125   { "a?b+|a", "", "", "baba", { 1, 1, 2 } },
126   { "a*b+|a", "", "", "baabaa", { 1, 1, 2, 2 } },
127   // Iterations {n,m}
128   { "ab{2}", "", "", "abbabb", { 1, 1 } },
129   { "ab{2,3}", "", "", "abbabbb", { 1, 1 } },
130   { "ab{2,}", "", "", "abbabbbabbbb", { 1, 1, 1 } },
131   { "ab{0,}", "", "", "a", { 1 } },
132   { "(ab{0,2}c){2}", "", "", "abbcacabcabc", { 1, 1 } },
133 #if 0 // Boost POSIX mode does not support lazy quantifiers
134   // Lazy optional X?
135   { "(a|b)?\?a", "", "", "aaba", { 1, 1, 1 } },
136   { "a(a|b)?\?(?=a|ab)|ac", "", "", "aababac", { 1, 1, 1, 2 } },
137   { "(a|b)?\?(a|b)?\?aa", "", "", "baaaabbaa", { 1, 1, 1 } },
138   { "(a|b)?\?(a|b)?\?(a|b)?\?aaa", "", "", "baaaaaa", { 1, 1 } },
139   { "a?\?b?a", "", "", "aba", { 1, 1 } }, // 'a' 'ba'
140   { "a?\?b?b", "", "", "abb", { 1 } }, // 'abb'
141   // Lazy closure X*
142   { "a*?a", "", "", "aaaa", { 1, 1, 1, 1 } },
143   { "a*?|a|b", "", "", "aab", { 2, 2, 3 } },
144   { "(a|bb)*?abb", "", "", "abbbbabb", { 1, 1 } },
145   { "ab*?|b", "", "", "ab", { 1, 2 } },
146   { "(ab)*?|b", "", "", "b", { 2 } },
147   { "a(ab)*?|b", "", "", "ab", { 1, 2 } },
148   { "(a|b)*?a|c?", "", "", "bbaaac", { 1, 1, 1, 2 } },
149   { "a(a|b)*?a", "", "", "aaaba", { 1, 1 } },
150   { "a(a|b)*?a?\?|b", "", "", "aaaba", { 1, 1, 1, 2, 1 } },
151   { "a(a|b)*?a?", "", "", "aa", { 1 } },
152   { "a(a|b)*?a|a", "", "", "aaaba", { 1, 1 } },
153   { "a(a|b)*?a|a?", "", "", "aaaba", { 1, 1 } },
154   { "a(a|b)*?a|a?\?", "", "", "aaaba", { 1, 1 } },
155   { "a(a|b)*?a|aa?", "", "", "aaaba", { 1, 1 } },
156   { "a(a|b)*?a|aa?\?", "", "", "aaaba", { 1, 1 } },
157   { "ab(ab|cd)*?ab|ab", "", "", "abababcdabab", { 1, 1, 2 } },
158   { "(a|b)(a|b)*?a|a", "", "", "aaabaa", { 1, 1, 2 } },
159   { "(ab|cd)(ab|cd)*?ab|ab", "", "", "abababcdabab", { 1, 1, 2 } },
160   { "(ab)(ab)*?a|b", "", "", "abababa", { 1, 2, 1 } },
161   { "a?(a|b)*?a", "", "", "aaababa", { 1, 1, 1 } },
162   { "(?m)^(a|b)*?a", "m", "", "bba", { 1 } },
163   { "(?m)(a|b)*?a$", "m", "", "bba", { 1 } },
164   { "(?m)^(a|b)*?|b", "m", "", "ab", { 1, 2 } },
165   // Lazy positive closure X+
166   { "a+?a", "", "", "aaaa", { 1, 1 } },
167   { "(a|b)+?", "", "", "ab", { 1, 1 } },
168   { "(a|b)+?a", "", "", "bbaaa", { 1, 1 } },
169   { "(a|b)+?a|c?", "", "", "bbaaa", { 1, 1 } },
170   { "(ab|cd)+?ab|d?", "", "", "cdcdababab", { 1, 1 } },
171   { "(ab)+?a|b", "", "", "abababa", { 1, 2, 1 } },
172   { "(ab)+?ac", "", "", "ababac", { 1 } },
173   { "ABB*?|ab+?|A|a", "", "", "ABab", { 1, 2 } },
174   { "(a|b)+?a|a", "", "", "bbaaa", { 1, 1 } },
175   { "(?m)^(a|b)+?a", "m", "", "abba", { 1 } },
176   { "(?m)(a|b)+?a$", "m", "", "abba", { 1 } },
177   // Lazy iterations {n,m}
178   { "(a|b){0,3}?aaa", "", "", "baaaaaa", { 1, 1 } },
179   { "(a|b){1,3}?aaa", "", "", "baaaaaaa", { 1, 1 } },
180   { "(a|b){1,3}?aaa", "", "", "bbbaaaaaaa", { 1, 1 } },
181   { "(ab|cd){0,3}?ababab", "", "", "cdabababababab", { 1, 1 } },
182   { "(ab|cd){1,3}?ababab", "", "", "cdababababababab", { 1, 1 } },
183   { "(a|b){1,}?a|a", "", "", "bbaaa", { 1, 1 } },
184   { "(a|b){2,}?a|aa", "", "", "bbbaaaa", { 1, 1 } },
185 #endif
186   // Bracket lists
187   { "[a-z]", "", "", "abcxyz", { 1, 1, 1, 1, 1, 1 } },
188   { "[a-d-z]", "", "", "abcd-z", { 1, 1, 1, 1, 1, 1 } },
189   { "[-z]", "", "", "-z", { 1, 1 } },
190   { "[z-]", "", "", "-z", { 1, 1 } },
191   { "[--z]", "", "", "-az", { 1, 1, 1 } },
192   { "[ --]", "", "", " +-", { 1, 1, 1 } },
193   { "[^a-z]", "", "", "A", { 1 } },
194   { "[[:alpha:]]", "", "", "abcxyz", { 1, 1, 1, 1, 1, 1 } },
195   { "[\\p{Alpha}]", "", "", "abcxyz", { 1, 1, 1, 1, 1, 1 } },
196   { "[][]", "", "", "[]", { 1, 1 } },
197   // Lookahead
198   { "a(?=bc)|ab(?=d)|bc|d", "", "", "abcdabd", { 1, 3, 4, 2, 4 } },
199   // { "[ab]+(?=ab)|-|ab", "", "", "aaab-bbab", { 1, 3, 2, 1, 3 } }, // has trailing context (undefined as per POSIX)
200   { "(?m)a(?=b?)|bc", "m", "", "aabc", { 1, 1, 2 } },
201 #ifndef INTERACTIVE
202   { "(?m)a(?=\\nb)|a|^b|\\n", "m", "", "aa\nb\n", { 2, 1, 4, 3, 4 } }, // boost has a partial match bug when interactive() blk=1
203 #endif
204   { "(?m)^a(?=b$)|b|\\n", "m", "", "ab\n", { 1, 2, 3 } },
205   { "(?m)a(?=\n)|a|\\n", "m", "", "aa\n", { 2, 1, 3 } },
206   { "(?m)^( +(?=a)|b)|a|\\n", "m", "", " a\n  a\nb\n", { 1, 2, 3, 1, 2, 3, 1, 3 } },
207   // Word boundaries \<, \>, \b, and \B
208   { "\\<a\\>|\\<a|a\\>|a|-", "", "", "a-aaa", { 1, 5, 2, 4, 3 } },
209   { "\\<.*ab\\>|[ab]*|-|\\n", "", "", "-aaa-aaba-aab-\n-aaa", { 3, 1, 3, 4, 3, 2 } },
210 #ifndef INTERACTIVE
211   { "\\<.*\\>", "", "", "abc def", { 1 } }, // boost has a partial match bug when interactive() blk=1
212 #endif
213   { "\\<.*\\>|-", "", "", "abc-", { 1, 2 } },
214   { "\\b.*\\b|-", "", "", "abc-", { 1, 2 } },
215   { "-|\\<.*\\>", "", "", "-abc-", { 1, 2, 1 } },
216   { "-|\\b.*\\b", "", "", "-abc-", { 1, 2, 1 } },
217   { "(-|a)\\<(-|a)\\>(-|a)", "", "", "-a-", { 1 } },
218   { "(-|a)\\b(-|a)\\b(-|a)", "", "", "-a-a-a", { 1, 1 } },
219   { "(-|a)\\B(-|a)\\B(-|a)", "", "", "---aaa", { 1, 1 } },
220   { "\\<(-|a)(-|a)\\>| ", "", "", "aa aa", { 1, 2, 1 } },
221   { "\\b(-|a)(-|a)\\b| ", "", "", "aa aa", { 1, 2, 1 } },
222 #ifndef INTERACTIVE
223   { "\\B(-|a)(-|a)\\B|b|#", "", "", "baab#--#", { 2, 1, 2, 3, 1, 3 } }, // boost has a partial match bug when interactive() blk=1
224 #endif
225   { "-\\b(-|a)(-|a)\\b", "", "", "-aa", { 1 } },
226   { "a\\b(-|a)(-|a)\\b", "", "", "a-a", { 1 } },
227 #ifndef INTERACTIVE
228   { "a?\\>(-|a)(-|a)\\b| ", "", "", "a-a-a", { 1, 1 } }, // boost has a partial match bug when interactive() blk=1 & does not check \> at start, so accepts more liberally
229 #endif
230   { "\\b(-|a)(-|a)\\bz?| ", "", "", "aa a-z", { 1, 2, 1 } },
231   { "(-|a)(-|a)\\bz?| ", "", "", "aa a-z", { 1, 2, 1 } },
232   { "a?\\b(-|a)(-|a)\\b| ", "", "", "a-a", { 1 } },
233 #ifndef INTERACTIVE
234   { "-(?=\\<a\\>)|-|a|b", "", "", "-a-ab", { 1, 3, 2, 3, 4 } }, // boost has a partial match bug when interactive() blk=1
235 #endif
236   // Unicode
237   { "(©)+", "", "", "©", { 1 } },
238   { NULL, NULL, NULL, NULL, { } }
239 };
240 
main()241 int main()
242 {
243   banner("PATTERN TESTS");
244   for (const Test *test = tests; test->pattern != NULL; ++test)
245   {
246     std::string regex;
247     try
248     {
249       regex = BoostPosixMatcher::convert(test->pattern, convert_flag::recap);
250     }
251     catch (const regex_error& e)
252     {
253       std::cerr << e.what();
254     }
255     std::cout << regex << std::endl;
256     boost::regex pattern(regex);
257     BoostPosixMatcher matcher(pattern, test->cstring, test->mopts);
258 #ifdef INTERACTIVE
259     matcher.interactive(); // test with blk=1
260 #endif
261     printf("Test \"%s\" against \"%s\"\n", test->pattern, test->cstring);
262     if (*test->popts)
263       printf("With pattern options \"%s\"\n", test->popts);
264     if (*test->mopts)
265       printf("With matcher options \"%s\"\n", test->mopts);
266     size_t i = 0;
267     while (matcher.scan())
268     {
269       printf("  At %zu,%zu;[%zu,%zu]: \"%s\" matches pattern %zu\n", matcher.lineno(), matcher.columno(), matcher.first(), matcher.last(), matcher.text(), matcher.accept());
270       if (matcher.accept() != test->accepts[i])
271         break;
272       ++i;
273     }
274     if (matcher.accept() != 0 || test->accepts[i] != 0 || !matcher.at_end())
275     {
276       if (!matcher.at_end())
277         printf("ERROR: remaining input rest = '%s'\n", matcher.rest());
278       else
279         printf("ERROR: accept = %zu text = '%s'\n", matcher.accept(), matcher.text());
280       exit(1);
281     }
282     printf("OK\n\n");
283   }
284   BoostPosixMatcher pattern1("(\\w+)|(\\W)");
285   BoostPosixMatcher pattern2("\\<.*\\>");
286   BoostPosixMatcher pattern3(" ");
287   BoostPosixMatcher pattern4("[ \\t]+");
288   BoostPosixMatcher pattern5("\\b");
289   BoostPosixMatcher pattern6("");
290   BoostPosixMatcher pattern7("[[:alpha:]]");
291   BoostPosixMatcher pattern8("\\w+");
292   BoostPosixMatcher pattern9(BoostPosixMatcher::convert("(?u:\\p{L})"));
293 
294   BoostPosixMatcher matcher(pattern1);
295   std::string test;
296   //
297   banner("TEST FIND");
298   //
299   matcher.pattern(pattern8);
300   matcher.input("an apple a day");
301   test = "";
302   while (matcher.find())
303   {
304     std::cout << matcher.text() << "/";
305     test.append(matcher.text()).append("/");
306   }
307   std::cout << std::endl;
308   if (test != "an/apple/a/day/")
309     error("find results");
310   //
311   matcher.pattern(pattern5);
312   matcher.reset("N");
313   matcher.input("a a");
314   test = "";
315   while (matcher.find())
316   {
317     std::cout << matcher.text() << "/";
318     test.append(matcher.text()).append("/");
319   }
320   std::cout << std::endl;
321   if (test != "///")
322     error("find with nullable results");
323   matcher.reset("");
324   //
325   matcher.pattern(pattern6);
326   matcher.reset("N");
327   matcher.input("a a");
328   test = "";
329   while (matcher.find())
330   {
331     std::cout << matcher.text() << "/";
332     test.append(matcher.text()).append("/");
333   }
334   std::cout << std::endl;
335   if (test != "///")
336     error("find with nullable results");
337   matcher.reset("");
338   //
339   banner("TEST SPLIT");
340   //
341   matcher.pattern(pattern3);
342   matcher.input("ab c  d");
343   test = "";
344   while (matcher.split())
345   {
346     std::cout << matcher.text() << "/";
347     test.append(matcher.text()).append("/");
348   }
349   std::cout << std::endl;
350   if (test != "ab/c//d/")
351     error("split results");
352   //
353   matcher.pattern(pattern3);
354   matcher.input("ab c  d ");
355   test = "";
356   while (matcher.split())
357   {
358     std::cout << matcher.text() << "/";
359     test.append(matcher.text()).append("/");
360   }
361   std::cout << std::endl;
362   if (test != "ab/c//d//")
363     error("split results");
364   //
365   matcher.pattern(pattern4);
366   matcher.input("ab c  d");
367   test = "";
368   while (matcher.split())
369   {
370     std::cout << matcher.text() << "/";
371     test.append(matcher.text()).append("/");
372   }
373   std::cout << std::endl;
374   if (test != "ab/c/d/")
375     error("split results");
376   //
377   matcher.pattern(pattern5);
378   matcher.input("ab c  d");
379   test = "";
380   while (matcher.split())
381   {
382     std::cout << matcher.text() << "/";
383     test.append(matcher.text()).append("/");
384   }
385   std::cout << std::endl;
386   if (test != "/ab/ /c/  /d//")
387     error("split results");
388   //
389   matcher.pattern(pattern6);
390   matcher.input("ab c  d");
391   test = "";
392   while (matcher.split())
393   {
394     std::cout << matcher.text() << "/";
395     test.append(matcher.text()).append("/");
396   }
397   std::cout << std::endl;
398   if (test != "/a/b/ /c/ / /d//")
399     error("split results");
400   //
401   matcher.pattern(pattern6);
402   matcher.input("");
403   test = "";
404   while (matcher.split())
405   {
406     std::cout << matcher.text() << "/";
407     test.append(matcher.text()).append("/");
408   }
409   std::cout << std::endl;
410   if (test != "/")
411     error("split results");
412   //
413   matcher.pattern(pattern7);
414   matcher.input("a-b");
415   test = "";
416   while (matcher.split())
417   {
418     std::cout << matcher.text() << "/";
419     test.append(matcher.text()).append("/");
420   }
421   std::cout << std::endl;
422   if (test != "/-//")
423     error("split results");
424   //
425   matcher.pattern(pattern7);
426   matcher.input("a");
427   test = "";
428   while (matcher.split())
429   {
430     std::cout << matcher.text() << "/";
431     test.append(matcher.text()).append("/");
432   }
433   std::cout << std::endl;
434   if (test != "//")
435     error("split results");
436   //
437   matcher.pattern(pattern7);
438   matcher.input("-");
439   test = "";
440   while (matcher.split())
441   {
442     std::cout << matcher.text() << "/";
443     test.append(matcher.text()).append("/");
444   }
445   std::cout << std::endl;
446   if (test != "-/")
447     error("split results");
448   //
449   matcher.pattern(pattern4);
450   matcher.input("ab c  d");
451   int n = 2; // split 2
452   while (n-- && matcher.split())
453     std::cout << matcher.text() << "/";
454   std::cout << std::endl << "REST = " << matcher.rest() << std::endl;
455   //
456   banner("TEST INPUT/UNPUT");
457   //
458   matcher.pattern(pattern2);
459   matcher.input("ab c  d");
460   while (!matcher.at_end())
461     std::cout << (char)matcher.input() << "/";
462   std::cout << std::endl;
463   //
464   matcher.pattern(pattern2);
465   matcher.input("ab c  d");
466   test = "";
467   while (true)
468   {
469     if (matcher.scan())
470     {
471       std::cout << matcher.text() << "/";
472       test.append(matcher.text()).append("/");
473     }
474     else if (!matcher.at_end())
475     {
476       std::cout << (char)matcher.input() << "?/";
477       test.append("?/");
478     }
479     else
480     {
481       break;
482     }
483   }
484   std::cout << std::endl;
485   if (test != "ab c  d/")
486     error("input");
487   //
488   matcher.pattern(pattern7);
489   matcher.input("ab c  d");
490   test = "";
491   while (true)
492   {
493     if (matcher.scan())
494     {
495       std::cout << matcher.text() << "/";
496       test.append(matcher.text()).append("/");
497     }
498     else if (!matcher.at_end())
499     {
500       std::cout << (char)matcher.input() << "?/";
501       test.append("?/");
502     }
503     else
504     {
505       break;
506     }
507   }
508   std::cout << std::endl;
509   if (test != "a/b/?/c/?/?/d/")
510     error("input");
511   //
512   matcher.pattern(pattern7);
513   matcher.input("ab c  d");
514   matcher.unput('a');
515   test = "";
516   while (true)
517   {
518     if (matcher.scan())
519     {
520       std::cout << matcher.text() << "/";
521       test.append(matcher.text()).append("/");
522       if (*matcher.text() == 'b')
523         matcher.unput('c');
524     }
525     else if (!matcher.at_end())
526     {
527       std::cout << (char)matcher.input() << "?/";
528     }
529     else
530     {
531       break;
532     }
533   }
534   std::cout << std::endl;
535   if (test != "a/a/b/c/c/d/")
536     error("unput");
537   //
538   matcher.pattern(pattern9);
539   matcher.input("ab c  d");
540   matcher.wunput(L'ä');
541   test = "";
542   while (true)
543   {
544     if (matcher.scan())
545     {
546       std::cout << matcher.text() << "/";
547       test.append(matcher.text()).append("/");
548       if (*matcher.text() == 'b')
549         matcher.wunput(L'ç');
550     }
551     else if (!matcher.at_end())
552     {
553       std::cout << (char)matcher.winput() << "?/";
554     }
555     else
556     {
557       break;
558     }
559   }
560   std::cout << std::endl;
561   if (test != "ä/a/b/ç/c/d/")
562     error("wunput");
563   //
564   banner("TEST WRAP");
565   //
566   WrappedMatcher wrapped_matcher;
567   wrapped_matcher.pattern(pattern8);
568   test = "";
569   while (wrapped_matcher.find())
570   {
571     std::cout << wrapped_matcher.text() << "/";
572     test.append(wrapped_matcher.text()).append("/");
573   }
574   std::cout << std::endl;
575   if (test != "Hello/World/How/now/brown/cow/An/apple/a/day/")
576     error("wrap");
577   //
578   banner("TEST REST");
579   //
580   matcher.pattern(pattern8);
581   matcher.input("abc def xyz");
582   test = "";
583   if (matcher.find())
584   {
585     std::cout << matcher.text() << "/";
586     test.append(matcher.text()).append("/");
587   }
588   std::cout << std::endl;
589   if (test != "abc/" || strcmp(matcher.rest(), " def xyz") != 0)
590     error("rest");
591   //
592   banner("TEST SKIP");
593   //
594   matcher.pattern(pattern8);
595   matcher.input("abc  \ndef xyz");
596   test = "";
597   if (matcher.scan())
598   {
599     std::cout << matcher.text() << "/";
600     test.append(matcher.text()).append("/");
601     matcher.skip('\n');
602   }
603   if (matcher.scan())
604   {
605     std::cout << matcher.text() << "/";
606     test.append(matcher.text()).append("/");
607     matcher.skip('\n');
608   }
609   //
610   matcher.input("abc  ¶def¶");
611   test = "";
612   if (matcher.scan())
613   {
614     std::cout << matcher.text() << "/";
615     test.append(matcher.text()).append("/");
616     matcher.skip(L'¶');
617   }
618   if (matcher.scan())
619   {
620     std::cout << matcher.text() << "/";
621     test.append(matcher.text()).append("/");
622     matcher.skip(L'¶');
623   }
624   //
625   matcher.input("abc  xxydef xx");
626   test = "";
627   if (matcher.scan())
628   {
629     std::cout << matcher.text() << "/";
630     test.append(matcher.text()).append("/");
631     matcher.skip("xy");
632   }
633   if (matcher.scan())
634   {
635     std::cout << matcher.text() << "/";
636     test.append(matcher.text()).append("/");
637     matcher.skip("xy");
638   }
639   std::cout << std::endl;
640   if (test != "abc/def/")
641     error("skip");
642   //
643 #ifdef WITH_SPAN
644   banner("TEST SPAN");
645   //
646   matcher.pattern(pattern8);
647   matcher.input("##a#b#c##\ndef##\n##ghi\n##xyz");
648   test = "";
649   while (matcher.find())
650   {
651     std::cout << matcher.span() << "/";
652     test.append(matcher.span()).append("/");
653   }
654   std::cout << std::endl;
655   if (test != "##a#b#c##/def##/##ghi/##xyz/")
656     error("span");
657   //
658   banner("TEST LINE");
659   //
660   matcher.pattern(pattern8);
661   matcher.input("##a#b#c##\ndef##\n##ghi\n##xyz");
662   test = "";
663   while (matcher.find())
664   {
665     std::cout << matcher.line() << "/";
666     test.append(matcher.line()).append("/");
667   }
668   std::cout << std::endl;
669   if (test != "##a#b#c##/##a#b#c##/##a#b#c##/def##/##ghi/##xyz/")
670     error("line");
671 #endif
672   //
673   banner("TEST MORE");
674   //
675   matcher.pattern(pattern7);
676   matcher.input("abc");
677   test = "";
678   while (matcher.scan())
679   {
680     std::cout << matcher.text() << "/";
681     matcher.more();
682     test.append(matcher.text()).append("/");
683   }
684   std::cout << std::endl;
685   if (test != "a/ab/abc/")
686     error("more");
687   //
688   banner("TEST LESS");
689   //
690   matcher.pattern(pattern1);
691   matcher.input("abc");
692   test = "";
693   while (matcher.scan())
694   {
695     matcher.less(1);
696     std::cout << matcher.text() << "/";
697     test.append(matcher.text()).append("/");
698   }
699   std::cout << std::endl;
700   if (test != "a/b/c/")
701     error("less");
702   //
703   banner("TEST MATCHES");
704   //
705   if (BoostPosixMatcher("\\w+", "hello").matches()) // on the fly string matching
706     std::cout << "OK";
707   else
708     error("match results");
709   std::cout << std::endl;
710   if (BoostPosixMatcher("\\d", "0").matches())
711     std::cout << "OK";
712   else
713     error("match results");
714   std::cout << std::endl;
715   //
716   matcher.pattern(pattern1);
717   matcher.input("abc");
718   if (matcher.matches())
719     std::cout << "OK";
720   else
721     error("match results");
722   std::cout << std::endl;
723   //
724   matcher.pattern(pattern2);
725   matcher.input("abc");
726   if (matcher.matches())
727     std::cout << "OK";
728   else
729     error("match results");
730   std::cout << std::endl;
731   //
732   matcher.pattern(pattern6);
733   matcher.input("");
734   if (matcher.matches())
735     std::cout << "OK";
736   else
737     error("match results");
738   std::cout << std::endl;
739   //
740   matcher.pattern(pattern2);
741   matcher.input("---");
742   if (!matcher.matches())
743     std::cout << "OK";
744   else
745     error("match results");
746   std::cout << std::endl;
747   //
748   banner("DONE");
749   //
750   return 0;
751 }
752