]> granicus.if.org Git - procps-ng/commitdiff
ps: generalize help text logic, add related translator hints
authorJim Warner <james.warner@comcast.net>
Mon, 2 Jan 2012 07:33:34 +0000 (01:33 -0600)
committerCraig Small <csmall@enc.com.au>
Tue, 3 Jan 2012 21:58:53 +0000 (08:58 +1100)
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
ps/display.c
ps/global.c
ps/help.c
ps/parser.c

index 1a68bd726f9d5fa42635b3924d04546af9adec9d..66d8d6436602df64d516f798b26b814fa6c66d11 100644 (file)
@@ -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"
 
 /***************** 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);
index f1d90ae488faef58f56fe8c6e90918e157ee86be..67d14390ef18b8500e4ca6b386b2341d7655e335 100644 (file)
@@ -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 <procps@freelists.org>\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);
index 111e269f10c70ee5c094708023ae1c01f4d67a58..706d3e39852349e41b2c8840e762807d406e5037 100644 (file)
@@ -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[] =
index b0da7cb6937bbeb47ddcda024128cb9f8ba805ba..9ce9e769a398d44b475f6a17d4a12f3f761b26fb 100644 (file)
--- a/ps/help.c
+++ b/ps/help.c
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #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>         command name\n"
-               " U, -u, --user <uid>  effective user id or name\n"
-               " -U, --User <uid>     real user id or name\n"
-               " -G, --Group <gid>    real group id or name\n"
-               " -g, --group <group>  session or effective group name\n"
-               " -p, --pid <pid>      process id\n"
-               " --ppid <pid>         select by parent process id\n"
-               " -s, --sid <session>  session id\n"
-               " t, -t, --tty <tty>   terminal\n"
-               "\n selection <arguments> take csv list e.g. `-u root,nobody'\n"), out);
-       }
-       if (section == USAGE_OUTPUT || section == USAGE_ALL) {
-       fputs(_("\nOutput formats:\n"
-               " o, -o, --format <format>"
-               "                  user defined format\n"
-               " O  <format>      preloaded -o allowing sorting\n"
-               " -O <format>      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 <num>     set screen width\n"
-               " --rows <num>     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 <spec>    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 <selection|list|output|threads|misc|all>\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 <selection|list|output|threads|misc|all>
-        *                (zlekzio|lizt|czreen vrites|threadz|mizc|trezt)
-        */
-       fprintf(out, _("\n Try `%s --help <selection|list|output|threads|misc|all>'\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 <simple|list|output|threads|misc|all>'
+   .       or 'ps --help <s|l|o|t|m|a>'
+   .      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>         command name\n"
+      " -G, --Group <gid>    real group id or name\n"
+      " -g, --group <group>  session or effective group name\n"
+      " -p, --pid <pid>      process id\n"
+      "     --ppid <pid>     select by parent process id\n"
+      " -s, --sid <session>  session id\n"
+      " -t, t, --tty <tty>   terminal\n"
+      " -u, U, --user <uid>  effective user id or name\n"
+      " -U, --User <uid>     real user id or name\n"
+      "\n"
+      "  selection <arguments> 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 <format>          preloaded with default columns\n"
+      "  O <format>          as -O, with BSD personality\n"
+      " -o, o, --format <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 <num>\n"
+      "                      set screen width\n"
+      "     --rows, --lines <num>\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 <simple|list|output|threads|misc|all>'
+   .       or 'ps --help <s|l|o|t|m|a>'
+   .      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:
index 329b0ed31d5fc02bcb4b261247c6d1ad2a7f60b2..fefde644a54de21acd4adcb6da6719dfcf6d8984 100644 (file)
@@ -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);
 }