/* * add builtin */ const char * builtin(const char *name, int (*func) (const char **)) { struct tbl *tp; uint32_t flag; /* see if any flags should be set for this builtin */ for (flag = 0; ; name++) { if (*name == '=') /* command does variable assignment */ flag |= KEEPASN; else if (*name == '*') /* POSIX special builtin */ flag |= SPEC_BI; else if (*name == '+') /* POSIX regular builtin */ flag |= REG_BI; else break; } tp = ktenter(&builtins, name, hash(name)); tp->flag = DEFINED | flag; tp->type = CSHELL; tp->val.f = func; return (name); }
void initvar(void) { int i = 0; struct tbl *tp; ktinit(APERM, &specials, /* currently 14 specials: 75% of 32 = 2^5 */ 5); while (i < V_MAX - 1) { tp = ktenter(&specials, initvar_names[i], hash(initvar_names[i])); tp->flag = DEFINED|ISSET; tp->type = ++i; } }
/* * Search for local variable, if not found create locally. */ struct tbl * local(const char *n, bool copy) { struct tbl *vp; union mksh_cchack vname; struct block *l = e->loc; bool array; uint32_t h, val; /* * check to see if this is an array; * dereference namerefs; must come first */ vn = array_index_calc(n, &array, &val); h = hash(vn); if (!ctype(*vn, C_ALPHX)) { vp = vtemp; vp->flag = DEFINED|RDONLY; vp->type = 0; vp->areap = ATEMP; goto out; } vp = ktenter(&l->vars, vn, h); if (copy && !(vp->flag & DEFINED)) { struct tbl *vq; varsearch(l->next, &vq, vn, h); if (vq != NULL) { vp->flag |= vq->flag & (EXPORT | INTEGER | RDONLY | LJUST | RJUST | ZEROFIL | LCASEV | UCASEV_AL | INT_U | INT_L); if (vq->flag & INTEGER) vp->type = vq->type; vp->u2.field = vq->u2.field; } } if (array) vp = arraysearch(vp, val); vp->flag |= DEFINED; if (special(vn)) vp->flag |= SPECIAL; out: last_lookup_was_array = array; if (vn != n) afree(vname.rw, ATEMP); return (vp); }
/* * Search for local variable, if not found create locally. */ struct tbl * local(const char *n, bool copy) { struct block *l = e->loc; struct tbl *vp; unsigned int h; bool array; int val; /* Check to see if this is an array */ n = array_index_calc(n, &array, &val); h = hash(n); if (!letter(*n)) { vp = &vtemp; vp->flag = DEFINED|RDONLY; vp->type = 0; vp->areap = ATEMP; return vp; } vp = ktenter(&l->vars, n, h); if (copy && !(vp->flag & DEFINED)) { struct block *ll = l; struct tbl *vq = (struct tbl *) 0; while ((ll = ll->next) && !(vq = ktsearch(&ll->vars, n, h))) ; if (vq) { vp->flag |= vq->flag & (EXPORT | INTEGER | RDONLY | LJUST | RJUST | ZEROFIL | LCASEV | UCASEV_AL | INT_U | INT_L); if (vq->flag & INTEGER) vp->type = vq->type; vp->u2.field = vq->u2.field; } } if (array) vp = arraysearch(vp, val); vp->flag |= DEFINED; if (special(n)) vp->flag |= SPECIAL; return vp; }
/* * Search for local variable, if not found create locally. */ struct tbl * local(const char *n, bool copy) { struct block *l = e->loc; struct tbl *vp; bool array; uint32_t h, val; /* * check to see if this is an array; * dereference namerefs; must come first */ n = array_index_calc(n, &array, &val); h = hash(n); if (!ksh_isalphx(*n)) { vp = &vtemp; vp->flag = DEFINED|RDONLY; vp->type = 0; vp->areap = ATEMP; return (vp); } vp = ktenter(&l->vars, n, h); if (copy && !(vp->flag & DEFINED)) { struct tbl *vq; varsearch(l->next, &vq, n, h); if (vq != NULL) { vp->flag |= vq->flag & (EXPORT | INTEGER | RDONLY | LJUST | RJUST | ZEROFIL | LCASEV | UCASEV_AL | INT_U | INT_L); if (vq->flag & INTEGER) vp->type = vq->type; vp->u2.field = vq->u2.field; } } if (array) vp = arraysearch(vp, val); vp->flag |= DEFINED; if (special(n)) vp->flag |= SPECIAL; return (vp); }
/* * Search function tables for a function. If create set, a table entry * is created if none is found. */ struct tbl * findfunc(const char *name, uint32_t h, bool create) { struct block *l; struct tbl *tp = NULL; for (l = e->loc; l; l = l->next) { tp = ktsearch(&l->funs, name, h); if (tp) break; if (!l->next && create) { tp = ktenter(&l->funs, name, h); tp->flag = DEFINED; tp->type = CFUNC; tp->val.t = NULL; break; } } return (tp); }
/* called by main() to initialize variable data structures */ void initvar(void) { static const struct { const char *name; int v; } names[] = { { "COLUMNS", V_COLUMNS }, { "IFS", V_IFS }, { "OPTIND", V_OPTIND }, { "PATH", V_PATH }, { "POSIXLY_CORRECT", V_POSIXLY_CORRECT }, { "TMPDIR", V_TMPDIR }, #ifdef HISTORY { "HISTFILE", V_HISTFILE }, { "HISTSIZE", V_HISTSIZE }, #endif /* HISTORY */ #ifdef EDIT { "EDITOR", V_EDITOR }, { "VISUAL", V_VISUAL }, #endif /* EDIT */ { "MAIL", V_MAIL }, { "MAILCHECK", V_MAILCHECK }, { "MAILPATH", V_MAILPATH }, { "RANDOM", V_RANDOM }, { "SECONDS", V_SECONDS }, { "TMOUT", V_TMOUT }, { "LINENO", V_LINENO }, { (char *) 0, 0 } }; int i; struct tbl *tp; ktinit(&specials, APERM, 32); /* must be 2^n (currently 17 specials) */ for (i = 0; names[i].name; i++) { tp = ktenter(&specials, names[i].name, hash(names[i].name)); tp->flag = DEFINED|ISSET; tp->type = names[i].v; } }
/* * find command * either function, hashed command, or built-in (in that order) */ struct tbl * findcom(const char *name, int flags) { static struct tbl temp; uint32_t h = hash(name); struct tbl *tp = NULL, *tbi; /* insert if not found */ unsigned char insert = Flag(FTRACKALL); /* for function autoloading */ char *fpath; union mksh_cchack npath; if (vstrchr(name, '/')) { insert = 0; /* prevent FPATH search below */ flags &= ~FC_FUNC; goto Search; } tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL; /* * POSIX says special builtins first, then functions, then * POSIX regular builtins, then search path... */ if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI)) tp = tbi; if (!tp && (flags & FC_FUNC)) { tp = findfunc(name, h, false); if (tp && !(tp->flag & ISSET)) { if ((fpath = str_val(global("FPATH"))) == null) { tp->u.fpath = NULL; tp->u2.errnov = ENOENT; } else tp->u.fpath = search_path(name, fpath, R_OK, &tp->u2.errnov); } } if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI)) tp = tbi; if (!tp && (flags & FC_UNREGBI) && tbi) tp = tbi; if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) { tp = ktsearch(&taliases, name, h); if (tp && (tp->flag & ISSET) && ksh_access(tp->val.s, X_OK) != 0) { if (tp->flag & ALLOC) { tp->flag &= ~ALLOC; afree(tp->val.s, APERM); } tp->flag &= ~ISSET; } } Search: if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) && (flags & FC_PATH)) { if (!tp) { if (insert && !(flags & FC_DEFPATH)) { tp = ktenter(&taliases, name, h); tp->type = CTALIAS; } else { tp = &temp; tp->type = CEXEC; } /* make ~ISSET */ tp->flag = DEFINED; } npath.ro = search_path(name, (flags & FC_DEFPATH) ? def_path : path, X_OK, &tp->u2.errnov); if (npath.ro) { strdupx(tp->val.s, npath.ro, APERM); if (npath.ro != name) afree(npath.rw, ATEMP); tp->flag |= ISSET|ALLOC; } else if ((flags & FC_FUNC) && (fpath = str_val(global("FPATH"))) != null && (npath.ro = search_path(name, fpath, R_OK, &tp->u2.errnov)) != NULL) { /* * An undocumented feature of AT&T ksh is that * it searches FPATH if a command is not found, * even if the command hasn't been set up as an * autoloaded function (ie, no typeset -uf). */ tp = &temp; tp->type = CFUNC; /* make ~ISSET */ tp->flag = DEFINED; tp->u.fpath = npath.ro; } } return (tp); }
/* * Search for variable, if not found create globally. */ struct tbl * global(const char *n) { struct block *l = e->loc; struct tbl *vp; int c; unsigned int h; bool array; int val; /* Check to see if this is an array */ n = array_index_calc(n, &array, &val); h = hash(n); c = n[0]; if (!letter(c)) { if (array) errorf("bad substitution"); vp = &vtemp; vp->flag = DEFINED; vp->type = 0; vp->areap = ATEMP; *vp->name = c; if (digit(c)) { for (c = 0; digit(*n); n++) c = c*10 + *n-'0'; if (c <= l->argc) /* setstr can't fail here */ setstr(vp, l->argv[c], KSH_RETURN_ERROR); vp->flag |= RDONLY; return vp; } vp->flag |= RDONLY; if (n[1] != '\0') return vp; vp->flag |= ISSET|INTEGER; switch (c) { case '$': vp->val.i = kshpid; break; case '!': /* If no job, expand to nothing */ if ((vp->val.i = j_async()) == 0) vp->flag &= ~(ISSET|INTEGER); break; case '?': vp->val.i = exstat; break; case '#': vp->val.i = l->argc; break; case '-': vp->flag &= ~INTEGER; vp->val.s = getoptions(); break; default: vp->flag &= ~(ISSET|INTEGER); } return vp; } for (l = e->loc; ; l = l->next) { vp = ktsearch(&l->vars, n, h); if (vp != NULL) { if (array) return arraysearch(vp, val); else return vp; } if (l->next == NULL) break; } vp = ktenter(&l->vars, n, h); if (array) vp = arraysearch(vp, val); vp->flag |= DEFINED; if (special(n)) vp->flag |= SPECIAL; return vp; }
/* * Search for variable, if not found create globally. */ struct tbl * global(const char *n) { struct block *l = e->loc; struct tbl *vp; int c; bool array; uint32_t h, val; /* * check to see if this is an array; * dereference namerefs; must come first */ n = array_index_calc(n, &array, &val); h = hash(n); c = (unsigned char)n[0]; if (!ksh_isalphx(c)) { if (array) errorf("bad substitution"); vp = &vtemp; vp->flag = DEFINED; vp->type = 0; vp->areap = ATEMP; *vp->name = c; if (ksh_isdigit(c)) { if (getn(n, &c) && (c <= l->argc)) /* setstr can't fail here */ setstr(vp, l->argv[c], KSH_RETURN_ERROR); vp->flag |= RDONLY; return (vp); } vp->flag |= RDONLY; if (n[1] != '\0') return (vp); vp->flag |= ISSET|INTEGER; switch (c) { case '$': vp->val.i = kshpid; break; case '!': /* if no job, expand to nothing */ if ((vp->val.i = j_async()) == 0) vp->flag &= ~(ISSET|INTEGER); break; case '?': vp->val.i = exstat & 0xFF; break; case '#': vp->val.i = l->argc; break; case '-': vp->flag &= ~INTEGER; vp->val.s = getoptions(); break; default: vp->flag &= ~(ISSET|INTEGER); } return (vp); } l = varsearch(e->loc, &vp, n, h); if (vp != NULL) return (array ? arraysearch(vp, val) : vp); vp = ktenter(&l->vars, n, h); if (array) vp = arraysearch(vp, val); vp->flag |= DEFINED; if (special(n)) vp->flag |= SPECIAL; return (vp); }
/* search for variable; if not found, return NULL or create globally */ struct tbl * isglobal(const char *n, bool docreate) { struct tbl *vp; union mksh_cchack vname; struct block *l = e->loc; int c; bool array; uint32_t h, val; /* * check to see if this is an array; * dereference namerefs; must come first */ vn = array_index_calc(n, &array, &val); h = hash(vn); c = (unsigned char)vn[0]; if (!ctype(c, C_ALPHX)) { if (array) errorf(Tbadsubst); vp = vtemp; vp->flag = DEFINED; vp->type = 0; vp->areap = ATEMP; if (ctype(c, C_DIGIT)) { if (getn(vn, &c)) { /* main.c:main_init() says 12 */ shf_snprintf(vp->name, 12, Tf_d, c); if (c <= l->argc) { /* setstr can't fail here */ setstr(vp, l->argv[c], KSH_RETURN_ERROR); } } else vp->name[0] = '\0'; vp->flag |= RDONLY; goto out; } vp->name[0] = c; vp->name[1] = '\0'; vp->flag |= RDONLY; if (vn[1] != '\0') goto out; vp->flag |= ISSET|INTEGER; switch (c) { case '$': vp->val.i = kshpid; break; case '!': /* if no job, expand to nothing */ if ((vp->val.i = j_async()) == 0) vp->flag &= ~(ISSET|INTEGER); break; case '?': vp->val.i = exstat & 0xFF; break; case '#': vp->val.i = l->argc; break; case '-': vp->flag &= ~INTEGER; vp->val.s = getoptions(); break; default: vp->flag &= ~(ISSET|INTEGER); } goto out; } l = varsearch(e->loc, &vp, vn, h); if (vp == NULL && docreate) vp = ktenter(&l->vars, vn, h); else docreate = false; if (vp != NULL) { if (array) vp = arraysearch(vp, val); if (docreate) { vp->flag |= DEFINED; if (special(vn)) vp->flag |= SPECIAL; } } out: last_lookup_was_array = array; if (vn != n) afree(vname.rw, ATEMP); return (vp); }