1996-08-26 18:22:31 +00:00
|
|
|
|
/* mkbuiltins.c - Create builtins.c, builtext.h, and builtdoc.c from
|
|
|
|
|
a single source file called builtins.def. */
|
|
|
|
|
|
2016-09-15 16:59:08 -04:00
|
|
|
|
/* Copyright (C) 1987-2016 Free Software Foundation, Inc.
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2009-01-12 13:36:28 +00:00
|
|
|
|
This file is part of GNU Bash, the Bourne Again SHell.
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2009-01-12 13:36:28 +00:00
|
|
|
|
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.
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2009-01-12 13:36:28 +00:00
|
|
|
|
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.
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2009-01-12 13:36:28 +00:00
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2006-10-10 14:15:34 +00:00
|
|
|
|
#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 */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
|
|
|
|
|
#if defined (HAVE_UNISTD_H)
|
1998-04-17 19:52:44 +00:00
|
|
|
|
# ifdef _MINIX
|
|
|
|
|
# include <sys/types.h>
|
|
|
|
|
# endif
|
1996-12-23 17:02:34 +00:00
|
|
|
|
# include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
1998-04-17 19:52:44 +00:00
|
|
|
|
#ifndef _MINIX
|
2004-07-27 13:29:18 +00:00
|
|
|
|
# include "../bashtypes.h"
|
|
|
|
|
# if defined (HAVE_SYS_FILE_H)
|
|
|
|
|
# include <sys/file.h>
|
|
|
|
|
# endif
|
1998-04-17 19:52:44 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2000-03-17 21:46:59 +00:00
|
|
|
|
#include "posixstat.h"
|
|
|
|
|
#include "filecntl.h"
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
1997-06-05 14:59:13 +00:00
|
|
|
|
#include "../bashansi.h"
|
|
|
|
|
#include <stdio.h>
|
2002-07-17 14:10:11 +00:00
|
|
|
|
#include <errno.h>
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2001-11-13 17:56:06 +00:00
|
|
|
|
#include "stdc.h"
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
#define DOCFILE "builtins.texi"
|
|
|
|
|
|
2002-07-17 14:10:11 +00:00
|
|
|
|
#ifndef errno
|
|
|
|
|
extern int errno;
|
|
|
|
|
#endif
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
static 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
|
1996-12-23 17:02:34 +00:00
|
|
|
|
#define BUILTIN_FLAG_ASSIGNMENT 0x02
|
2016-09-15 16:59:08 -04:00
|
|
|
|
#define BUILTIN_FLAG_LOCALVAR 0x04
|
|
|
|
|
#define BUILTIN_FLAG_POSIX_BUILTIN 0x08
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2005-12-07 14:08:12 +00:00
|
|
|
|
#define BASE_INDENT 4
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
/* 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;
|
|
|
|
|
|
2014-02-26 09:36:43 -05:00
|
|
|
|
/* Non-zero means to not add functions (xxx_builtin) to the members of the
|
|
|
|
|
produced `struct builtin []' */
|
|
|
|
|
int inhibit_functions = 0;
|
|
|
|
|
|
2002-07-17 14:10:11 +00:00
|
|
|
|
/* Non-zero means to produce separate help files for each builtin, named by
|
|
|
|
|
the builtin name, in `./helpfiles'. */
|
|
|
|
|
int separate_helpfiles = 0;
|
|
|
|
|
|
2005-12-07 14:08:12 +00:00
|
|
|
|
/* Non-zero means to create single C strings for each `longdoc', with
|
|
|
|
|
embedded newlines, for ease of translation. */
|
|
|
|
|
int single_longdoc_strings = 1;
|
|
|
|
|
|
2002-07-17 14:10:11 +00:00
|
|
|
|
/* The name of a directory into which the separate external help files will
|
|
|
|
|
eventually be installed. */
|
|
|
|
|
char *helpfile_directory;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
/* 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",
|
2005-12-07 14:08:12 +00:00
|
|
|
|
"export", "readonly", "return", "set", "shift", "times", "trap", "unset",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
(char *)NULL
|
|
|
|
|
};
|
1996-12-23 17:02:34 +00:00
|
|
|
|
|
|
|
|
|
/* The builtin commands that take assignment statements as arguments. */
|
|
|
|
|
char *assignment_builtins[] =
|
|
|
|
|
{
|
|
|
|
|
"alias", "declare", "export", "local", "readonly", "typeset",
|
|
|
|
|
(char *)NULL
|
|
|
|
|
};
|
|
|
|
|
|
2016-09-15 16:59:08 -04:00
|
|
|
|
char *localvar_builtins[] =
|
|
|
|
|
{
|
|
|
|
|
"declare", "local", "typeset", (char *)NULL
|
|
|
|
|
};
|
|
|
|
|
|
2009-01-12 13:36:28 +00:00
|
|
|
|
/* 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
|
|
|
|
|
};
|
|
|
|
|
|
1996-12-23 17:02:34 +00:00
|
|
|
|
/* Forward declarations. */
|
1996-08-26 18:22:31 +00:00
|
|
|
|
static int is_special_builtin ();
|
1996-12-23 17:02:34 +00:00
|
|
|
|
static int is_assignment_builtin ();
|
2016-09-15 16:59:08 -04:00
|
|
|
|
static int is_localvar_builtin ();
|
2009-01-12 13:36:28 +00:00
|
|
|
|
static int is_posix_builtin ();
|
1996-12-23 17:02:34 +00:00
|
|
|
|
|
1999-02-19 17:11:39 +00:00
|
|
|
|
#if !defined (HAVE_RENAME)
|
|
|
|
|
static int rename ();
|
|
|
|
|
#endif
|
|
|
|
|
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void 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 ();
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2002-07-17 14:10:11 +00:00
|
|
|
|
int write_helpfiles ();
|
|
|
|
|
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void free_defs ();
|
|
|
|
|
void add_documentation ();
|
|
|
|
|
|
|
|
|
|
void must_be_building ();
|
|
|
|
|
void remove_trailing_whitespace ();
|
2002-07-17 14:10:11 +00:00
|
|
|
|
|
|
|
|
|
#define document_name(b) ((b)->docname ? (b)->docname : (b)->name)
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
/* For each file mentioned on the command line, process it and
|
|
|
|
|
write the information to STRUCTFILE and EXTERNFILE, while
|
2014-02-26 09:36:43 -05:00
|
|
|
|
creating the production file if necessary. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
int
|
1996-08-26 18:22:31 +00:00
|
|
|
|
main (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;
|
2014-02-26 09:36:43 -05:00
|
|
|
|
else if (strcmp (arg, "-nofunctions") == 0)
|
|
|
|
|
inhibit_functions = 1;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
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");
|
|
|
|
|
}
|
2002-07-17 14:10:11 +00:00
|
|
|
|
else if (strcmp (arg, "-H") == 0)
|
|
|
|
|
{
|
|
|
|
|
separate_helpfiles = 1;
|
|
|
|
|
helpfile_directory = argv[arg_index++];
|
|
|
|
|
}
|
2005-12-07 14:08:12 +00:00
|
|
|
|
else if (strcmp (arg, "-S") == 0)
|
|
|
|
|
single_longdoc_strings = 0;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
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);
|
2001-11-13 17:56:06 +00:00
|
|
|
|
sprintf (temp_struct_filename, "mk-%ld", (long) getpid ());
|
1996-08-26 18:22:31 +00:00
|
|
|
|
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);
|
1999-02-19 17:11:39 +00:00
|
|
|
|
rename (temp_struct_filename, struct_filename);
|
1996-08-26 18:22:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (externfile)
|
|
|
|
|
fclose (externfile);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-26 09:36:43 -05:00
|
|
|
|
#if 0
|
|
|
|
|
/* This is now done by a different program */
|
2002-07-17 14:10:11 +00:00
|
|
|
|
if (separate_helpfiles)
|
|
|
|
|
{
|
|
|
|
|
write_helpfiles (saved_builtins);
|
|
|
|
|
}
|
2014-02-26 09:36:43 -05:00
|
|
|
|
#endif
|
2002-07-17 14:10:11 +00:00
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-26 09:36:43 -05:00
|
|
|
|
/* Add ELEMENT to ARRAY, growing the array if necessary. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
array_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. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
array_free (array)
|
|
|
|
|
ARRAY *array;
|
|
|
|
|
{
|
|
|
|
|
if (array->array)
|
|
|
|
|
free (array->array);
|
|
|
|
|
|
|
|
|
|
free (array);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
/* */
|
|
|
|
|
/* Processing a DEF File */
|
|
|
|
|
/* */
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
|
|
|
|
|
/* The definition of a function. */
|
|
|
|
|
typedef int Function ();
|
2001-11-13 17:56:06 +00:00
|
|
|
|
typedef int mk_handler_func_t __P((char *, DEF_FILE *, char *));
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
/* Structure handles processor directives. */
|
|
|
|
|
typedef struct {
|
|
|
|
|
char *directive;
|
2001-11-13 17:56:06 +00:00
|
|
|
|
mk_handler_func_t *function;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
} HANDLER_ENTRY;
|
|
|
|
|
|
2001-11-13 17:56:06 +00:00
|
|
|
|
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 *));
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
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 },
|
2001-11-13 17:56:06 +00:00
|
|
|
|
{ (char *)NULL, (mk_handler_func_t *)NULL }
|
1996-08-26 18:22:31 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* 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". */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
extract_info (filename, structfile, externfile)
|
|
|
|
|
char *filename;
|
|
|
|
|
FILE *structfile, *externfile;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
DEF_FILE *defs;
|
|
|
|
|
struct stat finfo;
|
1998-04-17 19:52:44 +00:00
|
|
|
|
size_t file_size;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
char *buffer, *line;
|
1998-04-17 19:52:44 +00:00
|
|
|
|
int fd, nr;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
if (stat (filename, &finfo) == -1)
|
|
|
|
|
file_error (filename);
|
|
|
|
|
|
|
|
|
|
fd = open (filename, O_RDONLY, 0666);
|
|
|
|
|
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
file_error (filename);
|
|
|
|
|
|
1998-04-17 19:52:44 +00:00
|
|
|
|
file_size = (size_t)finfo.st_size;
|
|
|
|
|
buffer = xmalloc (1 + file_size);
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
1998-04-17 19:52:44 +00:00
|
|
|
|
if ((nr = read (fd, buffer, file_size)) < 0)
|
1996-08-26 18:22:31 +00:00
|
|
|
|
file_error (filename);
|
|
|
|
|
|
1999-02-19 17:11:39 +00:00
|
|
|
|
/* This is needed on WIN32, and does not hurt on Unix. */
|
|
|
|
|
if (nr < file_size)
|
|
|
|
|
file_size = nr;
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
close (fd);
|
|
|
|
|
|
1998-04-17 19:52:44 +00:00
|
|
|
|
if (nr == 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "mkbuiltins: %s: skipping zero-length file\n", filename);
|
2014-02-26 09:36:43 -05:00
|
|
|
|
free (buffer);
|
1998-04-17 19:52:44 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
/* 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;
|
|
|
|
|
defs->builtins = (ARRAY *)NULL;
|
|
|
|
|
|
|
|
|
|
/* Build the array of lines. */
|
|
|
|
|
i = 0;
|
1998-04-17 19:52:44 +00:00
|
|
|
|
while (i < file_size)
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
|
|
|
|
array_add (&buffer[i], defs->lines);
|
|
|
|
|
|
2014-02-26 09:36:43 -05:00
|
|
|
|
while (i < file_size && buffer[i] != '\n')
|
1996-08-26 18:22:31 +00:00
|
|
|
|
i++;
|
|
|
|
|
buffer[i++] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Begin processing the input file. We don't write any output
|
|
|
|
|
until we have a file to write output to. */
|
|
|
|
|
output_cpp_line_info = 1;
|
|
|
|
|
|
|
|
|
|
/* Process each line in the array. */
|
|
|
|
|
for (i = 0; line = defs->lines->array[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
defs->line_number = i;
|
|
|
|
|
|
|
|
|
|
if (*line == '$')
|
|
|
|
|
{
|
|
|
|
|
register int j;
|
|
|
|
|
char *directive;
|
|
|
|
|
HANDLER_ENTRY *handler;
|
|
|
|
|
|
|
|
|
|
/* Isolate the directive. */
|
|
|
|
|
for (j = 0; line[j] && !whitespace (line[j]); j++);
|
|
|
|
|
|
|
|
|
|
directive = xmalloc (j);
|
|
|
|
|
strncpy (directive, line + 1, j - 1);
|
|
|
|
|
directive[j -1] = '\0';
|
|
|
|
|
|
|
|
|
|
/* Get the function handler and call it. */
|
|
|
|
|
handler = find_directive (directive);
|
|
|
|
|
|
|
|
|
|
if (!handler)
|
|
|
|
|
{
|
|
|
|
|
line_error (defs, "Unknown directive `%s'", directive);
|
|
|
|
|
free (directive);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Advance to the first non-whitespace character. */
|
|
|
|
|
while (whitespace (line[j]))
|
|
|
|
|
j++;
|
|
|
|
|
|
|
|
|
|
/* Call the directive handler with the FILE, and ARGS. */
|
|
|
|
|
(*(handler->function)) (directive, defs, line + j);
|
|
|
|
|
}
|
|
|
|
|
free (directive);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (building_builtin)
|
|
|
|
|
add_documentation (defs, line);
|
|
|
|
|
else if (defs->output)
|
|
|
|
|
{
|
|
|
|
|
if (output_cpp_line_info)
|
|
|
|
|
{
|
|
|
|
|
/* If we're handed an absolute pathname, don't prepend
|
|
|
|
|
the directory name. */
|
|
|
|
|
if (defs->filename[0] == '/')
|
|
|
|
|
fprintf (defs->output, "#line %d \"%s\"\n",
|
|
|
|
|
defs->line_number + 1, defs->filename);
|
|
|
|
|
else
|
|
|
|
|
fprintf (defs->output, "#line %d \"%s%s\"\n",
|
|
|
|
|
defs->line_number + 1,
|
|
|
|
|
error_directory ? error_directory : "./",
|
|
|
|
|
defs->filename);
|
|
|
|
|
output_cpp_line_info = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (defs->output, "%s\n", line);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Close the production file. */
|
|
|
|
|
if (defs->output)
|
|
|
|
|
fclose (defs->output);
|
|
|
|
|
|
|
|
|
|
/* The file has been processed. Write the accumulated builtins to
|
|
|
|
|
the builtins.c file, and write the extern definitions to the
|
|
|
|
|
builtext.h file. */
|
|
|
|
|
write_builtins (defs, structfile, externfile);
|
|
|
|
|
|
|
|
|
|
free (buffer);
|
|
|
|
|
free_defs (defs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define free_safely(x) if (x) free (x)
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
free_builtin (builtin)
|
|
|
|
|
BUILTIN_DESC *builtin;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
|
|
|
|
|
free_safely (builtin->name);
|
|
|
|
|
free_safely (builtin->function);
|
|
|
|
|
free_safely (builtin->shortdoc);
|
|
|
|
|
free_safely (builtin->docname);
|
|
|
|
|
|
|
|
|
|
if (builtin->longdoc)
|
|
|
|
|
array_free (builtin->longdoc);
|
|
|
|
|
|
|
|
|
|
if (builtin->dependencies)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; builtin->dependencies->array[i]; i++)
|
|
|
|
|
free (builtin->dependencies->array[i]);
|
|
|
|
|
array_free (builtin->dependencies);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free all of the memory allocated to a DEF_FILE. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
free_defs (defs)
|
|
|
|
|
DEF_FILE *defs;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
register BUILTIN_DESC *builtin;
|
|
|
|
|
|
|
|
|
|
if (defs->production)
|
|
|
|
|
free (defs->production);
|
|
|
|
|
|
|
|
|
|
if (defs->lines)
|
|
|
|
|
array_free (defs->lines);
|
|
|
|
|
|
|
|
|
|
if (defs->builtins)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; builtin = (BUILTIN_DESC *)defs->builtins->array[i]; i++)
|
2001-04-06 19:14:31 +00:00
|
|
|
|
{
|
1996-08-26 18:22:31 +00:00
|
|
|
|
free_builtin (builtin);
|
|
|
|
|
free (builtin);
|
2001-04-06 19:14:31 +00:00
|
|
|
|
}
|
1996-08-26 18:22:31 +00:00
|
|
|
|
array_free (defs->builtins);
|
|
|
|
|
}
|
|
|
|
|
free (defs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
/* */
|
|
|
|
|
/* The Handler Functions Themselves */
|
|
|
|
|
/* */
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
|
|
|
|
|
/* Strip surrounding whitespace from STRING, and
|
|
|
|
|
return a pointer to the start of it. */
|
|
|
|
|
char *
|
|
|
|
|
strip_whitespace (string)
|
|
|
|
|
char *string;
|
|
|
|
|
{
|
|
|
|
|
while (whitespace (*string))
|
|
|
|
|
string++;
|
|
|
|
|
|
|
|
|
|
remove_trailing_whitespace (string);
|
|
|
|
|
return (string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remove only the trailing whitespace from STRING. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
remove_trailing_whitespace (string)
|
|
|
|
|
char *string;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
|
|
|
|
|
i = strlen (string) - 1;
|
|
|
|
|
|
|
|
|
|
while (i > 0 && whitespace (string[i]))
|
|
|
|
|
i--;
|
|
|
|
|
|
|
|
|
|
string[++i] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ensure that there is a argument in STRING and return it.
|
|
|
|
|
FOR_WHOM is the name of the directive which needs the argument.
|
|
|
|
|
DEFS is the DEF_FILE in which the directive is found.
|
|
|
|
|
If there is no argument, produce an error. */
|
|
|
|
|
char *
|
|
|
|
|
get_arg (for_whom, defs, string)
|
|
|
|
|
char *for_whom, *string;
|
|
|
|
|
DEF_FILE *defs;
|
|
|
|
|
{
|
|
|
|
|
char *new;
|
|
|
|
|
|
|
|
|
|
new = strip_whitespace (string);
|
|
|
|
|
|
|
|
|
|
if (!*new)
|
|
|
|
|
line_error (defs, "%s requires an argument", for_whom);
|
|
|
|
|
|
|
|
|
|
return (savestring (new));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Error if not building a builtin. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
must_be_building (directive, defs)
|
|
|
|
|
char *directive;
|
|
|
|
|
DEF_FILE *defs;
|
|
|
|
|
{
|
|
|
|
|
if (!building_builtin)
|
|
|
|
|
line_error (defs, "%s must be inside of a $BUILTIN block", directive);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the current builtin. */
|
|
|
|
|
BUILTIN_DESC *
|
|
|
|
|
current_builtin (directive, defs)
|
|
|
|
|
char *directive;
|
|
|
|
|
DEF_FILE *defs;
|
|
|
|
|
{
|
|
|
|
|
must_be_building (directive, defs);
|
1998-04-17 19:52:44 +00:00
|
|
|
|
if (defs->builtins)
|
|
|
|
|
return ((BUILTIN_DESC *)defs->builtins->array[defs->builtins->sindex - 1]);
|
|
|
|
|
else
|
|
|
|
|
return ((BUILTIN_DESC *)NULL);
|
1996-08-26 18:22:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add LINE to the long documentation for the current builtin.
|
|
|
|
|
Ignore blank lines until the first non-blank line has been seen. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
add_documentation (defs, line)
|
|
|
|
|
DEF_FILE *defs;
|
|
|
|
|
char *line;
|
|
|
|
|
{
|
|
|
|
|
register BUILTIN_DESC *builtin;
|
|
|
|
|
|
|
|
|
|
builtin = current_builtin ("(implied LONGDOC)", defs);
|
|
|
|
|
|
|
|
|
|
remove_trailing_whitespace (line);
|
|
|
|
|
|
|
|
|
|
if (!*line && !builtin->longdoc)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!builtin->longdoc)
|
|
|
|
|
builtin->longdoc = array_create (sizeof (char *));
|
|
|
|
|
|
|
|
|
|
array_add (line, builtin->longdoc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How to handle the $BUILTIN directive. */
|
|
|
|
|
int
|
|
|
|
|
builtin_handler (self, defs, arg)
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *self;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
DEF_FILE *defs;
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *arg;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
1996-12-23 17:02:34 +00:00
|
|
|
|
BUILTIN_DESC *new;
|
|
|
|
|
char *name;
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
/* If we are already building a builtin, we cannot start a new one. */
|
|
|
|
|
if (building_builtin)
|
1996-12-23 17:02:34 +00:00
|
|
|
|
{
|
|
|
|
|
line_error (defs, "%s found before $END", self);
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
output_cpp_line_info++;
|
|
|
|
|
|
|
|
|
|
/* Get the name of this builtin, and stick it in the array. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
name = get_arg (self, defs, arg);
|
|
|
|
|
|
|
|
|
|
/* If this is the first builtin, create the array to hold them. */
|
|
|
|
|
if (!defs->builtins)
|
|
|
|
|
defs->builtins = array_create (sizeof (BUILTIN_DESC *));
|
|
|
|
|
|
|
|
|
|
new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC));
|
|
|
|
|
new->name = name;
|
|
|
|
|
new->function = (char *)NULL;
|
|
|
|
|
new->shortdoc = (char *)NULL;
|
|
|
|
|
new->docname = (char *)NULL;
|
|
|
|
|
new->longdoc = (ARRAY *)NULL;
|
|
|
|
|
new->dependencies = (ARRAY *)NULL;
|
|
|
|
|
new->flags = 0;
|
|
|
|
|
|
|
|
|
|
if (is_special_builtin (name))
|
|
|
|
|
new->flags |= BUILTIN_FLAG_SPECIAL;
|
|
|
|
|
if (is_assignment_builtin (name))
|
|
|
|
|
new->flags |= BUILTIN_FLAG_ASSIGNMENT;
|
2016-09-15 16:59:08 -04:00
|
|
|
|
if (is_localvar_builtin (name))
|
|
|
|
|
new->flags |= BUILTIN_FLAG_LOCALVAR;
|
2009-01-12 13:36:28 +00:00
|
|
|
|
if (is_posix_builtin (name))
|
|
|
|
|
new->flags |= BUILTIN_FLAG_POSIX_BUILTIN;
|
1996-12-23 17:02:34 +00:00
|
|
|
|
|
|
|
|
|
array_add ((char *)new, defs->builtins);
|
|
|
|
|
building_builtin = 1;
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How to handle the $FUNCTION directive. */
|
|
|
|
|
int
|
|
|
|
|
function_handler (self, defs, arg)
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *self;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
DEF_FILE *defs;
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *arg;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
|
|
|
|
register BUILTIN_DESC *builtin;
|
|
|
|
|
|
|
|
|
|
builtin = current_builtin (self, defs);
|
|
|
|
|
|
1998-04-17 19:52:44 +00:00
|
|
|
|
if (builtin == 0)
|
|
|
|
|
{
|
|
|
|
|
line_error (defs, "syntax error: no current builtin for $FUNCTION directive");
|
|
|
|
|
exit (1);
|
|
|
|
|
}
|
1996-08-26 18:22:31 +00:00
|
|
|
|
if (builtin->function)
|
|
|
|
|
line_error (defs, "%s already has a function (%s)",
|
|
|
|
|
builtin->name, builtin->function);
|
|
|
|
|
else
|
|
|
|
|
builtin->function = get_arg (self, defs, arg);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How to handle the $DOCNAME directive. */
|
|
|
|
|
int
|
|
|
|
|
docname_handler (self, defs, arg)
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *self;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
DEF_FILE *defs;
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *arg;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
|
|
|
|
register BUILTIN_DESC *builtin;
|
|
|
|
|
|
|
|
|
|
builtin = current_builtin (self, defs);
|
|
|
|
|
|
|
|
|
|
if (builtin->docname)
|
|
|
|
|
line_error (defs, "%s already had a docname (%s)",
|
|
|
|
|
builtin->name, builtin->docname);
|
|
|
|
|
else
|
|
|
|
|
builtin->docname = get_arg (self, defs, arg);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How to handle the $SHORT_DOC directive. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
int
|
1996-08-26 18:22:31 +00:00
|
|
|
|
short_doc_handler (self, defs, arg)
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *self;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
DEF_FILE *defs;
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *arg;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
|
|
|
|
register BUILTIN_DESC *builtin;
|
|
|
|
|
|
|
|
|
|
builtin = current_builtin (self, defs);
|
|
|
|
|
|
|
|
|
|
if (builtin->shortdoc)
|
|
|
|
|
line_error (defs, "%s already has short documentation (%s)",
|
|
|
|
|
builtin->name, builtin->shortdoc);
|
|
|
|
|
else
|
|
|
|
|
builtin->shortdoc = get_arg (self, defs, arg);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How to handle the $COMMENT directive. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
int
|
2001-11-13 17:56:06 +00:00
|
|
|
|
comment_handler (self, defs, arg)
|
1996-08-26 18:22:31 +00:00
|
|
|
|
char *self;
|
|
|
|
|
DEF_FILE *defs;
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *arg;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
1996-12-23 17:02:34 +00:00
|
|
|
|
return (0);
|
1996-08-26 18:22:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How to handle the $DEPENDS_ON directive. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
int
|
1996-08-26 18:22:31 +00:00
|
|
|
|
depends_on_handler (self, defs, arg)
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *self;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
DEF_FILE *defs;
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *arg;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
|
|
|
|
register BUILTIN_DESC *builtin;
|
|
|
|
|
char *dependent;
|
|
|
|
|
|
|
|
|
|
builtin = current_builtin (self, defs);
|
|
|
|
|
dependent = get_arg (self, defs, arg);
|
|
|
|
|
|
|
|
|
|
if (!builtin->dependencies)
|
|
|
|
|
builtin->dependencies = array_create (sizeof (char *));
|
|
|
|
|
|
|
|
|
|
array_add (dependent, builtin->dependencies);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How to handle the $PRODUCES directive. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
int
|
1996-08-26 18:22:31 +00:00
|
|
|
|
produces_handler (self, defs, arg)
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *self;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
DEF_FILE *defs;
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *arg;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
|
|
|
|
/* If just hacking documentation, don't change any of the production
|
|
|
|
|
files. */
|
|
|
|
|
if (only_documentation)
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
output_cpp_line_info++;
|
|
|
|
|
|
|
|
|
|
if (defs->production)
|
|
|
|
|
line_error (defs, "%s already has a %s definition", defs->filename, self);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
defs->production = get_arg (self, defs, arg);
|
|
|
|
|
|
|
|
|
|
if (inhibit_production)
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
|
|
defs->output = fopen (defs->production, "w");
|
|
|
|
|
|
|
|
|
|
if (!defs->output)
|
|
|
|
|
file_error (defs->production);
|
|
|
|
|
|
|
|
|
|
fprintf (defs->output, "/* %s, created from %s. */\n",
|
|
|
|
|
defs->production, defs->filename);
|
|
|
|
|
}
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How to handle the $END directive. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
int
|
1996-08-26 18:22:31 +00:00
|
|
|
|
end_handler (self, defs, arg)
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *self;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
DEF_FILE *defs;
|
2001-11-13 17:56:06 +00:00
|
|
|
|
char *arg;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
|
|
|
|
must_be_building (self, defs);
|
|
|
|
|
building_builtin = 0;
|
1996-12-23 17:02:34 +00:00
|
|
|
|
return (0);
|
1996-08-26 18:22:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
/* */
|
|
|
|
|
/* Error Handling Functions */
|
|
|
|
|
/* */
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
|
|
|
|
|
/* Produce an error for DEFS with FORMAT and ARGS. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
line_error (defs, format, arg1, arg2)
|
|
|
|
|
DEF_FILE *defs;
|
|
|
|
|
char *format, *arg1, *arg2;
|
|
|
|
|
{
|
|
|
|
|
if (defs->filename[0] != '/')
|
|
|
|
|
fprintf (stderr, "%s", error_directory ? error_directory : "./");
|
|
|
|
|
fprintf (stderr, "%s:%d:", defs->filename, defs->line_number + 1);
|
|
|
|
|
fprintf (stderr, format, arg1, arg2);
|
|
|
|
|
fprintf (stderr, "\n");
|
|
|
|
|
fflush (stderr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Print error message for FILENAME. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
file_error (filename)
|
|
|
|
|
char *filename;
|
|
|
|
|
{
|
|
|
|
|
perror (filename);
|
|
|
|
|
exit (2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
/* */
|
|
|
|
|
/* xmalloc and xrealloc () */
|
|
|
|
|
/* */
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
|
|
|
|
|
static void memory_error_and_abort ();
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
xmalloc (bytes)
|
|
|
|
|
int bytes;
|
|
|
|
|
{
|
|
|
|
|
char *temp = (char *)malloc (bytes);
|
|
|
|
|
|
|
|
|
|
if (!temp)
|
|
|
|
|
memory_error_and_abort ();
|
|
|
|
|
return (temp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
xrealloc (pointer, bytes)
|
|
|
|
|
char *pointer;
|
|
|
|
|
int bytes;
|
|
|
|
|
{
|
|
|
|
|
char *temp;
|
|
|
|
|
|
|
|
|
|
if (!pointer)
|
|
|
|
|
temp = (char *)malloc (bytes);
|
|
|
|
|
else
|
|
|
|
|
temp = (char *)realloc (pointer, bytes);
|
|
|
|
|
|
|
|
|
|
if (!temp)
|
|
|
|
|
memory_error_and_abort ();
|
|
|
|
|
|
|
|
|
|
return (temp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
memory_error_and_abort ()
|
|
|
|
|
{
|
1996-12-23 17:02:34 +00:00
|
|
|
|
fprintf (stderr, "mkbuiltins: out of virtual memory\n");
|
1996-08-26 18:22:31 +00:00
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
/* */
|
|
|
|
|
/* Creating the Struct and Extern Files */
|
|
|
|
|
/* */
|
|
|
|
|
/* **************************************************************** */
|
|
|
|
|
|
|
|
|
|
/* Return a pointer to a newly allocated builtin which is
|
|
|
|
|
an exact copy of BUILTIN. */
|
|
|
|
|
BUILTIN_DESC *
|
|
|
|
|
copy_builtin (builtin)
|
|
|
|
|
BUILTIN_DESC *builtin;
|
|
|
|
|
{
|
|
|
|
|
BUILTIN_DESC *new;
|
|
|
|
|
|
|
|
|
|
new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC));
|
|
|
|
|
|
2001-04-06 19:14:31 +00:00
|
|
|
|
new->name = savestring (builtin->name);
|
|
|
|
|
new->shortdoc = savestring (builtin->shortdoc);
|
|
|
|
|
new->longdoc = copy_string_array (builtin->longdoc);
|
1996-08-26 18:22:31 +00:00
|
|
|
|
new->dependencies = copy_string_array (builtin->dependencies);
|
|
|
|
|
|
|
|
|
|
new->function =
|
|
|
|
|
builtin->function ? savestring (builtin->function) : (char *)NULL;
|
|
|
|
|
new->docname =
|
|
|
|
|
builtin->docname ? savestring (builtin->docname) : (char *)NULL;
|
|
|
|
|
|
|
|
|
|
return (new);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How to save away a builtin. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
save_builtin (builtin)
|
|
|
|
|
BUILTIN_DESC *builtin;
|
|
|
|
|
{
|
|
|
|
|
BUILTIN_DESC *newbuiltin;
|
|
|
|
|
|
|
|
|
|
newbuiltin = copy_builtin (builtin);
|
|
|
|
|
|
|
|
|
|
/* If this is the first builtin to be saved, create the array
|
|
|
|
|
to hold it. */
|
|
|
|
|
if (!saved_builtins)
|
|
|
|
|
saved_builtins = array_create (sizeof (BUILTIN_DESC *));
|
|
|
|
|
|
|
|
|
|
array_add ((char *)newbuiltin, saved_builtins);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Flags that mean something to write_documentation (). */
|
2005-12-07 14:08:12 +00:00
|
|
|
|
#define STRING_ARRAY 0x01
|
|
|
|
|
#define TEXINFO 0x02
|
|
|
|
|
#define PLAINTEXT 0x04
|
|
|
|
|
#define HELPFILE 0x08
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
char *structfile_header[] = {
|
|
|
|
|
"/* builtins.c -- the built in shell commands. */",
|
|
|
|
|
"",
|
|
|
|
|
"/* This file is manufactured by ./mkbuiltins, and should not be",
|
|
|
|
|
" edited by hand. See the source to mkbuiltins for details. */",
|
|
|
|
|
"",
|
2016-09-15 16:59:08 -04:00
|
|
|
|
"/* Copyright (C) 1987-2015 Free Software Foundation, Inc.",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
"",
|
|
|
|
|
" This file is part of GNU Bash, the Bourne Again SHell.",
|
|
|
|
|
"",
|
2009-01-12 13:36:28 +00:00
|
|
|
|
" 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.",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
"",
|
2009-01-12 13:36:28 +00:00
|
|
|
|
" 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.",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
"",
|
|
|
|
|
" You should have received a copy of the GNU General Public License",
|
2009-01-12 13:36:28 +00:00
|
|
|
|
" along with Bash. If not, see <http://www.gnu.org/licenses/>.",
|
|
|
|
|
"*/",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
"",
|
1996-12-23 17:02:34 +00:00
|
|
|
|
"/* The list of shell builtins. Each element is name, function, flags,",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
" long-doc, short-doc. The long-doc field contains a pointer to an array",
|
|
|
|
|
" of help lines. The function takes a WORD_LIST *; the first word in the",
|
|
|
|
|
" list is the first arg to the command. The list has already had word",
|
|
|
|
|
" expansion performed.",
|
|
|
|
|
"",
|
|
|
|
|
" Functions which need to look at only the simple commands (e.g.",
|
|
|
|
|
" the enable_builtin ()), should ignore entries where",
|
2001-11-13 17:56:06 +00:00
|
|
|
|
" (array[i].function == (sh_builtin_func_t *)NULL). Such entries are for",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
" the list of shell reserved control structures, like `if' and `while'.",
|
|
|
|
|
" The end of the list is denoted with a NULL name field. */",
|
|
|
|
|
"",
|
2016-09-15 16:59:08 -04:00
|
|
|
|
"/* TRANSLATORS: Please do not translate command names in descriptions */",
|
|
|
|
|
"",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
"#include \"../builtins.h\"",
|
|
|
|
|
(char *)NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
char *structfile_footer[] = {
|
2011-11-22 19:11:26 -05:00
|
|
|
|
" { (char *)0x0, (sh_builtin_func_t *)0x0, 0, (char **)0x0, (char *)0x0, (char *)0x0 }",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
"};",
|
|
|
|
|
"",
|
1996-12-23 17:02:34 +00:00
|
|
|
|
"struct builtin *shell_builtins = static_shell_builtins;",
|
|
|
|
|
"struct builtin *current_builtin;",
|
|
|
|
|
"",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
"int num_shell_builtins =",
|
1996-12-23 17:02:34 +00:00
|
|
|
|
"\tsizeof (static_shell_builtins) / sizeof (struct builtin) - 1;",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
(char *)NULL
|
|
|
|
|
};
|
|
|
|
|
|
2014-02-26 09:36:43 -05:00
|
|
|
|
/* Write out any necessary opening information for
|
1996-08-26 18:22:31 +00:00
|
|
|
|
STRUCTFILE and EXTERNFILE. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
write_file_headers (structfile, externfile)
|
|
|
|
|
FILE *structfile, *externfile;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
|
|
|
|
|
if (structfile)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; structfile_header[i]; i++)
|
|
|
|
|
fprintf (structfile, "%s\n", structfile_header[i]);
|
|
|
|
|
|
|
|
|
|
fprintf (structfile, "#include \"%s\"\n",
|
|
|
|
|
extern_filename ? extern_filename : "builtext.h");
|
2004-07-27 13:29:18 +00:00
|
|
|
|
|
|
|
|
|
fprintf (structfile, "#include \"bashintl.h\"\n");
|
|
|
|
|
|
1996-12-23 17:02:34 +00:00
|
|
|
|
fprintf (structfile, "\nstruct builtin static_shell_builtins[] = {\n");
|
1996-08-26 18:22:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (externfile)
|
|
|
|
|
fprintf (externfile,
|
|
|
|
|
"/* %s - The list of builtins found in libbuiltins.a. */\n",
|
|
|
|
|
extern_filename ? extern_filename : "builtext.h");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out any necessary closing information for
|
|
|
|
|
STRUCTFILE and EXTERNFILE. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
write_file_footers (structfile, externfile)
|
|
|
|
|
FILE *structfile, *externfile;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
|
|
|
|
|
/* Write out the footers. */
|
|
|
|
|
if (structfile)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; structfile_footer[i]; i++)
|
|
|
|
|
fprintf (structfile, "%s\n", structfile_footer[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out the information accumulated in DEFS to
|
|
|
|
|
STRUCTFILE and EXTERNFILE. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
write_builtins (defs, structfile, externfile)
|
|
|
|
|
DEF_FILE *defs;
|
|
|
|
|
FILE *structfile, *externfile;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
|
|
|
|
|
/* Write out the information. */
|
|
|
|
|
if (defs->builtins)
|
|
|
|
|
{
|
|
|
|
|
register BUILTIN_DESC *builtin;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < defs->builtins->sindex; i++)
|
|
|
|
|
{
|
|
|
|
|
builtin = (BUILTIN_DESC *)defs->builtins->array[i];
|
|
|
|
|
|
|
|
|
|
/* Write out any #ifdefs that may be there. */
|
|
|
|
|
if (!only_documentation)
|
|
|
|
|
{
|
|
|
|
|
if (builtin->dependencies)
|
|
|
|
|
{
|
1996-12-23 17:02:34 +00:00
|
|
|
|
write_ifdefs (externfile, builtin->dependencies->array);
|
1996-08-26 18:22:31 +00:00
|
|
|
|
write_ifdefs (structfile, builtin->dependencies->array);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write the extern definition. */
|
|
|
|
|
if (externfile)
|
|
|
|
|
{
|
|
|
|
|
if (builtin->function)
|
2001-11-13 17:56:06 +00:00
|
|
|
|
fprintf (externfile, "extern int %s __P((WORD_LIST *));\n",
|
1996-08-26 18:22:31 +00:00
|
|
|
|
builtin->function);
|
|
|
|
|
|
2002-07-17 14:10:11 +00:00
|
|
|
|
fprintf (externfile, "extern char * const %s_doc[];\n",
|
|
|
|
|
document_name (builtin));
|
1996-08-26 18:22:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write the structure definition. */
|
|
|
|
|
if (structfile)
|
|
|
|
|
{
|
|
|
|
|
fprintf (structfile, " { \"%s\", ", builtin->name);
|
|
|
|
|
|
2014-02-26 09:36:43 -05:00
|
|
|
|
if (builtin->function && inhibit_functions == 0)
|
1996-08-26 18:22:31 +00:00
|
|
|
|
fprintf (structfile, "%s, ", builtin->function);
|
|
|
|
|
else
|
2001-11-13 17:56:06 +00:00
|
|
|
|
fprintf (structfile, "(sh_builtin_func_t *)0x0, ");
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2016-09-15 16:59:08 -04:00
|
|
|
|
fprintf (structfile, "%s%s%s%s%s, %s_doc,\n",
|
1996-12-23 17:02:34 +00:00
|
|
|
|
"BUILTIN_ENABLED | STATIC_BUILTIN",
|
|
|
|
|
(builtin->flags & BUILTIN_FLAG_SPECIAL) ? " | SPECIAL_BUILTIN" : "",
|
|
|
|
|
(builtin->flags & BUILTIN_FLAG_ASSIGNMENT) ? " | ASSIGNMENT_BUILTIN" : "",
|
2016-09-15 16:59:08 -04:00
|
|
|
|
(builtin->flags & BUILTIN_FLAG_LOCALVAR) ? " | LOCALVAR_BUILTIN" : "",
|
2009-01-12 13:36:28 +00:00
|
|
|
|
(builtin->flags & BUILTIN_FLAG_POSIX_BUILTIN) ? " | POSIX_BUILTIN" : "",
|
2002-07-17 14:10:11 +00:00
|
|
|
|
document_name (builtin));
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2016-09-15 16:59:08 -04:00
|
|
|
|
/* Don't translate short document summaries that are identical
|
|
|
|
|
to command names */
|
|
|
|
|
if (builtin->shortdoc && strcmp (builtin->name, builtin->shortdoc) == 0)
|
|
|
|
|
{
|
|
|
|
|
if (inhibit_functions)
|
|
|
|
|
fprintf (structfile, " \"%s\", \"%s\" },\n",
|
|
|
|
|
builtin->shortdoc ? builtin->shortdoc : builtin->name,
|
|
|
|
|
document_name (builtin));
|
|
|
|
|
else
|
|
|
|
|
fprintf (structfile, " \"%s\", (char *)NULL },\n",
|
|
|
|
|
builtin->shortdoc ? builtin->shortdoc : builtin->name);
|
|
|
|
|
}
|
2014-02-26 09:36:43 -05:00
|
|
|
|
else
|
2016-09-15 16:59:08 -04:00
|
|
|
|
{
|
|
|
|
|
if (inhibit_functions)
|
|
|
|
|
fprintf (structfile, " N_(\"%s\"), \"%s\" },\n",
|
|
|
|
|
builtin->shortdoc ? builtin->shortdoc : builtin->name,
|
|
|
|
|
document_name (builtin));
|
|
|
|
|
else
|
|
|
|
|
fprintf (structfile, " N_(\"%s\"), (char *)NULL },\n",
|
|
|
|
|
builtin->shortdoc ? builtin->shortdoc : builtin->name);
|
|
|
|
|
}
|
1996-08-26 18:22:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-07-17 14:10:11 +00:00
|
|
|
|
if (structfile || separate_helpfiles)
|
|
|
|
|
/* Save away this builtin for later writing of the
|
|
|
|
|
long documentation strings. */
|
|
|
|
|
save_builtin (builtin);
|
|
|
|
|
|
2014-02-26 09:36:43 -05:00
|
|
|
|
/* Write out the matching #endif, if necessary. */
|
1996-08-26 18:22:31 +00:00
|
|
|
|
if (builtin->dependencies)
|
|
|
|
|
{
|
|
|
|
|
if (externfile)
|
|
|
|
|
write_endifs (externfile, builtin->dependencies->array);
|
|
|
|
|
|
|
|
|
|
if (structfile)
|
|
|
|
|
write_endifs (structfile, builtin->dependencies->array);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (documentation_file)
|
|
|
|
|
{
|
|
|
|
|
fprintf (documentation_file, "@item %s\n", builtin->name);
|
|
|
|
|
write_documentation
|
|
|
|
|
(documentation_file, builtin->longdoc->array, 0, TEXINFO);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out the long documentation strings in BUILTINS to STREAM. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
write_longdocs (stream, builtins)
|
|
|
|
|
FILE *stream;
|
|
|
|
|
ARRAY *builtins;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
register BUILTIN_DESC *builtin;
|
2002-07-17 14:10:11 +00:00
|
|
|
|
char *dname;
|
|
|
|
|
char *sarray[2];
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < builtins->sindex; i++)
|
|
|
|
|
{
|
|
|
|
|
builtin = (BUILTIN_DESC *)builtins->array[i];
|
|
|
|
|
|
|
|
|
|
if (builtin->dependencies)
|
|
|
|
|
write_ifdefs (stream, builtin->dependencies->array);
|
|
|
|
|
|
|
|
|
|
/* Write the long documentation strings. */
|
2002-07-17 14:10:11 +00:00
|
|
|
|
dname = document_name (builtin);
|
|
|
|
|
fprintf (stream, "char * const %s_doc[] =", dname);
|
|
|
|
|
|
|
|
|
|
if (separate_helpfiles)
|
|
|
|
|
{
|
|
|
|
|
int l = strlen (helpfile_directory) + strlen (dname) + 1;
|
|
|
|
|
sarray[0] = (char *)xmalloc (l + 1);
|
|
|
|
|
sprintf (sarray[0], "%s/%s", helpfile_directory, dname);
|
|
|
|
|
sarray[1] = (char *)NULL;
|
2005-12-07 14:08:12 +00:00
|
|
|
|
write_documentation (stream, sarray, 0, STRING_ARRAY|HELPFILE);
|
2002-07-17 14:10:11 +00:00
|
|
|
|
free (sarray[0]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
write_documentation (stream, builtin->longdoc->array, 0, STRING_ARRAY);
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
if (builtin->dependencies)
|
|
|
|
|
write_endifs (stream, builtin->dependencies->array);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-26 09:36:43 -05:00
|
|
|
|
void
|
|
|
|
|
write_dummy_declarations (stream, builtins)
|
|
|
|
|
FILE *stream;
|
|
|
|
|
ARRAY *builtins;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
BUILTIN_DESC *builtin;
|
|
|
|
|
|
|
|
|
|
for (i = 0; structfile_header[i]; i++)
|
|
|
|
|
fprintf (stream, "%s\n", structfile_header[i]);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < builtins->sindex; i++)
|
|
|
|
|
{
|
|
|
|
|
builtin = (BUILTIN_DESC *)builtins->array[i];
|
|
|
|
|
|
|
|
|
|
/* How to guarantee that no builtin is written more than once? */
|
|
|
|
|
fprintf (stream, "int %s () { return (0); }\n", builtin->function);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
/* Write an #ifdef string saying what needs to be defined (or not defined)
|
|
|
|
|
in order to allow compilation of the code that will follow.
|
|
|
|
|
STREAM is the stream to write the information to,
|
|
|
|
|
DEFINES is a null terminated array of define names.
|
|
|
|
|
If a define is preceded by an `!', then the sense of the test is
|
|
|
|
|
reversed. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
write_ifdefs (stream, defines)
|
|
|
|
|
FILE *stream;
|
|
|
|
|
char **defines;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
|
|
|
|
|
if (!stream)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
fprintf (stream, "#if ");
|
|
|
|
|
|
|
|
|
|
for (i = 0; defines[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
char *def = defines[i];
|
|
|
|
|
|
|
|
|
|
if (*def == '!')
|
|
|
|
|
fprintf (stream, "!defined (%s)", def + 1);
|
|
|
|
|
else
|
|
|
|
|
fprintf (stream, "defined (%s)", def);
|
|
|
|
|
|
|
|
|
|
if (defines[i + 1])
|
|
|
|
|
fprintf (stream, " && ");
|
|
|
|
|
}
|
|
|
|
|
fprintf (stream, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write an #endif string saying what defines controlled the compilation
|
|
|
|
|
of the immediately preceding code.
|
|
|
|
|
STREAM is the stream to write the information to.
|
|
|
|
|
DEFINES is a null terminated array of define names. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
write_endifs (stream, defines)
|
|
|
|
|
FILE *stream;
|
|
|
|
|
char **defines;
|
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
|
|
|
|
|
if (!stream)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
fprintf (stream, "#endif /* ");
|
|
|
|
|
|
|
|
|
|
for (i = 0; defines[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stream, "%s", defines[i]);
|
|
|
|
|
|
|
|
|
|
if (defines[i + 1])
|
|
|
|
|
fprintf (stream, " && ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (stream, " */\n");
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-07 14:08:12 +00:00
|
|
|
|
/* Write DOCUMENTATION to STREAM, perhaps surrounding it with double-quotes
|
|
|
|
|
and quoting special characters in the string. Handle special things for
|
|
|
|
|
internationalization (gettext) and the single-string vs. multiple-strings
|
|
|
|
|
issues. */
|
1996-12-23 17:02:34 +00:00
|
|
|
|
void
|
1996-08-26 18:22:31 +00:00
|
|
|
|
write_documentation (stream, documentation, indentation, flags)
|
|
|
|
|
FILE *stream;
|
|
|
|
|
char **documentation;
|
|
|
|
|
int indentation, flags;
|
|
|
|
|
{
|
|
|
|
|
register int i, j;
|
|
|
|
|
register char *line;
|
2011-11-22 19:11:26 -05:00
|
|
|
|
int string_array, texinfo, base_indent, filename_p;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2006-10-10 14:15:34 +00:00
|
|
|
|
if (stream == 0)
|
1996-08-26 18:22:31 +00:00
|
|
|
|
return;
|
|
|
|
|
|
1996-12-23 17:02:34 +00:00
|
|
|
|
string_array = flags & STRING_ARRAY;
|
2005-12-07 14:08:12 +00:00
|
|
|
|
filename_p = flags & HELPFILE;
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
if (string_array)
|
2005-12-07 14:08:12 +00:00
|
|
|
|
{
|
|
|
|
|
fprintf (stream, " {\n#if defined (HELP_BUILTIN)\n"); /* } */
|
|
|
|
|
if (single_longdoc_strings)
|
|
|
|
|
{
|
|
|
|
|
if (filename_p == 0)
|
2006-10-10 14:15:34 +00:00
|
|
|
|
{
|
|
|
|
|
if (documentation && documentation[0] && documentation[0][0])
|
|
|
|
|
fprintf (stream, "N_(\"");
|
|
|
|
|
else
|
|
|
|
|
fprintf (stream, "N_(\" "); /* the empty string translates specially. */
|
|
|
|
|
}
|
2005-12-07 14:08:12 +00:00
|
|
|
|
else
|
|
|
|
|
fprintf (stream, "\"");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
base_indent = (string_array && single_longdoc_strings && filename_p == 0) ? BASE_INDENT : 0;
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
2014-02-26 09:36:43 -05:00
|
|
|
|
for (i = 0, texinfo = (flags & TEXINFO); documentation && (line = documentation[i]); i++)
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
2005-12-07 14:08:12 +00:00
|
|
|
|
/* Allow #ifdef's to be written out verbatim, but don't put them into
|
|
|
|
|
separate help files. */
|
1996-08-26 18:22:31 +00:00
|
|
|
|
if (*line == '#')
|
|
|
|
|
{
|
2005-12-07 14:08:12 +00:00
|
|
|
|
if (string_array && filename_p == 0 && single_longdoc_strings == 0)
|
1996-08-26 18:22:31 +00:00
|
|
|
|
fprintf (stream, "%s\n", line);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-27 13:29:18 +00:00
|
|
|
|
/* prefix with N_( for gettext */
|
2005-12-07 14:08:12 +00:00
|
|
|
|
if (string_array && single_longdoc_strings == 0)
|
|
|
|
|
{
|
|
|
|
|
if (filename_p == 0)
|
2006-10-10 14:15:34 +00:00
|
|
|
|
{
|
|
|
|
|
if (line[0])
|
|
|
|
|
fprintf (stream, " N_(\"");
|
|
|
|
|
else
|
|
|
|
|
fprintf (stream, " N_(\" "); /* the empty string translates specially. */
|
|
|
|
|
}
|
2005-12-07 14:08:12 +00:00
|
|
|
|
else
|
|
|
|
|
fprintf (stream, " \"");
|
|
|
|
|
}
|
1996-08-26 18:22:31 +00:00
|
|
|
|
|
|
|
|
|
if (indentation)
|
|
|
|
|
for (j = 0; j < indentation; j++)
|
|
|
|
|
fprintf (stream, " ");
|
|
|
|
|
|
2005-12-07 14:08:12 +00:00
|
|
|
|
/* Don't indent the first line, because of how the help builtin works. */
|
|
|
|
|
if (i == 0)
|
|
|
|
|
indentation += base_indent;
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
if (string_array)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; line[j]; j++)
|
|
|
|
|
{
|
|
|
|
|
switch (line[j])
|
|
|
|
|
{
|
|
|
|
|
case '\\':
|
|
|
|
|
case '"':
|
|
|
|
|
fprintf (stream, "\\%c", line[j]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf (stream, "%c", line[j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-27 13:29:18 +00:00
|
|
|
|
/* closing right paren for gettext */
|
2005-12-07 14:08:12 +00:00
|
|
|
|
if (single_longdoc_strings == 0)
|
|
|
|
|
{
|
|
|
|
|
if (filename_p == 0)
|
|
|
|
|
fprintf (stream, "\"),\n");
|
|
|
|
|
else
|
|
|
|
|
fprintf (stream, "\",\n");
|
|
|
|
|
}
|
|
|
|
|
else if (documentation[i+1])
|
|
|
|
|
/* don't add extra newline after last line */
|
|
|
|
|
fprintf (stream, "\\n\\\n");
|
1996-08-26 18:22:31 +00:00
|
|
|
|
}
|
|
|
|
|
else if (texinfo)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; line[j]; j++)
|
|
|
|
|
{
|
|
|
|
|
switch (line[j])
|
|
|
|
|
{
|
|
|
|
|
case '@':
|
|
|
|
|
case '{':
|
|
|
|
|
case '}':
|
|
|
|
|
fprintf (stream, "@%c", line[j]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf (stream, "%c", line[j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fprintf (stream, "\n");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fprintf (stream, "%s\n", line);
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-07 14:08:12 +00:00
|
|
|
|
/* closing right paren for gettext */
|
|
|
|
|
if (string_array && single_longdoc_strings)
|
|
|
|
|
{
|
|
|
|
|
if (filename_p == 0)
|
|
|
|
|
fprintf (stream, "\"),\n");
|
|
|
|
|
else
|
|
|
|
|
fprintf (stream, "\",\n");
|
|
|
|
|
}
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
if (string_array)
|
1996-12-23 17:02:34 +00:00
|
|
|
|
fprintf (stream, "#endif /* HELP_BUILTIN */\n (char *)NULL\n};\n");
|
1996-08-26 18:22:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-07-17 14:10:11 +00:00
|
|
|
|
int
|
|
|
|
|
write_helpfiles (builtins)
|
|
|
|
|
ARRAY *builtins;
|
|
|
|
|
{
|
|
|
|
|
char *helpfile, *bname;
|
|
|
|
|
FILE *helpfp;
|
|
|
|
|
int i, hdlen;
|
|
|
|
|
BUILTIN_DESC *builtin;
|
|
|
|
|
|
|
|
|
|
i = mkdir ("helpfiles", 0777);
|
|
|
|
|
if (i < 0 && errno != EEXIST)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "write_helpfiles: helpfiles: cannot create directory\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hdlen = strlen ("helpfiles/");
|
|
|
|
|
for (i = 0; i < builtins->sindex; i++)
|
|
|
|
|
{
|
|
|
|
|
builtin = (BUILTIN_DESC *)builtins->array[i];
|
|
|
|
|
|
|
|
|
|
bname = document_name (builtin);
|
|
|
|
|
helpfile = (char *)xmalloc (hdlen + strlen (bname) + 1);
|
|
|
|
|
sprintf (helpfile, "helpfiles/%s", bname);
|
|
|
|
|
|
|
|
|
|
helpfp = fopen (helpfile, "w");
|
|
|
|
|
if (helpfp == 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "write_helpfiles: cannot open %s\n", helpfile);
|
|
|
|
|
free (helpfile);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_documentation (helpfp, builtin->longdoc->array, 4, PLAINTEXT);
|
|
|
|
|
|
|
|
|
|
fflush (helpfp);
|
|
|
|
|
fclose (helpfp);
|
|
|
|
|
free (helpfile);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1996-08-26 18:22:31 +00:00
|
|
|
|
static int
|
1996-12-23 17:02:34 +00:00
|
|
|
|
_find_in_table (name, name_table)
|
|
|
|
|
char *name, *name_table[];
|
1996-08-26 18:22:31 +00:00
|
|
|
|
{
|
|
|
|
|
register int i;
|
|
|
|
|
|
1996-12-23 17:02:34 +00:00
|
|
|
|
for (i = 0; name_table[i]; i++)
|
|
|
|
|
if (strcmp (name, name_table[i]) == 0)
|
1996-08-26 18:22:31 +00:00
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1996-12-23 17:02:34 +00:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
is_special_builtin (name)
|
|
|
|
|
char *name;
|
|
|
|
|
{
|
|
|
|
|
return (_find_in_table (name, special_builtins));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
is_assignment_builtin (name)
|
|
|
|
|
char *name;
|
|
|
|
|
{
|
|
|
|
|
return (_find_in_table (name, assignment_builtins));
|
|
|
|
|
}
|
1999-02-19 17:11:39 +00:00
|
|
|
|
|
2016-09-15 16:59:08 -04:00
|
|
|
|
static int
|
|
|
|
|
is_localvar_builtin (name)
|
|
|
|
|
char *name;
|
|
|
|
|
{
|
|
|
|
|
return (_find_in_table (name, localvar_builtins));
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-12 13:36:28 +00:00
|
|
|
|
static int
|
|
|
|
|
is_posix_builtin (name)
|
|
|
|
|
char *name;
|
|
|
|
|
{
|
|
|
|
|
return (_find_in_table (name, posix_builtins));
|
|
|
|
|
}
|
|
|
|
|
|
1999-02-19 17:11:39 +00:00
|
|
|
|
#if !defined (HAVE_RENAME)
|
|
|
|
|
static int
|
|
|
|
|
rename (from, to)
|
|
|
|
|
char *from, *to;
|
|
|
|
|
{
|
|
|
|
|
unlink (to);
|
|
|
|
|
if (link (from, to) < 0)
|
|
|
|
|
return (-1);
|
|
|
|
|
unlink (from);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
#endif /* !HAVE_RENAME */
|