#define debug_printf_subst(...) fprintf(stderr, __VA_ARGS__)
#endif
-/* Keep unconditionally on for now */
-#define ENABLE_HUSH_DEBUG 1
-
#ifndef debug_printf_clean
/* broken, of course, but OK for testing */
static const char *indenter(int i)
#define debug_print_strings(prefix, vv) ((void)0)
#endif
-
/*
* Leak hunting. Use hush_leaktool.sh for post-processing.
*/
#endif
+/* Keep unconditionally on for now */
+#define HUSH_DEBUG 1
+/* Do we support ANY keywords? */
+#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS
+#define HAS_KEYWORDS 1
+#define IF_HAS_KEYWORDS(...) __VA_ARGS__
+#define IF_HAS_NO_KEYWORDS(...)
+#else
+#define HAS_KEYWORDS 0
+#define IF_HAS_KEYWORDS(...)
+#define IF_HAS_NO_KEYWORDS(...) __VA_ARGS__
+#endif
+
+
#define SPECIAL_VAR_SYMBOL 3
#define PARSEFLAG_EXIT_FROM_LOOP 1
struct pipe *list_head;
struct pipe *pipe;
struct redir_struct *pending_redirect;
- smallint res_w;
- smallint ctx_inverted; /* "! cmd | cmd" */
- int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */
+#if HAS_KEYWORDS
+ smallint ctx_res_w;
+ smallint ctx_inverted; /* "! cmd | cmd" */
+ int old_flag; /* bitmask of FLAG_xxx, for figuring out valid reserved words */
struct p_context *stack;
+#endif
};
struct redir_struct {
struct redir_struct *next;
- smallint /*redir_type*/ rd_type;
+ char *rd_filename; /* filename */
int fd; /* file descriptor being redirected */
int dup; /* -1, or file descriptor being duplicated */
- char *rd_filename; /* filename */
+ smallint /*enum redir_type*/ rd_type;
};
struct child_prog {
char *cmdtext; /* name of job */
#endif
struct child_prog *progs; /* array of commands in pipe */
- smallint pi_inverted; /* "! cmd | cmd" */
smallint followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
- smallint res_word; /* needed for if, for, while, until... */
+ IF_HAS_KEYWORDS(smallint pi_inverted;) /* "! cmd | cmd" */
+ IF_HAS_KEYWORDS(smallint res_word;) /* needed for if, for, while, until... */
};
/* On program start, environ points to initial environment.
if (i == fg_pipe->num_progs - 1) {
/* last process gives overall exitstatus */
rcode = WEXITSTATUS(status);
- if (fg_pipe->pi_inverted)
- rcode = !rcode;
+ IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
}
} else {
fg_pipe->progs[i].is_stopped = 1;
rcode = run_list(child->group) & 0xff;
restore_redirects(squirrel);
debug_printf_exec("run_pipe return %d\n", rcode);
- if (pi->pi_inverted)
- rcode = !rcode;
+ IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
return rcode;
}
free(argv_expanded);
restore_redirects(squirrel);
debug_printf_exec("run_pipe return %d\n", rcode);
- if (pi->pi_inverted)
- rcode = !rcode;
+ IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
return rcode;
}
}
free(argv_expanded);
restore_redirects(squirrel);
debug_printf_exec("run_pipe return %d\n", rcode);
- if (pi->pi_inverted)
- rcode = !rcode;
+ IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;)
return rcode;
}
}
#else
enum { if_code = 0, next_if_code = 0 };
#endif
-// TODO: rword and ->res_word are not needed if !LOOPS and !IF
- reserved_style rword;
+ reserved_style rword IF_HAS_NO_KEYWORDS(= RES_NONE);
reserved_style skip_more_for_this_rword = RES_XXXX;
debug_printf_exec("run_list start lvl %d\n", run_list_level + 1);
#endif /* JOB */
for (; pi; pi = flag_restore ? rpipe : pi->next) {
- rword = pi->res_word;
+ IF_HAS_KEYWORDS(rword = pi->res_word;)
+ IF_HAS_NO_KEYWORDS(rword = RES_NONE;)
#if ENABLE_HUSH_LOOPS
if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) {
flag_restore = 0;
struct pipe *pi, *next;
for (pi = head; pi; pi = next) {
+#if HAS_KEYWORDS
debug_printf_clean("%s pipe reserved mode %d\n", indenter(indent), pi->res_word);
+#endif
rcode = free_pipe(pi, indent);
debug_printf_clean("%s pipe followup code %d\n", indenter(indent), pi->followup);
next = pi->next;
argv[0] = (char*)str;
argv[1] = NULL;
list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */
- if (ENABLE_HUSH_DEBUG)
+ if (HUSH_DEBUG)
if (!list[0] || list[1])
bb_error_msg_and_die("BUG in varexp2");
/* actually, just move string 2*sizeof(char*) bytes back */
if (list[0]) {
int n = 1;
while (list[n]) {
- if (ENABLE_HUSH_DEBUG)
+ if (HUSH_DEBUG)
if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
bb_error_msg_and_die("BUG in varexp3");
list[n][-1] = ' '; /* TODO: or to ifs[0]? */
struct pipe *pi;
pi = xzalloc(sizeof(struct pipe));
/*pi->followup = 0; - deliberately invalid value */
- if (RES_NONE)
- pi->res_word = RES_NONE;
+ /*pi->res_word = RES_NONE; - RES_NONE is 0 anyway */
return pi;
}
* Handles if, then, elif, else, fi, for, while, until, do, done.
* case, function, and select are obnoxious, save those for later.
*/
-#if ENABLE_HUSH_IF || ENABLE_HUSH_LOOPS
+#if HAS_KEYWORDS
static int reserved_word(const o_string *word, struct p_context *ctx)
{
struct reserved_combo {
debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
if (r->flag == 0) { /* '!' */
#if ENABLE_HUSH_LOOPS
- if (ctx->res_w == RES_IN) {
+ if (ctx->ctx_res_w == RES_IN) {
/* 'for a in ! a b c; ...' - ! isn't a keyword here */
break;
}
#endif
if (ctx->ctx_inverted /* bash doesn't accept '! ! true' */
#if ENABLE_HUSH_LOOPS
- || ctx->res_w == RES_FOR /* example: 'for ! a' */
+ || ctx->ctx_res_w == RES_FOR /* example: 'for ! a' */
#endif
) {
syntax(NULL);
- ctx->res_w = RES_SNTX;
+ IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
}
ctx->ctx_inverted = 1;
return 1;
struct p_context *new;
debug_printf("push stack\n");
#if ENABLE_HUSH_LOOPS
- if (ctx->res_w == RES_IN || ctx->res_w == RES_FOR) {
+ if (ctx->ctx_res_w == RES_IN || ctx->ctx_res_w == RES_FOR) {
syntax("malformed for"); /* example: 'for if' */
- ctx->res_w = RES_SNTX;
+ ctx->ctx_res_w = RES_SNTX;
return 1;
}
#endif
*new = *ctx; /* physical copy */
initialize_context(ctx);
ctx->stack = new;
- } else if (ctx->res_w == RES_NONE || !(ctx->old_flag & (1 << r->res))) {
+ } else if (ctx->ctx_res_w == RES_NONE || !(ctx->old_flag & (1 << r->res))) {
syntax(NULL);
- ctx->res_w = RES_SNTX;
+ ctx->ctx_res_w = RES_SNTX;
return 1;
}
- ctx->res_w = r->res;
+ ctx->ctx_res_w = r->res;
ctx->old_flag = r->flag;
if (ctx->old_flag & FLAG_END) {
struct p_context *old;
}
return 0;
}
-#else
-#define reserved_word(word, ctx) ((int)0)
#endif
/* Word is complete, look at it and update parsing context.
debug_printf_parse("done_word return 1: syntax error, groups and arglists don't mix\n");
return 1;
}
+#if HAS_KEYWORDS
if (!child->argv) { /* if it's the first word... */
debug_printf_parse(": checking '%s' for reserved-ness\n", word->data);
if (reserved_word(word, ctx)) {
o_reset(word);
word->o_assignment = NOT_ASSIGNMENT;
- debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX));
- return (ctx->res_w == RES_SNTX);
+ debug_printf_parse("done_word return %d\n", (ctx->ctx_res_w == RES_SNTX));
+ return (ctx->ctx_res_w == RES_SNTX);
}
}
+#endif
if (word->nonnull /* we saw "xx" or 'xx' */
/* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
&& (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
#if ENABLE_HUSH_LOOPS
/* Force FOR to have just one word (variable name) */
- if (ctx->res_w == RES_FOR)
+ if (ctx->ctx_res_w == RES_FOR)
done_pipe(ctx, PIPE_SEQ);
#endif
debug_printf_parse("done_word return 0\n");
debug_printf_parse("done_pipe entered, followup %d\n", type);
not_null = done_command(ctx); /* implicit closure of previous command */
ctx->pipe->followup = type;
- ctx->pipe->res_word = ctx->res_w;
- ctx->pipe->pi_inverted = ctx->ctx_inverted;
- ctx->ctx_inverted = 0;
+ IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;)
+ IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;)
+ IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;)
/* Without this check, even just <enter> on command line generates
* tree of three NOPs (!). Which is harmless but annoying.
* IOW: it is safe to do it unconditionally.
//err chk?
done_pipe(ctx, PIPE_SEQ);
}
- if (ctx->res_w == RES_NONE) {
+ if (!HAS_KEYWORDS IF_HAS_KEYWORDS(|| ctx->ctx_res_w == RES_NONE)) {
debug_printf_parse("parse_stream return 0: end_trigger char found\n");
return 0;
}
debug_printf_parse("parse_stream return 1: unexpected '}'\n");
return 1;
default:
- if (ENABLE_HUSH_DEBUG)
+ if (HUSH_DEBUG)
bb_error_msg_and_die("BUG: unexpected %c\n", ch);
}
} /* while (1) */
* Example: "sleep 9999; echo TEST" + ctrl-C:
* TEST should be printed */
rcode = parse_stream(&temp, &ctx, inp, ";\n");
+#if HAS_KEYWORDS
if (rcode != 1 && ctx.old_flag != 0) {
syntax(NULL);
}
- if (rcode != 1 && ctx.old_flag == 0) {
+#endif
+ if (rcode != 1 IF_HAS_KEYWORDS(&& ctx.old_flag == 0)) {
done_word(&temp, &ctx);
done_pipe(&ctx, PIPE_SEQ);
debug_print_tree(ctx.list_head, 0);
run_and_free_list(ctx.list_head);
} else {
/* We arrive here also if rcode == 1 (error in parse_stream) */
+#if HAS_KEYWORDS
if (ctx.old_flag != 0) {
free(ctx.stack);
o_reset(&temp);
}
+#endif
/*temp.nonnull = 0; - o_free does it below */
/*temp.o_quote = 0; - o_free does it below */
free_pipe_list(ctx.list_head, /* indent: */ 0);