]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/mkbuiltins.c
Imported from ../bash-2.02.tar.gz.
[thirdparty/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 }