aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-07-28 23:04:34 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-07-28 23:04:34 +0000
commitbcb25537d02b50ce26678defcf4f39d0c89f5b3b (patch)
tree4a8a8068c8078d893fb1036e5e5d33634f26cb7d /shell/hush.c
parentcf22c89f9a7d19166fa038d3bb2bac3011f946fd (diff)
downloadbusybox-w32-bcb25537d02b50ce26678defcf4f39d0c89f5b3b.tar.gz
busybox-w32-bcb25537d02b50ce26678defcf4f39d0c89f5b3b.tar.bz2
busybox-w32-bcb25537d02b50ce26678defcf4f39d0c89f5b3b.zip
hush: implement break and continue
function old new delta bltins 252 276 +24 builtin_continue - 12 +12 builtin_break - 12 +12 static.version_str 18 17 -1 run_list 1984 1948 -36 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 1/2 up/down: 48/-27) Total: 11 bytes
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c171
1 files changed, 98 insertions, 73 deletions
diff --git a/shell/hush.c b/shell/hush.c
index ca2a1d21f..21cb36564 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -54,7 +54,7 @@
54 * to-do: 54 * to-do:
55 * port selected bugfixes from post-0.49 busybox lash - done? 55 * port selected bugfixes from post-0.49 busybox lash - done?
56 * change { and } from special chars to reserved words 56 * change { and } from special chars to reserved words
57 * builtins: break, continue, eval, return, set, trap, ulimit 57 * builtins: return, trap, ulimit
58 * test magic exec 58 * test magic exec
59 * check setting of global_argc and global_argv 59 * check setting of global_argc and global_argv
60 * follow IFS rules more precisely, including update semantics 60 * follow IFS rules more precisely, including update semantics
@@ -74,6 +74,7 @@
74#include <fnmatch.h> 74#include <fnmatch.h>
75#endif 75#endif
76 76
77#define HUSH_VER_STR "0.9"
77 78
78#if !BB_MMU && ENABLE_HUSH_TICK 79#if !BB_MMU && ENABLE_HUSH_TICK
79//#undef ENABLE_HUSH_TICK 80//#undef ENABLE_HUSH_TICK
@@ -230,7 +231,7 @@ void xxfree(void *ptr)
230#define SPECIAL_VAR_SYMBOL 3 231#define SPECIAL_VAR_SYMBOL 3
231#define PARSEFLAG_EXIT_FROM_LOOP 1 232#define PARSEFLAG_EXIT_FROM_LOOP 1
232 233
233typedef enum { 234typedef enum redir_type {
234 REDIRECT_INPUT = 1, 235 REDIRECT_INPUT = 1,
235 REDIRECT_OVERWRITE = 2, 236 REDIRECT_OVERWRITE = 2,
236 REDIRECT_APPEND = 3, 237 REDIRECT_APPEND = 3,
@@ -253,14 +254,14 @@ static const struct {
253 { O_RDWR, 1, "<>" } 254 { O_RDWR, 1, "<>" }
254}; 255};
255 256
256typedef enum { 257typedef enum pipe_style {
257 PIPE_SEQ = 1, 258 PIPE_SEQ = 1,
258 PIPE_AND = 2, 259 PIPE_AND = 2,
259 PIPE_OR = 3, 260 PIPE_OR = 3,
260 PIPE_BG = 4, 261 PIPE_BG = 4,
261} pipe_style; 262} pipe_style;
262 263
263typedef enum { 264typedef enum reserved_style {
264 RES_NONE = 0, 265 RES_NONE = 0,
265#if ENABLE_HUSH_IF 266#if ENABLE_HUSH_IF
266 RES_IF , 267 RES_IF ,
@@ -358,7 +359,7 @@ struct variable {
358 smallint flg_read_only; 359 smallint flg_read_only;
359}; 360};
360 361
361typedef struct { 362typedef struct o_string {
362 char *data; 363 char *data;
363 int length; /* position where data is appended */ 364 int length; /* position where data is appended */
364 int maxlen; 365 int maxlen;
@@ -378,9 +379,9 @@ enum {
378/* Used for initialization: o_string foo = NULL_O_STRING; */ 379/* Used for initialization: o_string foo = NULL_O_STRING; */
379#define NULL_O_STRING { NULL } 380#define NULL_O_STRING { NULL }
380 381
381/* I can almost use ordinary FILE *. Is open_memstream() universally 382/* I can almost use ordinary FILE*. Is open_memstream() universally
382 * available? Where is it documented? */ 383 * available? Where is it documented? */
383struct in_str { 384typedef struct in_str {
384 const char *p; 385 const char *p;
385 /* eof_flag=1: last char in ->p is really an EOF */ 386 /* eof_flag=1: last char in ->p is really an EOF */
386 char eof_flag; /* meaningless if ->p == NULL */ 387 char eof_flag; /* meaningless if ->p == NULL */
@@ -392,7 +393,7 @@ struct in_str {
392 FILE *file; 393 FILE *file;
393 int (*get) (struct in_str *); 394 int (*get) (struct in_str *);
394 int (*peek) (struct in_str *); 395 int (*peek) (struct in_str *);
395}; 396} in_str;
396#define i_getch(input) ((input)->get(input)) 397#define i_getch(input) ((input)->get(input))
397#define i_peek(input) ((input)->peek(input)) 398#define i_peek(input) ((input)->peek(input))
398 399
@@ -403,7 +404,11 @@ enum {
403 CHAR_SPECIAL = 3, /* example: $ */ 404 CHAR_SPECIAL = 3, /* example: $ */
404}; 405};
405 406
406#define HUSH_VER_STR "0.02" 407enum {
408 BC_BREAK = 1,
409 BC_CONTINUE = 2,
410};
411
407 412
408/* "Globals" within this file */ 413/* "Globals" within this file */
409 414
@@ -429,6 +434,7 @@ struct globals {
429 struct pipe *toplevel_list; 434 struct pipe *toplevel_list;
430 smallint ctrl_z_flag; 435 smallint ctrl_z_flag;
431#endif 436#endif
437 smallint flag_break_continue;
432 smallint fake_mode; 438 smallint fake_mode;
433 /* these three support $?, $#, and $1 */ 439 /* these three support $?, $#, and $1 */
434 smalluint last_return_code; 440 smalluint last_return_code;
@@ -481,6 +487,7 @@ enum { run_list_level = 0 };
481#define global_argc (G.global_argc ) 487#define global_argc (G.global_argc )
482#define last_return_code (G.last_return_code) 488#define last_return_code (G.last_return_code)
483#define ifs (G.ifs ) 489#define ifs (G.ifs )
490#define flag_break_continue (G.flag_break_continue)
484#define fake_mode (G.fake_mode ) 491#define fake_mode (G.fake_mode )
485#define cwd (G.cwd ) 492#define cwd (G.cwd )
486#define last_bg_pid (G.last_bg_pid ) 493#define last_bg_pid (G.last_bg_pid )
@@ -713,6 +720,8 @@ static int builtin_shift(char **argv);
713static int builtin_source(char **argv); 720static int builtin_source(char **argv);
714static int builtin_umask(char **argv); 721static int builtin_umask(char **argv);
715static int builtin_unset(char **argv); 722static int builtin_unset(char **argv);
723static int builtin_break(char **argv);
724static int builtin_continue(char **argv);
716//static int builtin_not_written(char **argv); 725//static int builtin_not_written(char **argv);
717 726
718/* Table of built-in functions. They can be forked or not, depending on 727/* Table of built-in functions. They can be forked or not, depending on
@@ -742,10 +751,10 @@ static const struct built_in_command bltins[] = {
742#if ENABLE_HUSH_JOB 751#if ENABLE_HUSH_JOB
743 BLTIN("bg" , builtin_fg_bg, "Resume a job in the background"), 752 BLTIN("bg" , builtin_fg_bg, "Resume a job in the background"),
744#endif 753#endif
745// BLTIN("break" , builtin_not_written, "Exit for, while or until loop"), 754 BLTIN("break" , builtin_break, "Exit from a loop"),
746 BLTIN("cd" , builtin_cd, "Change directory"), 755 BLTIN("cd" , builtin_cd, "Change directory"),
747// BLTIN("continue", builtin_not_written, "Continue for, while or until loop"), 756 BLTIN("continue", builtin_continue, "Start new loop iteration"),
748 BLTIN("echo" , builtin_echo, "Write strings to stdout"), 757 BLTIN("echo" , builtin_echo, "Write to stdout"),
749 BLTIN("eval" , builtin_eval, "Construct and run shell command"), 758 BLTIN("eval" , builtin_eval, "Construct and run shell command"),
750 BLTIN("exec" , builtin_exec, "Execute command, don't return to shell"), 759 BLTIN("exec" , builtin_exec, "Execute command, don't return to shell"),
751 BLTIN("exit" , builtin_exit, "Exit"), 760 BLTIN("exit" , builtin_exit, "Exit"),
@@ -2016,29 +2025,25 @@ static int run_list(struct pipe *pi)
2016 char *case_word = NULL; 2025 char *case_word = NULL;
2017#endif 2026#endif
2018#if ENABLE_HUSH_LOOPS 2027#if ENABLE_HUSH_LOOPS
2019 struct pipe *loop_top = loop_top; /* just for compiler */ 2028 struct pipe *loop_top = NULL;
2020 char *for_varname = NULL; 2029 char *for_varname = NULL;
2021 char **for_lcur = NULL; 2030 char **for_lcur = NULL;
2022 char **for_list = NULL; 2031 char **for_list = NULL;
2023 smallint flag_run_loop = 0;
2024 smallint flag_goto_looptop = 0;
2025#endif 2032#endif
2026 smallint flag_skip = 1; 2033 smallint flag_skip = 1;
2027 smalluint rcode = 0; /* probably just for compiler */ 2034 smalluint rcode = 0; /* probably just for compiler */
2028#if ENABLE_HUSH_IF 2035#if ENABLE_HUSH_IF
2029 smalluint cond_code = 0; 2036 smalluint cond_code = 0;
2030///experimentally off: last_cond_code seems to be bogus
2031 ///smalluint last_cond_code = 0; /* need double-buffer to handle "elif" */
2032#else 2037#else
2033 enum { cond_code = 0, /* ///last_cond_code = 0 */ }; 2038 enum { cond_code = 0, };
2034#endif 2039#endif
2035 /*reserved_style*/ smallint rword IF_HAS_NO_KEYWORDS(= RES_NONE); 2040 /*enum reserved_style*/ smallint rword = RES_NONE;
2036 /*reserved_style*/ smallint skip_more_for_this_rword = RES_XXXX; 2041 /*enum reserved_style*/ smallint skip_more_for_this_rword = RES_XXXX;
2037 2042
2038 debug_printf_exec("run_list start lvl %d\n", run_list_level + 1); 2043 debug_printf_exec("run_list start lvl %d\n", run_list_level + 1);
2039 2044
2040#if ENABLE_HUSH_LOOPS 2045#if ENABLE_HUSH_LOOPS
2041 /* check syntax for "for" */ 2046 /* Check syntax for "for" */
2042 for (struct pipe *cpipe = pi; cpipe; cpipe = cpipe->next) { 2047 for (struct pipe *cpipe = pi; cpipe; cpipe = cpipe->next) {
2043 if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN) 2048 if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN)
2044 continue; 2049 continue;
@@ -2108,20 +2113,16 @@ static int run_list(struct pipe *pi)
2108 } 2113 }
2109#endif /* JOB */ 2114#endif /* JOB */
2110 2115
2111 /* Go through list of pipes, (maybe) executing them */ 2116 /* Go through list of pipes, (maybe) executing them. */
2112 for (; pi; pi = USE_HUSH_LOOPS( flag_goto_looptop ? loop_top : ) pi->next) { 2117 for (; pi; pi = USE_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
2113 IF_HAS_KEYWORDS(rword = pi->res_word;) 2118 IF_HAS_KEYWORDS(rword = pi->res_word;)
2114 IF_HAS_NO_KEYWORDS(rword = RES_NONE;) 2119 IF_HAS_NO_KEYWORDS(rword = RES_NONE;)
2115 debug_printf_exec(": rword=%d cond_code=%d last_cond_code=%d skip_more=%d flag_run_loop=%d\n", 2120 debug_printf_exec(": rword=%d cond_code=%d skip_more=%d\n",
2116 rword, cond_code, last_cond_code, skip_more_for_this_rword, flag_run_loop); 2121 rword, cond_code, skip_more_for_this_rword);
2117#if ENABLE_HUSH_LOOPS 2122#if ENABLE_HUSH_LOOPS
2118 if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) { 2123 if (rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) {
2119 /* start of a loop: remember it */ 2124 /* start of a loop: remember where loop starts */
2120 flag_goto_looptop = 0; /* not yet reached final "done" */ 2125 loop_top = pi;
2121// if (!loop_top) { /* hmm why this check is needed? */
2122// flag_run_loop = 0; /* suppose loop condition is false (for now) */
2123 loop_top = pi; /* remember where loop starts */
2124// }
2125 } 2126 }
2126#endif 2127#endif
2127 if (rword == skip_more_for_this_rword && flag_skip) { 2128 if (rword == skip_more_for_this_rword && flag_skip) {
@@ -2134,18 +2135,21 @@ static int run_list(struct pipe *pi)
2134 flag_skip = 1; 2135 flag_skip = 1;
2135 skip_more_for_this_rword = RES_XXXX; 2136 skip_more_for_this_rword = RES_XXXX;
2136#if ENABLE_HUSH_IF 2137#if ENABLE_HUSH_IF
2137/// if (rword == RES_THEN) // || rword == RES_ELSE) 2138 if (cond_code) {
2138/// cond_code = last_cond_code; 2139 if (rword == RES_THEN) {
2139 if (rword == RES_THEN && cond_code) 2140 /* "if <false> THEN cmd": skip cmd */
2140 continue; /* "if <false> THEN cmd": skip cmd */ 2141 continue;
2141 if (rword == RES_ELSE && !cond_code) 2142 }
2142 //continue; /* "if <true> then ... ELSE cmd": skip cmd */ 2143 } else {
2143 break; //TEST 2144 if (rword == RES_ELSE || rword == RES_ELIF) {
2144 if (rword == RES_ELIF && !cond_code) 2145 /* "if <true> then ... ELSE/ELIF cmd":
2145 break; /* "if <true> then ... ELIF cmd": skip cmd and all following ones */ 2146 * skip cmd and all following ones */
2147 break;
2148 }
2149 }
2146#endif 2150#endif
2147#if ENABLE_HUSH_LOOPS 2151#if ENABLE_HUSH_LOOPS
2148 if (rword == RES_FOR && pi->num_progs) { /* hmm why "&& pi->num_progs"? */ 2152 if (rword == RES_FOR) { /* && pi->num_progs - always == 1 */
2149 if (!for_lcur) { 2153 if (!for_lcur) {
2150 /* first loop through for */ 2154 /* first loop through for */
2151 2155
@@ -2161,7 +2165,7 @@ static int run_list(struct pipe *pi)
2161 if (pi->next->res_word == RES_IN) { 2165 if (pi->next->res_word == RES_IN) {
2162 /* if no variable values after "in" we skip "for" */ 2166 /* if no variable values after "in" we skip "for" */
2163 if (!pi->next->progs->argv) 2167 if (!pi->next->progs->argv)
2164 continue; 2168 break;
2165 vals = pi->next->progs->argv; 2169 vals = pi->next->progs->argv;
2166 } /* else: "for var; do..." -> assume "$@" list */ 2170 } /* else: "for var; do..." -> assume "$@" list */
2167 /* create list of variable values */ 2171 /* create list of variable values */
@@ -2171,7 +2175,6 @@ static int run_list(struct pipe *pi)
2171 debug_print_strings("for_list", for_list); 2175 debug_print_strings("for_list", for_list);
2172 for_varname = pi->progs->argv[0]; 2176 for_varname = pi->progs->argv[0];
2173 pi->progs->argv[0] = NULL; 2177 pi->progs->argv[0] = NULL;
2174 flag_run_loop = 1; /* "for" has no loop condition, loop... */
2175 } 2178 }
2176 free(pi->progs->argv[0]); 2179 free(pi->progs->argv[0]);
2177 if (!*for_lcur) { 2180 if (!*for_lcur) {
@@ -2179,33 +2182,22 @@ static int run_list(struct pipe *pi)
2179 free(for_list); 2182 free(for_list);
2180 for_list = NULL; 2183 for_list = NULL;
2181 for_lcur = NULL; 2184 for_lcur = NULL;
2182 flag_run_loop = 0; /* ... until end of value list */
2183 pi->progs->argv[0] = for_varname; 2185 pi->progs->argv[0] = for_varname;
2184 continue; 2186 break;
2185 } 2187 }
2186 /* insert next value from for_lcur */ 2188 /* insert next value from for_lcur */
2187//TODO: does it need escaping? 2189//TODO: does it need escaping?
2188 pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++); 2190 pi->progs->argv[0] = xasprintf("%s=%s", for_varname, *for_lcur++);
2189 } 2191 }
2190 if (rword == RES_IN) /* "for v IN list; do ..." - no pipe to execute here */ 2192 if (rword == RES_IN) /* "for v IN list;..." - "in" has no cmds anyway */
2191 continue; 2193 continue;
2192 if (rword == RES_DO) { /* "...; DO cmd; cmd" - this pipe is in loop body */ 2194 if (rword == RES_DONE) {
2193 if (!flag_run_loop) 2195 continue; /* "done" has no cmds too */
2194 continue; /* we are skipping this iteration */
2195 }
2196 if (rword == RES_DONE) { /* end of loop? */
2197 if (flag_run_loop) {
2198 flag_goto_looptop = 1;
2199// } else {
2200// loop_top = NULL;
2201 }
2202 continue; //TEST /* "done" has no cmd anyway */
2203 } 2196 }
2204#endif 2197#endif
2205#if ENABLE_HUSH_CASE 2198#if ENABLE_HUSH_CASE
2206 if (rword == RES_CASE) { 2199 if (rword == RES_CASE) {
2207 case_word = expand_strvec_to_string(pi->progs->argv); 2200 case_word = expand_strvec_to_string(pi->progs->argv);
2208 //bb_error_msg("case: arg:'%s' case_word:'%s'", pi->progs->argv[0], case_word);
2209 continue; 2201 continue;
2210 } 2202 }
2211 if (rword == RES_MATCH) { 2203 if (rword == RES_MATCH) {
@@ -2215,35 +2207,53 @@ static int run_list(struct pipe *pi)
2215 /* all prev words didn't match, does this one match? */ 2207 /* all prev words didn't match, does this one match? */
2216 pattern = expand_strvec_to_string(pi->progs->argv); 2208 pattern = expand_strvec_to_string(pi->progs->argv);
2217 /* TODO: which FNM_xxx flags to use? */ 2209 /* TODO: which FNM_xxx flags to use? */
2218 /* ///last_ */ cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0); 2210 cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0);
2219 //bb_error_msg("fnmatch('%s','%s'):%d", pattern, case_word, cond_code);
2220 free(pattern); 2211 free(pattern);
2221 if (/* ///last_ */ cond_code == 0) { /* match! we will execute this branch */ 2212 if (cond_code == 0) { /* match! we will execute this branch */
2222 free(case_word); /* make future "word)" stop */ 2213 free(case_word); /* make future "word)" stop */
2223 case_word = NULL; 2214 case_word = NULL;
2224 } 2215 }
2225 continue; 2216 continue;
2226 } 2217 }
2227 if (rword == RES_CASEI) { /* inside of a case branch */ 2218 if (rword == RES_CASEI) { /* inside of a case branch */
2228 if (/* ///last_ */ cond_code != 0) 2219 if (cond_code != 0)
2229 continue; /* not matched yet, skip this pipe */ 2220 continue; /* not matched yet, skip this pipe */
2230 } 2221 }
2231#endif 2222#endif
2232 if (pi->num_progs == 0) 2223 if (pi->num_progs == 0)
2233 continue; 2224 continue;
2234 2225
2235 /* After analyzing all keywrds and conditions, we decided 2226 /* After analyzing all keywords and conditions, we decided
2236 * to execute this pipe */ 2227 * to execute this pipe. NB: has to do checkjobs(NULL)
2228 * after run_pipe() to collect any background children,
2229 * even if list execution is to be stopped. */
2237 debug_printf_exec(": run_pipe with %d members\n", pi->num_progs); 2230 debug_printf_exec(": run_pipe with %d members\n", pi->num_progs);
2238 { 2231 {
2239 int r; 2232 int r;
2233 flag_break_continue = 0;
2240 rcode = r = run_pipe(pi); /* NB: rcode is a smallint */ 2234 rcode = r = run_pipe(pi); /* NB: rcode is a smallint */
2241 if (r != -1) { 2235 if (r != -1) {
2242 /* We only ran a builtin: rcode was set by the return value 2236 /* we only ran a builtin: rcode is already known
2243 * of run_pipe(), and we don't need to wait for anything. */ 2237 * and we don't need to wait for anything. */
2238 /* was it "break" or "continue"? */
2239 if (flag_break_continue) {
2240 smallint fbc = flag_break_continue;
2241 /* we might fall into outer *loop*,
2242 * don't want to break it too */
2243 flag_break_continue = 0;
2244 if (loop_top) {
2245 if (fbc == BC_BREAK)
2246 goto check_jobs_and_break;
2247 /* "continue": simulate end of loop */
2248 rword = RES_DONE;
2249 continue;
2250 }
2251 bb_error_msg("break/continue: only meaningful in a loop");
2252 /* bash compat: exit code is still 0 */
2253 }
2244 } else if (pi->followup == PIPE_BG) { 2254 } else if (pi->followup == PIPE_BG) {
2245 /* What does bash do with attempts to background builtins? */ 2255 /* what does bash do with attempts to background builtins? */
2246 /* Even bash 3.2 doesn't do that well with nested bg: 2256 /* even bash 3.2 doesn't do that well with nested bg:
2247 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". 2257 * try "{ { sleep 10; echo DEEP; } & echo HERE; } &".
2248 * I'm NOT treating inner &'s as jobs */ 2258 * I'm NOT treating inner &'s as jobs */
2249#if ENABLE_HUSH_JOB 2259#if ENABLE_HUSH_JOB
@@ -2271,16 +2281,19 @@ static int run_list(struct pipe *pi)
2271 /* Analyze how result affects subsequent commands */ 2281 /* Analyze how result affects subsequent commands */
2272#if ENABLE_HUSH_IF 2282#if ENABLE_HUSH_IF
2273 if (rword == RES_IF || rword == RES_ELIF) 2283 if (rword == RES_IF || rword == RES_ELIF)
2274 /* ///last_cond_code = */ cond_code = rcode; 2284 cond_code = rcode;
2275#endif 2285#endif
2276#if ENABLE_HUSH_LOOPS 2286#if ENABLE_HUSH_LOOPS
2277 if (rword == RES_WHILE) { 2287 if (rword == RES_WHILE) {
2278 flag_run_loop = !rcode; 2288 if (rcode)
2279 debug_printf_exec(": setting flag_run_loop=%d\n", flag_run_loop); 2289 goto check_jobs_and_break;
2280 } 2290 }
2281 if (rword == RES_UNTIL) { 2291 if (rword == RES_UNTIL) {
2282 flag_run_loop = rcode; 2292 if (!rcode) {
2283 debug_printf_exec(": setting flag_run_loop=%d\n", flag_run_loop); 2293 check_jobs_and_break:
2294 checkjobs(NULL);
2295 break;
2296 }
2284 } 2297 }
2285#endif 2298#endif
2286 if ((rcode == 0 && pi->followup == PIPE_OR) 2299 if ((rcode == 0 && pi->followup == PIPE_OR)
@@ -4498,3 +4511,15 @@ static int builtin_unset(char **argv)
4498 unset_local_var(argv[1]); 4511 unset_local_var(argv[1]);
4499 return EXIT_SUCCESS; 4512 return EXIT_SUCCESS;
4500} 4513}
4514
4515static int builtin_break(char **argv UNUSED_PARAM)
4516{
4517 flag_break_continue = BC_BREAK;
4518 return EXIT_SUCCESS;
4519}
4520
4521static int builtin_continue(char **argv UNUSED_PARAM)
4522{
4523 flag_break_continue = BC_CONTINUE;
4524 return EXIT_SUCCESS;
4525}