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