简体   繁体   中英

The output still remain in buffer and print out after each child process

My situation is the output print "p2: " each time the child processes.

When I type a command line "echo NULL; echo void". My parse() will split each word and assign to *newargv[] by using getword() function. The getword(char *w) is basically split each word in command line. In my situation, the ";" is treat as a newline character. Getword(char * w) will return '\\0' when it encounters the semi-colon.

The output when I run the program. p2: echo NULL;echo void NULL void p2: p2:

I thought it will need to flush output buffer and tried fflush(stdout). But it doesn't work.

Here is my p2.c and 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

Here 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();

Here getword.c and 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);

the following code:

  1. corrects the problems listed in the comments and exposed by the compiler.
  2. cleanly compiles
  3. documents why each header file is being included
  4. keeps data declarations local to where they are used
  5. is not a complete answer because you have not indicated what you want to trigger the code to exit.

And now the code:

#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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM