No specific user configuration
[platform/upstream/bash.git] / builtins / help.def
index 234307b..1894f17 100644 (file)
@@ -1,35 +1,46 @@
 This file is help.def, from which is created help.c.
 It implements the builtin "help" in Bash.
 
-Copyright (C) 1987-2002 Free Software Foundation, Inc.
+Copyright (C) 1987-2013 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
-Bash is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
+Bash is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
-Bash is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
+Bash is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License along
-with Bash; see the file COPYING.  If not, write to the Free Software
-Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
+You should have received a copy of the GNU General Public License
+along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 
 $PRODUCES help.c
 
 $BUILTIN help
 $FUNCTION help_builtin
 $DEPENDS_ON HELP_BUILTIN
-$SHORT_DOC help [-s] [pattern ...]
-Display helpful information about builtin commands.  If PATTERN is
+$SHORT_DOC help [-dms] [pattern ...]
+Display information about builtin commands.
+
+Displays brief summaries of builtin commands.  If PATTERN is
 specified, gives detailed help on all commands matching PATTERN,
-otherwise a list of the builtins is printed.  The -s option
-restricts the output for each builtin command matching PATTERN to
-a short usage synopsis.
+otherwise the list of help topics is printed.
+
+Options:
+  -d   output short description for each topic
+  -m   display usage in pseudo-manpage format
+  -s   output only a short usage synopsis for each topic matching
+       PATTERN
+
+Arguments:
+  PATTERN      Pattern specifiying a help topic
+
+Exit Status:
+Returns success unless PATTERN is not found or an invalid option is given.
 $END
 
 #include <config.h>
@@ -48,6 +59,8 @@ $END
 
 #include <filecntl.h>
 
+#include "../bashintl.h"
+
 #include "../shell.h"
 #include "../builtins.h"
 #include "../pathexp.h"
@@ -61,7 +74,13 @@ $END
 extern int errno;
 #endif
 
+extern const char * const bash_copyright;
+extern const char * const bash_license;
+
 static void show_builtin_command_help __P((void));
+static int open_helpfile __P((char *));
+static void show_desc __P((char *, int));
+static void show_manpage __P((char *, int));
 static void show_longdoc __P((int));
 
 /* Print out a list of the known functions in the shell, and what they do.
@@ -73,14 +92,20 @@ help_builtin (list)
 {
   register int i;
   char *pattern, *name;
-  int plen, match_found, sflag;
+  int plen, match_found, sflag, dflag, mflag, m, pass, this_found;
 
-  sflag = 0;
+  dflag = sflag = mflag = 0;
   reset_internal_getopt ();
-  while ((i = internal_getopt (list, "s")) != -1)
+  while ((i = internal_getopt (list, "dms")) != -1)
     {
       switch (i)
        {
+       case 'd':
+         dflag = 1;
+         break;
+       case 'm':
+         mflag = 1;
+         break;
        case 's':
          sflag = 1;
          break;
@@ -102,7 +127,7 @@ help_builtin (list)
 
   if (glob_pattern_p (list->word->word))
     {
-      printf ("Shell commands matching keyword%s `", list->next ? "s" : "");
+      printf (ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
       print_word_list (list, ", ");
       printf ("'\n\n");
     }
@@ -112,25 +137,49 @@ help_builtin (list)
       pattern = list->word->word;
       plen = strlen (pattern);
 
-      for (i = 0; name = shell_builtins[i].name; i++)
+      for (pass = 1, this_found = 0; pass < 3; pass++)
        {
-         QUIT;
-         if ((strncmp (pattern, name, plen) == 0) ||
-             (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH))
+         for (i = 0; name = shell_builtins[i].name; i++)
            {
-             printf ("%s: %s\n", name, shell_builtins[i].short_doc);
-
-             if (sflag == 0)
-               show_longdoc (i);
-
-             match_found++;
+             QUIT;
+
+             /* First pass: look for exact string or pattern matches.
+                Second pass: look for prefix matches like bash-4.2 */
+             if (pass == 1)
+               m = (strcmp (pattern, name) == 0) ||
+                   (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH);
+             else
+               m = strncmp (pattern, name, plen) == 0;
+
+             if (m)
+               {
+                 this_found = 1;
+                 match_found++;
+                 if (dflag)
+                   {
+                     show_desc (name, i);
+                     continue;
+                   }
+                 else if (mflag)
+                   {
+                     show_manpage (name, i);
+                     continue;
+                   }
+
+                 printf ("%s: %s\n", name, _(shell_builtins[i].short_doc));
+
+                 if (sflag == 0)
+                   show_longdoc (i);
+               }
            }
+         if (pass == 1 && this_found == 1)
+           break;
        }
     }
 
   if (match_found == 0)
     {
-      builtin_error ("no help topics match `%s'.  Try `help help' or `man -k %s' or `info %s'.", pattern, pattern, pattern);
+      builtin_error (_("no help topics match `%s'.  Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern);
       return (EXECUTION_FAILURE);
     }
 
@@ -138,6 +187,21 @@ help_builtin (list)
   return (EXECUTION_SUCCESS);
 }
 
+static int
+open_helpfile (name)
+     char *name;
+{
+  int fd;
+
+  fd = open (name, O_RDONLY);
+  if (fd == -1)
+    {
+      builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
+      return -1;
+    }
+  return fd;
+}
+
 /* By convention, enforced by mkbuiltins.c, if separate help files are being
    used, the long_doc array contains one string -- the full pathname of the
    help file for this builtin.  */
@@ -153,50 +217,301 @@ show_longdoc (i)
 
   if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
     {
-      fd = open (doc[0], O_RDONLY);
-      if (fd == -1)
-       {
-         builtin_error ("%s: cannot open: %s", doc[0], strerror (errno));
-         return;
-       }
+      fd = open_helpfile (doc[0]);
+      if (fd < 0)
+       return;
       zcatfd (fd, 1, doc[0]);
       close (fd);
     }
-  else
+  else if (doc)
     for (j = 0; doc[j]; j++)
-      printf ("    %s\n", doc[j]);
+      printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
+}
+
+static void
+show_desc (name, i)
+     char *name;
+     int i;
+{
+  register int j;
+  char **doc, *line;
+  int fd, usefile;
+
+  doc = (char **)shell_builtins[i].long_doc;
+
+  usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
+  if (usefile)
+    {
+      fd = open_helpfile (doc[0]);
+      if (fd < 0)
+       return;
+      zmapfd (fd, &line, doc[0]);
+      close (fd);
+    }
+  else
+    line = doc ? doc[0] : (char *)NULL;
+
+  printf ("%s - ", name);
+  for (j = 0; line && line[j]; j++)
+    {
+      putchar (line[j]);
+      if (line[j] == '\n')
+       break;
+    }
+  
+  fflush (stdout);
+
+  if (usefile)
+    free (line);
 }
 
+/* Print builtin help in pseudo-manpage format. */
+static void
+show_manpage (name, i)
+     char *name;
+     int i;
+{
+  register int j;
+  char **doc, *line;
+  int fd, usefile;
+
+  doc = (char **)shell_builtins[i].long_doc;
+
+  usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
+  if (usefile)
+    {
+      fd = open_helpfile (doc[0]);
+      if (fd < 0)
+       return;
+      zmapfd (fd, &line, doc[0]);
+      close (fd);
+    }
+  else
+    line = doc ? _(doc[0]) : (char *)NULL;
+
+  /* NAME */
+  printf ("NAME\n");
+  printf ("%*s%s - ", BASE_INDENT, " ", name);
+  for (j = 0; line && line[j]; j++)
+    {
+      putchar (line[j]);
+      if (line[j] == '\n')
+       break;
+    }
+  printf ("\n");
+
+  /* SYNOPSIS */
+  printf ("SYNOPSIS\n");
+  printf ("%*s%s\n\n", BASE_INDENT, " ", _(shell_builtins[i].short_doc));
+
+  /* DESCRIPTION */
+  printf ("DESCRIPTION\n");
+  if (usefile == 0)
+    {
+      for (j = 0; doc[j]; j++)
+        printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
+    }
+  else
+    {
+      for (j = 0; line && line[j]; j++)
+       {
+         putchar (line[j]);
+         if (line[j] == '\n')
+           printf ("%*s", BASE_INDENT, " ");
+       }
+    }
+  putchar ('\n');
+
+  /* SEE ALSO */
+  printf ("SEE ALSO\n");
+  printf ("%*sbash(1)\n\n", BASE_INDENT, " ");
+
+  /* IMPLEMENTATION */
+  printf ("IMPLEMENTATION\n");
+  printf ("%*s", BASE_INDENT, " ");
+  show_shell_version (0);
+  printf ("%*s", BASE_INDENT, " ");
+  printf ("%s\n", _(bash_copyright));
+  printf ("%*s", BASE_INDENT, " ");
+  printf ("%s\n", _(bash_license));
+
+  fflush (stdout);
+  if (usefile)
+    free (line);
+}
+
+static void
+dispcolumn (i, buf, bufsize, width, height)
+     int i;
+     char *buf;
+     size_t bufsize;
+     int width, height;
+{
+  int j;
+  int displen;
+  char *helpdoc;
+
+  /* first column */
+  helpdoc = _(shell_builtins[i].short_doc);
+
+  buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
+  strncpy (buf + 1, helpdoc, width - 2);
+  buf[width - 2] = '>';                /* indicate truncation */
+  buf[width - 1] = '\0';
+  printf ("%s", buf);
+  if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
+    {
+      printf ("\n");
+      return;
+    }
+
+  displen = strlen (buf);
+  /* two spaces */
+  for (j = displen; j < width; j++)
+    putc (' ', stdout);
+
+  /* second column */
+  helpdoc = _(shell_builtins[i+height].short_doc);
+
+  buf[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*';
+  strncpy (buf + 1, helpdoc, width - 3);
+  buf[width - 3] = '>';                /* indicate truncation */
+  buf[width - 2] = '\0';
+
+  printf ("%s\n", buf);
+}
+
+#if defined (HANDLE_MULTIBYTE)
+static void
+wdispcolumn (i, buf, bufsize, width, height)
+     int i;
+     char *buf;
+     size_t bufsize;
+     int width, height;
+{
+  int j;
+  int displen;
+  char *helpdoc;
+  wchar_t *wcstr;
+  size_t slen, n;
+  int wclen;
+
+  /* first column */
+  helpdoc = _(shell_builtins[i].short_doc);
+
+  wcstr = 0;
+  slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
+  if (slen == -1)
+    {
+      dispcolumn (i, buf, bufsize, width, height);
+      return;
+    }
+
+  /* No bigger than the passed max width */
+  if (slen >= width)
+    slen = width - 2;
+  wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
+  n = mbstowcs (wcstr+1, helpdoc, slen + 1);
+  wcstr[n+1] = L'\0';
+
+  /* Turn tabs and newlines into spaces for column display, since wcwidth
+     returns -1 for them */
+  for (j = 1; j < n; j++)
+    if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
+      wcstr[j] = L' ';
+
+  displen = wcsnwidth (wcstr+1, slen, width - 2) + 1;  /* +1 for ' ' or '*' */
+  
+  wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
+
+  /* This assumes each wide char takes up one column position when displayed */
+  wcstr[width - 2] = L'>';             /* indicate truncation */
+  wcstr[width - 1] = L'\0';
+
+  printf ("%ls", wcstr);
+  if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
+    {
+      printf ("\n");
+      return;
+    }
+
+  /* at least one space */
+  for (j = displen; j < width; j++)
+    putc (' ', stdout);
+
+  /* second column */
+  helpdoc = _(shell_builtins[i+height].short_doc);
+  slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
+  if (slen == -1)
+    {
+      /* for now */
+      printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
+      return;
+    }
+
+  /* Reuse wcstr since it is already width wide chars long */
+  if (slen >= width)
+    slen = width - 2;
+  n = mbstowcs (wcstr+1, helpdoc, slen + 1);
+  wcstr[n+1] = L'\0';          /* make sure null-terminated */
+
+  /* Turn tabs and newlines into spaces for column display */
+  for (j = 1; j < n; j++)
+    if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
+      wcstr[j] = L' ';
+
+  displen = wcsnwidth (wcstr+1, slen, width - 2);
+  
+  wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
+
+  /* This assumes each wide char takes up one column position when displayed */
+  wcstr[width - 3] = L'>';             /* indicate truncation */
+  wcstr[width - 2] = L'\0';
+
+  printf ("%ls\n", wcstr);
+
+  free (wcstr);
+}
+#endif /* HANDLE_MULTIBYTE */
+
 static void
 show_builtin_command_help ()
 {
   int i, j;
-  char blurb[36];
+  int height, width;
+  char *t, blurb[128];
 
   printf (
-"These shell commands are defined internally.  Type `help' to see this list.\n\
+_("These shell commands are defined internally.  Type `help' to see this list.\n\
 Type `help name' to find out more about the function `name'.\n\
 Use `info bash' to find out more about the shell in general.\n\
 Use `man -k' or `info' to find out more about commands not in this list.\n\
 \n\
 A star (*) next to a name means that the command is disabled.\n\
-\n");
+\n"));
 
-  for (i = 0; i < num_shell_builtins; i++)
+  t = get_string_value ("COLUMNS");
+  width = (t && *t) ? atoi (t) : 80;
+  if (width <= 0)
+    width = 80;
+
+  width /= 2;
+  if (width > sizeof (blurb))
+    width = sizeof (blurb);
+  if (width <= 3)
+    width = 40;
+  height = (num_shell_builtins + 1) / 2;       /* number of rows */
+
+  for (i = 0; i < height; i++)
     {
       QUIT;
-      blurb[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
-      strncpy (blurb + 1, shell_builtins[i].short_doc, 34);
-      blurb[35] = '\0';
-      printf ("%s", blurb);
 
-      if (i % 2)
-       printf ("\n");
+#if defined (HANDLE_MULTIBYTE)
+      if (MB_CUR_MAX > 1)
+       wdispcolumn (i, blurb, sizeof (blurb), width, height);
       else
-       for (j = strlen (blurb); j < 35; j++)
-         putc (' ', stdout);
+#endif
+       dispcolumn (i, blurb, sizeof (blurb), width, height);
     }
-  if (i % 2)
-    printf ("\n");
 }
 #endif /* HELP_BUILTIN */