Save the length of each variable in the name table so that we can

compare the lengths and then use memcmp() in the search code.
Speeds up one of my scripts by a facter of 2.
Increase the size of the variable hash table.
Cuts down time for script to execute from 60 seconds to 10.
Move variable search into a new function to hide the implementation
from most of the code, new version is slightly smaller than old.
This commit is contained in:
dsl 2004-10-02 12:16:53 +00:00
parent 5a0e6a845d
commit 5f9b910124
2 changed files with 124 additions and 118 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: var.c,v 1.34 2003/08/26 18:14:24 jmmv Exp $ */
/* $NetBSD: var.c,v 1.35 2004/10/02 12:16:53 dsl Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: var.c,v 1.34 2003/08/26 18:14:24 jmmv Exp $");
__RCSID("$NetBSD: var.c,v 1.35 2004/10/02 12:16:53 dsl Exp $");
#endif
#endif /* not lint */
@ -69,8 +69,11 @@ __RCSID("$NetBSD: var.c,v 1.34 2003/08/26 18:14:24 jmmv Exp $");
#include "myhistedit.h"
#endif
#ifdef SMALL
#define VTABSIZE 39
#else
#define VTABSIZE 517
#endif
struct varinit {
@ -134,8 +137,8 @@ const struct varinit varinit[] = {
struct var *vartab[VTABSIZE];
STATIC struct var **hashvar(const char *);
STATIC int varequal(const char *, const char *);
STATIC int strequal(const char *, const char *);
STATIC struct var *find_var(const char *, struct var ***, int *);
/*
* Initialize the varable symbol tables and import the environment
@ -170,20 +173,18 @@ initvar(void)
struct var **vpp;
for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
if ((vp->flags & VEXPORT) == 0) {
vpp = hashvar(ip->text);
vp->next = *vpp;
*vpp = vp;
vp->text = strdup(ip->text);
vp->flags = ip->flags;
vp->func = ip->func;
}
if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
continue;
vp->next = *vpp;
*vpp = vp;
vp->text = strdup(ip->text);
vp->flags = ip->flags;
vp->func = ip->func;
}
/*
* PS1 depends on uid
*/
if ((vps1.flags & VEXPORT) == 0) {
vpp = hashvar("PS1=");
if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
vps1.next = *vpp;
*vpp = &vps1;
vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
@ -277,39 +278,36 @@ void
setvareq(char *s, int flags)
{
struct var *vp, **vpp;
int nlen;
if (aflag)
flags |= VEXPORT;
vpp = hashvar(s);
for (vp = *vpp ; vp ; vp = vp->next) {
if (varequal(s, vp->text)) {
if (vp->flags & VREADONLY) {
size_t len = strchr(s, '=') - s;
error("%.*s: is read only", len, s);
}
if (flags & VNOSET)
return;
INTOFF;
if (vp->func && (flags & VNOFUNC) == 0)
(*vp->func)(strchr(s, '=') + 1);
if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
ckfree(vp->text);
vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
vp->flags |= flags & ~VNOFUNC;
vp->text = s;
/*
* We could roll this to a function, to handle it as
* a regular variable function callback, but why bother?
*/
if (vp == &vmpath || (vp == &vmail && ! mpathset()))
chkmail(1);
INTON;
vp = find_var(s, &vpp, &nlen);
if (vp != NULL) {
if (vp->flags & VREADONLY)
error("%.*s: is read only", vp->name_len, s);
if (flags & VNOSET)
return;
}
INTOFF;
if (vp->func && (flags & VNOFUNC) == 0)
(*vp->func)(s + vp->name_len + 1);
if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
ckfree(vp->text);
vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
vp->flags |= flags & ~VNOFUNC;
vp->text = s;
/*
* We could roll this to a function, to handle it as
* a regular variable function callback, but why bother?
*/
if (vp == &vmpath || (vp == &vmail && ! mpathset()))
chkmail(1);
INTON;
return;
}
/* not found */
if (flags & VNOSET)
@ -317,6 +315,7 @@ setvareq(char *s, int flags)
vp = ckmalloc(sizeof (*vp));
vp->flags = flags & ~VNOFUNC;
vp->text = s;
vp->name_len = nlen;
vp->next = *vpp;
vp->func = NULL;
*vpp = vp;
@ -359,14 +358,10 @@ lookupvar(const char *name)
{
struct var *v;
for (v = *hashvar(name) ; v ; v = v->next) {
if (varequal(v->text, name)) {
if (v->flags & VUNSET)
return NULL;
return strchr(v->text, '=') + 1;
}
}
return NULL;
v = find_var(name, NULL, NULL);
if (v == NULL || v->flags & VUNSET)
return NULL;
return v->text + v->name_len + 1;
}
@ -384,18 +379,15 @@ bltinlookup(const char *name, int doall)
struct var *v;
for (sp = cmdenviron ; sp ; sp = sp->next) {
if (varequal(sp->text, name))
if (strequal(sp->text, name))
return strchr(sp->text, '=') + 1;
}
for (v = *hashvar(name) ; v ; v = v->next) {
if (varequal(v->text, name)) {
if ((v->flags & VUNSET)
|| (!doall && (v->flags & VEXPORT) == 0))
return NULL;
return strchr(v->text, '=') + 1;
}
}
return NULL;
v = find_var(name, NULL, NULL);
if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT)))
return NULL;
return v->text + v->name_len + 1;
}
@ -579,7 +571,6 @@ showvars(const char *name, int flag, int show_value)
int
exportcmd(int argc, char **argv)
{
struct var **vpp;
struct var *vp;
char *name;
const char *p;
@ -596,16 +587,13 @@ exportcmd(int argc, char **argv)
if ((p = strchr(name, '=')) != NULL) {
p++;
} else {
vpp = hashvar(name);
for (vp = *vpp ; vp ; vp = vp->next) {
if (varequal(vp->text, name)) {
vp->flags |= flag;
goto found;
}
vp = find_var(name, NULL, NULL);
if (vp != NULL) {
vp->flags |= flag;
return 0;
}
}
setvar(name, p, flag);
found:;
}
return 0;
}
@ -651,8 +639,7 @@ mklocal(const char *name, int flags)
lvp->text = memcpy(p, optlist, sizeof_optlist);
vp = NULL;
} else {
vpp = hashvar(name);
for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
vp = find_var(name, &vpp, NULL);
if (vp == NULL) {
if (strchr(name, '='))
setvareq(savestr(name), VSTRFIXED|flags);
@ -665,7 +652,7 @@ mklocal(const char *name, int flags)
lvp->text = vp->text;
lvp->flags = vp->flags;
vp->flags |= VSTRFIXED|VTEXTFIXED;
if (strchr(name, '='))
if (name[vp->name_len] == '=')
setvareq(savestr(name), flags);
}
}
@ -697,7 +684,7 @@ poplocalvars(void)
(void)unsetvar(vp->text, 0);
} else {
if (vp->func && (vp->flags & VNOFUNC) == 0)
(*vp->func)(strchr(lvp->text, '=') + 1);
(*vp->func)(lvp->text + vp->name_len + 1);
if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text);
vp->flags = lvp->flags;
@ -765,53 +752,33 @@ unsetvar(const char *s, int unexport)
struct var **vpp;
struct var *vp;
vpp = hashvar(s);
for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
if (varequal(vp->text, s)) {
if (vp->flags & VREADONLY)
return (1);
INTOFF;
if (unexport) {
vp->flags &= ~VEXPORT;
} else {
if (*(strchr(vp->text, '=') + 1) != '\0')
setvar(s, nullstr, 0);
vp->flags &= ~VEXPORT;
vp->flags |= VUNSET;
if ((vp->flags & VSTRFIXED) == 0) {
if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text);
*vpp = vp->next;
ckfree(vp);
}
}
INTON;
return (0);
vp = find_var(s, &vpp, NULL);
if (vp == NULL)
return 1;
if (vp->flags & VREADONLY)
return (1);
INTOFF;
if (unexport) {
vp->flags &= ~VEXPORT;
} else {
if (vp->text[vp->name_len + 1] != '\0')
setvar(s, nullstr, 0);
vp->flags &= ~VEXPORT;
vp->flags |= VUNSET;
if ((vp->flags & VSTRFIXED) == 0) {
if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text);
*vpp = vp->next;
ckfree(vp);
}
}
return (1);
INTON;
return 0;
}
/*
* Find the appropriate entry in the hash table from the name.
*/
STATIC struct var **
hashvar(const char *p)
{
unsigned int hashval;
hashval = ((unsigned char) *p) << 4;
while (*p && *p != '=')
hashval += (unsigned char) *p++;
return &vartab[hashval % VTABSIZE];
}
/*
* Returns true if the two strings specify the same varable. The first
* variable name is terminated by '='; the second may be terminated by
@ -819,7 +786,7 @@ hashvar(const char *p)
*/
STATIC int
varequal(const char *p, const char *q)
strequal(const char *p, const char *q)
{
while (*p == *q++) {
if (*p++ == '=')
@ -829,3 +796,41 @@ varequal(const char *p, const char *q)
return 1;
return 0;
}
/*
* Search for a variable.
* 'name' may be terminated by '=' or a NUL.
* vppp is set to the pointer to vp, or the list head if vp isn't found
* lenp is set to the number of charactets in 'name'
*/
STATIC struct var *
find_var(const char *name, struct var ***vppp, int *lenp)
{
unsigned int hashval;
int len;
struct var *vp, **vpp;
const char *p = name;
hashval = 0;
while (*p && *p != '=')
hashval = 2 * hashval + (unsigned char)*p++;
len = p - name;
if (lenp)
*lenp = len;
vpp = &vartab[hashval % VTABSIZE];
if (vppp)
*vppp = vpp;
for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
if (vp->name_len != len)
continue;
if (memcmp(vp->text, name, len) != 0)
continue;
if (vppp)
*vppp = vpp;
return vp;
}
return NULL;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: var.h,v 1.22 2003/08/07 09:05:39 agc Exp $ */
/* $NetBSD: var.h,v 1.23 2004/10/02 12:16:53 dsl Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -53,6 +53,7 @@ struct var {
struct var *next; /* next entry in hash list */
int flags; /* flags are defined above */
char *text; /* name=value */
int name_len; /* length of name */
void (*func)(const char *);
/* function to be called when */
/* the variable gets set/unset */