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