#include "../config.h"
#ifdef ZSH_HASH_DEBUG
# define HASHTABLE_DEBUG_MEMBERS \
\
HashTable next, last; \
char *tablename; \
PrintTableStats printinfo;
#else
# define HASHTABLE_DEBUG_MEMBERS
#endif
#define HASHTABLE_INTERNAL_MEMBERS \
ScanStatus scan; \
HASHTABLE_DEBUG_MEMBERS
typedef struct scanstatus *ScanStatus;
#include "zsh.mdh"
#include "hashtable.pro"
struct scanstatus {
int sorted;
union {
struct {
HashNode *tab;
int ct;
} s;
HashNode u;
} u;
};
#ifdef ZSH_HASH_DEBUG
static HashTable firstht, lastht;
#endif
mod_export unsigned
hasher(const char *str)
{
unsigned hashval = 0, c;
while ((c = *((unsigned char *) str++)))
hashval += (hashval << 5) + c;
return hashval;
}
mod_export HashTable
newhashtable(int size, UNUSED(char const *name), UNUSED(PrintTableStats printinfo))
{
HashTable ht;
ht = (HashTable) zshcalloc(sizeof *ht);
#ifdef ZSH_HASH_DEBUG
ht->next = NULL;
if(!firstht)
firstht = ht;
ht->last = lastht;
if(lastht)
lastht->next = ht;
lastht = ht;
ht->printinfo = printinfo ? printinfo : printhashtabinfo;
ht->tablename = ztrdup(name);
#endif
ht->nodes = (HashNode *) zshcalloc(size * sizeof(HashNode));
ht->hsize = size;
ht->ct = 0;
ht->scan = NULL;
ht->scantab = NULL;
return ht;
}
mod_export void
deletehashtable(HashTable ht)
{
ht->emptytable(ht);
#ifdef ZSH_HASH_DEBUG
if(ht->next)
ht->next->last = ht->last;
else
lastht = ht->last;
if(ht->last)
ht->last->next = ht->next;
else
firstht = ht->next;
zsfree(ht->tablename);
#endif
zfree(ht->nodes, ht->hsize * sizeof(HashNode));
zfree(ht, sizeof(*ht));
}
mod_export void
addhashnode(HashTable ht, char *nam, void *nodeptr)
{
HashNode oldnode = addhashnode2(ht, nam, nodeptr);
if (oldnode)
ht->freenode(oldnode);
}
HashNode
addhashnode2(HashTable ht, char *nam, void *nodeptr)
{
unsigned hashval;
HashNode hn, hp, hq;
hn = (HashNode) nodeptr;
hn->nam = nam;
hashval = ht->hash(hn->nam) % ht->hsize;
hp = ht->nodes[hashval];
if (!hp) {
hn->next = NULL;
ht->nodes[hashval] = hn;
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
expandhashtable(ht);
return NULL;
}
if (ht->cmpnodes(hp->nam, hn->nam) == 0) {
ht->nodes[hashval] = hn;
replacing:
hn->next = hp->next;
if(ht->scan) {
if(ht->scan->sorted) {
HashNode *tab = ht->scan->u.s.tab;
int i;
for(i = ht->scan->u.s.ct; i--; )
if(tab[i] == hp)
tab[i] = hn;
} else if(ht->scan->u.u == hp)
ht->scan->u.u = hn;
}
return hp;
}
hq = hp;
hp = hp->next;
for (; hp; hq = hp, hp = hp->next) {
if (ht->cmpnodes(hp->nam, hn->nam) == 0) {
hq->next = hn;
goto replacing;
}
}
hn->next = ht->nodes[hashval];
ht->nodes[hashval] = hn;
if (++ht->ct >= ht->hsize * 2 && !ht->scan)
expandhashtable(ht);
return NULL;
}
mod_export HashNode
gethashnode(HashTable ht, const char *nam)
{
unsigned hashval;
HashNode hp;
hashval = ht->hash(nam) % ht->hsize;
for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
if (ht->cmpnodes(hp->nam, nam) == 0) {
if (hp->flags & DISABLED)
return NULL;
else
return hp;
}
}
return NULL;
}
mod_export HashNode
gethashnode2(HashTable ht, const char *nam)
{
unsigned hashval;
HashNode hp;
hashval = ht->hash(nam) % ht->hsize;
for (hp = ht->nodes[hashval]; hp; hp = hp->next) {
if (ht->cmpnodes(hp->nam, nam) == 0)
return hp;
}
return NULL;
}
mod_export HashNode
removehashnode(HashTable ht, const char *nam)
{
unsigned hashval;
HashNode hp, hq;
hashval = ht->hash(nam) % ht->hsize;
hp = ht->nodes[hashval];
if (!hp)
return NULL;
if (ht->cmpnodes(hp->nam, nam) == 0) {
ht->nodes[hashval] = hp->next;
gotit:
ht->ct--;
if(ht->scan) {
if(ht->scan->sorted) {
HashNode *tab = ht->scan->u.s.tab;
int i;
for(i = ht->scan->u.s.ct; i--; )
if(tab[i] == hp)
tab[i] = NULL;
} else if(ht->scan->u.u == hp)
ht->scan->u.u = hp->next;
}
return hp;
}
hq = hp;
hp = hp->next;
for (; hp; hq = hp, hp = hp->next) {
if (ht->cmpnodes(hp->nam, nam) == 0) {
hq->next = hp->next;
goto gotit;
}
}
return NULL;
}
void
disablehashnode(HashNode hn, UNUSED(int flags))
{
hn->flags |= DISABLED;
}
void
enablehashnode(HashNode hn, UNUSED(int flags))
{
hn->flags &= ~DISABLED;
}
static int
hnamcmp(const void *ap, const void *bp)
{
HashNode a = *(HashNode *)ap;
HashNode b = *(HashNode *)bp;
return ztrcmp(a->nam, b->nam);
}
mod_export int
scanmatchtable(HashTable ht, Patprog pprog, int sorted,
int flags1, int flags2, ScanFunc scanfunc, int scanflags)
{
int match = 0;
struct scanstatus st;
if (!pprog && ht->scantab) {
ht->scantab(ht, scanfunc, scanflags);
return ht->ct;
}
if (sorted) {
int i, ct = ht->ct;
VARARR(HashNode, hnsorttab, ct);
HashNode *htp, hn;
for (htp = hnsorttab, i = 0; i < ht->hsize; i++)
for (hn = ht->nodes[i]; hn; hn = hn->next)
*htp++ = hn;
qsort((void *)hnsorttab, ct, sizeof(HashNode), hnamcmp);
st.sorted = 1;
st.u.s.tab = hnsorttab;
st.u.s.ct = ct;
ht->scan = &st;
for (htp = hnsorttab, i = 0; i < ct; i++, htp++) {
if ((!flags1 || ((*htp)->flags & flags1)) &&
!((*htp)->flags & flags2) &&
(!pprog || pattry(pprog, (*htp)->nam))) {
match++;
scanfunc(*htp, scanflags);
}
}
ht->scan = NULL;
} else {
int i, hsize = ht->hsize;
HashNode *nodes = ht->nodes;
st.sorted = 0;
ht->scan = &st;
for (i = 0; i < hsize; i++)
for (st.u.u = nodes[i]; st.u.u; ) {
HashNode hn = st.u.u;
st.u.u = st.u.u->next;
if ((!flags1 || (hn->flags & flags1)) && !(hn->flags & flags2)
&& (!pprog || pattry(pprog, hn->nam))) {
match++;
scanfunc(hn, scanflags);
}
}
ht->scan = NULL;
}
return match;
}
mod_export int
scanhashtable(HashTable ht, int sorted, int flags1, int flags2,
ScanFunc scanfunc, int scanflags)
{
return scanmatchtable(ht, NULL, sorted, flags1, flags2,
scanfunc, scanflags);
}
static void
expandhashtable(HashTable ht)
{
struct hashnode **onodes, **ha, *hn, *hp;
int i, osize;
osize = ht->hsize;
onodes = ht->nodes;
ht->hsize = osize * 4;
ht->nodes = (HashNode *) zshcalloc(ht->hsize * sizeof(HashNode));
ht->ct = 0;
for (i = 0, ha = onodes; i < osize; i++, ha++) {
for (hn = *ha; hn;) {
hp = hn->next;
ht->addnode(ht, hn->nam, hn);
hn = hp;
}
}
zfree(onodes, osize * sizeof(HashNode));
}
static void
resizehashtable(HashTable ht, int newsize)
{
struct hashnode **ha, *hn, *hp;
int i;
ha = ht->nodes;
for (i = 0; i < ht->hsize; i++, ha++) {
for (hn = *ha; hn;) {
hp = hn->next;
ht->freenode(hn);
hn = hp;
}
}
if (ht->hsize != newsize) {
zfree(ht->nodes, ht->hsize * sizeof(HashNode));
ht->nodes = (HashNode *) zshcalloc(newsize * sizeof(HashNode));
ht->hsize = newsize;
} else {
memset(ht->nodes, 0, newsize * sizeof(HashNode));
}
ht->ct = 0;
}
mod_export void
emptyhashtable(HashTable ht)
{
resizehashtable(ht, ht->hsize);
}
#ifdef ZSH_HASH_DEBUG
#define MAXDEPTH 7
static void
printhashtabinfo(HashTable ht)
{
HashNode hn;
int chainlen[MAXDEPTH + 1];
int i, tmpcount, total;
printf("name of table : %s\n", ht->tablename);
printf("size of nodes[] : %d\n", ht->hsize);
printf("number of nodes : %d\n\n", ht->ct);
memset(chainlen, 0, sizeof(chainlen));
total = 0;
for (i = 0; i < ht->hsize; i++) {
tmpcount = 0;
for (hn = ht->nodes[i]; hn; hn = hn->next)
tmpcount++;
if (tmpcount >= MAXDEPTH)
chainlen[MAXDEPTH]++;
else
chainlen[tmpcount]++;
total += tmpcount;
}
for (i = 0; i < MAXDEPTH; i++)
printf("number of hash values with chain of length %d : %4d\n", i, chainlen[i]);
printf("number of hash values with chain of length %d+ : %4d\n", MAXDEPTH, chainlen[MAXDEPTH]);
printf("total number of nodes : %4d\n", total);
}
int
bin_hashinfo(char *nam, char **args, Options ops, int func)
{
HashTable ht;
printf("----------------------------------------------------\n");
queue_signals();
for(ht = firstht; ht; ht = ht->next) {
ht->printinfo(ht);
printf("----------------------------------------------------\n");
}
unqueue_signals();
return 0;
}
#endif
mod_export HashTable cmdnamtab;
mod_export char **pathchecked;
void
createcmdnamtable(void)
{
cmdnamtab = newhashtable(201, "cmdnamtab", NULL);
cmdnamtab->hash = hasher;
cmdnamtab->emptytable = emptycmdnamtable;
cmdnamtab->filltable = fillcmdnamtable;
cmdnamtab->cmpnodes = strcmp;
cmdnamtab->addnode = addhashnode;
cmdnamtab->getnode = gethashnode2;
cmdnamtab->getnode2 = gethashnode2;
cmdnamtab->removenode = removehashnode;
cmdnamtab->disablenode = NULL;
cmdnamtab->enablenode = NULL;
cmdnamtab->freenode = freecmdnamnode;
cmdnamtab->printnode = printcmdnamnode;
pathchecked = path;
}
static void
emptycmdnamtable(HashTable ht)
{
emptyhashtable(ht);
pathchecked = path;
}
void
hashdir(char **dirp)
{
Cmdnam cn;
DIR *dir;
char *fn;
#if defined(_WIN32) || defined(__CYGWIN__)
char *exe;
#endif
if (isrelative(*dirp) || !(dir = opendir(unmeta(*dirp))))
return;
while ((fn = zreaddir(dir, 1))) {
if (!cmdnamtab->getnode(cmdnamtab, fn)) {
cn = (Cmdnam) zshcalloc(sizeof *cn);
cn->node.flags = 0;
cn->u.name = dirp;
cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
}
#if defined(_WIN32) || defined(__CYGWIN__)
if ((exe = strrchr(fn, '.')) &&
(exe[1] == 'E' || exe[1] == 'e') &&
(exe[2] == 'X' || exe[2] == 'x') &&
(exe[3] == 'E' || exe[3] == 'e') && exe[4] == 0) {
*exe = 0;
if (!cmdnamtab->getnode(cmdnamtab, fn)) {
cn = (Cmdnam) zshcalloc(sizeof *cn);
cn->node.flags = 0;
cn->u.name = dirp;
cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
}
}
#endif
}
closedir(dir);
}
static void
fillcmdnamtable(UNUSED(HashTable ht))
{
char **pq;
for (pq = pathchecked; *pq; pq++)
hashdir(pq);
pathchecked = pq;
}
static void
freecmdnamnode(HashNode hn)
{
Cmdnam cn = (Cmdnam) hn;
zsfree(cn->node.nam);
if (cn->node.flags & HASHED)
zsfree(cn->u.cmd);
zfree(cn, sizeof(struct cmdnam));
}
static void
printcmdnamnode(HashNode hn, int printflags)
{
Cmdnam cn = (Cmdnam) hn;
if (printflags & PRINT_WHENCE_WORD) {
printf("%s: %s\n", cn->node.nam, (cn->node.flags & HASHED) ?
"hashed" : "command");
return;
}
if ((printflags & PRINT_WHENCE_CSH) || (printflags & PRINT_WHENCE_SIMPLE)) {
if (cn->node.flags & HASHED) {
zputs(cn->u.cmd, stdout);
putchar('\n');
} else {
zputs(*(cn->u.name), stdout);
putchar('/');
zputs(cn->node.nam, stdout);
putchar('\n');
}
return;
}
if (printflags & PRINT_WHENCE_VERBOSE) {
if (cn->node.flags & HASHED) {
nicezputs(cn->node.nam, stdout);
printf(" is hashed to ");
nicezputs(cn->u.cmd, stdout);
putchar('\n');
} else {
nicezputs(cn->node.nam, stdout);
printf(" is ");
nicezputs(*(cn->u.name), stdout);
putchar('/');
nicezputs(cn->node.nam, stdout);
putchar('\n');
}
return;
}
if (printflags & PRINT_LIST) {
printf("hash ");
if(cn->node.nam[0] == '-')
printf("-- ");
}
if (cn->node.flags & HASHED) {
quotedzputs(cn->node.nam, stdout);
putchar('=');
quotedzputs(cn->u.cmd, stdout);
putchar('\n');
} else {
quotedzputs(cn->node.nam, stdout);
putchar('=');
quotedzputs(*(cn->u.name), stdout);
putchar('/');
quotedzputs(cn->node.nam, stdout);
putchar('\n');
}
}
mod_export HashTable shfunctab;
void
createshfunctable(void)
{
shfunctab = newhashtable(7, "shfunctab", NULL);
shfunctab->hash = hasher;
shfunctab->emptytable = NULL;
shfunctab->filltable = NULL;
shfunctab->cmpnodes = strcmp;
shfunctab->addnode = addhashnode;
shfunctab->getnode = gethashnode;
shfunctab->getnode2 = gethashnode2;
shfunctab->removenode = removeshfuncnode;
shfunctab->disablenode = disableshfuncnode;
shfunctab->enablenode = enableshfuncnode;
shfunctab->freenode = freeshfuncnode;
shfunctab->printnode = printshfuncnode;
}
static HashNode
removeshfuncnode(UNUSED(HashTable ht), const char *nam)
{
HashNode hn;
int signum;
if (!strncmp(nam, "TRAP", 4) && (signum = getsignum(nam + 4)) != -1)
hn = removetrap(signum);
else
hn = removehashnode(shfunctab, nam);
return hn;
}
static void
disableshfuncnode(HashNode hn, UNUSED(int flags))
{
hn->flags |= DISABLED;
if (!strncmp(hn->nam, "TRAP", 4)) {
int signum = getsignum(hn->nam + 4);
if (signum != -1) {
sigtrapped[signum] &= ~ZSIG_FUNC;
unsettrap(signum);
}
}
}
static void
enableshfuncnode(HashNode hn, UNUSED(int flags))
{
Shfunc shf = (Shfunc) hn;
shf->node.flags &= ~DISABLED;
if (!strncmp(shf->node.nam, "TRAP", 4)) {
int signum = getsignum(shf->node.nam + 4);
if (signum != -1) {
settrap(signum, NULL, ZSIG_FUNC);
}
}
}
static void
freeshfuncnode(HashNode hn)
{
Shfunc shf = (Shfunc) hn;
zsfree(shf->node.nam);
if (shf->funcdef)
freeeprog(shf->funcdef);
zsfree(shf->filename);
zfree(shf, sizeof(struct shfunc));
}
static void
printshfuncnode(HashNode hn, int printflags)
{
Shfunc f = (Shfunc) hn;
char *t = 0;
if ((printflags & PRINT_NAMEONLY) ||
((printflags & PRINT_WHENCE_SIMPLE) &&
!(printflags & PRINT_WHENCE_FUNCDEF))) {
zputs(f->node.nam, stdout);
putchar('\n');
return;
}
if ((printflags & (PRINT_WHENCE_VERBOSE|PRINT_WHENCE_WORD)) &&
!(printflags & PRINT_WHENCE_FUNCDEF)) {
nicezputs(f->node.nam, stdout);
printf((printflags & PRINT_WHENCE_WORD) ? ": function\n" :
" is a shell function\n");
return;
}
quotedzputs(f->node.nam, stdout);
if (f->funcdef || f->node.flags & PM_UNDEFINED) {
printf(" () {\n\t");
if (f->node.flags & PM_UNDEFINED)
printf("%c undefined\n\t", hashchar);
else
t = getpermtext(f->funcdef, NULL, 1);
if (f->node.flags & PM_TAGGED)
printf("%c traced\n\t", hashchar);
if (!t) {
char *fopt = "Utkz";
int flgs[] = {
PM_UNALIASED, PM_TAGGED, PM_KSHSTORED, PM_ZSHSTORED, 0
};
int fl;;
zputs("builtin autoload -X", stdout);
for (fl=0;fopt[fl];fl++)
if (f->node.flags & flgs[fl]) putchar(fopt[fl]);
} else {
zputs(t, stdout);
zsfree(t);
if (f->funcdef->flags & EF_RUN) {
printf("\n\t");
quotedzputs(f->node.nam, stdout);
printf(" \"$@\"");
}
}
printf("\n}\n");
} else {
printf(" () { }\n");
}
}
static struct reswd reswds[] = {
{{NULL, "!", 0}, BANG},
{{NULL, "[[", 0}, DINBRACK},
{{NULL, "{", 0}, INBRACE},
{{NULL, "}", 0}, OUTBRACE},
{{NULL, "case", 0}, CASE},
{{NULL, "coproc", 0}, COPROC},
{{NULL, "do", 0}, DOLOOP},
{{NULL, "done", 0}, DONE},
{{NULL, "elif", 0}, ELIF},
{{NULL, "else", 0}, ELSE},
{{NULL, "end", 0}, ZEND},
{{NULL, "esac", 0}, ESAC},
{{NULL, "fi", 0}, FI},
{{NULL, "for", 0}, FOR},
{{NULL, "foreach", 0}, FOREACH},
{{NULL, "function", 0}, FUNC},
{{NULL, "if", 0}, IF},
{{NULL, "nocorrect", 0}, NOCORRECT},
{{NULL, "repeat", 0}, REPEAT},
{{NULL, "select", 0}, SELECT},
{{NULL, "then", 0}, THEN},
{{NULL, "time", 0}, TIME},
{{NULL, "until", 0}, UNTIL},
{{NULL, "while", 0}, WHILE},
{{NULL, NULL, 0}, 0}
};
mod_export HashTable reswdtab;
void
createreswdtable(void)
{
Reswd rw;
reswdtab = newhashtable(23, "reswdtab", NULL);
reswdtab->hash = hasher;
reswdtab->emptytable = NULL;
reswdtab->filltable = NULL;
reswdtab->cmpnodes = strcmp;
reswdtab->addnode = addhashnode;
reswdtab->getnode = gethashnode;
reswdtab->getnode2 = gethashnode2;
reswdtab->removenode = NULL;
reswdtab->disablenode = disablehashnode;
reswdtab->enablenode = enablehashnode;
reswdtab->freenode = NULL;
reswdtab->printnode = printreswdnode;
for (rw = reswds; rw->node.nam; rw++)
reswdtab->addnode(reswdtab, rw->node.nam, rw);
}
static void
printreswdnode(HashNode hn, int printflags)
{
Reswd rw = (Reswd) hn;
if (printflags & PRINT_WHENCE_WORD) {
printf("%s: reserved\n", rw->node.nam);
return;
}
if (printflags & PRINT_WHENCE_CSH) {
printf("%s: shell reserved word\n", rw->node.nam);
return;
}
if (printflags & PRINT_WHENCE_VERBOSE) {
printf("%s is a reserved word\n", rw->node.nam);
return;
}
printf("%s\n", rw->node.nam);
}
mod_export HashTable aliastab;
mod_export HashTable sufaliastab;
void
createaliastable(HashTable ht)
{
ht->hash = hasher;
ht->emptytable = NULL;
ht->filltable = NULL;
ht->cmpnodes = strcmp;
ht->addnode = addhashnode;
ht->getnode = gethashnode;
ht->getnode2 = gethashnode2;
ht->removenode = removehashnode;
ht->disablenode = disablehashnode;
ht->enablenode = enablehashnode;
ht->freenode = freealiasnode;
ht->printnode = printaliasnode;
}
void
createaliastables(void)
{
aliastab = newhashtable(23, "aliastab", NULL);
createaliastable(aliastab);
aliastab->addnode(aliastab, ztrdup("run-help"), createaliasnode(ztrdup("man"), 0));
aliastab->addnode(aliastab, ztrdup("which-command"), createaliasnode(ztrdup("whence"), 0));
sufaliastab = newhashtable(11, "sufaliastab", NULL);
createaliastable(sufaliastab);
}
mod_export Alias
createaliasnode(char *txt, int flags)
{
Alias al;
al = (Alias) zshcalloc(sizeof *al);
al->node.flags = flags;
al->text = txt;
al->inuse = 0;
return al;
}
static void
freealiasnode(HashNode hn)
{
Alias al = (Alias) hn;
zsfree(al->node.nam);
zsfree(al->text);
zfree(al, sizeof(struct alias));
}
static void
printaliasnode(HashNode hn, int printflags)
{
Alias a = (Alias) hn;
if (printflags & PRINT_NAMEONLY) {
zputs(a->node.nam, stdout);
putchar('\n');
return;
}
if (printflags & PRINT_WHENCE_WORD) {
printf("%s: alias\n", a->node.nam);
return;
}
if (printflags & PRINT_WHENCE_SIMPLE) {
zputs(a->text, stdout);
putchar('\n');
return;
}
if (printflags & PRINT_WHENCE_CSH) {
nicezputs(a->node.nam, stdout);
printf(": ");
if (a->node.flags & ALIAS_SUFFIX)
printf("suffix ");
else if (a->node.flags & ALIAS_GLOBAL)
printf("globally ");
printf ("aliased to ");
nicezputs(a->text, stdout);
putchar('\n');
return;
}
if (printflags & PRINT_WHENCE_VERBOSE) {
nicezputs(a->node.nam, stdout);
printf(" is a");
if (a->node.flags & ALIAS_SUFFIX)
printf(" suffix");
else if (a->node.flags & ALIAS_GLOBAL)
printf(" global");
else
printf("n");
printf(" alias for ");
nicezputs(a->text, stdout);
putchar('\n');
return;
}
if (printflags & PRINT_LIST) {
printf("alias ");
if (a->node.flags & ALIAS_SUFFIX)
printf("-s ");
else if (a->node.flags & ALIAS_GLOBAL)
printf("-g ");
if(a->node.nam[0] == '-')
printf("-- ");
}
quotedzputs(a->node.nam, stdout);
putchar('=');
quotedzputs(a->text, stdout);
putchar('\n');
}
#ifdef HAVE_NIS_PLUS
# include <rpcsvc/nis.h>
#else
# ifdef HAVE_NIS
# include <rpc/types.h>
# include <rpc/rpc.h>
# include <rpcsvc/ypclnt.h>
# include <rpcsvc/yp_prot.h>
# endif
#endif
mod_export HashTable nameddirtab;
static int allusersadded;
void
createnameddirtable(void)
{
nameddirtab = newhashtable(201, "nameddirtab", NULL);
nameddirtab->hash = hasher;
nameddirtab->emptytable = emptynameddirtable;
nameddirtab->filltable = fillnameddirtable;
nameddirtab->cmpnodes = strcmp;
nameddirtab->addnode = addnameddirnode;
nameddirtab->getnode = gethashnode;
nameddirtab->getnode2 = gethashnode2;
nameddirtab->removenode = removenameddirnode;
nameddirtab->disablenode = NULL;
nameddirtab->enablenode = NULL;
nameddirtab->freenode = freenameddirnode;
nameddirtab->printnode = printnameddirnode;
allusersadded = 0;
finddir(NULL);
}
static void
emptynameddirtable(HashTable ht)
{
emptyhashtable(ht);
allusersadded = 0;
finddir(NULL);
}
#ifdef HAVE_NIS_PLUS
static int
add_userdir(nis_name table, nis_object *object, void *userdata)
{
if (object->zo_data.objdata_u.en_data.en_cols.en_cols_len >= 6) {
static char name[40], dir[PATH_MAX + 1];
register entry_col *ec =
object->zo_data.objdata_u.en_data.en_cols.en_cols_val;
register int nl = minimum(ec[0].ec_value.ec_value_len, 39);
register int dl = minimum(ec[5].ec_value.ec_value_len, PATH_MAX);
memcpy(name, ec[0].ec_value.ec_value_val, nl);
name[nl] = '\0';
memcpy(dir, ec[5].ec_value.ec_value_val, dl);
dir[dl] = '\0';
adduserdir(name, dir, ND_USERNAME, 1);
}
return 0;
}
#else
# ifdef HAVE_NIS
static int
add_userdir(int status, char *key, int keylen, char *val, int vallen, char *dummy)
{
char *p, *d, *de;
if (status != YP_TRUE)
return 1;
if (vallen > keylen && *(p = val + keylen) == ':') {
*p++ = '\0';
for (de = val + vallen - 1; *de != ':' && de > val; de--);
if (de > val) {
*de = '\0';
if ((d = strrchr(p, ':'))) {
if (*++d && val[0])
adduserdir(val, d, ND_USERNAME, 1);
}
}
}
return 0;
}
# endif
#endif
static void
fillnameddirtable(UNUSED(HashTable ht))
{
if (!allusersadded) {
#if defined(HAVE_NIS) || defined(HAVE_NIS_PLUS)
FILE *pwf;
char buf[BUFSIZ], *p, *d, *de;
int skipping, oldct = nameddirtab->ct, usepwf = 1;
# ifndef HAVE_NIS_PLUS
char domain[YPMAXDOMAIN];
struct ypall_callback cb;
if (getdomainname(domain, YPMAXDOMAIN) == 0) {
cb.foreach = (int (*)()) add_userdir;
cb.data = NULL;
yp_all(domain, PASSWD_MAP, &cb);
}
# else
nis_list("passwd.org_dir", EXPAND_NAME|ALL_RESULTS|FOLLOW_LINKS|FOLLOW_PATH,
add_userdir, 0);
# endif
if (nameddirtab->ct == oldct) {
#ifdef HAVE_GETPWENT
struct passwd *pw;
setpwent();
while ((pw = getpwent()) && !errflag)
adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1);
endpwent();
usepwf = 0;
#endif
}
if (usepwf) {
if ((pwf = fopen(PASSWD_FILE, "r")) != NULL) {
skipping = 0;
while (fgets(buf, BUFSIZ, pwf) != NULL) {
if (strchr(buf, '\n') != NULL) {
if (!skipping) {
if ((p = strchr(buf, ':')) != NULL) {
*p++ = '\0';
if ((de = strrchr(p, ':'))) {
*de = '\0';
if ((d = strrchr(p, ':'))) {
if (*++d && buf[0])
adduserdir(buf, d, ND_USERNAME, 1);
}
}
}
} else
skipping = 0;
} else
skipping = 1;
}
fclose(pwf);
}
}
#else
#ifdef USE_GETPWENT
struct passwd *pw;
setpwent();
while ((pw = getpwent()) && !errflag)
adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1);
endpwent();
#endif
#endif
allusersadded = 1;
}
}
static void
addnameddirnode(HashTable ht, char *nam, void *nodeptr)
{
Nameddir nd = (Nameddir) nodeptr;
nd->diff = strlen(nd->dir) - strlen(nam);
finddir(NULL);
addhashnode(ht, nam, nodeptr);
}
static HashNode
removenameddirnode(HashTable ht, const char *nam)
{
HashNode hn = removehashnode(ht, nam);
if(hn)
finddir(NULL);
return hn;
}
static void
freenameddirnode(HashNode hn)
{
Nameddir nd = (Nameddir) hn;
zsfree(nd->node.nam);
zsfree(nd->dir);
zfree(nd, sizeof(struct nameddir));
}
static void
printnameddirnode(HashNode hn, int printflags)
{
Nameddir nd = (Nameddir) hn;
if (printflags & PRINT_NAMEONLY) {
zputs(nd->node.nam, stdout);
putchar('\n');
return;
}
if (printflags & PRINT_LIST) {
printf("hash -d ");
if(nd->node.nam[0] == '-')
printf("-- ");
}
quotedzputs(nd->node.nam, stdout);
putchar('=');
quotedzputs(nd->dir, stdout);
putchar('\n');
}
void
createhisttable(void)
{
histtab = newhashtable(599, "histtab", NULL);
histtab->hash = histhasher;
histtab->emptytable = emptyhisttable;
histtab->filltable = NULL;
histtab->cmpnodes = histstrcmp;
histtab->addnode = addhistnode;
histtab->getnode = gethashnode2;
histtab->getnode2 = gethashnode2;
histtab->removenode = removehashnode;
histtab->disablenode = NULL;
histtab->enablenode = NULL;
histtab->freenode = freehistnode;
histtab->printnode = NULL;
}
unsigned
histhasher(const char *str)
{
unsigned hashval = 0;
while (inblank(*str)) str++;
while (*str) {
if (inblank(*str)) {
do str++; while (inblank(*str));
if (*str)
hashval += (hashval << 5) + ' ';
}
else
hashval += (hashval << 5) + *(unsigned char *)str++;
}
return hashval;
}
void
emptyhisttable(HashTable ht)
{
emptyhashtable(ht);
if (hist_ring)
histremovedups();
}
int
histstrcmp(const char *str1, const char *str2)
{
while (inblank(*str1)) str1++;
while (inblank(*str2)) str2++;
while (*str1 && *str2) {
if (inblank(*str1)) {
if (!inblank(*str2))
break;
do str1++; while (inblank(*str1));
do str2++; while (inblank(*str2));
}
else {
if (*str1 != *str2)
break;
str1++;
str2++;
}
}
return *str1 - *str2;
}
void
addhistnode(HashTable ht, char *nam, void *nodeptr)
{
HashNode oldnode = addhashnode2(ht, nam, nodeptr);
Histent he = (Histent)nodeptr;
if (oldnode && oldnode != (HashNode)nodeptr) {
if (he->node.flags & HIST_MAKEUNIQUE
|| (he->node.flags & HIST_FOREIGN && (Histent)oldnode == he->up)) {
(void) addhashnode2(ht, oldnode->nam, oldnode);
he->node.flags |= HIST_DUP;
he->node.flags &= ~HIST_MAKEUNIQUE;
}
else {
oldnode->flags |= HIST_DUP;
if (hist_ignore_all_dups)
freehistnode(oldnode);
}
}
else
he->node.flags &= ~HIST_MAKEUNIQUE;
}
void
freehistnode(HashNode nodeptr)
{
freehistdata((Histent)nodeptr, 1);
zfree(nodeptr, sizeof (struct histent));
}
void
freehistdata(Histent he, int unlink)
{
if (!he)
return;
if (!(he->node.flags & (HIST_DUP | HIST_TMPSTORE)))
removehashnode(histtab, he->node.nam);
zsfree(he->node.nam);
if (he->nwords)
zfree(he->words, he->nwords*2*sizeof(short));
if (unlink) {
if (!--histlinect)
hist_ring = NULL;
else {
if (he == hist_ring)
hist_ring = hist_ring->up;
he->up->down = he->down;
he->down->up = he->up;
}
}
}