//parses a stage, returning a command struct //modifies global variable t CMD *stage() { CMD *tmp; CMD *cmd = 0; if (!t) return 0; tmp = mallocCMD(); while (t && (ISREDOUT(t->type) || ISREDIN(t->type))) tmp = redirect(tmp); if (!tmp) return 0; else if (!t) { DIE("Parse: null command\n"); return 0; } else if (t->type == PAR_LEFT) { cmd = mallocCMD(); cmd->type = SUBCMD; t = t->next; cmd->left = command(); if (!cmd->left) { DIE("Parse: null command\n"); freeCMD(cmd); return 0; } else if (!t || t->type != PAR_RIGHT) { DIE("Parse: unbalanced parens\n"); freeCMD(cmd); return 0; } else { t = t->next; while(t && cmd && (ISREDOUT(t->type) || ISREDIN(t->type))) cmd = redirect(cmd); } } else cmd = simple(); cmd = merge(cmd, tmp); freeCMD(tmp); return cmd; }
//parses a SIMPLE statement, returning command struct //modifies global variable t CMD *simple() { CMD *cmd; cmd = mallocCMD(); cmd->type = SIMPLE; while (t && cmd != NULL) { if (t->type == SIMPLE) { (cmd->argc)++; cmd->argv = realloc(cmd->argv, sizeof(char*) * (cmd->argc + 1)); cmd->argv[cmd->argc] = 0; cmd->argv[cmd->argc - 1] = malloc(strlen(t->text) + 1); strcpy(cmd->argv[cmd->argc - 1], t->text); t = t->next; } else if (ISREDOUT(t->type) || ISREDIN(t->type)) cmd = redirect(cmd); else break; } if (!cmd || !cmd->argc) return 0; else return cmd; }
//handles redirect statements for stage and simple //input is a command struct, output is same struct with changed i/o CMD *redirect(CMD* cmd) { if (ISREDOUT(t->type)) { if (cmd->toType != NONE) { DIE("Parse: two output redirects\n"); freeCMD(cmd); return 0; } cmd->toType = t->type; t = t->next; if (!t || t->type != SIMPLE) { DIE("Parse: missing filename\n"); freeCMD(cmd); return 0; } cmd->toFile = malloc(strlen(t->text) + 1); strcpy(cmd->toFile, t->text); t = t->next; } else if (t->type == RED_IN || t->type == RED_HERE) { if (cmd->fromType != NONE) { DIE("Parse: two input redirects\n"); freeCMD(cmd); return 0; } cmd->fromType = t->type; t = t->next; if (!t || t->type != SIMPLE) { DIE("Parse: missing filename\n"); freeCMD(cmd); return 0; } if (cmd->fromType == RED_IN) { cmd->fromFile = malloc(strlen(t->text) + 1); strcpy(cmd->fromFile, t->text); } else { cmd->fromFile = hereDoc(t->text); } t = t->next; } return cmd; }
CMD* make_stage(token_list** list_ref) { token_list* list = *list_ref; if (!list) return make_error_cmd("could not form stage (no tokens)"); CMD* stage_tree = mallocCMD(); // Current type is NONE int next_type = NONE; // Hold the type of the head token of list bool redir_in = false; // Has there been a previous input redirection? bool redir_out = false; // Loop until hit a pipe or a separator; raise an error if multiple redirect // or both a command and subcommand while ((next_type = type(list)) != -1 && !ISSEP(next_type) && !ISPIPE(next_type) && next_type != PAR_RIGHT) { bool error = false; // Signals whether the current action results in an // error if (next_type == SIMPLE && stage_tree->type != SUBCMD) { int argc = stage_tree->argc + 1; char** argv = stage_tree->argv; argv = realloc(argv, (argc + 1) * sizeof(char*)); // +1 for trailing // NULL required // by freeCMD argv[argc - 1] = strdup(text(list)); argv[argc] = NULL; stage_tree->argc = argc; stage_tree->argv = argv; stage_tree->type = SIMPLE; } else if ((next_type == RED_IN || next_type == RED_HERE) && !redir_in) { error = make_redirect(stage_tree, &redir_in, next_type, &list); } else if (ISREDOUT(next_type) && !redir_out) { error = make_redirect(stage_tree, &redir_out, next_type, &list); } else if (next_type == PAR_LEFT && stage_tree->type == NONE) { // Can't have two subcommands in a stage advance(&list); // Advance past left parentheses CMD* subcmd_tree = make_cmd(&list); error = subcmd_tree->type == ERROR || type(list) != PAR_RIGHT; stage_tree->type = SUBCMD; stage_tree->left = subcmd_tree; } else { error = true; } if (error) { freeCMD(stage_tree); return make_error_cmd("Invalid stage"); } advance(&list); } // Make sure we didn't double-redirect if (ISPIPE(next_type) && redir_out) { freeCMD(stage_tree); return make_error_cmd("Double redirect - pipe and >"); } // Make sure there was actually an argument if (stage_tree->type == NONE) { freeCMD(stage_tree); return make_error_cmd("No arguments for simple command"); } assert(stage_tree->type != NONE); *list_ref = list; return stage_tree; }