From 4fb48c0bdbdfe78c17f440af428c210c698e69fb Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Mon, 2 Jan 2012 01:33:34 -0600 Subject: [PATCH] ps: generalize help text logic, add related translator hints This commit represents an experiment in nls help text support. The word --help itself been made translatable along with the help section names and their abbreviations. Thus, the work of the translators will ultimately alter program run-time behavior. Perhaps someday all "long" options can behave in a similar way which could offer a considerable benefit to other languages. Instead of translationg just option descriptions, the long forms of those options could also be transalated. This commit also: . includes the section abbreviations in --help output . isolates all --help support in the ps/help.c module . provides (hopefully) meaningful Translator guidance . removes --help support from the ps/common.h header . removes --help support from the ps/parser.c module . eliminates tabs in line with the style of other ps modules . eliminates the need for the include/c.h header file --- ps/common.h | 18 +--- ps/display.c | 7 +- ps/global.c | 10 +- ps/help.c | 277 ++++++++++++++++++++++++++++++++++----------------- ps/parser.c | 33 ++---- 5 files changed, 214 insertions(+), 131 deletions(-) diff --git a/ps/common.h b/ps/common.h index 1a68bd72..66d8d643 100644 --- a/ps/common.h +++ b/ps/common.h @@ -12,7 +12,6 @@ #ifndef PROCPS_PS_H #define PROCPS_PS_H -#include "../include/c.h" #include "../include/nls.h" #include "../proc/procps.h" #include "../proc/escape.h" @@ -27,17 +26,6 @@ /***************** GENERAL DEFINE ********************/ -/* usage output sections */ -enum { - USAGE_DEFAULT, - USAGE_ALL, - USAGE_SELECTION, - USAGE_LIST, - USAGE_OUTPUT, - USAGE_THREADS, - USAGE_MISC -}; - /* selection list */ #define SEL_RUID 1 #define SEL_EUID 2 @@ -325,9 +313,13 @@ extern unsigned thread_flags; extern int unix_f_option; extern int user_is_number; extern int wchan_is_number; +extern const char *the_word_help; /************************* PS GLOBALS *********************/ +/* display.c */ +extern char *myname; + /* sortformat.c */ extern int defer_sf_option(const char *arg, int source); extern const char *process_sf_options(int localbroken); @@ -338,7 +330,7 @@ extern int want_this_proc(proc_t *buf); extern const char *select_bits_setup(void); /* help.c */ -extern void usage(FILE * out, int section) NORETURN; +extern void do_help(const char *opt, int rc) NORETURN; /* global.c */ extern void self_info(void); diff --git a/ps/display.c b/ps/display.c index f1d90ae4..67d14390 100644 --- a/ps/display.c +++ b/ps/display.c @@ -34,6 +34,8 @@ #define SIGCHLD SIGCLD #endif +char *myname; + /* just reports a crash */ static void signal_handler(int signo){ if(signo==SIGPIPE) _exit(0); /* "ps | head" will cause this */ @@ -44,7 +46,7 @@ static void signal_handler(int signo){ "Please send bug reports to \n"), signo, signal_number_to_name(signo), - program_invocation_short_name, + myname, procps_version ); _exit(signo+128); @@ -523,6 +525,9 @@ static void fancy_spew(void){ /***** no comment */ int main(int argc, char *argv[]){ + myname = strrchr(*argv, '/'); + if (myname) ++myname; else myname = *argv; + setlocale (LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); diff --git a/ps/global.c b/ps/global.c index 111e269f..706d3e39 100644 --- a/ps/global.c +++ b/ps/global.c @@ -81,7 +81,7 @@ unsigned thread_flags = 0xffffffff; int unix_f_option = -1; int user_is_number = -1; int wchan_is_number = -1; - +const char *the_word_help; static void reset_selection_list(void){ selection_node *old; @@ -391,6 +391,14 @@ void reset_global(void){ unix_f_option = 0; user_is_number = 0; wchan_is_number = 0; +/* Translation Note: + . The following translatable word will be used to recognize the + . user's request for help text. In other words, the translation + . you provide will alter program behavior. + . + . It must be limited to 15 characters or less. + */ + the_word_help = _("help"); } static const char archdefs[] = diff --git a/ps/help.c b/ps/help.c index b0da7cb6..9ce9e769 100644 --- a/ps/help.c +++ b/ps/help.c @@ -12,101 +12,196 @@ #include #include #include +#include #include "common.h" -void usage(FILE * out, int section) NORETURN; -void usage(FILE * out, int section){ - fputs(USAGE_HEADER, out); - fprintf(out, - _(" %s [options]\n"), program_invocation_short_name); - if (section == USAGE_SELECTION || section == USAGE_ALL) { - fputs(_("\nSimple options:\n" - " -A all processes\n" - " -N, --deselect negate selection\n" - " -a all without tty and session leader\n" - " -d all except session leader\n" - " -e all processes\n" - " T all processes on this terminal\n" - " a all without tty, including other users\n" - " g obsolete, do not use\n" - " r only running processes\n" - " x processes without controlling ttys\n"), out); - } - if (section == USAGE_LIST || section == USAGE_ALL) { - fputs(_("\nSelection by list:\n" - " -C command name\n" - " U, -u, --user effective user id or name\n" - " -U, --User real user id or name\n" - " -G, --Group real group id or name\n" - " -g, --group session or effective group name\n" - " -p, --pid process id\n" - " --ppid select by parent process id\n" - " -s, --sid session id\n" - " t, -t, --tty terminal\n" - "\n selection take csv list e.g. `-u root,nobody'\n"), out); - } - if (section == USAGE_OUTPUT || section == USAGE_ALL) { - fputs(_("\nOutput formats:\n" - " o, -o, --format " - " user defined format\n" - " O preloaded -o allowing sorting\n" - " -O preloaded, with default columns, allowing sorting\n" - " -j jobs format\n" - " j BSD job control format\n" - " -l long format\n" - " l BSD long format\n" - " y do not show flags, show rrs in place addr (used with -l)\n" - " -f full-format\n" - " -F extra full\n" - " s signal format\n" - " v virtual memory\n" - " u user-oriented format\n" - " X register format\n" - " Z, -M security data (for SE Linux)\n" - " f, --forest ascii art process tree\n" - " -H show process hierarchy\n" - " --context display security context (for SE Linux)\n" - " --heading repeat header lines\n" - " --no-headers do not print header at all\n" - " --cols set screen width\n" - " --rows set screen height\n"), out); - } - if (section == USAGE_THREADS || section == USAGE_ALL) { - fputs(_("\nShow threads:\n" - " H as if they where processes\n" - " -L possibly with LWP and NLWP columns\n" - " -T possibly with SPID column\n" - " m, -m after processes\n"), out); - } - if (section == USAGE_MISC || section == USAGE_ALL) { - fputs(_("\nMisc options:\n" - " w, -w unlimited output width\n" - " L list format codes\n" - " c true command name\n" - " n display numeric uid and wchan\n" - " -y do not show flags, show rss (only with -l)\n" - " -c show scheduling class\n" - " --sort specify sort order, can be a csv list\n" - " S, --cumulative include some dead child process data\n" - " --info print debuggin information\n" - " V,-V, --version display version information and exit\n" - " --help \n" - " display help\n"), out); - } - if (section == USAGE_DEFAULT) - /* Translation Hint: do not translate arguments, that breaks - * string comparison. Outputting something like following - * might work. - * - * Zry `%s --help - * (zlekzio|lizt|czreen vrites|threadz|mizc|trezt) - */ - fprintf(out, _("\n Try `%s --help '\n" - " for more information.\n"), program_invocation_short_name); - fprintf(out, USAGE_MAN_TAIL("ps(1)")); - exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +enum { + HELP_SMP, HELP_LST, HELP_OUT, + HELP_THD, HELP_MSC, HELP_ALL, + HELP_default +}; + +static struct { + const char *word; + const char *abrv; +} help_tab[HELP_default]; + + +static int parse_help_opt (const char *opt) { +/* Translation Notes for ps Help #1 --------------------------------- + . This next group of lines represents 6 pairs of words + abbreviations + . which are the basis of the 'ps' program help text. + . + . The words and abbreviations you provide will alter program behavior. + . They will also appear in the help usage summary associated with the + . "Notes for ps Help #2" below. + . + . In their English form, help text would look like this: + . Try 'ps --help ' + . or 'ps --help ' + . for additional help text. + . + . When translating these 6 pairs you may choose any appropriate + . language equivalents and the only requirement is the abbreviated + . representations must be unique. + . + . By default, those abbreviations are single characters. However, + . they are not limited to only one character after translation. + . */ + +/* Translation Hint, Pair #1 */ + help_tab[HELP_SMP].word = _("simple"); help_tab[HELP_SMP].abrv = _("s"); +/* Translation Hint, Pair #2 */ + help_tab[HELP_LST].word = _("list"); help_tab[HELP_LST].abrv = _("l"); +/* Translation Hint, Pair #3 */ + help_tab[HELP_OUT].word = _("output"); help_tab[HELP_OUT].abrv = _("o"); +/* Translation Hint, Pair #4 */ + help_tab[HELP_THD].word = _("threads"); help_tab[HELP_THD].abrv = _("t"); +/* Translation Hint, Pair #5 */ + help_tab[HELP_MSC].word = _("misc"); help_tab[HELP_MSC].abrv = _("m"); +/* Translation Hint, Pair #6 */ + help_tab[HELP_ALL].word = _("all"); help_tab[HELP_ALL].abrv = _("a"); +/* + * the above are doubled on each line so they carry the same .pot + * line # reference and thus appear more like true "pairs" even + * though xgettext will produce separate msgid/msgstr groups */ + + if(opt) { + int i; + for (i = HELP_SMP; i < HELP_default; i++) + if (!strcmp(opt, help_tab[i].word) || !strcmp(opt, help_tab[i].abrv)) + return i; + } + return HELP_default; +} + + +void do_help (const char *opt, int rc) NORETURN; +void do_help (const char *opt, int rc) { + FILE *out = (rc == EXIT_SUCCESS) ? stdout : stderr; + int section = parse_help_opt(opt); + + fprintf(out, _("\n" + "Usage:\n" + " %s [options]\n"), myname); + + if (section == HELP_SMP || section == HELP_ALL) { + fprintf(out, _("\n" + "Basic options:\n" + " -A, -e all processes\n" + " -a all with tty, except session leaders\n" + " a all with tty, including other users\n" + " -d all except session leaders\n" + " -N, --deselect negate selection\n" + " r only running processes\n" + " T all processes on this terminal\n" + " x processes without controlling ttys\n")); + } + if (section == HELP_LST || section == HELP_ALL) { + fprintf(out, _("\n" + "Selection by list:\n" + " -C command name\n" + " -G, --Group real group id or name\n" + " -g, --group session or effective group name\n" + " -p, --pid process id\n" + " --ppid select by parent process id\n" + " -s, --sid session id\n" + " -t, t, --tty terminal\n" + " -u, U, --user effective user id or name\n" + " -U, --User real user id or name\n" + "\n" + " selection take either:\n" + " comma-separated list e.g. '-u root,nobody' or\n" + " blank-separated list e.g. '-p 123 4567'\n")); + } + if (section == HELP_OUT || section == HELP_ALL) { + fprintf(out, _("\n" + "Output formats:\n" + " -F extra full\n" + " -f full-format, including command lines\n" + " f, --forest ascii art process tree\n" + " -H show process hierarchy\n" + " -j jobs format\n" + " j BSD job control format\n" + " -l long format\n" + " l BSD long format\n" + " -M, Z add security data (for SE Linux)\n" + " -O preloaded with default columns\n" + " O as -O, with BSD personality\n" + " -o, o, --format \n" + " user defined format\n" + " s signal format\n" + " u user-oriented format\n" + " v virtual memory format\n" + " X register format\n" + " -y do not show flags, show rrs vs. addr (used with -l)\n" + " --context display security context (for SE Linux)\n" + " --headers repeat header lines, one per page\n" + " --no-headers do not print header at all\n" + " --cols, --columns, --width \n" + " set screen width\n" + " --rows, --lines \n" + " set screen height\n")); + } + if (section == HELP_THD || section == HELP_ALL) { + fprintf(out, _("\n" + "Show threads:\n" + " H as if they where processes\n" + " -L possibly with LWP and NLWP columns\n" + " -m, m after processes\n" + " -T possibly with SPID column\n")); + } + if (section == HELP_MSC || section == HELP_ALL) { + fprintf(out, _("\n" + "Miscellaneous options:\n" + " -c show scheduling class with -l option\n" + " c show true command name\n" + " e show the environment after command\n" + " k, --sort specify sort order as: [+|-]key[,[+|-]key[,...]]\n" + " L list format specifiers\n" + " n display numeric uid and wchan\n" + " S, --cumulative include some dead child process data\n" + " -y do not show flags, show rss (only with -l)\n" + " -V, V, --version display version information and exit\n" + " -w, w unlimited output width\n" + "\n" + " --%s <%s|%s|%s|%s|%s|%s>\n" + " display help and exit\n") + , the_word_help + , help_tab[HELP_SMP].word, help_tab[HELP_LST].word + , help_tab[HELP_OUT].word, help_tab[HELP_THD].word + , help_tab[HELP_MSC].word, help_tab[HELP_ALL].word); + } + if (section == HELP_default) { +/* Translation Notes for ps Help #2 --------------------------------- + . Most of the following c-format string is derived from the 6 + . pairs of words + chars mentioned above in "Notes for ps Help #1". + . + . In its full English form, help text would look like this: + . Try 'ps --help ' + . or 'ps --help ' + . for additional help text. + . + . The word for "help" will be translated elsewhere. Thus, the only + . translations below will be: "Try", "or" and "for additional...". + . */ + fprintf(out, _("\n" + " Try '%s --%s <%s|%s|%s|%s|%s|%s>'\n" + " or '%s --%s <%s|%s|%s|%s|%s|%s>'\n" + " for additional help text.\n") + , myname, the_word_help + , help_tab[HELP_SMP].word, help_tab[HELP_LST].word + , help_tab[HELP_OUT].word, help_tab[HELP_THD].word + , help_tab[HELP_MSC].word, help_tab[HELP_ALL].word + , myname, the_word_help + , help_tab[HELP_SMP].abrv, help_tab[HELP_LST].abrv + , help_tab[HELP_OUT].abrv, help_tab[HELP_THD].abrv + , help_tab[HELP_MSC].abrv, help_tab[HELP_ALL].abrv); + } + fprintf(out, _("\nFor more details see ps(1).\n")); + exit(rc); } /* Missing: diff --git a/ps/parser.c b/ps/parser.c index 329b0ed3..fefde644 100644 --- a/ps/parser.c +++ b/ps/parser.c @@ -153,22 +153,6 @@ found_it: return 0; } -static int parse_usage_section(const char *opt){ - if (!strcmp(opt, "s") || !strcmp(opt, "selection")) - return USAGE_SELECTION; - if (!strcmp(opt, "l") || !strcmp(opt, "list")) - return USAGE_LIST; - if (!strcmp(opt, "o") || !strcmp(opt, "output")) - return USAGE_OUTPUT; - if (!strcmp(opt, "t") || !strcmp(opt, "threads")) - return USAGE_THREADS; - if (!strcmp(opt, "m") || !strcmp(opt, "misc")) - return USAGE_MISC; - if (!strcmp(opt, "a") || !strcmp(opt, "all")) - return USAGE_ALL; - return USAGE_DEFAULT; -} - /* * Used to parse lists in a generic way. (function pointers) */ @@ -793,7 +777,6 @@ static const char *parse_gnu_option(void){ char buf[16]; gnu_table_struct findme = { buf, NULL}; gnu_table_struct *found; - int usage_section; static const gnu_table_struct gnu_table[] = { {"Group", &&case_Group}, /* rgid */ {"User", &&case_User}, /* ruid */ @@ -809,7 +792,7 @@ static const char *parse_gnu_option(void){ {"headers", &&case_headers}, {"heading", &&case_heading}, {"headings", &&case_headings}, - {"help", &&case_help}, +//{"help", &&case_help}, /* now TRANSLATABLE ! */ {"info", &&case_info}, {"lines", &&case_lines}, {"no-header", &&case_no_header}, @@ -843,7 +826,11 @@ static const char *parse_gnu_option(void){ sizeof(gnu_table_struct), compare_gnu_table_structs ); - if(!found) return _("Unknown gnu long option."); + if(!found) { + if (!strcmp(buf, the_word_help)) + goto case_help; + return _("Unknown gnu long option."); + } goto *(found->jump); /* See gcc extension info. :-) */ @@ -932,11 +919,7 @@ static const char *parse_gnu_option(void){ case_help: trace("--help\n"); arg = grab_gnu_arg(); - if(!arg) - usage_section = USAGE_DEFAULT; - else - usage_section = parse_usage_section(arg); - usage(stdout, usage_section); + do_help(arg, EXIT_SUCCESS); case_info: trace("--info\n"); exclusive("--info"); @@ -1266,5 +1249,5 @@ total_failure: reset_parser(); if(personality & PER_FORCE_BSD) fprintf(stderr, _("ERROR: %s\n"), err2); else fprintf(stderr, _("ERROR: %s\n"), err); - usage(stderr, USAGE_DEFAULT); + do_help(NULL, EXIT_FAILURE); }