How to flush stdin without requiring user input? [duplicate]

岁酱吖の 提交于 2021-02-08 19:41:43

问题


I'm trying to simulate a command line shell. The user inputs a shell command they want to input, e.g. /bin/pwd and the code is meant to execute it.

The buffer is set to read a fixed number of chars (let's say 20 for example).

In the case that the user inputs more than 20 chars, the excess characters need to be flushed before the shell loops again.

I've been trying to do this like so:

int garbageCollector; 
while ((garbageCollector = getchar()) != '\n' && garbageCollector != EOF);

But the problem is getChar() requires you to input a char first.

Is there a way to flush stdin that doesn't require user to input anything?

while (1) {

    // Prompt user for input
    ssize_t readIn = read(STDIN_FILENO, buffer, BUF_SIZE + 1);
    if (readIn < 0) {
        perror("read() failed");
        return 2;
    } 

    // Null-terminate and remove line return
    buffer[readIn - 1] = '\0'; 

    char program[strlen(buffer)];
    strcpy(program, buffer);
    printf("program is: %s\n", program);

    // Flush stdin
    int garbageCollector; 
    while ((garbageCollector = getchar()) != '\n' && garbageCollector != EOF);

    // Create child process
    child = fork();
    if (child < 0) {
        perror("fork() failed");
        return 3;
    }

    // Start alarm that is triggered after timeout exceeded
    // which then kills child process
    signal(SIGALRM, killChild);
    alarm(timeout); 

    if (child == 0) { // Child
        char* av[] = { program, NULL };
        execve(program, av, NULL);  

    } else {  // Parent
        wait(NULL);
        alarm(0);  // Reset alarm if program executed
    }

    memset(buffer, 0, BUF_SIZE); // Flush buffer
}

回答1:


If non-POSIX portability is not a concern (note that this will not work with Windows - but I see you're using fork() which also will not work with Windows), you could temporarily make the file descriptor you're attempting to flush non-blocking and read all input from it:

int flush_in(FILE *file)
{
    int ch;
    int flags;
    int fd;

    fd = fileno(file);
    flags = fcntl(fd, F_GETFL, 0);
    if (flags < 0) {
        return -1;
    }
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
        return -1;
    }
    do {
        ch = fgetc(file);
    } while (ch != EOF);
    clearerr(file);
    if (fcntl(fd, F_SETFL, flags)) {
        return -1;
    }
    return 0;
}

And then you would call flush_in(stdin).




回答2:


Someone in a related question suggested this:

fseek(stdin,0,SEEK_END);

Seems to work on Mac and Windows but not Linux. For Linux, Daniel's suggestion works:

fflush(stdin);

So, you can solve this at compile time and use either fflush or fseek depending on the OS you're compiling for.

#ifdef defined(_WIN32) || defined(__APPLE__)
  #define flush_stdin(stdin) fseek(stdin,0,SEEK_END)
#elif defined(__linux__) || defined(__unix__)
  #define flush_stdin(stdin) fflush(stdin)
#else
  #define flush_stdin(...) UNIMPLEMENTED


来源:https://stackoverflow.com/questions/54299405/how-to-flush-stdin-without-requiring-user-input

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!