]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/mkbuiltins.c
bash-4.3-rc1 overlay
[thirdparty/bash.git] / builtins / mkbuiltins.c
CommitLineData
726f6388
JA
1/* mkbuiltins.c - Create builtins.c, builtext.h, and builtdoc.c from
2 a single source file called builtins.def. */
3
631b20c6 4/* Copyright (C) 1987-2011 Free Software Foundation, Inc.
726f6388 5
2e4498b3 6 This file is part of GNU Bash, the Bourne Again SHell.
726f6388 7
2e4498b3
CR
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.
726f6388 12
2e4498b3
CR
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.
726f6388 17
2e4498b3
CR
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*/
726f6388 21
20587658 22#if !defined (CROSS_COMPILING)
dc8fbaf9
CR
23# include <config.h>
24#else /* CROSS_COMPILING */
25/* A conservative set of defines based on POSIX/SUS3/XPG6 */
26# define HAVE_UNISTD_H
27# define HAVE_STRING_H
28# define HAVE_STDLIB_H
29
30# define HAVE_RENAME
31#endif /* CROSS_COMPILING */
ccc6cda3
JA
32
33#if defined (HAVE_UNISTD_H)
cce855bc
JA
34# ifdef _MINIX
35# include <sys/types.h>
36# endif
ccc6cda3
JA
37# include <unistd.h>
38#endif
39
cce855bc 40#ifndef _MINIX
d3a24ed2
CR
41# include "../bashtypes.h"
42# if defined (HAVE_SYS_FILE_H)
43# include <sys/file.h>
44# endif
cce855bc
JA
45#endif
46
bb70624e
JA
47#include "posixstat.h"
48#include "filecntl.h"
726f6388 49
d166f048
JA
50#include "../bashansi.h"
51#include <stdio.h>
7117c2d2 52#include <errno.h>
726f6388 53
f73dda09
JA
54#include "stdc.h"
55
726f6388
JA
56#define DOCFILE "builtins.texi"
57
7117c2d2
JA
58#ifndef errno
59extern int errno;
60#endif
61
726f6388
JA
62static char *xmalloc (), *xrealloc ();
63
64#if !defined (__STDC__) && !defined (strcpy)
65extern char *strcpy ();
66#endif /* !__STDC__ && !strcpy */
67
68#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
69#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
70
71/* Flag values that builtins can have. */
72#define BUILTIN_FLAG_SPECIAL 0x01
ccc6cda3 73#define BUILTIN_FLAG_ASSIGNMENT 0x02
234d8729 74#define BUILTIN_FLAG_POSIX_BUILTIN 0x04
726f6388 75
01ed5ba4
CR
76#define BASE_INDENT 4
77
726f6388
JA
78/* If this stream descriptor is non-zero, then write
79 texinfo documentation to it. */
80FILE *documentation_file = (FILE *)NULL;
81
82/* Non-zero means to only produce documentation. */
83int only_documentation = 0;
84
85/* Non-zero means to not do any productions. */
86int inhibit_production = 0;
87
abe2eb5b
CR
88/* Non-zero means to not add functions (xxx_builtin) to the members of the
89 produced `struct builtin []' */
90int inhibit_functions = 0;
91
7117c2d2
JA
92/* Non-zero means to produce separate help files for each builtin, named by
93 the builtin name, in `./helpfiles'. */
94int separate_helpfiles = 0;
95
01ed5ba4
CR
96/* Non-zero means to create single C strings for each `longdoc', with
97 embedded newlines, for ease of translation. */
98int single_longdoc_strings = 1;
99
7117c2d2
JA
100/* The name of a directory into which the separate external help files will
101 eventually be installed. */
102char *helpfile_directory;
726f6388
JA
103
104/* The name of a directory to precede the filename when reporting
105 errors. */
106char *error_directory = (char *)NULL;
107
108/* The name of the structure file. */
109char *struct_filename = (char *)NULL;
110
111/* The name of the external declaration file. */
112char *extern_filename = (char *)NULL;
113
114/* Here is a structure for manipulating arrays of data. */
115typedef struct {
116 int size; /* Number of slots allocated to array. */
117 int sindex; /* Current location in array. */
118 int width; /* Size of each element. */
119 int growth_rate; /* How fast to grow. */
120 char **array; /* The array itself. */
121} ARRAY;
122
123/* Here is a structure defining a single BUILTIN. */
124typedef struct {
125 char *name; /* The name of this builtin. */
126 char *function; /* The name of the function to call. */
127 char *shortdoc; /* The short documentation for this builtin. */
128 char *docname; /* Possible name for documentation string. */
129 ARRAY *longdoc; /* The long documentation for this builtin. */
130 ARRAY *dependencies; /* Null terminated array of #define names. */
131 int flags; /* Flags for this builtin. */
132} BUILTIN_DESC;
133
134/* Here is a structure which defines a DEF file. */
135typedef struct {
136 char *filename; /* The name of the input def file. */
137 ARRAY *lines; /* The contents of the file. */
138 int line_number; /* The current line number. */
139 char *production; /* The name of the production file. */
140 FILE *output; /* Open file stream for PRODUCTION. */
141 ARRAY *builtins; /* Null terminated array of BUILTIN_DESC *. */
142} DEF_FILE;
143
144/* The array of all builtins encountered during execution of this code. */
145ARRAY *saved_builtins = (ARRAY *)NULL;
146
147/* The Posix.2 so-called `special' builtins. */
148char *special_builtins[] =
149{
150 ":", ".", "source", "break", "continue", "eval", "exec", "exit",
9d2b70f0 151 "export", "readonly", "return", "set", "shift", "times", "trap", "unset",
726f6388
JA
152 (char *)NULL
153};
ccc6cda3
JA
154
155/* The builtin commands that take assignment statements as arguments. */
156char *assignment_builtins[] =
157{
158 "alias", "declare", "export", "local", "readonly", "typeset",
159 (char *)NULL
160};
161
234d8729
CR
162/* The builtin commands that are special to the POSIX search order. */
163char *posix_builtins[] =
164{
165 "alias", "bg", "cd", "command", "false", "fc", "fg", "getopts", "jobs",
166 "kill", "newgrp", "pwd", "read", "true", "umask", "unalias", "wait",
167 (char *)NULL
168};
169
ccc6cda3 170/* Forward declarations. */
726f6388 171static int is_special_builtin ();
ccc6cda3 172static int is_assignment_builtin ();
234d8729 173static int is_posix_builtin ();
ccc6cda3 174
b72432fd
JA
175#if !defined (HAVE_RENAME)
176static int rename ();
177#endif
178
ccc6cda3
JA
179void extract_info ();
180
181void file_error ();
182void line_error ();
183
184void write_file_headers ();
185void write_file_footers ();
186void write_ifdefs ();
187void write_endifs ();
188void write_documentation ();
189void write_longdocs ();
190void write_builtins ();
726f6388 191
7117c2d2
JA
192int write_helpfiles ();
193
ccc6cda3
JA
194void free_defs ();
195void add_documentation ();
196
197void must_be_building ();
198void remove_trailing_whitespace ();
7117c2d2
JA
199
200#define document_name(b) ((b)->docname ? (b)->docname : (b)->name)
201
726f6388
JA
202\f
203/* For each file mentioned on the command line, process it and
204 write the information to STRUCTFILE and EXTERNFILE, while
8581f42d 205 creating the production file if necessary. */
ccc6cda3 206int
726f6388
JA
207main (argc, argv)
208 int argc;
209 char **argv;
210{
211 int arg_index = 1;
212 FILE *structfile, *externfile;
213 char *documentation_filename, *temp_struct_filename;
214
215 structfile = externfile = (FILE *)NULL;
216 documentation_filename = DOCFILE;
217 temp_struct_filename = (char *)NULL;
218
219 while (arg_index < argc && argv[arg_index][0] == '-')
220 {
221 char *arg = argv[arg_index++];
222
223 if (strcmp (arg, "-externfile") == 0)
224 extern_filename = argv[arg_index++];
225 else if (strcmp (arg, "-structfile") == 0)
226 struct_filename = argv[arg_index++];
227 else if (strcmp (arg, "-noproduction") == 0)
228 inhibit_production = 1;
abe2eb5b
CR
229 else if (strcmp (arg, "-nofunctions") == 0)
230 inhibit_functions = 1;
726f6388
JA
231 else if (strcmp (arg, "-document") == 0)
232 documentation_file = fopen (documentation_filename, "w");
233 else if (strcmp (arg, "-D") == 0)
234 {
235 int len;
236
237 if (error_directory)
238 free (error_directory);
239
240 error_directory = xmalloc (2 + strlen (argv[arg_index]));
241 strcpy (error_directory, argv[arg_index]);
242 len = strlen (error_directory);
243
244 if (len && error_directory[len - 1] != '/')
245 strcat (error_directory, "/");
246
247 arg_index++;
248 }
249 else if (strcmp (arg, "-documentonly") == 0)
250 {
251 only_documentation = 1;
252 documentation_file = fopen (documentation_filename, "w");
253 }
7117c2d2
JA
254 else if (strcmp (arg, "-H") == 0)
255 {
256 separate_helpfiles = 1;
257 helpfile_directory = argv[arg_index++];
258 }
01ed5ba4
CR
259 else if (strcmp (arg, "-S") == 0)
260 single_longdoc_strings = 0;
726f6388
JA
261 else
262 {
263 fprintf (stderr, "%s: Unknown flag %s.\n", argv[0], arg);
264 exit (2);
265 }
266 }
267
268 /* If there are no files to process, just quit now. */
269 if (arg_index == argc)
270 exit (0);
271
272 if (!only_documentation)
273 {
274 /* Open the files. */
275 if (struct_filename)
276 {
277 temp_struct_filename = xmalloc (15);
f73dda09 278 sprintf (temp_struct_filename, "mk-%ld", (long) getpid ());
726f6388
JA
279 structfile = fopen (temp_struct_filename, "w");
280
281 if (!structfile)
282 file_error (temp_struct_filename);
283 }
284
285 if (extern_filename)
286 {
287 externfile = fopen (extern_filename, "w");
288
289 if (!externfile)
290 file_error (extern_filename);
291 }
292
293 /* Write out the headers. */
294 write_file_headers (structfile, externfile);
295 }
296
297 if (documentation_file)
298 {
299 fprintf (documentation_file, "@c Table of builtins created with %s.\n",
300 argv[0]);
301 fprintf (documentation_file, "@ftable @asis\n");
302 }
303
304 /* Process the .def files. */
305 while (arg_index < argc)
306 {
307 register char *arg;
308
309 arg = argv[arg_index++];
310
311 extract_info (arg, structfile, externfile);
312 }
313
314 /* Close the files. */
315 if (!only_documentation)
316 {
317 /* Write the footers. */
318 write_file_footers (structfile, externfile);
319
320 if (structfile)
321 {
322 write_longdocs (structfile, saved_builtins);
323 fclose (structfile);
b72432fd 324 rename (temp_struct_filename, struct_filename);
726f6388
JA
325 }
326
327 if (externfile)
328 fclose (externfile);
329 }
330
abe2eb5b
CR
331#if 0
332 /* This is now done by a different program */
7117c2d2
JA
333 if (separate_helpfiles)
334 {
335 write_helpfiles (saved_builtins);
336 }
abe2eb5b 337#endif
7117c2d2 338
726f6388
JA
339 if (documentation_file)
340 {
341 fprintf (documentation_file, "@end ftable\n");
342 fclose (documentation_file);
343 }
344
345 exit (0);
346}
347
348/* **************************************************************** */
349/* */
350/* Array Functions and Manipulators */
351/* */
352/* **************************************************************** */
353
354/* Make a new array, and return a pointer to it. The array will
355 contain elements of size WIDTH, and is initialized to no elements. */
356ARRAY *
357array_create (width)
358 int width;
359{
360 ARRAY *array;
361
362 array = (ARRAY *)xmalloc (sizeof (ARRAY));
363 array->size = 0;
364 array->sindex = 0;
365 array->width = width;
366
367 /* Default to increasing size in units of 20. */
368 array->growth_rate = 20;
369
370 array->array = (char **)NULL;
371
372 return (array);
373}
374
375/* Copy the array of strings in ARRAY. */
376ARRAY *
377copy_string_array (array)
378 ARRAY *array;
379{
380 register int i;
381 ARRAY *copy;
382
383 if (!array)
384 return (ARRAY *)NULL;
385
386 copy = array_create (sizeof (char *));
387
388 copy->size = array->size;
389 copy->sindex = array->sindex;
390 copy->width = array->width;
391
392 copy->array = (char **)xmalloc ((1 + array->sindex) * sizeof (char *));
393
394 for (i = 0; i < array->sindex; i++)
395 copy->array[i] = savestring (array->array[i]);
396
397 copy->array[i] = (char *)NULL;
398
399 return (copy);
400}
401
8581f42d 402/* Add ELEMENT to ARRAY, growing the array if necessary. */
ccc6cda3 403void
726f6388
JA
404array_add (element, array)
405 char *element;
406 ARRAY *array;
407{
408 if (array->sindex + 2 > array->size)
409 array->array = (char **)xrealloc
410 (array->array, (array->size += array->growth_rate) * array->width);
411
726f6388
JA
412 array->array[array->sindex++] = element;
413 array->array[array->sindex] = (char *)NULL;
726f6388
JA
414}
415
416/* Free an allocated array and data pointer. */
ccc6cda3 417void
726f6388
JA
418array_free (array)
419 ARRAY *array;
420{
421 if (array->array)
422 free (array->array);
423
424 free (array);
425}
426
427/* **************************************************************** */
428/* */
429/* Processing a DEF File */
430/* */
431/* **************************************************************** */
432
433/* The definition of a function. */
434typedef int Function ();
f73dda09 435typedef int mk_handler_func_t __P((char *, DEF_FILE *, char *));
726f6388
JA
436
437/* Structure handles processor directives. */
438typedef struct {
439 char *directive;
f73dda09 440 mk_handler_func_t *function;
726f6388
JA
441} HANDLER_ENTRY;
442
f73dda09
JA
443extern int builtin_handler __P((char *, DEF_FILE *, char *));
444extern int function_handler __P((char *, DEF_FILE *, char *));
445extern int short_doc_handler __P((char *, DEF_FILE *, char *));
446extern int comment_handler __P((char *, DEF_FILE *, char *));
447extern int depends_on_handler __P((char *, DEF_FILE *, char *));
448extern int produces_handler __P((char *, DEF_FILE *, char *));
449extern int end_handler __P((char *, DEF_FILE *, char *));
450extern int docname_handler __P((char *, DEF_FILE *, char *));
726f6388
JA
451
452HANDLER_ENTRY handlers[] = {
453 { "BUILTIN", builtin_handler },
454 { "DOCNAME", docname_handler },
455 { "FUNCTION", function_handler },
456 { "SHORT_DOC", short_doc_handler },
457 { "$", comment_handler },
458 { "COMMENT", comment_handler },
459 { "DEPENDS_ON", depends_on_handler },
460 { "PRODUCES", produces_handler },
461 { "END", end_handler },
f73dda09 462 { (char *)NULL, (mk_handler_func_t *)NULL }
726f6388
JA
463};
464
465/* Return the entry in the table of handlers for NAME. */
466HANDLER_ENTRY *
467find_directive (directive)
468 char *directive;
469{
470 register int i;
471
472 for (i = 0; handlers[i].directive; i++)
473 if (strcmp (handlers[i].directive, directive) == 0)
474 return (&handlers[i]);
475
476 return ((HANDLER_ENTRY *)NULL);
477}
478
479/* Non-zero indicates that a $BUILTIN has been seen, but not
480 the corresponding $END. */
481static int building_builtin = 0;
482
483/* Non-zero means to output cpp line and file information before
484 printing the current line to the production file. */
485int output_cpp_line_info = 0;
486
487/* The main function of this program. Read FILENAME and act on what is
488 found. Lines not starting with a dollar sign are copied to the
489 $PRODUCES target, if one is present. Lines starting with a dollar sign
490 are directives to this program, specifying the name of the builtin, the
491 function to call, the short documentation and the long documentation
492 strings. FILENAME can contain multiple $BUILTINs, but only one $PRODUCES
493 target. After the file has been processed, write out the names of
494 builtins found in each $BUILTIN. Plain text found before the $PRODUCES
495 is ignored, as is "$$ comment text". */
ccc6cda3 496void
726f6388
JA
497extract_info (filename, structfile, externfile)
498 char *filename;
499 FILE *structfile, *externfile;
500{
501 register int i;
502 DEF_FILE *defs;
503 struct stat finfo;
cce855bc 504 size_t file_size;
726f6388 505 char *buffer, *line;
cce855bc 506 int fd, nr;
726f6388
JA
507
508 if (stat (filename, &finfo) == -1)
509 file_error (filename);
510
511 fd = open (filename, O_RDONLY, 0666);
512
513 if (fd == -1)
514 file_error (filename);
515
cce855bc
JA
516 file_size = (size_t)finfo.st_size;
517 buffer = xmalloc (1 + file_size);
726f6388 518
cce855bc 519 if ((nr = read (fd, buffer, file_size)) < 0)
726f6388
JA
520 file_error (filename);
521
b72432fd
JA
522 /* This is needed on WIN32, and does not hurt on Unix. */
523 if (nr < file_size)
524 file_size = nr;
525
726f6388
JA
526 close (fd);
527
cce855bc
JA
528 if (nr == 0)
529 {
530 fprintf (stderr, "mkbuiltins: %s: skipping zero-length file\n", filename);
631b20c6 531 free (buffer);
cce855bc
JA
532 return;
533 }
534
726f6388
JA
535 /* Create and fill in the initial structure describing this file. */
536 defs = (DEF_FILE *)xmalloc (sizeof (DEF_FILE));
537 defs->filename = filename;
538 defs->lines = array_create (sizeof (char *));
539 defs->line_number = 0;
540 defs->production = (char *)NULL;
541 defs->output = (FILE *)NULL;
542 defs->builtins = (ARRAY *)NULL;
543
544 /* Build the array of lines. */
545 i = 0;
cce855bc 546 while (i < file_size)
726f6388
JA
547 {
548 array_add (&buffer[i], defs->lines);
549
77638cbf 550 while (i < file_size && buffer[i] != '\n')
726f6388
JA
551 i++;
552 buffer[i++] = '\0';
553 }
554
555 /* Begin processing the input file. We don't write any output
556 until we have a file to write output to. */
557 output_cpp_line_info = 1;
558
559 /* Process each line in the array. */
560 for (i = 0; line = defs->lines->array[i]; i++)
561 {
562 defs->line_number = i;
563
564 if (*line == '$')
565 {
566 register int j;
567 char *directive;
568 HANDLER_ENTRY *handler;
569
570 /* Isolate the directive. */
571 for (j = 0; line[j] && !whitespace (line[j]); j++);
572
573 directive = xmalloc (j);
574 strncpy (directive, line + 1, j - 1);
575 directive[j -1] = '\0';
576
577 /* Get the function handler and call it. */
578 handler = find_directive (directive);
579
580 if (!handler)
581 {
582 line_error (defs, "Unknown directive `%s'", directive);
583 free (directive);
584 continue;
585 }
586 else
587 {
588 /* Advance to the first non-whitespace character. */
589 while (whitespace (line[j]))
590 j++;
591
592 /* Call the directive handler with the FILE, and ARGS. */
593 (*(handler->function)) (directive, defs, line + j);
594 }
595 free (directive);
596 }
597 else
598 {
599 if (building_builtin)
600 add_documentation (defs, line);
601 else if (defs->output)
602 {
603 if (output_cpp_line_info)
604 {
605 /* If we're handed an absolute pathname, don't prepend
606 the directory name. */
607 if (defs->filename[0] == '/')
608 fprintf (defs->output, "#line %d \"%s\"\n",
609 defs->line_number + 1, defs->filename);
610 else
611 fprintf (defs->output, "#line %d \"%s%s\"\n",
612 defs->line_number + 1,
613 error_directory ? error_directory : "./",
614 defs->filename);
615 output_cpp_line_info = 0;
616 }
617
618 fprintf (defs->output, "%s\n", line);
619 }
620 }
621 }
622
623 /* Close the production file. */
624 if (defs->output)
625 fclose (defs->output);
626
627 /* The file has been processed. Write the accumulated builtins to
628 the builtins.c file, and write the extern definitions to the
629 builtext.h file. */
630 write_builtins (defs, structfile, externfile);
631
632 free (buffer);
633 free_defs (defs);
634}
635
636#define free_safely(x) if (x) free (x)
637
638static void
639free_builtin (builtin)
640 BUILTIN_DESC *builtin;
641{
642 register int i;
643
644 free_safely (builtin->name);
645 free_safely (builtin->function);
646 free_safely (builtin->shortdoc);
647 free_safely (builtin->docname);
648
649 if (builtin->longdoc)
650 array_free (builtin->longdoc);
651
652 if (builtin->dependencies)
653 {
654 for (i = 0; builtin->dependencies->array[i]; i++)
655 free (builtin->dependencies->array[i]);
656 array_free (builtin->dependencies);
657 }
658}
659
660/* Free all of the memory allocated to a DEF_FILE. */
ccc6cda3 661void
726f6388
JA
662free_defs (defs)
663 DEF_FILE *defs;
664{
665 register int i;
666 register BUILTIN_DESC *builtin;
667
668 if (defs->production)
669 free (defs->production);
670
671 if (defs->lines)
672 array_free (defs->lines);
673
674 if (defs->builtins)
675 {
676 for (i = 0; builtin = (BUILTIN_DESC *)defs->builtins->array[i]; i++)
28ef6c31 677 {
726f6388
JA
678 free_builtin (builtin);
679 free (builtin);
28ef6c31 680 }
726f6388
JA
681 array_free (defs->builtins);
682 }
683 free (defs);
684}
685
686/* **************************************************************** */
687/* */
688/* The Handler Functions Themselves */
689/* */
690/* **************************************************************** */
691
692/* Strip surrounding whitespace from STRING, and
693 return a pointer to the start of it. */
694char *
695strip_whitespace (string)
696 char *string;
697{
698 while (whitespace (*string))
699 string++;
700
701 remove_trailing_whitespace (string);
702 return (string);
703}
704
705/* Remove only the trailing whitespace from STRING. */
ccc6cda3 706void
726f6388
JA
707remove_trailing_whitespace (string)
708 char *string;
709{
710 register int i;
711
712 i = strlen (string) - 1;
713
714 while (i > 0 && whitespace (string[i]))
715 i--;
716
717 string[++i] = '\0';
718}
719
720/* Ensure that there is a argument in STRING and return it.
721 FOR_WHOM is the name of the directive which needs the argument.
722 DEFS is the DEF_FILE in which the directive is found.
723 If there is no argument, produce an error. */
724char *
725get_arg (for_whom, defs, string)
726 char *for_whom, *string;
727 DEF_FILE *defs;
728{
729 char *new;
730
731 new = strip_whitespace (string);
732
733 if (!*new)
734 line_error (defs, "%s requires an argument", for_whom);
735
736 return (savestring (new));
737}
738
739/* Error if not building a builtin. */
ccc6cda3 740void
726f6388
JA
741must_be_building (directive, defs)
742 char *directive;
743 DEF_FILE *defs;
744{
745 if (!building_builtin)
746 line_error (defs, "%s must be inside of a $BUILTIN block", directive);
747}
748
749/* Return the current builtin. */
750BUILTIN_DESC *
751current_builtin (directive, defs)
752 char *directive;
753 DEF_FILE *defs;
754{
755 must_be_building (directive, defs);
cce855bc
JA
756 if (defs->builtins)
757 return ((BUILTIN_DESC *)defs->builtins->array[defs->builtins->sindex - 1]);
758 else
759 return ((BUILTIN_DESC *)NULL);
726f6388
JA
760}
761
762/* Add LINE to the long documentation for the current builtin.
763 Ignore blank lines until the first non-blank line has been seen. */
ccc6cda3 764void
726f6388
JA
765add_documentation (defs, line)
766 DEF_FILE *defs;
767 char *line;
768{
769 register BUILTIN_DESC *builtin;
770
771 builtin = current_builtin ("(implied LONGDOC)", defs);
772
773 remove_trailing_whitespace (line);
774
775 if (!*line && !builtin->longdoc)
776 return;
777
778 if (!builtin->longdoc)
779 builtin->longdoc = array_create (sizeof (char *));
780
781 array_add (line, builtin->longdoc);
782}
783
784/* How to handle the $BUILTIN directive. */
785int
786builtin_handler (self, defs, arg)
f73dda09 787 char *self;
726f6388 788 DEF_FILE *defs;
f73dda09 789 char *arg;
726f6388 790{
ccc6cda3
JA
791 BUILTIN_DESC *new;
792 char *name;
793
726f6388
JA
794 /* If we are already building a builtin, we cannot start a new one. */
795 if (building_builtin)
ccc6cda3
JA
796 {
797 line_error (defs, "%s found before $END", self);
798 return (-1);
799 }
726f6388
JA
800
801 output_cpp_line_info++;
802
803 /* Get the name of this builtin, and stick it in the array. */
ccc6cda3
JA
804 name = get_arg (self, defs, arg);
805
806 /* If this is the first builtin, create the array to hold them. */
807 if (!defs->builtins)
808 defs->builtins = array_create (sizeof (BUILTIN_DESC *));
809
810 new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC));
811 new->name = name;
812 new->function = (char *)NULL;
813 new->shortdoc = (char *)NULL;
814 new->docname = (char *)NULL;
815 new->longdoc = (ARRAY *)NULL;
816 new->dependencies = (ARRAY *)NULL;
817 new->flags = 0;
818
819 if (is_special_builtin (name))
820 new->flags |= BUILTIN_FLAG_SPECIAL;
821 if (is_assignment_builtin (name))
822 new->flags |= BUILTIN_FLAG_ASSIGNMENT;
234d8729
CR
823 if (is_posix_builtin (name))
824 new->flags |= BUILTIN_FLAG_POSIX_BUILTIN;
ccc6cda3
JA
825
826 array_add ((char *)new, defs->builtins);
827 building_builtin = 1;
828
726f6388
JA
829 return (0);
830}
831
832/* How to handle the $FUNCTION directive. */
833int
834function_handler (self, defs, arg)
f73dda09 835 char *self;
726f6388 836 DEF_FILE *defs;
f73dda09 837 char *arg;
726f6388
JA
838{
839 register BUILTIN_DESC *builtin;
840
841 builtin = current_builtin (self, defs);
842
cce855bc
JA
843 if (builtin == 0)
844 {
845 line_error (defs, "syntax error: no current builtin for $FUNCTION directive");
846 exit (1);
847 }
726f6388
JA
848 if (builtin->function)
849 line_error (defs, "%s already has a function (%s)",
850 builtin->name, builtin->function);
851 else
852 builtin->function = get_arg (self, defs, arg);
853
854 return (0);
855}
856
857/* How to handle the $DOCNAME directive. */
858int
859docname_handler (self, defs, arg)
f73dda09 860 char *self;
726f6388 861 DEF_FILE *defs;
f73dda09 862 char *arg;
726f6388
JA
863{
864 register BUILTIN_DESC *builtin;
865
866 builtin = current_builtin (self, defs);
867
868 if (builtin->docname)
869 line_error (defs, "%s already had a docname (%s)",
870 builtin->name, builtin->docname);
871 else
872 builtin->docname = get_arg (self, defs, arg);
873
874 return (0);
875}
876
877/* How to handle the $SHORT_DOC directive. */
ccc6cda3 878int
726f6388 879short_doc_handler (self, defs, arg)
f73dda09 880 char *self;
726f6388 881 DEF_FILE *defs;
f73dda09 882 char *arg;
726f6388
JA
883{
884 register BUILTIN_DESC *builtin;
885
886 builtin = current_builtin (self, defs);
887
888 if (builtin->shortdoc)
889 line_error (defs, "%s already has short documentation (%s)",
890 builtin->name, builtin->shortdoc);
891 else
892 builtin->shortdoc = get_arg (self, defs, arg);
893
894 return (0);
895}
896
897/* How to handle the $COMMENT directive. */
ccc6cda3 898int
f73dda09 899comment_handler (self, defs, arg)
726f6388
JA
900 char *self;
901 DEF_FILE *defs;
f73dda09 902 char *arg;
726f6388 903{
ccc6cda3 904 return (0);
726f6388
JA
905}
906
907/* How to handle the $DEPENDS_ON directive. */
ccc6cda3 908int
726f6388 909depends_on_handler (self, defs, arg)
f73dda09 910 char *self;
726f6388 911 DEF_FILE *defs;
f73dda09 912 char *arg;
726f6388
JA
913{
914 register BUILTIN_DESC *builtin;
915 char *dependent;
916
917 builtin = current_builtin (self, defs);
918 dependent = get_arg (self, defs, arg);
919
920 if (!builtin->dependencies)
921 builtin->dependencies = array_create (sizeof (char *));
922
923 array_add (dependent, builtin->dependencies);
924
925 return (0);
926}
927
928/* How to handle the $PRODUCES directive. */
ccc6cda3 929int
726f6388 930produces_handler (self, defs, arg)
f73dda09 931 char *self;
726f6388 932 DEF_FILE *defs;
f73dda09 933 char *arg;
726f6388
JA
934{
935 /* If just hacking documentation, don't change any of the production
936 files. */
937 if (only_documentation)
938 return (0);
939
940 output_cpp_line_info++;
941
942 if (defs->production)
943 line_error (defs, "%s already has a %s definition", defs->filename, self);
944 else
945 {
946 defs->production = get_arg (self, defs, arg);
947
948 if (inhibit_production)
949 return (0);
950
951 defs->output = fopen (defs->production, "w");
952
953 if (!defs->output)
954 file_error (defs->production);
955
956 fprintf (defs->output, "/* %s, created from %s. */\n",
957 defs->production, defs->filename);
958 }
959 return (0);
960}
961
962/* How to handle the $END directive. */
ccc6cda3 963int
726f6388 964end_handler (self, defs, arg)
f73dda09 965 char *self;
726f6388 966 DEF_FILE *defs;
f73dda09 967 char *arg;
726f6388
JA
968{
969 must_be_building (self, defs);
970 building_builtin = 0;
ccc6cda3 971 return (0);
726f6388
JA
972}
973
974/* **************************************************************** */
975/* */
976/* Error Handling Functions */
977/* */
978/* **************************************************************** */
979
980/* Produce an error for DEFS with FORMAT and ARGS. */
ccc6cda3 981void
726f6388
JA
982line_error (defs, format, arg1, arg2)
983 DEF_FILE *defs;
984 char *format, *arg1, *arg2;
985{
986 if (defs->filename[0] != '/')
987 fprintf (stderr, "%s", error_directory ? error_directory : "./");
988 fprintf (stderr, "%s:%d:", defs->filename, defs->line_number + 1);
989 fprintf (stderr, format, arg1, arg2);
990 fprintf (stderr, "\n");
991 fflush (stderr);
992}
993
994/* Print error message for FILENAME. */
ccc6cda3 995void
726f6388
JA
996file_error (filename)
997 char *filename;
998{
999 perror (filename);
1000 exit (2);
1001}
1002
1003/* **************************************************************** */
1004/* */
1005/* xmalloc and xrealloc () */
1006/* */
1007/* **************************************************************** */
1008
1009static void memory_error_and_abort ();
1010
1011static char *
1012xmalloc (bytes)
1013 int bytes;
1014{
1015 char *temp = (char *)malloc (bytes);
1016
1017 if (!temp)
1018 memory_error_and_abort ();
1019 return (temp);
1020}
1021
1022static char *
1023xrealloc (pointer, bytes)
1024 char *pointer;
1025 int bytes;
1026{
1027 char *temp;
1028
1029 if (!pointer)
1030 temp = (char *)malloc (bytes);
1031 else
1032 temp = (char *)realloc (pointer, bytes);
1033
1034 if (!temp)
1035 memory_error_and_abort ();
1036
1037 return (temp);
1038}
1039
1040static void
1041memory_error_and_abort ()
1042{
ccc6cda3 1043 fprintf (stderr, "mkbuiltins: out of virtual memory\n");
726f6388
JA
1044 abort ();
1045}
1046
1047/* **************************************************************** */
1048/* */
1049/* Creating the Struct and Extern Files */
1050/* */
1051/* **************************************************************** */
1052
1053/* Return a pointer to a newly allocated builtin which is
1054 an exact copy of BUILTIN. */
1055BUILTIN_DESC *
1056copy_builtin (builtin)
1057 BUILTIN_DESC *builtin;
1058{
1059 BUILTIN_DESC *new;
1060
1061 new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC));
1062
28ef6c31
JA
1063 new->name = savestring (builtin->name);
1064 new->shortdoc = savestring (builtin->shortdoc);
1065 new->longdoc = copy_string_array (builtin->longdoc);
726f6388
JA
1066 new->dependencies = copy_string_array (builtin->dependencies);
1067
1068 new->function =
1069 builtin->function ? savestring (builtin->function) : (char *)NULL;
1070 new->docname =
1071 builtin->docname ? savestring (builtin->docname) : (char *)NULL;
1072
1073 return (new);
1074}
1075
1076/* How to save away a builtin. */
ccc6cda3 1077void
726f6388
JA
1078save_builtin (builtin)
1079 BUILTIN_DESC *builtin;
1080{
1081 BUILTIN_DESC *newbuiltin;
1082
1083 newbuiltin = copy_builtin (builtin);
1084
1085 /* If this is the first builtin to be saved, create the array
1086 to hold it. */
1087 if (!saved_builtins)
1088 saved_builtins = array_create (sizeof (BUILTIN_DESC *));
1089
1090 array_add ((char *)newbuiltin, saved_builtins);
1091}
1092
1093/* Flags that mean something to write_documentation (). */
01ed5ba4
CR
1094#define STRING_ARRAY 0x01
1095#define TEXINFO 0x02
1096#define PLAINTEXT 0x04
1097#define HELPFILE 0x08
726f6388
JA
1098
1099char *structfile_header[] = {
1100 "/* builtins.c -- the built in shell commands. */",
1101 "",
1102 "/* This file is manufactured by ./mkbuiltins, and should not be",
1103 " edited by hand. See the source to mkbuiltins for details. */",
1104 "",
c31d56a7 1105 "/* Copyright (C) 1987-2012 Free Software Foundation, Inc.",
726f6388
JA
1106 "",
1107 " This file is part of GNU Bash, the Bourne Again SHell.",
1108 "",
2e4498b3
CR
1109 " Bash is free software: you can redistribute it and/or modify",
1110 " it under the terms of the GNU General Public License as published by",
1111 " the Free Software Foundation, either version 3 of the License, or",
1112 " (at your option) any later version.",
726f6388 1113 "",
2e4498b3
CR
1114 " Bash is distributed in the hope that it will be useful,",
1115 " but WITHOUT ANY WARRANTY; without even the implied warranty of",
1116 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
1117 " GNU General Public License for more details.",
726f6388
JA
1118 "",
1119 " You should have received a copy of the GNU General Public License",
2e4498b3
CR
1120 " along with Bash. If not, see <http://www.gnu.org/licenses/>.",
1121 "*/",
726f6388 1122 "",
ccc6cda3 1123 "/* The list of shell builtins. Each element is name, function, flags,",
726f6388
JA
1124 " long-doc, short-doc. The long-doc field contains a pointer to an array",
1125 " of help lines. The function takes a WORD_LIST *; the first word in the",
1126 " list is the first arg to the command. The list has already had word",
1127 " expansion performed.",
1128 "",
1129 " Functions which need to look at only the simple commands (e.g.",
1130 " the enable_builtin ()), should ignore entries where",
f73dda09 1131 " (array[i].function == (sh_builtin_func_t *)NULL). Such entries are for",
726f6388
JA
1132 " the list of shell reserved control structures, like `if' and `while'.",
1133 " The end of the list is denoted with a NULL name field. */",
1134 "",
1135 "#include \"../builtins.h\"",
1136 (char *)NULL
1137 };
1138
1139char *structfile_footer[] = {
e3af9370 1140 " { (char *)0x0, (sh_builtin_func_t *)0x0, 0, (char **)0x0, (char *)0x0, (char *)0x0 }",
726f6388
JA
1141 "};",
1142 "",
ccc6cda3
JA
1143 "struct builtin *shell_builtins = static_shell_builtins;",
1144 "struct builtin *current_builtin;",
1145 "",
726f6388 1146 "int num_shell_builtins =",
ccc6cda3 1147 "\tsizeof (static_shell_builtins) / sizeof (struct builtin) - 1;",
726f6388
JA
1148 (char *)NULL
1149};
1150
8581f42d 1151/* Write out any necessary opening information for
726f6388 1152 STRUCTFILE and EXTERNFILE. */
ccc6cda3 1153void
726f6388
JA
1154write_file_headers (structfile, externfile)
1155 FILE *structfile, *externfile;
1156{
1157 register int i;
1158
1159 if (structfile)
1160 {
1161 for (i = 0; structfile_header[i]; i++)
1162 fprintf (structfile, "%s\n", structfile_header[i]);
1163
1164 fprintf (structfile, "#include \"%s\"\n",
1165 extern_filename ? extern_filename : "builtext.h");
5e13499c
CR
1166
1167 fprintf (structfile, "#include \"bashintl.h\"\n");
1168
ccc6cda3 1169 fprintf (structfile, "\nstruct builtin static_shell_builtins[] = {\n");
726f6388
JA
1170 }
1171
1172 if (externfile)
1173 fprintf (externfile,
1174 "/* %s - The list of builtins found in libbuiltins.a. */\n",
1175 extern_filename ? extern_filename : "builtext.h");
1176}
1177
1178/* Write out any necessary closing information for
1179 STRUCTFILE and EXTERNFILE. */
ccc6cda3 1180void
726f6388
JA
1181write_file_footers (structfile, externfile)
1182 FILE *structfile, *externfile;
1183{
1184 register int i;
1185
1186 /* Write out the footers. */
1187 if (structfile)
1188 {
1189 for (i = 0; structfile_footer[i]; i++)
1190 fprintf (structfile, "%s\n", structfile_footer[i]);
1191 }
1192}
1193
1194/* Write out the information accumulated in DEFS to
1195 STRUCTFILE and EXTERNFILE. */
ccc6cda3 1196void
726f6388
JA
1197write_builtins (defs, structfile, externfile)
1198 DEF_FILE *defs;
1199 FILE *structfile, *externfile;
1200{
1201 register int i;
1202
1203 /* Write out the information. */
1204 if (defs->builtins)
1205 {
1206 register BUILTIN_DESC *builtin;
1207
1208 for (i = 0; i < defs->builtins->sindex; i++)
1209 {
1210 builtin = (BUILTIN_DESC *)defs->builtins->array[i];
1211
1212 /* Write out any #ifdefs that may be there. */
1213 if (!only_documentation)
1214 {
1215 if (builtin->dependencies)
1216 {
ccc6cda3 1217 write_ifdefs (externfile, builtin->dependencies->array);
726f6388
JA
1218 write_ifdefs (structfile, builtin->dependencies->array);
1219 }
1220
1221 /* Write the extern definition. */
1222 if (externfile)
1223 {
1224 if (builtin->function)
f73dda09 1225 fprintf (externfile, "extern int %s __P((WORD_LIST *));\n",
726f6388
JA
1226 builtin->function);
1227
7117c2d2
JA
1228 fprintf (externfile, "extern char * const %s_doc[];\n",
1229 document_name (builtin));
726f6388
JA
1230 }
1231
1232 /* Write the structure definition. */
1233 if (structfile)
1234 {
1235 fprintf (structfile, " { \"%s\", ", builtin->name);
1236
abe2eb5b 1237 if (builtin->function && inhibit_functions == 0)
726f6388
JA
1238 fprintf (structfile, "%s, ", builtin->function);
1239 else
f73dda09 1240 fprintf (structfile, "(sh_builtin_func_t *)0x0, ");
726f6388 1241
234d8729 1242 fprintf (structfile, "%s%s%s%s, %s_doc,\n",
ccc6cda3
JA
1243 "BUILTIN_ENABLED | STATIC_BUILTIN",
1244 (builtin->flags & BUILTIN_FLAG_SPECIAL) ? " | SPECIAL_BUILTIN" : "",
1245 (builtin->flags & BUILTIN_FLAG_ASSIGNMENT) ? " | ASSIGNMENT_BUILTIN" : "",
234d8729 1246 (builtin->flags & BUILTIN_FLAG_POSIX_BUILTIN) ? " | POSIX_BUILTIN" : "",
7117c2d2 1247 document_name (builtin));
726f6388 1248
abe2eb5b
CR
1249 if (inhibit_functions)
1250 fprintf
1251 (structfile, " N_(\"%s\"), \"%s\" },\n",
1252 builtin->shortdoc ? builtin->shortdoc : builtin->name,
1253 document_name (builtin));
1254 else
1255 fprintf
1256 (structfile, " N_(\"%s\"), (char *)NULL },\n",
1257 builtin->shortdoc ? builtin->shortdoc : builtin->name);
726f6388 1258
726f6388
JA
1259 }
1260
7117c2d2
JA
1261 if (structfile || separate_helpfiles)
1262 /* Save away this builtin for later writing of the
1263 long documentation strings. */
1264 save_builtin (builtin);
1265
8581f42d 1266 /* Write out the matching #endif, if necessary. */
726f6388
JA
1267 if (builtin->dependencies)
1268 {
1269 if (externfile)
1270 write_endifs (externfile, builtin->dependencies->array);
1271
1272 if (structfile)
1273 write_endifs (structfile, builtin->dependencies->array);
1274 }
1275 }
1276
1277 if (documentation_file)
1278 {
1279 fprintf (documentation_file, "@item %s\n", builtin->name);
1280 write_documentation
1281 (documentation_file, builtin->longdoc->array, 0, TEXINFO);
1282 }
1283 }
1284 }
1285}
1286
1287/* Write out the long documentation strings in BUILTINS to STREAM. */
ccc6cda3 1288void
726f6388
JA
1289write_longdocs (stream, builtins)
1290 FILE *stream;
1291 ARRAY *builtins;
1292{
1293 register int i;
1294 register BUILTIN_DESC *builtin;
7117c2d2
JA
1295 char *dname;
1296 char *sarray[2];
726f6388
JA
1297
1298 for (i = 0; i < builtins->sindex; i++)
1299 {
1300 builtin = (BUILTIN_DESC *)builtins->array[i];
1301
1302 if (builtin->dependencies)
1303 write_ifdefs (stream, builtin->dependencies->array);
1304
1305 /* Write the long documentation strings. */
7117c2d2
JA
1306 dname = document_name (builtin);
1307 fprintf (stream, "char * const %s_doc[] =", dname);
1308
1309 if (separate_helpfiles)
1310 {
1311 int l = strlen (helpfile_directory) + strlen (dname) + 1;
1312 sarray[0] = (char *)xmalloc (l + 1);
1313 sprintf (sarray[0], "%s/%s", helpfile_directory, dname);
1314 sarray[1] = (char *)NULL;
01ed5ba4 1315 write_documentation (stream, sarray, 0, STRING_ARRAY|HELPFILE);
7117c2d2
JA
1316 free (sarray[0]);
1317 }
1318 else
1319 write_documentation (stream, builtin->longdoc->array, 0, STRING_ARRAY);
726f6388
JA
1320
1321 if (builtin->dependencies)
1322 write_endifs (stream, builtin->dependencies->array);
1323
1324 }
abe2eb5b
CR
1325}
1326
1327void
1328write_dummy_declarations (stream, builtins)
1329 FILE *stream;
1330 ARRAY *builtins;
1331{
1332 register int i;
1333 BUILTIN_DESC *builtin;
1334
1335 for (i = 0; structfile_header[i]; i++)
1336 fprintf (stream, "%s\n", structfile_header[i]);
1337
1338 for (i = 0; i < builtins->sindex; i++)
1339 {
1340 builtin = (BUILTIN_DESC *)builtins->array[i];
1341
1342 /* How to guarantee that no builtin is written more than once? */
1343 fprintf (stream, "int %s () { return (0); }\n", builtin->function);
1344 }
726f6388
JA
1345}
1346
1347/* Write an #ifdef string saying what needs to be defined (or not defined)
1348 in order to allow compilation of the code that will follow.
1349 STREAM is the stream to write the information to,
1350 DEFINES is a null terminated array of define names.
1351 If a define is preceded by an `!', then the sense of the test is
1352 reversed. */
ccc6cda3 1353void
726f6388
JA
1354write_ifdefs (stream, defines)
1355 FILE *stream;
1356 char **defines;
1357{
1358 register int i;
1359
1360 if (!stream)
1361 return;
1362
1363 fprintf (stream, "#if ");
1364
1365 for (i = 0; defines[i]; i++)
1366 {
1367 char *def = defines[i];
1368
1369 if (*def == '!')
1370 fprintf (stream, "!defined (%s)", def + 1);
1371 else
1372 fprintf (stream, "defined (%s)", def);
1373
1374 if (defines[i + 1])
1375 fprintf (stream, " && ");
1376 }
1377 fprintf (stream, "\n");
1378}
1379
1380/* Write an #endif string saying what defines controlled the compilation
1381 of the immediately preceding code.
1382 STREAM is the stream to write the information to.
1383 DEFINES is a null terminated array of define names. */
ccc6cda3 1384void
726f6388
JA
1385write_endifs (stream, defines)
1386 FILE *stream;
1387 char **defines;
1388{
1389 register int i;
1390
1391 if (!stream)
1392 return;
1393
1394 fprintf (stream, "#endif /* ");
1395
1396 for (i = 0; defines[i]; i++)
1397 {
1398 fprintf (stream, "%s", defines[i]);
1399
1400 if (defines[i + 1])
1401 fprintf (stream, " && ");
1402 }
1403
1404 fprintf (stream, " */\n");
1405}
1406
01ed5ba4
CR
1407/* Write DOCUMENTATION to STREAM, perhaps surrounding it with double-quotes
1408 and quoting special characters in the string. Handle special things for
1409 internationalization (gettext) and the single-string vs. multiple-strings
1410 issues. */
ccc6cda3 1411void
726f6388
JA
1412write_documentation (stream, documentation, indentation, flags)
1413 FILE *stream;
1414 char **documentation;
1415 int indentation, flags;
1416{
1417 register int i, j;
1418 register char *line;
3d8cce26 1419 int string_array, texinfo, base_indent, filename_p;
726f6388 1420
74d9692b 1421 if (stream == 0)
726f6388
JA
1422 return;
1423
ccc6cda3 1424 string_array = flags & STRING_ARRAY;
01ed5ba4
CR
1425 filename_p = flags & HELPFILE;
1426
726f6388 1427 if (string_array)
01ed5ba4
CR
1428 {
1429 fprintf (stream, " {\n#if defined (HELP_BUILTIN)\n"); /* } */
1430 if (single_longdoc_strings)
1431 {
1432 if (filename_p == 0)
74d9692b
CR
1433 {
1434 if (documentation && documentation[0] && documentation[0][0])
1435 fprintf (stream, "N_(\"");
1436 else
1437 fprintf (stream, "N_(\" "); /* the empty string translates specially. */
1438 }
01ed5ba4
CR
1439 else
1440 fprintf (stream, "\"");
1441 }
1442 }
1443
1444 base_indent = (string_array && single_longdoc_strings && filename_p == 0) ? BASE_INDENT : 0;
726f6388 1445
631b20c6 1446 for (i = 0, texinfo = (flags & TEXINFO); documentation && (line = documentation[i]); i++)
726f6388 1447 {
01ed5ba4
CR
1448 /* Allow #ifdef's to be written out verbatim, but don't put them into
1449 separate help files. */
726f6388
JA
1450 if (*line == '#')
1451 {
01ed5ba4 1452 if (string_array && filename_p == 0 && single_longdoc_strings == 0)
726f6388
JA
1453 fprintf (stream, "%s\n", line);
1454 continue;
1455 }
1456
5e13499c 1457 /* prefix with N_( for gettext */
01ed5ba4
CR
1458 if (string_array && single_longdoc_strings == 0)
1459 {
1460 if (filename_p == 0)
74d9692b
CR
1461 {
1462 if (line[0])
1463 fprintf (stream, " N_(\"");
1464 else
1465 fprintf (stream, " N_(\" "); /* the empty string translates specially. */
1466 }
01ed5ba4
CR
1467 else
1468 fprintf (stream, " \"");
1469 }
726f6388
JA
1470
1471 if (indentation)
1472 for (j = 0; j < indentation; j++)
1473 fprintf (stream, " ");
1474
01ed5ba4
CR
1475 /* Don't indent the first line, because of how the help builtin works. */
1476 if (i == 0)
1477 indentation += base_indent;
1478
726f6388
JA
1479 if (string_array)
1480 {
1481 for (j = 0; line[j]; j++)
1482 {
1483 switch (line[j])
1484 {
1485 case '\\':
1486 case '"':
1487 fprintf (stream, "\\%c", line[j]);
1488 break;
1489
1490 default:
1491 fprintf (stream, "%c", line[j]);
1492 }
1493 }
1494
5e13499c 1495 /* closing right paren for gettext */
01ed5ba4
CR
1496 if (single_longdoc_strings == 0)
1497 {
1498 if (filename_p == 0)
1499 fprintf (stream, "\"),\n");
1500 else
1501 fprintf (stream, "\",\n");
1502 }
1503 else if (documentation[i+1])
1504 /* don't add extra newline after last line */
1505 fprintf (stream, "\\n\\\n");
726f6388
JA
1506 }
1507 else if (texinfo)
1508 {
1509 for (j = 0; line[j]; j++)
1510 {
1511 switch (line[j])
1512 {
1513 case '@':
1514 case '{':
1515 case '}':
1516 fprintf (stream, "@%c", line[j]);
1517 break;
1518
1519 default:
1520 fprintf (stream, "%c", line[j]);
1521 }
1522 }
1523 fprintf (stream, "\n");
1524 }
1525 else
1526 fprintf (stream, "%s\n", line);
1527 }
1528
01ed5ba4
CR
1529 /* closing right paren for gettext */
1530 if (string_array && single_longdoc_strings)
1531 {
1532 if (filename_p == 0)
1533 fprintf (stream, "\"),\n");
1534 else
1535 fprintf (stream, "\",\n");
1536 }
1537
726f6388 1538 if (string_array)
ccc6cda3 1539 fprintf (stream, "#endif /* HELP_BUILTIN */\n (char *)NULL\n};\n");
726f6388
JA
1540}
1541
7117c2d2
JA
1542int
1543write_helpfiles (builtins)
1544 ARRAY *builtins;
1545{
1546 char *helpfile, *bname;
1547 FILE *helpfp;
1548 int i, hdlen;
1549 BUILTIN_DESC *builtin;
1550
1551 i = mkdir ("helpfiles", 0777);
1552 if (i < 0 && errno != EEXIST)
1553 {
1554 fprintf (stderr, "write_helpfiles: helpfiles: cannot create directory\n");
1555 return -1;
1556 }
1557
1558 hdlen = strlen ("helpfiles/");
1559 for (i = 0; i < builtins->sindex; i++)
1560 {
1561 builtin = (BUILTIN_DESC *)builtins->array[i];
1562
1563 bname = document_name (builtin);
1564 helpfile = (char *)xmalloc (hdlen + strlen (bname) + 1);
1565 sprintf (helpfile, "helpfiles/%s", bname);
1566
1567 helpfp = fopen (helpfile, "w");
1568 if (helpfp == 0)
1569 {
1570 fprintf (stderr, "write_helpfiles: cannot open %s\n", helpfile);
1571 free (helpfile);
1572 continue;
1573 }
1574
1575 write_documentation (helpfp, builtin->longdoc->array, 4, PLAINTEXT);
1576
1577 fflush (helpfp);
1578 fclose (helpfp);
1579 free (helpfile);
1580 }
1581 return 0;
1582}
1583
726f6388 1584static int
ccc6cda3
JA
1585_find_in_table (name, name_table)
1586 char *name, *name_table[];
726f6388
JA
1587{
1588 register int i;
1589
ccc6cda3
JA
1590 for (i = 0; name_table[i]; i++)
1591 if (strcmp (name, name_table[i]) == 0)
726f6388
JA
1592 return 1;
1593 return 0;
1594}
ccc6cda3
JA
1595
1596static int
1597is_special_builtin (name)
1598 char *name;
1599{
1600 return (_find_in_table (name, special_builtins));
1601}
1602
1603static int
1604is_assignment_builtin (name)
1605 char *name;
1606{
1607 return (_find_in_table (name, assignment_builtins));
1608}
b72432fd 1609
234d8729
CR
1610static int
1611is_posix_builtin (name)
1612 char *name;
1613{
1614 return (_find_in_table (name, posix_builtins));
1615}
1616
b72432fd
JA
1617#if !defined (HAVE_RENAME)
1618static int
1619rename (from, to)
1620 char *from, *to;
1621{
1622 unlink (to);
1623 if (link (from, to) < 0)
1624 return (-1);
1625 unlink (from);
1626 return (0);
1627}
1628#endif /* !HAVE_RENAME */