diff -Nru libeconf-0.4.4+dfsg1/debian/changelog libeconf-0.4.6+dfsg1/debian/changelog --- libeconf-0.4.4+dfsg1/debian/changelog 2022-07-08 15:42:20.000000000 +0000 +++ libeconf-0.4.6+dfsg1/debian/changelog 2022-08-16 05:09:20.000000000 +0000 @@ -1,11 +1,9 @@ -libeconf (0.4.4+dfsg1-1ubuntu1) kinetic; urgency=medium +libeconf (0.4.6+dfsg1-1) unstable; urgency=medium - * Suppress -Werror=format-truncation during build; the code is doing - some string manipulation which looks to be ok but too complicated - for gcc to statically analyze, so just suppress the error rather - than refactoring the code. + * New upstream release. + * Add debian/patches/werror.patch (Closes: #1015485, #1014604) - -- Steve Langasek Fri, 08 Jul 2022 15:42:20 +0000 + -- Andreas Henriksson Tue, 16 Aug 2022 07:09:20 +0200 libeconf (0.4.4+dfsg1-1) unstable; urgency=medium diff -Nru libeconf-0.4.4+dfsg1/debian/control libeconf-0.4.6+dfsg1/debian/control --- libeconf-0.4.4+dfsg1/debian/control 2022-07-08 15:42:20.000000000 +0000 +++ libeconf-0.4.6+dfsg1/debian/control 2022-07-18 21:45:01.000000000 +0000 @@ -1,7 +1,6 @@ Source: libeconf Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Andreas Henriksson +Maintainer: Andreas Henriksson Build-Depends: debhelper-compat (= 13), meson, doxygen Standards-Version: 4.5.0 Section: libs diff -Nru libeconf-0.4.4+dfsg1/debian/patches/series libeconf-0.4.6+dfsg1/debian/patches/series --- libeconf-0.4.4+dfsg1/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ libeconf-0.4.6+dfsg1/debian/patches/series 2022-08-16 05:06:48.000000000 +0000 @@ -0,0 +1 @@ +werror.patch diff -Nru libeconf-0.4.4+dfsg1/debian/patches/werror.patch libeconf-0.4.6+dfsg1/debian/patches/werror.patch --- libeconf-0.4.4+dfsg1/debian/patches/werror.patch 1970-01-01 00:00:00.000000000 +0000 +++ libeconf-0.4.6+dfsg1/debian/patches/werror.patch 2022-08-16 05:07:25.000000000 +0000 @@ -0,0 +1,31 @@ +Description: Drop -Werror from CFLAGS + Explicitly adding "-Werror" to cflags gives the following warning: + . + ../meson.build:42: WARNING: Consider using the built-in werror option instead of using "-Werror". + . + In general using -Werror is a problem for distributions as this causes + a lot of fallout on build toolchain changes, eg. compiler upgrades. + . + An example of problematic behaviour is when enabling LTO which in turn + seems to enable -Wformat-truncation while at the same time econftool + uses sprintf to truncate strings, the combination causes build failure + with Werror. + . + In short, it's better to use `-Dwerror=true` meson option on command + line (and in CI) when developers do builds and want to avoid the chance + of missing any warnings. +Author: Andreas Henriksson +Bug: https://github.com/openSUSE/libeconf/issues/167 +Bug-Debian: https://bugs.debian.org/1015485 +Last-Update: 2022-08-16 + +--- libeconf-0.4.4+dfsg1.orig/meson.build ++++ libeconf-0.4.4+dfsg1/meson.build +@@ -19,7 +19,6 @@ add_project_arguments(['-D_GNU_SOURCE=1' + '-D_FORTIFY_SOURCE=2'], language : 'c') + + possible_cc_flags = [ +- '-Werror', + '-fstack-protector-strong', + '-funwind-tables', + '-fasynchronous-unwind-tables', diff -Nru libeconf-0.4.4+dfsg1/debian/rules libeconf-0.4.6+dfsg1/debian/rules --- libeconf-0.4.4+dfsg1/debian/rules 2022-07-08 15:41:11.000000000 +0000 +++ libeconf-0.4.6+dfsg1/debian/rules 2022-08-16 05:09:11.000000000 +0000 @@ -13,7 +13,6 @@ # package maintainers to append LDFLAGS #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed -export DEB_CFLAGS_MAINT_APPEND = -Wno-error=format-truncation %: dh $@ --buildsystem=meson diff -Nru libeconf-0.4.4+dfsg1/doc/man/econftool.8 libeconf-0.4.6+dfsg1/doc/man/econftool.8 --- libeconf-0.4.4+dfsg1/doc/man/econftool.8 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/doc/man/econftool.8 2022-04-27 21:57:10.000000000 +0000 @@ -35,6 +35,18 @@ .B OPTIONS -y, --yes: Assumes yes for all prompts and runs non-interactively. + +.SH general OPTIONS +.TP +.B --comment + Character which starts a comment. ('#' default). + +.TP +.B --delimiters + Characters which separates key/value entries. ("=" default). + e.g. --delimiters="= \t" + e.g. --delimiters=spaces regarding all spaces + .SH "SEE ALSO" .PP libeconf\& diff -Nru libeconf-0.4.4+dfsg1/include/libeconf.h libeconf-0.4.6+dfsg1/include/libeconf.h --- libeconf-0.4.4+dfsg1/include/libeconf.h 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/include/libeconf.h 2022-04-27 21:57:10.000000000 +0000 @@ -107,7 +107,9 @@ * * @param result content of parsed file * @param file_name absolute path of parsed file - * @param delim delimiters of key/value e.g. "\t =" + * @param delim delimiters of key/value e.g. "\t =". + * If delim contains space characters AND none space characters, + * multiline values are not parseable. * @param comment array of characters which define the start of a comment * @return econf_err ECONF_SUCCESS or error code * @@ -170,6 +172,8 @@ * @param project_name basename of the configuration file * @param config_suffix suffix of the configuration file. Can also be NULL. * @param delim delimiters of key/value e.g. "\t =" + * If delim contains space characters AND none space characters, + * multiline values are not parseable. * @param comment array of characters which define the start of a comment * @return econf_err ECONF_SUCCESS or error code * @@ -211,6 +215,8 @@ * @param project_name basename of the configuration file * @param config_suffix suffix of the configuration file. Can also be NULL. * @param delim delimiters of key/value e.g. "\t =" + * If delim contains space characters AND none space characters, + * multiline values are not parseable. * @param comment array of characters which define the start of a comment * @return econf_err ECONF_SUCCESS or error code * diff -Nru libeconf-0.4.4+dfsg1/lib/getfilecontents.c libeconf-0.4.6+dfsg1/lib/getfilecontents.c --- libeconf-0.4.4+dfsg1/lib/getfilecontents.c 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/lib/getfilecontents.c 2022-04-27 21:57:10.000000000 +0000 @@ -369,45 +369,51 @@ *data++ = '\0'; } - /* Checking and adding multiline entries which are - * not defined by a beginning quote in the line before. - */ - bool found_delim = delim_seen; - if (!found_delim) - { - /* searching the rest of the string for delimiters */ - char *c = data; - while (*c && !(strchr(delim, *c) != NULL)) - c++; - if (*c) - found_delim = true; - } - if (!found_delim && - /* Entry has already been found */ - ef->length > 0 && - /* The Entry must be the next line. Otherwise it is a new one */ - ef->file_entry[ef->length-1].line_number+1 == line) - { - /* removing comments */ - for (size_t i = 0; i < strlen(comment); i++) { - char *pt = strchr(org_buf, comment[i]); - if (pt) - *pt = '\0'; + if (!has_wsp || !has_nonwsp) { + /* Multiline entries make no sense if the delimiters are + * whitespaces AND none whitespaces. + */ + + /* Checking and adding multiline entries which are + * not defined by a beginning quote in the line before. + */ + bool found_delim = delim_seen; + if (!found_delim) + { + /* searching the rest of the string for delimiters */ + char *c = data; + while (*c && !(strchr(delim, *c) != NULL)) + c++; + if (*c) + found_delim = true; + } + if (!found_delim && + /* Entry has already been found */ + ef->length > 0 && + /* The Entry must be the next line. Otherwise it is a new one */ + ef->file_entry[ef->length-1].line_number+1 == line) + { + /* removing comments */ + for (size_t i = 0; i < strlen(comment); i++) { + char *pt = strchr(org_buf, comment[i]); + if (pt) + *pt = '\0'; + } + /* removing \n at the end of the line */ + if( org_buf[strlen(org_buf)-1] == '\n' ) + org_buf[strlen(org_buf)-1] = 0; + retval = store(ef, current_group, name, org_buf, line, + current_comment_before_key, current_comment_after_value, + false, /* Quotes does not matter in the following lines */ + true /* appending entry */); + free(current_comment_before_key); + current_comment_before_key = NULL; + free(current_comment_after_value); + current_comment_after_value = NULL; + if (retval) + goto out; + continue; } - /* removing \n at the end of the line */ - if( org_buf[strlen(org_buf)-1] == '\n' ) - org_buf[strlen(org_buf)-1] = 0; - retval = store(ef, current_group, name, org_buf, line, - current_comment_before_key, current_comment_after_value, - false, /* Quotes does not matter in the following lines */ - true /* appending entry */); - free(current_comment_before_key); - current_comment_before_key = NULL; - free(current_comment_after_value); - current_comment_after_value = NULL; - if (retval) - goto out; - continue; } /* Go on. It is not an multiline entry */ diff -Nru libeconf-0.4.4+dfsg1/lib/libeconf_ext.c libeconf-0.4.6+dfsg1/lib/libeconf_ext.c --- libeconf-0.4.4+dfsg1/lib/libeconf_ext.c 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/lib/libeconf_ext.c 2022-04-27 21:57:10.000000000 +0000 @@ -77,25 +77,29 @@ char buf[BUFSIZ]; char *line; size_t n_del = 0; - strncpy(buf,value_string,BUFSIZ-1); - free(value_string); - value_string = trim(buf); + (*result)->values = NULL; - if (value_string[0] == '\"') - { - /* one quoted string only */ - (*result)->values = realloc ((*result)->values, sizeof (char*) * ++n_del); - if ((*result)->values == NULL) - return ECONF_NOMEM; /* memory allocation failed */ - (*result)->values[n_del-1] = strdup(value_string); - } else { - /* splitting into a character array */ - while ((line = strsep(&value_string, "\n")) != NULL) { + if (value_string!=NULL) { + strncpy(buf,value_string,BUFSIZ-1); + free(value_string); + value_string = trim(buf); + + if (value_string[0] == '\"') + { + /* one quoted string only */ (*result)->values = realloc ((*result)->values, sizeof (char*) * ++n_del); if ((*result)->values == NULL) - return ECONF_NOMEM; /* memory allocation failed */ - (*result)->values[n_del-1] = strdup(trim(line)); + return ECONF_NOMEM; /* memory allocation failed */ + (*result)->values[n_del-1] = strdup(value_string); + } else { + /* splitting into a character array */ + while ((line = strsep(&value_string, "\n")) != NULL) { + (*result)->values = realloc ((*result)->values, sizeof (char*) * ++n_del); + if ((*result)->values == NULL) + return ECONF_NOMEM; /* memory allocation failed */ + (*result)->values[n_del-1] = strdup(trim(line)); + } } } diff -Nru libeconf-0.4.4+dfsg1/meson.build libeconf-0.4.6+dfsg1/meson.build --- libeconf-0.4.4+dfsg1/meson.build 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/meson.build 2022-04-27 21:57:10.000000000 +0000 @@ -7,7 +7,7 @@ 'b_pie=true', 'warning_level=3',], license : 'MIT', - version : '0.4.4', + version : '0.4.6', ) cc = meson.get_compiler('c') diff -Nru libeconf-0.4.4+dfsg1/NEWS libeconf-0.4.6+dfsg1/NEWS --- libeconf-0.4.4+dfsg1/NEWS 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/NEWS 2022-04-27 21:57:10.000000000 +0000 @@ -1,3 +1,18 @@ +Version 0.4.6 +* econftool: + ** Parsing error: Reporting file and line nr. + ** --delimeters=spaces Taking all kind of spaces for delimiter +* libeconf: + Fixed bnc#1198165: Parsing files correctly which have space characters + AND none space characters as delimiters. + +Version 0.4.5 +* econftool: + ** New call "syntax" for checking the configuration files only. + Returns an error string with line number if an error occurs. + ** New options "--comment" and "--delimeters" + ** Parsing one file only if needed. + Version 0.4.4 * Fixed i586 build Version 0.4.3 diff -Nru libeconf-0.4.4+dfsg1/tests/tst-econftool_cat.sh libeconf-0.4.6+dfsg1/tests/tst-econftool_cat.sh --- libeconf-0.4.4+dfsg1/tests/tst-econftool_cat.sh 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/tests/tst-econftool_cat.sh 2022-04-27 21:57:10.000000000 +0000 @@ -8,7 +8,7 @@ declare -a experr=("variable = 301" "Path:" "Configuration file not found" - "Currently only works with a dot in the filename!") + "Currently only works with a dot in the filename and a suffix!") teststringslength=${#teststrings[@]} diff -Nru libeconf-0.4.4+dfsg1/tests/tst-econftool_show1.sh libeconf-0.4.6+dfsg1/tests/tst-econftool_show1.sh --- libeconf-0.4.4+dfsg1/tests/tst-econftool_show1.sh 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/tests/tst-econftool_show1.sh 2022-04-27 21:57:10.000000000 +0000 @@ -8,7 +8,7 @@ declare -a experr=("variable = 301" "variable = 301" "Configuration file not found" - "Currently only works with a dot in the filename!") + "Currently only works with a dot in the filename and a suffix!") teststringslength=${#teststrings[@]} diff -Nru libeconf-0.4.4+dfsg1/tests/tst-logindefs1.c libeconf-0.4.6+dfsg1/tests/tst-logindefs1.c --- libeconf-0.4.4+dfsg1/tests/tst-logindefs1.c 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/tests/tst-logindefs1.c 2022-04-27 21:57:10.000000000 +0000 @@ -20,7 +20,7 @@ char *val; econf_err error; - if ((error = econf_readFile (&key_file, TESTSDIR"tst-logindefs1-data/etc/login.defs", " \t", "#"))) + if ((error = econf_readFile (&key_file, TESTSDIR"tst-logindefs1-data/etc/login.defs", "= \t", "#"))) { fprintf (stderr, "ERROR: couldn't read configuration file: %s\n", econf_errString(error)); return 1; @@ -43,6 +43,24 @@ return 1; } free (val); + + if ((error = econf_getStringValue (key_file, NULL, "ENV_SUPATH", &val))) + { + fprintf (stderr, "Error reading ENV_SUPATH: %s\n", + econf_errString(error)); + return 1; + } + else if (strlen(val) == 0) + { + fprintf (stderr, "ENV_SUPATH returns nothing!\n"); + return 1; + } + else if (strcmp (val, "PATH=/sbin:/bin:/usr/sbin:/usr/bin") != 0) + { + fprintf (stderr, "ENV_SUPATH returns wrong value: '%s'\n", val); + return 1; + } + free (val); if ((error = econf_getStringValue (key_file, "", "UMASK", &val))) { diff -Nru libeconf-0.4.4+dfsg1/util/econftool.c libeconf-0.4.6+dfsg1/util/econftool.c --- libeconf-0.4.4+dfsg1/util/econftool.c 2022-01-04 11:20:35.000000000 +0000 +++ libeconf-0.4.6+dfsg1/util/econftool.c 2022-04-27 21:57:10.000000000 +0000 @@ -51,7 +51,11 @@ */ static void usage(void) { - fprintf(stderr, "Usage: %s COMMAND [OPTIONS] .conf\n\n", utilname); + fprintf(stderr, "Usage: %s COMMAND [OPTIONS] <. | >\n\n", utilname); + fprintf(stderr, "If (begins with \"/\") is given, only this\n"); + fprintf(stderr, "file will be parsed.\n"); + fprintf(stderr, "Otherwise different files in /etc /usr/vendor and */.suffix.d/\n"); + fprintf(stderr, "directories will be parsed.\n\n"); fprintf(stderr, "COMMANDS:\n"); fprintf(stderr, "show reads all snippets for .conf (in /usr/etc and /etc),\n"); fprintf(stderr, " and prints all groups,keys and their values.\n"); @@ -59,6 +63,9 @@ fprintf(stderr, " variable $ECONFTOOL_ROOT \n"); fprintf(stderr, "cat prints the content of the files and the name of the file in the order\n"); fprintf(stderr, " as it has been read.\n"); + fprintf(stderr, "syntax checks the syntax, prints parsing errors and returns 1 if an error\n"); + fprintf(stderr, " has been found (otherwise 0).\n"); + fprintf(stderr, " as it has been read.\n"); fprintf(stderr, "edit starts the editor $EDITOR (environment variable) where the\n"); fprintf(stderr, " groups, keys and values can be modified and saved afterwards.\n"); fprintf(stderr, " -f, --full: copy the original configuration file to /etc instead of\n"); @@ -68,6 +75,34 @@ fprintf(stderr, "revert reverts all changes to the vendor versions. Basically deletes\n"); fprintf(stderr, " the config file and snippet directory in /etc.\n"); fprintf(stderr, " -y, --yes: assumes yes for all prompts and runs non-interactively.\n\n"); + fprintf(stderr, "\ngeneral Options:\n"); + fprintf(stderr, "--comment : Character which starts a comment. ('#' default).\n"); + fprintf(stderr, "--delimiters : Characters which separates key/value entries. (\"=\" default).\n"); + fprintf(stderr, " e.g. --delimiters=\"= \\t\"\n"); + fprintf(stderr, " e.g. --delimiters=spaces regarding all spaces\n"); +} + +/** + * @brief Replace a substring of a string by another + * + * @param str source string + * @param orig search string + * @param rep replace string + */ +static char *replace_str(char *str, char *orig, char *rep) +{ + static char buffer[1024]; + char *p; + + if(!(p = strstr(str, orig))) + return str; + + strncpy(buffer, str, p-str); + buffer[p-str] = '\0'; + + sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig)); + + return buffer; } /** @@ -136,6 +171,21 @@ } /** + * @brief printing error with linenr and filename + */ +static void print_error(const econf_err error) +{ + char *filename = NULL; + uint64_t line_nr = 0; + + econf_errLocation( &filename, &line_nr); + fprintf(stderr, "%s (line %d): %s\n", filename, (int) line_nr, + econf_errString(error)); + free(filename); +} + + +/** * @brief printing header */ static void pr_header(void) @@ -167,8 +217,15 @@ /* show groups, keys and their value */ econf_error = econf_getGroups(key_file, &groupCount, &groups); if (econf_error) { - fprintf(stderr, "%d: %s\n", econf_error, econf_errString(econf_error)); - return econf_error; + if (econf_error != ECONF_NOGROUP) { + print_error(econf_error); + return econf_error; + } else { + /* no groups defined; generating an root entry */ + groups = calloc(1, sizeof(char*)); + groups[0] = NULL; + groupCount = 1; + } } for (size_t g = 0; g < groupCount; g++) { char **keys = NULL; @@ -176,23 +233,27 @@ econf_error = econf_getKeys(key_file, groups[g], &key_count, &keys); if (econf_error) { - fprintf(stderr, "%d: %s\n", econf_error, econf_errString(econf_error)); + print_error(econf_error); econf_free(keys); return econf_error; } - printf("%s\n", groups[g]); + + if (groups[g] != NULL) + printf("%s\n", groups[g]); + for (size_t k = 0; k < key_count; k++) { econf_error = econf_getExtValue(key_file, groups[g], keys[k], &value); if (econf_error) { - fprintf(stderr, "%d: %s\n", econf_error, econf_errString(econf_error)); + print_error(econf_error); econf_free(keys); return econf_error; } if (value != NULL) { size_t v = 0; + printf("%s = ", keys[k]); while (value->values[v] != 0) { if (v==0) { - printf("%s = %s\n", keys[k], value->values[v]); + printf("%s\n", value->values[v]); } else { printf(" %s\n", value->values[v]); } @@ -210,20 +271,31 @@ /** * @brief This command will read all snippets for filename.conf - * (econf_readDirs) and print all groups, keys and their - * values as an application would see them. + * (econf_readDirs) OR a single file only. After that it + * will evtl. print all groups, keys and their values as + * an application would see them. */ -static int econf_show(struct econf_file **key_file) +static int econf_read(struct econf_file **key_file, const char *delimiters, const char *comment, const bool show) { econf_err econf_error; - econf_error = econf_readDirs(key_file, usr_root_dir, root_dir, conf_basename, - conf_suffix, "=", "#"); + if (conf_filename[0] == '/') { + /* reading one file only */ + econf_error = econf_readFile(key_file, conf_filename, + delimiters, comment); + } else { + econf_error = econf_readDirs(key_file, usr_root_dir, root_dir, conf_basename, + conf_suffix, delimiters, comment); + } if (econf_error) { - fprintf(stderr, "%d: %s\n", econf_error, econf_errString(econf_error)); + print_error(econf_error); return -1; } - pr_header(); - pr_key_file(*key_file); + if (show) { + pr_header(); + pr_key_file(*key_file); + } else { + fprintf(stderr, "Syntax is OK\n"); + } return 0; } @@ -232,17 +304,23 @@ * (econf_readDirs) in hierarchical order and print all groups, * keys and their values. */ -static int econf_cat(void) +static int econf_cat(const char *delimiters, const char *comment) { econf_file **key_files; econf_err econf_error; size_t size = 0; + if (conf_filename[0] == '/') { + fprintf(stderr, + "The cat command does not makes sense for parsing a single file. Please use the show command instead.\n"); + return -1; + } + econf_error = econf_readDirsHistory(&key_files, &size, usr_root_dir, root_dir, conf_basename, - conf_suffix, "=", "#"); + conf_suffix, delimiters, comment); if (econf_error) { - fprintf(stderr, "%d: %s\n", econf_error, econf_errString(econf_error)); + print_error(econf_error); return -1; } @@ -260,7 +338,8 @@ * @brief Generates a tmpfiles from key_file and opens editor to allow user editing. * It then saves the edited in key_file_edit and deletes the tmpfile */ -static int econf_edit_editor(struct econf_file **key_file_edit, struct econf_file **key_file) +static int econf_edit_editor(struct econf_file **key_file_edit, struct econf_file **key_file, + const char *delimiters, const char *comment) { econf_err econf_error; int wstatus; @@ -317,7 +396,7 @@ } while (!WIFEXITED(wstatus)); /* save edits from tmpfile_edit in key_file_edit */ - econf_error = econf_readFile(key_file_edit, path_tmpfile_edit, "=", "#"); + econf_error = econf_readFile(key_file_edit, path_tmpfile_edit, delimiters, comment); if (econf_error) { fprintf(stderr, "%s\n", econf_errString(econf_error)); ret = -1; @@ -343,16 +422,21 @@ * TODO: * - Replace static values of the path with future libeconf API calls */ -static int econf_edit(struct econf_file **key_file) +static int econf_edit(struct econf_file **key_file, const char *delimiters, const char *comment) { econf_err econf_error; econf_file *key_file_edit = NULL; - econf_error = econf_readDirs(key_file, usr_root_dir, root_dir, conf_basename, conf_suffix, "=", "#"); + if (conf_filename[0] == '/') { + /* reading one file only */ + econf_error = econf_readFile(key_file, conf_filename, + delimiters, comment); + } else { + econf_error = econf_readDirs(key_file, usr_root_dir, root_dir, conf_basename, conf_suffix, delimiters, comment); + } if (econf_error == ECONF_NOFILE) { - /* the file does not exist */ - + /* the file does not exist */ /* create empty key file */ if ((econf_error = econf_newIniFile(key_file))) { fprintf(stderr, "%s\n", econf_errString(econf_error)); @@ -364,7 +448,7 @@ return -1; } - if (econf_edit_editor(&key_file_edit, key_file)) { + if (econf_edit_editor(&key_file_edit, key_file, delimiters, comment)) { econf_free(key_file_edit); return -1; } @@ -519,6 +603,8 @@ bool is_dropin_file = true; bool is_root = false; bool use_homedir = false; + char *comment = "#"; + char *delimiters = "="; /* parse command line arguments. See getopt_long(3) */ int opt, nonopts; @@ -530,10 +616,12 @@ {"help", no_argument, 0, 'h'}, {"yes", no_argument, 0, 'y'}, {"use-home", no_argument, 0, 'u'}, + {"comment", required_argument, 0, 'c'}, + {"delimiters", required_argument, 0, 'd'}, {0, 0, 0, 0 } }; - while ((opt = getopt_long(argc, argv, "hfy", longopts, &index)) != -1) { + while ((opt = getopt_long(argc, argv, "hfyuc:d:", longopts, &index)) != -1) { switch(opt) { case 'f': /* overwrite path */ @@ -550,6 +638,12 @@ case 'u': use_homedir = true; break; + case 'c': + comment = optarg; + break; + case 'd': + delimiters = optarg; + break; case '?': default: fprintf(stderr, "Try '%s --help' for more information.\n", utilname); @@ -568,27 +662,43 @@ usage(); return EXIT_FAILURE; } - /**** initialization ****/ + /* translating delimiters */ + if ( strcmp(delimiters, "spaces") == 0 ) { + delimiters = " \t\f\n\r\v"; + } else { + delimiters = replace_str(delimiters, "\\t", "\t"); + delimiters = replace_str(delimiters, "\\f", "\f"); + delimiters = replace_str(delimiters, "\\n", "\n"); + delimiters = replace_str(delimiters, "\\r", "\r"); + delimiters = replace_str(delimiters, "\\v", "\v"); + } + + /**** initialization ****/ /* basic write permission check */ is_root = getuid() == 0; - /* get the position of the last dot in the filename to extract - * the suffix from it. - */ - conf_suffix = strrchr(argv[optind + 1], '.'); + if ( argv[optind + 1][0] != '/') { + /* it is not a single file only */ - if (conf_suffix == NULL) { - fprintf(stderr, "Currently only works with a dot in the filename!\n\n"); - usage(); + /* get the position of the last dot in the filename to extract + * the suffix from it. + */ + conf_suffix = strrchr(argv[optind + 1], '.'); + if (conf_suffix == NULL) { + fprintf(stderr, "Currently only works with a dot in the filename and a suffix!\n\n"); + usage(); + exit(1); + } else { + /* set filename to the proper argv argument */ + if (strlen(argv[optind + 1]) > sizeof(conf_basename)) { + fprintf(stderr, "Filename too long\n"); + return EXIT_FAILURE; + } + snprintf(conf_basename, strlen(argv[optind + 1]) - strlen(conf_suffix) + 1, "%s", argv[optind + 1]); + } } - /* set filename to the proper argv argument */ - if (strlen(argv[optind + 1]) > sizeof(conf_basename)) { - fprintf(stderr, "Filename too long\n"); - return EXIT_FAILURE; - } - snprintf(conf_basename, strlen(argv[optind + 1]) - strlen(conf_suffix) + 1, "%s", argv[optind + 1]); snprintf(conf_filename, sizeof(conf_filename), "%s" , argv[optind + 1]); if (is_dropin_file) { @@ -622,7 +732,9 @@ int ret = 0; if (strcmp(argv[optind], "show") == 0) { - ret = econf_show(&key_file); + ret = econf_read(&key_file, delimiters, comment, true); + } else if (strcmp(argv[optind], "syntax") == 0) { + ret = econf_read(&key_file, delimiters, comment, false); } else if (strcmp(argv[optind], "edit") == 0) { if (!is_root || use_homedir) { /* adjust path to home directory of the user.*/ @@ -636,11 +748,11 @@ conf_filename); } - ret = econf_edit(&key_file); + ret = econf_edit(&key_file, delimiters, comment); } else if (strcmp(argv[optind], "revert") == 0) { - ret = econf_revert(is_root, use_homedir); + ret = econf_revert(is_root, use_homedir); } else if (strcmp(argv[optind], "cat") == 0) { - ret = econf_cat(); + ret = econf_cat(delimiters, comment); } else { fprintf(stderr, "Unknown command!\n\n"); usage();