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