| 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 */
|
|---|