Search code examples
cstdio

Check new lines before format element scanf


So, I want to read some input in two integer variables with fscanf, the input must be

INTEGER ONE SPACE INTEGER \n

So for example a file could be like that:

235 190\n

And what I want to do is checking if there is any new line before the first integer or the second, then throw an exception if that's the case:

So basically what you do with fscanf for that case would be just to do like:

FILE *somefile;
[...]
int w, h;
if (fscanf(somefile, "%d%d") == EOF)
    return (1);

But this method does not provide checking if there is a new line between the integers

(for example if there is INTEGER NEW_LINE INTEGER it will still read the second)

as it skips all spaces before seeing a digit, so what I managed to do is more close but still wrong:

FILE *somefile;
int w, h;
char check[2];
if (fscanf(somefile, "%d%c%d%c", &w, check, &h, check + 1) == EOF)
    return (-1);
if (check[0] != ' ' || check[1] != '\n')
    return (-1);

So after I did that I realized that the %c before the %d just reads one character, so if there is a space then a new line between the two, it will continue reading the file wrongly and won't detect an error. Now I wonder if there is a way to skip all spaces like when using " %c", while knowing if we skipped a \n. Thanks for your help.

PS: I know we can use fgets and strtol but it would be too easy, in this project I can only use fscanf to parse the file.


Solution

  • if there is a way to skip all spaces

    I can only use fscanf to parse the file.

    Let us assume ungetc() is not allowed - which makes things harder.


    "%d" happily consumes all (0 or more) leading white-spaces including '\n' without notice.

    Use fscanf("%[...]") to find leading white-spaces first. The usual suspects are " \t\n\r\f\v".

    // Consume leading whitespaces 
    // Return
    // 1: \n or EOF found
    // 0: not found
    int EatLeadingWS(FILE *f) {
      int count;
      char space[2];
      while ((count = fscanf("%1[ \t\n\r\f\v]", space)) == 1) {
        if (space[0] == '\n') return 1;
      }
      return count == EOF;
    }
    

    Alternative: use "%c" and isspace(), but then we need a way to put non white-spaces back.

    Then look for white-spaces before "%d"

    int some_int;
    if (EatLeadingWS(f) == 0) {
      int count;
      if ((count = fscanf("%d", &some_int)) == 1) { 
        printf("int %d found before a \\n\n", some_int);
      }
    }
      
    

    Another alternative is to use char buf[100]; fscanf("%99[^\n]", buf) to read most of the line and then parse the string with sscanf(buf, "%d%1[ ]%d" ....