Skip to content

Commit d5277d3

Browse files
committed
Refactor b_unset(), b_unalias, and unall()
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.
1 parent 9ba9355 commit d5277d3

File tree

8 files changed

+172
-120
lines changed

8 files changed

+172
-120
lines changed

Diff for: src/cmd/ksh93/bltins/bg.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@
3333
//
3434
// Builtin `bg` command.
3535
//
36-
int b_bg(int n, char *argv[], Shbltin_t *context) {
36+
int b_bg(int argc, char *argv[], Shbltin_t *context) {
37+
UNUSED(argc);
3738
Shell_t *shp = context->shp;
39+
int n;
3840

3941
while ((n = optget(argv, sh_optbg))) {
4042
switch (n) { //!OCLINT(MissingDefaultStatement)

Diff for: src/cmd/ksh93/bltins/fg.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@
3333
//
3434
// Builtin `fg` command.
3535
//
36-
int b_fg(int n, char *argv[], Shbltin_t *context) {
36+
int b_fg(int argc, char *argv[], Shbltin_t *context) {
37+
UNUSED(argc);
3738
Shell_t *shp = context->shp;
39+
int n;
3840

3941
while ((n = optget(argv, sh_optfg))) {
4042
switch (n) { //!OCLINT(MissingDefaultStatement)

Diff for: src/cmd/ksh93/bltins/jobs.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
//
3535
// Builtin `jobs`.
3636
//
37-
int b_jobs(int n, char *argv[], Shbltin_t *context) {
37+
int b_jobs(int argc, char *argv[], Shbltin_t *context) {
38+
UNUSED(argc);
39+
int n;
3840
int flag = 0;
3941
Shell_t *shp = context->shp;
4042
while ((n = optget(argv, sh_optjobs))) {

Diff for: src/cmd/ksh93/bltins/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ ksh93_files += [
3535
'bltins/typeset.c',
3636
'bltins/ulimit.c',
3737
'bltins/umask.c',
38+
'bltins/unalias.c',
3839
'bltins/unset.c',
3940
'bltins/wait.c',
4041
'bltins/whence.c'

Diff for: src/cmd/ksh93/bltins/unalias.c

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/***********************************************************************
2+
* *
3+
* This software is part of the ast package *
4+
* Copyright (c) 1982-2014 AT&T Intellectual Property *
5+
* and is licensed under the *
6+
* Eclipse Public License, Version 1.0 *
7+
* by AT&T Intellectual Property *
8+
* *
9+
* A copy of the License is available at *
10+
* http://www.eclipse.org/org/documents/epl-v10.html *
11+
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12+
* *
13+
* Information and Software Systems Research *
14+
* AT&T Research *
15+
* Florham Park NJ *
16+
* *
17+
* David Korn <[email protected]> *
18+
* *
19+
***********************************************************************/
20+
#include "config_ast.h" // IWYU pragma: keep
21+
22+
#include <stdbool.h>
23+
#include <string.h>
24+
25+
#include "builtins.h"
26+
#include "cdt.h"
27+
#include "defs.h"
28+
#include "error.h"
29+
#include "name.h"
30+
#include "option.h"
31+
#include "shcmd.h"
32+
33+
// The `unalias` builtin.
34+
int b_unalias(int argc, char *argv[], Shbltin_t *context) {
35+
UNUSED(argc);
36+
Shell_t *shp = context->shp;
37+
Dt_t *troot = shp->alias_tree;
38+
nvflag_t nvflags = NV_NOSCOPE;
39+
bool all = false;
40+
int n;
41+
42+
if (shp->subshell) troot = sh_subaliastree(shp, 0);
43+
while ((n = optget(argv, sh_optunalias))) {
44+
switch (n) { //!OCLINT(MissingDefaultStatement)
45+
case 'a': {
46+
all = true;
47+
break;
48+
}
49+
case ':': {
50+
errormsg(SH_DICT, 2, "%s", opt_info.arg);
51+
break;
52+
}
53+
case '?': {
54+
errormsg(SH_DICT, ERROR_usage(0), "%s", opt_info.arg);
55+
return 2;
56+
}
57+
}
58+
}
59+
argv += opt_info.index;
60+
if (error_info.errors || (!*argv && !all)) {
61+
errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL));
62+
__builtin_unreachable();
63+
}
64+
65+
if (!troot) return 1;
66+
if (all) {
67+
dtclear(troot);
68+
return 0;
69+
}
70+
return nv_unall(argv, true, nvflags, troot, shp);
71+
}

Diff for: src/cmd/ksh93/bltins/unset.c

+13-117
Original file line numberDiff line numberDiff line change
@@ -19,71 +19,37 @@
1919
***********************************************************************/
2020
#include "config_ast.h" // IWYU pragma: keep
2121

22-
#include <setjmp.h>
2322
#include <stdbool.h>
2423
#include <string.h>
2524

2625
#include "builtins.h"
2726
#include "cdt.h"
2827
#include "defs.h"
2928
#include "error.h"
30-
#include "fault.h"
3129
#include "name.h"
3230
#include "option.h"
33-
#include "sfio.h"
3431
#include "shcmd.h"
3532

36-
static_fn int unall(int, char **, Dt_t *, Shell_t *);
37-
38-
// The `unalias` builtin.
39-
int b_unalias(int argc, char *argv[], Shbltin_t *context) {
40-
Shell_t *shp = context->shp;
41-
return unall(argc, argv, shp->alias_tree, shp);
42-
}
43-
4433
// The `unset` builtin.
4534
int b_unset(int argc, char *argv[], Shbltin_t *context) {
35+
UNUSED(argc);
4636
Shell_t *shp = context->shp;
47-
return unall(argc, argv, shp->var_tree, shp);
48-
}
49-
50-
//
51-
// The removing of Shell variable names, aliases, and functions is performed here. Unset functions
52-
// with unset -f. Non-existent items being deleted give non-zero exit status.
53-
//
54-
static_fn int unall(int argc, char **argv, Dt_t *troot, Shell_t *shp) {
55-
Namval_t *np;
56-
const char *name;
57-
volatile int r;
58-
Dt_t *dp;
37+
Dt_t *troot = shp->var_tree;
5938
nvflag_t nvflags = 0;
60-
int all = 0, isfun, jmpval;
61-
checkpt_t buff;
62-
enum { ALIAS, VARIABLE } type;
63-
UNUSED(argc);
39+
int n;
6440

65-
if (troot == shp->alias_tree) {
66-
type = ALIAS;
67-
name = sh_optunalias;
68-
if (shp->subshell) troot = sh_subaliastree(shp, 0);
69-
} else {
70-
type = VARIABLE;
71-
name = sh_optunset;
72-
}
73-
while ((r = optget(argv, name))) {
74-
switch (r) { //!OCLINT(MissingDefaultStatement)
41+
while ((n = optget(argv, sh_optunset))) {
42+
switch (n) { //!OCLINT(MissingDefaultStatement)
7543
case 'f': {
7644
troot = sh_subfuntree(shp, true);
77-
break;
78-
}
79-
case 'a': {
80-
all = 1;
45+
nvflags |= NV_NOSCOPE;
8146
break;
8247
}
8348
case 'n': {
84-
nvflags = NV_NOREF;
49+
nvflags |= NV_NOREF;
50+
troot = shp->var_tree;
51+
break;
8552
}
86-
// FALLTHRU
8753
case 'v': {
8854
troot = shp->var_tree;
8955
break;
@@ -99,82 +65,12 @@ static_fn int unall(int argc, char **argv, Dt_t *troot, Shell_t *shp) {
9965
}
10066
}
10167
argv += opt_info.index;
102-
if (error_info.errors || (*argv == 0 && !all)) {
68+
if (error_info.errors || !*argv) {
10369
errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NULL));
10470
__builtin_unreachable();
10571
}
106-
if (!troot) return 1;
107-
r = 0;
108-
if (troot == shp->var_tree) {
109-
nvflags |= NV_VARNAME;
110-
} else {
111-
nvflags = NV_NOSCOPE;
112-
}
113-
if (all) {
114-
dtclear(troot);
115-
return r;
116-
}
117-
sh_pushcontext(shp, &buff, 1);
118-
while (*argv) {
119-
name = *argv++;
120-
jmpval = sigsetjmp(buff.buff, 0);
121-
np = NULL;
122-
if (jmpval == 0) {
123-
if (shp->namespace && troot != shp->var_tree) {
124-
np = sh_fsearch(shp, name, nvflags ? NV_NOSCOPE : 0);
125-
}
126-
if (!np) np = nv_open(name, troot, NV_NOADD | nvflags);
127-
} else {
128-
r = 1;
129-
continue;
130-
}
131-
if (np) {
132-
if (is_abuiltin(np) || nv_isattr(np, NV_RDONLY)) {
133-
if (nv_isattr(np, NV_RDONLY)) {
134-
errormsg(SH_DICT, ERROR_warn(0), e_readonly, nv_name(np));
135-
}
136-
r = 1;
137-
continue;
138-
}
139-
isfun = is_afunction(np);
140-
if (troot == shp->var_tree) {
141-
if (nv_isarray(np) && name[strlen(name) - 1] == ']' && !nv_getsub(np)) {
142-
r = 1;
143-
continue;
144-
}
145-
146-
if (shp->subshell) np = sh_assignok(np, 0);
147-
}
148-
if (!nv_isnull(np) || nv_size(np) || nv_isattr(np, ~(NV_MINIMAL | NV_NOFREE))) {
149-
_nv_unset(np, 0);
150-
}
151-
if (troot == shp->var_tree && shp->st.real_fun && (dp = shp->var_tree->walk) &&
152-
dp == shp->st.real_fun->sdict) {
153-
nv_delete(np, dp, NV_NOFREE);
154-
} else if (isfun) {
155-
struct Ufunction *rp = FETCH_VT(np->nvalue, rp);
156-
if (!rp || !rp->running) nv_delete(np, troot, 0);
157-
} else if (type == ALIAS) {
158-
// Alias has been unset by call to _nv_unset, remove it from the tree.
159-
nv_delete(np, troot, 0);
160-
}
161-
#if 0
162-
// Causes unsetting local variable to expose global.
163-
else if(shp->var_tree == troot && shp->var_tree != shp->var_base &&
164-
nv_search_namval(np, shp->var_tree, NV_NOSCOPE)) {
165-
nv_delete(np,shp->var_tree,0);
166-
}
167-
#endif
168-
else {
169-
nv_close(np);
170-
}
17172

172-
} else if (type == ALIAS) {
173-
// Alias not found
174-
sfprintf(sfstderr, sh_translate(e_noalias), name);
175-
r = 1;
176-
}
177-
}
178-
sh_popcontext(shp, &buff);
179-
return r;
73+
if (!troot) return 1;
74+
if (troot == shp->var_tree) nvflags |= NV_VARNAME;
75+
return nv_unall(argv, false, nvflags, troot, shp);
18076
}

Diff for: src/cmd/ksh93/include/name.h

+1
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ extern void nv_setvec(Namval_t *, int, int, char *[]);
544544
extern void nv_setvtree(Namval_t *);
545545
extern int nv_setsize(Namval_t *, int);
546546
extern Namfun_t *nv_disc(Namval_t *, Namfun_t *, Nvdisc_op_t);
547+
extern int nv_unall(char **, bool, nvflag_t, Dt_t *, Shell_t *);
547548
extern void nv_unset(Namval_t *); /*obsolete */
548549
extern void _nv_unset(Namval_t *, nvflag_t);
549550
extern Namval_t *nv_search(const char *, Dt_t *, nvflag_t);

Diff for: src/cmd/ksh93/sh/name.c

+77
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <ctype.h>
2323
#include <float.h>
2424
#include <limits.h>
25+
#include <setjmp.h>
2526
#include <stdbool.h>
2627
#include <stddef.h>
2728
#include <stdint.h>
@@ -3235,3 +3236,79 @@ void nv_unset(Namval_t *np) {
32353236
_nv_unset(np, 0);
32363237
return;
32373238
}
3239+
3240+
//
3241+
// Removing of Shell variable names, aliases, and functions is performed here. Non-existent
3242+
// items being deleted give non-zero exit status. This is used by `unset` and `unalias`.
3243+
//
3244+
int nv_unall(char **names, bool aliases, nvflag_t nvflags, Dt_t *troot, Shell_t *shp) {
3245+
Namval_t *np;
3246+
volatile int r = 0;
3247+
Dt_t *dp;
3248+
int isfun, jmpval;
3249+
checkpt_t buff;
3250+
3251+
sh_pushcontext(shp, &buff, 1);
3252+
while (*names) {
3253+
char *name = *names++;
3254+
jmpval = sigsetjmp(buff.buff, 0);
3255+
np = NULL;
3256+
if (jmpval == 0) {
3257+
if (shp->namespace && troot != shp->var_tree) {
3258+
np = sh_fsearch(shp, name, nvflags ? NV_NOSCOPE : 0);
3259+
}
3260+
if (!np) np = nv_open(name, troot, NV_NOADD | nvflags);
3261+
} else {
3262+
r = 1;
3263+
continue;
3264+
}
3265+
if (np) {
3266+
if (is_abuiltin(np) || nv_isattr(np, NV_RDONLY)) {
3267+
if (nv_isattr(np, NV_RDONLY)) {
3268+
errormsg(SH_DICT, ERROR_warn(0), e_readonly, nv_name(np));
3269+
}
3270+
r = 1;
3271+
continue;
3272+
}
3273+
isfun = is_afunction(np);
3274+
if (troot == shp->var_tree) {
3275+
if (nv_isarray(np) && name[strlen(name) - 1] == ']' && !nv_getsub(np)) {
3276+
r = 1;
3277+
continue;
3278+
}
3279+
3280+
if (shp->subshell) np = sh_assignok(np, 0);
3281+
}
3282+
if (!nv_isnull(np) || nv_size(np) || nv_isattr(np, ~(NV_MINIMAL | NV_NOFREE))) {
3283+
_nv_unset(np, 0);
3284+
}
3285+
if (troot == shp->var_tree && shp->st.real_fun && (dp = shp->var_tree->walk) &&
3286+
dp == shp->st.real_fun->sdict) {
3287+
nv_delete(np, dp, NV_NOFREE);
3288+
} else if (isfun) {
3289+
struct Ufunction *rp = FETCH_VT(np->nvalue, rp);
3290+
if (!rp || !rp->running) nv_delete(np, troot, 0);
3291+
} else if (aliases) {
3292+
// Alias has been unset by call to _nv_unset, remove it from the tree.
3293+
nv_delete(np, troot, 0);
3294+
}
3295+
#if 0
3296+
// Causes unsetting local variable to expose global.
3297+
else if(shp->var_tree == troot && shp->var_tree != shp->var_base &&
3298+
nv_search_namval(np, shp->var_tree, NV_NOSCOPE)) {
3299+
nv_delete(np,shp->var_tree,0);
3300+
}
3301+
#endif
3302+
else {
3303+
nv_close(np);
3304+
}
3305+
3306+
} else if (aliases) {
3307+
// Alias not found
3308+
sfprintf(sfstderr, sh_translate(e_noalias), name);
3309+
r = 1;
3310+
}
3311+
}
3312+
sh_popcontext(shp, &buff);
3313+
return r;
3314+
}

0 commit comments

Comments
 (0)