static enum ParserResult parsePipeline(struct Parser* parser, struct Pipeline* pipeline) { pipeline->commands = NULL; pipeline->numCommands = 0; pipeline->bang = false; enum ParserResult result; struct Token* token = getToken(parser); if (!token) return PARSER_SYNTAX; while (token->type == TOKEN && strcmp(token->text, "!") == 0) { pipeline->bang = !pipeline->bang; parser->offset++; token = getToken(parser); if (!token) return PARSER_SYNTAX; } while (true) { struct SimpleCommand command; result = parseSimpleCommand(parser, &command); if (result != PARSER_MATCH) goto fail; if (!addToArray((void**) &pipeline->commands, &pipeline->numCommands, &command, sizeof(command))) { result = PARSER_ERROR; goto fail; } token = getToken(parser); if (!token) return PARSER_MATCH; if (token->type != OPERATOR || strcmp(token->text, "|") != 0) { return PARSER_MATCH; } parser->offset++; token = getToken(parser); if (!token) { result = PARSER_SYNTAX; goto fail; } while (token->type == OPERATOR && strcmp(token->text, "\n") == 0) { parser->offset++; token = getToken(parser); if (!token) { result = PARSER_NEWLINE; goto fail; } } } return PARSER_MATCH; fail: freePipeline(pipeline); return result; }
void freePipeline(pipeline* pl) { if(pl->next != NULL) { freePipeline(pl->next); } if(pl->command != NULL) { free(pl->command->args); free(pl->command); } free(pl); }
void execTokens(int numTokens, char** tokens) { pipeline* pl = malloc(sizeof(pipeline)); pl->next = NULL; pl->command = NULL; pipeline* lastPipe = pl; bool hasFileIn = false; int fileIn[2]; // pretends to be a pipe to pass to execSimple // actually just a regular array bool hasSpecial = false; int i; for(i = 0; i < numTokens; hasSpecial = false) { simpleCmd* cmd = malloc(sizeof(simpleCmd)); cmd->name = tokens[i]; // allocate enough space for all remaining tokens, plus null terminator // this will be more than we need in many cases, but it's easy cmd->args = (char**) malloc((numTokens - i + 1) * sizeof(char*)); int j; for(j = 0; j < numTokens - i; j++) { if (isSpecialToken(tokens[i + j])) { hasSpecial = true; break; } cmd->args[j] = tokens[i + j]; } i += j; // advances i to the next token to read if (hasSpecial) { specials: switch(tokens[i][0]) { // deal w/ special token: // '|' -> advance past to next token case '|' : i++; break; // '<' -> open file desriptor, set up pipe case '<' : { i++; if(i >= numTokens) { fprintf(stderr, "%s", "quash: syntax error after '<'\n"); return; } char* filename = tokens[i]; int fd = open(filename, O_RDONLY); if(fd < 0) { fprintf(stderr, "quash: could not open file: %s\n", filename); return; } hasFileIn = true; fileIn[0]=fd; fileIn[1]=fd; i++; // should be followed by a special symbol // rather than a commaand, so jump to the // appropriate place unless we are at the end if(i < numTokens) { goto specials; } break; } // '>' -> convert to new builtin (writef) case '>' : if (tokens[i][1] == '>') { tokens[i] = "appendf"; } else { tokens[i] = "writef"; } break; // '&' -> ? (deal w/ later? Should only occur at end) : dealt with in main } } cmd->args[j] = NULL; pipeline* nextPipe = malloc(sizeof(pipeline)); nextPipe->command = cmd; nextPipe->next = NULL; lastPipe->next = nextPipe; lastPipe = nextPipe; } // drop dummy block, pass null for stdin runPipeline(pl->next, hasFileIn ? fileIn : NULL); freePipeline(pl); if(hasFileIn) { close(fileIn[0]); } }
void freeCompleteCommand(struct CompleteCommand* command) { freePipeline(&command->pipeline); }