blob: 4f043055662f91844436141e345c17b6fe0ec3b7 [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001This file is help.def, from which is created help.c.
2It implements the builtin "help" in Bash.
3
Chet Rameyac50fba2014-02-26 09:36:43 -05004Copyright (C) 1987-2013 Free Software Foundation, Inc.
Jari Aalto726f6381996-08-26 18:22:31 +00005
6This file is part of GNU Bash, the Bourne Again SHell.
7
Jari Aalto31859422009-01-12 13:36:28 +00008Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
Jari Aalto726f6381996-08-26 18:22:31 +000012
Jari Aalto31859422009-01-12 13:36:28 +000013Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
Jari Aalto726f6381996-08-26 18:22:31 +000017
Jari Aalto31859422009-01-12 13:36:28 +000018You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
Jari Aalto726f6381996-08-26 18:22:31 +000020
21$PRODUCES help.c
22
23$BUILTIN help
24$FUNCTION help_builtin
Jari Aaltoccc6cda1996-12-23 17:02:34 +000025$DEPENDS_ON HELP_BUILTIN
Chet Ramey00018032011-11-21 20:51:19 -050026$SHORT_DOC help [-dms] [pattern ...]
Jari Aalto31859422009-01-12 13:36:28 +000027Display information about builtin commands.
28
29Displays brief summaries of builtin commands. If PATTERN is
Jari Aalto726f6381996-08-26 18:22:31 +000030specified, gives detailed help on all commands matching PATTERN,
Jari Aalto31859422009-01-12 13:36:28 +000031otherwise the list of help topics is printed.
32
33Options:
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
39Arguments:
40 PATTERN Pattern specifiying a help topic
41
42Exit Status:
43Returns success unless PATTERN is not found or an invalid option is given.
Jari Aalto726f6381996-08-26 18:22:31 +000044$END
45
Jari Aaltoccc6cda1996-12-23 17:02:34 +000046#include <config.h>
47
48#if defined (HELP_BUILTIN)
Jari Aalto726f6381996-08-26 18:22:31 +000049#include <stdio.h>
Jari Aaltoccc6cda1996-12-23 17:02:34 +000050
51#if defined (HAVE_UNISTD_H)
Jari Aaltocce855b1998-04-17 19:52:44 +000052# ifdef _MINIX
53# include <sys/types.h>
54# endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +000055# include <unistd.h>
56#endif
57
Jari Aalto7117c2d2002-07-17 14:10:11 +000058#include <errno.h>
59
60#include <filecntl.h>
61
Jari Aaltob80f6442004-07-27 13:29:18 +000062#include "../bashintl.h"
63
Jari Aalto726f6381996-08-26 18:22:31 +000064#include "../shell.h"
65#include "../builtins.h"
Jari Aaltocce855b1998-04-17 19:52:44 +000066#include "../pathexp.h"
Jari Aaltof73dda02001-11-13 17:56:06 +000067#include "common.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000068#include "bashgetopt.h"
Jari Aalto726f6381996-08-26 18:22:31 +000069
Jari Aaltof73dda02001-11-13 17:56:06 +000070#include <glob/strmatch.h>
Jari Aaltoccc6cda1996-12-23 17:02:34 +000071#include <glob/glob.h>
72
Jari Aalto7117c2d2002-07-17 14:10:11 +000073#ifndef errno
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010074#include <errno.h>
Jari Aalto7117c2d2002-07-17 14:10:11 +000075#endif
76
Jari Aalto31859422009-01-12 13:36:28 +000077extern const char * const bash_copyright;
78extern const char * const bash_license;
79
Jari Aalto7117c2d2002-07-17 14:10:11 +000080static void show_builtin_command_help __P((void));
Jari Aalto31859422009-01-12 13:36:28 +000081static int open_helpfile __P((char *));
82static void show_desc __P((char *, int));
83static void show_manpage __P((char *, int));
Jari Aalto7117c2d2002-07-17 14:10:11 +000084static void show_longdoc __P((int));
Jari Aalto726f6381996-08-26 18:22:31 +000085
86/* Print out a list of the known functions in the shell, and what they do.
87 If LIST is supplied, print out the list which matches for each pattern
88 specified. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +000089int
Jari Aalto726f6381996-08-26 18:22:31 +000090help_builtin (list)
91 WORD_LIST *list;
92{
Jari Aalto7117c2d2002-07-17 14:10:11 +000093 register int i;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000094 char *pattern, *name;
Chet Rameyac50fba2014-02-26 09:36:43 -050095 int plen, match_found, sflag, dflag, mflag, m, pass, this_found;
Jari Aalto726f6381996-08-26 18:22:31 +000096
Jari Aalto31859422009-01-12 13:36:28 +000097 dflag = sflag = mflag = 0;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000098 reset_internal_getopt ();
Jari Aalto31859422009-01-12 13:36:28 +000099 while ((i = internal_getopt (list, "dms")) != -1)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000100 {
101 switch (i)
102 {
Jari Aalto31859422009-01-12 13:36:28 +0000103 case 'd':
104 dflag = 1;
105 break;
106 case 'm':
107 mflag = 1;
108 break;
Jari Aaltobb706242000-03-17 21:46:59 +0000109 case 's':
110 sflag = 1;
111 break;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000112 default:
113 builtin_usage ();
114 return (EX_USAGE);
115 }
116 }
117 list = loptend;
118
Jari Aaltod166f041997-06-05 14:59:13 +0000119 if (list == 0)
120 {
121 show_shell_version (0);
122 show_builtin_command_help ();
123 return (EXECUTION_SUCCESS);
124 }
125
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000126 /* We should consider making `help bash' do something. */
127
128 if (glob_pattern_p (list->word->word))
129 {
Jari Aalto31859422009-01-12 13:36:28 +0000130 printf (ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000131 print_word_list (list, ", ");
132 printf ("'\n\n");
133 }
134
135 for (match_found = 0, pattern = ""; list; list = list->next)
136 {
137 pattern = list->word->word;
138 plen = strlen (pattern);
139
Chet Rameyac50fba2014-02-26 09:36:43 -0500140 for (pass = 1, this_found = 0; pass < 3; pass++)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000141 {
Chet Rameyac50fba2014-02-26 09:36:43 -0500142 for (i = 0; name = shell_builtins[i].name; i++)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000143 {
Chet Rameyac50fba2014-02-26 09:36:43 -0500144 QUIT;
Jari Aalto31859422009-01-12 13:36:28 +0000145
Chet Rameyac50fba2014-02-26 09:36:43 -0500146 /* First pass: look for exact string or pattern matches.
147 Second pass: look for prefix matches like bash-4.2 */
148 if (pass == 1)
149 m = (strcmp (pattern, name) == 0) ||
150 (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH);
151 else
152 m = strncmp (pattern, name, plen) == 0;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000153
Chet Rameyac50fba2014-02-26 09:36:43 -0500154 if (m)
155 {
156 this_found = 1;
157 match_found++;
158 if (dflag)
159 {
160 show_desc (name, i);
161 continue;
162 }
163 else if (mflag)
164 {
165 show_manpage (name, i);
166 continue;
167 }
168
169 printf ("%s: %s\n", name, _(shell_builtins[i].short_doc));
170
171 if (sflag == 0)
172 show_longdoc (i);
173 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000174 }
Chet Rameyac50fba2014-02-26 09:36:43 -0500175 if (pass == 1 && this_found == 1)
176 break;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000177 }
178 }
179
180 if (match_found == 0)
181 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000182 builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000183 return (EXECUTION_FAILURE);
184 }
185
186 fflush (stdout);
187 return (EXECUTION_SUCCESS);
188}
189
Jari Aalto31859422009-01-12 13:36:28 +0000190static int
191open_helpfile (name)
192 char *name;
193{
194 int fd;
195
196 fd = open (name, O_RDONLY);
197 if (fd == -1)
198 {
199 builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
200 return -1;
201 }
202 return fd;
203}
204
Jari Aalto7117c2d2002-07-17 14:10:11 +0000205/* By convention, enforced by mkbuiltins.c, if separate help files are being
206 used, the long_doc array contains one string -- the full pathname of the
207 help file for this builtin. */
208static void
209show_longdoc (i)
210 int i;
211{
212 register int j;
213 char * const *doc;
214 int fd;
215
216 doc = shell_builtins[i].long_doc;
217
218 if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
219 {
Jari Aalto31859422009-01-12 13:36:28 +0000220 fd = open_helpfile (doc[0]);
221 if (fd < 0)
222 return;
Jari Aalto7117c2d2002-07-17 14:10:11 +0000223 zcatfd (fd, 1, doc[0]);
224 close (fd);
225 }
Chet Rameyac50fba2014-02-26 09:36:43 -0500226 else if (doc)
Jari Aalto7117c2d2002-07-17 14:10:11 +0000227 for (j = 0; doc[j]; j++)
Jari Aalto95732b42005-12-07 14:08:12 +0000228 printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
Jari Aalto7117c2d2002-07-17 14:10:11 +0000229}
230
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000231static void
Jari Aalto31859422009-01-12 13:36:28 +0000232show_desc (name, i)
233 char *name;
234 int i;
235{
236 register int j;
237 char **doc, *line;
238 int fd, usefile;
239
240 doc = (char **)shell_builtins[i].long_doc;
241
242 usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
243 if (usefile)
244 {
245 fd = open_helpfile (doc[0]);
246 if (fd < 0)
247 return;
248 zmapfd (fd, &line, doc[0]);
249 close (fd);
250 }
251 else
252 line = doc ? doc[0] : (char *)NULL;
253
254 printf ("%s - ", name);
255 for (j = 0; line && line[j]; j++)
256 {
257 putchar (line[j]);
258 if (line[j] == '\n')
259 break;
260 }
261
262 fflush (stdout);
263
264 if (usefile)
265 free (line);
266}
267
268/* Print builtin help in pseudo-manpage format. */
269static void
270show_manpage (name, i)
271 char *name;
272 int i;
273{
274 register int j;
275 char **doc, *line;
276 int fd, usefile;
277
278 doc = (char **)shell_builtins[i].long_doc;
279
280 usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
281 if (usefile)
282 {
283 fd = open_helpfile (doc[0]);
284 if (fd < 0)
285 return;
286 zmapfd (fd, &line, doc[0]);
287 close (fd);
288 }
289 else
290 line = doc ? _(doc[0]) : (char *)NULL;
291
292 /* NAME */
293 printf ("NAME\n");
294 printf ("%*s%s - ", BASE_INDENT, " ", name);
295 for (j = 0; line && line[j]; j++)
296 {
297 putchar (line[j]);
298 if (line[j] == '\n')
299 break;
300 }
301 printf ("\n");
302
303 /* SYNOPSIS */
304 printf ("SYNOPSIS\n");
Chet Ramey495aee42011-11-22 19:11:26 -0500305 printf ("%*s%s\n\n", BASE_INDENT, " ", _(shell_builtins[i].short_doc));
Jari Aalto31859422009-01-12 13:36:28 +0000306
307 /* DESCRIPTION */
308 printf ("DESCRIPTION\n");
309 if (usefile == 0)
310 {
311 for (j = 0; doc[j]; j++)
312 printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
313 }
314 else
315 {
316 for (j = 0; line && line[j]; j++)
317 {
318 putchar (line[j]);
319 if (line[j] == '\n')
320 printf ("%*s", BASE_INDENT, " ");
321 }
322 }
323 putchar ('\n');
324
325 /* SEE ALSO */
326 printf ("SEE ALSO\n");
327 printf ("%*sbash(1)\n\n", BASE_INDENT, " ");
328
329 /* IMPLEMENTATION */
330 printf ("IMPLEMENTATION\n");
331 printf ("%*s", BASE_INDENT, " ");
332 show_shell_version (0);
333 printf ("%*s", BASE_INDENT, " ");
334 printf ("%s\n", _(bash_copyright));
335 printf ("%*s", BASE_INDENT, " ");
336 printf ("%s\n", _(bash_license));
337
338 fflush (stdout);
339 if (usefile)
340 free (line);
341}
342
343static void
Chet Rameyac50fba2014-02-26 09:36:43 -0500344dispcolumn (i, buf, bufsize, width, height)
345 int i;
346 char *buf;
347 size_t bufsize;
348 int width, height;
349{
350 int j;
351 int displen;
352 char *helpdoc;
353
354 /* first column */
355 helpdoc = _(shell_builtins[i].short_doc);
356
357 buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
358 strncpy (buf + 1, helpdoc, width - 2);
359 buf[width - 2] = '>'; /* indicate truncation */
360 buf[width - 1] = '\0';
361 printf ("%s", buf);
362 if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
363 {
364 printf ("\n");
365 return;
366 }
367
368 displen = strlen (buf);
369 /* two spaces */
370 for (j = displen; j < width; j++)
371 putc (' ', stdout);
372
373 /* second column */
374 helpdoc = _(shell_builtins[i+height].short_doc);
375
376 buf[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*';
377 strncpy (buf + 1, helpdoc, width - 3);
378 buf[width - 3] = '>'; /* indicate truncation */
379 buf[width - 2] = '\0';
380
381 printf ("%s\n", buf);
382}
383
384#if defined (HANDLE_MULTIBYTE)
385static void
386wdispcolumn (i, buf, bufsize, width, height)
387 int i;
388 char *buf;
389 size_t bufsize;
390 int width, height;
391{
392 int j;
393 int displen;
394 char *helpdoc;
395 wchar_t *wcstr;
396 size_t slen, n;
397 int wclen;
398
399 /* first column */
400 helpdoc = _(shell_builtins[i].short_doc);
401
402 wcstr = 0;
403 slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
404 if (slen == -1)
405 {
406 dispcolumn (i, buf, bufsize, width, height);
407 return;
408 }
409
410 /* No bigger than the passed max width */
411 if (slen >= width)
412 slen = width - 2;
413 wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
414 n = mbstowcs (wcstr+1, helpdoc, slen + 1);
415 wcstr[n+1] = L'\0';
416
417 /* Turn tabs and newlines into spaces for column display, since wcwidth
418 returns -1 for them */
419 for (j = 1; j < n; j++)
420 if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
421 wcstr[j] = L' ';
422
423 displen = wcsnwidth (wcstr+1, slen, width - 2) + 1; /* +1 for ' ' or '*' */
424
425 wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
426
427 /* This assumes each wide char takes up one column position when displayed */
428 wcstr[width - 2] = L'>'; /* indicate truncation */
429 wcstr[width - 1] = L'\0';
430
431 printf ("%ls", wcstr);
432 if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
433 {
434 printf ("\n");
435 return;
436 }
437
438 /* at least one space */
439 for (j = displen; j < width; j++)
440 putc (' ', stdout);
441
442 /* second column */
443 helpdoc = _(shell_builtins[i+height].short_doc);
444 slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
445 if (slen == -1)
446 {
447 /* for now */
448 printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
449 return;
450 }
451
452 /* Reuse wcstr since it is already width wide chars long */
453 if (slen >= width)
454 slen = width - 2;
455 n = mbstowcs (wcstr+1, helpdoc, slen + 1);
456 wcstr[n+1] = L'\0'; /* make sure null-terminated */
457
458 /* Turn tabs and newlines into spaces for column display */
459 for (j = 1; j < n; j++)
460 if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
461 wcstr[j] = L' ';
462
463 displen = wcsnwidth (wcstr+1, slen, width - 2);
464
465 wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
466
467 /* This assumes each wide char takes up one column position when displayed */
468 wcstr[width - 3] = L'>'; /* indicate truncation */
469 wcstr[width - 2] = L'\0';
470
471 printf ("%ls\n", wcstr);
472
473 free (wcstr);
474}
475#endif /* HANDLE_MULTIBYTE */
476
477static void
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000478show_builtin_command_help ()
479{
480 int i, j;
Jari Aalto31859422009-01-12 13:36:28 +0000481 int height, width;
482 char *t, blurb[128];
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000483
484 printf (
Jari Aaltob80f6442004-07-27 13:29:18 +0000485_("These shell commands are defined internally. Type `help' to see this list.\n\
Jari Aalto726f6381996-08-26 18:22:31 +0000486Type `help name' to find out more about the function `name'.\n\
487Use `info bash' to find out more about the shell in general.\n\
Jari Aalto7117c2d2002-07-17 14:10:11 +0000488Use `man -k' or `info' to find out more about commands not in this list.\n\
Jari Aalto726f6381996-08-26 18:22:31 +0000489\n\
490A star (*) next to a name means that the command is disabled.\n\
Jari Aaltob80f6442004-07-27 13:29:18 +0000491\n"));
Jari Aalto726f6381996-08-26 18:22:31 +0000492
Jari Aalto31859422009-01-12 13:36:28 +0000493 t = get_string_value ("COLUMNS");
494 width = (t && *t) ? atoi (t) : 80;
495 if (width <= 0)
496 width = 80;
497
498 width /= 2;
499 if (width > sizeof (blurb))
500 width = sizeof (blurb);
Chet Ramey00018032011-11-21 20:51:19 -0500501 if (width <= 3)
502 width = 40;
Jari Aalto31859422009-01-12 13:36:28 +0000503 height = (num_shell_builtins + 1) / 2; /* number of rows */
504
505 for (i = 0; i < height; i++)
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000506 {
507 QUIT;
Jari Aalto726f6381996-08-26 18:22:31 +0000508
Chet Rameyac50fba2014-02-26 09:36:43 -0500509#if defined (HANDLE_MULTIBYTE)
510 if (MB_CUR_MAX > 1)
511 wdispcolumn (i, blurb, sizeof (blurb), width, height);
512 else
513#endif
514 dispcolumn (i, blurb, sizeof (blurb), width, height);
Jari Aalto726f6381996-08-26 18:22:31 +0000515 }
Jari Aalto726f6381996-08-26 18:22:31 +0000516}
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000517#endif /* HELP_BUILTIN */