From 77cc9b39a4f04f95767a5186189ebf282cdadfe9 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Thu, 15 Apr 2021 19:07:41 -0400 Subject: [PATCH] Use option generator script from dxcommon. Instead of maintaining the relation between long options and help text directly in C code, let's use this new script to generate C code from a simple description file. --- Makefile.am | 11 +++- configure.ac | 1 + m4/gnulib-cache.m4 | 2 + src/.gitignore | 1 + src/options.opt | 12 ++++ src/slotifier.c | 141 ++++++++++++++++++++++++++------------------- 6 files changed, 109 insertions(+), 59 deletions(-) create mode 100644 src/.gitignore create mode 100644 src/options.opt diff --git a/Makefile.am b/Makefile.am index 3d9b938..891cc75 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,10 +20,11 @@ AM_CFLAGS = $(LIBGERBV_CFLAGS) $(CNEARTREE_CFLAGS) bin_PROGRAMS = slotifier -slotifier_SOURCES = src/slotifier.c +slotifier_SOURCES = src/slotifier.c src/options.h slotifier_LDADD = $(LIBGERBV_LIBS) $(CNEARTREE_LIBS) libgnu.a \ $(LTLIBICONV) $(LTLIBINTL) $(HYPOT_LIBM) $(slotifier_OBJECTS): $(gnulib_headers) +$(slotifier_OBJECTS): src/options.h dist_man_MANS = doc/slotifier.1 @@ -78,6 +79,14 @@ distcheck-hook: echo ' *** Remember to update NEWS before preparing a release.'; \ $(TEST_DISTRIBUTION_OR_ERROR); } >&2 +OPTFILES = src/options.opt +.opt.h: + $(AM_V_GEN) $(AWK) -f $(DX_BASEDIR)/scripts/gen-options.awk $< >$@.tmp + $(AM_V_at) mv -f $@.tmp $@ +$(OPTFILES:.opt=.h): $(DX_BASEDIR)/scripts/gen-options.awk +MAINTAINERCLEANFILES += $(OPTFILES:.opt=.h) +EXTRA_DIST += $(DX_BASEDIR)/scripts/gen-options.awk $(OPTFILES) + # Supporting rules for gettext. include $(top_srcdir)/common/snippet/gettext.mk noinst_DATA = $(MOFILES) diff --git a/configure.ac b/configure.ac index c622738..28ad954 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,7 @@ AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([-Wall -Wno-portability foreign subdir-objects dist-xz]) AM_SILENT_RULES([yes]) +DX_AUTOMAKE_COMPAT AC_PROG_CC AM_PROG_CC_C_O diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4 index 8df890f..436ee41 100644 --- a/m4/gnulib-cache.m4 +++ b/m4/gnulib-cache.m4 @@ -44,6 +44,7 @@ # gitlog-to-changelog \ # hypot \ # localcharset \ +# mbswidth \ # striconv # Specification in the form of a few gnulib-tool.m4 macro invocations: @@ -54,6 +55,7 @@ gl_MODULES([ gitlog-to-changelog hypot localcharset + mbswidth striconv ]) gl_AVOID([]) diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..82a27fa --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +/options.h diff --git a/src/options.opt b/src/options.opt new file mode 100644 index 0000000..f04d22f --- /dev/null +++ b/src/options.opt @@ -0,0 +1,12 @@ +-o, --output=FILE +Write drill data to FILE instead of standard output. + +-v, --verbose +Increase verbosity (can be specified multiple times for +increased effect). + +-V, --version +Print a version message and then exit. + +-H, --help +Print this message and then exit. diff --git a/src/slotifier.c b/src/slotifier.c index 05ede6b..19865c0 100644 --- a/src/slotifier.c +++ b/src/slotifier.c @@ -19,17 +19,18 @@ #include #include #include -#include #include -#include -#include #include +#include + #include #include +#include +#include +#include + #include #include -#include -#include #if !ENABLE_NLS # undef ENABLE_NLS @@ -38,16 +39,14 @@ #define _(x) (gettext(x)) +static const char *progname = "slotifier"; static unsigned verbose; -static const char *progname = "slotifier"; -static const char sopts[] = "o:vVH"; +#include "options.h" +static const char sopts[] = SOPT_STRING; static const struct option lopts[] = { - { "output", 1, NULL, 'o' }, - { "verbose", 0, NULL, 'v' }, - { "version", 0, NULL, 'V' }, - { "help", 0, NULL, 'H' }, - { 0 } + LOPTS_INITIALIZER, + {0} }; static void print_version(void) @@ -79,9 +78,69 @@ static void print_usage(FILE *f) progname); } +static int +print_optstring(const struct option *opt, const struct lopt_help *help) +{ + char optstring[100]; + int w; + + if (!ENABLE_NLS) + goto no_translate; + + if (opt->has_arg) { + w = snprintf(optstring, sizeof optstring, + _(" -%c, --%s=%s"), opt->val, opt->name, + pgettext_expr(opt->name, help->arg)); + } else { + w = snprintf(optstring, sizeof optstring, + _(" -%c, --%s"), opt->val, opt->name); + } + + if (w < 0) + goto no_translate; + + w = mbsnwidth(optstring, w, 0); + printf("%s", optstring); + goto out; + +no_translate: + if (opt->has_arg) { + w = printf(" -%c, --%s=%s", opt->val, opt->name, help->arg); + } else { + w = printf(" -%c, --%s", opt->val, opt->name); + } +out: + if (w < 0 || w > 18) { + putchar('\n'); + return 0; + } + + return w; +} + +/* + * Print a string, with each line indented by i spaces. The first line + * will be indented by w fewer spaces (to account for the cursor being in + * some other column). + */ +static void print_block(const char *s, int i, int w) +{ + for (; *s; w = 0) { + const char *nl = strchr(s, '\n'); + int n = (nl ? nl-s : -1); + + printf("%*s%.*s\n", i-w, "", n, s); + if (!nl) + break; + + s = nl+1; + } +} + static void print_help(void) { const struct option *opt; + print_usage(stdout); puts(_("This is \"slotifier\": a tool to convert overlapping drill hits in Excellon\n" @@ -90,63 +149,29 @@ static void print_help(void) puts(_("Options:")); for (opt = lopts; opt->val; opt++) { - const char *line, *text = "ARG"; - int w = 0; + struct lopt_help help; + int w; - if (opt->has_arg) { - switch (opt->val) { - case 'o': text = _("FILE"); - } - - w += printf(_(" -%c, --%s=%s"), - opt->val, opt->name, text); - } else { - w += printf(_(" -%c, --%s"), opt->val, opt->name); - } - - if (w > 18) { - putchar('\n'); - w = 0; - } - - switch (opt->val) { - case 'o': - text = _("Output to FILE, instead of standard output."); - break; - case 'v': - text = _("Increase verbosity (can be specified more than once)."); - break; - case 'V': - text = _("Print a version message and then exit."); - break; - case 'H': - text = _("Print this message and then exit."); - break; - default: - if (w) - putchar('\n'); + if (!lopt_get_help(opt, &help)) continue; - } - for (line = text; line[0];) { - const char *nl = strchr(line, '\n'); + w = print_optstring(opt, &help); - if (!nl) { - printf("%*s%s\n", 20-w, "", line); - break; - } + if (ENABLE_NLS) + help.desc = pgettext_expr(opt->name, help.desc); - printf("%*s%.*s\n", 20-w, "", (int)(nl-line), line); - line = nl+1; - } + print_block(help.desc, 20, w); } putchar('\n'); puts(_("For more information, see the slotifier(1) man page.")); putchar('\n'); - printf(_("Report bugs to <%s>."), PACKAGE_BUGREPORT); - putchar('\n'); + /* + * TRANSLATORS: Please add *another line* indicating where users should + * report translation bugs. + */ + printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT); } static void init_i18n(void) -- 2.43.0