mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-12-19 00:51:51 +00:00
4cef9792f4
They take a pointer to a free-list used for hashlinks so the hashlink pools can be per-thread. However, hash tables that are not updated are always thread-safe, so this affects only updates. progs_t has been set up such that it is easy for multiple progs within one thread can share hashlinks.
190 lines
4.2 KiB
C
190 lines
4.2 KiB
C
/*
|
|
#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
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#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 "gib_regex.h"
|
|
#include "QF/qtypes.h"
|
|
|
|
hashtab_t *gib_regexs;
|
|
static char errstr[1024];
|
|
|
|
static const char *
|
|
GIB_Regex_Get_Key (const void *ele, void *ptr)
|
|
{
|
|
return ((gib_regex_t *) ele)->regex;
|
|
}
|
|
|
|
static 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, 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;
|
|
}
|
|
|
|
int
|
|
GIB_Regex_Translate_Runtime_Options (const char *opstr)
|
|
{
|
|
int options = 0;
|
|
|
|
if (strchr (opstr, '<'))
|
|
options |= REG_NOTBOL;
|
|
if (strchr (opstr, '>'))
|
|
options |= REG_NOTEOL;
|
|
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;
|
|
}
|