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 */
|