blob: 42c80e5e43cb00bb034bb118ed67b48ee070734b [file] [log] [blame]
Dan Pasanenc6e37862014-10-02 14:08:59 -05001/* help.c, created from help.def. */
2#line 22 "./help.def"
3
4#line 45 "./help.def"
5
6#include <config.h>
7
8#if defined (HELP_BUILTIN)
9#include <stdio.h>
10
11#if defined (HAVE_UNISTD_H)
12# ifdef _MINIX
13# include <sys/types.h>
14# endif
15# include <unistd.h>
16#endif
17
18#include <errno.h>
19
20#include <filecntl.h>
21
22#include "../bashintl.h"
23
24#include "../shell.h"
25#include "../builtins.h"
26#include "../pathexp.h"
27#include "common.h"
28#include "bashgetopt.h"
29
30#include <glob/strmatch.h>
31#include <glob/glob.h>
32
33#ifndef errno
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010034#include <errno.h>
Dan Pasanenc6e37862014-10-02 14:08:59 -050035#endif
36
37extern const char * const bash_copyright;
38extern const char * const bash_license;
39
40static void show_builtin_command_help __P((void));
41static int open_helpfile __P((char *));
42static void show_desc __P((char *, int));
43static void show_manpage __P((char *, int));
44static void show_longdoc __P((int));
45
46/* Print out a list of the known functions in the shell, and what they do.
47 If LIST is supplied, print out the list which matches for each pattern
48 specified. */
49int
50help_builtin (list)
51 WORD_LIST *list;
52{
53 register int i;
54 char *pattern, *name;
55 int plen, match_found, sflag, dflag, mflag, m, pass, this_found;
56
57 dflag = sflag = mflag = 0;
58 reset_internal_getopt ();
59 while ((i = internal_getopt (list, "dms")) != -1)
60 {
61 switch (i)
62 {
63 case 'd':
64 dflag = 1;
65 break;
66 case 'm':
67 mflag = 1;
68 break;
69 case 's':
70 sflag = 1;
71 break;
72 default:
73 builtin_usage ();
74 return (EX_USAGE);
75 }
76 }
77 list = loptend;
78
79 if (list == 0)
80 {
81 show_shell_version (0);
82 show_builtin_command_help ();
83 return (EXECUTION_SUCCESS);
84 }
85
86 /* We should consider making `help bash' do something. */
87
88 if (glob_pattern_p (list->word->word))
89 {
90 printf (ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
91 print_word_list (list, ", ");
92 printf ("'\n\n");
93 }
94
95 for (match_found = 0, pattern = ""; list; list = list->next)
96 {
97 pattern = list->word->word;
98 plen = strlen (pattern);
99
100 for (pass = 1, this_found = 0; pass < 3; pass++)
101 {
102 for (i = 0; name = shell_builtins[i].name; i++)
103 {
104 QUIT;
105
106 /* First pass: look for exact string or pattern matches.
107 Second pass: look for prefix matches like bash-4.2 */
108 if (pass == 1)
109 m = (strcmp (pattern, name) == 0) ||
110 (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH);
111 else
112 m = strncmp (pattern, name, plen) == 0;
113
114 if (m)
115 {
116 this_found = 1;
117 match_found++;
118 if (dflag)
119 {
120 show_desc (name, i);
121 continue;
122 }
123 else if (mflag)
124 {
125 show_manpage (name, i);
126 continue;
127 }
128
129 printf ("%s: %s\n", name, _(shell_builtins[i].short_doc));
130
131 if (sflag == 0)
132 show_longdoc (i);
133 }
134 }
135 if (pass == 1 && this_found == 1)
136 break;
137 }
138 }
139
140 if (match_found == 0)
141 {
142 builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern);
143 return (EXECUTION_FAILURE);
144 }
145
146 fflush (stdout);
147 return (EXECUTION_SUCCESS);
148}
149
150static int
151open_helpfile (name)
152 char *name;
153{
154 int fd;
155
156 fd = open (name, O_RDONLY);
157 if (fd == -1)
158 {
159 builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
160 return -1;
161 }
162 return fd;
163}
164
165/* By convention, enforced by mkbuiltins.c, if separate help files are being
166 used, the long_doc array contains one string -- the full pathname of the
167 help file for this builtin. */
168static void
169show_longdoc (i)
170 int i;
171{
172 register int j;
173 char * const *doc;
174 int fd;
175
176 doc = shell_builtins[i].long_doc;
177
178 if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
179 {
180 fd = open_helpfile (doc[0]);
181 if (fd < 0)
182 return;
183 zcatfd (fd, 1, doc[0]);
184 close (fd);
185 }
186 else if (doc)
187 for (j = 0; doc[j]; j++)
188 printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
189}
190
191static void
192show_desc (name, i)
193 char *name;
194 int i;
195{
196 register int j;
197 char **doc, *line;
198 int fd, usefile;
199
200 doc = (char **)shell_builtins[i].long_doc;
201
202 usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
203 if (usefile)
204 {
205 fd = open_helpfile (doc[0]);
206 if (fd < 0)
207 return;
208 zmapfd (fd, &line, doc[0]);
209 close (fd);
210 }
211 else
212 line = doc ? doc[0] : (char *)NULL;
213
214 printf ("%s - ", name);
215 for (j = 0; line && line[j]; j++)
216 {
217 putchar (line[j]);
218 if (line[j] == '\n')
219 break;
220 }
221
222 fflush (stdout);
223
224 if (usefile)
225 free (line);
226}
227
228/* Print builtin help in pseudo-manpage format. */
229static void
230show_manpage (name, i)
231 char *name;
232 int i;
233{
234 register int j;
235 char **doc, *line;
236 int fd, usefile;
237
238 doc = (char **)shell_builtins[i].long_doc;
239
240 usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
241 if (usefile)
242 {
243 fd = open_helpfile (doc[0]);
244 if (fd < 0)
245 return;
246 zmapfd (fd, &line, doc[0]);
247 close (fd);
248 }
249 else
250 line = doc ? _(doc[0]) : (char *)NULL;
251
252 /* NAME */
253 printf ("NAME\n");
254 printf ("%*s%s - ", BASE_INDENT, " ", name);
255 for (j = 0; line && line[j]; j++)
256 {
257 putchar (line[j]);
258 if (line[j] == '\n')
259 break;
260 }
261 printf ("\n");
262
263 /* SYNOPSIS */
264 printf ("SYNOPSIS\n");
265 printf ("%*s%s\n\n", BASE_INDENT, " ", _(shell_builtins[i].short_doc));
266
267 /* DESCRIPTION */
268 printf ("DESCRIPTION\n");
269 if (usefile == 0)
270 {
271 for (j = 0; doc[j]; j++)
272 printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
273 }
274 else
275 {
276 for (j = 0; line && line[j]; j++)
277 {
278 putchar (line[j]);
279 if (line[j] == '\n')
280 printf ("%*s", BASE_INDENT, " ");
281 }
282 }
283 putchar ('\n');
284
285 /* SEE ALSO */
286 printf ("SEE ALSO\n");
287 printf ("%*sbash(1)\n\n", BASE_INDENT, " ");
288
289 /* IMPLEMENTATION */
290 printf ("IMPLEMENTATION\n");
291 printf ("%*s", BASE_INDENT, " ");
292 show_shell_version (0);
293 printf ("%*s", BASE_INDENT, " ");
294 printf ("%s\n", _(bash_copyright));
295 printf ("%*s", BASE_INDENT, " ");
296 printf ("%s\n", _(bash_license));
297
298 fflush (stdout);
299 if (usefile)
300 free (line);
301}
302
303static void
304dispcolumn (i, buf, bufsize, width, height)
305 int i;
306 char *buf;
307 size_t bufsize;
308 int width, height;
309{
310 int j;
311 int displen;
312 char *helpdoc;
313
314 /* first column */
315 helpdoc = _(shell_builtins[i].short_doc);
316
317 buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
318 strncpy (buf + 1, helpdoc, width - 2);
319 buf[width - 2] = '>'; /* indicate truncation */
320 buf[width - 1] = '\0';
321 printf ("%s", buf);
322 if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
323 {
324 printf ("\n");
325 return;
326 }
327
328 displen = strlen (buf);
329 /* two spaces */
330 for (j = displen; j < width; j++)
331 putc (' ', stdout);
332
333 /* second column */
334 helpdoc = _(shell_builtins[i+height].short_doc);
335
336 buf[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*';
337 strncpy (buf + 1, helpdoc, width - 3);
338 buf[width - 3] = '>'; /* indicate truncation */
339 buf[width - 2] = '\0';
340
341 printf ("%s\n", buf);
342}
343
344#if defined (HANDLE_MULTIBYTE)
345static void
346wdispcolumn (i, buf, bufsize, width, height)
347 int i;
348 char *buf;
349 size_t bufsize;
350 int width, height;
351{
352 int j;
353 int displen;
354 char *helpdoc;
355 wchar_t *wcstr;
356 size_t slen, n;
357 int wclen;
358
359 /* first column */
360 helpdoc = _(shell_builtins[i].short_doc);
361
362 wcstr = 0;
363 slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
364 if (slen == -1)
365 {
366 dispcolumn (i, buf, bufsize, width, height);
367 return;
368 }
369
370 /* No bigger than the passed max width */
371 if (slen >= width)
372 slen = width - 2;
373 wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
374 n = mbstowcs (wcstr+1, helpdoc, slen + 1);
375 wcstr[n+1] = L'\0';
376
377 /* Turn tabs and newlines into spaces for column display, since wcwidth
378 returns -1 for them */
379 for (j = 1; j < n; j++)
380 if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
381 wcstr[j] = L' ';
382
383 displen = wcsnwidth (wcstr+1, slen, width - 2) + 1; /* +1 for ' ' or '*' */
384
385 wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
386
387 /* This assumes each wide char takes up one column position when displayed */
388 wcstr[width - 2] = L'>'; /* indicate truncation */
389 wcstr[width - 1] = L'\0';
390
391 printf ("%ls", wcstr);
392 if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
393 {
394 printf ("\n");
395 return;
396 }
397
398 /* at least one space */
399 for (j = displen; j < width; j++)
400 putc (' ', stdout);
401
402 /* second column */
403 helpdoc = _(shell_builtins[i+height].short_doc);
404 slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
405 if (slen == -1)
406 {
407 /* for now */
408 printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
409 return;
410 }
411
412 /* Reuse wcstr since it is already width wide chars long */
413 if (slen >= width)
414 slen = width - 2;
415 n = mbstowcs (wcstr+1, helpdoc, slen + 1);
416 wcstr[n+1] = L'\0'; /* make sure null-terminated */
417
418 /* Turn tabs and newlines into spaces for column display */
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);
424
425 wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
426
427 /* This assumes each wide char takes up one column position when displayed */
428 wcstr[width - 3] = L'>'; /* indicate truncation */
429 wcstr[width - 2] = L'\0';
430
431 printf ("%ls\n", wcstr);
432
433 free (wcstr);
434}
435#endif /* HANDLE_MULTIBYTE */
436
437static void
438show_builtin_command_help ()
439{
440 int i, j;
441 int height, width;
442 char *t, blurb[128];
443
444 printf (
445_("These shell commands are defined internally. Type `help' to see this list.\n\
446Type `help name' to find out more about the function `name'.\n\
447Use `info bash' to find out more about the shell in general.\n\
448Use `man -k' or `info' to find out more about commands not in this list.\n\
449\n\
450A star (*) next to a name means that the command is disabled.\n\
451\n"));
452
453 t = get_string_value ("COLUMNS");
454 width = (t && *t) ? atoi (t) : 80;
455 if (width <= 0)
456 width = 80;
457
458 width /= 2;
459 if (width > sizeof (blurb))
460 width = sizeof (blurb);
461 if (width <= 3)
462 width = 40;
463 height = (num_shell_builtins + 1) / 2; /* number of rows */
464
465 for (i = 0; i < height; i++)
466 {
467 QUIT;
468
469#if defined (HANDLE_MULTIBYTE)
470 if (MB_CUR_MAX > 1)
471 wdispcolumn (i, blurb, sizeof (blurb), width, height);
472 else
473#endif
474 dispcolumn (i, blurb, sizeof (blurb), width, height);
475 }
476}
477#endif /* HELP_BUILTIN */