Coverage Report

Created: 2024-05-20 06:23

/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
}