You are working down the correct path, but there are a few things that you must approach differently if you want ensure things work correctly. If you take nothing else from this answer, learn that you cannot use any input or parsing function without checking the return (that applies to virtually every function you use, unless the operation of code that follows does not depend on the result -- like just printing values) Also, you never use while (!feof(fpointer))
, e.g. see: Why is while ( !feof (file) ) always wrong?
Now, how to approach the problem. First, if you need a constant for your array size, then #define
a constant or use a global enum
. For example, for my sect
, inisect
, key
, inikey
and val
buffers I would define SPLTC
and then for my line buffer, I define MAXC
, e.g.
#define SPLTC 128 /* if you need a constant, #define one (or more) */
#define MAXC 256
Depending on whether you need to be -ansi
or c89/90 compatible, declare your variables before any operations, e.g.
int main (int argc, char **argv) {
char buf[MAXC], sect[SPLTC], inisect[SPLTC], key[SPLTC], inikey[SPLTC], val[SPLTC];
FILE *fp = NULL;
Then the first thing you will do is validate that sufficient arguments were provided on the command line:
if (argc < 3) { /* validate 2 arguments provided */
fprintf (stderr,
"error: insufficient number of arguments\n"
"usage: %s file.ini section.key\n", argv[0]);
return 1;
}
Next you will open your file and validate that it is open for reading:
/* open/validate file open for reading */
if ((fp = fopen (argv[1], "r")) == NULL) {
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
perror ("fopen");
return 1;
}
Then split your section.key
argument argv[2]
into sect
and key
and validate the separation:
/* split section.key into sect & key */
if (sscanf (argv[2], " %127[^.]. %127s", sect, key) != 2) {
fputs ("error: invalid section.key\n", stderr);
return 1;
}
Now enter your read loop to find your section in the file (you always control the loop with the return of the read function itself):
while (fgets (buf, MAXC, fp)) { /* read each line */
if (buf[0] == '[') { /* is first char '[]'? */
if (sscanf (buf, " [%127[^]]", inisect) == 1) { /* parse section */
if (strcmp (sect, inisect) == 0) /* does it match 2nd arg? */
break; /* if so break loop */
}
}
}
How do you check that the section was found? You can keep a flag-variable as you have done with right_section
, or... think about where you would be in the file if your section wasn't found? You would be at EOF
. So now you can correctly check feof(fp)
, e.g.
if (feof (fp)) { /* if file stream at EOF, section not found */
fprintf (stderr, "error: EOF encountered before section '%s' found.\n",
sect);
return 1;
}
If you haven't exited due to not finding your section (meaning you got to this point in the code), just read each line validating a separation into inikey
and val
(if the validation fails -- you have read all the key/val pairs in that section without a match) If you find the key match during your read of the section success you have your inikey
and val
. If you complete the loop without a match you can check if you issue an error, and if you reach EOF
without a match, you can again check feof(fp)
after the loop, e.g.
while (fgets (buf, MAXC, fp)) { /* continue reading lines */
/* parse key & val from line */
if (sscanf (buf, " %127s = %127s", inikey, val) != 2) { /* if not key & val */
fprintf (stderr, "error: end of section '%s' reached "
"with no matching key found.\n", sect);
return 1;
}
if (strcmp (key, inikey) == 0) { /* does key match? */
printf ("section : %s\n key : %s\n val : %s\n", sect, key, val);
break;
}
}
if (feof (fp)) { /* if file stream at EOF, key not found */
fprintf (stderr, "error: EOF encountered before key '%s' found.\n",
argv[3]);
return 1;
}
That's basically it. If you put it altogether you have:
#include <stdio.h>
#include <string.h>
#define SPLTC 128 /* if you need a constant, #define one (or more) */
#define MAXC 256
int main (int argc, char **argv) {
char buf[MAXC], sect[SPLTC], inisect[SPLTC], key[SPLTC], inikey[SPLTC], val[SPLTC];
FILE *fp = NULL;
if (argc < 3) { /* validate 2 arguments provided */
fprintf (stderr,
"error: insufficient number of arguments\n"
"usage: %s file.ini section.key\n", argv[0]);
return 1;
}
/* open/validate file open for reading */
if ((fp = fopen (argv[1], "r")) == NULL) {
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
perror ("fopen");
return 1;
}
/* split section.key into sect & key */
if (sscanf (argv[2], " %127[^.]. %127s", sect, key) != 2) {
fputs ("error: invalid section.key\n", stderr);
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line */
if (buf[0] == '[') { /* is first char '[]'? */
if (sscanf (buf, " [%127[^]]", inisect) == 1) { /* parse section */
if (strcmp (sect, inisect) == 0) /* does it match 2nd arg? */
break; /* if so break loop */
}
}
}
if (feof (fp)) { /* if file stream at EOF, section not found */
fprintf (stderr, "error: EOF encountered before section '%s' found.\n",
sect);
return 1;
}
while (fgets (buf, MAXC, fp)) { /* continue reading lines */
/* parse key & val from line */
if (sscanf (buf, " %127s = %127s", inikey, val) != 2) { /* if not key & val */
fprintf (stderr, "error: end of section '%s' reached "
"with no matching key found.\n", sect);
return 1;
}
if (strcmp (key, inikey) == 0) { /* does key match? */
printf ("section : %s\n key : %s\n val : %s\n", sect, key, val);
break;
}
}
if (feof (fp)) { /* if file stream at EOF, key not found */
fprintf (stderr, "error: EOF encountered before key '%s' found.\n",
argv[3]);
return 1;
}
}
Example Use/Output
Finding valid section/key combinations:
$ ./bin/readini dat/test.ini section2.key3
section : section2
key : key3
val : vaule3
$ /bin/readini dat/test.ini section2.key5
section : section2
key : key5
val : value5
$ ./bin/readini dat/test.ini section1.key2
section : section1
key : key2
val : value2
Attempts to find invalid section/key combinations.
$ ./bin/readini dat/test.ini section1.key3
error: end of section 'section1' reached with no matching key found.
$ ./bin/readini dat/test.ini section2.key8
error: EOF encountered before key 'key8' found.
Look things over and let me know if you have further questions.