diff options
author | dgp <dgp@users.sourceforge.net> | 2007-11-16 07:20:49 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2007-11-16 07:20:49 (GMT) |
commit | 98f0d1a3406ed99293cd6bb505ccd29063208ce5 (patch) | |
tree | 91c4790b7f459c9347f152a95205730c4119ff6c /generic | |
parent | 55e6c0333341b101e68407be7eebe42f829c9f33 (diff) | |
download | tcl-98f0d1a3406ed99293cd6bb505ccd29063208ce5.zip tcl-98f0d1a3406ed99293cd6bb505ccd29063208ce5.tar.gz tcl-98f0d1a3406ed99293cd6bb505ccd29063208ce5.tar.bz2 |
merge updates from HEAD
Diffstat (limited to 'generic')
-rw-r--r-- | generic/regc_color.c | 16 | ||||
-rw-r--r-- | generic/regc_cvec.c | 102 | ||||
-rw-r--r-- | generic/regc_locale.c | 87 | ||||
-rw-r--r-- | generic/regc_nfa.c | 46 | ||||
-rw-r--r-- | generic/regcomp.c | 366 | ||||
-rw-r--r-- | generic/regcustom.h | 113 | ||||
-rw-r--r-- | generic/regguts.h | 34 | ||||
-rw-r--r-- | generic/tclCmdIL.c | 19 | ||||
-rw-r--r-- | generic/tclCompCmds.c | 340 | ||||
-rw-r--r-- | generic/tclCompile.c | 64 | ||||
-rw-r--r-- | generic/tclCompile.h | 10 | ||||
-rw-r--r-- | generic/tclExecute.c | 121 | ||||
-rw-r--r-- | generic/tclInt.h | 8 | ||||
-rw-r--r-- | generic/tclNamesp.c | 52 | ||||
-rw-r--r-- | generic/tclTrace.c | 251 | ||||
-rw-r--r-- | generic/tclVar.c | 126 |
16 files changed, 876 insertions, 879 deletions
diff --git a/generic/regc_color.c b/generic/regc_color.c index 02634d9..003f5fc 100644 --- a/generic/regc_color.c +++ b/generic/regc_color.c @@ -678,22 +678,6 @@ uncolorchain( a->colorchain = NULL; /* paranoia */ } -#ifdef REGEXP_MCCE_ENABLED -/* - - singleton - is this character in its own color? - ^ static int singleton(struct colormap *, pchr c); - */ -static int /* predicate */ -singleton( - struct colormap *cm, - pchr c) -{ - color co = GETCOLOR(cm, c); /* color of c */ - - return (cm->cd[co].nchrs == 1) && (cm->cd[co].sub == NOSUB); -} -#endif - /* - rainbow - add arcs of all full colors (but one) between specified states ^ static VOID rainbow(struct nfa *, struct colormap *, int, pcolor, diff --git a/generic/regc_cvec.c b/generic/regc_cvec.c index a0a14c2..64f34cd 100644 --- a/generic/regc_cvec.c +++ b/generic/regc_cvec.c @@ -36,28 +36,23 @@ /* - newcvec - allocate a new cvec - ^ static struct cvec *newcvec(int, int, int); + ^ static struct cvec *newcvec(int, int); */ static struct cvec * newcvec( int nchrs, /* to hold this many chrs... */ - int nranges, /* ... and this many ranges... */ - int nmcces) /* ... and this many MCCEs */ + int nranges) /* ... and this many ranges... */ { - size_t n, nc; - struct cvec *cv; + size_t nc = (size_t)nchrs + (size_t)nranges*2; + size_t n = sizeof(struct cvec) + nc*sizeof(chr); + struct cvec *cv = (struct cvec *) MALLOC(n); - nc = (size_t)nchrs + (size_t)nmcces*(MAXMCCE+1) + (size_t)nranges*2; - n = sizeof(struct cvec) + (size_t)(nmcces-1)*sizeof(chr *) - + nc*sizeof(chr); - cv = (struct cvec *) MALLOC(n); if (cv == NULL) { return NULL; } cv->chrspace = nchrs; - cv->chrs = (chr *)&cv->mcces[nmcces]; /* chrs just after MCCE ptrs */ - cv->mccespace = nmcces; - cv->ranges = cv->chrs + nchrs + nmcces*(MAXMCCE+1); + cv->chrs = (chr *)(((char *)cv)+sizeof(struct cvec)); + cv->ranges = cv->chrs + nchrs; cv->rangespace = nranges; return clearcvec(cv); } @@ -71,18 +66,9 @@ static struct cvec * clearcvec( struct cvec *cv) /* character vector */ { - int i; - assert(cv != NULL); cv->nchrs = 0; - assert(cv->chrs == (chr *)&cv->mcces[cv->mccespace]); - cv->nmcces = 0; - cv->nmccechrs = 0; cv->nranges = 0; - for (i = 0; i < cv->mccespace; i++) { - cv->mcces[i] = NULL; - } - return cv; } @@ -95,7 +81,6 @@ addchr( struct cvec *cv, /* character vector */ pchr c) /* character to add */ { - assert(cv->nchrs < cv->chrspace - cv->nmccechrs); cv->chrs[cv->nchrs++] = (chr)c; } @@ -115,90 +100,25 @@ addrange( cv->nranges++; } -#ifdef REGEXP_MCCE_ENABLED -/* - * This static function is currently called from a single spot in regcomp.c, - * with two NULL pointers; in that case it does nothing, so that we define out - * both the call and the code. - */ - -/* - - addmcce - add an MCCE to a cvec - ^ static VOID addmcce(struct cvec *, const chr *, const chr *); - */ - -static void -addmcce( - struct cvec *cv, /* character vector */ - const chr *startp, /* beginning of text */ - const chr *endp) /* just past end of text */ -{ - int len, i; - const chr *s, *d; - - if (startp == NULL && endp == NULL) { - return; - } - len = endp - startp; - assert(len > 0); - assert(cv->nchrs + len < cv->chrspace - cv->nmccechrs); - assert(cv->nmcces < cv->mccespace); - d = &cv->chrs[cv->chrspace - cv->nmccechrs - len - 1]; - cv->mcces[cv->nmcces++] = d; - for (s = startp, i = len; i > 0; s++, i--) { - *d++ = *s; - } - *d++ = 0; /* endmarker */ - assert(d == &cv->chrs[cv->chrspace - cv->nmccechrs]); - cv->nmccechrs += len + 1; -} -#endif - -/* - - haschr - does a cvec contain this chr? - ^ static int haschr(struct cvec *, pchr); - */ -static int /* predicate */ -haschr( - struct cvec *cv, /* character vector */ - pchr c) /* character to test for */ -{ - int i; - const chr *p; - - for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--) { - if (*p == c) { - return 1; - } - } - for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--) { - if ((*p <= c) && (c <= *(p+1))) { - return 1; - } - } - return 0; -} - /* - getcvec - get a cvec, remembering it as v->cv - ^ static struct cvec *getcvec(struct vars *, int, int, int); + ^ static struct cvec *getcvec(struct vars *, int, int); */ static struct cvec * getcvec( struct vars *v, /* context */ int nchrs, /* to hold this many chrs... */ - int nranges, /* ... and this many ranges... */ - int nmcces) /* ... and this many MCCEs */ + int nranges) /* ... and this many ranges... */ { if ((v->cv != NULL) && (nchrs <= v->cv->chrspace) && - (nranges <= v->cv->rangespace) && (nmcces <= v->cv->mccespace)) { + (nranges <= v->cv->rangespace)) { return clearcvec(v->cv); } if (v->cv != NULL) { freecvec(v->cv); } - v->cv = newcvec(nchrs, nranges, nmcces); + v->cv = newcvec(nchrs, nranges); if (v->cv == NULL) { ERR(REG_ESPACE); } diff --git a/generic/regc_locale.c b/generic/regc_locale.c index b08c300..13c3cda 100644 --- a/generic/regc_locale.c +++ b/generic/regc_locale.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: regc_locale.c,v 1.17 2007/04/19 09:00:55 dkf Exp $ + * RCS: @(#) $Id: regc_locale.c,v 1.17.2.1 2007/11/16 07:20:53 dgp Exp $ */ /* ASCII character-name table */ @@ -611,43 +611,6 @@ static const chr printCharTable[] = { #define CH NOCELT /* - - nmcces - how many distinct MCCEs are there? - ^ static int nmcces(struct vars *); - */ -static int -nmcces( - struct vars *v) /* context */ -{ - /* - * No multi-character collating elements defined at the moment. - */ - return 0; -} - -/* - - nleaders - how many chrs can be first chrs of MCCEs? - ^ static int nleaders(struct vars *); - */ -static int -nleaders( - struct vars *v) /* context */ -{ - return 0; -} - -/* - - allmcces - return a cvec with all the MCCEs of the locale - ^ static struct cvec *allmcces(struct vars *, struct cvec *); - */ -static struct cvec * -allmcces( - struct vars *v, /* context */ - struct cvec *cv) /* this is supposed to have enough room */ -{ - return clearcvec(cv); -} - -/* - element - map collating-element name to celt ^ static celt element(struct vars *, const chr *, const chr *); */ @@ -718,8 +681,8 @@ range( return NULL; } - if (!cases) { /* easy version */ - cv = getcvec(v, 0, 1, 0); + if (!cases) { /* easy version */ + cv = getcvec(v, 0, 1); NOERRN(); addrange(cv, a, b); return cv; @@ -733,7 +696,7 @@ range( nchrs = (b - a + 1)*2 + 4; - cv = getcvec(v, nchrs, 0, 0); + cv = getcvec(v, nchrs, 0); NOERRN(); for (c=a; c<=b; c++) { @@ -759,14 +722,10 @@ range( - before - is celt x before celt y, for purposes of range legality? ^ static int before(celt, celt); */ -static int /* predicate */ +static int /* predicate */ before( - celt x, celt y) /* collating elements */ + celt x, celt y) /* collating elements */ { - /* - * trivial because no MCCEs. - */ - if (x < y) { return 1; } @@ -792,7 +751,7 @@ eclass( */ if ((v->cflags®_FAKE) && c == 'x') { - cv = getcvec(v, 4, 0, 0); + cv = getcvec(v, 4, 0); addchr(cv, (chr)'x'); addchr(cv, (chr)'y'); if (cases) { @@ -809,7 +768,7 @@ eclass( if (cases) { return allcases(v, c); } - cv = getcvec(v, 1, 0, 0); + cv = getcvec(v, 1, 0); assert(cv != NULL); addchr(cv, (chr)c); return cv; @@ -889,7 +848,7 @@ cclass( switch((enum classes) index) { case CC_PRINT: - cv = getcvec(v, NUM_PRINT_CHAR, NUM_PRINT_RANGE, 0); + cv = getcvec(v, NUM_PRINT_CHAR, NUM_PRINT_RANGE); if (cv) { for (i=0 ; (size_t)i<NUM_PRINT_CHAR ; i++) { addchr(cv, printCharTable[i]); @@ -901,7 +860,7 @@ cclass( } break; case CC_ALNUM: - cv = getcvec(v, NUM_ALPHA_CHAR, NUM_DIGIT_RANGE + NUM_ALPHA_RANGE, 0); + cv = getcvec(v, NUM_ALPHA_CHAR, NUM_DIGIT_RANGE + NUM_ALPHA_RANGE); if (cv) { for (i=0 ; (size_t)i<NUM_ALPHA_CHAR ; i++) { addchr(cv, alphaCharTable[i]); @@ -917,7 +876,7 @@ cclass( } break; case CC_ALPHA: - cv = getcvec(v, NUM_ALPHA_CHAR, NUM_ALPHA_RANGE, 0); + cv = getcvec(v, NUM_ALPHA_CHAR, NUM_ALPHA_RANGE); if (cv) { for (i=0 ; (size_t)i<NUM_ALPHA_RANGE ; i++) { addrange(cv, alphaRangeTable[i].start, @@ -929,23 +888,23 @@ cclass( } break; case CC_ASCII: - cv = getcvec(v, 0, 1, 0); + cv = getcvec(v, 0, 1); if (cv) { addrange(cv, 0, 0x7f); } break; case CC_BLANK: - cv = getcvec(v, 2, 0, 0); + cv = getcvec(v, 2, 0); addchr(cv, '\t'); addchr(cv, ' '); break; case CC_CNTRL: - cv = getcvec(v, 0, 2, 0); + cv = getcvec(v, 0, 2); addrange(cv, 0x0, 0x1f); addrange(cv, 0x7f, 0x9f); break; case CC_DIGIT: - cv = getcvec(v, 0, NUM_DIGIT_RANGE, 0); + cv = getcvec(v, 0, NUM_DIGIT_RANGE); if (cv) { for (i=0 ; (size_t)i<NUM_DIGIT_RANGE ; i++) { addrange(cv, digitRangeTable[i].start, @@ -954,7 +913,7 @@ cclass( } break; case CC_PUNCT: - cv = getcvec(v, NUM_PUNCT_CHAR, NUM_PUNCT_RANGE, 0); + cv = getcvec(v, NUM_PUNCT_CHAR, NUM_PUNCT_RANGE); if (cv) { for (i=0 ; (size_t)i<NUM_PUNCT_RANGE ; i++) { addrange(cv, punctRangeTable[i].start, @@ -975,7 +934,7 @@ cclass( * someone comes up with a better arrangement!) */ - cv = getcvec(v, 0, 3, 0); + cv = getcvec(v, 0, 3); if (cv) { addrange(cv, '0', '9'); addrange(cv, 'a', 'f'); @@ -983,7 +942,7 @@ cclass( } break; case CC_SPACE: - cv = getcvec(v, NUM_SPACE_CHAR, NUM_SPACE_RANGE, 0); + cv = getcvec(v, NUM_SPACE_CHAR, NUM_SPACE_RANGE); if (cv) { for (i=0 ; (size_t)i<NUM_SPACE_RANGE ; i++) { addrange(cv, spaceRangeTable[i].start, @@ -995,7 +954,7 @@ cclass( } break; case CC_LOWER: - cv = getcvec(v, NUM_LOWER_CHAR, NUM_LOWER_RANGE, 0); + cv = getcvec(v, NUM_LOWER_CHAR, NUM_LOWER_RANGE); if (cv) { for (i=0 ; (size_t)i<NUM_LOWER_RANGE ; i++) { addrange(cv, lowerRangeTable[i].start, @@ -1007,7 +966,7 @@ cclass( } break; case CC_UPPER: - cv = getcvec(v, NUM_UPPER_CHAR, NUM_UPPER_RANGE, 0); + cv = getcvec(v, NUM_UPPER_CHAR, NUM_UPPER_RANGE); if (cv) { for (i=0 ; (size_t)i<NUM_UPPER_RANGE ; i++) { addrange(cv, upperRangeTable[i].start, @@ -1019,7 +978,7 @@ cclass( } break; case CC_GRAPH: - cv = getcvec(v, NUM_GRAPH_CHAR, NUM_GRAPH_RANGE, 0); + cv = getcvec(v, NUM_GRAPH_CHAR, NUM_GRAPH_RANGE); if (cv) { for (i=0 ; (size_t)i<NUM_GRAPH_RANGE ; i++) { addrange(cv, graphRangeTable[i].start, @@ -1057,10 +1016,10 @@ allcases( tc = Tcl_UniCharToTitle((chr)c); if (tc != uc) { - cv = getcvec(v, 3, 0, 0); + cv = getcvec(v, 3, 0); addchr(cv, tc); } else { - cv = getcvec(v, 2, 0, 0); + cv = getcvec(v, 2, 0); } addchr(cv, lc); if (lc != uc) { diff --git a/generic/regc_nfa.c b/generic/regc_nfa.c index 9f63f73..741887f 100644 --- a/generic/regc_nfa.c +++ b/generic/regc_nfa.c @@ -88,7 +88,7 @@ newnfa( - freenfa - free an entire NFA ^ static VOID freenfa(struct nfa *); */ -static VOID +static void freenfa( struct nfa *nfa) { @@ -859,6 +859,25 @@ pull( } /* + * DGP 2007-11-15: Cloning a state with a circular constraint on its list + * of outs can lead to trouble [Bug 1810038], so get rid of them first. + */ + + for (a = from->outs; a != NULL; a = nexta) { + nexta = a->outchain; + switch (a->type) { + case '^': + case '$': + case BEHIND: + case AHEAD: + if (from == a->to) { + freearc(nfa, a); + } + break; + } + } + + /* * First, clone from state if necessary to avoid other outarcs. */ @@ -997,6 +1016,28 @@ push( } /* + * DGP 2007-11-15: Here we duplicate the same protections as appear + * in pull() above to avoid troubles with cloning a state with a + * circular constraint on its list of ins. It is not clear whether + * this is necessary, or is protecting against a "can't happen". + * Any test case that actually leads to a freearc() call here would + * be a welcome addition to the test suite. + */ + + for (a = to->ins; a != NULL; a = nexta) { + nexta = a->inchain; + switch (a->type) { + case '^': + case '$': + case BEHIND: + case AHEAD: + if (a->from == to) { + freearc(nfa, a); + } + break; + } + } + /* * First, clone to state if necessary to avoid other inarcs. */ @@ -1133,7 +1174,8 @@ fixempties( do { progress = 0; - for (s = nfa->states; s != NULL && !NISERR(); s = nexts) { + for (s = nfa->states; s != NULL && !NISERR() + && s->no != FREESTATE; s = nexts) { nexts = s->next; for (a = s->outs; a != NULL && !NISERR(); a = nexta) { nexta = a->outchain; diff --git a/generic/regcomp.c b/generic/regcomp.c index b9169f9..afe1b1b 100644 --- a/generic/regcomp.c +++ b/generic/regcomp.c @@ -53,12 +53,8 @@ static void bracket(struct vars *, struct state *, struct state *); static void cbracket(struct vars *, struct state *, struct state *); static void brackpart(struct vars *, struct state *, struct state *); static const chr *scanplain(struct vars *); -static void leaders(struct vars *, struct cvec *); static void onechr(struct vars *, pchr, struct state *, struct state *); static void dovec(struct vars *, struct cvec *, struct state *, struct state *); -#ifdef REGEXP_MCCE_ENABLED -static celt nextleader(struct vars *, pchr, pchr); -#endif static void wordchrs(struct vars *); static struct subre *subre(struct vars *, int, int, struct state *, struct state *); static void freesubre(struct vars *, struct subre *); @@ -107,9 +103,6 @@ static void subblock(struct vars *, pchr, struct state *, struct state *); static void okcolors(struct nfa *, struct colormap *); static void colorchain(struct colormap *, struct arc *); static void uncolorchain(struct colormap *, struct arc *); -#ifdef REGEXP_MCCE_ENABLED -static int singleton(struct colormap *, pchr c); -#endif static void rainbow(struct nfa *, struct colormap *, int, pcolor, struct state *, struct state *); static void colorcomplement(struct nfa *, struct colormap *, int, struct state *, struct state *, struct state *); #ifdef REG_DEBUG @@ -171,20 +164,13 @@ static void dumpcnfa(struct cnfa *, FILE *); static void dumpcstate(int, struct carc *, struct cnfa *, FILE *); #endif /* === regc_cvec.c === */ -static struct cvec *newcvec(int, int, int); static struct cvec *clearcvec(struct cvec *); static void addchr(struct cvec *, pchr); static void addrange(struct cvec *, pchr, pchr); -#ifdef REGEXP_MCCE_ENABLED -static void addmcce(struct cvec *, const chr *, const chr *); -#endif -static int haschr(struct cvec *, pchr); -static struct cvec *getcvec(struct vars *, int, int, int); +static struct cvec *newcvec(int, int); +static struct cvec *getcvec(struct vars *, int, int); static void freecvec(struct cvec *); /* === regc_locale.c === */ -static int nmcces(struct vars *); -static int nleaders(struct vars *); -static struct cvec *allmcces(struct vars *, struct cvec *); static celt element(struct vars *, const chr *, const chr *); static struct cvec *range(struct vars *, celt, celt, int); static int before(celt, celt); @@ -223,10 +209,6 @@ struct vars { int ntree; /* number of tree nodes */ struct cvec *cv; /* interface cvec */ struct cvec *cv2; /* utility cvec */ - struct cvec *mcces; /* collating-element information */ -#define ISCELEADER(v,c) (v->mcces != NULL && haschr(v->mcces, (c))) - struct state *mccepbegin; /* in nfa, start of MCCE prototypes */ - struct state *mccepend; /* in nfa, end of MCCE prototypes */ struct subre *lacons; /* lookahead-constraint vector */ int nlacons; /* size of lacons */ }; @@ -336,7 +318,6 @@ compile( v->treefree = NULL; v->cv = NULL; v->cv2 = NULL; - v->mcces = NULL; v->lacons = NULL; v->nlacons = 0; re->re_magic = REMAGIC; @@ -362,22 +343,10 @@ compile( ZAPCNFA(g->search); v->nfa = newnfa(v, v->cm, NULL); CNOERR(); - v->cv = newcvec(100, 20, 10); + v->cv = newcvec(100, 20); if (v->cv == NULL) { return freev(v, REG_ESPACE); } - i = nmcces(v); - if (i > 0) { - v->mcces = newcvec(nleaders(v), 0, i); - CNOERR(); - v->mcces = allmcces(v, v->mcces); - leaders(v, v->mcces); -#ifdef REGEXP_MCCE_ENABLED - /* Function does nothing with NULL pointers */ - addmcce(v->mcces, NULL, NULL); /* dummy */ -#endif - } - CNOERR(); /* * Parsing. @@ -550,9 +519,6 @@ freev( if (v->cv2 != NULL) { freecvec(v->cv2); } - if (v->mcces != NULL) { - freecvec(v->mcces); - } if (v->lacons != NULL) { freelacons(v->lacons, v->nlacons); } @@ -839,7 +805,6 @@ parseqatom( } NEXT(); return; - break; case '$': ARCV('$', 1); if (v->cflags®_NLANCH) { @@ -847,19 +812,16 @@ parseqatom( } NEXT(); return; - break; case SBEGIN: ARCV('^', 1); /* BOL */ ARCV('^', 0); /* or BOS */ NEXT(); return; - break; case SEND: ARCV('$', 1); /* EOL */ ARCV('$', 0); /* or EOS */ NEXT(); return; - break; case '<': wordchrs(v); /* does NEXT() */ s = newstate(v->nfa); @@ -867,7 +829,6 @@ parseqatom( nonword(v, BEHIND, lp, s); word(v, AHEAD, s, rp); return; - break; case '>': wordchrs(v); /* does NEXT() */ s = newstate(v->nfa); @@ -875,7 +836,6 @@ parseqatom( word(v, BEHIND, lp, s); nonword(v, AHEAD, s, rp); return; - break; case WBDRY: wordchrs(v); /* does NEXT() */ s = newstate(v->nfa); @@ -887,7 +847,6 @@ parseqatom( word(v, BEHIND, lp, s); nonword(v, AHEAD, s, rp); return; - break; case NWBDRY: wordchrs(v); /* does NEXT() */ s = newstate(v->nfa); @@ -899,7 +858,6 @@ parseqatom( nonword(v, BEHIND, lp, s); nonword(v, AHEAD, s, rp); return; - break; case LACON: /* lookahead constraint */ pos = v->nextvalue; NEXT(); @@ -914,7 +872,6 @@ parseqatom( NOERR(); ARCV(LACON, n); return; - break; /* * Then errors, to get them out of the way. @@ -926,11 +883,9 @@ parseqatom( case '{': ERR(REG_BADRPT); return; - break; default: ERR(REG_ASSERT); return; - break; /* * Then plain characters, and minor variants on that theme. @@ -1467,13 +1422,6 @@ cbracket( { struct state *left = newstate(v->nfa); struct state *right = newstate(v->nfa); - struct state *s; - struct arc *a; /* arc from lp */ - struct arc *ba; /* arc from left, from bracket() */ - struct arc *pa; /* MCCE-prototype arc */ - color co; - const chr *p; - int i; NOERR(); bracket(v, left, right); @@ -1485,67 +1433,16 @@ cbracket( assert(lp->nouts == 0); /* all outarcs will be ours */ /* - * Easy part of complementing + * Easy part of complementing, and all there is to do since the MCCE code + * was removed. */ colorcomplement(v->nfa, v->cm, PLAIN, left, lp, rp); NOERR(); - if (v->mcces == NULL) { /* no MCCEs -- we're done */ - dropstate(v->nfa, left); - assert(right->nins == 0); - freestate(v->nfa, right); - return; - } - - /* - * But complementing gets messy in the presence of MCCEs... - */ - - NOTE(REG_ULOCALE); - for (p = v->mcces->chrs, i = v->mcces->nchrs; i > 0; p++, i--) { - co = GETCOLOR(v->cm, *p); - a = findarc(lp, PLAIN, co); - ba = findarc(left, PLAIN, co); - if (ba == NULL) { - assert(a != NULL); - freearc(v->nfa, a); - } else { - assert(a == NULL); - } - s = newstate(v->nfa); - NOERR(); - newarc(v->nfa, PLAIN, co, lp, s); - NOERR(); - pa = findarc(v->mccepbegin, PLAIN, co); - assert(pa != NULL); - if (ba == NULL) { /* easy case, need all of them */ - cloneouts(v->nfa, pa->to, s, rp, PLAIN); - newarc(v->nfa, '$', 1, s, rp); - newarc(v->nfa, '$', 0, s, rp); - colorcomplement(v->nfa, v->cm, AHEAD, pa->to, s, rp); - } else { /* must be selective */ - if (findarc(ba->to, '$', 1) == NULL) { - newarc(v->nfa, '$', 1, s, rp); - newarc(v->nfa, '$', 0, s, rp); - colorcomplement(v->nfa, v->cm, AHEAD, pa->to, s, rp); - } - for (pa = pa->to->outs; pa != NULL; pa = pa->outchain) { - if (findarc(ba->to, PLAIN, pa->co) == NULL) { - newarc(v->nfa, PLAIN, pa->co, s, rp); - } - } - if (s->nouts == 0) { /* limit of selectivity: none */ - dropstate(v->nfa, s); /* frees arc too */ - } - } - NOERR(); - } - - delsub(v->nfa, left, right); - assert(left->nouts == 0); - freestate(v->nfa, left); + dropstate(v->nfa, left); assert(right->nins == 0); freestate(v->nfa, right); + return; } /* @@ -1577,10 +1474,10 @@ brackpart( NEXT(); /* - * Shortcut for ordinary chr (not range, not MCCE leader). + * Shortcut for ordinary chr (not range). */ - if (!SEE(RANGE) && !ISCELEADER(v, c[0])) { + if (!SEE(RANGE)) { onechr(v, c[0], lp, rp); return; } @@ -1691,48 +1588,6 @@ scanplain( } /* - - leaders - process a cvec of collating elements to also include leaders - * Also gives all characters involved their own colors, which is almost - * certainly necessary, and sets up little disconnected subNFA. - ^ static void leaders(struct vars *, struct cvec *); - */ -static void -leaders( - struct vars *v, - struct cvec *cv) -{ - int mcce; - const chr *p; - chr leader; - struct state *s; - struct arc *a; - - v->mccepbegin = newstate(v->nfa); - v->mccepend = newstate(v->nfa); - NOERR(); - - for (mcce = 0; mcce < cv->nmcces; mcce++) { - p = cv->mcces[mcce]; - leader = *p; - if (!haschr(cv, leader)) { - addchr(cv, leader); - s = newstate(v->nfa); - newarc(v->nfa, PLAIN, subcolor(v->cm, leader), v->mccepbegin, s); - okcolors(v->nfa, v->cm); - } else { - a = findarc(v->mccepbegin, PLAIN, GETCOLOR(v->cm, leader)); - assert(a != NULL); - s = a->to; - assert(s != v->mccepend); - } - p++; - assert(*p != 0 && *(p+1) == 0); /* only 2-char MCCEs for now */ - newarc(v->nfa, PLAIN, subcolor(v->cm, *p), s, v->mccepend); - okcolors(v->nfa, v->cm); - } -} - -/* - onechr - fill in arcs for a plain character, and possible case complements * This is mostly a shortcut for efficient handling of the common case. ^ static void onechr(struct vars *, pchr, struct state *, struct state *); @@ -1749,17 +1604,18 @@ onechr( return; } - /* rats, need general case anyway... */ + /* + * Rats, need general case anyway... + */ + dovec(v, allcases(v, c), lp, rp); } /* - dovec - fill in arcs for each element of a cvec - * This one has to handle the messy cases, like MCCEs and MCCE leaders. ^ static void dovec(struct vars *, struct cvec *, struct state *, ^ struct state *); */ -#ifndef REGEXP_MCCE_ENABLED static void dovec( struct vars *v, @@ -1785,184 +1641,6 @@ dovec( } } -#else /* REGEXP_MCCE_ENABLED */ -static void -dovec( - struct vars *v, - struct cvec *cv, - struct state *lp, - struct state *rp) -{ - chr ch, from, to; - celt ce; - const chr *p; - int i; - struct cvec *leads; - color co; - struct arc *a; - struct arc *pa; /* arc in prototype */ - struct state *s; - struct state *ps; /* state in prototype */ - - /* - * Need a place to store leaders, if any. - */ - - if (nmcces(v) > 0) { - assert(v->mcces != NULL); - if (v->cv2 == NULL || v->cv2->nchrs < v->mcces->nchrs) { - if (v->cv2 != NULL) { - free(v->cv2); - } - v->cv2 = newcvec(v->mcces->nchrs, 0, v->mcces->nmcces); - NOERR(); - leads = v->cv2; - } else { - leads = clearcvec(v->cv2); - } - } else { - leads = NULL; - } - - /* - * First, get the ordinary characters out of the way. - */ - - for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--) { - ch = *p; - if (!ISCELEADER(v, ch)) { - newarc(v->nfa, PLAIN, subcolor(v->cm, ch), lp, rp); - } else { - assert(singleton(v->cm, ch)); - assert(leads != NULL); - if (!haschr(leads, ch)) { - addchr(leads, ch); - } - } - } - - /* - * And the ranges. - */ - - for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--) { - from = *p; - to = *(p+1); - while (from <= to && (ce = nextleader(v, from, to)) != NOCELT) { - if (from < ce) { - subrange(v, from, ce - 1, lp, rp); - } - assert(singleton(v->cm, ce)); - assert(leads != NULL); - if (!haschr(leads, ce)) { - addchr(leads, ce); - } - from = ce + 1; - } - if (from <= to) { - subrange(v, from, to, lp, rp); - } - } - - /* *** WARNING *** - * - * This was buggy, check before enabling: the original version would cause - * a segfault at the loopinit below if (leads==NULL && cv->nmcces!=0) - * Possibly just a problem with parens? The original condition was - * ((leads == NULL || leads->nchrs == 0) && cv->nmcces == 0) - */ - - if (leads == NULL || (leads->nchrs == 0 && cv->nmcces == 0)) { - return; - } - - /* - * Deal with the MCCE leaders. - */ - - NOTE(REG_ULOCALE); - for (p = leads->chrs, i = leads->nchrs; i > 0; p++, i--) { - co = GETCOLOR(v->cm, *p); - a = findarc(lp, PLAIN, co); - if (a != NULL) { - s = a->to; - } else { - s = newstate(v->nfa); - NOERR(); - newarc(v->nfa, PLAIN, co, lp, s); - NOERR(); - } - pa = findarc(v->mccepbegin, PLAIN, co); - assert(pa != NULL); - ps = pa->to; - newarc(v->nfa, '$', 1, s, rp); - newarc(v->nfa, '$', 0, s, rp); - colorcomplement(v->nfa, v->cm, AHEAD, ps, s, rp); - NOERR(); - } - - /* - * And the MCCEs. - */ - - for (i = 0; i < cv->nmcces; i++) { - p = cv->mcces[i]; - assert(singleton(v->cm, *p)); - if (!singleton(v->cm, *p)) { - ERR(REG_ASSERT); - return; - } - ch = *p++; - co = GETCOLOR(v->cm, ch); - a = findarc(lp, PLAIN, co); - if (a != NULL) { - s = a->to; - } else { - s = newstate(v->nfa); - NOERR(); - newarc(v->nfa, PLAIN, co, lp, s); - NOERR(); - } - assert(*p != 0); /* at least two chars */ - assert(singleton(v->cm, *p)); - ch = *p++; - co = GETCOLOR(v->cm, ch); - assert(*p == 0); /* and only two, for now */ - newarc(v->nfa, PLAIN, co, s, rp); - NOERR(); - } -} - -/* - - nextleader - find next MCCE leader within range - ^ static celt nextleader(struct vars *, pchr, pchr); - */ -static celt /* NOCELT means none */ -nextleader( - struct vars *v, - pchr from, - pchr to) -{ - int i; - const chr *p; - chr ch; - celt it = NOCELT; - - if (v->mcces == NULL) { - return it; - } - - for (i = v->mcces->nchrs, p = v->mcces->chrs; i > 0; i--, p++) { - ch = *p; - if (from <= ch && ch <= to) { - if (it == NOCELT || ch < it) { - it = ch; - } - } - } - return it; -} -#endif /* - wordchrs - set up word-chr list for word-boundary stuff, if needed @@ -2103,20 +1781,14 @@ optst( struct vars *v, struct subre *t) { - if (t == NULL) { - return; - } - /* - * Recurse through children. + * DGP (2007-11-13): I assume it was the programmer's intent to eventually + * come back and add code to optimize subRE trees, but the routine coded + * just spends effort traversing the tree and doing nothing. We can do + * nothing with less effort. */ - if (t->left != NULL) { - optst(v, t->left); - } - if (t->right != NULL) { - optst(v, t->right); - } + return; } /* @@ -2447,8 +2119,8 @@ stdump( if (!NULLCNFA(t->cnfa)) { fprintf(f, "\n"); dumpcnfa(&t->cnfa, f); - fprintf(f, "\n"); } + fprintf(f, "\n"); if (t->left != NULL) { stdump(t->left, f, nfapresent); } diff --git a/generic/regcustom.h b/generic/regcustom.h index 6b6b38c..ac33087 100644 --- a/generic/regcustom.h +++ b/generic/regcustom.h @@ -3,13 +3,13 @@ * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics - * Corporation, none of whom are responsible for the results. The author + * Corporation, none of whom are responsible for the results. The author * thanks all of them. * - * Redistribution and use in source and binary forms -- with or without - * modification -- are permitted for any purpose, provided that - * redistributions in source form retain this entire copyright notice and - * indicate the origin and nature of any modifications. + * Redistribution and use in source and binary forms - with or without + * modification - are permitted for any purpose, provided that redistributions + * in source form retain this entire copyright notice and indicate the origin + * and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation of * software which uses it, but that is not a requirement. @@ -26,23 +26,28 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* headers if any */ +/* + * Headers if any. + */ + #include "tclInt.h" -/* overrides for regguts.h definitions, if any */ -#define FUNCPTR(name, args) (*name) _ANSI_ARGS_(args) +/* + * Overrides for regguts.h definitions, if any. + */ + +#define FUNCPTR(name, args) (*name)args #define MALLOC(n) ckalloc(n) #define FREE(p) ckfree(VS(p)) #define REALLOC(p,n) ckrealloc(VS(p),n) - - /* - * Do not insert extras between the "begin" and "end" lines -- this - * chunk is automatically extracted to be fitted into regex.h. + * Do not insert extras between the "begin" and "end" lines - this chunk is + * automatically extracted to be fitted into regex.h. */ + /* --- begin --- */ -/* ensure certain things don't sneak in from system headers */ +/* Ensure certain things don't sneak in from system headers. */ #ifdef __REG_WIDE_T #undef __REG_WIDE_T #endif @@ -67,70 +72,90 @@ #ifdef __REG_NOCHAR #undef __REG_NOCHAR #endif -/* interface types */ +/* Interface types */ #define __REG_WIDE_T Tcl_UniChar -#define __REG_REGOFF_T long /* not really right, but good enough... */ -#define __REG_VOID_T VOID -#define __REG_CONST CONST -/* names and declarations */ +#define __REG_REGOFF_T long /* Not really right, but good enough... */ +#define __REG_VOID_T void +#define __REG_CONST const +/* Names and declarations */ #define __REG_WIDE_COMPILE TclReComp #define __REG_WIDE_EXEC TclReExec -#define __REG_NOFRONT /* don't want regcomp() and regexec() */ -#define __REG_NOCHAR /* or the char versions */ +#define __REG_NOFRONT /* Don't want regcomp() and regexec() */ +#define __REG_NOCHAR /* Or the char versions */ #define regfree TclReFree #define regerror TclReError /* --- end --- */ +/* + * Internal character type and related. + */ - -/* internal character type and related */ -typedef Tcl_UniChar chr; /* the type itself */ -typedef int pchr; /* what it promotes to */ -typedef unsigned uchr; /* unsigned type that will hold a chr */ -typedef int celt; /* type to hold chr, MCCE number, or NOCELT */ -#define NOCELT (-1) /* celt value which is not valid chr or MCCE */ -#define CHR(c) (UCHAR(c)) /* turn char literal into chr literal */ -#define DIGITVAL(c) ((c)-'0') /* turn chr digit into its value */ +typedef Tcl_UniChar chr; /* The type itself. */ +typedef int pchr; /* What it promotes to. */ +typedef unsigned uchr; /* Unsigned type that will hold a chr. */ +typedef int celt; /* Type to hold chr, or NOCELT */ +#define NOCELT (-1) /* Celt value which is not valid chr */ +#define CHR(c) (UCHAR(c)) /* Turn char literal into chr literal */ +#define DIGITVAL(c) ((c)-'0') /* Turn chr digit into its value */ #if TCL_UTF_MAX > 3 -#define CHRBITS 32 /* bits in a chr; must not use sizeof */ -#define CHR_MIN 0x00000000 /* smallest and largest chr; the value */ -#define CHR_MAX 0xffffffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */ +#define CHRBITS 32 /* Bits in a chr; must not use sizeof */ +#define CHR_MIN 0x00000000 /* Smallest and largest chr; the value */ +#define CHR_MAX 0xffffffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */ #else -#define CHRBITS 16 /* bits in a chr; must not use sizeof */ -#define CHR_MIN 0x0000 /* smallest and largest chr; the value */ -#define CHR_MAX 0xffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */ +#define CHRBITS 16 /* Bits in a chr; must not use sizeof */ +#define CHR_MIN 0x0000 /* Smallest and largest chr; the value */ +#define CHR_MAX 0xffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */ #endif -/* functions operating on chr */ +/* + * Functions operating on chr. + */ + #define iscalnum(x) Tcl_UniCharIsAlnum(x) #define iscalpha(x) Tcl_UniCharIsAlpha(x) #define iscdigit(x) Tcl_UniCharIsDigit(x) #define iscspace(x) Tcl_UniCharIsSpace(x) -/* name the external functions */ +/* + * Name the external functions. + */ + #define compile TclReComp #define exec TclReExec -/* enable/disable debugging code (by whether REG_DEBUG is defined or not) */ -#if 0 /* no debug unless requested by makefile */ +/* +& Enable/disable debugging code (by whether REG_DEBUG is defined or not). +*/ + +#if 0 /* No debug unless requested by makefile. */ #define REG_DEBUG /* */ #endif -/* method of allocating a local workspace */ +/* + * Method of allocating a local workspace. We used a thread-specific data + * space to store this because the regular expression engine is never + * reentered from the same thread; it doesn't make any callbacks. + */ + #if 1 #define AllocVars(vPtr) \ static Tcl_ThreadDataKey varsKey; \ register struct vars *vPtr = (struct vars *) \ - Tcl_GetThreadData(&varsKey, sizeof(struct vars)) + Tcl_GetThreadData(&varsKey, sizeof(struct vars)) #else -/* This strategy for allocating workspace is "more proper" in some sense, but +/* + * This strategy for allocating workspace is "more proper" in some sense, but * quite a bit slower. Using TSD (as above) leads to code that is quite a bit - * faster in practice. */ + * faster in practice (measured!) + */ #define AllocVars(vPtr) \ register struct vars *vPtr = (struct vars *) MALLOC(sizeof(struct vars)) #define FreeVars(vPtr) \ FREE(vPtr) #endif -/* and pick up the standard header */ +/* + * And pick up the standard header. + */ + #include "regex.h" diff --git a/generic/regguts.h b/generic/regguts.h index 991979e..cbf6615 100644 --- a/generic/regguts.h +++ b/generic/regguts.h @@ -60,24 +60,24 @@ /* voids */ #ifndef VOID -#define VOID void /* for function return values */ +#define VOID void /* for function return values */ #endif #ifndef DISCARD -#define DISCARD void /* for throwing values away */ +#define DISCARD void /* for throwing values away */ #endif #ifndef PVOID -#define PVOID void * /* generic pointer */ +#define PVOID void * /* generic pointer */ #endif #ifndef VS -#define VS(x) ((void*)(x)) /* cast something to generic ptr */ +#define VS(x) ((void*)(x)) /* cast something to generic ptr */ #endif #ifndef NOPARMS -#define NOPARMS void /* for empty parm lists */ +#define NOPARMS void /* for empty parm lists */ #endif /* const */ #ifndef CONST -#define CONST const /* for old compilers, might be empty */ +#define CONST const /* for old compilers, might be empty */ #endif /* function-pointer declarator */ @@ -105,7 +105,7 @@ #include <limits.h> #endif #ifndef _POSIX2_RE_DUP_MAX -#define _POSIX2_RE_DUP_MAX 255 /* normally from <limits.h> */ +#define _POSIX2_RE_DUP_MAX 255 /* normally from <limits.h> */ #endif /* @@ -189,7 +189,7 @@ union tree { #define tcolor colors.ccolor #define tptr ptrs.pptr -/* internal per-color structure for the color machinery */ +/* Internal per-color descriptor structure for the color machinery */ struct colordesc { uchr nchrs; /* number of chars of this color */ color sub; /* open subcolor (if any); free chain ptr */ @@ -235,9 +235,9 @@ struct colormap { /* * Interface definitions for locale-interface functions in locale.c. - * Multi-character collating elements (MCCEs) cause most of the trouble. */ +/* Representation of a set of characters. */ struct cvec { int nchrs; /* number of chrs */ int chrspace; /* number of chrs possible */ @@ -245,18 +245,11 @@ struct cvec { int nranges; /* number of ranges (chr pairs) */ int rangespace; /* number of chrs possible */ chr *ranges; /* pointer to vector of chr pairs */ - int nmcces; /* number of MCCEs */ - int mccespace; /* number of MCCEs possible */ - int nmccechrs; /* number of chrs used for MCCEs */ - chr *mcces[1]; /* pointers to 0-terminated MCCEs */ - /* and both batches of chrs are on the end */ }; -/* caution: this value cannot be changed easily */ -#define MAXMCCE 2 /* length of longest MCCE */ - /* - * definitions for NFA internal representation + * definitions for non-deterministic finite autmaton (NFA) internal + * representation * * Having a "from" pointer within each arc may seem redundant, but it saves a * lot of hassle. @@ -284,7 +277,7 @@ struct arcbatch { /* for bulk allocation of arcs */ struct state { int no; -# define FREESTATE (-1) +#define FREESTATE (-1) char flag; /* marks special states */ int nins; /* number of inarcs */ struct arc *ins; /* chain of inarcs */ @@ -401,7 +394,8 @@ struct guts { }; /* - * Magic for allocating a variable workspace. + * Magic for allocating a variable workspace. This default version is + * stack-hungry. */ #ifndef AllocVars diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c index d558cd1..a7c53f4 100644 --- a/generic/tclCmdIL.c +++ b/generic/tclCmdIL.c @@ -16,7 +16,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdIL.c,v 1.115.2.8 2007/11/12 19:18:14 dgp Exp $ + * RCS: @(#) $Id: tclCmdIL.c,v 1.115.2.9 2007/11/16 07:20:53 dgp Exp $ */ #include "tclInt.h" @@ -110,8 +110,6 @@ static int InfoCompleteCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); static int InfoDefaultCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); -static int InfoExistsCmd(ClientData dummy, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[]); /* TIP #280 - New 'info' subcommand 'frame' */ static int InfoFrameCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); @@ -161,7 +159,7 @@ static const struct { {"commands", InfoCommandsCmd}, {"complete", InfoCompleteCmd}, {"default", InfoDefaultCmd}, - {"exists", InfoExistsCmd}, + {"exists", TclInfoExistsCmd}, {"frame", InfoFrameCmd}, {"functions", InfoFunctionsCmd}, {"globals", TclInfoGlobalsCmd}, @@ -416,6 +414,13 @@ TclInitInfoCmd( } Tcl_SetEnsembleMappingDict(interp, ensemble, mapDict); } + + /* + * Enable compilation of the [info exists] subcommand. + */ + + ((Command *)ensemble)->compileProc = &TclCompileInfoCmd; + return ensemble; } @@ -990,7 +995,7 @@ InfoDefaultCmd( /* *---------------------------------------------------------------------- * - * InfoExistsCmd -- + * TclInfoExistsCmd -- * * Called to implement the "info exists" command that determines whether * a variable exists. Handles the following syntax: @@ -1007,8 +1012,8 @@ InfoDefaultCmd( *---------------------------------------------------------------------- */ -static int -InfoExistsCmd( +int +TclInfoExistsCmd( ClientData dummy, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 5d64717..9bc0f30 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompCmds.c,v 1.109.2.10 2007/11/12 19:18:15 dgp Exp $ + * RCS: @(#) $Id: tclCompCmds.c,v 1.109.2.11 2007/11/16 07:20:53 dgp Exp $ */ #include "tclInt.h" @@ -61,7 +61,6 @@ TclCompileCmdWord((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \ (envPtr)) - /* * Convenience macro for use when compiling tokens to be pushed. The ANSI C * "prototype" for this macro is: @@ -916,8 +915,7 @@ TclCompileDictCmd( Tcl_Token **keyTokenPtrs, *dictVarTokenPtr, *bodyTokenPtr; DictUpdateInfo *duiPtr; JumpFixup jumpFixup; - - + /* * Parse the command. Expect the following: * dict update <lit(eral)> <any> <lit> ?<any> <lit> ...? <lit> @@ -995,9 +993,9 @@ TclCompileDictCmd( /* * Normal termination code: the stack has the key list below the * result of the body evaluation: swap them and finish the update - * code. + * code. */ - + TclEmitOpcode( INST_END_CATCH, envPtr); TclEmitInstInt4( INST_REVERSE, 2, envPtr); TclEmitInstInt4( INST_DICT_UPDATE_END, dictIndex, envPtr); @@ -1006,7 +1004,7 @@ TclCompileDictCmd( /* * Jump around the exceptional termination code */ - + TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup); /* @@ -1014,7 +1012,7 @@ TclCompileDictCmd( * options in the stack, bring up the key list, finish the update * code, and finally return with the catched return data */ - + ExceptionRangeTarget(envPtr, range, catchOffset); TclEmitOpcode( INST_PUSH_RESULT, envPtr); TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr); @@ -1025,7 +1023,6 @@ TclCompileDictCmd( TclEmitInt4( infoIndex, envPtr); TclEmitOpcode( INST_RETURN_STK, envPtr); - if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) { Tcl_Panic("TclCompileDictCmd(update): bad jump distance %d", CurrentOffset(envPtr) - jumpFixup.codeOffset); @@ -1303,7 +1300,6 @@ TclCompileForCmd( envPtr->currStackDepth = savedStackDepth + 1; TclEmitOpcode(INST_POP, envPtr); - /* * Compile the "next" subcommand. */ @@ -1890,7 +1886,6 @@ TclCompileIfCmd( tokenPtr = TokenAfter(tokenPtr); } - TclInitJumpFixupArray(&jumpFalseFixupArray); TclInitJumpFixupArray(&jumpEndFixupArray); code = TCL_OK; @@ -1929,7 +1924,6 @@ TclCompileIfCmd( envPtr->currStackDepth = savedStackDepth; testTokenPtr = tokenPtr; - if (realCond) { /* * Find out if the condition is a constant. @@ -1964,7 +1958,6 @@ TclCompileIfCmd( code = TCL_OK; } - /* * Skip over the optional "then" before the then clause. */ @@ -2944,8 +2937,8 @@ TclCompileRegexpCmd( } /* - * Get the regexp string. If it is not a simple string, punt to runtime. - * If it has a '-', it could be an incorrectly formed regexp command. + * Get the regexp string. If it is not a simple string or can't be + * converted to a glob pattern, push the word for the INST_REGEXP. */ varTokenPtr = TokenAfter(varTokenPtr); @@ -2953,9 +2946,12 @@ TclCompileRegexpCmd( if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { Tcl_DString ds; - simple = 1; str = (char *) varTokenPtr[1].start; len = varTokenPtr[1].size; + /* + * If it has a '-', it could be an incorrectly formed regexp command. + */ + if ((*str == '-') && !sawLast) { return TCL_ERROR; } @@ -2971,17 +2967,18 @@ TclCompileRegexpCmd( /* * Attempt to convert pattern to glob. If successful, push the - * converted pattern. + * converted pattern as a literal. */ if (TclReToGlob(NULL, varTokenPtr[1].start, len, &ds, &exact) - != TCL_OK) { - return TCL_ERROR; + == TCL_OK) { + simple = 1; + PushLiteral(envPtr, Tcl_DStringValue(&ds),Tcl_DStringLength(&ds)); + Tcl_DStringFree(&ds); } + } - PushLiteral(envPtr, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds)); - Tcl_DStringFree(&ds); - } else { + if (!simple) { CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords-2); } @@ -3175,7 +3172,7 @@ CompileReturnInternal( unsigned char op, int code, int level, - Tcl_Obj *returnOpts) + Tcl_Obj *returnOpts) { TclEmitPush(TclAddLiteralObj(envPtr, returnOpts, NULL), envPtr); TclEmitInstInt4(op, code, envPtr); @@ -3543,7 +3540,7 @@ TclCompileSwitchCmd( int numWords; /* Number of words in command. */ Tcl_Token *valueTokenPtr; /* Token for the value to switch on. */ - enum {Switch_Exact, Switch_Glob} mode; + enum {Switch_Exact, Switch_Glob, Switch_Regexp} mode; /* What kind of switch are we doing? */ Tcl_Token *bodyTokenArray; /* Array of real pattern list items. */ @@ -3571,12 +3568,14 @@ TclCompileSwitchCmd( /* * Only handle the following versions: - * switch -- word {pattern body ...} - * switch -exact -- word {pattern body ...} - * switch -glob -- word {pattern body ...} - * switch -- word simpleWordPattern simpleWordBody ... - * switch -exact -- word simpleWordPattern simpleWordBody ... - * switch -glob -- word simpleWordPattern simpleWordBody ... + * switch -- word {pattern body ...} + * switch -exact -- word {pattern body ...} + * switch -glob -- word {pattern body ...} + * switch -regexp -- word {pattern body ...} + * switch -- word simpleWordPattern simpleWordBody ... + * switch -exact -- word simpleWordPattern simpleWordBody ... + * switch -glob -- word simpleWordPattern simpleWordBody ... + * switch -regexp -- word simpleWordPattern simpleWordBody ... * When the mode is -glob, can also handle a -nocase flag. * * First off, we don't care how the command's word was generated; we're @@ -3628,6 +3627,14 @@ TclCompileSwitchCmd( foundMode = 1; valueIndex++; continue; + } else if ((size <= 7) && !memcmp(chrs, "-regexp", size)) { + if (foundMode) { + return TCL_ERROR; + } + mode = Switch_Regexp; + foundMode = 1; + valueIndex++; + continue; } else if ((size <= 7) && !memcmp(chrs, "-nocase", size)) { noCase = 1; valueIndex++; @@ -3651,7 +3658,7 @@ TclCompileSwitchCmd( } tokenPtr = TokenAfter(tokenPtr); numWords--; - if (noCase && (mode == Switch_Exact)) { + if (noCase && (mode != Switch_Exact)) { /* * Can't compile this case; no opcode for case-insensitive equality! */ @@ -4063,19 +4070,65 @@ TclCompileSwitchCmd( if (i!=numWords-2 || bodyToken[numWords-2]->size != 7 || memcmp(bodyToken[numWords-2]->start, "default", 7)) { /* - * Generate the test for the arm. This code is slightly - * inefficient, but much simpler than the first version. + * Generate the test for the arm. */ - TclCompileTokens(interp, bodyToken[i], 1, envPtr); - TclEmitInstInt4(INST_OVER, 1, envPtr); switch (mode) { case Switch_Exact: + TclEmitOpcode(INST_DUP, envPtr); + TclCompileTokens(interp, bodyToken[i], 1, envPtr); TclEmitOpcode(INST_STR_EQ, envPtr); break; case Switch_Glob: + TclCompileTokens(interp, bodyToken[i], 1, envPtr); + TclEmitInstInt4(INST_OVER, 1, envPtr); TclEmitInstInt1(INST_STR_MATCH, noCase, envPtr); break; + case Switch_Regexp: { + int simple = 0, exact = 0; + + if (bodyToken[i]->type == TCL_TOKEN_TEXT) { + Tcl_DString ds; + + if (bodyToken[i]->size == 0) { + /* + * The semantics of regexps are that they always match + * when the RE == "". + */ + + PushLiteral(envPtr, "1", 1); + break; + } + + /* + * Attempt to convert pattern to glob. If successful, push + * the converted pattern. + */ + + if (TclReToGlob(NULL, bodyToken[i]->start, + bodyToken[i]->size, &ds, &exact) == TCL_OK) { + simple = 1; + PushLiteral(envPtr, Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds)); + Tcl_DStringFree(&ds); + } + } + if (!simple) { + TclCompileTokens(interp, bodyToken[i], 1, envPtr); + } + + TclEmitInstInt4(INST_OVER, 1, envPtr); + if (simple) { + if (exact && !noCase) { + TclEmitOpcode(INST_STR_EQ, envPtr); + } else { + TclEmitInstInt1(INST_STR_MATCH, noCase, envPtr); + } + } else { + TclEmitInstInt1(INST_REGEXP, noCase, envPtr); + } + break; + } default: Tcl_Panic("unknown switch mode: %d", mode); } @@ -4449,7 +4502,6 @@ TclCompileWhileCmd( } } - /* * Set the loop's body, continue and break offsets. */ @@ -5233,7 +5285,6 @@ TclCompileDivOpCmd( } return TCL_OK; } - /* *---------------------------------------------------------------------- @@ -5246,7 +5297,7 @@ TclCompileDivOpCmd( * * Results: * Returns the variable's index in the table of compiled locals if the - * tail is known at compile time, or -1 otherwise. + * tail is known at compile time, or -1 otherwise. * * Side effects: * None. @@ -5258,14 +5309,14 @@ static int IndexTailVarIfKnown( Tcl_Interp *interp, Tcl_Token *varTokenPtr, /* Token representing the variable name */ - CompileEnv *envPtr) /* Holds resulting instructions. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Obj *tailPtr; const char *tailName, *p; int len, n = varTokenPtr->numComponents; Tcl_Token *lastTokenPtr; int full, localIndex; - + /* * Determine if the tail is (a) known at compile time, and (b) not an * array element. Should any of these fail, return an error so that @@ -5285,13 +5336,13 @@ IndexTailVarIfKnown( lastTokenPtr = varTokenPtr; } else { full = 0; - lastTokenPtr = varTokenPtr + n; + lastTokenPtr = varTokenPtr + n; if (!TclWordKnownAtCompileTime(lastTokenPtr, tailPtr)) { Tcl_DecrRefCount(tailPtr); return -1; } } - + tailName = TclGetStringFromObj(tailPtr, &len); if (len) { @@ -5299,7 +5350,7 @@ IndexTailVarIfKnown( /* * Possible array: bail out */ - + Tcl_DecrRefCount(tailPtr); return -1; } @@ -5307,7 +5358,7 @@ IndexTailVarIfKnown( /* * Get the tail: immediately after the last '::' */ - + for(p = tailName + len -1; p > tailName; p--) { if ((*p == ':') && (*(p-1) == ':')) { p++; @@ -5331,7 +5382,6 @@ IndexTailVarIfKnown( Tcl_DecrRefCount(tailPtr); return localIndex; } - /* *---------------------------------------------------------------------- @@ -5359,22 +5409,21 @@ TclCompileUpvarCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr; - int simpleVarName, isScalar, localIndex, numWords, i; + int simpleVarName, isScalar, localIndex, numWords, i; DefineLineInformation; /* TIP #280 */ Tcl_Obj *objPtr = Tcl_NewObj(); - + if (envPtr->procPtr == NULL) { Tcl_DecrRefCount(objPtr); return TCL_ERROR; } - + numWords = parsePtr->numWords; if (numWords < 3) { Tcl_DecrRefCount(objPtr); return TCL_ERROR; } - /* * Push the frame index if it is known at compile time */ @@ -5388,11 +5437,11 @@ TclCompileUpvarCmd( * Attempt to convert to a level reference. Note that TclObjGetFrame * only changes the obj type when a conversion was successful. */ - + TclObjGetFrame(interp, objPtr, &framePtr); newTypePtr = objPtr->typePtr; Tcl_DecrRefCount(objPtr); - + if (newTypePtr != typePtr) { if(numWords%2) { return TCL_ERROR; @@ -5412,7 +5461,7 @@ TclCompileUpvarCmd( Tcl_DecrRefCount(objPtr); return TCL_ERROR; } - + /* * Loop over the (otherVar, thisVar) pairs. If any of the thisVar is not a * local variable, return an error so that the non-compiled command will @@ -5432,7 +5481,7 @@ TclCompileUpvarCmd( } TclEmitInstInt4(INST_UPVAR, localIndex, envPtr); } - + /* * Pop the frame index, and set the result to empty */ @@ -5441,7 +5490,6 @@ TclCompileUpvarCmd( PushLiteral(envPtr, "", 0); return TCL_OK; } - /* *---------------------------------------------------------------------- @@ -5470,13 +5518,13 @@ TclCompileNamespaceCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr; - int simpleVarName, isScalar, localIndex, numWords, i; + int simpleVarName, isScalar, localIndex, numWords, i; DefineLineInformation; /* TIP #280 */ - + if (envPtr->procPtr == NULL) { return TCL_ERROR; } - + /* * Only compile [namespace upvar ...]: needs an odd number of args, >=5 */ @@ -5486,7 +5534,6 @@ TclCompileNamespaceCmd( return TCL_ERROR; } - /* * Check if the second argument is "upvar" */ @@ -5525,7 +5572,7 @@ TclCompileNamespaceCmd( } TclEmitInstInt4(INST_NSUPVAR, localIndex, envPtr); } - + /* * Pop the namespace, and set the result to empty */ @@ -5534,7 +5581,6 @@ TclCompileNamespaceCmd( PushLiteral(envPtr, "", 0); return TCL_OK; } - /* *---------------------------------------------------------------------- @@ -5548,7 +5594,7 @@ TclCompileNamespaceCmd( * evaluation to runtime. * * Side effects: - * Instructions are added to envPtr to execute the "global" command at + * Instructions are added to envPtr to execute the "global" command at * runtime. * *---------------------------------------------------------------------- @@ -5562,9 +5608,9 @@ TclCompileGlobalCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr; - int localIndex, numWords, i; + int localIndex, numWords, i; DefineLineInformation; /* TIP #280 */ - + numWords = parsePtr->numWords; if (numWords < 2) { return TCL_ERROR; @@ -5577,7 +5623,7 @@ TclCompileGlobalCmd( if (envPtr->procPtr == NULL) { return TCL_ERROR; } - + /* * Push the namespace */ @@ -5599,7 +5645,7 @@ TclCompileGlobalCmd( CompileWord(envPtr, varTokenPtr, interp, 1); TclEmitInstInt4(INST_NSUPVAR, localIndex, envPtr); } - + /* * Pop the namespace, and set the result to empty */ @@ -5608,7 +5654,6 @@ TclCompileGlobalCmd( PushLiteral(envPtr, "", 0); return TCL_OK; } - /* *---------------------------------------------------------------------- @@ -5622,7 +5667,7 @@ TclCompileGlobalCmd( * evaluation to runtime. * * Side effects: - * Instructions are added to envPtr to execute the "variable" command at + * Instructions are added to envPtr to execute the "variable" command at * runtime. * *---------------------------------------------------------------------- @@ -5636,9 +5681,9 @@ TclCompileVariableCmd( CompileEnv *envPtr) /* Holds resulting instructions. */ { Tcl_Token *varTokenPtr, *valueTokenPtr; - int localIndex, numWords, i; + int localIndex, numWords, i; DefineLineInformation; /* TIP #280 */ - + numWords = parsePtr->numWords; if (numWords < 2) { return TCL_ERROR; @@ -5647,13 +5692,13 @@ TclCompileVariableCmd( /* * Bail out if not compiling a proc body */ - + if (envPtr->procPtr == NULL) { return TCL_ERROR; } - + /* - * Loop over the (var, value) pairs. + * Loop over the (var, value) pairs. */ valueTokenPtr = parsePtr->tokenPtr; @@ -5666,10 +5711,10 @@ TclCompileVariableCmd( if(localIndex < 0) { return TCL_ERROR; } - + CompileWord(envPtr, varTokenPtr, interp, 1); TclEmitInstInt4(INST_VARIABLE, localIndex, envPtr); - + if (i != numWords) { /* * A value has been given: set the variable, pop the value @@ -5680,7 +5725,7 @@ TclCompileVariableCmd( TclEmitOpcode(INST_POP, envPtr); } } - + /* * Set the result to empty */ @@ -5688,7 +5733,152 @@ TclCompileVariableCmd( PushLiteral(envPtr, "", 0); return TCL_OK; } + +/* + *---------------------------------------------------------------------- + * + * TclCompileInfoCmd -- + * + * Procedure called to compile the "info" command. Only handles the + * "exists" subcommand. + * + * Results: + * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer + * evaluation to runtime. + * + * Side effects: + * Instructions are added to envPtr to execute the "info exists" + * subcommand at runtime. + * + *---------------------------------------------------------------------- + */ + +int +TclCompileInfoCmd( + Tcl_Interp *interp, /* Used for error reporting. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the command + * created by Tcl_ParseCommand. */ + CompileEnv *envPtr) /* Holds resulting instructions. */ +{ + Tcl_Token *tokenPtr; + int isScalar, simpleVarName, localIndex, numWords; + DefineLineInformation; /* TIP #280 */ + + numWords = parsePtr->numWords; + if (numWords != 3) { + return TCL_ERROR; + } + + /* + * Ensure that the next word is "exists"; that's the only case we will + * deal with. + */ + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + if (parsePtr->tokenPtr->type == TCL_TOKEN_SIMPLE_WORD && + tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { + const char *word = tokenPtr[1].start; + int numBytes = tokenPtr[1].size; + Command *cmdPtr; + Tcl_Obj *mapObj, *existsObj, *targetCmdObj; + Tcl_DString ds; + + /* + * There's a sporting chance we'll be able to compile this. But now we + * must check properly. To do that, look up what we expect to be + * called (inefficient, should be in context?) and check that that's + * an ensemble that has [info exists] as its appropriate subcommand. + */ + + Tcl_DStringInit(&ds); + Tcl_DStringAppend(&ds, parsePtr->tokenPtr[1].start, + parsePtr->tokenPtr[1].size); + cmdPtr = (Command *) Tcl_FindCommand(interp, Tcl_DStringValue(&ds), + (Tcl_Namespace *) envPtr->iPtr->globalNsPtr, 0); + Tcl_DStringFree(&ds); + if (cmdPtr == NULL || cmdPtr->compileProc != &TclCompileInfoCmd) { + /* + * Not [info], and can't be bothered to follow rabbit hole of + * renaming. This is an optimization, darnit! + */ + + return TCL_ERROR; + } + + if (Tcl_GetEnsembleMappingDict(interp, (Tcl_Command) cmdPtr, + &mapObj) != TCL_OK || mapObj == NULL) { + /* + * Either not an ensemble or a mapping isn't installed. Crud. Too + * hard to proceed. + */ + + return TCL_ERROR; + } + + TclNewStringObj(existsObj, word, numBytes); + if (Tcl_DictObjGet(NULL, mapObj, existsObj, &targetCmdObj) != TCL_OK + || targetCmdObj == NULL) { + /* + * We've not got a valid subcommand. + */ + + TclDecrRefCount(existsObj); + return TCL_ERROR; + } + TclDecrRefCount(existsObj); + + cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, targetCmdObj); + if (cmdPtr == NULL || cmdPtr->objProc != &TclInfoExistsCmd) { + /* + * Maps to something unexpected. Help! + */ + + return TCL_ERROR; + } + + /* + * OK, it really is [info exists]! + */ + } else { + return TCL_ERROR; + } + + /* + * Decide if we can use a frame slot for the var/array name or if we need + * to emit code to compute and push the name at runtime. We use a frame + * slot (entry in the array of local vars) if we are compiling a procedure + * body and if the name is simple text that does not include namespace + * qualifiers. + */ + + tokenPtr = TokenAfter(tokenPtr); + PushVarName(interp, tokenPtr, envPtr, TCL_CREATE_VAR, &localIndex, + &simpleVarName, &isScalar, mapPtr->loc[eclIndex].line[2]); + + /* + * Emit instruction to check the variable for existence. + */ + if (simpleVarName) { + if (isScalar) { + if (localIndex < 0) { + TclEmitOpcode(INST_EXIST_STK, envPtr); + } else { + TclEmitInstInt4(INST_EXIST_SCALAR, localIndex, envPtr); + } + } else { + if (localIndex < 0) { + TclEmitOpcode(INST_EXIST_ARRAY_STK, envPtr); + } else { + TclEmitInstInt4(INST_EXIST_ARRAY, localIndex, envPtr); + } + } + } else { + TclEmitOpcode(INST_EXIST_STK, envPtr); + } + + return TCL_OK; +} /* * Local Variables: diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 25b9d1e..cffb8a4 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompile.c,v 1.117.2.13 2007/11/12 19:18:16 dgp Exp $ + * RCS: @(#) $Id: tclCompile.c,v 1.117.2.14 2007/11/16 07:20:53 dgp Exp $ */ #include "tclInt.h" @@ -388,6 +388,17 @@ InstructionDesc tclInstructionTable[] = { {"regexp", 2, -1, 1, {OPERAND_INT1}}, /* Regexp: push (regexp stknext stktop) opnd == nocase */ + + {"existScalar", 5, 1, 1, {OPERAND_LVT4}}, + /* Test if scalar variable at index op1 in call frame exists */ + {"existArray", 5, 0, 1, {OPERAND_LVT4}}, + /* Test if array element exists; array at slot op1, element is + * stktop */ + {"existArrayStk", 1, -1, 0, {OPERAND_NONE}}, + /* Test if array element exists; element is stktop, array name is + * stknext */ + {"existStk", 1, 0, 0, {OPERAND_NONE}}, + /* Test if general variable exists; unparsed variable name is stktop*/ {0} }; @@ -1138,9 +1149,9 @@ TclCompileScript( Tcl_DString ds; /* TIP #280 */ ExtCmdLoc *eclPtr = envPtr->extCmdMapPtr; - int *wlines; - int wlineat, cmdLine; - Tcl_Parse *parsePtr = (Tcl_Parse *) TclStackAlloc(interp, sizeof(Tcl_Parse)); + int *wlines, wlineat, cmdLine; + Tcl_Parse *parsePtr = (Tcl_Parse *) + TclStackAlloc(interp, sizeof(Tcl_Parse)); Tcl_DStringInit(&ds); @@ -1167,8 +1178,10 @@ TclCompileScript( cmdLine = envPtr->line; do { if (Tcl_ParseCommand(interp, p, bytesLeft, 0, parsePtr) != TCL_OK) { + /* + * Compile bytecodes to report the parse error at runtime. + */ - /* Compile bytecodes to report the parse error at runtime. */ Tcl_LogCommandInfo(interp, script, parsePtr->commandStart, /* Drop the command terminator (";","]") if appropriate */ (parsePtr->term == @@ -1179,8 +1192,8 @@ TclCompileScript( } gotParse = 1; if (parsePtr->numWords > 0) { - int expand = 0; /* Set if there are dynamic expansions - * to handle */ + int expand = 0; /* Set if there are dynamic expansions to + * handle */ /* * If not the first command, pop the previous command's result @@ -1264,8 +1277,9 @@ TclCompileScript( TclAdvanceLines(&cmdLine, p, parsePtr->commandStart); EnterCmdWordData(eclPtr, parsePtr->commandStart - envPtr->source, - parsePtr->tokenPtr, parsePtr->commandStart, parsePtr->commandSize, - parsePtr->numWords, cmdLine, &wlines); + parsePtr->tokenPtr, parsePtr->commandStart, + parsePtr->commandSize, parsePtr->numWords, cmdLine, + &wlines); wlineat = eclPtr->nuloc - 1; /* @@ -1335,6 +1349,7 @@ TclCompileScript( * produce such a beast (currently 'while 1' only) set * envPtr->atCmdStart to 0 in order to signal this * case. [Bug 1752146] + * * Note that the environment is initialised with * atCmdStart=1 to avoid emitting ISC for the first * command. @@ -1377,6 +1392,20 @@ TclCompileScript( } goto finishCommand; } else { + if (envPtr->atCmdStart && savedCodeNext != 0) { + /* + * Decrease the number of commands being + * started at the current point. Note that + * this depends on the exact layout of the + * INST_START_CMD's operands, so be careful! + */ + + unsigned char *fixPtr = envPtr->codeNext - 4; + + TclStoreInt4AtPtr(TclGetUInt4AtPtr(fixPtr)-1, + fixPtr); + } + /* * Restore numCommands and codeNext to their * correct values, removing any commands compiled @@ -1563,11 +1592,10 @@ TclCompileTokens( */ if (Tcl_DStringLength(&textBuffer) > 0) { - int literal; - - literal = TclRegisterNewLiteral(envPtr, + int literal = TclRegisterNewLiteral(envPtr, Tcl_DStringValue(&textBuffer), Tcl_DStringLength(&textBuffer)); + TclEmitPush(literal, envPtr); numObjsToConcat++; Tcl_DStringFree(&textBuffer); @@ -1909,8 +1937,7 @@ TclInitByteCodeObj( #endif int numLitObjects = envPtr->literalArrayNext; Namespace *namespacePtr; - int i; - int new; + int i, isNew; Interp *iPtr; iPtr = envPtr->iPtr; @@ -2027,7 +2054,7 @@ TclInitByteCodeObj( */ Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->lineBCPtr, (char *) codePtr, - &new), envPtr->extCmdMapPtr); + &isNew), envPtr->extCmdMapPtr); envPtr->extCmdMapPtr = NULL; codePtr->localCachePtr = NULL; @@ -2127,8 +2154,8 @@ TclFindCompiledLocal( procPtr->numCompiledLocals++; } return localVar; - } + /* *---------------------------------------------------------------------- * @@ -3621,7 +3648,7 @@ FormatInstruction( int opnd = 0, i, j, numBytes = 1; int localCt = procPtr ? procPtr->numCompiledLocals : 0; CompiledLocal *localPtr = procPtr ? procPtr->firstLocalPtr : NULL; - char suffixBuffer[64]; /* Additional info to print after main opcode + char suffixBuffer[128]; /* Additional info to print after main opcode * and immediates. */ char *suffixSrc = NULL; Tcl_Obj *suffixObj = NULL; @@ -3662,7 +3689,8 @@ FormatInstruction( if (opCode == INST_PUSH4) { suffixObj = codePtr->objArrayPtr[opnd]; } else if (opCode == INST_START_CMD && opnd != 1) { - sprintf(suffixBuffer, ", %u cmds start here", opnd); + sprintf(suffixBuffer+strlen(suffixBuffer), + ", %u cmds start here", opnd); } Tcl_AppendPrintfToObj(bufferObj, "%u ", (unsigned int) opnd); if (instDesc->opTypes[i] == OPERAND_AUX4) { diff --git a/generic/tclCompile.h b/generic/tclCompile.h index e8d5cbc..8d94530 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompile.h,v 1.70.2.11 2007/11/12 19:18:16 dgp Exp $ + * RCS: @(#) $Id: tclCompile.h,v 1.70.2.12 2007/11/16 07:20:53 dgp Exp $ */ #ifndef _TCLCOMPILATION @@ -640,8 +640,14 @@ typedef struct ByteCode { #define INST_REGEXP 127 +/* For [info exists] compilation */ +#define INST_EXIST_SCALAR 128 +#define INST_EXIST_ARRAY 129 +#define INST_EXIST_ARRAY_STK 130 +#define INST_EXIST_STK 131 + /* The last opcode */ -#define LAST_INST_OPCODE 127 +#define LAST_INST_OPCODE 131 /* * Table describing the Tcl bytecode instructions: their name (for displaying diff --git a/generic/tclExecute.c b/generic/tclExecute.c index bb83839..35d2f41 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclExecute.c,v 1.285.2.23 2007/11/13 13:07:41 dgp Exp $ + * RCS: @(#) $Id: tclExecute.c,v 1.285.2.24 2007/11/16 07:20:54 dgp Exp $ */ #include "tclInt.h" @@ -1721,8 +1721,6 @@ TclExecuteByteCode( iPtr->stats.instructionCount[*pc]++; #endif - TCL_DTRACE_INST_NEXT(); - /* * Check for asynchronous handlers [Bug 746722]; we do the check every * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-1). @@ -1758,6 +1756,8 @@ TclExecuteByteCode( } } + TCL_DTRACE_INST_NEXT(); + /* * These two instructions account for 26% of all instructions (according * to measurements on tclbench by Ben Vitale @@ -3107,6 +3107,121 @@ TclExecuteByteCode( * --------------------------------------------------------- */ + /* + * --------------------------------------------------------- + * Start of INST_EXIST instructions. + */ + { + int opnd, pcAdjustment; + Tcl_Obj *part1Ptr, *part2Ptr; + Var *varPtr, *arrayPtr; + +#define ReadTraced(varPtr) ((varPtr)->flags & VAR_TRACED_READ) + + case INST_EXIST_SCALAR: + opnd = TclGetUInt4AtPtr(pc+1); + varPtr = &(compiledLocals[opnd]); + while (TclIsVarLink(varPtr)) { + varPtr = varPtr->value.linkPtr; + } + TRACE(("%u => ", opnd)); + if (ReadTraced(varPtr)) { + DECACHE_STACK_INFO(); + if (TclObjCallVarTraces(iPtr, NULL, varPtr, NULL, NULL, + TCL_TRACE_READS, 0, opnd) != TCL_OK) { + varPtr = NULL; + } + CACHE_STACK_INFO(); + } + /* + * Tricky! Arrays always exist. + */ + if (varPtr == NULL || varPtr->value.objPtr == NULL) { + objResultPtr = constants[0]; + } else { + objResultPtr = constants[1]; + } + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_F(5, 0, 1); + + case INST_EXIST_ARRAY: + opnd = TclGetUInt4AtPtr(pc+1); + part2Ptr = OBJ_AT_TOS; + arrayPtr = &(compiledLocals[opnd]); + while (TclIsVarLink(arrayPtr)) { + arrayPtr = arrayPtr->value.linkPtr; + } + TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr))); + if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)) { + varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr); + if (!varPtr) { + objResultPtr = constants[0]; + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_F(5, 1, 1); + } else if (!ReadTraced(varPtr)) { + objResultPtr = constants[varPtr->value.objPtr != NULL ? 1:0]; + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_F(5, 1, 1); + } + } + varPtr = TclLookupArrayElement(interp, NULL, part2Ptr, 0, "access", + 0, 0, arrayPtr, opnd); + if (varPtr&&(ReadTraced(varPtr)||(arrayPtr&&ReadTraced(arrayPtr)))) { + DECACHE_STACK_INFO(); + if (TclObjCallVarTraces(iPtr, arrayPtr, varPtr, NULL, + part2Ptr, TCL_TRACE_READS, 0, opnd) != TCL_OK) { + varPtr = NULL; + } + CACHE_STACK_INFO(); + } + if (varPtr == NULL) { + objResultPtr = constants[0]; + } else { + objResultPtr = constants[varPtr->value.objPtr != NULL ? 1 : 0]; + } + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_F(5, 1, 1); + + case INST_EXIST_ARRAY_STK: + cleanup = 2; + pcAdjustment = 1; + part2Ptr = OBJ_AT_TOS; /* element name */ + part1Ptr = OBJ_UNDER_TOS; /* array name */ + TRACE(("\"%.30s(%.30s)\" => ", O2S(part1Ptr), O2S(part2Ptr))); + goto doExistStk; + + case INST_EXIST_STK: + cleanup = 1; + pcAdjustment = 1; + part2Ptr = NULL; + part1Ptr = OBJ_AT_TOS; /* variable name */ + TRACE(("\"%.30s\" => ", O2S(part1Ptr))); + + doExistStk: + varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, 0, "access", + /*createPart1*/0, /*createPart2*/0, &arrayPtr); + if (varPtr&&(ReadTraced(varPtr)||(arrayPtr&&ReadTraced(arrayPtr)))) { + DECACHE_STACK_INFO(); + if (TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr, + part2Ptr, TCL_TRACE_READS, 0, -1) != TCL_OK) { + varPtr = NULL; + } + CACHE_STACK_INFO(); + } + if (!varPtr) { + objResultPtr = constants[0]; + } else { + objResultPtr = constants[varPtr->value.objPtr != NULL ? 1:0]; + } + TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); + NEXT_INST_V(pcAdjustment, cleanup, 1); + } + + /* + * End of INST_EXIST instructions. + * --------------------------------------------------------- + */ + case INST_UPVAR: { int opnd; Var *varPtr, *otherPtr; diff --git a/generic/tclInt.h b/generic/tclInt.h index 639a8c4..9fb2502 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclInt.h,v 1.310.2.14 2007/11/13 13:07:42 dgp Exp $ + * RCS: @(#) $Id: tclInt.h,v 1.310.2.15 2007/11/16 07:20:54 dgp Exp $ */ #ifndef _TCLINT @@ -2471,6 +2471,8 @@ MODULE_SCOPE int TclIncrObj(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_Obj *incrPtr); MODULE_SCOPE Tcl_Obj * TclIncrObjVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *incrPtr, int flags); +MODULE_SCOPE int TclInfoExistsCmd(ClientData dummy, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE Tcl_Obj * TclInfoFrame(Tcl_Interp *interp, CmdFrame *framePtr); MODULE_SCOPE int TclInfoGlobalsCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); @@ -2551,7 +2553,7 @@ MODULE_SCOPE int TclpDeleteFile(CONST char *path); MODULE_SCOPE void TclpFinalizeCondition(Tcl_Condition *condPtr); MODULE_SCOPE void TclpFinalizeMutex(Tcl_Mutex *mutexPtr); MODULE_SCOPE void TclpFinalizePipes(void); -MODULE_SCOPE void TclpFinalizeSockets _ANSI_ARGS_((void)); +MODULE_SCOPE void TclpFinalizeSockets(void); MODULE_SCOPE int TclpThreadCreate(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc proc, ClientData clientData, int stackSize, int flags); @@ -2941,6 +2943,8 @@ MODULE_SCOPE int TclCompileGlobalCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileIfCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileInfoCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileIncrCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileLappendCmd(Tcl_Interp *interp, diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 1863faf..fe14f14 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -23,7 +23,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclNamesp.c,v 1.134.2.10 2007/11/12 19:18:20 dgp Exp $ + * RCS: @(#) $Id: tclNamesp.c,v 1.134.2.11 2007/11/16 07:20:54 dgp Exp $ */ #include "tclInt.h" @@ -5200,10 +5200,10 @@ NamespaceEnsembleCmd( flags = (permitPrefix ? flags|TCL_ENSEMBLE_PREFIX : flags&~TCL_ENSEMBLE_PREFIX); - Tcl_SetEnsembleSubcommandList(NULL, token, subcmdObj); - Tcl_SetEnsembleMappingDict(NULL, token, mapObj); - Tcl_SetEnsembleUnknownHandler(NULL, token, unknownObj); - Tcl_SetEnsembleFlags(NULL, token, flags); + Tcl_SetEnsembleSubcommandList(interp, token, subcmdObj); + Tcl_SetEnsembleMappingDict(interp, token, mapObj); + Tcl_SetEnsembleUnknownHandler(interp, token, unknownObj); + Tcl_SetEnsembleFlags(interp, token, flags); return TCL_OK; } @@ -5318,13 +5318,12 @@ Tcl_SetEnsembleSubcommandList( Tcl_Obj *oldList; if (cmdPtr->objProc != NsEnsembleImplementationCmd) { - if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); - } + Tcl_AppendResult(interp, "command is not an ensemble", NULL); return TCL_ERROR; } if (subcmdList != NULL) { int length; + if (TclListObjLength(interp, subcmdList, &length) != TCL_OK) { return TCL_ERROR; } @@ -5352,6 +5351,18 @@ Tcl_SetEnsembleSubcommandList( ensemblePtr->nsPtr->exportLookupEpoch++; + /* + * Special hack to make compiling of [info exists] work when the + * dictionary is modified. + */ + + if (cmdPtr->compileProc != NULL) { + ((Interp *)interp)->compileEpoch++; + if (subcmdList != NULL) { + cmdPtr->compileProc = NULL; + } + } + return TCL_OK; } @@ -5383,13 +5394,12 @@ Tcl_SetEnsembleMappingDict( Tcl_Obj *oldDict; if (cmdPtr->objProc != NsEnsembleImplementationCmd) { - if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); - } + Tcl_AppendResult(interp, "command is not an ensemble", NULL); return TCL_ERROR; } if (mapDict != NULL) { int size; + if (Tcl_DictObjSize(interp, mapDict, &size) != TCL_OK) { return TCL_ERROR; } @@ -5417,6 +5427,18 @@ Tcl_SetEnsembleMappingDict( ensemblePtr->nsPtr->exportLookupEpoch++; + /* + * Special hack to make compiling of [info exists] work when the + * dictionary is modified. + */ + + if (cmdPtr->compileProc != NULL) { + ((Interp *)interp)->compileEpoch++; + if (mapDict == NULL) { + cmdPtr->compileProc = NULL; + } + } + return TCL_OK; } @@ -5448,9 +5470,7 @@ Tcl_SetEnsembleUnknownHandler( Tcl_Obj *oldList; if (cmdPtr->objProc != NsEnsembleImplementationCmd) { - if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); - } + Tcl_AppendResult(interp, "command is not an ensemble", NULL); return TCL_ERROR; } if (unknownList != NULL) { @@ -5513,9 +5533,7 @@ Tcl_SetEnsembleFlags( EnsembleConfig *ensemblePtr; if (cmdPtr->objProc != NsEnsembleImplementationCmd) { - if (interp != NULL) { - Tcl_AppendResult(interp, "command is not an ensemble", NULL); - } + Tcl_AppendResult(interp, "command is not an ensemble", NULL); return TCL_ERROR; } diff --git a/generic/tclTrace.c b/generic/tclTrace.c index 1dffdf2..8fd1377 100644 --- a/generic/tclTrace.c +++ b/generic/tclTrace.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclTrace.c,v 1.37.2.6 2007/09/17 15:03:45 dgp Exp $ + * RCS: @(#) $Id: tclTrace.c,v 1.37.2.7 2007/11/16 07:20:54 dgp Exp $ */ #include "tclInt.h" @@ -96,7 +96,7 @@ typedef struct { */ typedef int (Tcl_TraceTypeObjCmd)(Tcl_Interp *interp, int optionIndex, - int objc, Tcl_Obj *CONST objv[]); + int objc, Tcl_Obj *const objv[]); static Tcl_TraceTypeObjCmd TraceVariableObjCmd; static Tcl_TraceTypeObjCmd TraceCommandObjCmd; @@ -109,7 +109,7 @@ static Tcl_TraceTypeObjCmd TraceExecutionObjCmd; * add to the list of supported trace types. */ -static CONST char *traceTypeOptions[] = { +static const char *traceTypeOptions[] = { "execution", "command", "variable", NULL }; static Tcl_TraceTypeObjCmd *traceSubCmds[] = { @@ -123,22 +123,22 @@ static Tcl_TraceTypeObjCmd *traceSubCmds[] = { */ static int CallTraceFunction(Tcl_Interp *interp, Trace *tracePtr, - Command *cmdPtr, CONST char *command, int numChars, - int objc, Tcl_Obj *CONST objv[]); + Command *cmdPtr, const char *command, int numChars, + int objc, Tcl_Obj *const objv[]); static char * TraceVarProc(ClientData clientData, Tcl_Interp *interp, - CONST char *name1, CONST char *name2, int flags); + const char *name1, const char *name2, int flags); static void TraceCommandProc(ClientData clientData, - Tcl_Interp *interp, CONST char *oldName, - CONST char *newName, int flags); + Tcl_Interp *interp, const char *oldName, + const char *newName, int flags); static Tcl_CmdObjTraceProc TraceExecutionProc; static int StringTraceProc(ClientData clientData, - Tcl_Interp* interp, int level, - CONST char* command, Tcl_Command commandInfo, - int objc, Tcl_Obj *CONST objv[]); + Tcl_Interp *interp, int level, + const char *command, Tcl_Command commandInfo, + int objc, Tcl_Obj *const objv[]); static void StringTraceDeleteProc(ClientData clientData); static void DisposeTraceResult(int flags, char *result); -static int TraceVarEx(Tcl_Interp *interp, CONST char *part1, - CONST char *part2, register VarTrace *tracePtr); +static int TraceVarEx(Tcl_Interp *interp, const char *part1, + const char *part2, register VarTrace *tracePtr); /* * The following structure holds the client data for string-based @@ -147,7 +147,7 @@ static int TraceVarEx(Tcl_Interp *interp, CONST char *part1, typedef struct StringTraceData { ClientData clientData; /* Client data from Tcl_CreateTrace */ - Tcl_CmdTraceProc* proc; /* Trace function from Tcl_CreateTrace */ + Tcl_CmdTraceProc *proc; /* Trace function from Tcl_CreateTrace */ } StringTraceData; /* @@ -175,12 +175,12 @@ Tcl_TraceObjCmd( ClientData dummy, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { int optionIndex; char *name, *flagOps, *p; /* Main sub commands to 'trace' */ - static CONST char *traceOptions[] = { + static const char *traceOptions[] = { "add", "info", "remove", #ifndef TCL_REMOVE_OBSOLETE_TRACES "variable", "vdelete", "vinfo", @@ -384,7 +384,7 @@ TraceExecutionObjCmd( Tcl_Interp *interp, /* Current interpreter. */ int optionIndex, /* Add, info or remove */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { int commandLength, index; char *name, *command; @@ -392,7 +392,7 @@ TraceExecutionObjCmd( enum traceOptions { TRACE_ADD, TRACE_INFO, TRACE_REMOVE }; - static CONST char *opStrings[] = { + static const char *opStrings[] = { "enter", "leave", "enterstep", "leavestep", NULL }; enum operations { @@ -523,7 +523,7 @@ TraceExecutionObjCmd( Tcl_DeleteTrace(interp, tcmdPtr->stepTrace); tcmdPtr->stepTrace = NULL; if (tcmdPtr->startCmd != NULL) { - ckfree((char *)tcmdPtr->startCmd); + ckfree((char *) tcmdPtr->startCmd); } } if (tcmdPtr->flags & TCL_TRACE_EXEC_IN_PROGRESS) { @@ -534,7 +534,7 @@ TraceExecutionObjCmd( tcmdPtr->flags = 0; } if ((--tcmdPtr->refCount) <= 0) { - ckfree((char*)tcmdPtr); + ckfree((char *) tcmdPtr); } break; } @@ -638,13 +638,13 @@ TraceCommandObjCmd( Tcl_Interp *interp, /* Current interpreter. */ int optionIndex, /* Add, info or remove */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { int commandLength, index; char *name, *command; size_t length; enum traceOptions { TRACE_ADD, TRACE_INFO, TRACE_REMOVE }; - static CONST char *opStrings[] = { "delete", "rename", NULL }; + static const char *opStrings[] = { "delete", "rename", NULL }; enum operations { TRACE_CMD_DELETE, TRACE_CMD_RENAME }; switch ((enum traceOptions) optionIndex) { @@ -836,13 +836,13 @@ TraceVariableObjCmd( Tcl_Interp *interp, /* Current interpreter. */ int optionIndex, /* Add, info or remove */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. */ + Tcl_Obj *const objv[]) /* Argument objects. */ { int commandLength, index; char *name, *command; size_t length; enum traceOptions { TRACE_ADD, TRACE_INFO, TRACE_REMOVE }; - static CONST char *opStrings[] = { + static const char *opStrings[] = { "array", "read", "unset", "write", NULL }; enum operations { @@ -1028,7 +1028,7 @@ TraceVariableObjCmd( ClientData Tcl_CommandTraceInfo( Tcl_Interp *interp, /* Interpreter containing command. */ - CONST char *cmdName, /* Name of command. */ + const char *cmdName, /* Name of command. */ int flags, /* OR-ed combo or TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY (can be 0). */ Tcl_CommandTraceProc *proc, /* Function assocated with trace. */ @@ -1094,7 +1094,7 @@ int Tcl_TraceCommand( Tcl_Interp *interp, /* Interpreter in which command is to be * traced. */ - CONST char *cmdName, /* Name of command. */ + const char *cmdName, /* Name of command. */ int flags, /* OR-ed collection of bits, including any of * TCL_TRACE_RENAME, TCL_TRACE_DELETE, and any * of the TRACE_*_EXEC flags */ @@ -1149,7 +1149,7 @@ Tcl_TraceCommand( void Tcl_UntraceCommand( Tcl_Interp *interp, /* Interpreter containing command. */ - CONST char *cmdName, /* Name of command. */ + const char *cmdName, /* Name of command. */ int flags, /* OR-ed collection of bits, including any of * TCL_TRACE_RENAME, TCL_TRACE_DELETE, and any * of the TRACE_*_EXEC flags */ @@ -1163,7 +1163,7 @@ Tcl_UntraceCommand( ActiveCommandTrace *activePtr; int hasExecTraces = 0; - cmdPtr = (Command*)Tcl_FindCommand(interp, cmdName, NULL, + cmdPtr = (Command *) Tcl_FindCommand(interp, cmdName, NULL, TCL_LEAVE_ERR_MSG); if (cmdPtr == NULL) { return; @@ -1211,7 +1211,7 @@ Tcl_UntraceCommand( tracePtr->flags = 0; if ((--tracePtr->refCount) <= 0) { - ckfree((char*)tracePtr); + ckfree((char *) tracePtr); } if (hasExecTraces) { @@ -1254,8 +1254,8 @@ static void TraceCommandProc( ClientData clientData, /* Information about the command trace. */ Tcl_Interp *interp, /* Interpreter containing command. */ - CONST char *oldName, /* Name of command being changed. */ - CONST char *newName, /* New name of command. Empty string or NULL + const char *oldName, /* Name of command being changed. */ + const char *newName, /* New name of command. Empty string or NULL * means command is being deleted (renamed to * ""). */ int flags) /* OR-ed bits giving operation and other @@ -1318,7 +1318,7 @@ TraceCommandProc( Tcl_DeleteTrace(interp, tcmdPtr->stepTrace); tcmdPtr->stepTrace = NULL; if (tcmdPtr->startCmd != NULL) { - ckfree((char *)tcmdPtr->startCmd); + ckfree((char *) tcmdPtr->startCmd); } } if (tcmdPtr->flags & TCL_TRACE_EXEC_IN_PROGRESS) { @@ -1361,7 +1361,7 @@ TraceCommandProc( tcmdPtr->refCount--; } if ((--tcmdPtr->refCount) <= 0) { - ckfree((char*)tcmdPtr); + ckfree((char *) tcmdPtr); } } @@ -1393,7 +1393,7 @@ TraceCommandProc( int TclCheckExecutionTraces( Tcl_Interp *interp, /* The current interpreter. */ - CONST char *command, /* Pointer to beginning of the current command + const char *command, /* Pointer to beginning of the current command * string. */ int numChars, /* The number of characters in 'command' which * are part of the command string. */ @@ -1401,14 +1401,13 @@ TclCheckExecutionTraces( int code, /* The current result code. */ int traceFlags, /* Current tracing situation. */ int objc, /* Number of arguments for the command. */ - Tcl_Obj *CONST objv[]) /* Pointers to Tcl_Obj of each argument. */ + Tcl_Obj *const objv[]) /* Pointers to Tcl_Obj of each argument. */ { Interp *iPtr = (Interp *) interp; CommandTrace *tracePtr, *lastTracePtr; ActiveCommandTrace active; int curLevel; int traceCode = TCL_OK; - TraceCommandInfo* tcmdPtr; Tcl_InterpState state = NULL; if (cmdPtr->tracePtr == NULL) { @@ -1442,7 +1441,9 @@ TclCheckExecutionTraces( active.nextTracePtr = tracePtr->nextPtr; } if (tracePtr->traceProc == TraceCommandProc) { - tcmdPtr = (TraceCommandInfo*)tracePtr->clientData; + TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) + tracePtr->clientData; + if (tcmdPtr->flags != 0) { tcmdPtr->curFlags = traceFlags | TCL_TRACE_EXEC_DIRECT; tcmdPtr->curCode = code; @@ -1450,10 +1451,10 @@ TclCheckExecutionTraces( if (state == NULL) { state = Tcl_SaveInterpState(interp, code); } - traceCode = TraceExecutionProc((ClientData)tcmdPtr, interp, - curLevel, command, (Tcl_Command)cmdPtr, objc, objv); + traceCode = TraceExecutionProc((ClientData) tcmdPtr, interp, + curLevel, command, (Tcl_Command) cmdPtr, objc, objv); if ((--tcmdPtr->refCount) <= 0) { - ckfree((char*)tcmdPtr); + ckfree((char *) tcmdPtr); } } } @@ -1495,7 +1496,7 @@ TclCheckExecutionTraces( int TclCheckInterpTraces( Tcl_Interp *interp, /* The current interpreter. */ - CONST char *command, /* Pointer to beginning of the current command + const char *command, /* Pointer to beginning of the current command * string. */ int numChars, /* The number of characters in 'command' which * are part of the command string. */ @@ -1503,7 +1504,7 @@ TclCheckInterpTraces( int code, /* The current result code. */ int traceFlags, /* Current tracing situation. */ int objc, /* Number of arguments for the command. */ - Tcl_Obj *CONST objv[]) /* Pointers to Tcl_Obj of each argument. */ + Tcl_Obj *const objv[]) /* Pointers to Tcl_Obj of each argument. */ { Interp *iPtr = (Interp *) interp; Trace *tracePtr, *lastTracePtr; @@ -1578,10 +1579,11 @@ TclCheckInterpTraces( if (tracePtr->flags & traceFlags) { if (tracePtr->proc == TraceExecutionProc) { - TraceCommandInfo* tcmdPtr = - (TraceCommandInfo *) tracePtr->clientData; + TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) + tracePtr->clientData; + tcmdPtr->curFlags = traceFlags; - tcmdPtr->curCode = code; + tcmdPtr->curCode = code; } traceCode = (tracePtr->proc)(tracePtr->clientData, interp, curLevel, command, (Tcl_Command) cmdPtr, @@ -1642,12 +1644,12 @@ CallTraceFunction( Tcl_Interp *interp, /* The current interpreter. */ register Trace *tracePtr, /* Describes the trace function to call. */ Command *cmdPtr, /* Points to command's Command struct. */ - CONST char *command, /* Points to the first character of the + const char *command, /* Points to the first character of the * command's source before substitutions. */ int numChars, /* The number of characters in the command's * source. */ register int objc, /* Number of arguments for the command. */ - Tcl_Obj *CONST objv[]) /* Pointers to Tcl_Obj of each argument. */ + Tcl_Obj *const objv[]) /* Pointers to Tcl_Obj of each argument. */ { Interp *iPtr = (Interp *) interp; char *commandCopy; @@ -1658,14 +1660,14 @@ CallTraceFunction( */ commandCopy = TclStackAlloc(interp, (unsigned) (numChars + 1)); - memcpy((void *) commandCopy, (void *) command, (size_t) numChars); + memcpy(commandCopy, command, (size_t) numChars); commandCopy[numChars] = '\0'; /* * Call the trace function then free allocated storage. */ - traceCode = (tracePtr->proc)(tracePtr->clientData, (Tcl_Interp*) iPtr, + traceCode = (tracePtr->proc)(tracePtr->clientData, (Tcl_Interp *) iPtr, iPtr->numLevels, commandCopy, (Tcl_Command) cmdPtr, objc, objv); TclStackFree(interp, commandCopy); @@ -1693,9 +1695,10 @@ static void CommandObjTraceDeleted( ClientData clientData) { - TraceCommandInfo* tcmdPtr = (TraceCommandInfo*)clientData; + TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) clientData; + if ((--tcmdPtr->refCount) <= 0) { - ckfree((char*)tcmdPtr); + ckfree((char *) tcmdPtr); } } @@ -1729,17 +1732,17 @@ TraceExecutionProc( ClientData clientData, Tcl_Interp *interp, int level, - CONST char *command, + const char *command, Tcl_Command cmdInfo, int objc, - struct Tcl_Obj *CONST objv[]) + struct Tcl_Obj *const objv[]) { int call = 0; Interp *iPtr = (Interp *) interp; - TraceCommandInfo* tcmdPtr = (TraceCommandInfo*)clientData; + TraceCommandInfo *tcmdPtr = (TraceCommandInfo *) clientData; int flags = tcmdPtr->curFlags; - int code = tcmdPtr->curCode; - int traceCode = TCL_OK; + int code = tcmdPtr->curCode; + int traceCode = TCL_OK; if (tcmdPtr->flags & TCL_TRACE_EXEC_IN_PROGRESS) { /* @@ -1778,7 +1781,7 @@ TraceExecutionProc( Tcl_DeleteTrace(interp, tcmdPtr->stepTrace); tcmdPtr->stepTrace = NULL; if (tcmdPtr->startCmd != NULL) { - ckfree((char *)tcmdPtr->startCmd); + ckfree((char *) tcmdPtr->startCmd); } } @@ -1816,8 +1819,8 @@ TraceExecutionProc( Tcl_DStringAppendElement(&cmd, "enterstep"); } } else if (flags & TCL_TRACE_LEAVE_EXEC) { - Tcl_Obj* resultCode; - char* resultCodeStr; + Tcl_Obj *resultCode; + char *resultCodeStr; /* * Append result code. @@ -1866,10 +1869,11 @@ TraceExecutionProc( traceCode = Tcl_Eval(interp, Tcl_DStringValue(&cmd)); tcmdPtr->flags &= ~TCL_TRACE_EXEC_IN_PROGRESS; - /* - * Restore the interp tracing flag to prevent cmd traces - * from affecting interp traces. + /* + * Restore the interp tracing flag to prevent cmd traces from + * affecting interp traces. */ + iPtr->flags = saveInterpFlags; if (tcmdPtr->flags == 0) { flags |= TCL_TRACE_DESTROYED; @@ -1888,10 +1892,11 @@ TraceExecutionProc( if ((flags & TCL_TRACE_ENTER_EXEC) && (tcmdPtr->stepTrace == NULL) && (tcmdPtr->flags & (TCL_TRACE_ENTER_DURING_EXEC | TCL_TRACE_LEAVE_DURING_EXEC))) { + register unsigned len = strlen(command) + 1; + tcmdPtr->startLevel = level; - tcmdPtr->startCmd = - (char *) ckalloc((unsigned) (strlen(command) + 1)); - strcpy(tcmdPtr->startCmd, command); + tcmdPtr->startCmd = ckalloc(len); + memcpy(tcmdPtr->startCmd, command, len); tcmdPtr->refCount++; tcmdPtr->stepTrace = Tcl_CreateObjTrace(interp, 0, (tcmdPtr->flags & TCL_TRACE_ANY_EXEC) >> 2, @@ -1904,13 +1909,13 @@ TraceExecutionProc( Tcl_DeleteTrace(interp, tcmdPtr->stepTrace); tcmdPtr->stepTrace = NULL; if (tcmdPtr->startCmd != NULL) { - ckfree((char *)tcmdPtr->startCmd); + ckfree(tcmdPtr->startCmd); } } } if (call) { if ((--tcmdPtr->refCount) <= 0) { - ckfree((char*)tcmdPtr); + ckfree((char *) tcmdPtr); } } return traceCode; @@ -1939,8 +1944,8 @@ static char * TraceVarProc( ClientData clientData, /* Information about the variable trace. */ Tcl_Interp *interp, /* Interpreter containing variable. */ - CONST char *name1, /* Name of variable or array. */ - CONST char *name2, /* Name of element within array; NULL means + const char *name1, /* Name of variable or array. */ + const char *name2, /* Name of element within array; NULL means * scalar variable is being referenced. */ int flags) /* OR-ed bits giving operation and other * information. */ @@ -2046,12 +2051,12 @@ TraceVarProc( * form: * * void proc(ClientData clientData, - * Tcl_Interp* interp, + * Tcl_Interp * interp, * int level, - * CONST char* command, + * const char * command, * Tcl_Command commandInfo, * int objc, - * Tcl_Obj *CONST objv[]); + * Tcl_Obj *const objv[]); * * The 'clientData' and 'interp' arguments to 'proc' will be the same as * the arguments to Tcl_CreateObjTrace. The 'level' argument gives the @@ -2090,12 +2095,12 @@ TraceVarProc( Tcl_Trace Tcl_CreateObjTrace( - Tcl_Interp* interp, /* Tcl interpreter */ + Tcl_Interp *interp, /* Tcl interpreter */ int level, /* Maximum nesting level */ int flags, /* Flags, see above */ - Tcl_CmdObjTraceProc* proc, /* Trace callback */ + Tcl_CmdObjTraceProc *proc, /* Trace callback */ ClientData clientData, /* Client data for the callback */ - Tcl_CmdObjTraceDeleteProc* delProc) + Tcl_CmdObjTraceDeleteProc *delProc) /* Function to call when trace is deleted */ { register Trace *tracePtr; @@ -2186,8 +2191,9 @@ Tcl_CreateTrace( * command. */ ClientData clientData) /* Arbitrary value word to pass to proc. */ { - StringTraceData* data; - data = (StringTraceData *) ckalloc(sizeof(*data)); + StringTraceData *data = (StringTraceData *) + ckalloc(sizeof(StringTraceData)); + data->clientData = clientData; data->proc = proc; return Tcl_CreateObjTrace(interp, level, 0, StringTraceProc, @@ -2213,16 +2219,16 @@ Tcl_CreateTrace( static int StringTraceProc( ClientData clientData, - Tcl_Interp* interp, + Tcl_Interp *interp, int level, - CONST char* command, + const char *command, Tcl_Command commandInfo, int objc, - Tcl_Obj *CONST *objv) + Tcl_Obj *const *objv) { - StringTraceData* data = (StringTraceData*) clientData; - Command* cmdPtr = (Command*) commandInfo; - CONST char** argv; /* Args to pass to string trace proc */ + StringTraceData *data = (StringTraceData *) clientData; + Command *cmdPtr = (Command *) commandInfo; + const char **argv; /* Args to pass to string trace proc */ int i; /* @@ -2230,8 +2236,8 @@ StringTraceProc( * which uses strings for everything. */ - argv = (CONST char **) TclStackAlloc(interp, - (unsigned) ((objc + 1) * sizeof(CONST char *))); + argv = (const char **) TclStackAlloc(interp, + (unsigned) ((objc + 1) * sizeof(const char *))); for (i = 0; i < objc; i++) { argv[i] = Tcl_GetString(objv[i]); } @@ -2245,7 +2251,7 @@ StringTraceProc( (data->proc)(data->clientData, interp, level, (char *) command, cmdPtr->proc, cmdPtr->clientData, objc, argv); - TclStackFree(interp, (void *)argv); + TclStackFree(interp, (void *) argv); return TCL_OK; } @@ -2360,7 +2366,7 @@ Tcl_DeleteTrace( * Delete the trace object. */ - Tcl_EventuallyFree((char*)tracePtr, TCL_DYNAMIC); + Tcl_EventuallyFree((char *) tracePtr, TCL_DYNAMIC); } /* @@ -2384,7 +2390,7 @@ Tcl_DeleteTrace( Var * TclVarTraceExists( Tcl_Interp *interp, /* The interpreter */ - CONST char *varName) /* The variable name */ + const char *varName) /* The variable name */ { Var *varPtr; Var *arrayPtr; @@ -2462,7 +2468,9 @@ TclObjCallVarTraces( int leaveErrMsg, /* If true, and one of the traces indicates an * error, then leave an error message and * stack trace information in *iPTr. */ - int index) + int index) /* Index into the local variable table of the + * variable, or -1. Only used when part1Ptr is + * NULL. */ { char *part1, *part2; @@ -2471,8 +2479,9 @@ TclObjCallVarTraces( } part1 = TclGetString(part1Ptr); part2 = part2Ptr? TclGetString(part2Ptr) : NULL; - - return TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, flags, leaveErrMsg); + + return TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, flags, + leaveErrMsg); } int @@ -2482,8 +2491,8 @@ TclCallVarTraces( * variable, or NULL if the variable isn't an * element of an array. */ Var *varPtr, /* Variable whose traces are to be invoked. */ - CONST char *part1, - CONST char *part2, /* Variable's two-part name. */ + const char *part1, + const char *part2, /* Variable's two-part name. */ int flags, /* Flags passed to trace functions: indicates * what's happening to variable, plus maybe * TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY */ @@ -2494,7 +2503,7 @@ TclCallVarTraces( register VarTrace *tracePtr; ActiveVarTrace active; char *result; - CONST char *openParen, *p; + const char *openParen, *p; Tcl_DString nameCopy; int copiedName; int code = TCL_OK; @@ -2502,7 +2511,7 @@ TclCallVarTraces( Tcl_InterpState state = NULL; Tcl_HashEntry *hPtr; int traceflags = flags & VAR_ALL_TRACES; - + /* * If there are already similar trace functions active for the variable, * don't call them again. @@ -2568,9 +2577,9 @@ TclCallVarTraces( active.nextPtr = iPtr->activeVarTracePtr; iPtr->activeVarTracePtr = &active; Tcl_Preserve((ClientData) iPtr); - if (arrayPtr && !TclIsVarTraceActive(arrayPtr) && (arrayPtr->flags & traceflags)) { - hPtr = Tcl_FindHashEntry(&iPtr->varTraces, - (char *) arrayPtr); + if (arrayPtr && !TclIsVarTraceActive(arrayPtr) + && (arrayPtr->flags & traceflags)) { + hPtr = Tcl_FindHashEntry(&iPtr->varTraces, (char *) arrayPtr); active.varPtr = arrayPtr; for (tracePtr = (VarTrace *) Tcl_GetHashValue(hPtr); tracePtr != NULL; tracePtr = active.nextTracePtr) { @@ -2615,8 +2624,7 @@ TclCallVarTraces( } active.varPtr = varPtr; if (varPtr->flags & traceflags) { - hPtr = Tcl_FindHashEntry(&iPtr->varTraces, - (char *) varPtr); + hPtr = Tcl_FindHashEntry(&iPtr->varTraces, (char *) varPtr); for (tracePtr = (VarTrace *) Tcl_GetHashValue(hPtr); tracePtr != NULL; tracePtr = active.nextTracePtr) { active.nextTracePtr = tracePtr->nextPtr; @@ -2637,7 +2645,7 @@ TclCallVarTraces( /* * Ignore errors in unset traces. */ - + DisposeTraceResult(tracePtr->flags, result); } else { disposeFlags = tracePtr->flags; @@ -2659,7 +2667,7 @@ TclCallVarTraces( done: if (code == TCL_ERROR) { if (leaveErrMsg) { - CONST char *type = ""; + const char *type = ""; Tcl_Obj *options = Tcl_GetReturnOptions((Tcl_Interp *)iPtr, code); Tcl_Obj *errorInfoKey, *errorInfo; @@ -2787,7 +2795,7 @@ DisposeTraceResult( void Tcl_UntraceVar( Tcl_Interp *interp, /* Interpreter containing variable. */ - CONST char *varName, /* Name of variable; may end with "(index)" to + const char *varName, /* Name of variable; may end with "(index)" to * signify an array reference. */ int flags, /* OR-ed collection of bits describing current * trace, including any of TCL_TRACE_READS, @@ -2819,8 +2827,8 @@ Tcl_UntraceVar( void Tcl_UntraceVar2( Tcl_Interp *interp, /* Interpreter containing variable. */ - CONST char *part1, /* Name of variable or array. */ - CONST char *part2, /* Name of element within array; NULL means + const char *part1, /* Name of variable or array. */ + const char *part2, /* Name of element within array; NULL means * trace applies to scalar variable or array * as-a-whole. */ int flags, /* OR-ed collection of bits describing current @@ -2904,8 +2912,8 @@ Tcl_UntraceVar2( tracePtr = tracePtr->nextPtr) { allFlags |= tracePtr->flags; } - - updateFlags: + + updateFlags: varPtr->flags &= ~VAR_ALL_TRACES; if (allFlags & VAR_ALL_TRACES) { varPtr->flags |= (allFlags & VAR_ALL_TRACES); @@ -2914,6 +2922,7 @@ Tcl_UntraceVar2( * If this is the last trace on the variable, and the variable is * unset and unused, then free up the variable. */ + TclCleanupVar(varPtr, NULL); } } @@ -2944,7 +2953,7 @@ Tcl_UntraceVar2( ClientData Tcl_VarTraceInfo( Tcl_Interp *interp, /* Interpreter containing variable. */ - CONST char *varName, /* Name of variable; may end with "(index)" to + const char *varName, /* Name of variable; may end with "(index)" to * signify an array reference. */ int flags, /* OR-ed combo or TCL_GLOBAL_ONLY, * TCL_NAMESPACE_ONLY (can be 0). */ @@ -2978,8 +2987,8 @@ Tcl_VarTraceInfo( ClientData Tcl_VarTraceInfo2( Tcl_Interp *interp, /* Interpreter containing variable. */ - CONST char *part1, /* Name of variable or array. */ - CONST char *part2, /* Name of element within array; NULL means + const char *part1, /* Name of variable or array. */ + const char *part2, /* Name of element within array; NULL means * trace applies to scalar variable or array * as-a-whole. */ int flags, /* OR-ed combination of TCL_GLOBAL_ONLY, @@ -3055,7 +3064,7 @@ int Tcl_TraceVar( Tcl_Interp *interp, /* Interpreter in which variable is to be * traced. */ - CONST char *varName, /* Name of variable; may end with "(index)" to + const char *varName, /* Name of variable; may end with "(index)" to * signify an array reference. */ int flags, /* OR-ed collection of bits, including any of * TCL_TRACE_READS, TCL_TRACE_WRITES, @@ -3093,8 +3102,8 @@ int Tcl_TraceVar2( Tcl_Interp *interp, /* Interpreter in which variable is to be * traced. */ - CONST char *part1, /* Name of scalar variable or array. */ - CONST char *part2, /* Name of element within array; NULL means + const char *part1, /* Name of scalar variable or array. */ + const char *part2, /* Name of element within array; NULL means * trace applies to scalar variable or array * as-a-whole. */ int flags, /* OR-ed collection of bits, including any of @@ -3146,8 +3155,8 @@ static int TraceVarEx( Tcl_Interp *interp, /* Interpreter in which variable is to be * traced. */ - CONST char *part1, /* Name of scalar variable or array. */ - CONST char *part2, /* Name of element within array; NULL means + const char *part1, /* Name of scalar variable or array. */ + const char *part2, /* Name of element within array; NULL means * trace applies to scalar variable or array * as-a-whole. */ register VarTrace *tracePtr)/* Structure containing flags, traceProc and @@ -3159,9 +3168,8 @@ TraceVarEx( { Interp *iPtr = (Interp *) interp; Var *varPtr, *arrayPtr; - int flagMask; + int flagMask, isNew; Tcl_HashEntry *hPtr; - int new; /* * We strip 'flags' down to just the parts which are relevant to @@ -3199,15 +3207,18 @@ TraceVarEx( #endif tracePtr->flags = tracePtr->flags & flagMask; - hPtr = Tcl_CreateHashEntry(&iPtr->varTraces, - (char *) varPtr, &new); - if (new) { + hPtr = Tcl_CreateHashEntry(&iPtr->varTraces, (char *) varPtr, &isNew); + if (isNew) { tracePtr->nextPtr = NULL; } else { tracePtr->nextPtr = (VarTrace *) Tcl_GetHashValue(hPtr); } Tcl_SetHashValue(hPtr, (char *) tracePtr); + /* + * Mark the variable as traced so we know to call them. + */ + varPtr->flags |= (tracePtr->flags & VAR_ALL_TRACES); return TCL_OK; diff --git a/generic/tclVar.c b/generic/tclVar.c index 63b393d..565d04a 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -16,7 +16,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclVar.c,v 1.135.2.10 2007/11/12 19:18:21 dgp Exp $ + * RCS: @(#) $Id: tclVar.c,v 1.135.2.11 2007/11/16 07:20:54 dgp Exp $ */ #include "tclInt.h" @@ -148,8 +148,9 @@ static void AppendLocals(Tcl_Interp *interp, Tcl_Obj *listPtr, static void DeleteSearches(Interp *iPtr, Var *arrayVarPtr); static void DeleteArray(Interp *iPtr, Tcl_Obj *arrayNamePtr, Var *varPtr, int flags); -static Tcl_Var ObjFindNamespaceVar(Tcl_Interp *interp, Tcl_Obj *namePtr, - Tcl_Namespace *contextNsPtr, int flags); +static Tcl_Var ObjFindNamespaceVar(Tcl_Interp *interp, + Tcl_Obj *namePtr, Tcl_Namespace *contextNsPtr, + int flags); static int ObjMakeUpvar(Tcl_Interp *interp, CallFrame *framePtr, Tcl_Obj *otherP1Ptr, const char *otherP2, const int otherFlags, @@ -245,11 +246,11 @@ Tcl_ObjType tclArraySearchType = { "array search", NULL, NULL, NULL, SetArraySearchObj }; - + Var * TclVarHashCreateVar( TclVarHashTable *tablePtr, - const char *key, + const char *key, int *newPtr) { Tcl_Obj *keyPtr; @@ -400,7 +401,7 @@ TclLookupVar( /* *---------------------------------------------------------------------- * - * TclObjLookupVar -- + * TclObjLookupVar, TclObjLookupVarEx -- * * This function is used by virtually all of the variable code to locate * a variable given its name(s). The parsing into array/element @@ -483,14 +484,27 @@ TclObjLookupVar( Var * TclObjLookupVarEx( - Tcl_Interp *interp, - Tcl_Obj *part1Ptr, - Tcl_Obj *part2Ptr, - int flags, - const char *msg, - const int createPart1, - const int createPart2, - Var **arrayPtrPtr) + Tcl_Interp *interp, /* Interpreter to use for lookup. */ + Tcl_Obj *part1Ptr, /* If part2Ptr isn't NULL, this is the name of + * an array. Otherwise, this is a full + * variable name that could include a + * parenthesized array element. */ + Tcl_Obj *part2Ptr, /* Name of element within array, or NULL. */ + int flags, /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, + * and TCL_LEAVE_ERR_MSG bits matter. */ + const char *msg, /* Verb to use in error messages, e.g. "read" + * or "set". Only needed if TCL_LEAVE_ERR_MSG + * is set in flags. */ + const int createPart1, /* If 1, create hash table entry for part 1 of + * name, if it doesn't already exist. If 0, + * return error if it doesn't exist. */ + const int createPart2, /* If 1, create hash table entry for part 2 of + * name, if it doesn't already exist. If 0, + * return error if it doesn't exist. */ + Var **arrayPtrPtr) /* If the name refers to an element of an + * array, *arrayPtrPtr gets filled in with + * address of array variable. Otherwise this + * is set to NULL. */ { Interp *iPtr = (Interp *) interp; register Var *varPtr; /* Points to the variable's in-frame Var @@ -522,8 +536,7 @@ TclObjLookupVarEx( if (typePtr == &localVarNameType) { int localIndex; - localVarNameTypeHandling: - + localVarNameTypeHandling: localIndex = (int) part1Ptr->internalRep.ptrAndLongRep.value; if (HasLocalVars(varFramePtr) && !(flags & (TCL_GLOBAL_ONLY | TCL_NAMESPACE_ONLY)) @@ -532,7 +545,8 @@ TclObjLookupVarEx( * Use the cached index if the names coincide. */ - Tcl_Obj *namePtr = (Tcl_Obj *) part1Ptr->internalRep.ptrAndLongRep.ptr; + Tcl_Obj *namePtr = (Tcl_Obj *) + part1Ptr->internalRep.ptrAndLongRep.ptr; Tcl_Obj *checkNamePtr = localName(iPtr->varFramePtr, localIndex); if ((!namePtr && (checkNamePtr == part1Ptr)) || @@ -711,8 +725,10 @@ TclObjLookupVarEx( part1Ptr->typePtr = &localVarNameType; if (part1Ptr != localName(iPtr->varFramePtr, index)) { - part1Ptr->internalRep.ptrAndLongRep.ptr = localName(iPtr->varFramePtr, index); - Tcl_IncrRefCount((Tcl_Obj *)part1Ptr->internalRep.ptrAndLongRep.ptr); + part1Ptr->internalRep.ptrAndLongRep.ptr = + localName(iPtr->varFramePtr, index); + Tcl_IncrRefCount((Tcl_Obj *) + part1Ptr->internalRep.ptrAndLongRep.ptr); } else { part1Ptr->internalRep.ptrAndLongRep.ptr = NULL; } @@ -919,11 +935,10 @@ TclLookupSimpleVar( || !HasLocalVars(varFramePtr) || (strstr(varName, "::") != NULL)) { const char *tail; - int lookGlobal; - - lookGlobal = (flags & TCL_GLOBAL_ONLY) + int lookGlobal = (flags & TCL_GLOBAL_ONLY) || (cxtNsPtr == iPtr->globalNsPtr) || ((*varName == ':') && (*(varName+1) == ':')); + if (lookGlobal) { *indexPtr = -1; flags = (flags | TCL_GLOBAL_ONLY) & ~TCL_NAMESPACE_ONLY; @@ -942,7 +957,8 @@ TclLookupSimpleVar( */ varPtr = (Var *) ObjFindNamespaceVar(interp, varNamePtr, - (Tcl_Namespace *) cxtNsPtr, (flags | AVOID_RESOLVERS) & ~TCL_LEAVE_ERR_MSG); + (Tcl_Namespace *) cxtNsPtr, + (flags | AVOID_RESOLVERS) & ~TCL_LEAVE_ERR_MSG); if (varPtr == NULL) { Tcl_Obj *tailPtr; @@ -952,11 +968,11 @@ TclLookupSimpleVar( if (varNsPtr == NULL) { *errMsgPtr = badNamespace; return NULL; - } - if (tail == NULL) { + } else if (tail == NULL) { *errMsgPtr = missingName; return NULL; - } else if (tail != varName) { + } + if (tail != varName) { tailPtr = Tcl_NewStringObj(tail, -1); } else { tailPtr = varNamePtr; @@ -984,9 +1000,11 @@ TclLookupSimpleVar( Tcl_Obj **objPtrPtr = &varFramePtr->localCachePtr->varName0; for (i=0 ; i<localCt ; i++, objPtrPtr++) { - Tcl_Obj *objPtr = *objPtrPtr; + register Tcl_Obj *objPtr = *objPtrPtr; + if (objPtr) { char *localName = TclGetString(objPtr); + if ((varName[0] == localName[0]) && (strcmp(varName, localName) == 0)) { *indexPtr = i; @@ -1366,7 +1384,9 @@ TclPtrGetVar( * in the array part1. */ const int flags, /* OR-ed combination of TCL_GLOBAL_ONLY, and * TCL_LEAVE_ERR_MSG bits. */ - int index) + int index) /* Index into the local variable table of the + * variable, or -1. Only used when part1Ptr is + * NULL. */ { Interp *iPtr = (Interp *) interp; const char *msg; @@ -2011,7 +2031,9 @@ TclPtrIncrObjVar( * any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY, * TCL_APPEND_VALUE, TCL_LIST_ELEMENT, * TCL_LEAVE_ERR_MSG. */ - int index) + int index) /* Index into the local variable table of the + * variable, or -1. Only used when part1Ptr is + * NULL. */ { register Tcl_Obj *varValuePtr, *newValuePtr = NULL; int duplicated, code; @@ -2322,7 +2344,8 @@ UnsetVarStruct( dummyVar.flags &= ~VAR_TRACE_ACTIVE; TclObjCallVarTraces(iPtr, arrayPtr, (Var *) &dummyVar, part1Ptr, part2Ptr, - (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY))| TCL_TRACE_UNSETS, + (flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY)) + | TCL_TRACE_UNSETS, /* leaveErrMsg */ 0, -1); if (tPtr) { Tcl_DeleteHashEntry(tPtr); @@ -4205,11 +4228,11 @@ ParseSearchId( * optimize this address arithmetic! */ - id = (int)(((char*)handleObj->internalRep.twoPtrValue.ptr1) - - ((char*)NULL)); + id = (int)(((char *) handleObj->internalRep.twoPtrValue.ptr1) - + ((char *) NULL)); string = TclGetString(handleObj); - offset = (((char*)handleObj->internalRep.twoPtrValue.ptr2) - - ((char*)NULL)); + offset = (((char *) handleObj->internalRep.twoPtrValue.ptr2) - + ((char *) NULL)); /* * This test cannot be placed inside the Tcl_Obj machinery, since it is @@ -4219,9 +4242,7 @@ ParseSearchId( if (strcmp(string+offset, varName) != 0) { Tcl_AppendResult(interp, "search identifier \"", string, "\" isn't for variable \"", varName, "\"", NULL); - Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAYSEARCH", string, - NULL); - return NULL; + goto badLookup; } /* @@ -4235,7 +4256,7 @@ ParseSearchId( if (varPtr->flags & VAR_SEARCH_ACTIVE) { Tcl_HashEntry *hPtr = - Tcl_FindHashEntry(&iPtr->varSearches,(char *) varPtr); + Tcl_FindHashEntry(&iPtr->varSearches, (char *) varPtr); for (searchPtr = (ArraySearch *) Tcl_GetHashValue(hPtr); searchPtr != NULL; searchPtr = searchPtr->nextPtr) { @@ -4245,6 +4266,7 @@ ParseSearchId( } } Tcl_AppendResult(interp, "couldn't find search \"", string, "\"", NULL); + badLookup: Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARRAYSEARCH", string, NULL); return NULL; } @@ -4610,11 +4632,13 @@ TclObjVarErrMsg( const char *operation, /* String describing operation that failed, * e.g. "read", "set", or "unset". */ const char *reason, /* String describing why operation failed. */ - int index) + int index) /* Index into the local variable table of the + * variable, or -1. Only used when part1Ptr is + * NULL. */ { Tcl_ResetResult(interp); if (!part1Ptr) { - part1Ptr = localName(((Interp*)interp)->varFramePtr, index); + part1Ptr = localName(((Interp *)interp)->varFramePtr, index); } Tcl_AppendResult(interp, "can't ", operation, " \"", TclGetString(part1Ptr), NULL); @@ -4685,8 +4709,9 @@ DupLocalVarName( } dupPtr->internalRep.ptrAndLongRep.ptr = namePtr; Tcl_IncrRefCount(namePtr); - - dupPtr->internalRep.ptrAndLongRep.value = srcPtr->internalRep.ptrAndLongRep.value; + + dupPtr->internalRep.ptrAndLongRep.value = + srcPtr->internalRep.ptrAndLongRep.value; dupPtr->typePtr = &localVarNameType; } @@ -4894,7 +4919,7 @@ ObjFindNamespaceVar( Tcl_Var var; Tcl_Obj *simpleNamePtr; char *name = TclGetString(namePtr); - + /* * If this namespace has a variable resolver, then give it first crack at * the variable resolution. It may return a Tcl_Var value, it may signal @@ -4955,7 +4980,7 @@ ObjFindNamespaceVar( } else { simpleNamePtr = namePtr; } - + for (search = 0; (search < 2) && (varPtr == NULL); search++) { if ((nsPtr[search] != NULL) && (simpleName != NULL)) { varPtr = VarHashFindVar(&nsPtr[search]->varTable, simpleNamePtr); @@ -4964,13 +4989,12 @@ ObjFindNamespaceVar( if (simpleName != name) { Tcl_DecrRefCount(simpleNamePtr); } - if (varPtr != NULL) { - return (Tcl_Var) varPtr; - } else if (flags & TCL_LEAVE_ERR_MSG) { + if ((varPtr == NULL) && (flags & TCL_LEAVE_ERR_MSG)) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "unknown variable \"", name, "\"", NULL); + Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARIABLE", name, NULL); } - return (Tcl_Var) NULL; + return (Tcl_Var) varPtr; } /* @@ -5489,8 +5513,8 @@ CompareVarKeys( } /* - * Don't use Tcl_GetStringFromObj as it would prevent l1 and l2 being - * in a register. + * Don't use Tcl_GetStringFromObj as it would prevent l1 and l2 being in a + * register. */ p1 = TclGetString(objPtr1); @@ -5540,7 +5564,7 @@ HashVarKey( * character's bits hang around in the low-order bits of the hash value * for ever, plus they spread fairly rapidly up to the high-order bits * to fill out the hash value. This seems works well both for decimal - * and *non-decimal strings. + * and non-decimal strings. */ for (i=0 ; i<length ; i++) { |