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