summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2007-11-16 07:20:49 (GMT)
committerdgp <dgp@users.sourceforge.net>2007-11-16 07:20:49 (GMT)
commit98f0d1a3406ed99293cd6bb505ccd29063208ce5 (patch)
tree91c4790b7f459c9347f152a95205730c4119ff6c /generic
parent55e6c0333341b101e68407be7eebe42f829c9f33 (diff)
downloadtcl-98f0d1a3406ed99293cd6bb505ccd29063208ce5.zip
tcl-98f0d1a3406ed99293cd6bb505ccd29063208ce5.tar.gz
tcl-98f0d1a3406ed99293cd6bb505ccd29063208ce5.tar.bz2
merge updates from HEAD
Diffstat (limited to 'generic')
-rw-r--r--generic/regc_color.c16
-rw-r--r--generic/regc_cvec.c102
-rw-r--r--generic/regc_locale.c87
-rw-r--r--generic/regc_nfa.c46
-rw-r--r--generic/regcomp.c366
-rw-r--r--generic/regcustom.h113
-rw-r--r--generic/regguts.h34
-rw-r--r--generic/tclCmdIL.c19
-rw-r--r--generic/tclCompCmds.c340
-rw-r--r--generic/tclCompile.c64
-rw-r--r--generic/tclCompile.h10
-rw-r--r--generic/tclExecute.c121
-rw-r--r--generic/tclInt.h8
-rw-r--r--generic/tclNamesp.c52
-rw-r--r--generic/tclTrace.c251
-rw-r--r--generic/tclVar.c126
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&REG_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&REG_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++) {