improve of cmpl.
[bush.git] / builtins / help.def
bloba2076829bb8188f27de24126f3acfcdb5b45e3ff
1 This file is help.def, from which is created help.c.
2 It implements the builtin "help" in Bush.
4 Copyright (C) 1987-2020 Free Software Foundation, Inc.
6 This file is part of GNU Bush, the Bourne Again SHell.
8 Bush 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.
13 Bush 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.
18 You should have received a copy of the GNU General Public License
19 along with Bush. If not, see <http://www.gnu.org/licenses/>.
21 $PRODUCES help.c
23 $BUILTIN help
24 $FUNCTION help_builtin
25 $DEPENDS_ON HELP_BUILTIN
26 $SHORT_DOC help [-dms] [pattern ...]
27 Display information about builtin commands.
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.
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
39 Arguments:
40 PATTERN Pattern specifying a help topic
42 Exit Status:
43 Returns success unless PATTERN is not found or an invalid option is given.
44 $END
46 #include <config.h>
48 #if defined (HELP_BUILTIN)
49 #include <stdio.h>
51 #if defined (HAVE_UNISTD_H)
52 # ifdef _MINIX
53 # include <sys/types.h>
54 # endif
55 # include <unistd.h>
56 #endif
58 #include <errno.h>
60 #include <filecntl.h>
61 #include <stddef.h>
63 #include "../src/bushintl.h"
65 #include "../src/shell.h"
66 #include "../src/builtins.h"
67 #include "../src/runner/execute_cmd.h"
68 #include "../src/impl/pathexp.h"
69 #include "common.h"
70 #include "bushgetopt.h"
72 #include <glob/strmatch.h>
73 #include <glob/glob.h>
75 #ifndef errno
76 extern int errno;
77 #endif
79 extern const char * const bush_copyright;
80 extern const char * const bush_license;
82 static void show_builtin_command_help PARAMS((void));
83 static int open_helpfile PARAMS((char *));
84 static void show_desc PARAMS((char *, int));
85 static void show_manpage PARAMS((char *, int));
86 static void show_longdoc PARAMS((int));
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;
95 register int i;
96 char *pattern, *name;
97 int plen, match_found, sflag, dflag, mflag, m, pass, this_found;
99 dflag = sflag = mflag = 0;
100 reset_internal_getopt ();
101 while ((i = internal_getopt (list, "dms")) != -1)
103 switch (i)
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);
120 list = loptend;
122 if (list == 0)
124 show_shell_version (0);
125 show_builtin_command_help ();
126 return (EXECUTION_SUCCESS);
129 /* We should consider making `help bush' do something. */
131 if (glob_pattern_p (list->word->word) == 1)
133 printf ("%s", ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
134 print_word_list (list, ", ");
135 printf ("%s", _("'\n\n"));
138 for (match_found = 0, pattern = ""; list; list = list->next)
140 pattern = list->word->word;
141 plen = strlen (pattern);
143 for (pass = 1, this_found = 0; pass < 3; pass++)
145 for (i = 0; name = shell_builtins[i].name; i++)
147 QUIT;
149 /* First pass: look for exact string or pattern matches.
150 Second pass: look for prefix matches like bush-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;
157 if (m)
159 this_found = 1;
160 match_found++;
161 if (dflag)
163 show_desc (name, i);
164 continue;
166 else if (mflag)
168 show_manpage (name, i);
169 continue;
172 printf ("%s: %s\n", name, _(shell_builtins[i].short_doc));
174 if (sflag == 0)
175 show_longdoc (i);
178 if (pass == 1 && this_found == 1)
179 break;
183 if (match_found == 0)
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);
189 fflush (stdout);
190 return (EXECUTION_SUCCESS);
193 void
194 builtin_help ()
196 int ind;
197 ptrdiff_t d;
199 current_builtin = builtin_address_internal (this_command_name, 0);
200 if (current_builtin == 0)
201 return;
203 d = current_builtin - shell_builtins;
205 #if defined (__STDC__)
206 ind = (int)d;
207 #else
208 ind = (int)d / sizeof (struct builtin);
209 #endif
211 printf ("%s: %s\n", this_command_name, _(shell_builtins[ind].short_doc));
212 show_longdoc (ind);
215 static int
216 open_helpfile (name)
217 char *name;
219 int fd;
221 fd = open (name, O_RDONLY);
222 if (fd == -1)
224 builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
225 return -1;
227 return fd;
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;
237 register int j;
238 char * const *doc;
239 int fd;
241 doc = shell_builtins[i].long_doc;
243 if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
245 fd = open_helpfile (doc[0]);
246 if (fd < 0)
247 return;
248 zcatfd (fd, 1, doc[0]);
249 close (fd);
251 else if (doc)
252 for (j = 0; doc[j]; j++)
253 printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
256 static void
257 show_desc (name, i)
258 char *name;
259 int i;
261 register int j, r;
262 char **doc, *line;
263 int fd, usefile;
265 doc = (char **)shell_builtins[i].long_doc;
267 usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
268 if (usefile)
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 */
277 else
278 line = doc ? doc[0] : (char *)NULL;
280 printf ("%s - ", name);
281 for (j = 0; line && line[j]; j++)
283 putchar (line[j]);
284 if (line[j] == '\n')
285 break;
288 fflush (stdout);
290 if (usefile)
291 free (line);
294 /* Print builtin help in pseudo-manpage format. */
295 static void
296 show_manpage (name, i)
297 char *name;
298 int i;
300 register int j;
301 char **doc, *line;
302 int fd, usefile;
304 doc = (char **)shell_builtins[i].long_doc;
306 usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
307 if (usefile)
309 fd = open_helpfile (doc[0]);
310 if (fd < 0)
311 return;
312 zmapfd (fd, &line, doc[0]);
313 close (fd);
315 else
316 line = doc ? _(doc[0]) : (char *)NULL;
318 /* NAME */
319 printf ("NAME\n");
320 printf ("%*s%s - ", BASE_INDENT, " ", name);
321 for (j = 0; line && line[j]; j++)
323 putchar (line[j]);
324 if (line[j] == '\n')
325 break;
327 printf ("\n");
329 /* SYNOPSIS */
330 printf ("SYNOPSIS\n");
331 printf ("%*s%s\n\n", BASE_INDENT, " ", _(shell_builtins[i].short_doc));
333 /* DESCRIPTION */
334 printf ("DESCRIPTION\n");
335 if (usefile == 0)
337 for (j = 0; doc[j]; j++)
338 printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
340 else
342 for (j = 0; line && line[j]; j++)
344 putchar (line[j]);
345 if (line[j] == '\n')
346 printf ("%*s", BASE_INDENT, " ");
349 putchar ('\n');
351 /* SEE ALSO */
352 printf ("SEE ALSO\n");
353 printf ("%*sbush(1)\n\n", BASE_INDENT, " ");
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", _(bush_copyright));
361 printf ("%*s", BASE_INDENT, " ");
362 printf ("%s\n", _(bush_license));
364 fflush (stdout);
365 if (usefile)
366 free (line);
369 static void
370 dispcolumn (i, buf, bufsize, width, height)
371 int i;
372 char *buf;
373 size_t bufsize;
374 int width, height;
376 int j;
377 int dispcols;
378 char *helpdoc;
380 /* first column */
381 helpdoc = _(shell_builtins[i].short_doc);
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))
390 printf ("\n");
391 return;
394 dispcols = strlen (buf);
395 /* two spaces */
396 for (j = dispcols; j < width; j++)
397 putc (' ', stdout);
399 /* second column */
400 helpdoc = _(shell_builtins[i+height].short_doc);
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';
407 printf ("%s\n", buf);
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;
418 int j;
419 int dispcols, dispchars;
420 char *helpdoc;
421 wchar_t *wcstr;
422 size_t slen, n;
424 /* first column */
425 helpdoc = _(shell_builtins[i].short_doc);
427 wcstr = 0;
428 slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
429 if (slen == -1)
431 dispcolumn (i, buf, bufsize, width, height);
432 return;
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';
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' ';
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 '*' */
453 wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
455 if (dispcols >= width-2)
457 wcstr[dispchars] = L'>'; /* indicate truncation */
458 wcstr[dispchars+1] = L'\0';
461 printf ("%ls", wcstr);
462 if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
464 printf ("\n");
465 free (wcstr);
466 return;
469 /* at least one space */
470 for (j = dispcols; j < width; j++)
471 putc (' ', stdout);
473 /* second column */
474 helpdoc = _(shell_builtins[i+height].short_doc);
475 slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
476 if (slen == -1)
478 /* for now */
479 printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
480 free (wcstr);
481 return;
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 */
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' ';
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 '*' */
499 wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
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 bush-4.3
503 did. */
504 if (dispcols >= width - 2)
506 wcstr[dispchars-1] = L'>'; /* indicate truncation */
507 wcstr[dispchars] = L'\0';
510 printf ("%ls\n", wcstr);
512 free (wcstr);
514 #endif /* HANDLE_MULTIBYTE */
516 static void
517 show_builtin_command_help ()
519 int i, j;
520 int height, width;
521 char *t, blurb[128];
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 bush' 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\
529 A star (*) next to a name means that the command is disabled.\n\
530 \n"));
532 width = default_columns ();
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 */
541 for (i = 0; i < height; i++)
543 QUIT;
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);
553 #endif /* HELP_BUILTIN */