This is just a proof of concept. I'd like to know this approach may be accepted.
It helps avoid manual aligning of help text, which is boring (e.g. chmod's --no-preserve-root does it wrong) and impossible to do right for shared options such as --verbose and --help. It also helps avoid misalignment in translations because translators may not notice that the number of spaces in such a translations has a special meaning. The convenient function may end up in gnulib, I don't know. Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com> --- lib/Makefile.am | 2 +- lib/usage.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/usage.h | 4 ++++ src/chmod.c | 40 ++++++++++++++++++-------------- 4 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 lib/usage.c create mode 100644 lib/usage.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 885f9b2..d8851af 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -31,7 +31,7 @@ include gnulib.mk AM_CFLAGS += $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS) libcoreutils_a_SOURCES += \ - buffer-lcm.c buffer-lcm.h + buffer-lcm.c buffer-lcm.h usage.c libcoreutils_a_LIBADD += $(LIBOBJS) libcoreutils_a_DEPENDENCIES += $(LIBOBJS) diff --git a/lib/usage.c b/lib/usage.c new file mode 100644 index 0000000..e2ecc00 --- /dev/null +++ b/lib/usage.c @@ -0,0 +1,72 @@ +#include <config.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <gettext.h> +#include "xalloc.h" + +#define _(msgid) gettext (msgid) + +int print_usage(const char **help) +{ + int i; + int arg_len = 0; + char *buf; + + for (i = 0; help[i]; i++) + { + const char *h = _(help[i]); + int len; + if (i % 2) + continue; + len = h[0] == '-' && h[1] == '-' ? 4 : 0; + len += strlen (h); + if (len > arg_len) + arg_len = len; + } + + arg_len += 4; /* two leading and trailing spaces */ + buf = xmalloc (arg_len + 1); + memset (buf, ' ', arg_len); + buf[arg_len] = '\0'; + + for (i = 0; help[i]; i += 2) + { + const char *a = _(help[i]); + const char *h = _(help[i + 1]); + int p = 2; + + if (!h) + { + free (buf); + return -1; + } + + if (a[0] == '-' && a[1] == '-') + p += 4; + memcpy (buf + p, a, strlen (a)); + fputs (buf, stdout); + memset (buf, ' ', arg_len); + + while (*h) + { + const char *newline = strchr (h, '\n'); + if (newline) + { + fwrite (h, newline + 1 - h, 1, stdout); + fputs (buf, stdout); + h = newline + 1; + } + else + { + fputs (h, stdout); + break; + } + } + fputs ("\n", stdout); + } + + free (buf); + + return 0; +} diff --git a/lib/usage.h b/lib/usage.h new file mode 100644 index 0000000..64e3bc0 --- /dev/null +++ b/lib/usage.h @@ -0,0 +1,4 @@ +#ifndef __USAGE_H__ +#define __USAGE_H__ +extern int print_usage(const char **help); +#endif diff --git a/src/chmod.c b/src/chmod.c index a54078c..5e790a3 100644 --- a/src/chmod.c +++ b/src/chmod.c @@ -31,6 +31,7 @@ #include "quotearg.h" #include "root-dev-ino.h" #include "xfts.h" +#include "usage.h" /* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "chmod" @@ -107,6 +108,27 @@ static struct option const long_options[] = {NULL, 0, NULL, 0} }; +static const char *option_help[] = +{ + N_("-c, --changes"), + N_("like --verbose but report only when a change is made"), + N_("-f, --silent, --quiet"), + N_("suppress most error messages"), + N_("-v, --verbose"), + N_("output a diagnostic for every file processed"), + N_("--no-preserve-root"), + N_("do not treat '/' specially (the default)"), + N_("--preserve-root"), + N_("fail to operate recursively on '/'"), + N_("--reference=RFILE"), + N_("use RFILE's mode instead of MODE values"), + N_("-R, --recursive"), + N_("change files and directories recursively"), + N_("--help"), N_("display this help and exit"), + N_("--version"), N_("output version information and exit"), + NULL +}; + /* Return true if the chmodable permission bits of FILE changed. The old mode was OLD_MODE, but it was changed to NEW_MODE. */ @@ -379,23 +401,7 @@ Change the mode of each FILE to MODE.\n\ With --reference, change the mode of each FILE to that of RFILE.\n\ \n\ "), stdout); - fputs (_("\ - -c, --changes like verbose but report only when a change is made\n\ - -f, --silent, --quiet suppress most error messages\n\ - -v, --verbose output a diagnostic for every file processed\n\ -"), stdout); - fputs (_("\ - --no-preserve-root do not treat '/' specially (the default)\n\ - --preserve-root fail to operate recursively on '/'\n\ -"), stdout); - fputs (_("\ - --reference=RFILE use RFILE's mode instead of MODE values\n\ -"), stdout); - fputs (_("\ - -R, --recursive change files and directories recursively\n\ -"), stdout); - fputs (HELP_OPTION_DESCRIPTION, stdout); - fputs (VERSION_OPTION_DESCRIPTION, stdout); + print_usage (option_help); fputs (_("\ \n\ Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=][0-7]+'.\n\ -- 1.7.12.rc2.18.g61b472e