1 /*
2  * callout.c
3  */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include "oniguruma.h"
8 
9 static int
callout_body(OnigCalloutArgs * args,void * user_data)10 callout_body(OnigCalloutArgs* args, void* user_data)
11 {
12   int r;
13   int i;
14   int n;
15   int begin, end;
16   int used_num;
17   int used_bytes;
18   OnigCalloutIn in;
19   int name_id;
20   const UChar* contents;
21   const UChar* start;
22   const UChar* current;
23   regex_t* regex;
24 
25   in            = onig_get_callout_in_by_callout_args(args);
26   name_id       = onig_get_name_id_by_callout_args(args);
27   start         = onig_get_start_by_callout_args(args);
28   current       = onig_get_current_by_callout_args(args);
29   regex         = onig_get_regex_by_callout_args(args);
30 
31   contents = onig_get_contents_by_callout_args(args);
32 
33   if (name_id != ONIG_NON_NAME_ID) {
34     UChar* name = onig_get_callout_name_by_name_id(name_id);
35     fprintf(stdout, "name: %s\n", name);
36   }
37   fprintf(stdout,
38           "%s %s: contents: \"%s\", start: \"%s\", current: \"%s\"\n",
39           contents != 0 ? "CONTENTS" : "NAME",
40           in == ONIG_CALLOUT_IN_PROGRESS ? "PROGRESS" : "RETRACTION",
41           contents, start, current);
42 
43   fprintf(stdout, "user_data: %s\n", (char* )user_data);
44 
45   (void )onig_get_used_stack_size_in_callout(args, &used_num, &used_bytes);
46   fprintf(stdout, "stack: used_num: %d, used_bytes: %d\n", used_num, used_bytes);
47 
48   n = onig_number_of_captures(regex);
49   for (i = 1; i <= n; i++) {
50     r = onig_get_capture_range_in_callout(args, i, &begin, &end);
51     if (r != ONIG_NORMAL) return r;
52 
53     fprintf(stdout, "capture %d: (%d-%d)\n", i, begin, end);
54   }
55 
56   fflush(stdout);
57   return ONIG_CALLOUT_SUCCESS;
58 }
59 
60 static int
progress_callout_func(OnigCalloutArgs * args,void * user_data)61 progress_callout_func(OnigCalloutArgs* args, void* user_data)
62 {
63   return callout_body(args, user_data);
64 }
65 
66 static int
retraction_callout_func(OnigCalloutArgs * args,void * user_data)67 retraction_callout_func(OnigCalloutArgs* args, void* user_data)
68 {
69   return callout_body(args, user_data);
70 }
71 
72 static int
foo(OnigCalloutArgs * args,void * user_data)73 foo(OnigCalloutArgs* args, void* user_data)
74 {
75   return callout_body(args, user_data);
76 }
77 
78 static int
bar(OnigCalloutArgs * args,void * user_data)79 bar(OnigCalloutArgs* args, void* user_data)
80 {
81   int r;
82   int i;
83   int n;
84   OnigType type;
85   OnigValue val;
86 
87   fprintf(stdout, "bar called.\n");
88 
89   n = onig_get_args_num_by_callout_args(args);
90   if (n < 0) {
91     fprintf(stderr, "FAIL: onig_get_args_num_by_callout_args(): %d\n", n);
92     return n;
93   }
94 
95   for (i = 0; i < n; i++) {
96     r = onig_get_arg_by_callout_args(args, i, &type, &val);
97     if (r != 0) {
98       fprintf(stderr, "FAIL: onig_get_arg_by_callout_args(): %d\n", r);
99       return r;
100     }
101 
102     fprintf(stdout, "arg[%d]: ", i);
103     switch (type) {
104     case ONIG_TYPE_LONG:
105       fprintf(stdout, "%ld\n", val.l);
106       break;
107     case ONIG_TYPE_CHAR:
108       fprintf(stdout, "0x%06x\n", val.c);
109       break;
110     case ONIG_TYPE_STRING:
111       fprintf(stdout, "'%s'\n", val.s.start);
112       break;
113     default:
114       /* Never come here. But escape warning. */
115       break;
116     };
117   }
118 
119   return ONIG_CALLOUT_SUCCESS;
120 }
121 
122 static int
test(OnigEncoding enc,OnigMatchParam * mp,char * in_pattern,char * in_str)123 test(OnigEncoding enc, OnigMatchParam* mp, char* in_pattern, char* in_str)
124 {
125   int r;
126   unsigned char *start, *range, *end;
127   regex_t* reg;
128   OnigErrorInfo einfo;
129   OnigRegion *region;
130   UChar* pattern;
131   UChar* str;
132 
133   pattern = (UChar* )in_pattern;
134   str = (UChar* )in_str;
135 
136   r = onig_new(&reg, pattern, pattern + strlen((char* )pattern),
137                ONIG_OPTION_DEFAULT, enc, ONIG_SYNTAX_DEFAULT, &einfo);
138   if (r != ONIG_NORMAL) {
139     char s[ONIG_MAX_ERROR_MESSAGE_LEN];
140     onig_error_code_to_str((UChar* )s, r, &einfo);
141     fprintf(stderr, "COMPILE ERROR: %d: %s\n", r, s);
142     return -1;
143   }
144 
145   region = onig_region_new();
146 
147   end   = str + strlen((char* )str);
148   start = str;
149   range = end;
150   r = onig_search_with_param(reg, str, end, start, range, region,
151                              ONIG_OPTION_NONE, mp);
152   if (r >= 0) {
153     int i;
154 
155     fprintf(stderr, "match at %d\n", r);
156     for (i = 0; i < region->num_regs; i++) {
157       fprintf(stderr, "%d: (%d-%d)\n", i, region->beg[i], region->end[i]);
158     }
159   }
160   else if (r == ONIG_MISMATCH) {
161     fprintf(stderr, "search fail\n");
162   }
163   else { /* error */
164     char s[ONIG_MAX_ERROR_MESSAGE_LEN];
165     onig_error_code_to_str((UChar* )s, r);
166     fprintf(stderr, "SEARCH ERROR: %d: %s\n", r, s);
167   }
168 
169   onig_region_free(region, 1 /* 1:free self, 0:free contents only */);
170   onig_free(reg);
171   return r;
172 }
173 
main(int argc,char * argv[])174 extern int main(int argc, char* argv[])
175 {
176   int r;
177   int id;
178   void* user_data;
179   UChar* name;
180   OnigEncoding use_encs[1];
181   unsigned int arg_types[4];
182   OnigValue opt_defaults[4];
183   OnigEncoding enc;
184   OnigMatchParam* mp;
185 
186   enc = ONIG_ENCODING_UTF8;
187   use_encs[0] = enc;
188 
189   r = onig_initialize(use_encs, sizeof(use_encs)/sizeof(use_encs[0]));
190   if (r != ONIG_NORMAL) return -1;
191 
192   /* monitor on */
193   r = onig_setup_builtin_monitors_by_ascii_encoded_name(stdout);
194   if (r != ONIG_NORMAL) return -1;
195 
196   name = (UChar* )"foo";
197   id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,
198                                 name, name + strlen((char* )name),
199                                 ONIG_CALLOUT_IN_BOTH, foo, 0, 0, 0, 0, 0);
200   if (id < 0) {
201     fprintf(stderr, "ERROR: fail to set callout of name: %s\n", name);
202     //return -1;
203   }
204 
205   name = (UChar* )"bar";
206   arg_types[0] = ONIG_TYPE_LONG;
207   arg_types[1] = ONIG_TYPE_STRING;
208   arg_types[2] = ONIG_TYPE_CHAR;
209   opt_defaults[0].s.start = (UChar* )"I am a option argument's default value.";
210   opt_defaults[0].s.end   = opt_defaults[0].s.start +
211                                 strlen((char* )opt_defaults[0].s.start);
212   opt_defaults[1].c = 0x4422;
213 
214   id = onig_set_callout_of_name(enc, ONIG_CALLOUT_TYPE_SINGLE,
215                                 name, name + strlen((char* )name),
216                                 ONIG_CALLOUT_IN_PROGRESS, bar, 0,
217                                 3, arg_types, 2, opt_defaults);
218   if (id < 0) {
219     fprintf(stderr, "ERROR: fail to set callout of name: %s\n", name);
220     //return -1;
221   }
222 
223   (void)onig_set_progress_callout(progress_callout_func);
224   (void)onig_set_retraction_callout(retraction_callout_func);
225 
226   mp = onig_new_match_param();
227 
228   user_data = (void* )"something data";
229   r = onig_set_callout_user_data_of_match_param(mp, user_data);
230   if (r != ONIG_NORMAL) {
231     fprintf(stderr, "ERROR: fail onig_set_callout_user_data_of_match_param(): %d\n", r);
232   }
233 
234   /* callout of contents */
235   test(enc, mp, "a+(?{foo bar baz...}X)$", "aaab");
236   test(enc, mp, "(?{{!{}#$%&'()=-~^|[_]`@*:+;<>?/.\\,}}[symbols])c", "abc");
237   test(enc, mp, "\\A(...)(?{{{booooooooooooo{{ooo}}ooooooooooz}}}<)", "aaab");
238   test(enc, mp, "\\A(?!a(?{in prec-read-not}[xxx]X)b)", "ac");
239   test(enc, mp, "(?<!a(?{in look-behind-not}X)c)c", "abc");
240 
241   // callout of name
242   test(enc, mp, "\\A(*foo)abc", "abc");
243   test(enc, mp, "abc(?:(*FAIL)|$)", "abcabc");
244   test(enc, mp, "abc(?:$|(*MISMATCH)|abc$)", "abcabc");
245   test(enc, mp, "abc(?:(*ERROR)|$)", "abcabc");
246   test(enc, mp, "ab(*foo{})(*FAIL)", "abc");
247   test(enc, mp, "abc(d|(*ERROR{-999}))", "abc");
248   test(enc, mp, "ab(*bar{372,I am a bar's argument,あ})c(*FAIL)", "abc");
249   test(enc, mp, "ab(*bar{1234567890})", "abc");
250   test(enc, mp, "(?:a(*MAX{2})|b)*", "abbabbabbabb");
251   test(enc, mp, "(?:(*MAX{2})a|b)*", "abbabbabbabb");
252   test(enc, mp, "(?:(*MAX{1})a|b)*", "bbbbbabbbbbabbbbb");
253   test(enc, mp, "(?:(*MAX{3})a|(*MAX{4})b)*", "bbbaabbab");
254   test(enc, mp, "(?:(*MAX[A]{3})a|(*MAX[B]{5})b)*(*CMP{A,<,B})", "abababc");
255   test(enc, mp, "(?:(*MAX[A]{7})a|(*MAX[B]{5})b)*(*CMP{A,>=,4})", "abababcabababaa");
256   test(enc, mp, "(?:(*MAX[T]{3})a)*(?:(*MAX{T})c)*", "aaccc");
257 
258   /* callouts in condition */
259   test(enc, mp, "\\A(?(?{in condition})then|else)\\z", "then");
260   test(enc, mp, "\\A(?(*FAIL)then|else)\\z", "else");
261 
262   /* monitor test */
263   test(enc, mp, "(?:(*MON{X})(*FAIL)|.{,3}(*MON[FOO])k)", "abcdefghijk");
264 
265   onig_free_match_param(mp);
266   onig_end();
267   return 0;
268 }
269