📄 hush.c
字号:
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;#ifndef __U_BOOT__ checkjobs(NULL);#endif } return rcode;}/* broken, of course, but OK for testing */static char *indenter(int i){ static char blanks[]=" "; return &blanks[sizeof(blanks)-i-1];}/* return code is the exit status of the pipe */static int free_pipe(struct pipe *pi, int indent){ char **p; struct child_prog *child;#ifndef __U_BOOT__ struct redir_struct *r, *rnext;#endif int a, i, ret_code=0; char *ind = indenter(indent);#ifndef __U_BOOT__ if (pi->stopped_progs > 0) return ret_code; final_printf("%s run pipe: (pid %d)\n",ind,getpid());#endif for (i=0; i<pi->num_progs; i++) { child = &pi->progs[i]; final_printf("%s command %d:\n",ind,i); if (child->argv) { for (a=0,p=child->argv; *p; a++,p++) { final_printf("%s argv[%d] = %s\n",ind,a,*p); }#ifndef __U_BOOT__ globfree(&child->glob_result);#else for (a = child->argc;a >= 0;a--) { free(child->argv[a]); } free(child->argv); child->argc = 0;#endif child->argv=NULL; } else if (child->group) {#ifndef __U_BOOT__ final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);#endif ret_code = free_pipe_list(child->group,indent+3); final_printf("%s end group\n",ind); } else { final_printf("%s (nil)\n",ind); }#ifndef __U_BOOT__ for (r=child->redirects; r; r=rnext) { final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip); if (r->dup == -1) { /* guard against the case >$FOO, where foo is unset or blank */ if (r->word.gl_pathv) { final_printf(" %s\n", *r->word.gl_pathv); globfree(&r->word); } } else { final_printf("&%d\n", r->dup); } rnext=r->next; free(r); } child->redirects=NULL;#endif } free(pi->progs); /* children are an array, they get freed all at once */ pi->progs=NULL; return ret_code;}static int free_pipe_list(struct pipe *head, int indent){ int rcode=0; /* if list has no members */ struct pipe *pi, *next; char *ind = indenter(indent); for (pi=head; pi; pi=next) { final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode); rcode = free_pipe(pi, indent); final_printf("%s pipe followup code %d\n", ind, pi->followup); next=pi->next; pi->next=NULL; free(pi); } return rcode;}/* Select which version we will use */static int run_list(struct pipe *pi){ int rcode=0;#ifndef __U_BOOT__ if (fake_mode==0) {#endif rcode = run_list_real(pi);#ifndef __U_BOOT__ }#endif /* free_pipe_list has the side effect of clearing memory * In the long run that function can be merged with run_list_real, * but doing that now would hobble the debugging effort. */ free_pipe_list(pi,0); return rcode;}/* The API for glob is arguably broken. This routine pushes a non-matching * string into the output structure, removing non-backslashed backslashes. * If someone can prove me wrong, by performing this function within the * original glob(3) api, feel free to rewrite this routine into oblivion. * Return code (0 vs. GLOB_NOSPACE) matches glob(3). * XXX broken if the last character is '\\', check that before calling. */#ifndef __U_BOOT__static int globhack(const char *src, int flags, glob_t *pglob){ int cnt=0, pathc; const char *s; char *dest; for (cnt=1, s=src; s && *s; s++) { if (*s == '\\') s++; cnt++; } dest = malloc(cnt); if (!dest) return GLOB_NOSPACE; if (!(flags & GLOB_APPEND)) { pglob->gl_pathv=NULL; pglob->gl_pathc=0; pglob->gl_offs=0; pglob->gl_offs=0; } pathc = ++pglob->gl_pathc; pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv)); if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; pglob->gl_pathv[pathc-1]=dest; pglob->gl_pathv[pathc]=NULL; for (s=src; s && *s; s++, dest++) { if (*s == '\\') s++; *dest = *s; } *dest='\0'; return 0;}/* XXX broken if the last character is '\\', check that before calling */static int glob_needed(const char *s){ for (; *s; s++) { if (*s == '\\') s++; if (strchr("*[?",*s)) return 1; } return 0;}#if 0static void globprint(glob_t *pglob){ int i; debug_printf("glob_t at %p:\n", pglob); debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n", pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags); for (i=0; i<pglob->gl_pathc; i++) debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i, pglob->gl_pathv[i], pglob->gl_pathv[i]);}#endifstatic int xglob(o_string *dest, int flags, glob_t *pglob){ int gr; /* short-circuit for null word */ /* we can code this better when the debug_printf's are gone */ if (dest->length == 0) { if (dest->nonnull) { /* bash man page calls this an "explicit" null */ gr = globhack(dest->data, flags, pglob); debug_printf("globhack returned %d\n",gr); } else { return 0; } } else if (glob_needed(dest->data)) { gr = glob(dest->data, flags, NULL, pglob); debug_printf("glob returned %d\n",gr); if (gr == GLOB_NOMATCH) { /* quote removal, or more accurately, backslash removal */ gr = globhack(dest->data, flags, pglob); debug_printf("globhack returned %d\n",gr); } } else { gr = globhack(dest->data, flags, pglob); debug_printf("globhack returned %d\n",gr); } if (gr == GLOB_NOSPACE) error_msg_and_die("out of memory during glob"); if (gr != 0) { /* GLOB_ABORTED ? */ error_msg("glob(3) error %d",gr); } /* globprint(glob_target); */ return gr;}#endif#ifdef __U_BOOT__static char *get_dollar_var(char ch);#endif/* This is used to get/check local shell variables */static char *get_local_var(const char *s){ struct variables *cur; if (!s) return NULL;#ifdef __U_BOOT__ if (*s == '$') return get_dollar_var(s[1]);#endif for (cur = top_vars; cur; cur=cur->next) if(strcmp(cur->name, s)==0) return cur->value; return NULL;}/* This is used to set local shell variables flg_export==0 if only local (not exporting) variable flg_export==1 if "new" exporting environ flg_export>1 if current startup environ (not call putenv()) */static int set_local_var(const char *s, int flg_export){ char *name, *value; int result=0; struct variables *cur;#ifdef __U_BOOT__ /* might be possible! */ if (!isalpha(*s)) return -1;#endif name=strdup(s);#ifdef __U_BOOT__ if (getenv(name) != NULL) { printf ("ERROR: " "There is a global environment variable with the same name.\n"); free(name); return -1; }#endif /* Assume when we enter this function that we are already in * NAME=VALUE format. So the first order of business is to * split 's' on the '=' into 'name' and 'value' */ value = strchr(name, '='); if (value==0 && ++value==0) { free(name); return -1; } *value++ = 0; for(cur = top_vars; cur; cur = cur->next) { if(strcmp(cur->name, name)==0) break; } if(cur) { if(strcmp(cur->value, value)==0) { if(flg_export>0 && cur->flg_export==0) cur->flg_export=flg_export; else result++; } else { if(cur->flg_read_only) { error_msg("%s: readonly variable", name); result = -1; } else { if(flg_export>0 || cur->flg_export>1) cur->flg_export=1; free(cur->value); cur->value = strdup(value); } } } else { cur = malloc(sizeof(struct variables)); if(!cur) { result = -1; } else { cur->name = strdup(name); if(cur->name == 0) { free(cur); result = -1; } else { struct variables *bottom = top_vars; cur->value = strdup(value); cur->next = 0; cur->flg_export = flg_export; cur->flg_read_only = 0; while(bottom->next) bottom=bottom->next; bottom->next = cur; } } }#ifndef __U_BOOT__ if(result==0 && cur->flg_export==1) { *(value-1) = '='; result = putenv(name); } else {#endif free(name);#ifndef __U_BOOT__ if(result>0) /* equivalent to previous set */ result = 0; }#endif return result;}#ifndef __U_BOOT__static void unset_local_var(const char *name){ struct variables *cur; if (name) { for (cur = top_vars; cur; cur=cur->next) { if(strcmp(cur->name, name)==0) break; } if(cur!=0) { struct variables *next = top_vars; if(cur->flg_read_only) { error_msg("%s: readonly variable", name); return; } else { if(cur->flg_export) unsetenv(cur->name); free(cur->name); free(cur->value); while (next->next != cur) next = next->next; next->next = cur->next; } free(cur); } }}#endifstatic int is_assignment(const char *s){ if (s == NULL) return 0; if (!isalpha(*s)) return 0; ++s; while(isalnum(*s) || *s=='_') ++s; return *s=='=';}#ifndef __U_BOOT__/* the src parameter allows us to peek forward to a possible &n syntax * for file descriptor duplication, e.g., "2>&1". * Return code is 0 normally, 1 if a syntax error is detected in src. * Resource errors (in xmalloc) cause the process to exit */static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input){ struct child_prog *child=ctx->child; struct redir_struct *redir = child->redirects; struct redir_struct *last_redir=NULL; /* Create a new redir_struct and drop it onto the end of the linked list */ while(redir) { last_redir=redir; redir=redir->next; } redir = xmalloc(sizeof(struct redir_struct)); redir->next=NULL; redir->word.gl_pathv=NULL; if (last_redir) { last_redir->next=redir; } else { child->redirects=redir; } redir->type=style; redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ; debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip); /* Check for a '2>&1' type redirect */ redir->dup = redirect_dup_num(input); if (redir->dup == -2) return 1; /* syntax error */ if (redir->dup != -1) { /* Erik had a check here that the file descriptor in question * is legit; I postpone that to "run time" * A "-" representation of "close me" shows up as a -3 here */ debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup); } else { /* We do _not_ try to open the file that src points to, * since we need to return and let src be expanded first. * Set ctx->pending_redirect, so we know what to do at the * end of the next parsed word. */ ctx->pending_redirect = redir; } return 0;}#endifstruct pipe *new_pipe(void) { struct pipe *pi; pi = xmalloc(sizeof(struct pipe)); pi->num_progs = 0; pi->progs = NULL; pi->next = NULL; pi->followup = 0; /* invalid */ pi->r_mode = RES_NONE; return pi;}static void initialize_context(struct p_context *ctx){ ctx->pipe=NULL;#ifndef __U_BOOT__ ctx->pending_redirect=NULL;#endif ctx->child=NULL; ctx->list_head=new_pipe(); ctx->pipe=ctx->list_head; ctx->w=RES_NONE; ctx->stack=NULL;#ifdef __U_BOOT__ ctx->old_flag=0;#endif done_command(ctx); /* creates the memory for working child */}/* normal return is 0 * if a reserved word is found, and processed, return 1 * should handle if, then, elif, else, fi, for, while, until, do, done. * case, function, and select are obnoxious, save those for later. */struct reserved_combo { char *literal; int code; long flag;};/* Mostly a list of accepted follow-up reserved words. * FLAG_END means we are done with the sequence, and are ready * to turn the compound list into a command. * FLAG_START means the word must start a new compound list. */static struct reserved_combo reserved_list[] = { { "if", RES_IF, FLAG_THEN | FLAG_START }, { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, { "elif", RES_ELIF, FLAG_THEN }, { "else", RES_ELSE, FLAG_FI }, { "fi", RES_FI, FLAG_END }, { "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 }};#define NRES (sizeof(reserved_list)/sizeof(struct reserved_combo))int reserved_word(o_string *dest, struct p_context *ctx){ struc
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -