From 566ca36af8e1f5955a43377f7044bc664d8b6dff Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Wed, 1 Jul 2026 11:57:07 +0300 Subject: [PATCH] fixed little bug with long-only options --- examples/cmdlnopts.c | 2 ++ locale/ru/messages.po | 8 ++++---- locale/ru/ru.po | 10 ++++------ parseargs.c | 27 +++++++++++++++++++-------- 4 files changed, 29 insertions(+), 18 deletions(-) diff --git a/examples/cmdlnopts.c b/examples/cmdlnopts.c index 0de807f..d576cf4 100644 --- a/examples/cmdlnopts.c +++ b/examples/cmdlnopts.c @@ -52,6 +52,8 @@ static glob_pars const Gdefault = { * name has_arg flag val type argptr help * BE carefull! The `help` field is mandatory! Omitting it equivalent of 'end_option' */ +// if val < 33 || val > 127 we mean this like long-only option; +// you can repeat the same `val` for several long-only options without any problem static sl_option_t cmdlnopts[] = { // short option in only-long options should be zeroed, or you can add flag to set it to given value {"lo0", NEED_ARG, NULL, 0, arg_int, APTR(&G.lo0), _("only long arg 0 (int)")}, diff --git a/locale/ru/messages.po b/locale/ru/messages.po index 51651b7..2061371 100644 --- a/locale/ru/messages.po +++ b/locale/ru/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-03-04 17:48+0300\n" +"POT-Creation-Date: 2026-03-31 11:35+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -36,7 +36,7 @@ msgstr "" msgid "Configuration file options (format: key=value):\n" msgstr "" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:69 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:70 #, c-format msgid "" "\n" @@ -44,11 +44,11 @@ msgid "" msgstr "" #. error reading self name -#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:117 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:95 msgid "Can't read self name" msgstr "" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:141 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:119 msgid "Can't open PID file" msgstr "" diff --git a/locale/ru/ru.po b/locale/ru/ru.po index a99b630..ba470b4 100644 --- a/locale/ru/ru.po +++ b/locale/ru/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2026-03-04 17:30+0300\n" + "POT-Creation-Date: 2026-03-31 11:31+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -35,7 +35,7 @@ msgstr "sl_conf_showhelp(): msgid "Configuration file options (format: key=value):\n" msgstr "Опции конфигурационного файла (формат: ключ=значение):\n" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:69 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:70 #, c-format msgid "\n" "Found running process (pid=%d), exit.\n" @@ -43,11 +43,11 @@ msgstr "\n" "Обнаружен одноименный процесс (pid=%d), выход.\n" #. error reading self name -#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:117 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:95 msgid "Can't read self name" msgstr "Не могу прочесть имя процесса" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:141 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:119 msgid "Can't open PID file" msgstr "Не могу открыть PID файл" @@ -236,5 +236,3 @@ msgstr " #: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:331 msgid "Can't setup console" msgstr "Не могу настроить консоль" - -#, c-format diff --git a/parseargs.c b/parseargs.c index 02ee35b..421a4e1 100644 --- a/parseargs.c +++ b/parseargs.c @@ -30,6 +30,9 @@ #include // isalpha #include "usefull_macros.h" +// check `val` field: if it's <33 || >127 - it's just ordered number, not short option +#define CHKOPTVAL(Oval) ((Oval) > 32 && (Oval) < 128) + const char *helpstring = NULL; // will be inited later, can't init with gettext on this stage /** @@ -130,8 +133,15 @@ static int get_optind(const char *key, int opt, sl_option_t *options, void (*hel helpfun(-1, options); return -1; // never reached until `helpfun` changed }else if(opt == ':') theopt = optopt; // search to show helpstring "need parameter" - for(oind = 0; opts->help && opts->val != theopt; oind++, opts++){ - DBG("cmp %c and %c", theopt, opts->val); + if(key[1] != '-'){ // search by unique short option + for(oind = 0; opts->help && opts->val != theopt; oind++, opts++){ + DBG("cmp %c and %c", theopt, opts->val); + } + }else{ // search by long option + key += 2; + for(oind = 0; opts->help; oind++, opts++){ + if(opts->name && 0 == strcmp(key, opts->name)) break; + } } if(!opts->help) return -1; if(opt == ':'){ @@ -249,7 +259,7 @@ void sl_parseargs_hf(int *argc, char ***argv, sl_option_t *options, void (*helpf loptr->flag = opts->flag; loptr->val = opts->val; // fill short options if they are: - if(!opts->flag && opts->val){ + if(!opts->flag && CHKOPTVAL(opts->val)){ shortlist[i] = (char) opts->val; *soptr++ = opts->val; if(loptr->has_arg) // add ':' if option has required argument @@ -371,21 +381,22 @@ void sl_parseargs(int *argc, char ***argv, sl_option_t *options){ /** * @brief argsort - compare function for qsort - * first - sort by short options; second - sort arguments without sort opts (by long options) + * first - sort by short options; second - sort arguments without short opts (by long options) */ static int argsort(const void *a1, const void *a2){ const sl_option_t *o1 = (sl_option_t*)a1, *o2 = (sl_option_t*)a2; const char *l1 = o1->name, *l2 = o2->name; int s1 = o1->val, s2 = o2->val; + int chk1 = CHKOPTVAL(s1), chk2 = CHKOPTVAL(s2); int *f1 = o1->flag, *f2 = o2->flag; // check if both options has short arg - if(f1 == NULL && f2 == NULL && s1 && s2){ // both have short arg + if(f1 == NULL && f2 == NULL && chk1 && chk2){ // both have short arg return (s1 - s2); - }else if((f1 != NULL || !s1) && (f2 != NULL || !s2)){ // both don't have short arg - sort by long + }else if((f1 != NULL || !chk1) && (f2 != NULL || !chk2)){ // both don't have short arg - sort by long assert(l1); assert(l2); // no way to omit long option if short is absent return strcmp(l1, l2); }else{ // only one have short arg -- return it - if(f2 || !s2) return -1; // a1 have short - it is 'lesser' + if(f2 || !chk2) return -1; // a1 have short - it is 'lesser' else return 1; } } @@ -394,7 +405,7 @@ static int argsort(const void *a1, const void *a2){ static void pr_helpstring(sl_option_t *opt, char *buf, int indent, size_t bufsz){ size_t p = sprintf(buf, " "); // a little indent int havelongopt = opt->name && *opt->name; - if(!opt->flag && opt->val){ // .val is short argument + if(!opt->flag && CHKOPTVAL(opt->val)){ // .val is short argument p += snprintf(buf+p, bufsz-p, "-%c", opt->val); if(havelongopt) p += snprintf(buf+p, bufsz-p, ", "); // show comma only it there's shor arg }