fgets returning null - file parsing

158 views Asked by At

I'm trying to get a program to parse a text file line by line for some data storage (I've tried binary file storage, but having mixed data types in the file seems to mess things up).

I'm trying to save a number of entries contained in hist[], which is an array of the history structure which basically contains a float (.value) and a time_t (.event_Time). Before saving these entries, the number of entries should be saved (currently an int).

So far I can write the file just fine using the following function:

void data_save(int node_Id, int sensor_Id, history *hist, int entries){
    FILE *file;
    char data_Dir[FILENAME_MAX] = "";
    char directory[FILENAME_MAX] = "";
    char fileName[FILENAME_MAX] = "";
    int length = 0;

    //define path of the file
    _getcwd(data_Dir, FILENAME_MAX);
    strcat(data_Dir, "\\Data");
    strcat(directory,"\\Node_");
    length = snprintf(NULL, 0,"%d",node_Id);
    char str1[length];
    sprintf(str1, "%d", node_Id);
    strcat(directory,str1);
    strcat(fileName,"\\Sensor_");
    length = snprintf(NULL, 0,"%d",sensor_Id);
    char str2[length];
    sprintf(str2, "%d", sensor_Id);
    strcat(fileName,str2);
    strcat(fileName,".txt");

    printf("%s\n", directory);
    printf("%s\n", fileName);

    //check if the Data directory exists, create it if not
    if (directory_exists(data_Dir) == false) {
        printf("Making directory\n");
        _mkdir(data_Dir);
    }
    strcat(data_Dir, directory);

    //check if the Node directory exists, create it if not
    if (directory_exists(data_Dir) == false) {
        printf("Making directory\n");
        _mkdir(data_Dir);
    }
    strcat(data_Dir, fileName);
    printf("%s\n", data_Dir);

    //open the file
    file = fopen(data_Dir, "w");
    if(file == NULL){
        printf("Error while opening file.\n");
        exit (1);
    }

    //Save the number of entries
    printf("Saving %d entries\n", entries);
    fprintf(file, "%d\n", entries);

    //Save each entry in the inverse chronological order
    //(ie. latest event first)
    for(int i=entries-1; i > -1; i--){
        fprintf(file, "%f %ld\n", hist[i].value, hist[i].event_Time);
    }

    fclose(file);

    free(data_Dir);
    free(directory);
    free(fileName);

    printf("Node %d, sensor %d: Data saved Successfully (%d Entries)\n", node_Id, sensor_Id, entries);
    return;
}

However, I am getting issues when trying to load the file I've just created using the following function:

history * data_load(int node_Id, int sensor_Id, int *entries){
    FILE *file;
    char data_Dir[FILENAME_MAX] = "";
    char directory[FILENAME_MAX] = "";
    char fileName[FILENAME_MAX] = "";
    int length = 0;
    int entries_Temp;
    int maxChar = 1000;
    char stream[maxChar];

    //define path of the file
    _getcwd(data_Dir, FILENAME_MAX);
    strcat(data_Dir, "\\Data");
    strcat(directory,"\\Node_");
    length = snprintf(NULL, 0,"%d",node_Id);
    char str1[length];
    sprintf(str1, "%d", node_Id);
    strcat(directory,str1);
    strcat(fileName,"\\Sensor_");
    length = snprintf(NULL, 0,"%d",sensor_Id);
    char str2[length];
    sprintf(str2, "%d", sensor_Id);
    strcat(fileName,str2);

    //check if the Data directory exists, exit if not
    if (directory_exists(data_Dir) == false) {
        printf("//Data does not exist\n");
        *entries = 0;
        return NULL;
    }
    strcat(data_Dir, directory);

    //check if the Node directory exists, exit if not
    if (directory_exists(data_Dir) == false) {
        printf("//Data//Node%d does not exist\n", node_Id);
        *entries = 0;
        return NULL;
    }
    strcat(data_Dir, fileName);

    printf("%s\n", data_Dir);

    //check if file exists (ie. there has been no previous
    //data for the given sensor) exit and return 0
    //existing entries
    file = fopen(data_Dir, "r");
    if(file!=NULL){
        printf("No file found for given sensor\n");
        *entries = 0;
        return NULL;
    }

    //Read the number of entries in the file
    printf("Reading number of entries\n");
    printf("%s", fgets(stream, sizeof(stream), file));
    printf("%s\n", stream);
    *entries = strtol(stream, NULL, 10);
    printf("Entries : %d\n", *entries);

    if(*entries > 100){
        printf("Entries is NOK\n");
        exit(1);
    }

    //create the array of structures containing the data
    printf("Creating the data array\n");
    history *hist = malloc(*entries * sizeof(history));

    //Read the data and copy it to the array
    //this has not been tackled yet

    printf("Closing file\n");
    fclose(file);

    printf("Freeing memory (filenames...)\n");
    free(data_Dir);
    free(directory);
    free(fileName);

    printf("Node %d, sensor %d: Data loaded Successfully (%d Entries)", node_Id, sensor_Id, *entries);
    return hist;
}

From what I can gather, it seems fgets returns NULL every time. I am unsure if the file is being read correctly, but it seems that the program manages to open the file as fopen returns non NULL. I also suspect that my first attempt at this using binary files might have failed for similar reasons, but due to the format, I couldn't check if the error was occuring during writing or reading of the file.

I'd like to get some insight on why fgets is failing. I'd also appreciate any guidance on better ways to handle saving and loading data from files, as I'm only a beginner in C and I'm pretty sure there's some more optimal ways of doing what I'm trying to achieve.

1

There are 1 answers

3
chux - Reinstate Monica On

At least these problems:

Off by 1.

With a short buffer, sprintf(str1, "%d", node_Id); is undefined behavior (UB) and rest of code is all suspect.

length = snprintf(NULL, 0,"%d",node_Id);
// char str1[length];
char str1[length + 1];
sprintf(str1, "%d", node_Id);

...
//char str2[length];
char str2[length+1];

Bad free

Do not call free() on something that lacks a matching *alloc().

//free(data_Dir);
//free(directory);
//free(fileName);

Suggest simplify string code.

E.g. filename

char fileName[FILENAME_MAX];
int length = snprintf(fileName, sizeof fileName, "%s%d%s",
    "\\Sensor_", sensor_Id, ".txt");
if (length < 0 || length >= sizeof fileName) {
  Handle_BufferTooSmall_Error();
}
else {
  printf("%s\n", fileName);
}