0

I used fscanf to parse a file, but on same cases it seem that the pointer does not advance correctly, and althought I thing I am using the right format to parsing the lines, the \n is not read, the pointer is not moved forward, and next fscanf returns the same line since the pointer does not advance.

I had to do an additional fgets to get the pointer advancing to next line/record.

Particularly, I have two cases on my code below, that I do not understand:

a).- After reading the ESSID with a first fscanf, I had to do another additional fscanf to be able to advance the pointer

b).- After reading the "Signal Level" at end of the code using fscanf(filePointer, "%*[^-0123456789] %i\n", &n1); the file pointer did not advance. I had to do resultado=fgets(buffer, bufferLength, filePointer) to keep on advancing pointer.

What I am doing worng to the parsing that forces me to do new reads to advance the file pointers?

See for example, the following code:

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

#define MAXCELLS 10
#define MAXCHAR 40
#define DO_DEBUG 1

struct structCell    
{
    int idCell;
    char MacAddress[MAXCHAR];
    char Essid[MAXCHAR];
    char Mode[MAXCHAR];
    int Channel;
    char Encrypted[MAXCHAR];  
    int Quality1;
    int Quality2;
    float Frequency;
    int SignalLevel;
};

typedef struct structCell Cell;


void main()
{

    Cell cell[MAXCELLS];
    

    FILE* filePointer;
    
    char* resultado;
    char filename [MAXCHAR]="./cells/info_cell_6.txt";
    
    int bufferLength = 255;
    char buffer[bufferLength];

    int cell_pos=0;
    char data[20] = {0};  
    char ignore[20] = {0};
    int n1, n2;
    float f1;

        
    if ( (filePointer = fopen(filename, "r") ) == NULL) { 
        printf("ERROR!! Unable to open file %s.\n", filename);
    } else {
        while (fscanf(filePointer, "Cell %i \n", &n1)!=EOF) {  
            printf ("\n\nReading Record number %d\n",cell_pos+1);
            // We already have fist line of the record (idCell)
            printf ("Cell %i \n", n1);
            cell[cell_pos].idCell=n1;
            // Address :  Get address data
            fscanf(filePointer, "Address: %s\n", data); 
            strcpy(cell[cell_pos].MacAddress, data); 
            printf("Address: -%s-\n", data);         
            // ESSID
            fscanf(filePointer, "ESSID: \"%[^\"]\"\n", data);
            strcpy(cell[cell_pos].Essid, data);
            printf("ESSID: -%s-\n", data); 
            // WHY I NEED THIS NEW FSCANF TO ADVANCE TO NEXT LINE ON FILE ?
            // WHY IS NOT PREVIOUS FSCANF AUTOMATICALLY MOVES THE POINTER?
            fscanf(filePointer, "%[A-Za-z]: %s\n", ignore, data);
            // Mode
            fscanf(filePointer, "Mode:%s\n", data);
            strcpy(cell[cell_pos].Mode, data);
            printf("Mode: -%s-\n", data); 
            // Channel
            fscanf(filePointer, "%*[^0123456789] %i\n", &n1);
            cell[cell_pos].Channel= n1; 
            printf("Chanel %i \n", n1);
            // Encryption
            fscanf(filePointer, "Encryption key:%s\n", data);
            strcpy(cell[cell_pos].Encrypted, data);
            printf("Encryption: -%s-\n", data); 
            // Quality
            fscanf(filePointer, "%*[^0123456789] %i/%i \n", &n1,&n2);   
            printf("Quality = %i/%i \n", n1,n2); 
            cell[cell_pos].Quality1=n1;
            cell[cell_pos].Quality2=n2;
            fscanf(filePointer, "Frequency: %f \n", &f1);
            cell[cell_pos].Frequency=f1;    
            printf("Frequency: %f GHz\n", f1);
            fscanf(filePointer, "%*[^-0123456789] %i\n", &n1);
            cell[cell_pos].SignalLevel=n1;  
            printf("Signal level= %i dBm\n", n1);
            resultado=fgets(buffer, bufferLength, filePointer); // Why is this line needed? to advance to next line?*/ 
            cell_pos++;
        }   
        fclose(filePointer);
    }
}

The file that is read (and that I should parse into the struct array) is the following one:

Cell 6
Address: 00:11:F5:E8:A4:54
ESSID:"Miguel 3"
Mode:Master
Channel:11
Encryption key:off
Quality=27/70  
Frequency:2.462 GHz
Signal level=-83 dBm  
Cell 6
Address: 90:84:0D:D8:46:89
ESSID:"acrumin"
Mode:Master
Channel:11
Encryption key:on
Quality=31/70  
Frequency:2.462 GHz
Signal level=-79 dBm  
Cell 6
Address: 00:27:0D:56:01:60
ESSID:"WiFi-UC3M"
Mode:Master
Channel:6
Encryption key:off
Quality=48/70  
Frequency:2.437 GHz
Signal level=-62 dBm
AndresG
  • 69
  • 6
  • `fscanf` generally ignores line boundaries. It's stream-based, not line-based. – Steve Summit Nov 02 '22 at 20:46
  • In any `scanf` or `fscanf` format string, `\n` does not do what you think it does. – Steve Summit Nov 02 '22 at 20:48
  • If you care about line boundaries, then the right tool is `fgets`. After reading a line, you can parse it with `sscanf`. You can also parse it using other methods, which won't be as easy as `sscanf`, but will give you more control over error checking. – user3386109 Nov 02 '22 at 20:56
  • [What can I use for input conversion instead of `scanf`?](https://stackoverflow.com/questions/58403537) (third time I've posted this link just today). – Steve Summit Nov 02 '22 at 21:02
  • 1
    As for what the code is doing wrong: it isn't checking the return value from `fscanf`. The `scanf` family of functions returns the number of successful conversions. If that returned number is not the same as the number of requested conversions, then the pointer will not advance, and there's a mess that needs to be cleaned up. Which is why you should read the whole line first with `fgets`. That way, the damage is limited to a single line, and doesn't propagate to subsequent lines. – user3386109 Nov 02 '22 at 21:03
  • It is usually a mistake to try to match whitespace in the `fscanf` format string, except to filter leading whitespace by placing a space before `%c` or `%[]` which do not otherwise filter whitespace. For the given sample file I would read each line with `fgets` and examine the string. – Weather Vane Nov 02 '22 at 21:03
  • Some may disagree, but one of my rules for *scanf users is: "If you find yourself needing to use `%[…]`, it's time to graduate beyond using *scanf". – Steve Summit Nov 02 '22 at 21:06

0 Answers0