/src/mupdf/thirdparty/mujs/jsregexp.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "jsi.h" |
2 | | #include "regexp.h" |
3 | | |
4 | 0 | static char *escaperegexp(js_State *J, const char *pattern) { |
5 | 0 | char *copy, *p; |
6 | 0 | const char *s; |
7 | 0 | int n = 0; |
8 | 0 | for (s = pattern; *s; ++s) { |
9 | 0 | if (*s == '/') |
10 | 0 | ++n; |
11 | 0 | ++n; |
12 | 0 | } |
13 | 0 | copy = p = js_malloc(J, n+1); |
14 | 0 | for (s = pattern; *s; ++s) { |
15 | 0 | if (*s == '/') |
16 | 0 | *p++ = '\\'; |
17 | 0 | *p++ = *s; |
18 | 0 | } |
19 | 0 | *p = 0; |
20 | 0 | return copy; |
21 | 0 | } |
22 | | |
23 | | static void js_newregexpx(js_State *J, const char *pattern, int flags, int is_clone) |
24 | 0 | { |
25 | 0 | const char *error; |
26 | 0 | js_Object *obj; |
27 | 0 | Reprog *prog; |
28 | 0 | int opts; |
29 | |
|
30 | 0 | obj = jsV_newobject(J, JS_CREGEXP, J->RegExp_prototype); |
31 | |
|
32 | 0 | opts = 0; |
33 | 0 | if (flags & JS_REGEXP_I) opts |= REG_ICASE; |
34 | 0 | if (flags & JS_REGEXP_M) opts |= REG_NEWLINE; |
35 | |
|
36 | 0 | prog = js_regcompx(J->alloc, J->actx, pattern, opts, &error); |
37 | 0 | if (!prog) |
38 | 0 | js_syntaxerror(J, "regular expression: %s", error); |
39 | | |
40 | 0 | obj->u.r.prog = prog; |
41 | 0 | obj->u.r.source = is_clone ? js_strdup(J, pattern) : escaperegexp(J, pattern); |
42 | 0 | obj->u.r.flags = flags; |
43 | 0 | obj->u.r.last = 0; |
44 | 0 | js_pushobject(J, obj); |
45 | 0 | } |
46 | | |
47 | | void js_newregexp(js_State *J, const char *pattern, int flags) |
48 | 0 | { |
49 | 0 | js_newregexpx(J, pattern, flags, 0); |
50 | 0 | } |
51 | | |
52 | | void js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text) |
53 | 0 | { |
54 | 0 | const char *haystack; |
55 | 0 | int result; |
56 | 0 | int i; |
57 | 0 | int opts; |
58 | 0 | Resub m; |
59 | |
|
60 | 0 | haystack = text; |
61 | 0 | opts = 0; |
62 | 0 | if (re->flags & JS_REGEXP_G) { |
63 | 0 | if (re->last > strlen(haystack)) { |
64 | 0 | re->last = 0; |
65 | 0 | js_pushnull(J); |
66 | 0 | return; |
67 | 0 | } |
68 | 0 | if (re->last > 0) { |
69 | 0 | haystack = text + re->last; |
70 | 0 | opts |= REG_NOTBOL; |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | 0 | result = js_regexec(re->prog, haystack, &m, opts); |
75 | 0 | if (result < 0) |
76 | 0 | js_error(J, "regexec failed"); |
77 | 0 | if (result == 0) { |
78 | 0 | js_newarray(J); |
79 | 0 | js_pushstring(J, text); |
80 | 0 | js_setproperty(J, -2, "input"); |
81 | 0 | js_pushnumber(J, js_utfptrtoidx(text, m.sub[0].sp)); |
82 | 0 | js_setproperty(J, -2, "index"); |
83 | 0 | for (i = 0; i < m.nsub; ++i) { |
84 | 0 | js_pushlstring(J, m.sub[i].sp, m.sub[i].ep - m.sub[i].sp); |
85 | 0 | js_setindex(J, -2, i); |
86 | 0 | } |
87 | 0 | if (re->flags & JS_REGEXP_G) |
88 | 0 | re->last = m.sub[0].ep - text; |
89 | 0 | return; |
90 | 0 | } |
91 | | |
92 | 0 | if (re->flags & JS_REGEXP_G) |
93 | 0 | re->last = 0; |
94 | |
|
95 | 0 | js_pushnull(J); |
96 | 0 | } |
97 | | |
98 | | static void Rp_test(js_State *J) |
99 | 0 | { |
100 | 0 | js_Regexp *re; |
101 | 0 | const char *text; |
102 | 0 | int result; |
103 | 0 | int opts; |
104 | 0 | Resub m; |
105 | |
|
106 | 0 | re = js_toregexp(J, 0); |
107 | 0 | text = js_tostring(J, 1); |
108 | |
|
109 | 0 | opts = 0; |
110 | 0 | if (re->flags & JS_REGEXP_G) { |
111 | 0 | if (re->last > strlen(text)) { |
112 | 0 | re->last = 0; |
113 | 0 | js_pushboolean(J, 0); |
114 | 0 | return; |
115 | 0 | } |
116 | 0 | if (re->last > 0) { |
117 | 0 | text += re->last; |
118 | 0 | opts |= REG_NOTBOL; |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | 0 | result = js_regexec(re->prog, text, &m, opts); |
123 | 0 | if (result < 0) |
124 | 0 | js_error(J, "regexec failed"); |
125 | 0 | if (result == 0) { |
126 | 0 | if (re->flags & JS_REGEXP_G) |
127 | 0 | re->last = re->last + (m.sub[0].ep - text); |
128 | 0 | js_pushboolean(J, 1); |
129 | 0 | return; |
130 | 0 | } |
131 | | |
132 | 0 | if (re->flags & JS_REGEXP_G) |
133 | 0 | re->last = 0; |
134 | |
|
135 | 0 | js_pushboolean(J, 0); |
136 | 0 | } |
137 | | |
138 | | static void jsB_new_RegExp(js_State *J) |
139 | 0 | { |
140 | 0 | js_Regexp *old; |
141 | 0 | const char *pattern; |
142 | 0 | int flags; |
143 | 0 | int is_clone = 0; |
144 | |
|
145 | 0 | if (js_isregexp(J, 1)) { |
146 | 0 | if (js_isdefined(J, 2)) |
147 | 0 | js_typeerror(J, "cannot supply flags when creating one RegExp from another"); |
148 | 0 | old = js_toregexp(J, 1); |
149 | 0 | pattern = old->source; |
150 | 0 | flags = old->flags; |
151 | 0 | is_clone = 1; |
152 | 0 | } else if (js_isundefined(J, 1)) { |
153 | 0 | pattern = "(?:)"; |
154 | 0 | flags = 0; |
155 | 0 | } else { |
156 | 0 | pattern = js_tostring(J, 1); |
157 | 0 | flags = 0; |
158 | 0 | } |
159 | | |
160 | 0 | if (strlen(pattern) == 0) |
161 | 0 | pattern = "(?:)"; |
162 | |
|
163 | 0 | if (js_isdefined(J, 2)) { |
164 | 0 | const char *s = js_tostring(J, 2); |
165 | 0 | int g = 0, i = 0, m = 0; |
166 | 0 | while (*s) { |
167 | 0 | if (*s == 'g') ++g; |
168 | 0 | else if (*s == 'i') ++i; |
169 | 0 | else if (*s == 'm') ++m; |
170 | 0 | else js_syntaxerror(J, "invalid regular expression flag: '%c'", *s); |
171 | 0 | ++s; |
172 | 0 | } |
173 | 0 | if (g > 1) js_syntaxerror(J, "invalid regular expression flag: 'g'"); |
174 | 0 | if (i > 1) js_syntaxerror(J, "invalid regular expression flag: 'i'"); |
175 | 0 | if (m > 1) js_syntaxerror(J, "invalid regular expression flag: 'm'"); |
176 | 0 | if (g) flags |= JS_REGEXP_G; |
177 | 0 | if (i) flags |= JS_REGEXP_I; |
178 | 0 | if (m) flags |= JS_REGEXP_M; |
179 | 0 | } |
180 | | |
181 | 0 | js_newregexpx(J, pattern, flags, is_clone); |
182 | 0 | } |
183 | | |
184 | | static void jsB_RegExp(js_State *J) |
185 | 0 | { |
186 | 0 | if (js_isregexp(J, 1)) |
187 | 0 | return; |
188 | 0 | jsB_new_RegExp(J); |
189 | 0 | } |
190 | | |
191 | | static void Rp_toString(js_State *J) |
192 | 0 | { |
193 | 0 | js_Regexp *re; |
194 | 0 | char * volatile out = NULL; |
195 | |
|
196 | 0 | re = js_toregexp(J, 0); |
197 | |
|
198 | 0 | if (js_try(J)) { |
199 | 0 | js_free(J, out); |
200 | 0 | js_throw(J); |
201 | 0 | } |
202 | | |
203 | 0 | out = js_malloc(J, strlen(re->source) + 6); /* extra space for //gim */ |
204 | 0 | strcpy(out, "/"); |
205 | 0 | strcat(out, re->source); |
206 | 0 | strcat(out, "/"); |
207 | 0 | if (re->flags & JS_REGEXP_G) strcat(out, "g"); |
208 | 0 | if (re->flags & JS_REGEXP_I) strcat(out, "i"); |
209 | 0 | if (re->flags & JS_REGEXP_M) strcat(out, "m"); |
210 | |
|
211 | 0 | js_pop(J, 0); |
212 | 0 | js_pushstring(J, out); |
213 | 0 | js_endtry(J); |
214 | 0 | js_free(J, out); |
215 | 0 | } |
216 | | |
217 | | static void Rp_exec(js_State *J) |
218 | 0 | { |
219 | 0 | js_RegExp_prototype_exec(J, js_toregexp(J, 0), js_tostring(J, 1)); |
220 | 0 | } |
221 | | |
222 | | void jsB_initregexp(js_State *J) |
223 | 0 | { |
224 | 0 | js_pushobject(J, J->RegExp_prototype); |
225 | 0 | { |
226 | 0 | jsB_propf(J, "RegExp.prototype.toString", Rp_toString, 0); |
227 | 0 | jsB_propf(J, "RegExp.prototype.test", Rp_test, 0); |
228 | 0 | jsB_propf(J, "RegExp.prototype.exec", Rp_exec, 0); |
229 | 0 | } |
230 | 0 | js_newcconstructor(J, jsB_RegExp, jsB_new_RegExp, "RegExp", 1); |
231 | 0 | js_defglobal(J, "RegExp", JS_DONTENUM); |
232 | 0 | } |