LCOV - code coverage report
Current view: top level - builtins - help.def (source / functions) Hit Total Coverage
Test: cov-bash.info Lines: 68 242 28.1 %
Date: 2020-10-29 14:49:28 Functions: 4 9 44.4 %

          Line data    Source code
       1             : This file is help.def, from which is created help.c.
       2             : It implements the builtin "help" in Bash.
       3             : 
       4             : Copyright (C) 1987-2015 Free Software Foundation, Inc.
       5             : 
       6             : This file is part of GNU Bash, the Bourne Again SHell.
       7             : 
       8             : Bash is free software: you can redistribute it and/or modify
       9             : it under the terms of the GNU General Public License as published by
      10             : the Free Software Foundation, either version 3 of the License, or
      11             : (at your option) any later version.
      12             : 
      13             : Bash is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with Bash.  If not, see <http://www.gnu.org/licenses/>.
      20             : 
      21             : $PRODUCES help.c
      22             : 
      23             : $BUILTIN help
      24             : $FUNCTION help_builtin
      25             : $DEPENDS_ON HELP_BUILTIN
      26             : $SHORT_DOC help [-dms] [pattern ...]
      27             : Display information about builtin commands.
      28             : 
      29             : Displays brief summaries of builtin commands.  If PATTERN is
      30             : specified, gives detailed help on all commands matching PATTERN,
      31             : otherwise the list of help topics is printed.
      32             : 
      33             : Options:
      34             :   -d    output short description for each topic
      35             :   -m    display usage in pseudo-manpage format
      36             :   -s    output only a short usage synopsis for each topic matching
      37             :                 PATTERN
      38             : 
      39             : Arguments:
      40             :   PATTERN       Pattern specifiying a help topic
      41             : 
      42             : Exit Status:
      43             : Returns success unless PATTERN is not found or an invalid option is given.
      44             : $END
      45             : 
      46             : #include <config.h>
      47             : 
      48             : #if defined (HELP_BUILTIN)
      49             : #include <stdio.h>
      50             : 
      51             : #if defined (HAVE_UNISTD_H)
      52             : #  ifdef _MINIX
      53             : #    include <sys/types.h>
      54             : #  endif
      55             : #  include <unistd.h>
      56             : #endif
      57             : 
      58             : #include <errno.h>
      59             : 
      60             : #include <filecntl.h>
      61             : #include <stddef.h>
      62             : 
      63             : #include "../bashintl.h"
      64             : 
      65             : #include "../shell.h"
      66             : #include "../builtins.h"
      67             : #include "../pathexp.h"
      68             : #include "common.h"
      69             : #include "bashgetopt.h"
      70             : 
      71             : #include <glob/strmatch.h>
      72             : #include <glob/glob.h>
      73             : 
      74             : #ifndef errno
      75             : extern int errno;
      76             : #endif
      77             : 
      78             : extern const char * const bash_copyright;
      79             : extern const char * const bash_license;
      80             : 
      81             : extern char *this_command_name;
      82             : extern struct builtin *current_builtin;
      83             : 
      84             : static void show_builtin_command_help __P((void));
      85             : static int open_helpfile __P((char *));
      86             : static void show_desc __P((char *, int));
      87             : static void show_manpage __P((char *, int));
      88             : static void show_longdoc __P((int));
      89             : 
      90             : /* Print out a list of the known functions in the shell, and what they do.
      91             :    If LIST is supplied, print out the list which matches for each pattern
      92             :    specified. */
      93             : int
      94          89 : help_builtin (list)
      95             :      WORD_LIST *list;
      96             : {
      97          89 :   register int i;
      98          89 :   char *pattern, *name;
      99          89 :   int plen, match_found, sflag, dflag, mflag, m, pass, this_found;
     100             : 
     101          89 :   dflag = sflag = mflag = 0;
     102          89 :   reset_internal_getopt ();
     103          89 :   while ((i = internal_getopt (list, "dms")) != -1)
     104             :     {
     105           0 :       switch (i)
     106             :         {
     107             :         case 'd':
     108             :           dflag = 1;
     109             :           break;
     110           0 :         case 'm':
     111           0 :           mflag = 1;
     112           0 :           break;
     113           0 :         case 's':
     114           0 :           sflag = 1;
     115           0 :           break;
     116           0 :         CASE_HELPOPT;
     117           0 :         default:
     118           0 :           builtin_usage ();
     119           0 :           return (EX_USAGE);
     120             :         }
     121             :     }
     122          89 :   list = loptend;
     123             : 
     124          89 :   if (list == 0)
     125             :     {
     126          48 :       show_shell_version (0);
     127          48 :       show_builtin_command_help ();
     128          48 :       return (EXECUTION_SUCCESS);
     129             :     }
     130             : 
     131             :   /* We should consider making `help bash' do something. */
     132             : 
     133          41 :   if (glob_pattern_p (list->word->word))
     134             :     {
     135           0 :       printf (ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
     136           0 :       print_word_list (list, ", ");
     137           0 :       printf ("'\n\n");
     138             :     }
     139             : 
     140         111 :   for (match_found = 0, pattern = ""; list; list = list->next)
     141             :     {
     142          70 :       pattern = list->word->word;
     143          70 :       plen = strlen (pattern);
     144             : 
     145         172 :       for (pass = 1, this_found = 0; pass < 3; pass++)
     146             :         {
     147        9317 :           for (i = 0; name = shell_builtins[i].name; i++)
     148             :             {
     149        9196 :               QUIT;
     150             : 
     151             :               /* First pass: look for exact string or pattern matches.
     152             :                  Second pass: look for prefix matches like bash-4.2 */
     153        9196 :               if (pass == 1)
     154       10621 :                 m = (strcmp (pattern, name) == 0) ||
     155       10602 :                     (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH);
     156             :               else
     157        3876 :                 m = strncmp (pattern, name, plen) == 0;
     158             : 
     159        3876 :               if (m)
     160             :                 {
     161          19 :                   this_found = 1;
     162          19 :                   match_found++;
     163          19 :                   if (dflag)
     164             :                     {
     165           0 :                       show_desc (name, i);
     166           0 :                       continue;
     167             :                     }
     168          19 :                   else if (mflag)
     169             :                     {
     170           0 :                       show_manpage (name, i);
     171           0 :                       continue;
     172             :                     }
     173             : 
     174          19 :                   printf ("%s: %s\n", name, _(shell_builtins[i].short_doc));
     175             : 
     176          19 :                   if (sflag == 0)
     177          19 :                     show_longdoc (i);
     178             :                 }
     179             :             }
     180         121 :           if (pass == 1 && this_found == 1)
     181             :             break;
     182             :         }
     183             :     }
     184             : 
     185          41 :   if (match_found == 0)
     186             :     {
     187          22 :       builtin_error (_("no help topics match `%s'.  Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern);
     188          22 :       return (EXECUTION_FAILURE);
     189             :     }
     190             : 
     191          19 :   fflush (stdout);
     192          19 :   return (EXECUTION_SUCCESS);
     193             : }
     194             : 
     195             : void
     196           0 : builtin_help ()
     197             : {
     198           0 :   int ind;
     199           0 :   ptrdiff_t d;
     200             : 
     201           0 :   current_builtin = builtin_address_internal (this_command_name, 0);
     202           0 :   if (current_builtin == 0)
     203             :     return;
     204             : 
     205           0 :   d = current_builtin - shell_builtins;
     206             : 
     207             : #if defined (__STDC__)
     208           0 :   ind = (int)d;
     209             : #else
     210             :   ind = (int)d / sizeof (struct builtin);
     211             : #endif
     212             : 
     213           0 :   printf ("%s: %s\n", this_command_name, _(shell_builtins[ind].short_doc));
     214           0 :   show_longdoc (ind);  
     215             : }
     216             : 
     217             : static int
     218          19 : open_helpfile (name)
     219             :      char *name;
     220             : {
     221          19 :   int fd;
     222             : 
     223          19 :   fd = open (name, O_RDONLY);
     224          19 :   if (fd == -1)
     225             :     {
     226           0 :       builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
     227           0 :       return -1;
     228             :     }
     229             :   return fd;
     230             : }
     231             : 
     232             : /* By convention, enforced by mkbuiltins.c, if separate help files are being
     233             :    used, the long_doc array contains one string -- the full pathname of the
     234             :    help file for this builtin.  */
     235             : static void
     236          19 : show_longdoc (i)
     237             :      int i;
     238             : {
     239          19 :   register int j;
     240          19 :   char * const *doc;
     241          19 :   int fd;
     242             : 
     243          19 :   doc = shell_builtins[i].long_doc;
     244             : 
     245          19 :   if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
     246             :     {
     247          19 :       fd = open_helpfile (doc[0]);
     248          19 :       if (fd < 0)
     249             :         return;
     250          19 :       zcatfd (fd, 1, doc[0]);
     251          19 :       close (fd);
     252             :     }
     253           0 :   else if (doc)
     254           0 :     for (j = 0; doc[j]; j++)
     255           0 :       printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
     256             : }
     257             : 
     258             : static void
     259           0 : show_desc (name, i)
     260             :      char *name;
     261             :      int i;
     262             : {
     263           0 :   register int j;
     264           0 :   char **doc, *line;
     265           0 :   int fd, usefile;
     266             : 
     267           0 :   doc = (char **)shell_builtins[i].long_doc;
     268             : 
     269           0 :   usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
     270           0 :   if (usefile)
     271             :     {
     272           0 :       fd = open_helpfile (doc[0]);
     273           0 :       if (fd < 0)
     274           0 :         return;
     275           0 :       zmapfd (fd, &line, doc[0]);
     276           0 :       close (fd);
     277             :     }
     278             :   else
     279           0 :     line = doc ? doc[0] : (char *)NULL;
     280             : 
     281           0 :   printf ("%s - ", name);
     282           0 :   for (j = 0; line && line[j]; j++)
     283             :     {
     284           0 :       putchar (line[j]);
     285           0 :       if (line[j] == '\n')
     286             :         break;
     287             :     }
     288             :   
     289           0 :   fflush (stdout);
     290             : 
     291           0 :   if (usefile)
     292           0 :     free (line);
     293             : }
     294             : 
     295             : /* Print builtin help in pseudo-manpage format. */
     296             : static void
     297           0 : show_manpage (name, i)
     298             :      char *name;
     299             :      int i;
     300             : {
     301           0 :   register int j;
     302           0 :   char **doc, *line;
     303           0 :   int fd, usefile;
     304             : 
     305           0 :   doc = (char **)shell_builtins[i].long_doc;
     306             : 
     307           0 :   usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
     308           0 :   if (usefile)
     309             :     {
     310           0 :       fd = open_helpfile (doc[0]);
     311           0 :       if (fd < 0)
     312           0 :         return;
     313           0 :       zmapfd (fd, &line, doc[0]);
     314           0 :       close (fd);
     315             :     }
     316             :   else
     317           0 :     line = doc ? _(doc[0]) : (char *)NULL;
     318             : 
     319             :   /* NAME */
     320           0 :   printf ("NAME\n");
     321           0 :   printf ("%*s%s - ", BASE_INDENT, " ", name);
     322           0 :   for (j = 0; line && line[j]; j++)
     323             :     {
     324           0 :       putchar (line[j]);
     325           0 :       if (line[j] == '\n')
     326             :         break;
     327             :     }
     328           0 :   printf ("\n");
     329             : 
     330             :   /* SYNOPSIS */
     331           0 :   printf ("SYNOPSIS\n");
     332           0 :   printf ("%*s%s\n\n", BASE_INDENT, " ", _(shell_builtins[i].short_doc));
     333             : 
     334             :   /* DESCRIPTION */
     335           0 :   printf ("DESCRIPTION\n");
     336           0 :   if (usefile == 0)
     337             :     {
     338           0 :       for (j = 0; doc[j]; j++)
     339           0 :         printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
     340             :     }
     341             :   else
     342             :     {
     343           0 :       for (j = 0; line && line[j]; j++)
     344             :         {
     345           0 :           putchar (line[j]);
     346           0 :           if (line[j] == '\n')
     347           0 :             printf ("%*s", BASE_INDENT, " ");
     348             :         }
     349             :     }
     350           0 :   putchar ('\n');
     351             : 
     352             :   /* SEE ALSO */
     353           0 :   printf ("SEE ALSO\n");
     354           0 :   printf ("%*sbash(1)\n\n", BASE_INDENT, " ");
     355             : 
     356             :   /* IMPLEMENTATION */
     357           0 :   printf ("IMPLEMENTATION\n");
     358           0 :   printf ("%*s", BASE_INDENT, " ");
     359           0 :   show_shell_version (0);
     360           0 :   printf ("%*s", BASE_INDENT, " ");
     361           0 :   printf ("%s\n", _(bash_copyright));
     362           0 :   printf ("%*s", BASE_INDENT, " ");
     363           0 :   printf ("%s\n", _(bash_license));
     364             : 
     365           0 :   fflush (stdout);
     366           0 :   if (usefile)
     367           0 :     free (line);
     368             : }
     369             : 
     370             : static void
     371           0 : dispcolumn (i, buf, bufsize, width, height)
     372             :      int i;
     373             :      char *buf;
     374             :      size_t bufsize;
     375             :      int width, height;
     376             : {
     377           0 :   int j;
     378           0 :   int dispcols;
     379           0 :   char *helpdoc;
     380             : 
     381             :   /* first column */
     382           0 :   helpdoc = _(shell_builtins[i].short_doc);
     383             : 
     384           0 :   buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
     385           0 :   strncpy (buf + 1, helpdoc, width - 2);
     386           0 :   buf[width - 2] = '>';              /* indicate truncation */
     387           0 :   buf[width - 1] = '\0';
     388           0 :   printf ("%s", buf);
     389           0 :   if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
     390             :     {
     391           0 :       printf ("\n");
     392           0 :       return;
     393             :     }
     394             : 
     395           0 :   dispcols = strlen (buf);
     396             :   /* two spaces */
     397           0 :   for (j = dispcols; j < width; j++)
     398           0 :     putc (' ', stdout);
     399             : 
     400             :   /* second column */
     401           0 :   helpdoc = _(shell_builtins[i+height].short_doc);
     402             : 
     403           0 :   buf[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*';
     404           0 :   strncpy (buf + 1, helpdoc, width - 3);
     405           0 :   buf[width - 3] = '>';              /* indicate truncation */
     406           0 :   buf[width - 2] = '\0';
     407             : 
     408           0 :   printf ("%s\n", buf);
     409             : }
     410             : 
     411             : #if defined (HANDLE_MULTIBYTE)
     412             : static void
     413           0 : wdispcolumn (i, buf, bufsize, width, height)
     414             :      int i;
     415             :      char *buf;
     416             :      size_t bufsize;
     417             :      int width, height;
     418             : {
     419           0 :   int j;
     420           0 :   int dispcols, dispchars;
     421           0 :   char *helpdoc;
     422           0 :   wchar_t *wcstr;
     423           0 :   size_t slen, n;
     424             : 
     425             :   /* first column */
     426           0 :   helpdoc = _(shell_builtins[i].short_doc);
     427             : 
     428           0 :   wcstr = 0;
     429           0 :   slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
     430           0 :   if (slen == -1)
     431             :     {
     432           0 :       dispcolumn (i, buf, bufsize, width, height);
     433           0 :       return;
     434             :     }
     435             : 
     436             :   /* No bigger than the passed max width */
     437           0 :   if (slen >= width)
     438           0 :     slen = width - 2;
     439           0 :   wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
     440           0 :   n = mbstowcs (wcstr+1, helpdoc, slen + 1);
     441           0 :   wcstr[n+1] = L'\0';
     442             : 
     443             :   /* Turn tabs and newlines into spaces for column display, since wcwidth
     444             :      returns -1 for them */
     445           0 :   for (j = 1; j < n; j++)
     446           0 :     if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
     447           0 :       wcstr[j] = L' ';
     448             : 
     449             :   /* dispchars == number of characters that will be displayed */
     450           0 :   dispchars = wcsnwidth (wcstr+1, slen, width - 2);
     451             :   /* dispcols == number of columns required to display DISPCHARS */
     452           0 :   dispcols = wcswidth (wcstr+1, dispchars) + 1; /* +1 for ' ' or '*' */
     453             : 
     454           0 :   wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
     455             : 
     456           0 :   if (dispcols >= width-2)
     457             :     {
     458           0 :       wcstr[dispchars] = L'>';               /* indicate truncation */
     459           0 :       wcstr[dispchars+1] = L'\0';
     460             :     }
     461             : 
     462           0 :   printf ("%ls", wcstr);
     463           0 :   if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
     464             :     {
     465           0 :       printf ("\n");
     466           0 :       free (wcstr);
     467           0 :       return;
     468             :     }
     469             : 
     470             :   /* at least one space */
     471           0 :   for (j = dispcols; j < width; j++)
     472           0 :     putc (' ', stdout);
     473             : 
     474             :   /* second column */
     475           0 :   helpdoc = _(shell_builtins[i+height].short_doc);
     476           0 :   slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
     477           0 :   if (slen == -1)
     478             :     {
     479             :       /* for now */
     480           0 :       printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
     481           0 :       free (wcstr);
     482           0 :       return;
     483             :     }
     484             : 
     485             :   /* Reuse wcstr since it is already width wide chars long */
     486           0 :   if (slen >= width)
     487           0 :     slen = width - 2;
     488           0 :   n = mbstowcs (wcstr+1, helpdoc, slen + 1);
     489           0 :   wcstr[n+1] = L'\0';           /* make sure null-terminated */
     490             : 
     491             :   /* Turn tabs and newlines into spaces for column display */
     492           0 :   for (j = 1; j < n; j++)
     493           0 :     if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
     494           0 :       wcstr[j] = L' ';
     495             : 
     496             :   /* dispchars == number of characters that will be displayed */
     497           0 :   dispchars = wcsnwidth (wcstr+1, slen, width - 2);
     498           0 :   dispcols = wcswidth (wcstr+1, dispchars) + 1; /* +1 for ' ' or '*' */
     499             :   
     500           0 :   wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
     501             : 
     502             :   /* The dispchars-1 is there for terminals that behave strangely when you
     503             :      have \n in the nth column for terminal width n; this is what bash-4.3
     504             :      did. */
     505           0 :   if (dispcols >= width - 2)
     506             :     {
     507           0 :       wcstr[dispchars-1] = L'>';             /* indicate truncation */
     508           0 :       wcstr[dispchars] = L'\0';
     509             :     }
     510             : 
     511           0 :   printf ("%ls\n", wcstr);
     512             : 
     513           0 :   free (wcstr);
     514             : }
     515             : #endif /* HANDLE_MULTIBYTE */
     516             : 
     517             : static void
     518          48 : show_builtin_command_help ()
     519             : {
     520          48 :   int i;
     521          48 :   int height, width;
     522          48 :   char *t, blurb[128];
     523             : 
     524         144 :   printf (
     525          48 : _("These shell commands are defined internally.  Type `help' to see this list.\n\
     526             : Type `help name' to find out more about the function `name'.\n\
     527             : Use `info bash' to find out more about the shell in general.\n\
     528             : Use `man -k' or `info' to find out more about commands not in this list.\n\
     529             : \n\
     530             : A star (*) next to a name means that the command is disabled.\n\
     531             : \n"));
     532             : 
     533          48 :   t = get_string_value ("COLUMNS");
     534          48 :   width = (t && *t) ? atoi (t) : 80;
     535           0 :   if (width <= 0)
     536           0 :     width = 80;
     537             : 
     538          48 :   width /= 2;
     539          48 :   if (width > sizeof (blurb))
     540             :     width = sizeof (blurb);
     541          48 :   if (width <= 3)
     542           0 :     width = 40;
     543          48 :   height = (num_shell_builtins + 1) / 2;        /* number of rows */
     544             : 
     545        1872 :   for (i = 0; i < height; i++)
     546             :     {
     547        1824 :       QUIT;
     548             : 
     549             : #if defined (HANDLE_MULTIBYTE)
     550        1824 :       if (MB_CUR_MAX > 1)
     551        1824 :         wdispcolumn (i, blurb, sizeof (blurb), width, height);
     552             :       else
     553             : #endif
     554           0 :         dispcolumn (i, blurb, sizeof (blurb), width, height);
     555             :     }
     556          48 : }
     557             : #endif /* HELP_BUILTIN */

Generated by: LCOV version 1.14.0.6.4058