2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void eat() // clears stdin upto and including \n OR EOF
{
    int eat;while ((eat = getchar()) != '\n' && eat != EOF);
}

int main(){

    printf("\n COMMAND : "); char cmd[21]=""; scanf("%20s",cmd);

    if(strcmp(cmd,"shell")==0||strcmp(cmd,"sh")==0)
    {
        getchar(); // absorb whitespace char separating 'shell' and the command, say 'ls'
        while(1)
        {
            printf("\n sh >>> "); // print prompt
            char shellcmd[1024]=""; // str to store command
            scanf("%1023[^\n]",shellcmd); eat(); // take input of command and clear stdin

            if(strcmp("close",shellcmd)==0||strcmp("x",shellcmd)==0)
                break;
            else
                system(shellcmd);
        }
    }
}

In the code, some anomalous behavior is occurring which I'm unable to catch.

Upon entering sh ls and pressing [ENTER], the expected response is:

  1. 1st scanf() stored sh in cmd[] and leaves ls\n in stdin.
  2. getchar() takes up the space.
  3. printf() prints \n sh >>> to Terminal
  4. second scanf() stores ls in shellcmd[], leaves \n in stdin
  5. eat() reads the \n from stdin, leaving it empty
  6. system("ls") is executed

I.e. results should be like this:

 COMMAND : sh ls

 sh >>>
 file1 file 2 file3 ...

 sh >>> | (cursor)

BUT

What I get:

COMMAND : sh ls

file1 file2 file3 ...
 sh >>> 
 sh >>> | 

Apparently, the 2nd scanf() and shell() are executing before printf() , or at least that's my assumption.

What's amiss?

Compiled on Clang and GCC with cc -Wall -Wextra -pedantic and tested on bash on MacOS as well as Linux

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
user13863346
  • 327
  • 2
  • 11

1 Answers1

4

As you can find in the man page:

If a stream refers to a terminal (as stdout normally does) it is line buffered

So you might experience a delay in seeing the message printed by printf whenever it doesn't contain a newline. On the other end, the previos message is displayed as soon as the leading newline of the next printf is sent.

Solutions:

  1. Add a newline at the end your message printf("\n sh >>> \n");

  2. Force the current buffer to be displayed even in absence of a newline by calling flush() function (fflush(stdout))

  3. Change the current stdout buffering behavior with setvbuf() function

    setvbuf(stdout,NULL,_IONBF,0);
    
Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
  • Oh, I see 0 0 ... so its *not* a fault with my program exactly :) – user13863346 Sep 17 '20 at 08:59
  • @user13863346 try it (I would start with option 2) and let me know if it works – Roberto Caboni Sep 17 '20 at 09:00
  • 1
    Yup, this worked ... its fixed ! flush() works, and so does `'\n'` at the end of my format string.. I'm daunted by the 3rd so won't try it ;) – user13863346 Sep 17 '20 at 09:01
  • @RobertoCaboni Does C have its own man-pages or are the 'Linux man pages' the authoritative guide ? – A P Jo Sep 17 '20 at 09:11
  • @APJo C "man-pages" are actually the language standard document. For example here it is the description of the streams in stdio library: https://port70.net/~nsz/c/c11/n1570.html#7.21.2 and in following 7.21.3§3 you can find more or less the same definition I quoted about fully buffered/line buffered/unbuffered streams. I usually post descriptions from linux.die.net that IMHO is a reliable source (and it can provide more hints about the relationships among the APIs) – Roberto Caboni Sep 17 '20 at 09:25
  • 1
    @user13863346 Just call `setvbuf(stdout,NULL,_IONBF,0);` before printing anything. – 12431234123412341234123 Sep 17 '20 at 11:28
  • @12431234123412341234123 that line of code was supposed to be in my answer as the code example of suggestion #3. Thanks to your comment I realized I forgot to add it – Roberto Caboni Sep 17 '20 at 11:41
  • 1
    The fault is with the insanely unintuitive basic C console api… – Kuba hasn't forgotten Monica Sep 17 '20 at 11:54
  • @UnslanderMonica I was just about to comment that `setvbuf(stdout,NULL,_IONBF,0);` is extremely non-intuitive and also quite cumbersome 0_0 – user13863346 Sep 18 '20 at 05:18