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