/* * Csh - a shell by PJAC - parse.c the command line parser */ #include "csh.h" #define LESS_LESS 2 #define MORE_MORE 3 #define MORE_AND 4 #define MORE_MAND 5 parse(in_line, treep) char *in_line; struct cmd **treep; { char *p, **xp; char *q; int c; struct cmd *cur_tree; char cur_arg[256]; char nxt_arg[256]; int narg; struct cmd *newtree(); struct cmd *tree_top, *tp; cur_tree = newtree(); /* get a new tree */ tree_top = cur_tree; for(p = in_line ; p = skipsp(p) ; ){ switch(next_object(cur_arg, &p, nxt_arg, noglob)){ case COMMENT: p = ""; /* YEUCH, cheat to end of line */ continue; case GLOBER: do { un_spec(nxt_arg); Args[Argc++] = strsave(nxt_arg); } while(explode( (char *)0, nxt_arg)); break; case NORMAL: /* normal string */ un_spec(cur_arg); Args[Argc++] = strsave(cur_arg); continue; case SPECIAL: /* * else it's a special char */ switch(c = *p++){ case '<': if(*p == '<'){ c = LESS_LESS; p++; break; } if(!(p = skipsp(p))) goto bad; switch(next_object(cur_arg, &p, nxt_arg, noglob)){ case GLOBER: if(!explode( (char *)0, nxt_arg)){ strcpy(cur_arg, nxt_arg); break; } /* fall through */ case SPECIAL: case COMMENT: goto bad; } un_spec(cur_arg); if(cur_tree->cm_ifile) goto bad; cur_tree->cm_ifile = strsave(cur_arg); break; case '>': if(*p == '>'){ if(*++p == '&'){ c = MORE_MAND; p++; } else c = MORE_MORE; } else if(*p == '&'){ c = MORE_AND; p++; } if(!(p = skipsp(p))) goto bad; switch(next_object(cur_arg, &p, nxt_arg, noglob)){ case GLOBER: if(!explode( (char *)0, nxt_arg)){ strcpy(cur_arg, nxt_arg); break; } /* fall through */ case SPECIAL: case COMMENT: goto bad; } un_spec(cur_arg); if(cur_tree->cm_ofile) goto bad; q = mmalloc(strlen(cur_arg) + 1 + 2); /* convert from user to internal rep */ switch(c){ case '>': *q = 0; break; case MORE_AND: strcpy(q, "&"); break; case MORE_MAND: strcpy(q, "&>"); break; case MORE_MORE: strcpy(q, ">"); break; } strcat(q, cur_arg); cur_tree->cm_ofile = q; break; case '|': if(cur_tree->cm_ofile) free(cur_tree->cm_ofile); if(*p == '&'){ p++; cur_tree->cm_ofile = strsave("|&"); } else cur_tree->cm_ofile = strsave("|"); if(save_args(cur_tree)) goto bad; tp = cur_tree; cur_tree = newtree(); tp->cm_next = cur_tree; cur_tree->cm_parent = tp->cm_parent; cur_tree->cm_ifile = strsave("|"); break; case '(': /* if not first char of command then * assume it is like any other char */ if(Argc != cur_tree->cm_savc){ Args[Argc++] = strsave("("); continue; } /* if we have been down before, give * a syntax error */ if(cur_tree->cm_child) goto bad; tp = cur_tree; cur_tree = newtree(); tp->cm_child = cur_tree; cur_tree->cm_parent = tp; break; case ')': if(cur_tree->cm_parent == 0){ Args[Argc++] = strsave(")"); continue; } if(save_args(cur_tree)) goto bad; cur_tree = cur_tree->cm_parent; break; case ';': case '&': /* treat & same as ';' */ /* * store away the args, * get a new node * link and remember to copy over the * same parent */ if(save_args(cur_tree)) goto bad; tp = cur_tree; cur_tree = newtree(); tp->cm_next = cur_tree; cur_tree->cm_parent = tp->cm_parent; break; case '`': break; } /* end of special chars */ break; } } if(p) goto bad; for(tp = tree_top ; tp ; tp = tp->cm_next) if(tp == cur_tree) break; if(!tp) goto bad; if(save_args(cur_tree)) goto bad; if(tree_top->cm_argc || tree_top->cm_next || tree_top->cm_child || tree_top->cm_ifile || tree_top->cm_ofile) *treep = tree_top; else free_tree(tree_top); return; bad:; free_tree(tree_top); syn_err(); } save_args(cur_tree) struct cmd *cur_tree; { int narg; narg = Argc - cur_tree->cm_savc; if(!narg) return(OK); if(cur_tree->cm_argv != 0) return(ERR); cur_tree->cm_argv = (char **)mmalloc(sizeof(char *)* (narg+1)); cur_tree->cm_argv[narg] = 0; cur_tree->cm_argc = narg; while(narg) cur_tree->cm_argv[--narg] = Args[--Argc]; return(OK); } struct cmd * newtree() { struct cmd *cp; cp = (struct cmd *)mmalloc(sizeof(struct cmd)); cp->cm_argv = 0; cp->cm_next = 0; cp->cm_child = 0; cp->cm_parent = 0; /* don't recurse down the parent */ cp->cm_ifile = 0; cp->cm_ofile = 0; cp->cm_argc = 0; cp->cm_savc = Argc; return(cp); } free_tree(cp) struct cmd *cp; { int i; if(cp->cm_next) free_tree(cp->cm_next); if(cp->cm_child) free_tree(cp->cm_child); if(cp->cm_ifile) free(cp->cm_ifile); if(cp->cm_ofile) free(cp->cm_ofile); for(i = 0; i < cp->cm_argc ; i++) free(cp->cm_argv[i]); free( (char *)cp); } /* * called on syntax error */ syn_err() { while(Argc > 0){ if(Args[--Argc]){ free(Args[Argc]); Args[Argc] = 0; } } longjmp(env_main, BADPARSE); } next_object(buf, strp, nxt_arg, nglob) char *buf, **strp, *nxt_arg; { char *bufp = buf; char *str = *strp; int c; int seenb = FALSE; if(*str == '#') return(COMMENT); if(index(Special, *str) != NULL){ if(*str == '"' || *str == '\''){ c = *str++; while(*str){ if(*str == c) break; *buf++ = *str++ | 0200; } *buf = 0; if(*str++ == '\0') syn_err(); *strp = str; return(NORMAL); } return(SPECIAL); } *buf++ = *str++; while(*str){ if(index(IFS, *str)) break; if(*str == '{') seenb = TRUE; else if(*str == '}'){ if(!seenb) break; } else if(index(Special, *str)) break; *buf++ = *str++; } *buf = 0; *strp = str; if(!nglob){ /* * explode ~ strings */ if(*bufp == '~' && (bufp[1] == '/' || bufp[1] == '\\' || bufp[1] == '\0')){ strcpy(nxt_arg, bufp+1); strcpy(bufp, HOME); strcat(bufp, nxt_arg); } for(str = "*?[]" ; *str ; str++) if(index(bufp, *str)){ if(explode(bufp, nxt_arg)) /* explode args */ return(GLOBER); break; } } return(NORMAL); }