os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclRegexp.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* 
sl@0
     2
 * tclRegexp.c --
sl@0
     3
 *
sl@0
     4
 *	This file contains the public interfaces to the Tcl regular
sl@0
     5
 *	expression mechanism.
sl@0
     6
 *
sl@0
     7
 * Copyright (c) 1998 by Sun Microsystems, Inc.
sl@0
     8
 * Copyright (c) 1998-1999 by Scriptics Corporation.
sl@0
     9
 * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
sl@0
    10
 *
sl@0
    11
 * See the file "license.terms" for information on usage and redistribution
sl@0
    12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    13
 *
sl@0
    14
 * RCS: @(#) $Id: tclRegexp.c,v 1.14.4.2 2006/04/07 01:14:28 hobbs Exp $
sl@0
    15
 */
sl@0
    16
sl@0
    17
#include "tclInt.h"
sl@0
    18
#include "tclPort.h"
sl@0
    19
#include "tclRegexp.h"
sl@0
    20
#if defined(__SYMBIAN32__) && defined(__WINSCW__)
sl@0
    21
#include "tclSymbianGlobals.h"
sl@0
    22
#define dataKey getdataKey(6)
sl@0
    23
#endif 
sl@0
    24
sl@0
    25
/*
sl@0
    26
 *----------------------------------------------------------------------
sl@0
    27
 * The routines in this file use Henry Spencer's regular expression
sl@0
    28
 * package contained in the following additional source files:
sl@0
    29
 *
sl@0
    30
 *	regc_color.c	regc_cvec.c	regc_lex.c
sl@0
    31
 *	regc_nfa.c	regcomp.c	regcustom.h
sl@0
    32
 *	rege_dfa.c	regerror.c	regerrs.h
sl@0
    33
 *	regex.h		regexec.c	regfree.c
sl@0
    34
 *	regfronts.c	regguts.h
sl@0
    35
 *
sl@0
    36
 * Copyright (c) 1998 Henry Spencer.  All rights reserved.
sl@0
    37
 * 
sl@0
    38
 * Development of this software was funded, in part, by Cray Research Inc.,
sl@0
    39
 * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
sl@0
    40
 * Corporation, none of whom are responsible for the results.  The author
sl@0
    41
 * thanks all of them. 
sl@0
    42
 * 
sl@0
    43
 * Redistribution and use in source and binary forms -- with or without
sl@0
    44
 * modification -- are permitted for any purpose, provided that
sl@0
    45
 * redistributions in source form retain this entire copyright notice and
sl@0
    46
 * indicate the origin and nature of any modifications.
sl@0
    47
 * 
sl@0
    48
 * I'd appreciate being given credit for this package in the documentation
sl@0
    49
 * of software which uses it, but that is not a requirement.
sl@0
    50
 * 
sl@0
    51
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
sl@0
    52
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
sl@0
    53
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
sl@0
    54
 * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
sl@0
    55
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
sl@0
    56
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
sl@0
    57
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
sl@0
    58
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
sl@0
    59
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
sl@0
    60
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
sl@0
    61
 *
sl@0
    62
 * *** NOTE: this code has been altered slightly for use in Tcl: ***
sl@0
    63
 * *** 1. Names have been changed, e.g. from re_comp to		 ***
sl@0
    64
 * ***    TclRegComp, to avoid clashes with other 		 ***
sl@0
    65
 * ***    regexp implementations used by applications. 		 ***
sl@0
    66
 */
sl@0
    67
sl@0
    68
/*
sl@0
    69
 * Thread local storage used to maintain a per-thread cache of compiled
sl@0
    70
 * regular expressions.
sl@0
    71
 */
sl@0
    72
sl@0
    73
#define NUM_REGEXPS 30
sl@0
    74
sl@0
    75
typedef struct ThreadSpecificData {
sl@0
    76
    int initialized;		/* Set to 1 when the module is initialized. */
sl@0
    77
    char *patterns[NUM_REGEXPS];/* Strings corresponding to compiled
sl@0
    78
				 * regular expression patterns.	 NULL
sl@0
    79
				 * means that this slot isn't used.
sl@0
    80
				 * Malloc-ed. */
sl@0
    81
    int patLengths[NUM_REGEXPS];/* Number of non-null characters in
sl@0
    82
				 * corresponding entry in patterns.
sl@0
    83
				 * -1 means entry isn't used. */
sl@0
    84
    struct TclRegexp *regexps[NUM_REGEXPS];
sl@0
    85
				/* Compiled forms of above strings.  Also
sl@0
    86
				 * malloc-ed, or NULL if not in use yet. */
sl@0
    87
} ThreadSpecificData;
sl@0
    88
sl@0
    89
#if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
sl@0
    90
static Tcl_ThreadDataKey dataKey;
sl@0
    91
#endif
sl@0
    92
sl@0
    93
/*
sl@0
    94
 * Declarations for functions used only in this file.
sl@0
    95
 */
sl@0
    96
sl@0
    97
static TclRegexp *	CompileRegexp _ANSI_ARGS_((Tcl_Interp *interp,
sl@0
    98
			    CONST char *pattern, int length, int flags));
sl@0
    99
static void		DupRegexpInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
sl@0
   100
			    Tcl_Obj *copyPtr));
sl@0
   101
static void		FinalizeRegexp _ANSI_ARGS_((ClientData clientData));
sl@0
   102
static void		FreeRegexp _ANSI_ARGS_((TclRegexp *regexpPtr));
sl@0
   103
static void		FreeRegexpInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr));
sl@0
   104
static int		RegExpExecUniChar _ANSI_ARGS_((Tcl_Interp *interp,
sl@0
   105
			    Tcl_RegExp re, CONST Tcl_UniChar *uniString,
sl@0
   106
			    int numChars, int nmatches, int flags));
sl@0
   107
static int		SetRegexpFromAny _ANSI_ARGS_((Tcl_Interp *interp,
sl@0
   108
			    Tcl_Obj *objPtr));
sl@0
   109
sl@0
   110
/*
sl@0
   111
 * The regular expression Tcl object type.  This serves as a cache
sl@0
   112
 * of the compiled form of the regular expression.
sl@0
   113
 */
sl@0
   114
sl@0
   115
static Tcl_ObjType tclRegexpType = {
sl@0
   116
    "regexp",				/* name */
sl@0
   117
    FreeRegexpInternalRep,		/* freeIntRepProc */
sl@0
   118
    DupRegexpInternalRep,		/* dupIntRepProc */
sl@0
   119
    NULL,				/* updateStringProc */
sl@0
   120
    SetRegexpFromAny			/* setFromAnyProc */
sl@0
   121
};
sl@0
   122
sl@0
   123

sl@0
   124
/*
sl@0
   125
 *----------------------------------------------------------------------
sl@0
   126
 *
sl@0
   127
 * Tcl_RegExpCompile --
sl@0
   128
 *
sl@0
   129
 *	Compile a regular expression into a form suitable for fast
sl@0
   130
 *	matching.  This procedure is DEPRECATED in favor of the
sl@0
   131
 *	object version of the command.
sl@0
   132
 *
sl@0
   133
 * Results:
sl@0
   134
 *	The return value is a pointer to the compiled form of string,
sl@0
   135
 *	suitable for passing to Tcl_RegExpExec.  This compiled form
sl@0
   136
 *	is only valid up until the next call to this procedure, so
sl@0
   137
 *	don't keep these around for a long time!  If an error occurred
sl@0
   138
 *	while compiling the pattern, then NULL is returned and an error
sl@0
   139
 *	message is left in the interp's result.
sl@0
   140
 *
sl@0
   141
 * Side effects:
sl@0
   142
 *	Updates the cache of compiled regexps.
sl@0
   143
 *
sl@0
   144
 *----------------------------------------------------------------------
sl@0
   145
 */
sl@0
   146
sl@0
   147
EXPORT_C Tcl_RegExp
sl@0
   148
Tcl_RegExpCompile(interp, string)
sl@0
   149
    Tcl_Interp *interp;		/* For use in error reporting and
sl@0
   150
				 * to access the interp regexp cache. */
sl@0
   151
    CONST char *string;		/* String for which to produce
sl@0
   152
				 * compiled regular expression. */
sl@0
   153
{
sl@0
   154
    return (Tcl_RegExp) CompileRegexp(interp, string, (int) strlen(string),
sl@0
   155
	    REG_ADVANCED);
sl@0
   156
}
sl@0
   157

sl@0
   158
/*
sl@0
   159
 *----------------------------------------------------------------------
sl@0
   160
 *
sl@0
   161
 * Tcl_RegExpExec --
sl@0
   162
 *
sl@0
   163
 *	Execute the regular expression matcher using a compiled form
sl@0
   164
 *	of a regular expression and save information about any match
sl@0
   165
 *	that is found.
sl@0
   166
 *
sl@0
   167
 * Results:
sl@0
   168
 *	If an error occurs during the matching operation then -1
sl@0
   169
 *	is returned and the interp's result contains an error message.
sl@0
   170
 *	Otherwise the return value is 1 if a matching range is
sl@0
   171
 *	found and 0 if there is no matching range.
sl@0
   172
 *
sl@0
   173
 * Side effects:
sl@0
   174
 *	None.
sl@0
   175
 *
sl@0
   176
 *----------------------------------------------------------------------
sl@0
   177
 */
sl@0
   178
sl@0
   179
EXPORT_C int
sl@0
   180
Tcl_RegExpExec(interp, re, string, start)
sl@0
   181
    Tcl_Interp *interp;		/* Interpreter to use for error reporting. */
sl@0
   182
    Tcl_RegExp re;		/* Compiled regular expression;  must have
sl@0
   183
				 * been returned by previous call to
sl@0
   184
				 * Tcl_GetRegExpFromObj. */
sl@0
   185
    CONST char *string;		/* String against which to match re. */
sl@0
   186
    CONST char *start;		/* If string is part of a larger string,
sl@0
   187
				 * this identifies beginning of larger
sl@0
   188
				 * string, so that "^" won't match. */
sl@0
   189
{
sl@0
   190
    int flags, result, numChars;
sl@0
   191
    TclRegexp *regexp = (TclRegexp *)re;
sl@0
   192
    Tcl_DString ds;
sl@0
   193
    CONST Tcl_UniChar *ustr;
sl@0
   194
sl@0
   195
    /*
sl@0
   196
     * If the starting point is offset from the beginning of the buffer,
sl@0
   197
     * then we need to tell the regexp engine not to match "^".
sl@0
   198
     */
sl@0
   199
sl@0
   200
    if (string > start) {
sl@0
   201
	flags = REG_NOTBOL;
sl@0
   202
    } else {
sl@0
   203
	flags = 0;
sl@0
   204
    }
sl@0
   205
sl@0
   206
    /*
sl@0
   207
     * Remember the string for use by Tcl_RegExpRange().
sl@0
   208
     */
sl@0
   209
sl@0
   210
    regexp->string = string;
sl@0
   211
    regexp->objPtr = NULL;
sl@0
   212
sl@0
   213
    /*
sl@0
   214
     * Convert the string to Unicode and perform the match.
sl@0
   215
     */
sl@0
   216
sl@0
   217
    Tcl_DStringInit(&ds);
sl@0
   218
    ustr = Tcl_UtfToUniCharDString(string, -1, &ds);
sl@0
   219
    numChars = Tcl_DStringLength(&ds) / sizeof(Tcl_UniChar);
sl@0
   220
    result = RegExpExecUniChar(interp, re, ustr, numChars,
sl@0
   221
	    -1 /* nmatches */, flags);
sl@0
   222
    Tcl_DStringFree(&ds);
sl@0
   223
sl@0
   224
    return result;
sl@0
   225
}
sl@0
   226

sl@0
   227
/*
sl@0
   228
 *---------------------------------------------------------------------------
sl@0
   229
 *
sl@0
   230
 * Tcl_RegExpRange --
sl@0
   231
 *
sl@0
   232
 *	Returns pointers describing the range of a regular expression match,
sl@0
   233
 *	or one of the subranges within the match.
sl@0
   234
 *
sl@0
   235
 * Results:
sl@0
   236
 *	The variables at *startPtr and *endPtr are modified to hold the
sl@0
   237
 *	addresses of the endpoints of the range given by index.  If the
sl@0
   238
 *	specified range doesn't exist then NULLs are returned.
sl@0
   239
 *
sl@0
   240
 * Side effects:
sl@0
   241
 *	None.
sl@0
   242
 *
sl@0
   243
 *---------------------------------------------------------------------------
sl@0
   244
 */
sl@0
   245
sl@0
   246
EXPORT_C void
sl@0
   247
Tcl_RegExpRange(re, index, startPtr, endPtr)
sl@0
   248
    Tcl_RegExp re;		/* Compiled regular expression that has
sl@0
   249
				 * been passed to Tcl_RegExpExec. */
sl@0
   250
    int index;			/* 0 means give the range of the entire
sl@0
   251
				 * match, > 0 means give the range of
sl@0
   252
				 * a matching subrange. */
sl@0
   253
    CONST char **startPtr;	/* Store address of first character in
sl@0
   254
				 * (sub-) range here. */
sl@0
   255
    CONST char **endPtr;	/* Store address of character just after last
sl@0
   256
				 * in (sub-) range here. */
sl@0
   257
{
sl@0
   258
    TclRegexp *regexpPtr = (TclRegexp *) re;
sl@0
   259
    CONST char *string;
sl@0
   260
sl@0
   261
    if ((size_t) index > regexpPtr->re.re_nsub) {
sl@0
   262
	*startPtr = *endPtr = NULL;
sl@0
   263
    } else if (regexpPtr->matches[index].rm_so < 0) {
sl@0
   264
	*startPtr = *endPtr = NULL;
sl@0
   265
    } else {
sl@0
   266
	if (regexpPtr->objPtr) {
sl@0
   267
	    string = Tcl_GetString(regexpPtr->objPtr);
sl@0
   268
	} else {
sl@0
   269
	    string = regexpPtr->string;
sl@0
   270
	}
sl@0
   271
	*startPtr = Tcl_UtfAtIndex(string, regexpPtr->matches[index].rm_so);
sl@0
   272
	*endPtr = Tcl_UtfAtIndex(string, regexpPtr->matches[index].rm_eo);
sl@0
   273
    }
sl@0
   274
}
sl@0
   275

sl@0
   276
/*
sl@0
   277
 *---------------------------------------------------------------------------
sl@0
   278
 *
sl@0
   279
 * RegExpExecUniChar --
sl@0
   280
 *
sl@0
   281
 *	Execute the regular expression matcher using a compiled form of a
sl@0
   282
 *	regular expression and save information about any match that is
sl@0
   283
 *	found.
sl@0
   284
 *
sl@0
   285
 * Results:
sl@0
   286
 *	If an error occurs during the matching operation then -1 is
sl@0
   287
 *	returned and an error message is left in interp's result.
sl@0
   288
 *	Otherwise the return value is 1 if a matching range was found or
sl@0
   289
 *	0 if there was no matching range.
sl@0
   290
 *
sl@0
   291
 * Side effects:
sl@0
   292
 *	None.
sl@0
   293
 *
sl@0
   294
 *----------------------------------------------------------------------
sl@0
   295
 */
sl@0
   296
sl@0
   297
static int
sl@0
   298
RegExpExecUniChar(interp, re, wString, numChars, nmatches, flags)
sl@0
   299
    Tcl_Interp *interp;		/* Interpreter to use for error reporting. */
sl@0
   300
    Tcl_RegExp re;		/* Compiled regular expression; returned by
sl@0
   301
				 * a previous call to Tcl_GetRegExpFromObj */
sl@0
   302
    CONST Tcl_UniChar *wString;	/* String against which to match re. */
sl@0
   303
    int numChars;		/* Length of Tcl_UniChar string (must
sl@0
   304
				 * be >= 0). */
sl@0
   305
    int nmatches;		/* How many subexpression matches (counting
sl@0
   306
				 * the whole match as subexpression 0) are
sl@0
   307
				 * of interest.  -1 means "don't know". */
sl@0
   308
    int flags;			/* Regular expression flags. */
sl@0
   309
{
sl@0
   310
    int status;
sl@0
   311
    TclRegexp *regexpPtr = (TclRegexp *) re;
sl@0
   312
    size_t last = regexpPtr->re.re_nsub + 1;
sl@0
   313
    size_t nm = last;
sl@0
   314
sl@0
   315
    if (nmatches >= 0 && (size_t) nmatches < nm) {
sl@0
   316
	nm = (size_t) nmatches;
sl@0
   317
    }
sl@0
   318
sl@0
   319
    status = TclReExec(&regexpPtr->re, wString, (size_t) numChars,
sl@0
   320
	    &regexpPtr->details, nm, regexpPtr->matches, flags);
sl@0
   321
sl@0
   322
    /*
sl@0
   323
     * Check for errors.
sl@0
   324
     */
sl@0
   325
sl@0
   326
    if (status != REG_OKAY) {
sl@0
   327
	if (status == REG_NOMATCH) {
sl@0
   328
	    return 0;
sl@0
   329
	}
sl@0
   330
	if (interp != NULL) {
sl@0
   331
	    TclRegError(interp, "error while matching regular expression: ",
sl@0
   332
		    status);
sl@0
   333
	}
sl@0
   334
	return -1;
sl@0
   335
    }
sl@0
   336
    return 1;
sl@0
   337
}
sl@0
   338

sl@0
   339
/*
sl@0
   340
 *---------------------------------------------------------------------------
sl@0
   341
 *
sl@0
   342
 * TclRegExpRangeUniChar --
sl@0
   343
 *
sl@0
   344
 *	Returns pointers describing the range of a regular expression match,
sl@0
   345
 *	or one of the subranges within the match, or the hypothetical range
sl@0
   346
 *	represented by the rm_extend field of the rm_detail_t.
sl@0
   347
 *
sl@0
   348
 * Results:
sl@0
   349
 *	The variables at *startPtr and *endPtr are modified to hold the
sl@0
   350
 *	offsets of the endpoints of the range given by index.  If the
sl@0
   351
 *	specified range doesn't exist then -1s are supplied.
sl@0
   352
 *
sl@0
   353
 * Side effects:
sl@0
   354
 *	None.
sl@0
   355
 *
sl@0
   356
 *---------------------------------------------------------------------------
sl@0
   357
 */
sl@0
   358
sl@0
   359
void
sl@0
   360
TclRegExpRangeUniChar(re, index, startPtr, endPtr)
sl@0
   361
    Tcl_RegExp re;		/* Compiled regular expression that has
sl@0
   362
				 * been passed to Tcl_RegExpExec. */
sl@0
   363
    int index;			/* 0 means give the range of the entire
sl@0
   364
				 * match, > 0 means give the range of
sl@0
   365
				 * a matching subrange, -1 means the
sl@0
   366
				 * range of the rm_extend field. */
sl@0
   367
    int *startPtr;		/* Store address of first character in
sl@0
   368
				 * (sub-) range here. */
sl@0
   369
    int *endPtr;		/* Store address of character just after last
sl@0
   370
				 * in (sub-) range here. */
sl@0
   371
{
sl@0
   372
    TclRegexp *regexpPtr = (TclRegexp *) re;
sl@0
   373
sl@0
   374
    if ((regexpPtr->flags&REG_EXPECT) && index == -1) {
sl@0
   375
	*startPtr = regexpPtr->details.rm_extend.rm_so;
sl@0
   376
	*endPtr = regexpPtr->details.rm_extend.rm_eo;
sl@0
   377
    } else if ((size_t) index > regexpPtr->re.re_nsub) {
sl@0
   378
	*startPtr = -1;
sl@0
   379
	*endPtr = -1;
sl@0
   380
    } else {
sl@0
   381
	*startPtr = regexpPtr->matches[index].rm_so;
sl@0
   382
	*endPtr = regexpPtr->matches[index].rm_eo;
sl@0
   383
    }
sl@0
   384
}
sl@0
   385

sl@0
   386
/*
sl@0
   387
 *----------------------------------------------------------------------
sl@0
   388
 *
sl@0
   389
 * Tcl_RegExpMatch --
sl@0
   390
 *
sl@0
   391
 *	See if a string matches a regular expression.
sl@0
   392
 *
sl@0
   393
 * Results:
sl@0
   394
 *	If an error occurs during the matching operation then -1
sl@0
   395
 *	is returned and the interp's result contains an error message.
sl@0
   396
 *	Otherwise the return value is 1 if "string" matches "pattern"
sl@0
   397
 *	and 0 otherwise.
sl@0
   398
 *
sl@0
   399
 * Side effects:
sl@0
   400
 *	None.
sl@0
   401
 *
sl@0
   402
 *----------------------------------------------------------------------
sl@0
   403
 */
sl@0
   404
sl@0
   405
EXPORT_C int
sl@0
   406
Tcl_RegExpMatch(interp, string, pattern)
sl@0
   407
    Tcl_Interp *interp;		/* Used for error reporting. May be NULL. */
sl@0
   408
    CONST char *string;		/* String. */
sl@0
   409
    CONST char *pattern;	/* Regular expression to match against
sl@0
   410
				 * string. */
sl@0
   411
{
sl@0
   412
    Tcl_RegExp re;
sl@0
   413
sl@0
   414
    re = Tcl_RegExpCompile(interp, pattern);
sl@0
   415
    if (re == NULL) {
sl@0
   416
	return -1;
sl@0
   417
    }
sl@0
   418
    return Tcl_RegExpExec(interp, re, string, string);
sl@0
   419
}
sl@0
   420

sl@0
   421
/*
sl@0
   422
 *----------------------------------------------------------------------
sl@0
   423
 *
sl@0
   424
 * Tcl_RegExpExecObj --
sl@0
   425
 *
sl@0
   426
 *	Execute a precompiled regexp against the given object.
sl@0
   427
 *
sl@0
   428
 * Results:
sl@0
   429
 *	If an error occurs during the matching operation then -1
sl@0
   430
 *	is returned and the interp's result contains an error message.
sl@0
   431
 *	Otherwise the return value is 1 if "string" matches "pattern"
sl@0
   432
 *	and 0 otherwise.
sl@0
   433
 *
sl@0
   434
 * Side effects:
sl@0
   435
 *	Converts the object to a Unicode object.
sl@0
   436
 *
sl@0
   437
 *----------------------------------------------------------------------
sl@0
   438
 */
sl@0
   439
sl@0
   440
EXPORT_C int
sl@0
   441
Tcl_RegExpExecObj(interp, re, objPtr, offset, nmatches, flags)
sl@0
   442
    Tcl_Interp *interp;		/* Interpreter to use for error reporting. */
sl@0
   443
    Tcl_RegExp re;		/* Compiled regular expression;  must have
sl@0
   444
				 * been returned by previous call to
sl@0
   445
				 * Tcl_GetRegExpFromObj. */
sl@0
   446
    Tcl_Obj *objPtr;		/* String against which to match re. */
sl@0
   447
    int offset;			/* Character index that marks where matching
sl@0
   448
				 * should begin. */
sl@0
   449
    int nmatches;		/* How many subexpression matches (counting
sl@0
   450
				 * the whole match as subexpression 0) are
sl@0
   451
				 * of interest.  -1 means all of them. */
sl@0
   452
    int flags;			/* Regular expression execution flags. */
sl@0
   453
{
sl@0
   454
    TclRegexp *regexpPtr = (TclRegexp *) re;
sl@0
   455
    Tcl_UniChar *udata;
sl@0
   456
    int length;
sl@0
   457
sl@0
   458
    /*
sl@0
   459
     * Save the target object so we can extract strings from it later.
sl@0
   460
     */
sl@0
   461
sl@0
   462
    regexpPtr->string = NULL;
sl@0
   463
    regexpPtr->objPtr = objPtr;
sl@0
   464
sl@0
   465
    udata = Tcl_GetUnicodeFromObj(objPtr, &length);
sl@0
   466
sl@0
   467
    if (offset > length) {
sl@0
   468
	offset = length;
sl@0
   469
    }
sl@0
   470
    udata += offset;
sl@0
   471
    length -= offset;
sl@0
   472
    
sl@0
   473
    return RegExpExecUniChar(interp, re, udata, length, nmatches, flags);
sl@0
   474
}
sl@0
   475

sl@0
   476
/*
sl@0
   477
 *----------------------------------------------------------------------
sl@0
   478
 *
sl@0
   479
 * Tcl_RegExpMatchObj --
sl@0
   480
 *
sl@0
   481
 *	See if an object matches a regular expression.
sl@0
   482
 *
sl@0
   483
 * Results:
sl@0
   484
 *	If an error occurs during the matching operation then -1
sl@0
   485
 *	is returned and the interp's result contains an error message.
sl@0
   486
 *	Otherwise the return value is 1 if "string" matches "pattern"
sl@0
   487
 *	and 0 otherwise.
sl@0
   488
 *
sl@0
   489
 * Side effects:
sl@0
   490
 *	Changes the internal rep of the pattern and string objects.
sl@0
   491
 *
sl@0
   492
 *----------------------------------------------------------------------
sl@0
   493
 */
sl@0
   494
sl@0
   495
EXPORT_C int
sl@0
   496
Tcl_RegExpMatchObj(interp, stringObj, patternObj)
sl@0
   497
    Tcl_Interp *interp;		/* Used for error reporting. May be NULL. */
sl@0
   498
    Tcl_Obj *stringObj;		/* Object containing the String to search. */
sl@0
   499
    Tcl_Obj *patternObj;	/* Regular expression to match against
sl@0
   500
				 * string. */
sl@0
   501
{
sl@0
   502
    Tcl_RegExp re;
sl@0
   503
sl@0
   504
    re = Tcl_GetRegExpFromObj(interp, patternObj,
sl@0
   505
	    TCL_REG_ADVANCED | TCL_REG_NOSUB);
sl@0
   506
    if (re == NULL) {
sl@0
   507
	return -1;
sl@0
   508
    }
sl@0
   509
    return Tcl_RegExpExecObj(interp, re, stringObj, 0 /* offset */,
sl@0
   510
	    0 /* nmatches */, 0 /* flags */);
sl@0
   511
}
sl@0
   512

sl@0
   513
/*
sl@0
   514
 *----------------------------------------------------------------------
sl@0
   515
 *
sl@0
   516
 * Tcl_RegExpGetInfo --
sl@0
   517
 *
sl@0
   518
 *	Retrieve information about the current match.
sl@0
   519
 *
sl@0
   520
 * Results:
sl@0
   521
 *	None.
sl@0
   522
 *
sl@0
   523
 * Side effects:
sl@0
   524
 *	None.
sl@0
   525
 *
sl@0
   526
 *----------------------------------------------------------------------
sl@0
   527
 */
sl@0
   528
sl@0
   529
EXPORT_C void
sl@0
   530
Tcl_RegExpGetInfo(regexp, infoPtr)
sl@0
   531
    Tcl_RegExp regexp;		/* Pattern from which to get subexpressions. */
sl@0
   532
    Tcl_RegExpInfo *infoPtr;	/* Match information is stored here.  */
sl@0
   533
{
sl@0
   534
    TclRegexp *regexpPtr = (TclRegexp *) regexp;
sl@0
   535
sl@0
   536
    infoPtr->nsubs = regexpPtr->re.re_nsub;
sl@0
   537
    infoPtr->matches = (Tcl_RegExpIndices *) regexpPtr->matches;
sl@0
   538
    infoPtr->extendStart = regexpPtr->details.rm_extend.rm_so;
sl@0
   539
}
sl@0
   540

sl@0
   541
/*
sl@0
   542
 *----------------------------------------------------------------------
sl@0
   543
 *
sl@0
   544
 * Tcl_GetRegExpFromObj --
sl@0
   545
 *
sl@0
   546
 *	Compile a regular expression into a form suitable for fast
sl@0
   547
 *	matching.  This procedure caches the result in a Tcl_Obj.
sl@0
   548
 *
sl@0
   549
 * Results:
sl@0
   550
 *	The return value is a pointer to the compiled form of string,
sl@0
   551
 *	suitable for passing to Tcl_RegExpExec.  If an error occurred
sl@0
   552
 *	while compiling the pattern, then NULL is returned and an error
sl@0
   553
 *	message is left in the interp's result.
sl@0
   554
 *
sl@0
   555
 * Side effects:
sl@0
   556
 *	Updates the native rep of the Tcl_Obj.
sl@0
   557
 *
sl@0
   558
 *----------------------------------------------------------------------
sl@0
   559
 */
sl@0
   560
sl@0
   561
EXPORT_C Tcl_RegExp
sl@0
   562
Tcl_GetRegExpFromObj(interp, objPtr, flags)
sl@0
   563
    Tcl_Interp *interp;		/* For use in error reporting, and to access
sl@0
   564
				 * the interp regexp cache. */
sl@0
   565
    Tcl_Obj *objPtr;		/* Object whose string rep contains regular
sl@0
   566
				 * expression pattern.  Internal rep will be
sl@0
   567
				 * changed to compiled form of this regular
sl@0
   568
				 * expression. */
sl@0
   569
    int flags;			/* Regular expression compilation flags. */
sl@0
   570
{
sl@0
   571
    int length;
sl@0
   572
    Tcl_ObjType *typePtr;
sl@0
   573
    TclRegexp *regexpPtr;
sl@0
   574
    char *pattern;
sl@0
   575
sl@0
   576
    typePtr = objPtr->typePtr;
sl@0
   577
    regexpPtr = (TclRegexp *) objPtr->internalRep.otherValuePtr;
sl@0
   578
sl@0
   579
    if ((typePtr != &tclRegexpType) || (regexpPtr->flags != flags)) {
sl@0
   580
	pattern = Tcl_GetStringFromObj(objPtr, &length);
sl@0
   581
sl@0
   582
	regexpPtr = CompileRegexp(interp, pattern, length, flags);
sl@0
   583
	if (regexpPtr == NULL) {
sl@0
   584
	    return NULL;
sl@0
   585
	}
sl@0
   586
sl@0
   587
	/*
sl@0
   588
	 * Add a reference to the regexp so it will persist even if it is
sl@0
   589
	 * pushed out of the current thread's regexp cache.  This reference
sl@0
   590
	 * will be removed when the object's internal rep is freed.
sl@0
   591
	 */
sl@0
   592
sl@0
   593
	regexpPtr->refCount++;
sl@0
   594
sl@0
   595
	/*
sl@0
   596
	 * Free the old representation and set our type.
sl@0
   597
	 */
sl@0
   598
sl@0
   599
	if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
sl@0
   600
	    (*typePtr->freeIntRepProc)(objPtr);
sl@0
   601
	}
sl@0
   602
	objPtr->internalRep.otherValuePtr = (VOID *) regexpPtr;
sl@0
   603
	objPtr->typePtr = &tclRegexpType;
sl@0
   604
    }
sl@0
   605
    return (Tcl_RegExp) regexpPtr;
sl@0
   606
}
sl@0
   607

sl@0
   608
/*
sl@0
   609
 *----------------------------------------------------------------------
sl@0
   610
 *
sl@0
   611
 * TclRegAbout --
sl@0
   612
 *
sl@0
   613
 *	Return information about a compiled regular expression.
sl@0
   614
 *
sl@0
   615
 * Results:
sl@0
   616
 *	The return value is -1 for failure, 0 for success, although at
sl@0
   617
 *	the moment there's nothing that could fail.  On success, a list
sl@0
   618
 *	is left in the interp's result:  first element is the subexpression
sl@0
   619
 *	count, second is a list of re_info bit names.
sl@0
   620
 *
sl@0
   621
 * Side effects:
sl@0
   622
 *	None.
sl@0
   623
 *
sl@0
   624
 *----------------------------------------------------------------------
sl@0
   625
 */
sl@0
   626
sl@0
   627
int
sl@0
   628
TclRegAbout(interp, re)
sl@0
   629
    Tcl_Interp *interp;		/* For use in variable assignment. */
sl@0
   630
    Tcl_RegExp re;		/* The compiled regular expression. */
sl@0
   631
{
sl@0
   632
    TclRegexp *regexpPtr = (TclRegexp *)re;
sl@0
   633
    char buf[TCL_INTEGER_SPACE];
sl@0
   634
    static struct infoname {
sl@0
   635
	int bit;
sl@0
   636
	char *text;
sl@0
   637
    } infonames[] = {
sl@0
   638
	{REG_UBACKREF,		"REG_UBACKREF"},
sl@0
   639
	{REG_ULOOKAHEAD,	"REG_ULOOKAHEAD"},
sl@0
   640
	{REG_UBOUNDS,		"REG_UBOUNDS"},
sl@0
   641
	{REG_UBRACES,		"REG_UBRACES"},
sl@0
   642
	{REG_UBSALNUM,		"REG_UBSALNUM"},
sl@0
   643
	{REG_UPBOTCH,		"REG_UPBOTCH"},
sl@0
   644
	{REG_UBBS,		"REG_UBBS"},
sl@0
   645
	{REG_UNONPOSIX,		"REG_UNONPOSIX"},
sl@0
   646
	{REG_UUNSPEC,		"REG_UUNSPEC"},
sl@0
   647
	{REG_UUNPORT,		"REG_UUNPORT"},
sl@0
   648
	{REG_ULOCALE,		"REG_ULOCALE"},
sl@0
   649
	{REG_UEMPTYMATCH,	"REG_UEMPTYMATCH"},
sl@0
   650
	{REG_UIMPOSSIBLE,	"REG_UIMPOSSIBLE"},
sl@0
   651
	{REG_USHORTEST,		"REG_USHORTEST"},
sl@0
   652
	{0,			""}
sl@0
   653
    };
sl@0
   654
    struct infoname *inf;
sl@0
   655
    int n;
sl@0
   656
sl@0
   657
    Tcl_ResetResult(interp);
sl@0
   658
sl@0
   659
    sprintf(buf, "%u", (unsigned)(regexpPtr->re.re_nsub));
sl@0
   660
    Tcl_AppendElement(interp, buf);
sl@0
   661
sl@0
   662
    /*
sl@0
   663
     * Must count bits before generating list, because we must know
sl@0
   664
     * whether {} are needed before we start appending names.
sl@0
   665
     */
sl@0
   666
    n = 0;
sl@0
   667
    for (inf = infonames; inf->bit != 0; inf++) {
sl@0
   668
	if (regexpPtr->re.re_info&inf->bit) {
sl@0
   669
	    n++;
sl@0
   670
	}
sl@0
   671
    }
sl@0
   672
    if (n != 1) {
sl@0
   673
	Tcl_AppendResult(interp, " {", NULL);
sl@0
   674
    }
sl@0
   675
    for (inf = infonames; inf->bit != 0; inf++) {
sl@0
   676
	if (regexpPtr->re.re_info&inf->bit) {
sl@0
   677
	    Tcl_AppendElement(interp, inf->text);
sl@0
   678
	}
sl@0
   679
    }
sl@0
   680
    if (n != 1) {
sl@0
   681
	Tcl_AppendResult(interp, "}", NULL);
sl@0
   682
    }
sl@0
   683
sl@0
   684
    return 0;
sl@0
   685
}
sl@0
   686

sl@0
   687
/*
sl@0
   688
 *----------------------------------------------------------------------
sl@0
   689
 *
sl@0
   690
 * TclRegError --
sl@0
   691
 *
sl@0
   692
 *	Generate an error message based on the regexp status code.
sl@0
   693
 *
sl@0
   694
 * Results:
sl@0
   695
 *	Places an error in the interpreter.
sl@0
   696
 *
sl@0
   697
 * Side effects:
sl@0
   698
 *	Sets errorCode as well.
sl@0
   699
 *
sl@0
   700
 *----------------------------------------------------------------------
sl@0
   701
 */
sl@0
   702
sl@0
   703
void
sl@0
   704
TclRegError(interp, msg, status)
sl@0
   705
    Tcl_Interp *interp;		/* Interpreter for error reporting. */
sl@0
   706
    CONST char *msg;		/* Message to prepend to error. */
sl@0
   707
    int status;			/* Status code to report. */
sl@0
   708
{
sl@0
   709
    char buf[100];		/* ample in practice */
sl@0
   710
    char cbuf[100];		/* lots in practice */
sl@0
   711
    size_t n;
sl@0
   712
    char *p;
sl@0
   713
sl@0
   714
    Tcl_ResetResult(interp);
sl@0
   715
    n = TclReError(status, (regex_t *)NULL, buf, sizeof(buf));
sl@0
   716
    p = (n > sizeof(buf)) ? "..." : "";
sl@0
   717
    Tcl_AppendResult(interp, msg, buf, p, NULL);
sl@0
   718
sl@0
   719
    sprintf(cbuf, "%d", status);
sl@0
   720
    (VOID) TclReError(REG_ITOA, (regex_t *)NULL, cbuf, sizeof(cbuf));
sl@0
   721
    Tcl_SetErrorCode(interp, "REGEXP", cbuf, buf, NULL);
sl@0
   722
}
sl@0
   723
sl@0
   724

sl@0
   725
/*
sl@0
   726
 *----------------------------------------------------------------------
sl@0
   727
 *
sl@0
   728
 * FreeRegexpInternalRep --
sl@0
   729
 *
sl@0
   730
 *	Deallocate the storage associated with a regexp object's internal
sl@0
   731
 *	representation.
sl@0
   732
 *
sl@0
   733
 * Results:
sl@0
   734
 *	None.
sl@0
   735
 *
sl@0
   736
 * Side effects:
sl@0
   737
 *	Frees the compiled regular expression.
sl@0
   738
 *
sl@0
   739
 *----------------------------------------------------------------------
sl@0
   740
 */
sl@0
   741
sl@0
   742
static void
sl@0
   743
FreeRegexpInternalRep(objPtr)
sl@0
   744
    Tcl_Obj *objPtr;		/* Regexp object with internal rep to free. */
sl@0
   745
{
sl@0
   746
    TclRegexp *regexpRepPtr = (TclRegexp *) objPtr->internalRep.otherValuePtr;
sl@0
   747
sl@0
   748
    /*
sl@0
   749
     * If this is the last reference to the regexp, free it.
sl@0
   750
     */
sl@0
   751
sl@0
   752
    if (--(regexpRepPtr->refCount) <= 0) {
sl@0
   753
	FreeRegexp(regexpRepPtr);
sl@0
   754
    }
sl@0
   755
}
sl@0
   756

sl@0
   757
/*
sl@0
   758
 *----------------------------------------------------------------------
sl@0
   759
 *
sl@0
   760
 * DupRegexpInternalRep --
sl@0
   761
 *
sl@0
   762
 *	We copy the reference to the compiled regexp and bump its
sl@0
   763
 *	reference count.
sl@0
   764
 *
sl@0
   765
 * Results:
sl@0
   766
 *	None.
sl@0
   767
 *
sl@0
   768
 * Side effects:
sl@0
   769
 *	Increments the reference count of the regexp.
sl@0
   770
 *
sl@0
   771
 *----------------------------------------------------------------------
sl@0
   772
 */
sl@0
   773
sl@0
   774
static void
sl@0
   775
DupRegexpInternalRep(srcPtr, copyPtr)
sl@0
   776
    Tcl_Obj *srcPtr;		/* Object with internal rep to copy. */
sl@0
   777
    Tcl_Obj *copyPtr;		/* Object with internal rep to set. */
sl@0
   778
{
sl@0
   779
    TclRegexp *regexpPtr = (TclRegexp *) srcPtr->internalRep.otherValuePtr;
sl@0
   780
    regexpPtr->refCount++;
sl@0
   781
    copyPtr->internalRep.otherValuePtr = srcPtr->internalRep.otherValuePtr;
sl@0
   782
    copyPtr->typePtr = &tclRegexpType;
sl@0
   783
}
sl@0
   784

sl@0
   785
/*
sl@0
   786
 *----------------------------------------------------------------------
sl@0
   787
 *
sl@0
   788
 * SetRegexpFromAny --
sl@0
   789
 *
sl@0
   790
 *	Attempt to generate a compiled regular expression for the Tcl object
sl@0
   791
 *	"objPtr".
sl@0
   792
 *
sl@0
   793
 * Results:
sl@0
   794
 *	The return value is TCL_OK or TCL_ERROR. If an error occurs during
sl@0
   795
 *	conversion, an error message is left in the interpreter's result
sl@0
   796
 *	unless "interp" is NULL.
sl@0
   797
 *
sl@0
   798
 * Side effects:
sl@0
   799
 *	If no error occurs, a regular expression is stored as "objPtr"s
sl@0
   800
 *	internal representation.
sl@0
   801
 *
sl@0
   802
 *----------------------------------------------------------------------
sl@0
   803
 */
sl@0
   804
sl@0
   805
static int
sl@0
   806
SetRegexpFromAny(interp, objPtr)
sl@0
   807
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
sl@0
   808
    Tcl_Obj *objPtr;		/* The object to convert. */
sl@0
   809
{
sl@0
   810
    if (Tcl_GetRegExpFromObj(interp, objPtr, REG_ADVANCED) == NULL) {
sl@0
   811
	return TCL_ERROR;
sl@0
   812
    }
sl@0
   813
    return TCL_OK;
sl@0
   814
}
sl@0
   815

sl@0
   816
/*
sl@0
   817
 *---------------------------------------------------------------------------
sl@0
   818
 *
sl@0
   819
 * CompileRegexp --
sl@0
   820
 *
sl@0
   821
 *	Attempt to compile the given regexp pattern.  If the compiled
sl@0
   822
 *	regular expression can be found in the per-thread cache, it
sl@0
   823
 *	will be used instead of compiling a new copy.
sl@0
   824
 *
sl@0
   825
 * Results:
sl@0
   826
 *	The return value is a pointer to a newly allocated TclRegexp
sl@0
   827
 *	that represents the compiled pattern, or NULL if the pattern
sl@0
   828
 *	could not be compiled.  If NULL is returned, an error message is
sl@0
   829
 *	left in the interp's result.
sl@0
   830
 *
sl@0
   831
 * Side effects:
sl@0
   832
 *	The thread-local regexp cache is updated and a new TclRegexp may
sl@0
   833
 *	be allocated.
sl@0
   834
 *
sl@0
   835
 *----------------------------------------------------------------------
sl@0
   836
 */
sl@0
   837
sl@0
   838
static TclRegexp *
sl@0
   839
CompileRegexp(interp, string, length, flags)
sl@0
   840
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
sl@0
   841
    CONST char *string;		/* The regexp to compile (UTF-8). */
sl@0
   842
    int length;			/* The length of the string in bytes. */
sl@0
   843
    int flags;			/* Compilation flags. */
sl@0
   844
{
sl@0
   845
    TclRegexp *regexpPtr;
sl@0
   846
    CONST Tcl_UniChar *uniString;
sl@0
   847
    int numChars;
sl@0
   848
    Tcl_DString stringBuf;
sl@0
   849
    int status, i;
sl@0
   850
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
sl@0
   851
 
sl@0
   852
    if (!tsdPtr->initialized) {
sl@0
   853
	tsdPtr->initialized = 1;
sl@0
   854
	Tcl_CreateThreadExitHandler(FinalizeRegexp, NULL);
sl@0
   855
    }
sl@0
   856
sl@0
   857
    /*
sl@0
   858
     * This routine maintains a second-level regular expression cache in
sl@0
   859
     * addition to the per-object regexp cache.  The per-thread cache is needed
sl@0
   860
     * to handle the case where for various reasons the object is lost between
sl@0
   861
     * invocations of the regexp command, but the literal pattern is the same.
sl@0
   862
     */
sl@0
   863
sl@0
   864
    /*
sl@0
   865
     * Check the per-thread compiled regexp cache.  We can only reuse
sl@0
   866
     * a regexp if it has the same pattern and the same flags.
sl@0
   867
     */
sl@0
   868
sl@0
   869
    for (i = 0; (i < NUM_REGEXPS) && (tsdPtr->patterns[i] != NULL); i++) {
sl@0
   870
	if ((length == tsdPtr->patLengths[i])
sl@0
   871
		&& (tsdPtr->regexps[i]->flags == flags)
sl@0
   872
		&& (strcmp(string, tsdPtr->patterns[i]) == 0)) {
sl@0
   873
	    /*
sl@0
   874
	     * Move the matched pattern to the first slot in the
sl@0
   875
	     * cache and shift the other patterns down one position.
sl@0
   876
	     */
sl@0
   877
sl@0
   878
	    if (i != 0) {
sl@0
   879
		int j;
sl@0
   880
		char *cachedString;
sl@0
   881
sl@0
   882
		cachedString = tsdPtr->patterns[i];
sl@0
   883
		regexpPtr = tsdPtr->regexps[i];
sl@0
   884
		for (j = i-1; j >= 0; j--) {
sl@0
   885
		    tsdPtr->patterns[j+1] = tsdPtr->patterns[j];
sl@0
   886
		    tsdPtr->patLengths[j+1] = tsdPtr->patLengths[j];
sl@0
   887
		    tsdPtr->regexps[j+1] = tsdPtr->regexps[j];
sl@0
   888
		}
sl@0
   889
		tsdPtr->patterns[0] = cachedString;
sl@0
   890
		tsdPtr->patLengths[0] = length;
sl@0
   891
		tsdPtr->regexps[0] = regexpPtr;
sl@0
   892
	    }
sl@0
   893
	    return tsdPtr->regexps[0];
sl@0
   894
	}
sl@0
   895
    }
sl@0
   896
sl@0
   897
    /*
sl@0
   898
     * This is a new expression, so compile it and add it to the cache.
sl@0
   899
     */
sl@0
   900
    
sl@0
   901
    regexpPtr = (TclRegexp *) ckalloc(sizeof(TclRegexp));
sl@0
   902
    regexpPtr->objPtr = NULL;
sl@0
   903
    regexpPtr->string = NULL;
sl@0
   904
    regexpPtr->details.rm_extend.rm_so = -1;
sl@0
   905
    regexpPtr->details.rm_extend.rm_eo = -1;
sl@0
   906
sl@0
   907
    /*
sl@0
   908
     * Get the up-to-date string representation and map to unicode.
sl@0
   909
     */
sl@0
   910
sl@0
   911
    Tcl_DStringInit(&stringBuf);
sl@0
   912
    uniString = Tcl_UtfToUniCharDString(string, length, &stringBuf);
sl@0
   913
    numChars = Tcl_DStringLength(&stringBuf) / sizeof(Tcl_UniChar);
sl@0
   914
sl@0
   915
    /*
sl@0
   916
     * Compile the string and check for errors.
sl@0
   917
     */
sl@0
   918
sl@0
   919
    regexpPtr->flags = flags;
sl@0
   920
    status = TclReComp(&regexpPtr->re, uniString, (size_t) numChars, flags);
sl@0
   921
    Tcl_DStringFree(&stringBuf);
sl@0
   922
sl@0
   923
    if (status != REG_OKAY) {
sl@0
   924
	/*
sl@0
   925
	 * Clean up and report errors in the interpreter, if possible.
sl@0
   926
	 */
sl@0
   927
sl@0
   928
	ckfree((char *)regexpPtr);
sl@0
   929
	if (interp) {
sl@0
   930
	    TclRegError(interp,
sl@0
   931
		    "couldn't compile regular expression pattern: ",
sl@0
   932
		    status);
sl@0
   933
	}
sl@0
   934
	return NULL;
sl@0
   935
    }
sl@0
   936
sl@0
   937
    /*
sl@0
   938
     * Allocate enough space for all of the subexpressions, plus one
sl@0
   939
     * extra for the entire pattern.
sl@0
   940
     */
sl@0
   941
sl@0
   942
    regexpPtr->matches = (regmatch_t *) ckalloc(
sl@0
   943
	    sizeof(regmatch_t) * (regexpPtr->re.re_nsub + 1));
sl@0
   944
sl@0
   945
    /*
sl@0
   946
     * Initialize the refcount to one initially, since it is in the cache.
sl@0
   947
     */
sl@0
   948
sl@0
   949
    regexpPtr->refCount = 1;
sl@0
   950
sl@0
   951
    /*
sl@0
   952
     * Free the last regexp, if necessary, and make room at the head of the
sl@0
   953
     * list for the new regexp.
sl@0
   954
     */
sl@0
   955
sl@0
   956
    if (tsdPtr->patterns[NUM_REGEXPS-1] != NULL) {
sl@0
   957
	TclRegexp *oldRegexpPtr = tsdPtr->regexps[NUM_REGEXPS-1];
sl@0
   958
	if (--(oldRegexpPtr->refCount) <= 0) {
sl@0
   959
	    FreeRegexp(oldRegexpPtr);
sl@0
   960
	}
sl@0
   961
	ckfree(tsdPtr->patterns[NUM_REGEXPS-1]);
sl@0
   962
    }
sl@0
   963
    for (i = NUM_REGEXPS - 2; i >= 0; i--) {
sl@0
   964
	tsdPtr->patterns[i+1] = tsdPtr->patterns[i];
sl@0
   965
	tsdPtr->patLengths[i+1] = tsdPtr->patLengths[i];
sl@0
   966
	tsdPtr->regexps[i+1] = tsdPtr->regexps[i];
sl@0
   967
    }
sl@0
   968
    tsdPtr->patterns[0] = (char *) ckalloc((unsigned) (length+1));
sl@0
   969
    strcpy(tsdPtr->patterns[0], string);
sl@0
   970
    tsdPtr->patLengths[0] = length;
sl@0
   971
    tsdPtr->regexps[0] = regexpPtr;
sl@0
   972
sl@0
   973
    return regexpPtr;
sl@0
   974
}
sl@0
   975

sl@0
   976
/*
sl@0
   977
 *----------------------------------------------------------------------
sl@0
   978
 *
sl@0
   979
 * FreeRegexp --
sl@0
   980
 *
sl@0
   981
 *	Release the storage associated with a TclRegexp.
sl@0
   982
 *
sl@0
   983
 * Results:
sl@0
   984
 *	None.
sl@0
   985
 *
sl@0
   986
 * Side effects:
sl@0
   987
 *	None.
sl@0
   988
 *
sl@0
   989
 *----------------------------------------------------------------------
sl@0
   990
 */
sl@0
   991
sl@0
   992
static void
sl@0
   993
FreeRegexp(regexpPtr)
sl@0
   994
    TclRegexp *regexpPtr;	/* Compiled regular expression to free. */
sl@0
   995
{
sl@0
   996
    TclReFree(&regexpPtr->re);
sl@0
   997
    if (regexpPtr->matches) {
sl@0
   998
	ckfree((char *) regexpPtr->matches);
sl@0
   999
    }
sl@0
  1000
    ckfree((char *) regexpPtr);
sl@0
  1001
}
sl@0
  1002

sl@0
  1003
/*
sl@0
  1004
 *----------------------------------------------------------------------
sl@0
  1005
 *
sl@0
  1006
 * FinalizeRegexp --
sl@0
  1007
 *
sl@0
  1008
 *	Release the storage associated with the per-thread regexp
sl@0
  1009
 *	cache.
sl@0
  1010
 *
sl@0
  1011
 * Results:
sl@0
  1012
 *	None.
sl@0
  1013
 *
sl@0
  1014
 * Side effects:
sl@0
  1015
 *	None.
sl@0
  1016
 *
sl@0
  1017
 *----------------------------------------------------------------------
sl@0
  1018
 */
sl@0
  1019
sl@0
  1020
static void
sl@0
  1021
FinalizeRegexp(clientData)
sl@0
  1022
    ClientData clientData;	/* Not used. */
sl@0
  1023
{
sl@0
  1024
    int i;
sl@0
  1025
    TclRegexp *regexpPtr;
sl@0
  1026
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
sl@0
  1027
sl@0
  1028
    for (i = 0; (i < NUM_REGEXPS) && (tsdPtr->patterns[i] != NULL); i++) {
sl@0
  1029
	regexpPtr = tsdPtr->regexps[i];
sl@0
  1030
	if (--(regexpPtr->refCount) <= 0) {
sl@0
  1031
	    FreeRegexp(regexpPtr);
sl@0
  1032
	}
sl@0
  1033
	ckfree(tsdPtr->patterns[i]);
sl@0
  1034
	tsdPtr->patterns[i] = NULL;
sl@0
  1035
    }
sl@0
  1036
    /*
sl@0
  1037
     * We may find ourselves reinitialized if another finalization routine
sl@0
  1038
     * invokes regexps.
sl@0
  1039
     */
sl@0
  1040
    tsdPtr->initialized = 0;
sl@0
  1041
}