]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/help.def
Bash-4.4 patch 19
[thirdparty/bash.git] / builtins / help.def
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 help_builtin (list)
95 WORD_LIST *list;
96 {
97 register int i;
98 char *pattern, *name;
99 int plen, match_found, sflag, dflag, mflag, m, pass, this_found;
100
101 dflag = sflag = mflag = 0;
102 reset_internal_getopt ();
103 while ((i = internal_getopt (list, "dms")) != -1)
104 {
105 switch (i)
106 {
107 case 'd':
108 dflag = 1;
109 break;
110 case 'm':
111 mflag = 1;
112 break;
113 case 's':
114 sflag = 1;
115 break;
116 CASE_HELPOPT;
117 default:
118 builtin_usage ();
119 return (EX_USAGE);
120 }
121 }
122 list = loptend;
123
124 if (list == 0)
125 {
126 show_shell_version (0);
127 show_builtin_command_help ();
128 return (EXECUTION_SUCCESS);
129 }
130
131 /* We should consider making `help bash' do something. */
132
133 if (glob_pattern_p (list->word->word))
134 {
135 printf (ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
136 print_word_list (list, ", ");
137 printf ("'\n\n");
138 }
139
140 for (match_found = 0, pattern = ""; list; list = list->next)
141 {
142 pattern = list->word->word;
143 plen = strlen (pattern);
144
145 for (pass = 1, this_found = 0; pass < 3; pass++)
146 {
147 for (i = 0; name = shell_builtins[i].name; i++)
148 {
149 QUIT;
150
151 /* First pass: look for exact string or pattern matches.
152 Second pass: look for prefix matches like bash-4.2 */
153 if (pass == 1)
154 m = (strcmp (pattern, name) == 0) ||
155 (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH);
156 else
157 m = strncmp (pattern, name, plen) == 0;
158
159 if (m)
160 {
161 this_found = 1;
162 match_found++;
163 if (dflag)
164 {
165 show_desc (name, i);
166 continue;
167 }
168 else if (mflag)
169 {
170 show_manpage (name, i);
171 continue;
172 }
173
174 printf ("%s: %s\n", name, _(shell_builtins[i].short_doc));
175
176 if (sflag == 0)
177 show_longdoc (i);
178 }
179 }
180 if (pass == 1 && this_found == 1)
181 break;
182 }
183 }
184
185 if (match_found == 0)
186 {
187 builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern);
188 return (EXECUTION_FAILURE);
189 }
190
191 fflush (stdout);
192 return (EXECUTION_SUCCESS);
193 }
194
195 void
196 builtin_help ()
197 {
198 int ind;
199 ptrdiff_t d;
200
201 current_builtin = builtin_address_internal (this_command_name, 0);
202 if (current_builtin == 0)
203 return;
204
205 d = current_builtin - shell_builtins;
206
207 #if defined (__STDC__)
208 ind = (int)d;
209 #else
210 ind = (int)d / sizeof (struct builtin);
211 #endif
212
213 printf ("%s: %s\n", this_command_name, _(shell_builtins[ind].short_doc));
214 show_longdoc (ind);
215 }
216
217 static int
218 open_helpfile (name)
219 char *name;
220 {
221 int fd;
222
223 fd = open (name, O_RDONLY);
224 if (fd == -1)
225 {
226 builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
227 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 show_longdoc (i)
237 int i;
238 {
239 register int j;
240 char * const *doc;
241 int fd;
242
243 doc = shell_builtins[i].long_doc;
244
245 if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
246 {
247 fd = open_helpfile (doc[0]);
248 if (fd < 0)
249 return;
250 zcatfd (fd, 1, doc[0]);
251 close (fd);
252 }
253 else if (doc)
254 for (j = 0; doc[j]; j++)
255 printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
256 }
257
258 static void
259 show_desc (name, i)
260 char *name;
261 int i;
262 {
263 register int j;
264 char **doc, *line;
265 int fd, usefile;
266
267 doc = (char **)shell_builtins[i].long_doc;
268
269 usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
270 if (usefile)
271 {
272 fd = open_helpfile (doc[0]);
273 if (fd < 0)
274 return;
275 zmapfd (fd, &line, doc[0]);
276 close (fd);
277 }
278 else
279 line = doc ? doc[0] : (char *)NULL;
280
281 printf ("%s - ", name);
282 for (j = 0; line && line[j]; j++)
283 {
284 putchar (line[j]);
285 if (line[j] == '\n')
286 break;
287 }
288
289 fflush (stdout);
290
291 if (usefile)
292 free (line);
293 }
294
295 /* Print builtin help in pseudo-manpage format. */
296 static void
297 show_manpage (name, i)
298 char *name;
299 int i;
300 {
301 register int j;
302 char **doc, *line;
303 int fd, usefile;
304
305 doc = (char **)shell_builtins[i].long_doc;
306
307 usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
308 if (usefile)
309 {
310 fd = open_helpfile (doc[0]);
311 if (fd < 0)
312 return;
313 zmapfd (fd, &line, doc[0]);
314 close (fd);
315 }
316 else
317 line = doc ? _(doc[0]) : (char *)NULL;
318
319 /* NAME */
320 printf ("NAME\n");
321 printf ("%*s%s - ", BASE_INDENT, " ", name);
322 for (j = 0; line && line[j]; j++)
323 {
324 putchar (line[j]);
325 if (line[j] == '\n')
326 break;
327 }
328 printf ("\n");
329
330 /* SYNOPSIS */
331 printf ("SYNOPSIS\n");
332 printf ("%*s%s\n\n", BASE_INDENT, " ", _(shell_builtins[i].short_doc));
333
334 /* DESCRIPTION */
335 printf ("DESCRIPTION\n");
336 if (usefile == 0)
337 {
338 for (j = 0; doc[j]; j++)
339 printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
340 }
341 else
342 {
343 for (j = 0; line && line[j]; j++)
344 {
345 putchar (line[j]);
346 if (line[j] == '\n')
347 printf ("%*s", BASE_INDENT, " ");
348 }
349 }
350 putchar ('\n');
351
352 /* SEE ALSO */
353 printf ("SEE ALSO\n");
354 printf ("%*sbash(1)\n\n", BASE_INDENT, " ");
355
356 /* IMPLEMENTATION */
357 printf ("IMPLEMENTATION\n");
358 printf ("%*s", BASE_INDENT, " ");
359 show_shell_version (0);
360 printf ("%*s", BASE_INDENT, " ");
361 printf ("%s\n", _(bash_copyright));
362 printf ("%*s", BASE_INDENT, " ");
363 printf ("%s\n", _(bash_license));
364
365 fflush (stdout);
366 if (usefile)
367 free (line);
368 }
369
370 static void
371 dispcolumn (i, buf, bufsize, width, height)
372 int i;
373 char *buf;
374 size_t bufsize;
375 int width, height;
376 {
377 int j;
378 int dispcols;
379 char *helpdoc;
380
381 /* first column */
382 helpdoc = _(shell_builtins[i].short_doc);
383
384 buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
385 strncpy (buf + 1, helpdoc, width - 2);
386 buf[width - 2] = '>'; /* indicate truncation */
387 buf[width - 1] = '\0';
388 printf ("%s", buf);
389 if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
390 {
391 printf ("\n");
392 return;
393 }
394
395 dispcols = strlen (buf);
396 /* two spaces */
397 for (j = dispcols; j < width; j++)
398 putc (' ', stdout);
399
400 /* second column */
401 helpdoc = _(shell_builtins[i+height].short_doc);
402
403 buf[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*';
404 strncpy (buf + 1, helpdoc, width - 3);
405 buf[width - 3] = '>'; /* indicate truncation */
406 buf[width - 2] = '\0';
407
408 printf ("%s\n", buf);
409 }
410
411 #if defined (HANDLE_MULTIBYTE)
412 static void
413 wdispcolumn (i, buf, bufsize, width, height)
414 int i;
415 char *buf;
416 size_t bufsize;
417 int width, height;
418 {
419 int j;
420 int dispcols, dispchars;
421 char *helpdoc;
422 wchar_t *wcstr;
423 size_t slen, n;
424 int wclen;
425
426 /* first column */
427 helpdoc = _(shell_builtins[i].short_doc);
428
429 wcstr = 0;
430 slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
431 if (slen == -1)
432 {
433 dispcolumn (i, buf, bufsize, width, height);
434 return;
435 }
436
437 /* No bigger than the passed max width */
438 if (slen >= width)
439 slen = width - 2;
440 wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
441 n = mbstowcs (wcstr+1, helpdoc, slen + 1);
442 wcstr[n+1] = L'\0';
443
444 /* Turn tabs and newlines into spaces for column display, since wcwidth
445 returns -1 for them */
446 for (j = 1; j < n; j++)
447 if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
448 wcstr[j] = L' ';
449
450 /* dispchars == number of characters that will be displayed */
451 dispchars = wcsnwidth (wcstr+1, slen, width - 2);
452 /* dispcols == number of columns required to display DISPCHARS */
453 dispcols = wcswidth (wcstr+1, dispchars) + 1; /* +1 for ' ' or '*' */
454
455 wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
456
457 if (dispcols >= width-2)
458 {
459 wcstr[dispchars] = L'>'; /* indicate truncation */
460 wcstr[dispchars+1] = L'\0';
461 }
462
463 printf ("%ls", wcstr);
464 if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
465 {
466 printf ("\n");
467 free (wcstr);
468 return;
469 }
470
471 /* at least one space */
472 for (j = dispcols; j < width; j++)
473 putc (' ', stdout);
474
475 /* second column */
476 helpdoc = _(shell_builtins[i+height].short_doc);
477 slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
478 if (slen == -1)
479 {
480 /* for now */
481 printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
482 free (wcstr);
483 return;
484 }
485
486 /* Reuse wcstr since it is already width wide chars long */
487 if (slen >= width)
488 slen = width - 2;
489 n = mbstowcs (wcstr+1, helpdoc, slen + 1);
490 wcstr[n+1] = L'\0'; /* make sure null-terminated */
491
492 /* Turn tabs and newlines into spaces for column display */
493 for (j = 1; j < n; j++)
494 if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
495 wcstr[j] = L' ';
496
497 /* dispchars == number of characters that will be displayed */
498 dispchars = wcsnwidth (wcstr+1, slen, width - 2);
499 dispcols = wcswidth (wcstr+1, dispchars) + 1; /* +1 for ' ' or '*' */
500
501 wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
502
503 /* The dispchars-1 is there for terminals that behave strangely when you
504 have \n in the nth column for terminal width n; this is what bash-4.3
505 did. */
506 if (dispcols >= width - 2)
507 {
508 wcstr[dispchars-1] = L'>'; /* indicate truncation */
509 wcstr[dispchars] = L'\0';
510 }
511
512 printf ("%ls\n", wcstr);
513
514 free (wcstr);
515 }
516 #endif /* HANDLE_MULTIBYTE */
517
518 static void
519 show_builtin_command_help ()
520 {
521 int i, j;
522 int height, width;
523 char *t, blurb[128];
524
525 printf (
526 _("These shell commands are defined internally. Type `help' to see this list.\n\
527 Type `help name' to find out more about the function `name'.\n\
528 Use `info bash' to find out more about the shell in general.\n\
529 Use `man -k' or `info' to find out more about commands not in this list.\n\
530 \n\
531 A star (*) next to a name means that the command is disabled.\n\
532 \n"));
533
534 t = get_string_value ("COLUMNS");
535 width = (t && *t) ? atoi (t) : 80;
536 if (width <= 0)
537 width = 80;
538
539 width /= 2;
540 if (width > sizeof (blurb))
541 width = sizeof (blurb);
542 if (width <= 3)
543 width = 40;
544 height = (num_shell_builtins + 1) / 2; /* number of rows */
545
546 for (i = 0; i < height; i++)
547 {
548 QUIT;
549
550 #if defined (HANDLE_MULTIBYTE)
551 if (MB_CUR_MAX > 1)
552 wdispcolumn (i, blurb, sizeof (blurb), width, height);
553 else
554 #endif
555 dispcolumn (i, blurb, sizeof (blurb), width, height);
556 }
557 }
558 #endif /* HELP_BUILTIN */