输出仍保留在缓冲区中,并在每个子进程后打印出来

时间:2017-10-01 18:08:48

标签: c shell unix operating-system

每次孩子处理时,我的情况是输出打印“p2:”。

当我输入命令行“echo NULL; echo void”时。我的parse()将拆分每个单词并使用getword()函数分配给* newargv []。 getword(char * w)基本上是在命令行中分割每个单词。在我的情况下,“;”被视为换行符。 Getword(char * w)在遇到分号时会返回'\ 0'。

运行程序时的输出。     p2:echo NULL; echo void     空值     空虚     p2:p2:

我认为需要刷新输出缓冲区并尝试fflush(stdout)。但它不起作用。

这是我的p2.c和p2.h

#include <stdio.h>
#include "p2.h"
#define MAXITEM 100 /* max number of words per line */


int BGFLAG = 0, INFLAG = 0, OUTFLAG = 0, AMFLAG = 0, SEMIFLAG = 0, PIPEFLAG = 0;
char argv[255]; //this array get a string from getword function
char *newargv[MAXITEM]; //this pointer array will keep the first character of argv array
char *in, *out; //pointers point to file in argv
int sizeC = 0; //check if it is EOF or not
int parse();

int main()
{
    int argc;
    signal(SIGTERM,myhandler);

    for (;;)
    {
        printf("p2: ");
        pid_t pid, child_pid;
        int status; 
        //call parse function
        argc = parse();

        if (sizeC == -1)
            break;
        if (argc == 0) //reissue prompt if line is empty
            continue;
        if (newargv[0] == NULL){
            fprintf(stderr, "Invalid command");
            continue;
        }

        child_pid = fork();
        if (child_pid < 0){
            printf("ERROR! can't fork\n");
            exit(1);
        }
        else if(child_pid == 0){ //return a new child process
            execvp(*newargv,newargv);
            printf("ERROR exec failed\n");
            exit(1);
        }
        else {
            pid = wait(NULL);
            if (pid == child_pid)
                continue;
        }


    }//end for
        killpg(getpgrp(),SIGTERM);
        printf("p2 terminated. \n");
        exit(0);

}// main

int parse()
{
    int p = 0; 

    //this pointer will keep track the argv array for each of loops
    //the getword function will not overwrite the argv array
    int ptr = 0; 
    int count = 0;
    SEMIFLAG = 0;
    int wCount = 0; //return the number of argc
    int semiColon = 0;


    /* Read from stdin to argv array. The ptr will keep track the argv array
        If it is meta character, set a flag appropriately. Otherwise,
        set the address of first char of argv to the newargv*/
    while ((sizeC = getword(argv + ptr)) > 0)
    {
        if(sizeC == 0){
            semiColon++;
            continue;
        }else{
            //Put the address of first char of each argv to the pointer array
            newargv[p] = argv + ptr;
            p++;
        }

        argv[ptr + sizeC] = '\0';
        //point to the next address of next word in argv, the getword will not overwrite the argv array
        ptr = ptr + sizeC + 1;
        wCount++;


    }//end while

    newargv[p] = NULL;
    return wCount;

}//end parse

void myhandler(){

}//end myhandler

这里是p2.h

#include <stdio.h>
#include "getword.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <signal.h>

#define MAXITEM 100


int parse();

void myhandler();

这里是getword.c和getword.h

#include <stdio.h>
#include "getword.h"


int getword(char *w)
{
    int count = 0; //represent how many characters are read
    char iochar;
    int flag = 0; // identify a pair of single quote

    //set an infinite loop
    while (1)
    {
        iochar = getchar(); //This variable stores a character from stdin

        /*  If the array is full, the character will put back for next call.
            Return (STORAGE -1) characters*/
        if (count >= (STORAGE -1))
        {
            ungetc(iochar,stdin);
            w[count] = '\0';
            return count;
        }

        /* This block code will eleminate the leading tab */
        if (iochar == '\t') //ignore the tabs if it counters
            continue;

        /* Identify if the function hit EOF */
        if (iochar == EOF)
        {
            /* Return an empty string and -1 for size of string array
               Because the EOF put back when count > 0 and the getword() encounters right away at next call
               Therefore, the count is 0.*/
            if (count == 0)
            {
                w[count] = '\0';
                return -1;
            }
            /*  The getword() read some characters before hitting EOF
                Set a null terminator to finish a string array.
                Return the size of string array.
                Put the EOF back to stdin for next call
                to print the EOF*/
            if (count > 0)
            {
                w[count] = '\0';
                ungetc(iochar,stdin);
                return count;
            }
        }

        /*  For backslash case, treat all metacharacter 
            and space character as a normal character
            The ";" and newline char will not effect meaning of that newline
            */
        if (iochar == '\\')
        {
            //identify next character is meta-char,
            //or normal char or a single quote
            char nextC = getchar();

            /* Only put a meta-character or space into the array
                the blackslash is ignored 
                flag = 0 means the SINGLE QUOTE MOD is OFF*/
            if ((nextC == '\'' || nextC == '!' || nextC  == '>' || 
                nextC == '&' || nextC == ' ' || nextC == '\\' || nextC == '\t') 
                && flag == 0)
            {
                w[count++] = nextC;
                continue;
            }
            /*  As in a pair of single quote
                slash and meta char both put in the array
                flag = 1 means the SINGLE QUOTE MOD is ON.
                The metacharacter and backslash are treat as normal char*/
            else if ( (nextC == '!' || nextC  == '>' || 
                nextC == '&' || nextC == ' ' || nextC == '\\' || nextC ==';') 
                && flag == 1)
            {
                w[count++] = iochar;
                w[count++] = nextC;
                continue;
            }
            //the single quote character in a pair of single quote
            //treat as a normal character
            else if (nextC == '\'' && flag == 1)
            {
                w[count++] = nextC;
                continue;
            }

            //return the string if it encounters new line
            //put nextC back to stdin for next call
            //because we need to print out to determine the new line exist
            else if (nextC == '\n' || nextC == ';')
            {
                w[count] = '\0';
                ungetc(nextC,stdin);
                return count;
            }
            else
            //the normal character is put into the string array
            {
                w[count++] = nextC;
                continue;
            }
        }// end if blacknextC

        /*  Identify Space case 
            Treat a space char as a normal char if it's in a pair of single quotes.
            Treat a space char as a delimeter if it's not in a pair of single quotes*/
        if (iochar == ' ')
        {
            if (flag == 1) //SINGLE QUOTE MOD is ON
            {   
                w[count++] = iochar; //space is treat as normal character instead of a delimeter
                continue;
            }
            else if (count == 0)//ignore if it is leading char or space char
                continue;
            else
            {   
                /*Set a null delimeter and return the size of the array
                    This case space is a delimeter*/
                w[count] = '\0'; 
                return count;
            }
        }// end if space

        /*  This block of codes will identify the single quote case*/
        if (iochar == '\'')
        {
            //read the character after single quote to determine 
            //it is a newline or normal character or metacharacter
            char c = getchar();

            /*  Detect the open quote
                If it is not newline or delimeter char, put it back to stdin for next call
                and move on*/
            if (flag == 0 && (c != '>' || c !=  '<' || c !=  '!' || c !=  '&' 
                    || c !=  '|' || c !=  ' ' || c != ';' || c !='\n'))
            {
                flag = 1;
                ungetc(c,stdin);
                continue;
            }
            /*  Detect the closed quote. Set flag on.
                Put the character back to stdin and move on*/
            else if (flag == 1 && (c != '>' || c !=  '<' || c !=  '!' || c !=  '&' || c !=  '|' || c !=  ' ' || c != ';' || c !='\n'))
            {
                //Set single quote mod back to normal(OFF) (flag = 0)
                //get the character back to stdin for next call to read as normal character
                flag = 0;
                ungetc(c,stdin);
                continue;
            }
            /*  if it hit a new line, set a null delimeter to terminate the array
                return size of the string array.
                the newline char is put back to stdin to print out nextcall*/
            else                
            {
                w[count] = '\0';
                ungetc(c,stdin);
                return count;
            }
        }//end if single quote

        /*  This code handle when the character is meta-character
            It is considered as a delimeter character */
        if (iochar == '>' || iochar == '<' || iochar == '!' 
            || iochar == ';' || iochar == '\n' || iochar == '&' || iochar == '|')
        {
            /*  Special character ">!" 
                Need to read next character to identify "!" */
            if (iochar == '>')
            {
                char c = getchar();

                /*  return the string if is "!". It becomes a delimeter
                    put two characters back to stdin for next getword() call.
                    Return the size of string array before the special char*/
                if ( c == '!' && count > 0)
                {
                    w[count] = '\0';
                    ungetc(c,stdin);    
                    ungetc(iochar,stdin);
                    return count;
                }

                //Return size and the special character ">!"
                if (c == '!' && count == 0)
                {
                    w[count++] = iochar; //iochar = ">"
                    w[count++] = c; //c = "!"
                    w[count] = '\0';
                    return count;
                }

                /*  Put c and iochar back to stdin for next call
                    make sure in order, ">" need to be read first to print out the ">" char
                    The delimeter is only ">". Return the size of string array before ">"*/
                if ( c != '!' && count > 0)
                {
                    ungetc(c,stdin);
                    ungetc(iochar,stdin);
                    w[count] = '\0';
                    return count;
                }
                //put the ">" in to the array
                //make sure put the non-"!" back to stdin for next call
                //Return the meta-character ">" and size = 1
                if ( c != '!' && count == 0)
                {
                    ungetc(c,stdin);
                    w[count++] = iochar;
                    w[count] = '\0';
                    return count;
                }

            }

            /* This code identify when the character is a new line "\n" or ";" */
            if (iochar == '\n' || iochar == ';')
            {
                if (count == 0) // return an empty string
                {
                    w[count] = '\0';
                    return 0;
                }
                /*  Return a string array after newline
                    Put newline back to stdin for next call
                    to print out*/
                if (count > 0) 
                {
                    w[count] = '\0';
                    ungetc(iochar,stdin);
                    return count;
                }
            }

            /*  This code block handle the rest of the metacharacter.
                Return the size of 1 and that metacharacter if count = 0.
                Set null delimeter and return string array before the metacharacter.
                Put the metacharacter back to stdin for next call to print out.*/
            if (iochar == '<' || iochar == '!' || iochar == '&' || iochar == '|')
            {
                //return the delimeter and size of 1.
                if (count == 0)
                {
                    w[count++] = iochar;
                    w[count] = '\0';
                    return count;
                }
                /*  Set null delimiter to and return size of 1 and string array.
                    put the meta-character back to stdin for next call to get the meta-character */
                if (count > 0)
                {
                    w[count] = '\0';
                    ungetc(iochar,stdin);
                    return count;
                }
            }
        }//end if meta case

        /*  After handling all situation, this character is normal. 
            Put the normal character to the string array */
        w[count++] = iochar;

    }//end while
}// getword

getword.h

#include <stdio.h>
#include <string.h>
#include <strings.h>

#define STORAGE 255
      /* This is one more than the max wordsize that getword() can handle */

int getword(char *w);

1 个答案:

答案 0 :(得分:0)

以下代码:

  1. 更正注释中列出的问题并由编译器公开。
  2. 干净地编译
  3. 记录了为什么要包含每个头文件
  4. 将数据声明保持在本地使用位置
  5. 不是一个完整的答案,因为您没有说明要触发代码退出的内容。
  6. 现在代码:

    #include <stdio.h>     // perror(), printf()
    #include <stdlib.h>    // exit(), EXIT_FAILURE
    #include <unistd.h>    // execvp(), fork(), pid_t
    #include <sys/types.h>
    #include <sys/wait.h>  // waitpid()
    
    
    char **parse( void );
    
    int main( void )
    {
        for (;;)
        {
            printf("p2: ");
            //pid_t pid;
            pid_t child_pid;
            //int status;
    
            //call parse function
            char **argv = parse();
    
    
            child_pid = fork(); //fork a child process
    
            if(child_pid < 0)
            { // then error occurred
                perror( "fork failed" );
                //printf("ERROR: can't fork! exec failed\n");
                //exit(1);
                exit( EXIT_FAILURE );
            }
    
            else if (child_pid == 0)
            { // then child process
    
                execvp( argv[0], argv );
                perror( "execvp failed" );
                exit(1);
            }
    
            else
            { // parent process
                int status;
                waitpid( child_pid, &status, 0);
            }
    
        }//end for
    
    }// main