Skip to content

Commit

Permalink
Refactor b_unset(), b_unalias, and unall()
Browse files Browse the repository at this point in the history
With this change all special builtins are now in their own source
module. More importantly this eliminates a lot of cleverness that
obfuscates the actual behavior.
  • Loading branch information
krader1961 committed Aug 30, 2019
1 parent 9ba9355 commit d5277d3
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 120 deletions.
4 changes: 3 additions & 1 deletion src/cmd/ksh93/bltins/bg.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
//
// Builtin `bg` command.
//
int b_bg(int n, char *argv[], Shbltin_t *context) {
int b_bg(int argc, char *argv[], Shbltin_t *context) {
UNUSED(argc);
Shell_t *shp = context->shp;
int n;

while ((n = optget(argv, sh_optbg))) {
switch (n) { //!OCLINT(MissingDefaultStatement)
Expand Down
4 changes: 3 additions & 1 deletion src/cmd/ksh93/bltins/fg.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
//
// Builtin `fg` command.
//
int b_fg(int n, char *argv[], Shbltin_t *context) {
int b_fg(int argc, char *argv[], Shbltin_t *context) {
UNUSED(argc);
Shell_t *shp = context->shp;
int n;

while ((n = optget(argv, sh_optfg))) {
switch (n) { //!OCLINT(MissingDefaultStatement)
Expand Down
4 changes: 3 additions & 1 deletion src/cmd/ksh93/bltins/jobs.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
//
// Builtin `jobs`.
//
int b_jobs(int n, char *argv[], Shbltin_t *context) {
int b_jobs(int argc, char *argv[], Shbltin_t *context) {
UNUSED(argc);
int n;
int flag = 0;
Shell_t *shp = context->shp;
while ((n = optget(argv, sh_optjobs))) {
Expand Down
1 change: 1 addition & 0 deletions src/cmd/ksh93/bltins/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ ksh93_files += [
'bltins/typeset.c',
'bltins/ulimit.c',
'bltins/umask.c',
'bltins/unalias.c',
'bltins/unset.c',
'bltins/wait.c',
'bltins/whence.c'
Expand Down
71 changes: 71 additions & 0 deletions src/cmd/ksh93/bltins/unalias.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2014 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* http://www.eclipse.org/org/documents/epl-v10.html *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <[email protected]> *
* *
***********************************************************************/
#include "config_ast.h" // IWYU pragma: keep

#include <stdbool.h>
#include <string.h>

#include "builtins.h"
#include "cdt.h"
#include "defs.h"
#include "error.h"
#include "name.h"
#include "option.h"
#include "shcmd.h"

// The `unalias` builtin.
int b_unalias(int argc, char *argv[], Shbltin_t *context) {
UNUSED(argc);
Shell_t *shp = context->shp;
Dt_t *troot = shp->alias_tree;
nvflag_t nvflags = NV_NOSCOPE;
bool all = false;
int n;

if (shp->subshell) troot = sh_subaliastree(shp, 0);
while ((n = optget(argv, sh_optunalias))) {
switch (n) { //!OCLINT(MissingDefaultStatement)
case 'a': {
all = true;
break;
}
case ':': {
errormsg(SH_DICT, 2, "%s", opt_info.arg);
break;
}
case '?': {
errormsg(SH_DICT, ERROR_usage(0), "%s", opt_info.arg);
return 2;
}
}
}
argv += opt_info.index;
if (error_info.errors || (!*argv && !all)) {
errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL));
__builtin_unreachable();
}

if (!troot) return 1;
if (all) {
dtclear(troot);
return 0;
}
return nv_unall(argv, true, nvflags, troot, shp);
}
130 changes: 13 additions & 117 deletions src/cmd/ksh93/bltins/unset.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,71 +19,37 @@
***********************************************************************/
#include "config_ast.h" // IWYU pragma: keep

#include <setjmp.h>
#include <stdbool.h>
#include <string.h>

#include "builtins.h"
#include "cdt.h"
#include "defs.h"
#include "error.h"
#include "fault.h"
#include "name.h"
#include "option.h"
#include "sfio.h"
#include "shcmd.h"

static_fn int unall(int, char **, Dt_t *, Shell_t *);

// The `unalias` builtin.
int b_unalias(int argc, char *argv[], Shbltin_t *context) {
Shell_t *shp = context->shp;
return unall(argc, argv, shp->alias_tree, shp);
}

// The `unset` builtin.
int b_unset(int argc, char *argv[], Shbltin_t *context) {
UNUSED(argc);
Shell_t *shp = context->shp;
return unall(argc, argv, shp->var_tree, shp);
}

//
// The removing of Shell variable names, aliases, and functions is performed here. Unset functions
// with unset -f. Non-existent items being deleted give non-zero exit status.
//
static_fn int unall(int argc, char **argv, Dt_t *troot, Shell_t *shp) {
Namval_t *np;
const char *name;
volatile int r;
Dt_t *dp;
Dt_t *troot = shp->var_tree;
nvflag_t nvflags = 0;
int all = 0, isfun, jmpval;
checkpt_t buff;
enum { ALIAS, VARIABLE } type;
UNUSED(argc);
int n;

if (troot == shp->alias_tree) {
type = ALIAS;
name = sh_optunalias;
if (shp->subshell) troot = sh_subaliastree(shp, 0);
} else {
type = VARIABLE;
name = sh_optunset;
}
while ((r = optget(argv, name))) {
switch (r) { //!OCLINT(MissingDefaultStatement)
while ((n = optget(argv, sh_optunset))) {
switch (n) { //!OCLINT(MissingDefaultStatement)
case 'f': {
troot = sh_subfuntree(shp, true);
break;
}
case 'a': {
all = 1;
nvflags |= NV_NOSCOPE;
break;
}
case 'n': {
nvflags = NV_NOREF;
nvflags |= NV_NOREF;
troot = shp->var_tree;
break;
}
// FALLTHRU
case 'v': {
troot = shp->var_tree;
break;
Expand All @@ -99,82 +65,12 @@ static_fn int unall(int argc, char **argv, Dt_t *troot, Shell_t *shp) {
}
}
argv += opt_info.index;
if (error_info.errors || (*argv == 0 && !all)) {
if (error_info.errors || !*argv) {
errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL));
__builtin_unreachable();
}
if (!troot) return 1;
r = 0;
if (troot == shp->var_tree) {
nvflags |= NV_VARNAME;
} else {
nvflags = NV_NOSCOPE;
}
if (all) {
dtclear(troot);
return r;
}
sh_pushcontext(shp, &buff, 1);
while (*argv) {
name = *argv++;
jmpval = sigsetjmp(buff.buff, 0);
np = NULL;
if (jmpval == 0) {
if (shp->namespace && troot != shp->var_tree) {
np = sh_fsearch(shp, name, nvflags ? NV_NOSCOPE : 0);
}
if (!np) np = nv_open(name, troot, NV_NOADD | nvflags);
} else {
r = 1;
continue;
}
if (np) {
if (is_abuiltin(np) || nv_isattr(np, NV_RDONLY)) {
if (nv_isattr(np, NV_RDONLY)) {
errormsg(SH_DICT, ERROR_warn(0), e_readonly, nv_name(np));
}
r = 1;
continue;
}
isfun = is_afunction(np);
if (troot == shp->var_tree) {
if (nv_isarray(np) && name[strlen(name) - 1] == ']' && !nv_getsub(np)) {
r = 1;
continue;
}

if (shp->subshell) np = sh_assignok(np, 0);
}
if (!nv_isnull(np) || nv_size(np) || nv_isattr(np, ~(NV_MINIMAL | NV_NOFREE))) {
_nv_unset(np, 0);
}
if (troot == shp->var_tree && shp->st.real_fun && (dp = shp->var_tree->walk) &&
dp == shp->st.real_fun->sdict) {
nv_delete(np, dp, NV_NOFREE);
} else if (isfun) {
struct Ufunction *rp = FETCH_VT(np->nvalue, rp);
if (!rp || !rp->running) nv_delete(np, troot, 0);
} else if (type == ALIAS) {
// Alias has been unset by call to _nv_unset, remove it from the tree.
nv_delete(np, troot, 0);
}
#if 0
// Causes unsetting local variable to expose global.
else if(shp->var_tree == troot && shp->var_tree != shp->var_base &&
nv_search_namval(np, shp->var_tree, NV_NOSCOPE)) {
nv_delete(np,shp->var_tree,0);
}
#endif
else {
nv_close(np);
}

} else if (type == ALIAS) {
// Alias not found
sfprintf(sfstderr, sh_translate(e_noalias), name);
r = 1;
}
}
sh_popcontext(shp, &buff);
return r;
if (!troot) return 1;
if (troot == shp->var_tree) nvflags |= NV_VARNAME;
return nv_unall(argv, false, nvflags, troot, shp);
}
1 change: 1 addition & 0 deletions src/cmd/ksh93/include/name.h
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ extern void nv_setvec(Namval_t *, int, int, char *[]);
extern void nv_setvtree(Namval_t *);
extern int nv_setsize(Namval_t *, int);
extern Namfun_t *nv_disc(Namval_t *, Namfun_t *, Nvdisc_op_t);
extern int nv_unall(char **, bool, nvflag_t, Dt_t *, Shell_t *);
extern void nv_unset(Namval_t *); /*obsolete */
extern void _nv_unset(Namval_t *, nvflag_t);
extern Namval_t *nv_search(const char *, Dt_t *, nvflag_t);
Expand Down
77 changes: 77 additions & 0 deletions src/cmd/ksh93/sh/name.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <setjmp.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
Expand Down Expand Up @@ -3235,3 +3236,79 @@ void nv_unset(Namval_t *np) {
_nv_unset(np, 0);
return;
}

//
// Removing of Shell variable names, aliases, and functions is performed here. Non-existent
// items being deleted give non-zero exit status. This is used by `unset` and `unalias`.
//
int nv_unall(char **names, bool aliases, nvflag_t nvflags, Dt_t *troot, Shell_t *shp) {
Namval_t *np;
volatile int r = 0;
Dt_t *dp;
int isfun, jmpval;
checkpt_t buff;

sh_pushcontext(shp, &buff, 1);
while (*names) {
char *name = *names++;
jmpval = sigsetjmp(buff.buff, 0);
np = NULL;
if (jmpval == 0) {
if (shp->namespace && troot != shp->var_tree) {
np = sh_fsearch(shp, name, nvflags ? NV_NOSCOPE : 0);
}
if (!np) np = nv_open(name, troot, NV_NOADD | nvflags);
} else {
r = 1;
continue;
}
if (np) {
if (is_abuiltin(np) || nv_isattr(np, NV_RDONLY)) {
if (nv_isattr(np, NV_RDONLY)) {
errormsg(SH_DICT, ERROR_warn(0), e_readonly, nv_name(np));
}
r = 1;
continue;
}
isfun = is_afunction(np);
if (troot == shp->var_tree) {
if (nv_isarray(np) && name[strlen(name) - 1] == ']' && !nv_getsub(np)) {
r = 1;
continue;
}

if (shp->subshell) np = sh_assignok(np, 0);
}
if (!nv_isnull(np) || nv_size(np) || nv_isattr(np, ~(NV_MINIMAL | NV_NOFREE))) {
_nv_unset(np, 0);
}
if (troot == shp->var_tree && shp->st.real_fun && (dp = shp->var_tree->walk) &&
dp == shp->st.real_fun->sdict) {
nv_delete(np, dp, NV_NOFREE);
} else if (isfun) {
struct Ufunction *rp = FETCH_VT(np->nvalue, rp);
if (!rp || !rp->running) nv_delete(np, troot, 0);
} else if (aliases) {
// Alias has been unset by call to _nv_unset, remove it from the tree.
nv_delete(np, troot, 0);
}
#if 0
// Causes unsetting local variable to expose global.
else if(shp->var_tree == troot && shp->var_tree != shp->var_base &&
nv_search_namval(np, shp->var_tree, NV_NOSCOPE)) {
nv_delete(np,shp->var_tree,0);
}
#endif
else {
nv_close(np);
}

} else if (aliases) {
// Alias not found
sfprintf(sfstderr, sh_translate(e_noalias), name);
r = 1;
}
}
sh_popcontext(shp, &buff);
return r;
}

0 comments on commit d5277d3

Please sign in to comment.