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