mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +00:00
Created gib_regex.[ch] to manage regular expressions in GIB. Regexs are
now cached and only recompiled when compile flags change. Changed regex builtins to take an options string argument after the regular expression.
This commit is contained in:
parent
1251cbda9e
commit
854f6d9054
6 changed files with 252 additions and 90 deletions
|
@ -4,9 +4,10 @@ includedir = $(prefix)/include/QF
|
|||
include_HEADERS = bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \
|
||||
console.h crc.h csqc.h cvar.h dstring.h draw.h gcc_attr.h gib_buffer.h \
|
||||
gib_builtin.h gib_function.h gib_init.h gib_parse.h gib_process.h \
|
||||
gib_thread.h gib_vars.h hash.h hl.h idparse.h in_event.h info.h input.h \
|
||||
joystick.h keys.h link.h locs.h mathlib.h mdfour.h model.h modelgen.h \
|
||||
msg.h pak.h pakfile.h pcx.h plugin.h pr_comp.h pr_debug.h pr_obj.h \
|
||||
progs.h qargs.h qdefs.h qendian.h qfplist.h qtypes.h quakefs.h quakeio.h \
|
||||
render.h screen.h sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h \
|
||||
texture.h tga.h uint32.h va.h ver_check.h vid.h wad.h zone.h
|
||||
gib_regex.h gib_thread.h gib_vars.h hash.h hl.h idparse.h in_event.h \
|
||||
info.h input.h joystick.h keys.h link.h locs.h mathlib.h mdfour.h \
|
||||
model.h modelgen.h msg.h pak.h pakfile.h pcx.h plugin.h pr_comp.h \
|
||||
pr_debug.h pr_obj.h progs.h qargs.h qdefs.h qendian.h qfplist.h \
|
||||
qtypes.h quakefs.h quakeio.h render.h screen.h sizebuf.h skin.h \
|
||||
sound.h spritegn.h sys.h teamplay.h texture.h tga.h uint32.h va.h \
|
||||
ver_check.h vid.h wad.h zone.h
|
||||
|
|
45
include/QF/gib_regex.h
Normal file
45
include/QF/gib_regex.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
#FILENAME#
|
||||
|
||||
#DESCRIPTION#
|
||||
|
||||
Copyright (C) 2002 #AUTHOR#
|
||||
|
||||
Author: #AUTHOR#
|
||||
Date: #DATE#
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
$Id$
|
||||
|
||||
*/
|
||||
|
||||
#include "regex.h"
|
||||
|
||||
typedef struct gib_regex_s {
|
||||
char *regex;
|
||||
regex_t comp;
|
||||
int cflags;
|
||||
} gib_regex_t;
|
||||
|
||||
void GIB_Regex_Init (void);
|
||||
regex_t *GIB_Regex_Compile (const char *regex, int cflags);
|
||||
const char *GIB_Regex_Error (void);
|
||||
int GIB_Regex_Translate_Options (const char *opstr);
|
||||
unsigned int GIB_Regex_Apply_Match (regmatch_t match[10], dstring_t *dstr, unsigned int ofs, const char *replace);
|
|
@ -7,4 +7,4 @@ lib_LTLIBRARIES= libQFgib.la
|
|||
libQFgib_la_LDFLAGS= -version-info 1:0:0
|
||||
libQFgib_la_SOURCES= \
|
||||
gib_buffer.c gib_builtin.c gib_function.c gib_parse.c gib_process.c \
|
||||
gib_thread.c gib_vars.c gib_init.c ops.c exp.c regex.c
|
||||
gib_regex.c gib_thread.c gib_vars.c gib_init.c ops.c exp.c regex.c
|
||||
|
|
|
@ -58,6 +58,7 @@ static const char rcsid[] =
|
|||
#include "QF/gib_buffer.h"
|
||||
#include "QF/gib_function.h"
|
||||
#include "QF/gib_vars.h"
|
||||
#include "QF/gib_regex.h"
|
||||
#include "QF/gib_thread.h"
|
||||
#include "regex.h"
|
||||
|
||||
|
@ -496,126 +497,66 @@ GIB_String_Findsub_f (void)
|
|||
GIB_Return ("-1");
|
||||
}
|
||||
|
||||
inline unsigned int
|
||||
GIB_Regex_Apply_Match (regmatch_t match[10], dstring_t *dstr, unsigned int ofs, const char *replace)
|
||||
{
|
||||
int i, start, len, sub, rlen = strlen(replace);
|
||||
char *matched;
|
||||
|
||||
start = match[0].rm_so+ofs;
|
||||
len = match[0].rm_eo - match[0].rm_so;
|
||||
|
||||
// Save matched pattern space
|
||||
matched = calloc (len + 1, sizeof(char));
|
||||
memcpy (matched, dstr->str+start, match[0].rm_eo - match[0].rm_so);
|
||||
|
||||
dstring_replace (dstr, start, len, replace, rlen);
|
||||
for (i = start; i < start+rlen; i++) {
|
||||
if (dstr->str[i] == '\\') {
|
||||
if (dstr->str[i+1] == '&') {
|
||||
dstring_snip (dstr, i, 1);
|
||||
rlen--;
|
||||
continue;
|
||||
}
|
||||
if (isdigit ((byte) dstr->str[i+1])) {
|
||||
if (i && dstr->str[i-1] == '\\') { // Escaped, not a true back reference
|
||||
dstring_snip (dstr, i, 1);
|
||||
rlen--;
|
||||
continue;
|
||||
}
|
||||
sub = dstr->str[i+1] - '0';
|
||||
if (match[sub].rm_so != -1) {
|
||||
dstring_replace (dstr, i, 2, matched+match[sub].rm_so, match[sub].rm_eo - match[sub].rm_so);
|
||||
rlen += match[sub].rm_eo - match[sub].rm_so - 2;
|
||||
} else {
|
||||
dstring_snip (dstr, i, 2);
|
||||
rlen -= 2;
|
||||
}
|
||||
}
|
||||
} else if (dstr->str[i] == '&') {
|
||||
dstring_replace (dstr, i, 1, matched, len);
|
||||
rlen += strlen(matched) - 1;
|
||||
}
|
||||
}
|
||||
free (matched);
|
||||
return rlen + match[0].rm_so;
|
||||
}
|
||||
|
||||
void
|
||||
GIB_Regex_Match_f (void)
|
||||
{
|
||||
regex_t *reg;
|
||||
int res;
|
||||
char errbuf[1024];
|
||||
|
||||
if (GIB_Argc() != 3) {
|
||||
GIB_USAGE ("string regex");
|
||||
if (GIB_Argc() != 4) {
|
||||
GIB_USAGE ("string regex options");
|
||||
return;
|
||||
}
|
||||
|
||||
reg = calloc (1, sizeof (regex_t));
|
||||
|
||||
if ((res = regcomp(reg, GIB_Argv(2), REG_NOSUB | REG_EXTENDED))) {
|
||||
regerror(res, reg, errbuf, sizeof(errbuf));
|
||||
Cbuf_Error ("regex", "%s: %s", GIB_Argv(0), errbuf);
|
||||
} else if (regexec(reg, GIB_Argv(1), 0, 0, 0))
|
||||
if (!(reg = GIB_Regex_Compile (GIB_Argv(2), REG_EXTENDED | GIB_Regex_Translate_Options (GIB_Argv(3)))))
|
||||
Cbuf_Error ("regex", "%s: %s", GIB_Argv(0), GIB_Regex_Error ());
|
||||
else if (regexec(reg, GIB_Argv(1), 0, 0, 0))
|
||||
GIB_Return ("0");
|
||||
else
|
||||
GIB_Return ("1");
|
||||
regfree (reg);
|
||||
free (reg);
|
||||
}
|
||||
|
||||
void
|
||||
GIB_Regex_Replace_f (void)
|
||||
{
|
||||
regex_t *reg;
|
||||
int res, ofs, len;//, e;
|
||||
char errbuf[1024];
|
||||
int ofs, len;//, e;
|
||||
regmatch_t match[10];
|
||||
|
||||
if (GIB_Argc() < 4 || GIB_Argc() > 5) {
|
||||
GIB_USAGE ("string regex replacement [options]");
|
||||
if (GIB_Argc() != 5) {
|
||||
GIB_USAGE ("string regex options replacement");
|
||||
return;
|
||||
}
|
||||
|
||||
ofs = 0;
|
||||
len = strlen (GIB_Argv(3));
|
||||
reg = calloc (1, sizeof (regex_t));
|
||||
len = strlen (GIB_Argv(4));
|
||||
|
||||
if ((res = regcomp(reg, GIB_Argv(2), REG_EXTENDED))) {
|
||||
regerror(res, reg, errbuf, sizeof(errbuf));
|
||||
Cbuf_Error ("regex", "%s: %s", GIB_Argv(0), errbuf);
|
||||
} else while (!regexec(reg, GIB_Argv(1)+ofs, 10, match, ofs > 0 ? REG_NOTBOL : 0) && match[0].rm_eo) {
|
||||
|
||||
ofs += GIB_Regex_Apply_Match (match, GIB_Argd(1), ofs, GIB_Argv(3));
|
||||
}
|
||||
regfree (reg);
|
||||
free (reg);
|
||||
if (!(reg = GIB_Regex_Compile (GIB_Argv(2), REG_EXTENDED | GIB_Regex_Translate_Options (GIB_Argv(3)))))
|
||||
Cbuf_Error ("regex", "%s: %s", GIB_Argv(0), GIB_Regex_Error ());
|
||||
else if (strchr(GIB_Argv(3), 'g'))
|
||||
while (!regexec(reg, GIB_Argv(1)+ofs, 10, match, ofs > 0 ? REG_NOTBOL : 0) && match[0].rm_eo)
|
||||
ofs += GIB_Regex_Apply_Match (match, GIB_Argd(1), ofs, GIB_Argv(4));
|
||||
else if (!regexec(reg, GIB_Argv(1), 10, match, 0) && match[0].rm_eo)
|
||||
GIB_Regex_Apply_Match (match, GIB_Argd(1), 0, GIB_Argv(4));
|
||||
GIB_Return (GIB_Argv(1));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GIB_Regex_Extract_f (void)
|
||||
{
|
||||
regex_t *reg;
|
||||
char errbuf[1024];
|
||||
regmatch_t *match;
|
||||
int i, res;
|
||||
int i;
|
||||
char o;
|
||||
|
||||
if (GIB_Argc() < 4) {
|
||||
GIB_USAGE ("string regex var1 [var2 var3 ...]");
|
||||
GIB_USAGE ("string regex options [var1 var2 var3 ...]");
|
||||
return;
|
||||
}
|
||||
match = calloc (GIB_Argc() - 3, sizeof(regmatch_t));
|
||||
reg = calloc (1, sizeof (regex_t));
|
||||
|
||||
if ((res = regcomp(reg, GIB_Argv(2), REG_EXTENDED))) {
|
||||
regerror(res, reg, errbuf, sizeof(errbuf));
|
||||
Cbuf_Error ("regex", "%s: %s", GIB_Argv(0), errbuf);
|
||||
} else if (!regexec(reg, GIB_Argv(1), GIB_Argc() - 3, match, 0) && match[0].rm_eo) {
|
||||
if (!(reg = GIB_Regex_Compile (GIB_Argv(2), REG_EXTENDED | GIB_Regex_Translate_Options (GIB_Argv(3)))))
|
||||
Cbuf_Error ("regex", "%s: %s", GIB_Argv(0), GIB_Regex_Error ());
|
||||
else if (!regexec(reg, GIB_Argv(1), GIB_Argc() - 3, match, 0) && match[0].rm_eo) {
|
||||
for (i = 0; i < GIB_Argc() - 3; i++) {
|
||||
if (match[i].rm_so != -1 && *GIB_Argv(i+3)) {
|
||||
o = GIB_Argv(1)[match[i].rm_eo];
|
||||
|
@ -627,8 +568,6 @@ GIB_Regex_Extract_f (void)
|
|||
GIB_Return (va("%lu", (unsigned long) match[0].rm_eo));
|
||||
} else
|
||||
GIB_Return ("-1");
|
||||
regfree (reg);
|
||||
free (reg);
|
||||
free (match);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ static const char rcsid[] =
|
|||
#include "QF/quakefs.h"
|
||||
#include "QF/gib_parse.h"
|
||||
#include "QF/gib_builtin.h"
|
||||
#include "QF/gib_regex.h"
|
||||
#include "QF/cmd.h"
|
||||
#include "QF/sys.h"
|
||||
#include "QF/zone.h"
|
||||
|
@ -83,6 +84,8 @@ GIB_Init (qboolean sandbox)
|
|||
Cmd_RemoveCommand ("exec");
|
||||
Cmd_AddCommand ("exec", GIB_Exec_Override_f, "Execute a script file.");
|
||||
}
|
||||
// Initialize regex cache
|
||||
GIB_Regex_Init ();
|
||||
// Initialize builtins
|
||||
GIB_Builtin_Init (sandbox);
|
||||
}
|
||||
|
|
174
libs/gib/gib_regex.c
Normal file
174
libs/gib/gib_regex.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
#FILENAME#
|
||||
|
||||
#DESCRIPTION#
|
||||
|
||||
Copyright (C) 2002 #AUTHOR#
|
||||
|
||||
Author: #AUTHOR#
|
||||
Date: #DATE#
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
*/
|
||||
|
||||
static const char rcsid[] =
|
||||
"$Id$";
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "regex.h"
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/hash.h"
|
||||
#include "QF/gib_regex.h"
|
||||
#include "QF/qtypes.h"
|
||||
|
||||
hashtab_t *gib_regexs;
|
||||
static char errstr[1024];
|
||||
|
||||
const char *
|
||||
GIB_Regex_Get_Key (void *ele, void *ptr)
|
||||
{
|
||||
return ((gib_regex_t *) ele)->regex;
|
||||
}
|
||||
|
||||
void
|
||||
GIB_Regex_Free (void *ele, void *ptr)
|
||||
{
|
||||
regfree (&(((gib_regex_t *) ele)->comp));
|
||||
free (((gib_regex_t *) ele)->regex);
|
||||
free (ele);
|
||||
}
|
||||
|
||||
void
|
||||
GIB_Regex_Init (void)
|
||||
{
|
||||
gib_regexs = Hash_NewTable (512, GIB_Regex_Get_Key, GIB_Regex_Free, 0);
|
||||
}
|
||||
|
||||
regex_t *
|
||||
GIB_Regex_Compile (const char *regex, int cflags)
|
||||
{
|
||||
static unsigned int num_regexs = 0;
|
||||
gib_regex_t *reg;
|
||||
int res;
|
||||
|
||||
// Already compiled ?
|
||||
if ((reg = Hash_Find (gib_regexs, regex))) {
|
||||
// Did cflags change?
|
||||
if (cflags != reg->cflags) {
|
||||
// Try to recompile
|
||||
reg->cflags = cflags;
|
||||
if ((res = regcomp (&(reg->comp), regex, cflags))) {
|
||||
// Blew up, remove from hash
|
||||
regerror(res, &(reg->comp), errstr, sizeof(errstr));
|
||||
regfree (&(reg->comp));
|
||||
free (reg->regex);
|
||||
free (Hash_Del (gib_regexs, regex));
|
||||
num_regexs--;
|
||||
return 0;
|
||||
} else
|
||||
return &(reg->comp);
|
||||
}
|
||||
else
|
||||
return &(reg->comp);
|
||||
} else {
|
||||
reg = calloc (1, sizeof (gib_regex_t));
|
||||
if ((res = regcomp (&(reg->comp), regex, cflags))) {
|
||||
regerror(res, &(reg->comp), errstr, sizeof(errstr));
|
||||
regfree (&(reg->comp));
|
||||
free (reg);
|
||||
return 0;
|
||||
} else {
|
||||
reg->cflags = cflags;
|
||||
reg->regex = strdup (regex);
|
||||
if (++num_regexs > 128) {
|
||||
Hash_FlushTable (gib_regexs);
|
||||
num_regexs = 0;
|
||||
}
|
||||
Hash_Add (gib_regexs, reg);
|
||||
return &(reg->comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
GIB_Regex_Error (void)
|
||||
{
|
||||
return errstr;
|
||||
}
|
||||
|
||||
int
|
||||
GIB_Regex_Translate_Options (const char *opstr)
|
||||
{
|
||||
int options = 0;
|
||||
if (strchr (opstr, 'i'))
|
||||
options |= REG_ICASE;
|
||||
if (strchr (opstr, 'n'))
|
||||
options |= REG_NEWLINE;
|
||||
return options;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
GIB_Regex_Apply_Match (regmatch_t match[10], dstring_t *dstr, unsigned int ofs, const char *replace)
|
||||
{
|
||||
int i, start, len, sub, rlen = strlen(replace);
|
||||
char *matched;
|
||||
|
||||
start = match[0].rm_so+ofs;
|
||||
len = match[0].rm_eo - match[0].rm_so;
|
||||
|
||||
// Save matched pattern space
|
||||
matched = calloc (len + 1, sizeof(char));
|
||||
memcpy (matched, dstr->str+start, match[0].rm_eo - match[0].rm_so);
|
||||
|
||||
dstring_replace (dstr, start, len, replace, rlen);
|
||||
for (i = start; i < start+rlen; i++) {
|
||||
if (dstr->str[i] == '\\') {
|
||||
if (dstr->str[i+1] == '&') {
|
||||
dstring_snip (dstr, i, 1);
|
||||
rlen--;
|
||||
continue;
|
||||
}
|
||||
if (isdigit ((byte) dstr->str[i+1])) {
|
||||
if (i && dstr->str[i-1] == '\\') { // Escaped, not a true back reference
|
||||
dstring_snip (dstr, i, 1);
|
||||
rlen--;
|
||||
continue;
|
||||
}
|
||||
sub = dstr->str[i+1] - '0';
|
||||
if (match[sub].rm_so != -1) {
|
||||
dstring_replace (dstr, i, 2, matched+match[sub].rm_so, match[sub].rm_eo - match[sub].rm_so);
|
||||
rlen += match[sub].rm_eo - match[sub].rm_so - 2;
|
||||
} else {
|
||||
dstring_snip (dstr, i, 2);
|
||||
rlen -= 2;
|
||||
}
|
||||
}
|
||||
} else if (dstr->str[i] == '&') {
|
||||
dstring_replace (dstr, i, 1, matched, len);
|
||||
rlen += strlen(matched) - 1;
|
||||
}
|
||||
}
|
||||
free (matched);
|
||||
return rlen + match[0].rm_so;
|
||||
}
|
Loading…
Reference in a new issue