Search code examples
cshellfeof

Check if the input stream is empty in C


I'm learning C language, I'm having trouble with my program.

So, I have this program called TEST this program should allow me to read the argument either with argv[] or by using the input stream $ TEST < argsTest.json.

argsTest.json :
{
"a" = 2,
"b" = 3
}

to simplify my question I will use this simple program :

Struct {
    int a;
    int b;
} number;

int main(int argc, char **argv) {
    json_t * root;
    struct number numbers;
    int c = 0, i = 0 , result;
    char str[1024]; // I'm not using malloc just to simplify my question
    // default values
    numbers.a = 0;
    number.b = 0;

    if (argc == 1 && !feof(stdin)) {
        while((c = fgetc(stdin)) != EOF) {
            str[i]=c;
            ++i;
        }
        str[i] = '\0';

        .... // code that use jansson library to extract value

        /** let's suppose we have extracted the two value int json_a
          * and int json_b.
          */

        numbers.a = json_a;
        numbers.b = json_b;

    } else if (argc == 3) {
        scanf("%d", numbers.a);
        scanf("%d", numbers.b);
    }

    result = numbers.a + number.b;
    printf("%d\n", result);

    return 0;
}

So, I'm trying to implement three behaviors :

  1. $ TEST it should display 0 ( we used the default values).
  2. $ TEST < argsTest.json display 5.
  3. $ TEST 4 3 display 7.

My problem is that if statement if (argc == 1 && !feof(stdin)) , actually $ TEST and $ TEST < argsTest.json have the same statement argc == 1, so when run $ TEST it bug because he enters the first condition.

I want an if statement that will check if the input stream is empty and having 0 argument, so I can implement the first case without getting in the if statement.

Thank you.


Solution

  • The general idea is

    • check argc first to see if you should use the values in argv
    • check whether the terminal is interactive
      • if it is then just print 0
      • if it's not interactive then you can read from stdin

    The problem is that there's no portable way to check if stdin is interactive. However, on POSIX systems, you can use the isatty function, as explained in this question.

    So assuming that you are on a POSIX system, the code looks like this:

    int main(int argc, char *argv[])
    {
        struct number numbers;
    
        if (argc == 3)
        {
            if (sscanf(argv[1], "%d", &numbers.a) == 1 && sscanf(argv[2], "%d", &numbers.b) == 1)
                printf("From argv the answer is %d\n", numbers.a + numbers.b);
            else
                printf("Bad strings in argv\n");
        }
        else if (isatty(STDIN_FILENO))
        {
            printf("Nothing in argv or on stdin, so the answer is 0\n");
        }
        else
        {
            if (scanf("%d%d", &numbers.a, &numbers.b) == 2)
                printf("From stdin the answer is %d\n", numbers.a + numbers.b);
            else
                printf("Found junk on stdin\n");
        }
    }