📄 mkbuiltins.c
字号:
/* mkbuiltins.c - Create builtins.c, builtext.h, and builtdoc.c from a single source file called builtins.def. *//* Copyright (C) 1987-2010 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. Bash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Bash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bash. If not, see <http://www.gnu.org/licenses/>.*/#if !defined (CROSS_COMPILING) # include <config.h>#else /* CROSS_COMPILING *//* A conservative set of defines based on POSIX/SUS3/XPG6 */# define HAVE_UNISTD_H# define HAVE_STRING_H# define HAVE_STDLIB_H# define HAVE_RENAME#endif /* CROSS_COMPILING */#if defined (HAVE_UNISTD_H)# ifdef _MINIX# include <sys/types.h># endif# include <unistd.h>#endif#ifndef _MINIX# include "../bashtypes.h"# if defined (HAVE_SYS_FILE_H)# include <sys/file.h># endif#endif#include "posixstat.h"#include "filecntl.h"#include "../bashansi.h"#include <stdio.h>#include <errno.h>#include "stdc.h"#define DOCFILE "builtins.texi"#ifndef errnoextern int errno;#endifstatic char *xmalloc (), *xrealloc ();#if !defined (__STDC__) && !defined (strcpy)extern char *strcpy ();#endif /* !__STDC__ && !strcpy */#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))#define whitespace(c) (((c) == ' ') || ((c) == '\t'))/* Flag values that builtins can have. */#define BUILTIN_FLAG_SPECIAL 0x01#define BUILTIN_FLAG_ASSIGNMENT 0x02#define BUILTIN_FLAG_POSIX_BUILTIN 0x04#define BASE_INDENT 4/* If this stream descriptor is non-zero, then write texinfo documentation to it. */FILE *documentation_file = (FILE *)NULL;/* Non-zero means to only produce documentation. */int only_documentation = 0;/* Non-zero means to not do any productions. */int inhibit_production = 0;/* Non-zero means to produce separate help files for each builtin, named by the builtin name, in `./helpfiles'. */int separate_helpfiles = 0;/* Non-zero means to create single C strings for each `longdoc', with embedded newlines, for ease of translation. */int single_longdoc_strings = 1;/* The name of a directory into which the separate external help files will eventually be installed. */char *helpfile_directory;/* The name of a directory to precede the filename when reporting errors. */char *error_directory = (char *)NULL;/* The name of the structure file. */char *struct_filename = (char *)NULL;/* The name of the external declaration file. */char *extern_filename = (char *)NULL;/* Here is a structure for manipulating arrays of data. */typedef struct { int size; /* Number of slots allocated to array. */ int sindex; /* Current location in array. */ int width; /* Size of each element. */ int growth_rate; /* How fast to grow. */ char **array; /* The array itself. */} ARRAY;/* Here is a structure defining a single BUILTIN. */typedef struct { char *name; /* The name of this builtin. */ char *function; /* The name of the function to call. */ char *shortdoc; /* The short documentation for this builtin. */ char *docname; /* Possible name for documentation string. */ ARRAY *longdoc; /* The long documentation for this builtin. */ ARRAY *dependencies; /* Null terminated array of #define names. */ int flags; /* Flags for this builtin. */} BUILTIN_DESC;/* Here is a structure which defines a DEF file. */typedef struct { char *filename; /* The name of the input def file. */ ARRAY *lines; /* The contents of the file. */ int line_number; /* The current line number. */ char *production; /* The name of the production file. */ FILE *output; /* Open file stream for PRODUCTION. */ ARRAY *builtins; /* Null terminated array of BUILTIN_DESC *. */} DEF_FILE;/* The array of all builtins encountered during execution of this code. */ARRAY *saved_builtins = (ARRAY *)NULL;/* The Posix.2 so-called `special' builtins. */char *special_builtins[] ={ ":", ".", "source", "break", "continue", "eval", "exec", "exit", "export", "readonly", "return", "set", "shift", "times", "trap", "unset", (char *)NULL};/* The builtin commands that take assignment statements as arguments. */char *assignment_builtins[] ={ "alias", "declare", "export", "local", "readonly", "typeset", (char *)NULL};/* The builtin commands that are special to the POSIX search order. */char *posix_builtins[] ={ "alias", "bg", "cd", "command", "false", "fc", "fg", "getopts", "jobs", "kill", "newgrp", "pwd", "read", "true", "umask", "unalias", "wait", (char *)NULL};/* Forward declarations. */static int is_special_builtin ();static int is_assignment_builtin ();static int is_posix_builtin ();#if !defined (HAVE_RENAME)static int rename ();#endifvoid extract_info ();void file_error ();void line_error ();void write_file_headers ();void write_file_footers ();void write_ifdefs ();void write_endifs ();void write_documentation ();void write_longdocs ();void write_builtins ();int write_helpfiles ();void free_defs ();void add_documentation ();void must_be_building ();void remove_trailing_whitespace ();#define document_name(b) ((b)->docname ? (b)->docname : (b)->name)/* For each file mentioned on the command line, process it and write the information to STRUCTFILE and EXTERNFILE, while creating the production file if neccessary. */intmain (argc, argv) int argc; char **argv;{ int arg_index = 1; FILE *structfile, *externfile; char *documentation_filename, *temp_struct_filename; structfile = externfile = (FILE *)NULL; documentation_filename = DOCFILE; temp_struct_filename = (char *)NULL; while (arg_index < argc && argv[arg_index][0] == '-') { char *arg = argv[arg_index++]; if (strcmp (arg, "-externfile") == 0) extern_filename = argv[arg_index++]; else if (strcmp (arg, "-structfile") == 0) struct_filename = argv[arg_index++]; else if (strcmp (arg, "-noproduction") == 0) inhibit_production = 1; else if (strcmp (arg, "-document") == 0) documentation_file = fopen (documentation_filename, "w"); else if (strcmp (arg, "-D") == 0) { int len; if (error_directory) free (error_directory); error_directory = xmalloc (2 + strlen (argv[arg_index])); strcpy (error_directory, argv[arg_index]); len = strlen (error_directory); if (len && error_directory[len - 1] != '/') strcat (error_directory, "/"); arg_index++; } else if (strcmp (arg, "-documentonly") == 0) { only_documentation = 1; documentation_file = fopen (documentation_filename, "w"); } else if (strcmp (arg, "-H") == 0) { separate_helpfiles = 1; helpfile_directory = argv[arg_index++]; } else if (strcmp (arg, "-S") == 0) single_longdoc_strings = 0; else { fprintf (stderr, "%s: Unknown flag %s.\n", argv[0], arg); exit (2); } } /* If there are no files to process, just quit now. */ if (arg_index == argc) exit (0); if (!only_documentation) { /* Open the files. */ if (struct_filename) { temp_struct_filename = xmalloc (15); sprintf (temp_struct_filename, "mk-%ld", (long) getpid ()); structfile = fopen (temp_struct_filename, "w"); if (!structfile) file_error (temp_struct_filename); } if (extern_filename) { externfile = fopen (extern_filename, "w"); if (!externfile) file_error (extern_filename); } /* Write out the headers. */ write_file_headers (structfile, externfile); } if (documentation_file) { fprintf (documentation_file, "@c Table of builtins created with %s.\n", argv[0]); fprintf (documentation_file, "@ftable @asis\n"); } /* Process the .def files. */ while (arg_index < argc) { register char *arg; arg = argv[arg_index++]; extract_info (arg, structfile, externfile); } /* Close the files. */ if (!only_documentation) { /* Write the footers. */ write_file_footers (structfile, externfile); if (structfile) { write_longdocs (structfile, saved_builtins); fclose (structfile); rename (temp_struct_filename, struct_filename); } if (externfile) fclose (externfile); } if (separate_helpfiles) { write_helpfiles (saved_builtins); } if (documentation_file) { fprintf (documentation_file, "@end ftable\n"); fclose (documentation_file); } exit (0);}/* **************************************************************** *//* *//* Array Functions and Manipulators *//* *//* **************************************************************** *//* Make a new array, and return a pointer to it. The array will contain elements of size WIDTH, and is initialized to no elements. */ARRAY *array_create (width) int width;{ ARRAY *array; array = (ARRAY *)xmalloc (sizeof (ARRAY)); array->size = 0; array->sindex = 0; array->width = width; /* Default to increasing size in units of 20. */ array->growth_rate = 20; array->array = (char **)NULL; return (array);}/* Copy the array of strings in ARRAY. */ARRAY *copy_string_array (array) ARRAY *array;{ register int i; ARRAY *copy; if (!array) return (ARRAY *)NULL; copy = array_create (sizeof (char *)); copy->size = array->size; copy->sindex = array->sindex; copy->width = array->width; copy->array = (char **)xmalloc ((1 + array->sindex) * sizeof (char *)); for (i = 0; i < array->sindex; i++) copy->array[i] = savestring (array->array[i]); copy->array[i] = (char *)NULL; return (copy);}/* Add ELEMENT to ARRAY, growing the array if neccessary. */voidarray_add (element, array) char *element; ARRAY *array;{ if (array->sindex + 2 > array->size) array->array = (char **)xrealloc (array->array, (array->size += array->growth_rate) * array->width); array->array[array->sindex++] = element; array->array[array->sindex] = (char *)NULL;}/* Free an allocated array and data pointer. */voidarray_free (array) ARRAY *array;{ if (array->array) free (array->array); free (array);}/* **************************************************************** *//* *//* Processing a DEF File *//* *//* **************************************************************** *//* The definition of a function. */typedef int Function ();typedef int mk_handler_func_t __P((char *, DEF_FILE *, char *));/* Structure handles processor directives. */typedef struct { char *directive; mk_handler_func_t *function;} HANDLER_ENTRY;extern int builtin_handler __P((char *, DEF_FILE *, char *));extern int function_handler __P((char *, DEF_FILE *, char *));extern int short_doc_handler __P((char *, DEF_FILE *, char *));extern int comment_handler __P((char *, DEF_FILE *, char *));extern int depends_on_handler __P((char *, DEF_FILE *, char *));extern int produces_handler __P((char *, DEF_FILE *, char *));extern int end_handler __P((char *, DEF_FILE *, char *));extern int docname_handler __P((char *, DEF_FILE *, char *));HANDLER_ENTRY handlers[] = { { "BUILTIN", builtin_handler }, { "DOCNAME", docname_handler }, { "FUNCTION", function_handler }, { "SHORT_DOC", short_doc_handler }, { "$", comment_handler }, { "COMMENT", comment_handler }, { "DEPENDS_ON", depends_on_handler }, { "PRODUCES", produces_handler }, { "END", end_handler }, { (char *)NULL, (mk_handler_func_t *)NULL }};/* Return the entry in the table of handlers for NAME. */HANDLER_ENTRY *find_directive (directive) char *directive;{ register int i; for (i = 0; handlers[i].directive; i++) if (strcmp (handlers[i].directive, directive) == 0) return (&handlers[i]); return ((HANDLER_ENTRY *)NULL);}/* Non-zero indicates that a $BUILTIN has been seen, but not the corresponding $END. */static int building_builtin = 0;/* Non-zero means to output cpp line and file information before printing the current line to the production file. */int output_cpp_line_info = 0;/* The main function of this program. Read FILENAME and act on what is found. Lines not starting with a dollar sign are copied to the $PRODUCES target, if one is present. Lines starting with a dollar sign are directives to this program, specifying the name of the builtin, the function to call, the short documentation and the long documentation strings. FILENAME can contain multiple $BUILTINs, but only one $PRODUCES target. After the file has been processed, write out the names of builtins found in each $BUILTIN. Plain text found before the $PRODUCES is ignored, as is "$$ comment text". */voidextract_info (filename, structfile, externfile) char *filename; FILE *structfile, *externfile;{ register int i; DEF_FILE *defs; struct stat finfo; size_t file_size; char *buffer, *line; int fd, nr; if (stat (filename, &finfo) == -1) file_error (filename); fd = open (filename, O_RDONLY, 0666); if (fd == -1) file_error (filename); file_size = (size_t)finfo.st_size; buffer = xmalloc (1 + file_size); if ((nr = read (fd, buffer, file_size)) < 0) file_error (filename); /* This is needed on WIN32, and does not hurt on Unix. */ if (nr < file_size) file_size = nr; close (fd); if (nr == 0) { fprintf (stderr, "mkbuiltins: %s: skipping zero-length file\n", filename); return; } /* Create and fill in the initial structure describing this file. */ defs = (DEF_FILE *)xmalloc (sizeof (DEF_FILE)); defs->filename = filename; defs->lines = array_create (sizeof (char *)); defs->line_number = 0; defs->production = (char *)NULL; defs->output = (FILE *)NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -