Search code examples
cconfigconfigparser

Skip line in config parser if character is # commented with fscanf


I've written a simple config parser using fscanf and now want to add a comment character (#).

My configuration file contains three columns of which fscanf reads and stores in their corresponding arrays. This works well, but I'm a little unsure how to write it so that "if the character read is # then move onto the next line.

I've tried using fgetc but that seems to only read the first character, and it appears to break the logic within my while loop.

I've tried using a modification of "%*[^\n]\n" in my fscanf as:

while(fscanf(fp,"%d\t%f\t%f%*[^#]\n", &a[i], &b[i], &c[i]) != EOF)

but that causes a seg fault.

Config:

#hello and welcome to my config file
1666    -0.314913523    0.999804843        #blah blah
1667    -0.337279687    0.999865966
1703    -0.323162231    0.999774194
1704    -0.311984064    0.99964375
1705    -0.311984064    0.99964375
1706    -0.313381260    0.999671436
1707    -0.313170802    0.999558174

Code:

#include <iostream>
using namespace std;

#define NUM_ITEMS 50

int main()
{
    FILE *fp;
    fp = fopen("config.conf","r");

    if(fp==NULL){
        printf("No file.\n");
        return -1;
    }

    int a[NUM_ITEMS];
    float b[NUM_ITEMS];
    float c[NUM_ITEMS];

    int i = 0;

    while(fscanf(fp,"%d\t%f\t%f", &a[i], &b[i], &c[i]) != EOF)
    {
        printf("-> %d   %f  %f\n", a[i], b[i], c[i]);
        i++;
    }

    fclose(fp);
}

Solution

  • You can use fgets to read each line as a string and then check where '#' appears.

    #include <stdio.h>
    
    #define NUM_ITEMS 50
    #define MAX_CHAR 500
    
    ssize_t find_index(char *str)
    {
      size_t i=0U;
    
      for (; *str!='\0'; i++)
      {
        if (*str++=='#')
        {
          return i;
        }
      }
    
      return -1;
    }
    
    int main(void)
    {
      int a[NUM_ITEMS];
      float b[NUM_ITEMS];
      float c[NUM_ITEMS];
      char buff[MAX_CHAR];
      FILE *fp;
      size_t i=0U;
      ssize_t index=0U;
    
      fp = fopen("config.conf","r");
    
      if(!fp)
      {
        printf("No file.\n");
        return -1;
      }
    
      while (fgets(buff,MAX_CHAR,fp))
      {
        index=find_index(buff);
        if (index!=-1)
        {
          buff[index]='\0'; /* Bare in mind this will skip the newline character which fgets appends */
        }
    
        if(sscanf(buff,"%d%f%f", &a[i], &b[i], &c[i])==3) /* Checking scanf read 3 numbers */
        {
          printf("-> %d %f %f\n", a[i], b[i], c[i]);
          i++;
        }
      }
    
      return 0;
    }
    

    So find_index() returns the location of the element # was found. Then replaced by NULL terminator.

    As Jonathan pointed out in the comments, you can also use the strcspn() function along with strlen() (for error checking) to find the index of #.