• rework hash table interna to avoid gcc-4.1 on Debian etch bug
• also improve behaviour with _a lot_ (>2²⁸) entries • while here, improve comments and whitespace
This commit is contained in:
parent
3695f9b259
commit
e0fb8dc431
4
check.t
4
check.t
@ -1,4 +1,4 @@
|
|||||||
# $MirOS: src/bin/mksh/check.t,v 1.461 2011/06/05 16:49:54 tg Exp $
|
# $MirOS: src/bin/mksh/check.t,v 1.462 2011/06/05 19:58:16 tg Exp $
|
||||||
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
|
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
|
||||||
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
|
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
|
||||||
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
|
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
|
||||||
@ -25,7 +25,7 @@
|
|||||||
# http://www.research.att.com/~gsf/public/ifs.sh
|
# http://www.research.att.com/~gsf/public/ifs.sh
|
||||||
|
|
||||||
expected-stdout:
|
expected-stdout:
|
||||||
@(#)MIRBSD KSH R40 2011/06/04
|
@(#)MIRBSD KSH R40 2011/06/05
|
||||||
description:
|
description:
|
||||||
Check version of shell.
|
Check version of shell.
|
||||||
stdin:
|
stdin:
|
||||||
|
90
main.c
90
main.c
@ -33,7 +33,7 @@
|
|||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.192 2011/06/04 16:42:30 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.193 2011/06/05 19:58:18 tg Exp $");
|
||||||
|
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
|
|
||||||
@ -206,8 +206,9 @@ main(int argc, const char *argv[])
|
|||||||
ccp = empty_argv[0];
|
ccp = empty_argv[0];
|
||||||
|
|
||||||
/* define built-in commands and see if we were called as one */
|
/* define built-in commands and see if we were called as one */
|
||||||
ktinit(&builtins, APERM,
|
ktinit(APERM, &builtins,
|
||||||
/* must be 80% of 2^n (currently 44 builtins) */ 64);
|
/* currently 50 builtins -> 80% of 64 (2^6) */
|
||||||
|
6);
|
||||||
for (i = 0; mkshbuiltins[i].name != NULL; i++)
|
for (i = 0; mkshbuiltins[i].name != NULL; i++)
|
||||||
if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
|
if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
|
||||||
mkshbuiltins[i].func)))
|
mkshbuiltins[i].func)))
|
||||||
@ -235,10 +236,10 @@ main(int argc, const char *argv[])
|
|||||||
coproc_init();
|
coproc_init();
|
||||||
|
|
||||||
/* set up variable and command dictionaries */
|
/* set up variable and command dictionaries */
|
||||||
ktinit(&taliases, APERM, 0);
|
ktinit(APERM, &taliases, 0);
|
||||||
ktinit(&aliases, APERM, 0);
|
ktinit(APERM, &aliases, 0);
|
||||||
#ifndef MKSH_NOPWNAM
|
#ifndef MKSH_NOPWNAM
|
||||||
ktinit(&homedirs, APERM, 0);
|
ktinit(APERM, &homedirs, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* define shell keywords */
|
/* define shell keywords */
|
||||||
@ -1442,53 +1443,48 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
|
|||||||
* but with a slightly tweaked implementation written from scratch.
|
* but with a slightly tweaked implementation written from scratch.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define INIT_TBLS 8 /* initial table size (power of 2) */
|
#define INIT_TBLSHIFT 3 /* initial table shift (2^3 = 8) */
|
||||||
#define PERTURB_SHIFT 5 /* see Python 2.5.4 Objects/dictobject.c */
|
#define PERTURB_SHIFT 5 /* see Python 2.5.4 Objects/dictobject.c */
|
||||||
|
|
||||||
static void texpand(struct table *, size_t);
|
static void tgrow(struct table *);
|
||||||
static int tnamecmp(const void *, const void *);
|
static int tnamecmp(const void *, const void *);
|
||||||
static struct tbl *ktscan(struct table *, const char *, uint32_t,
|
|
||||||
struct tbl ***);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
texpand(struct table *tp, size_t nsize)
|
tgrow(struct table *tp)
|
||||||
{
|
{
|
||||||
size_t i, j, osize = tp->size, perturb;
|
size_t i, j, osize, mask, perturb;
|
||||||
struct tbl *tblp, **pp;
|
struct tbl *tblp, **pp;
|
||||||
struct tbl **ntblp, **otblp = tp->tbls;
|
struct tbl **ntblp, **otblp = tp->tbls;
|
||||||
|
|
||||||
i = 1;
|
if (tp->tshift > 29)
|
||||||
i <<= 30;
|
|
||||||
if (nsize > i)
|
|
||||||
internal_errorf("hash table size limit reached");
|
internal_errorf("hash table size limit reached");
|
||||||
|
|
||||||
ntblp = alloc2(nsize, sizeof(struct tbl *), tp->areap);
|
/* calculate old size, new shift and new size */
|
||||||
memset(ntblp, 0, nsize * sizeof(struct tbl *));
|
osize = 1 << (tp->tshift++);
|
||||||
tp->size = nsize;
|
i = osize << 1;
|
||||||
if (nsize == i) {
|
|
||||||
/* cannot be grown any more, use a fixed value */
|
ntblp = alloc2(i, sizeof(struct tbl *), tp->areap);
|
||||||
tp->nfree = i - 65536;
|
/* multiplication cannot overflow: alloc2 checked that */
|
||||||
} else /* (nsize < 2^30) */ {
|
memset(ntblp, 0, i * sizeof(struct tbl *));
|
||||||
/* table can get 80% full */
|
|
||||||
tp->nfree = (nsize * 4) / 5;
|
/* table can get 80% full except when reaching its limit */
|
||||||
}
|
tp->nfree = (tp->tshift == 30) ? 0x3FFF0000UL : ((i * 4) / 5);
|
||||||
tp->tbls = ntblp;
|
tp->tbls = ntblp;
|
||||||
if (otblp == NULL)
|
if (otblp == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* from here on nsize := mask */
|
mask = i - 1;
|
||||||
nsize--;
|
|
||||||
for (i = 0; i < osize; i++)
|
for (i = 0; i < osize; i++)
|
||||||
if ((tblp = otblp[i]) != NULL) {
|
if ((tblp = otblp[i]) != NULL) {
|
||||||
if ((tblp->flag & DEFINED)) {
|
if ((tblp->flag & DEFINED)) {
|
||||||
/* search for free hash table slot */
|
/* search for free hash table slot */
|
||||||
j = (perturb = tblp->ua.hval) & nsize;
|
j = (perturb = tblp->ua.hval) & mask;
|
||||||
goto find_first_empty_slot;
|
goto find_first_empty_slot;
|
||||||
find_next_empty_slot:
|
find_next_empty_slot:
|
||||||
j = (j << 2) + j + perturb + 1;
|
j = (j << 2) + j + perturb + 1;
|
||||||
perturb >>= PERTURB_SHIFT;
|
perturb >>= PERTURB_SHIFT;
|
||||||
find_first_empty_slot:
|
find_first_empty_slot:
|
||||||
pp = &ntblp[j & nsize];
|
pp = &ntblp[j & mask];
|
||||||
if (*pp != NULL)
|
if (*pp != NULL)
|
||||||
goto find_next_empty_slot;
|
goto find_next_empty_slot;
|
||||||
/* found an empty hash table slot */
|
/* found an empty hash table slot */
|
||||||
@ -1502,23 +1498,23 @@ texpand(struct table *tp, size_t nsize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ktinit(struct table *tp, Area *ap, size_t tsize)
|
ktinit(Area *ap, struct table *tp, uint8_t initshift)
|
||||||
{
|
{
|
||||||
tp->areap = ap;
|
tp->areap = ap;
|
||||||
tp->tbls = NULL;
|
tp->tbls = NULL;
|
||||||
tp->size = tp->nfree = 0;
|
tp->tshift = ((initshift > INIT_TBLSHIFT) ?
|
||||||
if (tsize)
|
initshift : INIT_TBLSHIFT) - 1;
|
||||||
texpand(tp, tsize);
|
tgrow(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* table, name (key) to search for, hash(name), rv pointer to tbl ptr */
|
/* table, name (key) to search for, hash(name), rv pointer to tbl ptr */
|
||||||
static struct tbl *
|
struct tbl *
|
||||||
ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp)
|
ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp)
|
||||||
{
|
{
|
||||||
size_t j, perturb, mask;
|
size_t j, perturb, mask;
|
||||||
struct tbl **pp, *p;
|
struct tbl **pp, *p;
|
||||||
|
|
||||||
mask = tp->size - 1;
|
mask = (1 << (tp->tshift)) - 1;
|
||||||
/* search for hash table slot matching name */
|
/* search for hash table slot matching name */
|
||||||
j = (perturb = h) & mask;
|
j = (perturb = h) & mask;
|
||||||
goto find_first_slot;
|
goto find_first_slot;
|
||||||
@ -1536,13 +1532,6 @@ ktscan(struct table *tp, const char *name, uint32_t h, struct tbl ***ppp)
|
|||||||
return (p);
|
return (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* table, name (key) to search for, hash(n) */
|
|
||||||
struct tbl *
|
|
||||||
ktsearch(struct table *tp, const char *n, uint32_t h)
|
|
||||||
{
|
|
||||||
return (tp->size ? ktscan(tp, n, h, NULL) : NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* table, name (key) to enter, hash(n) */
|
/* table, name (key) to enter, hash(n) */
|
||||||
struct tbl *
|
struct tbl *
|
||||||
ktenter(struct table *tp, const char *n, uint32_t h)
|
ktenter(struct table *tp, const char *n, uint32_t h)
|
||||||
@ -1550,15 +1539,13 @@ ktenter(struct table *tp, const char *n, uint32_t h)
|
|||||||
struct tbl **pp, *p;
|
struct tbl **pp, *p;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (tp->size == 0)
|
|
||||||
texpand(tp, INIT_TBLS);
|
|
||||||
Search:
|
Search:
|
||||||
if ((p = ktscan(tp, n, h, &pp)))
|
if ((p = ktscan(tp, n, h, &pp)))
|
||||||
return (p);
|
return (p);
|
||||||
|
|
||||||
if (tp->nfree == 0) {
|
if (tp->nfree == 0) {
|
||||||
/* too full */
|
/* too full */
|
||||||
texpand(tp, 2 * tp->size);
|
tgrow(tp);
|
||||||
goto Search;
|
goto Search;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1583,7 +1570,7 @@ ktenter(struct table *tp, const char *n, uint32_t h)
|
|||||||
void
|
void
|
||||||
ktwalk(struct tstate *ts, struct table *tp)
|
ktwalk(struct tstate *ts, struct table *tp)
|
||||||
{
|
{
|
||||||
ts->left = tp->size;
|
ts->left = 1 << (tp->tshift);
|
||||||
ts->next = tp->tbls;
|
ts->next = tp->tbls;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1613,16 +1600,19 @@ ktsort(struct table *tp)
|
|||||||
size_t i;
|
size_t i;
|
||||||
struct tbl **p, **sp, **dp;
|
struct tbl **p, **sp, **dp;
|
||||||
|
|
||||||
/* tp->size + 1 will not overflow */
|
/*
|
||||||
p = alloc2(tp->size + 1, sizeof(struct tbl *), ATEMP);
|
* since the table is never entirely full, no need to reserve
|
||||||
|
* additional space for the trailing NULL appended below
|
||||||
|
*/
|
||||||
|
i = 1 << (tp->tshift);
|
||||||
|
p = alloc2(i, sizeof(struct tbl *), ATEMP);
|
||||||
sp = tp->tbls; /* source */
|
sp = tp->tbls; /* source */
|
||||||
dp = p; /* dest */
|
dp = p; /* dest */
|
||||||
i = (size_t)tp->size;
|
|
||||||
while (i--)
|
while (i--)
|
||||||
if ((*dp = *sp++) != NULL && (((*dp)->flag & DEFINED) ||
|
if ((*dp = *sp++) != NULL && (((*dp)->flag & DEFINED) ||
|
||||||
((*dp)->flag & ARRAY)))
|
((*dp)->flag & ARRAY)))
|
||||||
dp++;
|
dp++;
|
||||||
qsort(p, (i = dp - p), sizeof(void *), tnamecmp);
|
qsort(p, (i = dp - p), sizeof(struct tbl *), tnamecmp);
|
||||||
p[i] = NULL;
|
p[i] = NULL;
|
||||||
return (p);
|
return (p);
|
||||||
}
|
}
|
||||||
|
16
sh.h
16
sh.h
@ -151,9 +151,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EXTERN
|
#ifdef EXTERN
|
||||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.473 2011/06/04 16:42:31 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.474 2011/06/05 19:58:19 tg Exp $");
|
||||||
#endif
|
#endif
|
||||||
#define MKSH_VERSION "R40 2011/06/04"
|
#define MKSH_VERSION "R40 2011/06/05"
|
||||||
|
|
||||||
#ifndef MKSH_INCLUDES_ONLY
|
#ifndef MKSH_INCLUDES_ONLY
|
||||||
|
|
||||||
@ -935,8 +935,8 @@ extern struct shf shf_iob[];
|
|||||||
struct table {
|
struct table {
|
||||||
Area *areap; /* area to allocate entries */
|
Area *areap; /* area to allocate entries */
|
||||||
struct tbl **tbls; /* hashed table items */
|
struct tbl **tbls; /* hashed table items */
|
||||||
uint32_t size; /* table size (always 2^n) */
|
|
||||||
uint32_t nfree; /* free table entries */
|
uint32_t nfree; /* free table entries */
|
||||||
|
uint8_t tshift; /* table size (2^tshift) */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tbl { /* table item */
|
struct tbl { /* table item */
|
||||||
@ -1682,8 +1682,10 @@ void coproc_write_close(int);
|
|||||||
int coproc_getfd(int, const char **);
|
int coproc_getfd(int, const char **);
|
||||||
void coproc_cleanup(int);
|
void coproc_cleanup(int);
|
||||||
struct temp *maketemp(Area *, Temp_type, struct temp **);
|
struct temp *maketemp(Area *, Temp_type, struct temp **);
|
||||||
void ktinit(struct table *, Area *, size_t);
|
void ktinit(Area *, struct table *, uint8_t);
|
||||||
struct tbl *ktsearch(struct table *, const char *, uint32_t);
|
struct tbl *ktscan(struct table *, const char *, uint32_t, struct tbl ***);
|
||||||
|
/* table, name (key) to search for, hash(n) */
|
||||||
|
#define ktsearch(tp, s, h) ktscan((tp), (s), (h), NULL)
|
||||||
struct tbl *ktenter(struct table *, const char *, uint32_t);
|
struct tbl *ktenter(struct table *, const char *, uint32_t);
|
||||||
#define ktdelete(p) do { p->flag = 0; } while (/* CONSTCOND */ 0)
|
#define ktdelete(p) do { p->flag = 0; } while (/* CONSTCOND */ 0)
|
||||||
void ktwalk(struct tstate *, struct table *);
|
void ktwalk(struct tstate *, struct table *);
|
||||||
@ -1783,8 +1785,8 @@ struct tbl *typeset(const char *, Tflag, Tflag, int, int)
|
|||||||
MKSH_A_NONNULL((__nonnull__ (1)));
|
MKSH_A_NONNULL((__nonnull__ (1)));
|
||||||
void unset(struct tbl *, int);
|
void unset(struct tbl *, int);
|
||||||
const char *skip_varname(const char *, int);
|
const char *skip_varname(const char *, int);
|
||||||
const char *skip_wdvarname(const char *, int);
|
const char *skip_wdvarname(const char *, bool);
|
||||||
int is_wdvarname(const char *, int);
|
int is_wdvarname(const char *, bool);
|
||||||
int is_wdvarassign(const char *);
|
int is_wdvarassign(const char *);
|
||||||
struct tbl *arraysearch(struct tbl *, uint32_t);
|
struct tbl *arraysearch(struct tbl *, uint32_t);
|
||||||
char **makenv(void);
|
char **makenv(void);
|
||||||
|
8
syn.c
8
syn.c
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.66 2011/06/04 16:11:20 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.67 2011/06/05 19:58:20 tg Exp $");
|
||||||
|
|
||||||
extern short subshell_nesting_level;
|
extern short subshell_nesting_level;
|
||||||
|
|
||||||
@ -794,9 +794,9 @@ initkeywords(void)
|
|||||||
struct tokeninfo const *tt;
|
struct tokeninfo const *tt;
|
||||||
struct tbl *p;
|
struct tbl *p;
|
||||||
|
|
||||||
ktinit(&keywords, APERM,
|
ktinit(APERM, &keywords,
|
||||||
/* must be 80% of 2^n (currently 28 keywords) */
|
/* currently 28 keywords -> 80% of 64 (2^6) */
|
||||||
64);
|
6);
|
||||||
for (tt = tokentab; tt->name; tt++) {
|
for (tt = tokentab; tt->name; tt++) {
|
||||||
if (tt->reserved) {
|
if (tt->reserved) {
|
||||||
p = ktenter(&keywords, tt->name, hash(tt->name));
|
p = ktenter(&keywords, tt->name, hash(tt->name));
|
||||||
|
155
var.c
155
var.c
@ -26,9 +26,9 @@
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.122 2011/05/29 02:18:57 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.123 2011/06/05 19:58:20 tg Exp $");
|
||||||
|
|
||||||
/*
|
/*-
|
||||||
* Variables
|
* Variables
|
||||||
*
|
*
|
||||||
* WARNING: unreadable code, needs a rewrite
|
* WARNING: unreadable code, needs a rewrite
|
||||||
@ -37,6 +37,7 @@ __RCSID("$MirOS: src/bin/mksh/var.c,v 1.122 2011/05/29 02:18:57 tg Exp $");
|
|||||||
* otherwise, (val.s + type) contains string value.
|
* otherwise, (val.s + type) contains string value.
|
||||||
* if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
|
* if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct tbl vtemp;
|
static struct tbl vtemp;
|
||||||
static struct table specials;
|
static struct table specials;
|
||||||
static uint32_t lcg_state = 5381;
|
static uint32_t lcg_state = 5381;
|
||||||
@ -66,7 +67,8 @@ newblock(void)
|
|||||||
|
|
||||||
l = alloc(sizeof(struct block), ATEMP);
|
l = alloc(sizeof(struct block), ATEMP);
|
||||||
l->flags = 0;
|
l->flags = 0;
|
||||||
ainit(&l->area); /* todo: could use e->area (l->area => l->areap) */
|
/* TODO: could use e->area (l->area => l->areap) */
|
||||||
|
ainit(&l->area);
|
||||||
if (!e->loc) {
|
if (!e->loc) {
|
||||||
l->argc = 0;
|
l->argc = 0;
|
||||||
l->argv = empty;
|
l->argv = empty;
|
||||||
@ -75,8 +77,8 @@ newblock(void)
|
|||||||
l->argv = e->loc->argv;
|
l->argv = e->loc->argv;
|
||||||
}
|
}
|
||||||
l->exit = l->error = NULL;
|
l->exit = l->error = NULL;
|
||||||
ktinit(&l->vars, &l->area, 0);
|
ktinit(&l->area, &l->vars, 0);
|
||||||
ktinit(&l->funs, &l->area, 0);
|
ktinit(&l->area, &l->funs, 0);
|
||||||
l->next = e->loc;
|
l->next = e->loc;
|
||||||
e->loc = l;
|
e->loc = l;
|
||||||
}
|
}
|
||||||
@ -87,12 +89,15 @@ newblock(void)
|
|||||||
void
|
void
|
||||||
popblock(void)
|
popblock(void)
|
||||||
{
|
{
|
||||||
|
ssize_t i;
|
||||||
struct block *l = e->loc;
|
struct block *l = e->loc;
|
||||||
struct tbl *vp, **vpp = l->vars.tbls, *vq;
|
struct tbl *vp, **vpp = l->vars.tbls, *vq;
|
||||||
int i;
|
|
||||||
|
|
||||||
e->loc = l->next; /* pop block */
|
/* pop block */
|
||||||
for (i = l->vars.size; --i >= 0; )
|
e->loc = l->next;
|
||||||
|
|
||||||
|
i = 1 << (l->vars.tshift);
|
||||||
|
while (--i >= 0)
|
||||||
if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) {
|
if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) {
|
||||||
if ((vq = global(vp->name))->flag & ISSET)
|
if ((vq = global(vp->name))->flag & ISSET)
|
||||||
setspec(vq);
|
setspec(vq);
|
||||||
@ -115,6 +120,7 @@ enum var_specs {
|
|||||||
V_MAX
|
V_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* this is biased with -1 relative to VARSPEC_ENUMS */
|
||||||
static const char * const initvar_names[] = {
|
static const char * const initvar_names[] = {
|
||||||
#define VARSPEC_ITEMS
|
#define VARSPEC_ITEMS
|
||||||
#include "var_spec.h"
|
#include "var_spec.h"
|
||||||
@ -126,8 +132,9 @@ initvar(void)
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
struct tbl *tp;
|
struct tbl *tp;
|
||||||
|
|
||||||
ktinit(&specials, APERM,
|
ktinit(APERM, &specials,
|
||||||
/* must be 80% of 2^n (currently 12 specials) */ 16);
|
/* currently 12 specials -> 80% of 16 (2^4) */
|
||||||
|
4);
|
||||||
while (i < V_MAX - 1) {
|
while (i < V_MAX - 1) {
|
||||||
tp = ktenter(&specials, initvar_names[i],
|
tp = ktenter(&specials, initvar_names[i],
|
||||||
hash(initvar_names[i]));
|
hash(initvar_names[i]));
|
||||||
@ -136,8 +143,9 @@ initvar(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used to calculate an array index for global()/local(). Sets *arrayp to
|
/*
|
||||||
* true if this is an array, sets *valp to the array index, returns
|
* Used to calculate an array index for global()/local(). Sets *arrayp
|
||||||
|
* to true if this is an array, sets *valp to the array index, returns
|
||||||
* the basename of the array.
|
* the basename of the array.
|
||||||
*/
|
*/
|
||||||
static const char *
|
static const char *
|
||||||
@ -179,7 +187,7 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp)
|
|||||||
char *sub, *tmp;
|
char *sub, *tmp;
|
||||||
mksh_ari_t rval;
|
mksh_ari_t rval;
|
||||||
|
|
||||||
/* Calculate the value of the subscript */
|
/* calculate the value of the subscript */
|
||||||
*arrayp = true;
|
*arrayp = true;
|
||||||
strndupx(tmp, p + 1, len - 2, ATEMP);
|
strndupx(tmp, p + 1, len - 2, ATEMP);
|
||||||
sub = substitute(tmp, 0);
|
sub = substitute(tmp, 0);
|
||||||
@ -234,7 +242,7 @@ global(const char *n)
|
|||||||
vp->val.i = kshpid;
|
vp->val.i = kshpid;
|
||||||
break;
|
break;
|
||||||
case '!':
|
case '!':
|
||||||
/* If no job, expand to nothing */
|
/* if no job, expand to nothing */
|
||||||
if ((vp->val.i = j_async()) == 0)
|
if ((vp->val.i = j_async()) == 0)
|
||||||
vp->flag &= ~(ISSET|INTEGER);
|
vp->flag &= ~(ISSET|INTEGER);
|
||||||
break;
|
break;
|
||||||
@ -284,7 +292,7 @@ local(const char *n, bool copy)
|
|||||||
bool array;
|
bool array;
|
||||||
uint32_t h, val;
|
uint32_t h, val;
|
||||||
|
|
||||||
/* Check to see if this is an array */
|
/* check to see if this is an array */
|
||||||
n = array_index_calc(n, &array, &val);
|
n = array_index_calc(n, &array, &val);
|
||||||
h = hash(n);
|
h = hash(n);
|
||||||
if (!ksh_isalphx(*n)) {
|
if (!ksh_isalphx(*n)) {
|
||||||
@ -327,18 +335,23 @@ str_val(struct tbl *vp)
|
|||||||
if ((vp->flag&SPECIAL))
|
if ((vp->flag&SPECIAL))
|
||||||
getspec(vp);
|
getspec(vp);
|
||||||
if (!(vp->flag&ISSET))
|
if (!(vp->flag&ISSET))
|
||||||
s = null; /* special to dollar() */
|
/* special to dollar() */
|
||||||
else if (!(vp->flag&INTEGER)) /* string source */
|
s = null;
|
||||||
|
else if (!(vp->flag&INTEGER))
|
||||||
|
/* string source */
|
||||||
s = vp->val.s + vp->type;
|
s = vp->val.s + vp->type;
|
||||||
else { /* integer source */
|
else {
|
||||||
/* worst case number length is when base=2 */
|
/* integer source */
|
||||||
/* 1 (minus) + 2 (base, up to 36) + 1 ('#') + number of bits
|
mksh_uari_t n;
|
||||||
* in the mksh_uari_t + 1 (NUL) */
|
int base;
|
||||||
|
/**
|
||||||
|
* worst case number length is when base == 2:
|
||||||
|
* 1 (minus) + 2 (base, up to 36) + 1 ('#') +
|
||||||
|
* number of bits in the mksh_uari_t + 1 (NUL)
|
||||||
|
*/
|
||||||
char strbuf[1 + 2 + 1 + 8 * sizeof(mksh_uari_t) + 1];
|
char strbuf[1 + 2 + 1 + 8 * sizeof(mksh_uari_t) + 1];
|
||||||
const char *digits = (vp->flag & UCASEV_AL) ?
|
const char *digits = (vp->flag & UCASEV_AL) ?
|
||||||
digits_uc : digits_lc;
|
digits_uc : digits_lc;
|
||||||
mksh_uari_t n;
|
|
||||||
int base;
|
|
||||||
|
|
||||||
s = strbuf + sizeof(strbuf);
|
s = strbuf + sizeof(strbuf);
|
||||||
if (vp->flag & INT_U)
|
if (vp->flag & INT_U)
|
||||||
@ -375,7 +388,8 @@ str_val(struct tbl *vp)
|
|||||||
if (!(vp->flag & INT_U) && vp->val.i < 0)
|
if (!(vp->flag & INT_U) && vp->val.i < 0)
|
||||||
*--s = '-';
|
*--s = '-';
|
||||||
}
|
}
|
||||||
if (vp->flag & (RJUST|LJUST)) /* case already dealt with */
|
if (vp->flag & (RJUST|LJUST))
|
||||||
|
/* case already dealt with */
|
||||||
s = formatstr(vp, s);
|
s = formatstr(vp, s);
|
||||||
else
|
else
|
||||||
strdupx(s, s, ATEMP);
|
strdupx(s, s, ATEMP);
|
||||||
@ -411,7 +425,8 @@ setstr(struct tbl *vq, const char *s, int error_ok)
|
|||||||
errorfxz(2);
|
errorfxz(2);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (!(vq->flag&INTEGER)) { /* string dest */
|
if (!(vq->flag&INTEGER)) {
|
||||||
|
/* string dest */
|
||||||
if ((vq->flag&ALLOC)) {
|
if ((vq->flag&ALLOC)) {
|
||||||
/* debugging */
|
/* debugging */
|
||||||
if (s >= vq->val.s &&
|
if (s >= vq->val.s &&
|
||||||
@ -431,7 +446,8 @@ setstr(struct tbl *vq, const char *s, int error_ok)
|
|||||||
strdupx(vq->val.s, s, vq->areap);
|
strdupx(vq->val.s, s, vq->areap);
|
||||||
vq->flag |= ALLOC;
|
vq->flag |= ALLOC;
|
||||||
}
|
}
|
||||||
} else { /* integer dest */
|
} else {
|
||||||
|
/* integer dest */
|
||||||
if (!v_evaluate(vq, s, error_ok, true))
|
if (!v_evaluate(vq, s, error_ok, true))
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -539,7 +555,8 @@ getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
|
|||||||
return (base);
|
return (base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert variable vq to integer variable, setting its value from vp
|
/*
|
||||||
|
* convert variable vq to integer variable, setting its value from vp
|
||||||
* (vq and vp may be the same)
|
* (vq and vp may be the same)
|
||||||
*/
|
*/
|
||||||
struct tbl *
|
struct tbl *
|
||||||
@ -575,7 +592,8 @@ formatstr(struct tbl *vp, const char *s)
|
|||||||
olen = utf_mbswidth(s);
|
olen = utf_mbswidth(s);
|
||||||
|
|
||||||
if (vp->flag & (RJUST|LJUST)) {
|
if (vp->flag & (RJUST|LJUST)) {
|
||||||
if (!vp->u2.field) /* default field width */
|
if (!vp->u2.field)
|
||||||
|
/* default field width */
|
||||||
vp->u2.field = olen;
|
vp->u2.field = olen;
|
||||||
nlen = vp->u2.field;
|
nlen = vp->u2.field;
|
||||||
} else
|
} else
|
||||||
@ -660,16 +678,17 @@ exportprep(struct tbl *vp, const char *val)
|
|||||||
memcpy(vp->val.s = xp, vp->name, namelen);
|
memcpy(vp->val.s = xp, vp->name, namelen);
|
||||||
xp += namelen;
|
xp += namelen;
|
||||||
*xp++ = '=';
|
*xp++ = '=';
|
||||||
vp->type = xp - vp->val.s; /* offset to value */
|
/* offset to value */
|
||||||
|
vp->type = xp - vp->val.s;
|
||||||
memcpy(xp, val, vallen);
|
memcpy(xp, val, vallen);
|
||||||
if (op != NULL)
|
if (op != NULL)
|
||||||
afree(op, vp->areap);
|
afree(op, vp->areap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* lookup variable (according to (set&LOCAL)),
|
* lookup variable (according to (set&LOCAL)), set its attributes
|
||||||
* set its attributes (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL,
|
* (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL, LCASEV,
|
||||||
* LCASEV, UCASEV_AL), and optionally set its value if an assignment.
|
* UCASEV_AL), and optionally set its value if an assignment.
|
||||||
*/
|
*/
|
||||||
struct tbl *
|
struct tbl *
|
||||||
typeset(const char *var, Tflag set, Tflag clr, int field, int base)
|
typeset(const char *var, Tflag set, Tflag clr, int field, int base)
|
||||||
@ -694,11 +713,12 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
|
|||||||
len = array_ref_len(val);
|
len = array_ref_len(val);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
/* IMPORT is only used when the shell starts up and is
|
/*
|
||||||
|
* IMPORT is only used when the shell starts up and is
|
||||||
* setting up its environment. Allow only simple array
|
* setting up its environment. Allow only simple array
|
||||||
* references at this time since parameter/command substitution
|
* references at this time since parameter/command
|
||||||
* is preformed on the [expression] which would be a major
|
* substitution is preformed on the [expression] which
|
||||||
* security hole.
|
* would be a major security hole.
|
||||||
*/
|
*/
|
||||||
if (set & IMPORT) {
|
if (set & IMPORT) {
|
||||||
int i;
|
int i;
|
||||||
@ -715,7 +735,7 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
|
|||||||
vappend = true;
|
vappend = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Importing from original environment: must have an = */
|
/* importing from original environment: must have an = */
|
||||||
if (set & IMPORT)
|
if (set & IMPORT)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
strdupx(tvar, var, ATEMP);
|
strdupx(tvar, var, ATEMP);
|
||||||
@ -727,7 +747,7 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
|
|||||||
tvar[len-3] = '\0';
|
tvar[len-3] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prevent typeset from creating a local PATH/ENV/SHELL */
|
/* prevent typeset from creating a local PATH/ENV/SHELL */
|
||||||
if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 ||
|
if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 ||
|
||||||
strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0))
|
strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0))
|
||||||
errorf("%s: %s", tvar, "restricted");
|
errorf("%s: %s", tvar, "restricted");
|
||||||
@ -740,7 +760,7 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
|
|||||||
if (vp->flag & ARRAY) {
|
if (vp->flag & ARRAY) {
|
||||||
struct tbl *a, *tmp;
|
struct tbl *a, *tmp;
|
||||||
|
|
||||||
/* Free up entire array */
|
/* free up entire array */
|
||||||
for (a = vp->u.array; a; ) {
|
for (a = vp->u.array; a; ) {
|
||||||
tmp = a;
|
tmp = a;
|
||||||
a = a->u.array;
|
a = a->u.array;
|
||||||
@ -773,8 +793,9 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
|
|||||||
if (set | clr) {
|
if (set | clr) {
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
/* XXX if x[0] isn't set, there will be problems: need to have
|
/*
|
||||||
* one copy of attributes for arrays...
|
* XXX if x[0] isn't set, there will be problems: need
|
||||||
|
* to have one copy of attributes for arrays...
|
||||||
*/
|
*/
|
||||||
for (t = vpbase; t; t = t->u.array) {
|
for (t = vpbase; t; t = t->u.array) {
|
||||||
bool fake_assign;
|
bool fake_assign;
|
||||||
@ -847,7 +868,7 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
|
|||||||
if (vp->flag&INTEGER) {
|
if (vp->flag&INTEGER) {
|
||||||
/* do not zero base before assignment */
|
/* do not zero base before assignment */
|
||||||
setstr(vp, val, KSH_UNWIND_ERROR | 0x4);
|
setstr(vp, val, KSH_UNWIND_ERROR | 0x4);
|
||||||
/* Done after assignment to override default */
|
/* done after assignment to override default */
|
||||||
if (base > 0)
|
if (base > 0)
|
||||||
vp->type = base;
|
vp->type = base;
|
||||||
} else
|
} else
|
||||||
@ -879,7 +900,7 @@ unset(struct tbl *vp, int flags)
|
|||||||
if ((vp->flag & ARRAY) && (flags & 1)) {
|
if ((vp->flag & ARRAY) && (flags & 1)) {
|
||||||
struct tbl *a, *tmp;
|
struct tbl *a, *tmp;
|
||||||
|
|
||||||
/* Free up entire array */
|
/* free up entire array */
|
||||||
for (a = vp->u.array; a; ) {
|
for (a = vp->u.array; a; ) {
|
||||||
tmp = a;
|
tmp = a;
|
||||||
a = a->u.array;
|
a = a->u.array;
|
||||||
@ -893,15 +914,17 @@ unset(struct tbl *vp, int flags)
|
|||||||
vp->flag &= ~(ALLOC|ISSET);
|
vp->flag &= ~(ALLOC|ISSET);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* If foo[0] is being unset, the remainder of the array is kept... */
|
/* if foo[0] is being unset, the remainder of the array is kept... */
|
||||||
vp->flag &= SPECIAL | ((flags & 1) ? 0 : ARRAY|DEFINED);
|
vp->flag &= SPECIAL | ((flags & 1) ? 0 : ARRAY|DEFINED);
|
||||||
if (vp->flag & SPECIAL)
|
if (vp->flag & SPECIAL)
|
||||||
unsetspec(vp); /* responsible for 'unspecial'ing var */
|
/* responsible for 'unspecial'ing var */
|
||||||
|
unsetspec(vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return a pointer to the first char past a legal variable name (returns the
|
/*
|
||||||
* argument if there is no legal name, returns a pointer to the terminating
|
* Return a pointer to the first char past a legal variable name
|
||||||
* NUL if whole string is legal).
|
* (returns the argument if there is no legal name, returns a pointer to
|
||||||
|
* the terminating NUL if whole string is legal).
|
||||||
*/
|
*/
|
||||||
const char *
|
const char *
|
||||||
skip_varname(const char *s, int aok)
|
skip_varname(const char *s, int aok)
|
||||||
@ -920,7 +943,8 @@ skip_varname(const char *s, int aok)
|
|||||||
/* Return a pointer to the first character past any legal variable name */
|
/* Return a pointer to the first character past any legal variable name */
|
||||||
const char *
|
const char *
|
||||||
skip_wdvarname(const char *s,
|
skip_wdvarname(const char *s,
|
||||||
int aok) /* skip array de-reference? */
|
/* skip array de-reference? */
|
||||||
|
bool aok)
|
||||||
{
|
{
|
||||||
if (s[0] == CHAR && ksh_isalphx(s[1])) {
|
if (s[0] == CHAR && ksh_isalphx(s[1])) {
|
||||||
do {
|
do {
|
||||||
@ -951,7 +975,7 @@ skip_wdvarname(const char *s,
|
|||||||
|
|
||||||
/* Check if coded string s is a variable name */
|
/* Check if coded string s is a variable name */
|
||||||
int
|
int
|
||||||
is_wdvarname(const char *s, int aok)
|
is_wdvarname(const char *s, bool aok)
|
||||||
{
|
{
|
||||||
const char *p = skip_wdvarname(s, aok);
|
const char *p = skip_wdvarname(s, aok);
|
||||||
|
|
||||||
@ -974,14 +998,16 @@ is_wdvarassign(const char *s)
|
|||||||
char **
|
char **
|
||||||
makenv(void)
|
makenv(void)
|
||||||
{
|
{
|
||||||
|
ssize_t i;
|
||||||
struct block *l;
|
struct block *l;
|
||||||
XPtrV denv;
|
XPtrV denv;
|
||||||
struct tbl *vp, **vpp;
|
struct tbl *vp, **vpp;
|
||||||
int i;
|
|
||||||
|
|
||||||
XPinit(denv, 64);
|
XPinit(denv, 64);
|
||||||
for (l = e->loc; l != NULL; l = l->next)
|
for (l = e->loc; l != NULL; l = l->next) {
|
||||||
for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
|
vpp = l->vars.tbls;
|
||||||
|
i = 1 << (l->vars.tshift);
|
||||||
|
while (--i >= 0)
|
||||||
if ((vp = *vpp++) != NULL &&
|
if ((vp = *vpp++) != NULL &&
|
||||||
(vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
|
(vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
|
||||||
struct block *l2;
|
struct block *l2;
|
||||||
@ -1004,6 +1030,7 @@ makenv(void)
|
|||||||
}
|
}
|
||||||
XPput(denv, vp->val.s);
|
XPput(denv, vp->val.s);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
XPput(denv, NULL);
|
XPput(denv, NULL);
|
||||||
return ((char **)XPclose(denv));
|
return ((char **)XPclose(denv));
|
||||||
}
|
}
|
||||||
@ -1119,8 +1146,9 @@ setspec(struct tbl *vp)
|
|||||||
afree(tmpdir, APERM);
|
afree(tmpdir, APERM);
|
||||||
tmpdir = NULL;
|
tmpdir = NULL;
|
||||||
}
|
}
|
||||||
/* Use tmpdir iff it is an absolute path, is writable and
|
/*
|
||||||
* searchable and is a directory...
|
* Use tmpdir iff it is an absolute path, is writable
|
||||||
|
* and searchable and is a directory...
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
struct stat statb;
|
struct stat statb;
|
||||||
@ -1223,7 +1251,8 @@ unsetspec(struct tbl *vp)
|
|||||||
case V_LINENO:
|
case V_LINENO:
|
||||||
case V_RANDOM:
|
case V_RANDOM:
|
||||||
case V_SECONDS:
|
case V_SECONDS:
|
||||||
case V_TMOUT: /* AT&T ksh leaves previous value in place */
|
case V_TMOUT:
|
||||||
|
/* AT&T ksh leaves previous value in place */
|
||||||
unspecial(vp->name);
|
unspecial(vp->name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1248,7 +1277,7 @@ arraysearch(struct tbl *vp, uint32_t val)
|
|||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
vp->flag = (vp->flag | (ARRAY|DEFINED)) & ~ASSOC;
|
vp->flag = (vp->flag | (ARRAY|DEFINED)) & ~ASSOC;
|
||||||
/* The table entry is always [0] */
|
/* the table entry is always [0] */
|
||||||
if (val == 0)
|
if (val == 0)
|
||||||
return (vp);
|
return (vp);
|
||||||
prev = vp;
|
prev = vp;
|
||||||
@ -1275,16 +1304,18 @@ arraysearch(struct tbl *vp, uint32_t val)
|
|||||||
news->u2.field = vp->u2.field;
|
news->u2.field = vp->u2.field;
|
||||||
news->ua.index = val;
|
news->ua.index = val;
|
||||||
|
|
||||||
if (curr != news) { /* not reusing old array entry */
|
if (curr != news) {
|
||||||
|
/* not reusing old array entry */
|
||||||
prev->u.array = news;
|
prev->u.array = news;
|
||||||
news->u.array = curr;
|
news->u.array = curr;
|
||||||
}
|
}
|
||||||
return (news);
|
return (news);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the length of an array reference (eg, [1+2]) - cp is assumed
|
/*
|
||||||
* to point to the open bracket. Returns 0 if there is no matching closing
|
* Return the length of an array reference (eg, [1+2]) - cp is assumed
|
||||||
* bracket.
|
* to point to the open bracket. Returns 0 if there is no matching
|
||||||
|
* closing bracket.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
array_ref_len(const char *cp)
|
array_ref_len(const char *cp)
|
||||||
@ -1352,7 +1383,7 @@ set_array(const char *var, bool reset, const char **vals)
|
|||||||
/* trash existing values and attributes */
|
/* trash existing values and attributes */
|
||||||
unset(vp, 1);
|
unset(vp, 1);
|
||||||
/*
|
/*
|
||||||
* todo: would be nice for assignment to completely succeed or
|
* TODO: would be nice for assignment to completely succeed or
|
||||||
* completely fail. Only really effects integer arrays:
|
* completely fail. Only really effects integer arrays:
|
||||||
* evaluation of some of vals[] may fail...
|
* evaluation of some of vals[] may fail...
|
||||||
*/
|
*/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#if defined(VARSPEC_DEFNS)
|
#if defined(VARSPEC_DEFNS)
|
||||||
__RCSID("$MirOS: src/bin/mksh/var_spec.h,v 1.1 2009/09/26 03:40:03 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/var_spec.h,v 1.2 2011/06/05 19:58:21 tg Exp $");
|
||||||
#define FN(name) /* nothing */
|
#define FN(name) /* nothing */
|
||||||
#elif defined(VARSPEC_ENUMS)
|
#elif defined(VARSPEC_ENUMS)
|
||||||
#define FN(name) V_##name,
|
#define FN(name) V_##name,
|
||||||
@ -13,6 +13,8 @@ __RCSID("$MirOS: src/bin/mksh/var_spec.h,v 1.1 2009/09/26 03:40:03 tg Exp $");
|
|||||||
#define F0 FN
|
#define F0 FN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* NOTE: F0 are skipped for the ITEMS array, only FN generate names */
|
||||||
|
|
||||||
/* 0 is always V_NONE */
|
/* 0 is always V_NONE */
|
||||||
F0(NONE)
|
F0(NONE)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user