From 2ac601d07e226f0243125f2079c7af041b74fa6f Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Thu, 20 Feb 2014 15:07:37 +0100 Subject: [PATCH] Prepare for regular expression library. Wrap the posix regex calls with the desired API. --- Makefile | 4 +-- jsgc.c | 8 +++--- jsregexp.c | 35 +++++++++++-------------- jsstring.c | 76 +++++++++++++++++++++++++++--------------------------- regex.c | 45 ++++++++++++++++++++++++++++++++ regex.h | 16 ++++++++++++ 6 files changed, 119 insertions(+), 65 deletions(-) create mode 100644 regex.c create mode 100644 regex.h diff --git a/Makefile b/Makefile index 861e3d9..e931b78 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -SRCS := $(wildcard js*.c utf*.c) -HDRS := $(wildcard js*.h utf.h) +SRCS := $(wildcard js*.c utf*.c regex.c) +HDRS := $(wildcard js*.h utf.h regex.h) OBJS := $(SRCS:%.c=build/%.o) CFLAGS = -Wall -g diff --git a/jsgc.c b/jsgc.c index 1906518..da08d3e 100644 --- a/jsgc.c +++ b/jsgc.c @@ -3,7 +3,7 @@ #include "jsvalue.h" #include "jsrun.h" -#include +#include "regex.h" static void jsG_markobject(js_State *J, int mark, js_Object *obj); @@ -44,10 +44,8 @@ static void jsG_freeobject(js_State *J, js_Object *obj) { if (obj->head) jsG_freeproperty(J, obj->head); - if (obj->type == JS_CREGEXP) { - regfree(obj->u.r.prog); - free(obj->u.r.prog); - } + if (obj->type == JS_CREGEXP) + js_regfree(obj->u.r.prog); if (obj->type == JS_CITERATOR) jsG_freeiterator(J, obj->u.iter.head); free(obj); diff --git a/jsregexp.c b/jsregexp.c index c1a1270..021b22f 100644 --- a/jsregexp.c +++ b/jsregexp.c @@ -1,17 +1,16 @@ #include "jsi.h" #include "jsvalue.h" #include "jsbuiltin.h" +#include "regex.h" #define nelem(a) (sizeof (a) / sizeof (a)[0]) -#include - void js_newregexp(js_State *J, const char *pattern, int flags) { - char msg[256]; + const char *error; js_Object *obj; - regex_t *prog; - int opts, status; + Reprog *prog; + int opts; obj = jsV_newobject(J, JS_CREGEXP, J->RegExp_prototype); @@ -19,13 +18,9 @@ void js_newregexp(js_State *J, const char *pattern, int flags) 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); - } + prog = js_regcomp(pattern, opts, &error); + if (!prog) + js_syntaxerror(J, "regular expression: %s", error); obj->u.r.prog = prog; obj->u.r.source = pattern; @@ -36,7 +31,7 @@ void js_newregexp(js_State *J, const char *pattern, int flags) int js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text) { - regmatch_t m[10]; + Resub m[10]; int opts; int i; @@ -53,14 +48,14 @@ int js_RegExp_prototype_exec(js_State *J, js_Regexp *re, const char *text) } } - if (!regexec(re->prog, text, nelem(m), m, opts)) { + if (!js_regexec(re->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); + for (i = 0; i < nelem(m) && m[i].sp; ++i) { + js_pushlstring(J, m[i].sp, m[i].ep - m[i].sp); js_setindex(J, -2, i); } if (re->flags & JS_REGEXP_G) - re->last = re->last + m[0].rm_eo; + re->last = re->last + (m[0].ep - text); return 1; } @@ -75,7 +70,7 @@ static int Rp_test(js_State *J, int argc) { js_Regexp *re; const char *text; - regmatch_t m[10]; + Resub m[10]; int opts; re = js_toregexp(J, 0); @@ -94,9 +89,9 @@ static int Rp_test(js_State *J, int argc) } } - if (!regexec(re->prog, text, nelem(m), m, opts)) { + if (!js_regexec(re->prog, text, nelem(m), m, opts)) { if (re->flags & JS_REGEXP_G) - re->last = re->last + m[0].rm_eo; + re->last = re->last + (m[0].ep - text); js_pushboolean(J, 1); return 1; } diff --git a/jsstring.c b/jsstring.c index f614f7b..9b28020 100644 --- a/jsstring.c +++ b/jsstring.c @@ -2,8 +2,7 @@ #include "jsvalue.h" #include "jsbuiltin.h" #include "utf.h" - -#include +#include "regex.h" #define nelem(a) (sizeof (a) / sizeof (a)[0]) @@ -323,9 +322,10 @@ static int S_fromCharCode(js_State *J, int argc) static int Sp_match(js_State *J, int argc) { js_Regexp *re; - regmatch_t m[10]; + Resub m[10]; const char *text; - unsigned int len, a, b, c, e; + unsigned int len; + const char *a, *b, *c, *e; text = js_tostring(J, 0); @@ -344,17 +344,17 @@ static int Sp_match(js_State *J, int argc) js_newarray(J); - e = strlen(text); len = 0; - a = 0; + a = text; + e = text + strlen(text); while (a <= e) { - if (regexec(re->prog, text + a, nelem(m), m, a > 0 ? REG_NOTBOL : 0)) + if (js_regexec(re->prog, a, nelem(m), m, a > text ? REG_NOTBOL : 0)) break; - b = a + m[0].rm_so; - c = a + m[0].rm_eo; + b = m[0].sp; + c = m[0].ep; - js_pushlstring(J, text + b, c - b); + js_pushlstring(J, b, c - b); js_setindex(J, -2, len++); a = c; @@ -368,7 +368,7 @@ static int Sp_match(js_State *J, int argc) static int Sp_search(js_State *J, int argc) { js_Regexp *re; - regmatch_t m[10]; + Resub m[10]; const char *text; text = js_tostring(J, 0); @@ -382,8 +382,8 @@ static int Sp_search(js_State *J, int argc) re = js_toregexp(J, -1); - if (!regexec(re->prog, text, nelem(m), m, 0)) - js_pushnumber(J, js_utfptrtoidx(text, text + m[0].rm_so)); + if (!js_regexec(re->prog, text, nelem(m), m, 0)) + js_pushnumber(J, js_utfptrtoidx(text, m[0].sp)); else js_pushnumber(J, -1); @@ -393,7 +393,7 @@ static int Sp_search(js_State *J, int argc) static int Sp_replace_regexp(js_State *J, int argc) { js_Regexp *re; - regmatch_t m[10]; + Resub m[10]; const char *source, *s, *r; js_Buffer *sb = NULL; int n, x; @@ -401,7 +401,7 @@ static int Sp_replace_regexp(js_State *J, int argc) source = js_tostring(J, 0); re = js_toregexp(J, 1); - if (regexec(re->prog, source, nelem(m), m, 0)) { + if (js_regexec(re->prog, source, nelem(m), m, 0)) { js_copy(J, 0); return 1; } @@ -409,14 +409,14 @@ static int Sp_replace_regexp(js_State *J, int argc) re->last = 0; loop: - s = source + m[0].rm_so; - n = m[0].rm_eo - m[0].rm_so; + s = m[0].sp; + n = m[0].ep - m[0].sp; if (js_iscallable(J, 2)) { js_copy(J, 2); js_pushglobal(J); - for (x = 0; m[x].rm_so >= 0; ++x) /* arg 0..x: substring and subexps that matched */ - js_pushlstring(J, source + m[x].rm_so, m[x].rm_eo - m[x].rm_so); + for (x = 0; m[x].sp; ++x) /* arg 0..x: substring and subexps that matched */ + js_pushlstring(J, m[x].sp, m[x].ep - m[x].sp); js_pushnumber(J, s - source); /* arg x+2: offset within search string */ js_copy(J, 0); /* arg x+3: search string */ js_call(J, 2 + x); @@ -439,8 +439,8 @@ loop: case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': x = *r - '0'; - if (m[x].rm_so >= 0) { - sb_putm(&sb, source + m[x].rm_so, source + m[x].rm_eo); + if (m[x].sp) { + sb_putm(&sb, m[x].sp, m[x].ep); } else { sb_putc(&sb, '$'); sb_putc(&sb, '0'+x); @@ -459,14 +459,14 @@ loop: } if (re->flags & JS_REGEXP_G) { - source = source + m[0].rm_eo; + source = m[0].ep; if (n == 0) { if (*source) sb_putc(&sb, *source++); else goto end; } - if (!regexec(re->prog, source, nelem(m), m, REG_NOTBOL)) + if (!js_regexec(re->prog, source, nelem(m), m, REG_NOTBOL)) goto loop; } @@ -554,23 +554,23 @@ static int Sp_replace(js_State *J, int argc) static int Sp_split_regexp(js_State *J, int argc) { js_Regexp *re; - regmatch_t m[10]; - const char *str; - unsigned int limit, len, k, e; - unsigned int p, a, b, c; + Resub m[10]; + const char *text; + unsigned int limit, len, k; + const char *p, *a, *b, *c, *e; - str = js_tostring(J, 0); + text = js_tostring(J, 0); re = js_toregexp(J, 1); limit = js_isdefined(J, 2) ? js_touint32(J, 2) : 1 << 30; js_newarray(J); len = 0; - e = strlen(str); + e = text + strlen(text); /* splitting the empty string */ if (e == 0) { - if (regexec(re->prog, str, nelem(m), m, 0)) { + if (js_regexec(re->prog, text, nelem(m), m, 0)) { if (len == limit) return 1; js_pushliteral(J, ""); js_setindex(J, -2, 0); @@ -578,13 +578,13 @@ static int Sp_split_regexp(js_State *J, int argc) return 1; } - p = a = 0; + p = a = text; while (a < e) { - if (regexec(re->prog, str + a, nelem(m), m, a > 0 ? REG_NOTBOL : 0)) + if (js_regexec(re->prog, a, nelem(m), m, a > text ? REG_NOTBOL : 0)) break; /* no match */ - b = a + m[0].rm_so; - c = a + m[0].rm_eo; + b = m[0].sp; + c = m[0].ep; /* empty string at end of last match */ if (b == p) { @@ -593,12 +593,12 @@ static int Sp_split_regexp(js_State *J, int argc) } if (len == limit) return 1; - js_pushlstring(J, str + p, b - p); + js_pushlstring(J, p, b - p); js_setindex(J, -2, len++); - for (k = 1; k < nelem(m) && m[k].rm_so >= 0; ++k) { + for (k = 1; k < nelem(m) && m[k].sp; ++k) { if (len == limit) return 1; - js_pushlstring(J, str + a + m[k].rm_so, m[k].rm_eo - m[k].rm_so); + js_pushlstring(J, m[k].sp, m[k].ep - m[k].sp); js_setindex(J, -2, len++); } @@ -606,7 +606,7 @@ static int Sp_split_regexp(js_State *J, int argc) } if (len == limit) return 1; - js_pushstring(J, str + p); + js_pushstring(J, p); js_setindex(J, -2, len); return 1; diff --git a/regex.c b/regex.c new file mode 100644 index 0000000..dff1ab4 --- /dev/null +++ b/regex.c @@ -0,0 +1,45 @@ +#include +#include "regex.h" + +Reprog *js_regcomp(const char *pattern, int cflags, const char **errorp) +{ + static char msg[256]; + regex_t *prog = malloc(sizeof *prog); + int status = regcomp(prog, pattern, cflags); + if (status) { + free(prog); + if (errorp) { + regerror(status, prog, msg, sizeof msg); + *errorp = msg; + } + return NULL; + } + if (errorp) + *errorp = NULL; + return (Reprog*)prog; +} + +int js_regexec(Reprog *prog, const char *string, int nmatch, Resub *pmatch, int eflags) +{ + regmatch_t m[10]; + int i, status; + status = regexec((regex_t*)prog, string, 10, m, eflags); + for (i = 0; i < nmatch; ++i) { + if (m[i].rm_so >= 0) { + pmatch[i].sp = string + m[i].rm_so; + pmatch[i].ep = string + m[i].rm_eo; + } else { + pmatch[i].sp = NULL; + pmatch[i].ep = NULL; + } + } + return status; +} + +void js_regfree(Reprog *prog) +{ + if (prog) { + regfree((regex_t*)prog); + free(prog); + } +} diff --git a/regex.h b/regex.h new file mode 100644 index 0000000..7a6d891 --- /dev/null +++ b/regex.h @@ -0,0 +1,16 @@ +#ifndef regex_h +#define regex_h + +#include + +typedef struct Reprog Reprog; +typedef struct { + const char *sp; + const char *ep; +} Resub; + +Reprog *js_regcomp(const char *pattern, int cflags, const char **errorp); +int js_regexec(Reprog *prog, const char *string, int nmatch, Resub *pmatch, int eflags); +void js_regfree(Reprog *prog); + +#endif