// Executes a <pipeline> rooted with cmd and returns the status of the last // command executed. int processPipeline(CMD* cmd) { assert(cmd); assert(ISPIPE(cmd->type) || cmd->type == SIMPLE || cmd->type == SUBCMD); if(ISPIPE(cmd->type)) { int pipeStatus = execPipe(cmd); updateStatusVar(pipeStatus); return pipeStatus; } else { return processStage(cmd); } }
/* use: process a <pipeline> args: cmd = root of command tree fdin = input file descriptor return: status of process */ int processPipe(CMD *cmd, int fdin, bool suppress) { int status; // status of process // <stage> | <pipeline> case if (cmd->type == PIPE) { int fd[2]; // file descriptors // build the pipe if (pipe(fd) == -1) { status = errno; errorExit(status); } // built-in command if (isSpecial(cmd->left)) { processSpecial(cmd->left, true); status = processPipe(cmd->right, fd[0], true); return setStat(status); } pid_t pID = fork(); // process ID of fork // error check if (pID < 0) { status = errno; errorExit(status); } // child process else if (pID == 0) { // update input if (fdin != 0) { dup2(fdin, 0); close(fdin); } // update output close(fd[0]); dup2(fd[1], 1); close(fd[1]); // left side of pipe status = processStage(cmd->left); } // parent process else { // close file descriptors if (fdin != 0) { close(fdin); } close(fd[1]); // right side of pipe int temp = processPipe(cmd->right, fd[0], true); // close last file descriptor close(fd[0]); // wait for child process to finish (void) signal(SIGINT, SIG_IGN); waitpid(pID, &status, 0); // update status if (status == 0) { status = temp; } else { status = (WIFEXITED(status) ? WEXITSTATUS(status) : 128+WTERMSIG(status)); } (void) signal(SIGINT, SIG_DFL); } } // <stage> case else { // built-in command if (isSpecial(cmd)) { if (suppress) { status = processSpecial(cmd, true); } else { status = processSpecial(cmd, false); } return setStat(status); } pid_t pID = fork(); // process ID of fork // error check if (pID < 0) { status = errno; errorExit(status); } // child process else if (pID == 0) { // update input if (fdin != 0) { dup2(fdin, 0); close(fdin); } status = processStage(cmd); } // parent process else { //close input if (fdin != 0) { close(fdin); } // wait for child process to finish (void) signal(SIGINT, SIG_IGN); waitpid(pID, &status, 0); // update status status = (WIFEXITED(status) ? WEXITSTATUS(status) : 128+WTERMSIG(status)); (void) signal(SIGINT, SIG_DFL); } } return setStat(status); }
char SWBasicFilter::processText(std::string &text, const SWKey *key, const SWModule *module) { char *from; char token[4096]; int tokpos = 0; bool intoken = false; bool inEsc = false; int escStartPos = 0, escEndPos = 0; int tokenStartPos = 0, tokenEndPos = 0; std::string lastTextNode; BasicFilterUserData *userData = createUserData(module, key); std::string orig = text; from = &orig[0u]; text = ""; if (processStages & INITIALIZE) { if (processStage(INITIALIZE, text, from, userData)) { // processStage handled it all delete userData; return 0; } } for (;*from; from++) { if (processStages & PRECHAR) { if (processStage(PRECHAR, text, from, userData)) // processStage handled this char continue; } if (*from == tokenStart[tokenStartPos]) { if (tokenStartPos == (tokenStartLen - 1)) { intoken = true; tokpos = 0; token[0] = 0; token[1] = 0; token[2] = 0; inEsc = false; } else tokenStartPos++; continue; } if (*from == escStart[escStartPos]) { if (escStartPos == (escStartLen - 1)) { intoken = true; tokpos = 0; token[0] = 0; token[1] = 0; token[2] = 0; inEsc = true; } else escStartPos++; continue; } if (inEsc) { if (*from == escEnd[escEndPos]) { if (escEndPos == (escEndLen - 1)) { intoken = inEsc = false; userData->lastTextNode = lastTextNode; if (!userData->suspendTextPassThru) { //if text through is disabled no tokens should pass, too if ((!handleEscapeString(text, token, userData)) && (passThruUnknownEsc)) { appendEscapeString(text, token); } } escEndPos = escStartPos = tokenEndPos = tokenStartPos = 0; lastTextNode = ""; continue; } } } if (!inEsc) { if (*from == tokenEnd[tokenEndPos]) { if (tokenEndPos == (tokenEndLen - 1)) { intoken = false; userData->lastTextNode = lastTextNode; if ((!handleToken(text, token, userData)) && (passThruUnknownToken)) { text += tokenStart; text += token; text += tokenEnd; } escEndPos = escStartPos = tokenEndPos = tokenStartPos = 0; lastTextNode = ""; continue; } } } if (intoken) { if (tokpos < 4090) { token[tokpos++] = *from; token[tokpos+2] = 0; } } else { if ((!userData->supressAdjacentWhitespace) || (*from != ' ')) { if (!userData->suspendTextPassThru) { text.push_back(*from); userData->lastSuspendSegment.clear(); } else userData->lastSuspendSegment.push_back(*from); lastTextNode.push_back(*from); } userData->supressAdjacentWhitespace = false; } if (processStages & POSTCHAR) processStage(POSTCHAR, text, from, userData); } if (processStages & FINALIZE) processStage(FINALIZE, text, from, userData); delete userData; return 0; }
// Executes a pipeline and returns the exit status of the pipe. The arg // pipeRoot is the PIPE or PIPE_ERR command at the root of the pipeline. // This function draws upon code from Professor Stan Eisenstat at Yale // University int execPipe(CMD* pipeRoot) { // count the number of stages in the pipeline int numStages = 1; for(CMD* cmd = pipeRoot; ISPIPE(cmd->type); cmd = cmd->right, numStages++); // create table to hold pid and exit status of all stages in the pipe struct { int pid, status; } processTable[numStages]; int fd[2]; // holds file descriptors for the pipe int pid, status; // the pid and status of a single stage int fdIn = STDIN_FD; // the read end of the last pipe, or the original // stdin CMD* cmd = pipeRoot; for(int i = 0; ISPIPE(cmd->type); cmd = cmd->right, i++) { if(pipe(fd) < 0 || (pid = fork()) < 0) { perror(EXEC_NAME); return errno; } else if(pid == 0) { // child close(fd[0]); // redirect stdin to the last pipe read (if there was a last pipe) if(fdIn != STDIN_FD) { dup2(fdIn, STDIN_FD); close(fdIn); } bool shouldCloseFD1 = false; // redirect stdout to the new pipe write (if it's not stdout) if(fd[1] != STDOUT_FD) { dup2(fd[1], STDOUT_FD); shouldCloseFD1 = true; } // if this is a PIPE_ERR, redirect stderr to the new pipe write // (if it's not stderr) if(cmd->type == PIPE_ERR && fd[1] != STDERR_FD) { dup2(fd[1], STDERR_FD); shouldCloseFD1 = true; } if(shouldCloseFD1) close(fd[1]); exit(processStage(cmd->left)); } else { // parent processTable[i].pid = pid; // close the read end of the last pipe if it's not the orig stdin if(i > 0) { close(fdIn); } fdIn = fd[0]; // remember the read end of the new pipe close(fd[1]); } } // cmd is now the right child of last PIPE or PIPE_ERR, the last stage of // the pipeline // if the last stage is a built-in command, it should affect the parent // shell, so execute it here instead of forking off a process if(cmd->type == SIMPLE && IS_BUILTIN(cmd->argv[0])) { processTable[numStages - 1].pid = -1; // unused pid processTable[numStages - 1].status = processSimple(cmd, false); close(fdIn); } else if((pid = fork()) < 0) { perror(EXEC_NAME); return errno; } else if(pid == 0) { // child if(fdIn != STDIN_FD) { dup2(fdIn, STDIN_FD); close(fdIn); } exit(processStage(cmd)); } else { // parent processTable[numStages - 1].pid = pid; close(fdIn); } // wait for children to die signal(SIGINT, SIG_IGN); for(int i = 0; i < numStages; ) { pid = wait(&status); int j; for(j = 0; j < numStages && processTable[j].pid != pid; j++); // only add to the processTable if the child's pid is in the table; // that is, ignore zombies if(j < numStages) { processTable[j].status = status; i++; } } signal(SIGINT, SIG_DFL); for(int i = 0; i < numStages; i++) { if(GET_STATUS(processTable[i].status) != 0) { return GET_STATUS(processTable[i].status); } } return 0; }