openSUSE/libeconf

Inconsistent string handling with empty and quoted values

Closed this issue · 1 comments

Handling empty values is currently highly inconsistent, if not completely broken:

Assume the following contents of test.ini

[test]
test=
test2=""
test3="string"
test4=string
test5=" string "
test6= string

and the following C application (simpified - see https://gist.github.com/laenion/874e4794af1c7f004ccae5157ea0c185 for a version with error handling):

#include <libeconf.h>
#include <stdio.h>

int main(void) {
  char *val;

  // Create new econf_file
  econf_file *kf_freshini;
  econf_newIniFile(&kf_freshini);
  econf_setStringValue(kf_freshini, "test", "test", NULL);
  econf_getStringValue(kf_freshini, "test", "test", &val);
  printf("Reading 'test' from freshly created object: %s\n", val);
  // Result: empty string

  // Read empty value from INI
  econf_file *kf_fromfile;
  econf_readFile(&kf_fromfile, "test.ini", "=", "#");
  econf_getStringValue(kf_fromfile, "test", "test", &val);
  printf("Reading empty 'test' from file: %s\n", val);
  // Result: real NULL value, which glibc outputs as "(null)"

  // Test what happens with quoted and unquoted strings
  econf_getStringValue(kf_fromfile, "test", "test2", &val);
  printf("Reading 'test2' from file: %s\n", val);
  econf_getStringValue(kf_fromfile, "test", "test3", &val);
  printf("Reading 'test3' from file: %s\n", val);
  econf_getStringValue(kf_fromfile, "test", "test4", &val);
  printf("Reading 'test4' from file: %s\n", val);
  econf_getStringValue(kf_fromfile, "test", "test5", &val);
  printf("Reading 'test5' from file: %s\n", val);
  econf_getStringValue(kf_fromfile, "test", "test6", &val);
  printf("Reading 'test6' from file: %s\n", val);
  // Result: Horrible things are happening here:
  // - The empty value is detected as a single quotation mark
  // - Everything is stored without quotation marks now. In case of " test "
  //   when writing the value out to a file in the next step the spaces are
  //   lost due to that when reading the file again.

  // Rewrite file to disk
  econf_writeFile(kf_fromfile, ".", "out.ini");
  // Result: The value is stored as a literal "(null)"

  // Merge the two econf_files
  econf_file *kf_merged;
  econf_mergeFiles(&kf_merged, kf_freshini, kf_fromfile);
  // Result: Segmentation fault due to the NULL value
}

From what I understand the following should be happening:

  • If no value is assigned, then the value should always be NULL; the behavior of econf_readFile is thus correct.
  • Quoted strings must be considered as literals when reading, minus the quotes.
  • If a string to be written out is empty or begins with a space it has to be written out in quotes.
  • A NULL value mustn't be converted to an empty string.

Or, as a general rule of thumb: When reading a file, writing it back and reading it again the values should still be the same ones...

Thanks for the report. I have (hopefully) fixed it with version 0.4.2.