summaryrefslogtreecommitdiffstats
path: root/generic/tclRegexp.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclRegexp.c')
-rw-r--r--generic/tclRegexp.c341
1 files changed, 193 insertions, 148 deletions
diff --git a/generic/tclRegexp.c b/generic/tclRegexp.c
index 98458a6..6348e4a 100644
--- a/generic/tclRegexp.c
+++ b/generic/tclRegexp.c
@@ -9,8 +9,6 @@
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tclRegexp.c,v 1.20 2005/07/21 14:38:51 dkf Exp $
*/
#include "tclInt.h"
@@ -55,8 +53,8 @@
*
* *** NOTE: this code has been altered slightly for use in Tcl: ***
* *** 1. Names have been changed, e.g. from re_comp to ***
- * *** TclRegComp, to avoid clashes with other ***
- * *** regexp implementations used by applications. ***
+ * *** TclRegComp, to avoid clashes with other ***
+ * *** regexp implementations used by applications. ***
*/
/*
@@ -85,25 +83,24 @@ static Tcl_ThreadDataKey dataKey;
* Declarations for functions used only in this file.
*/
-static TclRegexp * CompileRegexp _ANSI_ARGS_((Tcl_Interp *interp,
- CONST char *pattern, int length, int flags));
-static void DupRegexpInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
- Tcl_Obj *copyPtr));
-static void FinalizeRegexp _ANSI_ARGS_((ClientData clientData));
-static void FreeRegexp _ANSI_ARGS_((TclRegexp *regexpPtr));
-static void FreeRegexpInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr));
-static int RegExpExecUniChar _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_RegExp re, CONST Tcl_UniChar *uniString,
- int numChars, int nmatches, int flags));
-static int SetRegexpFromAny _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_Obj *objPtr));
+static TclRegexp * CompileRegexp(Tcl_Interp *interp, const char *pattern,
+ int length, int flags);
+static void DupRegexpInternalRep(Tcl_Obj *srcPtr,
+ Tcl_Obj *copyPtr);
+static void FinalizeRegexp(ClientData clientData);
+static void FreeRegexp(TclRegexp *regexpPtr);
+static void FreeRegexpInternalRep(Tcl_Obj *objPtr);
+static int RegExpExecUniChar(Tcl_Interp *interp, Tcl_RegExp re,
+ const Tcl_UniChar *uniString, int numChars,
+ int nmatches, int flags);
+static int SetRegexpFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
/*
* The regular expression Tcl object type. This serves as a cache of the
* compiled form of the regular expression.
*/
-Tcl_ObjType tclRegexpType = {
+const Tcl_ObjType tclRegexpType = {
"regexp", /* name */
FreeRegexpInternalRep, /* freeIntRepProc */
DupRegexpInternalRep, /* dupIntRepProc */
@@ -134,10 +131,10 @@ Tcl_ObjType tclRegexpType = {
*/
Tcl_RegExp
-Tcl_RegExpCompile(interp, pattern)
- Tcl_Interp *interp; /* For use in error reporting and to access
+Tcl_RegExpCompile(
+ Tcl_Interp *interp, /* For use in error reporting and to access
* the interp regexp cache. */
- CONST char *pattern; /* String for which to produce compiled
+ const char *pattern) /* String for which to produce compiled
* regular expression. */
{
return (Tcl_RegExp) CompileRegexp(interp, pattern, (int) strlen(pattern),
@@ -165,20 +162,20 @@ Tcl_RegExpCompile(interp, pattern)
*/
int
-Tcl_RegExpExec(interp, re, text, start)
- Tcl_Interp *interp; /* Interpreter to use for error reporting. */
- Tcl_RegExp re; /* Compiled regular expression; must have been
+Tcl_RegExpExec(
+ Tcl_Interp *interp, /* Interpreter to use for error reporting. */
+ Tcl_RegExp re, /* Compiled regular expression; must have been
* returned by previous call to
* Tcl_GetRegExpFromObj. */
- CONST char *text; /* Text against which to match re. */
- CONST char *start; /* If text is part of a larger string, this
+ const char *text, /* Text against which to match re. */
+ const char *start) /* If text is part of a larger string, this
* identifies beginning of larger string, so
* that "^" won't match. */
{
int flags, result, numChars;
- TclRegexp *regexp = (TclRegexp *)re;
+ TclRegexp *regexp = (TclRegexp *) re;
Tcl_DString ds;
- CONST Tcl_UniChar *ustr;
+ const Tcl_UniChar *ustr;
/*
* If the starting point is offset from the beginning of the buffer, then
@@ -232,19 +229,19 @@ Tcl_RegExpExec(interp, re, text, start)
*/
void
-Tcl_RegExpRange(re, index, startPtr, endPtr)
- Tcl_RegExp re; /* Compiled regular expression that has been
+Tcl_RegExpRange(
+ Tcl_RegExp re, /* Compiled regular expression that has been
* passed to Tcl_RegExpExec. */
- int index; /* 0 means give the range of the entire match,
+ int index, /* 0 means give the range of the entire match,
* > 0 means give the range of a matching
* subrange. */
- CONST char **startPtr; /* Store address of first character in
+ const char **startPtr, /* Store address of first character in
* (sub-)range here. */
- CONST char **endPtr; /* Store address of character just after last
+ const char **endPtr) /* Store address of character just after last
* in (sub-)range here. */
{
TclRegexp *regexpPtr = (TclRegexp *) re;
- CONST char *string;
+ const char *string;
if ((size_t) index > regexpPtr->re.re_nsub) {
*startPtr = *endPtr = NULL;
@@ -252,7 +249,7 @@ Tcl_RegExpRange(re, index, startPtr, endPtr)
*startPtr = *endPtr = NULL;
} else {
if (regexpPtr->objPtr) {
- string = Tcl_GetString(regexpPtr->objPtr);
+ string = TclGetString(regexpPtr->objPtr);
} else {
string = regexpPtr->string;
}
@@ -282,17 +279,17 @@ Tcl_RegExpRange(re, index, startPtr, endPtr)
*/
static int
-RegExpExecUniChar(interp, re, wString, numChars, nmatches, flags)
- Tcl_Interp *interp; /* Interpreter to use for error reporting. */
- Tcl_RegExp re; /* Compiled regular expression; returned by a
+RegExpExecUniChar(
+ Tcl_Interp *interp, /* Interpreter to use for error reporting. */
+ Tcl_RegExp re, /* Compiled regular expression; returned by a
* previous call to Tcl_GetRegExpFromObj */
- CONST Tcl_UniChar *wString; /* String against which to match re. */
- int numChars; /* Length of Tcl_UniChar string (must be
+ const Tcl_UniChar *wString, /* String against which to match re. */
+ int numChars, /* Length of Tcl_UniChar string (must be
* >=0). */
- int nmatches; /* How many subexpression matches (counting
+ int nmatches, /* How many subexpression matches (counting
* the whole match as subexpression 0) are of
* interest. -1 means "don't know". */
- int flags; /* Regular expression flags. */
+ int flags) /* Regular expression flags. */
{
int status;
TclRegexp *regexpPtr = (TclRegexp *) re;
@@ -344,16 +341,16 @@ RegExpExecUniChar(interp, re, wString, numChars, nmatches, flags)
*/
void
-TclRegExpRangeUniChar(re, index, startPtr, endPtr)
- Tcl_RegExp re; /* Compiled regular expression that has been
+TclRegExpRangeUniChar(
+ Tcl_RegExp re, /* Compiled regular expression that has been
* passed to Tcl_RegExpExec. */
- int index; /* 0 means give the range of the entire match,
+ int index, /* 0 means give the range of the entire match,
* > 0 means give the range of a matching
* subrange, -1 means the range of the
* rm_extend field. */
- int *startPtr; /* Store address of first character in
+ int *startPtr, /* Store address of first character in
* (sub-)range here. */
- int *endPtr; /* Store address of character just after last
+ int *endPtr) /* Store address of character just after last
* in (sub-)range here. */
{
TclRegexp *regexpPtr = (TclRegexp *) re;
@@ -389,14 +386,13 @@ TclRegExpRangeUniChar(re, index, startPtr, endPtr)
*/
int
-Tcl_RegExpMatch(interp, text, pattern)
- Tcl_Interp *interp; /* Used for error reporting. May be NULL. */
- CONST char *text; /* Text to search for pattern matches. */
- CONST char *pattern; /* Regular expression to match against text. */
+Tcl_RegExpMatch(
+ Tcl_Interp *interp, /* Used for error reporting. May be NULL. */
+ const char *text, /* Text to search for pattern matches. */
+ const char *pattern) /* Regular expression to match against text. */
{
- Tcl_RegExp re;
+ Tcl_RegExp re = Tcl_RegExpCompile(interp, pattern);
- re = Tcl_RegExpCompile(interp, pattern);
if (re == NULL) {
return -1;
}
@@ -422,22 +418,44 @@ Tcl_RegExpMatch(interp, text, pattern)
*/
int
-Tcl_RegExpExecObj(interp, re, textObj, offset, nmatches, flags)
- Tcl_Interp *interp; /* Interpreter to use for error reporting. */
- Tcl_RegExp re; /* Compiled regular expression; must have been
+Tcl_RegExpExecObj(
+ Tcl_Interp *interp, /* Interpreter to use for error reporting. */
+ Tcl_RegExp re, /* Compiled regular expression; must have been
* returned by previous call to
* Tcl_GetRegExpFromObj. */
- Tcl_Obj *textObj; /* Text against which to match re. */
- int offset; /* Character index that marks where matching
+ Tcl_Obj *textObj, /* Text against which to match re. */
+ int offset, /* Character index that marks where matching
* should begin. */
- int nmatches; /* How many subexpression matches (counting
+ int nmatches, /* How many subexpression matches (counting
* the whole match as subexpression 0) are of
* interest. -1 means all of them. */
- int flags; /* Regular expression execution flags. */
+ int flags) /* Regular expression execution flags. */
{
TclRegexp *regexpPtr = (TclRegexp *) re;
Tcl_UniChar *udata;
int length;
+ int reflags = regexpPtr->flags;
+#define TCL_REG_GLOBOK_FLAGS \
+ (TCL_REG_ADVANCED | TCL_REG_NOSUB | TCL_REG_NOCASE)
+
+ /*
+ * Take advantage of the equivalent glob pattern, if one exists.
+ * This is possible based only on the right mix of incoming flags (0)
+ * and regexp compile flags.
+ */
+ if ((offset == 0) && (nmatches == 0) && (flags == 0)
+ && !(reflags & ~TCL_REG_GLOBOK_FLAGS)
+ && (regexpPtr->globObjPtr != NULL)) {
+ int nocase = (reflags & TCL_REG_NOCASE) ? TCL_MATCH_NOCASE : 0;
+
+ /*
+ * Pass to TclStringMatchObj for obj-specific handling.
+ * XXX: Currently doesn't take advantage of exact-ness that
+ * XXX: TclReToGlob tells us about
+ */
+
+ return TclStringMatchObj(textObj, regexpPtr->globObjPtr, nocase);
+ }
/*
* Save the target object so we can extract strings from it later.
@@ -476,10 +494,10 @@ Tcl_RegExpExecObj(interp, re, textObj, offset, nmatches, flags)
*/
int
-Tcl_RegExpMatchObj(interp, textObj, patternObj)
- Tcl_Interp *interp; /* Used for error reporting. May be NULL. */
- Tcl_Obj *textObj; /* Object containing the String to search. */
- Tcl_Obj *patternObj; /* Regular expression to match against
+Tcl_RegExpMatchObj(
+ Tcl_Interp *interp, /* Used for error reporting. May be NULL. */
+ Tcl_Obj *textObj, /* Object containing the String to search. */
+ Tcl_Obj *patternObj) /* Regular expression to match against
* string. */
{
Tcl_RegExp re;
@@ -510,9 +528,9 @@ Tcl_RegExpMatchObj(interp, textObj, patternObj)
*/
void
-Tcl_RegExpGetInfo(regexp, infoPtr)
- Tcl_RegExp regexp; /* Pattern from which to get subexpressions. */
- Tcl_RegExpInfo *infoPtr; /* Match information is stored here. */
+Tcl_RegExpGetInfo(
+ Tcl_RegExp regexp, /* Pattern from which to get subexpressions. */
+ Tcl_RegExpInfo *infoPtr) /* Match information is stored here. */
{
TclRegexp *regexpPtr = (TclRegexp *) regexp;
@@ -542,28 +560,28 @@ Tcl_RegExpGetInfo(regexp, infoPtr)
*/
Tcl_RegExp
-Tcl_GetRegExpFromObj(interp, objPtr, flags)
- Tcl_Interp *interp; /* For use in error reporting, and to access
+Tcl_GetRegExpFromObj(
+ Tcl_Interp *interp, /* For use in error reporting, and to access
* the interp regexp cache. */
- Tcl_Obj *objPtr; /* Object whose string rep contains regular
+ Tcl_Obj *objPtr, /* Object whose string rep contains regular
* expression pattern. Internal rep will be
* changed to compiled form of this regular
* expression. */
- int flags; /* Regular expression compilation flags. */
+ int flags) /* Regular expression compilation flags. */
{
int length;
TclRegexp *regexpPtr;
- char *pattern;
+ const char *pattern;
/*
* This is OK because we only actually interpret this value properly as a
* TclRegexp* when the type is tclRegexpType.
*/
- regexpPtr = (TclRegexp *) objPtr->internalRep.otherValuePtr;
+ regexpPtr = objPtr->internalRep.twoPtrValue.ptr1;
if ((objPtr->typePtr != &tclRegexpType) || (regexpPtr->flags != flags)) {
- pattern = Tcl_GetStringFromObj(objPtr, &length);
+ pattern = TclGetStringFromObj(objPtr, &length);
regexpPtr = CompileRegexp(interp, pattern, length, flags);
if (regexpPtr == NULL) {
@@ -583,7 +601,7 @@ Tcl_GetRegExpFromObj(interp, objPtr, flags)
*/
TclFreeIntRep(objPtr);
- objPtr->internalRep.otherValuePtr = (VOID *) regexpPtr;
+ objPtr->internalRep.twoPtrValue.ptr1 = regexpPtr;
objPtr->typePtr = &tclRegexpType;
}
return (Tcl_RegExp) regexpPtr;
@@ -609,16 +627,16 @@ Tcl_GetRegExpFromObj(interp, objPtr, flags)
*/
int
-TclRegAbout(interp, re)
- Tcl_Interp *interp; /* For use in variable assignment. */
- Tcl_RegExp re; /* The compiled regular expression. */
+TclRegAbout(
+ Tcl_Interp *interp, /* For use in variable assignment. */
+ Tcl_RegExp re) /* The compiled regular expression. */
{
- TclRegexp *regexpPtr = (TclRegexp *)re;
- char buf[TCL_INTEGER_SPACE];
- static struct infoname {
+ TclRegexp *regexpPtr = (TclRegexp *) re;
+ struct infoname {
int bit;
- char *text;
- } infonames[] = {
+ const char *text;
+ };
+ static const struct infoname infonames[] = {
{REG_UBACKREF, "REG_UBACKREF"},
{REG_ULOOKAHEAD, "REG_ULOOKAHEAD"},
{REG_UBOUNDS, "REG_UBOUNDS"},
@@ -633,38 +651,42 @@ TclRegAbout(interp, re)
{REG_UEMPTYMATCH, "REG_UEMPTYMATCH"},
{REG_UIMPOSSIBLE, "REG_UIMPOSSIBLE"},
{REG_USHORTEST, "REG_USHORTEST"},
- {0, ""}
+ {0, NULL}
};
- struct infoname *inf;
- int n;
+ const struct infoname *inf;
+ Tcl_Obj *infoObj, *resultObj;
+
+ /*
+ * The reset here guarantees that the interpreter result is empty and
+ * unshared. This means that we can use Tcl_ListObjAppendElement on the
+ * result object quite safely.
+ */
Tcl_ResetResult(interp);
- sprintf(buf, "%u", (unsigned)(regexpPtr->re.re_nsub));
- Tcl_AppendElement(interp, buf);
+ /*
+ * Assume that there will never be more than INT_MAX subexpressions. This
+ * is a pretty reasonable assumption; the RE engine doesn't scale _that_
+ * well and Tcl has other limits that constrain things as well...
+ */
+
+ resultObj = Tcl_NewObj();
+ Tcl_ListObjAppendElement(NULL, resultObj,
+ Tcl_NewIntObj((int) regexpPtr->re.re_nsub));
/*
- * Must count bits before generating list, because we must know whether {}
- * are needed before we start appending names.
+ * Now append a list of all the bit-flags set for the RE.
*/
- n = 0;
- for (inf = infonames; inf->bit != 0; inf++) {
- if (regexpPtr->re.re_info&inf->bit) {
- n++;
+ TclNewObj(infoObj);
+ for (inf=infonames ; inf->bit != 0 ; inf++) {
+ if (regexpPtr->re.re_info & inf->bit) {
+ Tcl_ListObjAppendElement(NULL, infoObj,
+ Tcl_NewStringObj(inf->text, -1));
}
}
- if (n != 1) {
- Tcl_AppendResult(interp, " {", NULL);
- }
- for (inf = infonames; inf->bit != 0; inf++) {
- if (regexpPtr->re.re_info&inf->bit) {
- Tcl_AppendElement(interp, inf->text);
- }
- }
- if (n != 1) {
- Tcl_AppendResult(interp, "}", NULL);
- }
+ Tcl_ListObjAppendElement(NULL, resultObj, infoObj);
+ Tcl_SetObjResult(interp, resultObj);
return 0;
}
@@ -686,23 +708,23 @@ TclRegAbout(interp, re)
*/
void
-TclRegError(interp, msg, status)
- Tcl_Interp *interp; /* Interpreter for error reporting. */
- CONST char *msg; /* Message to prepend to error. */
- int status; /* Status code to report. */
+TclRegError(
+ Tcl_Interp *interp, /* Interpreter for error reporting. */
+ const char *msg, /* Message to prepend to error. */
+ int status) /* Status code to report. */
{
char buf[100]; /* ample in practice */
- char cbuf[100]; /* lots in practice */
+ char cbuf[TCL_INTEGER_SPACE];
size_t n;
- char *p;
+ const char *p;
Tcl_ResetResult(interp);
- n = TclReError(status, (regex_t *)NULL, buf, sizeof(buf));
+ n = TclReError(status, NULL, buf, sizeof(buf));
p = (n > sizeof(buf)) ? "..." : "";
- Tcl_AppendResult(interp, msg, buf, p, NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf("%s%s%s", msg, buf, p));
sprintf(cbuf, "%d", status);
- (VOID) TclReError(REG_ITOA, (regex_t *)NULL, cbuf, sizeof(cbuf));
+ (void) TclReError(REG_ITOA, NULL, cbuf, sizeof(cbuf));
Tcl_SetErrorCode(interp, "REGEXP", cbuf, buf, NULL);
}
@@ -724,10 +746,10 @@ TclRegError(interp, msg, status)
*/
static void
-FreeRegexpInternalRep(objPtr)
- Tcl_Obj *objPtr; /* Regexp object with internal rep to free. */
+FreeRegexpInternalRep(
+ Tcl_Obj *objPtr) /* Regexp object with internal rep to free. */
{
- TclRegexp *regexpRepPtr = (TclRegexp *) objPtr->internalRep.otherValuePtr;
+ TclRegexp *regexpRepPtr = objPtr->internalRep.twoPtrValue.ptr1;
/*
* If this is the last reference to the regexp, free it.
@@ -736,6 +758,7 @@ FreeRegexpInternalRep(objPtr)
if (--(regexpRepPtr->refCount) <= 0) {
FreeRegexp(regexpRepPtr);
}
+ objPtr->typePtr = NULL;
}
/*
@@ -756,14 +779,14 @@ FreeRegexpInternalRep(objPtr)
*/
static void
-DupRegexpInternalRep(srcPtr, copyPtr)
- Tcl_Obj *srcPtr; /* Object with internal rep to copy. */
- Tcl_Obj *copyPtr; /* Object with internal rep to set. */
+DupRegexpInternalRep(
+ Tcl_Obj *srcPtr, /* Object with internal rep to copy. */
+ Tcl_Obj *copyPtr) /* Object with internal rep to set. */
{
- TclRegexp *regexpPtr = (TclRegexp *) srcPtr->internalRep.otherValuePtr;
+ TclRegexp *regexpPtr = srcPtr->internalRep.twoPtrValue.ptr1;
regexpPtr->refCount++;
- copyPtr->internalRep.otherValuePtr = srcPtr->internalRep.otherValuePtr;
+ copyPtr->internalRep.twoPtrValue.ptr1 = srcPtr->internalRep.twoPtrValue.ptr1;
copyPtr->typePtr = &tclRegexpType;
}
@@ -788,9 +811,9 @@ DupRegexpInternalRep(srcPtr, copyPtr)
*/
static int
-SetRegexpFromAny(interp, objPtr)
- Tcl_Interp *interp; /* Used for error reporting if not NULL. */
- Tcl_Obj *objPtr; /* The object to convert. */
+SetRegexpFromAny(
+ Tcl_Interp *interp, /* Used for error reporting if not NULL. */
+ Tcl_Obj *objPtr) /* The object to convert. */
{
if (Tcl_GetRegExpFromObj(interp, objPtr, REG_ADVANCED) == NULL) {
return TCL_ERROR;
@@ -821,17 +844,16 @@ SetRegexpFromAny(interp, objPtr)
*/
static TclRegexp *
-CompileRegexp(interp, string, length, flags)
- Tcl_Interp *interp; /* Used for error reporting if not NULL. */
- CONST char *string; /* The regexp to compile (UTF-8). */
- int length; /* The length of the string in bytes. */
- int flags; /* Compilation flags. */
+CompileRegexp(
+ Tcl_Interp *interp, /* Used for error reporting if not NULL. */
+ const char *string, /* The regexp to compile (UTF-8). */
+ int length, /* The length of the string in bytes. */
+ int flags) /* Compilation flags. */
{
TclRegexp *regexpPtr;
- CONST Tcl_UniChar *uniString;
- int numChars;
+ const Tcl_UniChar *uniString;
+ int numChars, status, i, exact;
Tcl_DString stringBuf;
- int status, i;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->initialized) {
@@ -883,7 +905,7 @@ CompileRegexp(interp, string, length, flags)
* This is a new expression, so compile it and add it to the cache.
*/
- regexpPtr = (TclRegexp *) ckalloc(sizeof(TclRegexp));
+ regexpPtr = ckalloc(sizeof(TclRegexp));
regexpPtr->objPtr = NULL;
regexpPtr->string = NULL;
regexpPtr->details.rm_extend.rm_so = -1;
@@ -910,22 +932,34 @@ CompileRegexp(interp, string, length, flags)
* Clean up and report errors in the interpreter, if possible.
*/
- ckfree((char *)regexpPtr);
+ ckfree(regexpPtr);
if (interp) {
TclRegError(interp,
- "couldn't compile regular expression pattern: ",
- status);
+ "couldn't compile regular expression pattern: ", status);
}
return NULL;
}
/*
+ * Convert RE to a glob pattern equivalent, if any, and cache it. If this
+ * is not possible, then globObjPtr will be NULL. This is used by
+ * Tcl_RegExpExecObj to optionally do a fast match (avoids RE engine).
+ */
+
+ if (TclReToGlob(NULL, string, length, &stringBuf, &exact) == TCL_OK) {
+ regexpPtr->globObjPtr = TclDStringToObj(&stringBuf);
+ Tcl_IncrRefCount(regexpPtr->globObjPtr);
+ } else {
+ regexpPtr->globObjPtr = NULL;
+ }
+
+ /*
* Allocate enough space for all of the subexpressions, plus one extra for
* the entire pattern.
*/
- regexpPtr->matches = (regmatch_t *) ckalloc(
- sizeof(regmatch_t) * (regexpPtr->re.re_nsub + 1));
+ regexpPtr->matches =
+ ckalloc(sizeof(regmatch_t) * (regexpPtr->re.re_nsub + 1));
/*
* Initialize the refcount to one initially, since it is in the cache.
@@ -940,6 +974,7 @@ CompileRegexp(interp, string, length, flags)
if (tsdPtr->patterns[NUM_REGEXPS-1] != NULL) {
TclRegexp *oldRegexpPtr = tsdPtr->regexps[NUM_REGEXPS-1];
+
if (--(oldRegexpPtr->refCount) <= 0) {
FreeRegexp(oldRegexpPtr);
}
@@ -950,8 +985,8 @@ CompileRegexp(interp, string, length, flags)
tsdPtr->patLengths[i+1] = tsdPtr->patLengths[i];
tsdPtr->regexps[i+1] = tsdPtr->regexps[i];
}
- tsdPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
- strcpy(tsdPtr->patterns[0], string);
+ tsdPtr->patterns[0] = ckalloc(length + 1);
+ memcpy(tsdPtr->patterns[0], string, (unsigned) length + 1);
tsdPtr->patLengths[0] = length;
tsdPtr->regexps[0] = regexpPtr;
@@ -975,14 +1010,17 @@ CompileRegexp(interp, string, length, flags)
*/
static void
-FreeRegexp(regexpPtr)
- TclRegexp *regexpPtr; /* Compiled regular expression to free. */
+FreeRegexp(
+ TclRegexp *regexpPtr) /* Compiled regular expression to free. */
{
TclReFree(&regexpPtr->re);
+ if (regexpPtr->globObjPtr) {
+ TclDecrRefCount(regexpPtr->globObjPtr);
+ }
if (regexpPtr->matches) {
- ckfree((char *) regexpPtr->matches);
+ ckfree(regexpPtr->matches);
}
- ckfree((char *) regexpPtr);
+ ckfree(regexpPtr);
}
/*
@@ -990,8 +1028,7 @@ FreeRegexp(regexpPtr)
*
* FinalizeRegexp --
*
- * Release the storage associated with the per-thread regexp
- * cache.
+ * Release the storage associated with the per-thread regexp cache.
*
* Results:
* None.
@@ -1003,8 +1040,8 @@ FreeRegexp(regexpPtr)
*/
static void
-FinalizeRegexp(clientData)
- ClientData clientData; /* Not used. */
+FinalizeRegexp(
+ ClientData clientData) /* Not used. */
{
int i;
TclRegexp *regexpPtr;
@@ -1016,7 +1053,15 @@ FinalizeRegexp(clientData)
FreeRegexp(regexpPtr);
}
ckfree(tsdPtr->patterns[i]);
+ tsdPtr->patterns[i] = NULL;
}
+
+ /*
+ * We may find ourselves reinitialized if another finalization routine
+ * invokes regexps.
+ */
+
+ tsdPtr->initialized = 0;
}
/*