ref: 6ecb4e7a4eda61860545ddff31fded249f536ebd
dir: /jsregexp.c/
#include "jsi.h"
#include "jsvalue.h"
#include "jsbuiltin.h"
#define nelem(a) (sizeof (a) / sizeof (a)[0])
#include <regex.h>
int js_RegExp_prototype_exec(js_State *J, int idx, const char *text)
{
int flags, opts;
regex_t *prog;
regmatch_t m[10];
int i;
prog = js_toregexp(J, idx, &flags);
opts = REG_EXTENDED;
if (flags & JS_REGEXP_I) opts |= REG_ICASE;
if (flags & JS_REGEXP_M) opts |= REG_NEWLINE;
// TODO: global and lastIndex
if (!regexec(prog, text, nelem(m), m, opts)) {
js_newarray(J);
for (i = 0; i < nelem(m) && m[i].rm_so >= 0; ++i) {
js_pushlstring(J, text + m[i].rm_so, m[i].rm_eo - m[i].rm_so);
js_setindex(J, -2, i);
}
return 1;
}
js_pushnull(J);
return 1;
}
void js_newregexp(js_State *J, const char *pattern, int flags)
{
char msg[256];
js_Object *obj;
regex_t *prog;
int opts, status;
obj = jsV_newobject(J, JS_CREGEXP, J->RegExp_prototype);
opts = REG_EXTENDED;
if (flags & JS_REGEXP_I) opts |= REG_ICASE;
if (flags & JS_REGEXP_M) opts |= REG_NEWLINE;
prog = malloc(sizeof (regex_t));
status = regcomp(prog, pattern, opts);
if (status) {
free(prog);
regerror(status, prog, msg, sizeof msg);
js_syntaxerror(J, "%s", msg);
}
obj->u.r.prog = prog;
obj->u.r.flags = flags;
js_pushobject(J, obj);
js_pushstring(J, pattern);
js_defproperty(J, -2, "source", JS_READONLY | JS_DONTENUM | JS_DONTDELETE);
js_pushboolean(J, flags & JS_REGEXP_G);
js_defproperty(J, -2, "global", JS_READONLY | JS_DONTENUM | JS_DONTDELETE);
js_pushboolean(J, flags & JS_REGEXP_I);
js_defproperty(J, -2, "ignoreCase", JS_READONLY | JS_DONTENUM | JS_DONTDELETE);
js_pushboolean(J, flags & JS_REGEXP_M);
js_defproperty(J, -2, "multiline", JS_READONLY | JS_DONTENUM | JS_DONTDELETE);
// TODO: lastIndex
}
static int jsB_new_RegExp(js_State *J, int argc)
{
const char *pattern;
int flags;
if (js_isregexp(J, 1)) {
if (argc > 1)
js_typeerror(J, "cannot supply flags when creating one RegExp from another");
js_toregexp(J, 1, &flags);
js_getproperty(J, 1, "source");
pattern = js_tostring(J, -1);
js_pop(J, 1);
} else if (js_isundefined(J, 1)) {
pattern = "";
flags = 0;
} else {
pattern = js_tostring(J, 1);
flags = 0;
}
if (argc > 1) {
const char *s = js_tostring(J, 2);
int g = 0, i = 0, m = 0;
while (*s) {
if (*s == 'g') ++g;
else if (*s == 'i') ++i;
else if (*s == 'm') ++m;
else js_syntaxerror(J, "invalid regular expression flag: '%c'", *s);
++s;
}
if (g > 1) js_syntaxerror(J, "invalid regular expression flag: 'g'");
if (i > 1) js_syntaxerror(J, "invalid regular expression flag: 'i'");
if (m > 1) js_syntaxerror(J, "invalid regular expression flag: 'm'");
if (g) flags |= JS_REGEXP_G;
if (i) flags |= JS_REGEXP_I;
if (m) flags |= JS_REGEXP_M;
}
js_newregexp(J, pattern, flags);
return 1;
}
static int jsB_RegExp(js_State *J, int argc)
{
if (js_isregexp(J, 1) && argc == 1)
return 1;
return jsB_new_RegExp(J, argc);
}
static int Rp_toString(js_State *J, int argc)
{
const char *source;
int flags;
char *out;
js_Object *self = js_toobject(J, 0);
if (self->type != JS_CREGEXP)
js_typeerror(J, "not a regexp");
flags = self->u.r.flags;
js_getproperty(J, 0, "source");
source = js_tostring(J, -1);
out = malloc(strlen(source) + 6); /* extra space for //gim */
strcpy(out, "/");
strcat(out, source);
strcat(out, "/");
if (flags & JS_REGEXP_G) strcat(out, "g");
if (flags & JS_REGEXP_I) strcat(out, "i");
if (flags & JS_REGEXP_M) strcat(out, "m");
if (js_try(J)) {
free(out);
js_throw(J);
}
js_pop(J, 0);
js_pushstring(J, out);
js_endtry(J);
free(out);
return 1;
}
static int Rp_exec(js_State *J, int argc)
{
return js_RegExp_prototype_exec(J, 0, js_tostring(J, 1));
}
static int Rp_test(js_State *J, int argc)
{
int flags;
regex_t *prog;
const char *text;
prog = js_toregexp(J, 0, &flags);
text = js_tostring(J, 1);
// TODO: global and lastIndex
js_pushboolean(J, !regexec(prog, text, 0, NULL, 0));
return 1;
}
void jsB_initregexp(js_State *J)
{
js_pushobject(J, J->RegExp_prototype);
{
jsB_propf(J, "toString", Rp_toString, 0);
jsB_propf(J, "test", Rp_test, 0);
jsB_propf(J, "exec", Rp_exec, 0);
}
js_newcconstructor(J, jsB_RegExp, jsB_new_RegExp, 1);
js_defglobal(J, "RegExp", JS_DONTENUM);
}