Nice patch from Wolfgang Denk
No binary (build failed)
—
(log yok)
| @@ -116,6 +116,10 @@ | |
| #undef CONFIG_FEATURE_SH_FANCY_PROMPT | |
| #define BB_BANNER | |
| #endif | |
| + | #define SPECIAL_VAR_SYMBOL 03 |
| + | #define FLAG_EXIT_FROM_LOOP 1 |
| + | #define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ |
| + | #define FLAG_REPARSING (1 << 2) /* >=2nd pass */ |
| typedef enum { | |
| REDIRECT_INPUT = 1, | |
| @@ -157,7 +161,8 @@ typedef enum { | |
| RES_DO = 9, | |
| RES_DONE = 10, | |
| RES_XXXX = 11, | |
| - | RES_SNTX = 12 |
| + | RES_IN = 12, |
| + | RES_SNTX = 13 |
| } reserved_style; | |
| #define FLAG_END (1<<RES_NONE) | |
| #define FLAG_IF (1<<RES_IF) | |
| @@ -170,6 +175,7 @@ typedef enum { | |
| #define FLAG_UNTIL (1<<RES_UNTIL) | |
| #define FLAG_DO (1<<RES_DO) | |
| #define FLAG_DONE (1<<RES_DONE) | |
| + | #define FLAG_IN (1<<RES_IN) |
| #define FLAG_START (1<<RES_XXXX) | |
| /* This holds pointers to the various results of parsing */ | |
| @@ -181,6 +187,7 @@ struct p_context { | |
| reserved_style w; | |
| int old_flag; /* for figuring out valid reserved words */ | |
| struct p_context *stack; | |
| + | int type; /* define type of parser : ";$" common or special symbol */ |
| /* How about quoting status? */ | |
| }; | |
| @@ -201,6 +208,8 @@ struct child_prog { | |
| glob_t glob_result; /* result of parameter globbing */ | |
| int is_stopped; /* is the program currently running? */ | |
| struct pipe *family; /* pointer back to the child's parent pipe */ | |
| + | int sp; /* number of SPECIAL_VAR_SYMBOL */ |
| + | int type; |
| }; | |
| struct pipe { | |
| @@ -319,6 +328,7 @@ static void __syntax(char *file, int line) { | |
| /* function prototypes for builtins */ | |
| static int builtin_cd(struct child_prog *child); | |
| static int builtin_env(struct child_prog *child); | |
| + | static int builtin_eval(struct child_prog *child); |
| static int builtin_exec(struct child_prog *child); | |
| static int builtin_exit(struct child_prog *child); | |
| static int builtin_export(struct child_prog *child); | |
| @@ -376,19 +386,22 @@ static int redirect_dup_num(struct in_str *input); | |
| static int redirect_opt_num(o_string *o); | |
| static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); | |
| static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); | |
| - | static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src); |
| + | static char *lookup_param(char *src); |
| + | static char *make_string(char **inp); |
| static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); | |
| static int parse_string(o_string *dest, struct p_context *ctx, const char *src); | |
| static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); | |
| /* setup: */ | |
| - | static int parse_stream_outer(struct in_str *inp); |
| - | static int parse_string_outer(const char *s); |
| + | static int parse_stream_outer(struct in_str *inp, int flag); |
| + | static int parse_string_outer(const char *s, int flag); |
| static int parse_file_outer(FILE *f); | |
| /* job management: */ | |
| static int checkjobs(struct pipe* fg_pipe); | |
| static void insert_bg_job(struct pipe *pi); | |
| static void remove_bg_job(struct pipe *pi); | |
| /* local variable support */ | |
| + | static char **make_list_in(char **inp, char *name); |
| + | static char *insert_var_value(char *inp); |
| static char *get_local_var(const char *var); | |
| static void unset_local_var(const char *name); | |
| static int set_local_var(const char *s, int flg_export); | |
| @@ -405,7 +418,7 @@ static struct built_in_command bltins[] = { | |
| {"cd", "Change working directory", builtin_cd}, | |
| {"continue", "Continue for, while or until loop", builtin_not_written}, | |
| {"env", "Print all environment variables", builtin_env}, | |
| - | {"eval", "Construct and run shell command", builtin_not_written}, |
| + | {"eval", "Construct and run shell command", builtin_eval}, |
| {"exec", "Exec command, replacing this shell with the exec'd process", | |
| builtin_exec}, | |
| {"exit", "Exit from shell()", builtin_exit}, | |
| @@ -436,6 +449,21 @@ static const char *set_cwd(void) | |
| return cwd; | |
| } | |
| + | /* built-in 'eval' handler */ |
| + | static int builtin_eval(struct child_prog *child) |
| + | { |
| + | char *str = NULL; |
| + | int rcode = EXIT_SUCCESS; |
| + | |
| + | if (child->argv[1]) { |
| + | str = make_string(child->argv + 1); |
| + | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | |
| + | FLAG_PARSE_SEMICOLON); |
| + | free(str); |
| + | rcode = last_return_code; |
| + | } |
| + | return rcode; |
| + | } |
| /* built-in 'cd <path>' handler */ | |
| static int builtin_cd(struct child_prog *child) | |
| @@ -1046,11 +1074,14 @@ static void restore_redirects(int squirrel[]) | |
| static void pseudo_exec(struct child_prog *child) | |
| { | |
| int i, rcode; | |
| + | char *p; |
| struct built_in_command *x; | |
| if (child->argv) { | |
| for (i=0; is_assignment(child->argv[i]); i++) { | |
| debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); | |
| - | putenv(strdup(child->argv[i])); |
| + | p = insert_var_value(child->argv[i]); |
| + | putenv(strdup(p)); |
| + | if (p != child->argv[i]) free(p); |
| } | |
| child->argv+=i; /* XXX this hack isn't so horrible, since we are about | |
| to exit, and therefore don't need to keep data | |
| @@ -1317,6 +1348,7 @@ static int run_pipe_real(struct pipe *pi) | |
| int pipefds[2]; /* pipefds[0] is for reading */ | |
| struct child_prog *child; | |
| struct built_in_command *x; | |
| + | char *p; |
| nextin = 0; | |
| pi->pgrp = -1; | |
| @@ -1359,10 +1391,28 @@ static int run_pipe_real(struct pipe *pi) | |
| export_me=1; | |
| } | |
| free(name); | |
| - | set_local_var(child->argv[i], export_me); |
| + | p = insert_var_value(child->argv[i]); |
| + | set_local_var(p, export_me); |
| + | if (p != child->argv[i]) free(p); |
| } | |
| return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ | |
| } | |
| + | for (i = 0; is_assignment(child->argv[i]); i++) { |
| + | p = insert_var_value(child->argv[i]); |
| + | putenv(strdup(p)); |
| + | if (p != child->argv[i]) { |
| + | child->sp--; |
| + | free(p); |
| + | } |
| + | } |
| + | if (child->sp) { |
| + | char * str = NULL; |
| + | |
| + | str = make_string((child->argv + i)); |
| + | parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); |
| + | free(str); |
| + | return last_return_code; |
| + | } |
| for (x = bltins; x->cmd; x++) { | |
| if (strcmp(child->argv[i], x->cmd) == 0 ) { | |
| int squirrel[] = {-1, -1, -1}; | |
| @@ -1378,9 +1428,6 @@ static int run_pipe_real(struct pipe *pi) | |
| * Is it really safe for inline use? Experimentally, | |
| * things seem to work with glibc. */ | |
| setup_redirects(child, squirrel); | |
| - | for (i=0; is_assignment(child->argv[i]); i++) { |
| - | putenv(strdup(child->argv[i])); |
| - | } |
| child->argv+=i; /* XXX horrible hack */ | |
| rcode = x->function(child); | |
| child->argv-=i; /* XXX restore hack so free() can work right */ | |
| @@ -1474,19 +1521,97 @@ static int run_pipe_real(struct pipe *pi) | |
| static int run_list_real(struct pipe *pi) | |
| { | |
| - | int rcode=0; |
| + | char *save_name = NULL; |
| + | char **list = NULL; |
| + | char **save_list = NULL; |
| + | struct pipe *rpipe; |
| + | int flag_rep = 0; |
| + | int save_num_progs; |
| + | int rcode=0, flag_skip=1; |
| + | int flag_restore = 0; |
| int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ | |
| reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; | |
| - | for (;pi;pi=pi->next) { |
| + | /* check syntax for "for" */ |
| + | for (rpipe = pi; rpipe; rpipe = rpipe->next) { |
| + | if ((rpipe->r_mode == RES_IN || |
| + | rpipe->r_mode == RES_FOR) && |
| + | (rpipe->next == NULL)) { |
| + | syntax(); |
| + | return 1; |
| + | } |
| + | if ((rpipe->r_mode == RES_IN && |
| + | (rpipe->next->r_mode == RES_IN && |
| + | rpipe->next->progs->argv != NULL))|| |
| + | (rpipe->r_mode == RES_FOR && |
| + | rpipe->next->r_mode != RES_IN)) { |
| + | syntax(); |
| + | return 1; |
| + | } |
| + | } |
| + | for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { |
| + | if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL || |
| + | pi->r_mode == RES_FOR) { |
| + | flag_restore = 0; |
| + | if (!rpipe) { |
| + | flag_rep = 0; |
| + | rpipe = pi; |
| + | } |
| + | } |
| rmode = pi->r_mode; | |
| debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); | |
| - | if (rmode == skip_more_in_this_rmode) continue; |
| + | if (rmode == skip_more_in_this_rmode && flag_skip) { |
| + | if (pi->followup == PIPE_SEQ) flag_skip=0; |
| + | continue; |
| + | } |
| + | flag_skip = 1; |
| skip_more_in_this_rmode = RES_XXXX; | |
| if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; | |
| if (rmode == RES_THEN && if_code) continue; | |
| if (rmode == RES_ELSE && !if_code) continue; | |
| if (rmode == RES_ELIF && !if_code) continue; | |
| + | if (rmode == RES_FOR && pi->num_progs) { |
| + | if (!list) { |
| + | /* if no variable values after "in" we skip "for" */ |
| + | if (!pi->next->progs->argv) continue; |
| + | /* create list of variable values */ |
| + | list = make_list_in(pi->next->progs->argv, |
| + | pi->progs->argv[0]); |
| + | save_list = list; |
| + | save_name = pi->progs->argv[0]; |
| + | pi->progs->argv[0] = NULL; |
| + | flag_rep = 1; |
| + | } |
| + | if (!(*list)) { |
| + | free(pi->progs->argv[0]); |
| + | free(save_list); |
| + | list = NULL; |
| + | flag_rep = 0; |
| + | pi->progs->argv[0] = save_name; |
| + | pi->progs->glob_result.gl_pathv[0] = |
| + | pi->progs->argv[0]; |
| + | continue; |
| + | } else { |
| + | /* insert new value from list for variable */ |
| + | if (pi->progs->argv[0]) |
| + | free(pi->progs->argv[0]); |
| + | pi->progs->argv[0] = *list++; |
| + | pi->progs->glob_result.gl_pathv[0] = |
| + | pi->progs->argv[0]; |
| + | } |
| + | } |
| + | if (rmode == RES_IN) continue; |
| + | if (rmode == RES_DO) { |
| + | if (!flag_rep) continue; |
| + | } |
| + | if ((rmode == RES_DONE)) { |
| + | if (flag_rep) { |
| + | flag_restore = 1; |
| + | } else { |
| + | rpipe = NULL; |
| + | } |
| + | } |
| if (pi->num_progs == 0) continue; | |
| + | save_num_progs = pi->num_progs; /* save number of programs */ |
| rcode = run_pipe_real(pi); | |
| debug_printf("run_pipe_real returned %d\n",rcode); | |
| if (rcode!=-1) { | |
| @@ -1513,8 +1638,13 @@ static int run_list_real(struct pipe *pi) | |
| debug_printf("checkjobs returned %d\n",rcode); | |
| } | |
| last_return_code=rcode; | |
| + | pi->num_progs = save_num_progs; /* restore number of programs */ |
| if ( rmode == RES_IF || rmode == RES_ELIF ) | |
| next_if_code=rcode; /* can be overwritten a number of times */ | |
| + | if (rmode == RES_WHILE) |
| + | flag_rep = !last_return_code; |
| + | if (rmode == RES_UNTIL) |
| + | flag_rep = last_return_code; |
| if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || | |
| (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) | |
| skip_more_in_this_rmode=rmode; | |
| @@ -1898,6 +2028,7 @@ static void initialize_context(struct p_context *ctx) | |
| ctx->pipe=ctx->list_head; | |
| ctx->w=RES_NONE; | |
| ctx->stack=NULL; | |
| + | ctx->old_flag=0; |
| done_command(ctx); /* creates the memory for working child */ | |
| } | |
| @@ -1924,9 +2055,10 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |
| { "elif", RES_ELIF, FLAG_THEN }, | |
| { "else", RES_ELSE, FLAG_FI }, | |
| { "fi", RES_FI, FLAG_END }, | |
| - | { "for", RES_FOR, FLAG_DO | FLAG_START }, |
| + | { "for", RES_FOR, FLAG_IN | FLAG_START }, |
| { "while", RES_WHILE, FLAG_DO | FLAG_START }, | |
| { "until", RES_UNTIL, FLAG_DO | FLAG_START }, | |
| + | { "in", RES_IN, FLAG_DO }, |
| { "do", RES_DO, FLAG_DONE }, | |
| { "done", RES_DONE, FLAG_END } | |
| }; | |
| @@ -1939,13 +2071,20 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |
| if (r->flag & FLAG_START) { | |
| struct p_context *new = xmalloc(sizeof(struct p_context)); | |
| debug_printf("push stack\n"); | |
| + | if (ctx->w == RES_IN || ctx->w == RES_FOR) { |
| + | syntax(); |
| + | free(new); |
| + | ctx->w = RES_SNTX; |
| + | b_reset(dest); |
| + | return 1; |
| + | } |
| *new = *ctx; /* physical copy */ | |
| initialize_context(ctx); | |
| ctx->stack=new; | |
| } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) { | |
| syntax(); | |
| ctx->w = RES_SNTX; | |
| - | b_reset (dest); |
| + | b_reset(dest); |
| return 1; | |
| } | |
| ctx->w=r->code; | |
| @@ -1953,6 +2092,7 @@ int reserved_word(o_string *dest, struct p_context *ctx) | |
| if (ctx->old_flag & FLAG_END) { | |
| struct p_context *old; | |
| debug_printf("pop stack\n"); | |
| + | done_pipe(ctx,PIPE_SEQ); |
| old = ctx->stack; | |
| old->child->group = ctx->list_head; | |
| old->child->subshell = 0; | |
| @@ -1986,7 +2126,7 @@ static int done_word(o_string *dest, struct p_context *ctx) | |
| syntax(); | |
| return 1; /* syntax error, groups and arglists don't mix */ | |
| } | |
| - | if (!child->argv) { |
| + | if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) { |
| debug_printf("checking %s for reserved-ness\n",dest->data); | |
| if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX; | |
| } | |
| @@ -2006,6 +2146,10 @@ static int done_word(o_string *dest, struct p_context *ctx) | |
| } else { | |
| child->argv = glob_target->gl_pathv; | |
| } | |
| + | if (ctx->w == RES_FOR) { |
| + | done_word(dest,ctx); |
| + | done_pipe(ctx,PIPE_SEQ); |
| + | } |
| return 0; | |
| } | |
| @@ -2041,8 +2185,10 @@ static int done_command(struct p_context *ctx) | |
| prog->group = NULL; | |
| prog->glob_result.gl_pathv = NULL; | |
| prog->family = pi; | |
| + | prog->sp = 0; |
| + | ctx->child = prog; |
| + | prog->type = ctx->type; |
| - | ctx->child=prog; |
| /* but ctx->pipe and ctx->list_head remain unchanged */ | |
| return 0; | |
| } | |
| @@ -2227,32 +2373,32 @@ static int parse_group(o_string *dest, struct p_context *ctx, | |
| /* basically useful version until someone wants to get fancier, | |
| * see the bash man page under "Parameter Expansion" */ | |
| - | static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src) |
| + | static char *lookup_param(char *src) |
| { | |
| - | const char *p=NULL; |
| - | if (src->data) { |
| - | p = getenv(src->data); |
| + | char *p=NULL; |
| + | if (src) { |
| + | p = getenv(src); |
| if (!p) | |
| - | p = get_local_var(src->data); |
| + | p = get_local_var(src); |
| } | |
| - | if (p) parse_string(dest, ctx, p); /* recursion */ |
| - | b_free(src); |
| + | return p; |
| } | |
| /* return code: 0 for OK, 1 for syntax error */ | |
| static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) | |
| { | |
| int i, advance=0; | |
| - | o_string alt=NULL_O_STRING; |
| char sep[]=" "; | |
| int ch = input->peek(input); /* first character after the $ */ | |
| debug_printf("handle_dollar: ch=%c\n",ch); | |
| if (isalpha(ch)) { | |
| + | b_addchr(dest, SPECIAL_VAR_SYMBOL); |
| + | ctx->child->sp++; |
| while(ch=b_peek(input),isalnum(ch) || ch=='_') { | |
| b_getch(input); | |
| - | b_addchr(&alt,ch); |
| + | b_addchr(dest,ch); |
| } | |
| - | lookup_param(dest, ctx, &alt); |
| + | b_addchr(dest, SPECIAL_VAR_SYMBOL); |
| } else if (isdigit(ch)) { | |
| i = ch-'0'; /* XXX is $0 special? */ | |
| if (i<global_argc) { | |
| @@ -2277,16 +2423,18 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i | |
| advance = 1; | |
| break; | |
| case '{': | |
| + | b_addchr(dest, SPECIAL_VAR_SYMBOL); |
| + | ctx->child->sp++; |
| b_getch(input); | |
| /* XXX maybe someone will try to escape the '}' */ | |
| while(ch=b_getch(input),ch!=EOF && ch!='}') { | |
| - | b_addchr(&alt,ch); |
| + | b_addchr(dest,ch); |
| } | |
| if (ch != '}') { | |
| syntax(); | |
| return 1; | |
| } | |
| - | lookup_param(dest, ctx, &alt); |
| + | b_addchr(dest, SPECIAL_VAR_SYMBOL); |
| break; | |
| case '(': | |
| b_getch(input); | |
| @@ -2348,7 +2496,9 @@ int parse_stream(o_string *dest, struct p_context *ctx, | |
| b_addqchr(dest, ch, dest->quote); | |
| } else { | |
| if (m==2) { /* unquoted IFS */ | |
| - | done_word(dest, ctx); |
| + | if (done_word(dest, ctx)) { |
| + | return 1; |
| + | } |
| /* If we aren't performing a substitution, treat a newline as a | |
| * command separator. */ | |
| if (end_trigger != '\0' && ch=='\n') | |
| @@ -2509,30 +2659,46 @@ void update_ifs_map(void) | |
| /* most recursion does not come through here, the exeception is | |
| * from builtin_source() */ | |
| - | int parse_stream_outer(struct in_str *inp) |
| + | int parse_stream_outer(struct in_str *inp, int flag) |
| { | |
| struct p_context ctx; | |
| o_string temp=NULL_O_STRING; | |
| int rcode; | |
| do { | |
| + | ctx.type = flag; |
| initialize_context(&ctx); | |
| update_ifs_map(); | |
| + | if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0); |
| inp->promptmode=1; | |
| rcode = parse_stream(&temp, &ctx, inp, '\n'); | |
| - | done_word(&temp, &ctx); |
| - | done_pipe(&ctx,PIPE_SEQ); |
| - | run_list(ctx.list_head); |
| + | if (rcode != 1 && ctx.old_flag != 0) { |
| + | syntax(); |
| + | } |
| + | if (rcode != 1 && ctx.old_flag == 0) { |
| + | done_word(&temp, &ctx); |
| + | done_pipe(&ctx,PIPE_SEQ); |
| + | run_list(ctx.list_head); |
| + | } else { |
| + | if (ctx.old_flag != 0) { |
| + | free(ctx.stack); |
| + | b_reset(&temp); |
| + | } |
| + | temp.nonnull = 0; |
| + | temp.quote = 0; |
| + | inp->p = NULL; |
| + | free_pipe_list(ctx.list_head,0); |
| + | } |
| b_free(&temp); | |
| - | } while (rcode != -1); /* loop on syntax errors, return on EOF */ |
| + | } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ |
| return 0; | |
| } | |
| - | static int parse_string_outer(const char *s) |
| + | static int parse_string_outer(const char *s, int flag) |
| { | |
| struct in_str input; | |
| setup_string_in_str(&input, s); | |
| - | return parse_stream_outer(&input); |
| + | return parse_stream_outer(&input, flag); |
| } | |
| static int parse_file_outer(FILE *f) | |
| @@ -2540,7 +2706,7 @@ static int parse_file_outer(FILE *f) | |
| int rcode; | |
| struct in_str input; | |
| setup_file_in_str(&input, f); | |
| - | rcode = parse_stream_outer(&input); |
| + | rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON); |
| return rcode; | |
| } | |
| @@ -2630,7 +2796,7 @@ int hush_main(int argc, char **argv) | |
| { | |
| global_argv = argv+optind; | |
| global_argc = argc-optind; | |
| - | opt = parse_string_outer(optarg); |
| + | opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); |
| goto final_return; | |
| } | |
| break; | |
| @@ -2703,3 +2869,106 @@ int hush_main(int argc, char **argv) | |
| final_return: | |
| return(opt?opt:last_return_code); | |
| } | |
| + | |
| + | static char *insert_var_value(char *inp) |
| + | { |
| + | int res_str_len = 0; |
| + | int len; |
| + | int done = 0; |
| + | char *p, *p1, *res_str = NULL; |
| + | |
| + | while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) { |
| + | if (p != inp) { |
| + | len = p - inp; |
| + | res_str = xrealloc(res_str, (res_str_len + len)); |
| + | strncpy((res_str + res_str_len), inp, len); |
| + | res_str_len += len; |
| + | } |
| + | inp = ++p; |
| + | p = strchr(inp, SPECIAL_VAR_SYMBOL); |
| + | *p = '\0'; |
| + | if ((p1 = lookup_param(inp))) { |
| + | len = res_str_len + strlen(p1); |
| + | res_str = xrealloc(res_str, (1 + len)); |
| + | strcpy((res_str + res_str_len), p1); |
| + | res_str_len = len; |
| + | } |
| + | *p = SPECIAL_VAR_SYMBOL; |
| + | inp = ++p; |
| + | done = 1; |
| + | } |
| + | if (done) { |
| + | res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp))); |
| + | strcpy((res_str + res_str_len), inp); |
| + | while ((p = strchr(res_str, '\n'))) { |
| + | *p = ' '; |
| + | } |
| + | } |
| + | return (res_str == NULL) ? inp : res_str; |
| + | } |
| + | |
| + | static char **make_list_in(char **inp, char *name) |
| + | { |
| + | int len, i; |
| + | int name_len = strlen(name); |
| + | int n = 0; |
| + | char **list; |
| + | char *p1, *p2, *p3; |
| + | |
| + | /* create list of variable values */ |
| + | list = xmalloc(sizeof(*list)); |
| + | for (i = 0; inp[i]; i++) { |
| + | p3 = insert_var_value(inp[i]); |
| + | p1 = p3; |
| + | while (*p1) { |
| + | if ((*p1 == ' ')) { |
| + | p1++; |
| + | continue; |
| + | } |
| + | if ((p2 = strchr(p1, ' '))) { |
| + | len = p2 - p1; |
| + | } else { |
| + | len = strlen(p1); |
| + | p2 = p1 + len; |
| + | } |
| + | /* we use n + 2 in realloc for list,because we add |
| + | * new element and then we will add NULL element */ |
| + | list = xrealloc(list, sizeof(*list) * (n + 2)); |
| + | list[n] = xmalloc(2 + name_len + len); |
| + | strcpy(list[n], name); |
| + | strcat(list[n], "="); |
| + | strncat(list[n], p1, len); |
| + | list[n++][name_len + len + 1] = '\0'; |
| + | p1 = p2; |
| + | } |
| + | if (p3 != inp[i]) free(p3); |
| + | } |
| + | list[n] = NULL; |
| + | return list; |
| + | } |
| + | |
| + | /* Make new string for parser */ |
| + | static char * make_string(char ** inp) |
| + | { |
| + | char *p; |
| + | char *str = NULL; |
| + | int n; |
| + | int len = 2; |
| + | |
| + | for (n = 0; inp[n]; n++) { |
| + | p = insert_var_value(inp[n]); |
| + | str = xrealloc(str, (len + strlen(p))); |
| + | if (n) { |
| + | strcat(str, " "); |
| + | } else { |
| + | *str = '\0'; |
| + | } |
| + | strcat(str, p); |
| + | len = strlen(str) + 3; |
| + | if (p != inp[n]) free(p); |
| + | } |
| + | len = strlen(str); |
| + | *(str + len) = '\n'; |
| + | *(str + len + 1) = '\0'; |
| + | return str; |
| + | } |