Imported from ../bash-2.05.tar.gz.
[platform/upstream/bash.git] / builtins / mkbuiltins.c
index 572d01e..139a46f 100644 (file)
@@ -7,7 +7,7 @@ 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 1, or (at your option) any later
+Software Foundation; either version 2, or (at your option) any later
 version.
 
 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -17,25 +17,27 @@ for more details.
 
 You should have received a copy of the GNU General Public License along
 with Bash; see the file COPYING.  If not, write to the Free Software
-Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
 
-#include "../bashansi.h"
-#include "../config.h"
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-#include "../filecntl.h"
+#include <config.h>
 
 #if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
 #  include <unistd.h>
-#endif /* HAVE_UNISTD_H */
+#endif
+
+#ifndef _MINIX
+#include "../bashtypes.h"
+#include <sys/file.h>
+#endif
 
-#if defined (HAVE_STRING_H)
-#  include <string.h>
-#else /* !HAVE_STRING_H */
-#  include <strings.h>
-#endif /* !HAVE_STRING_H */
+#include "posixstat.h"
+#include "filecntl.h"
+
+#include "../bashansi.h"
+#include <stdio.h>
 
 #define DOCFILE "builtins.texi"
 
@@ -50,6 +52,7 @@ extern char *strcpy ();
 
 /* Flag values that builtins can have. */
 #define BUILTIN_FLAG_SPECIAL   0x01
+#define BUILTIN_FLAG_ASSIGNMENT 0x02
 
 /* If this stream descriptor is non-zero, then write
    texinfo documentation to it. */
@@ -115,12 +118,45 @@ char *special_builtins[] =
   "export", "readonly", "return", "set", "shift", "trap", "unset",
   (char *)NULL
 };
+
+/* The builtin commands that take assignment statements as arguments. */
+char *assignment_builtins[] =
+{
+  "alias", "declare", "export", "local", "readonly", "typeset",
+  (char *)NULL
+};
+
+/* Forward declarations. */
 static int is_special_builtin ();
+static int is_assignment_builtin ();
+
+#if !defined (HAVE_RENAME)
+static int rename ();
+#endif
+
+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 ();
 
+void free_defs ();
+void add_documentation ();
+
+void must_be_building ();
+void remove_trailing_whitespace ();
 \f
 /* 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. */
+int
 main (argc, argv)
      int argc;
      char **argv;
@@ -169,7 +205,7 @@ main (argc, argv)
 #if !defined (OLDCODE)
       else if (strcmp (arg, "-nodocument") == 0)
        no_long_document = 1;
-#endif /* !OLDCODE */        
+#endif /* !OLDCODE */  
       else
        {
          fprintf (stderr, "%s: Unknown flag %s.\n", argv[0], arg);
@@ -233,8 +269,7 @@ main (argc, argv)
        {
          write_longdocs (structfile, saved_builtins);
          fclose (structfile);
-         link (temp_struct_filename, struct_filename);
-         unlink (temp_struct_filename);
+         rename (temp_struct_filename, struct_filename);
        }
 
       if (externfile)
@@ -305,6 +340,7 @@ copy_string_array (array)
 }
 
 /* Add ELEMENT to ARRAY, growing the array if neccessary. */
+void
 array_add (element, array)
      char *element;
      ARRAY *array;
@@ -314,9 +350,9 @@ array_add (element, array)
       (array->array, (array->size += array->growth_rate) * array->width);
 
 #if defined (HAVE_BCOPY)
-  bcopy (&element, &(array->array[array->sindex]), array->width);
+  bcopy (&element, (char *) &(array->array[array->sindex]), array->width);
   array->sindex++;
-  bzero (&(array->array[array->sindex]), array->width);
+  bzero ((char *) &(array->array[array->sindex]), array->width);
 #else
   array->array[array->sindex++] = element;
   array->array[array->sindex] = (char *)NULL;
@@ -324,6 +360,7 @@ array_add (element, array)
 }
 
 /* Free an allocated array and data pointer. */
+void
 array_free (array)
      ARRAY *array;
 {
@@ -397,6 +434,7 @@ int output_cpp_line_info = 0;
    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". */
+void
 extract_info (filename, structfile, externfile)
      char *filename;
      FILE *structfile, *externfile;
@@ -404,8 +442,9 @@ extract_info (filename, structfile, externfile)
   register int i;
   DEF_FILE *defs;
   struct stat finfo;
+  size_t file_size;
   char *buffer, *line;
-  int fd;
+  int fd, nr;
 
   if (stat (filename, &finfo) == -1)
     file_error (filename);
@@ -415,13 +454,24 @@ extract_info (filename, structfile, externfile)
   if (fd == -1)
     file_error (filename);
 
-  buffer = xmalloc (1 + (int)finfo.st_size);
+  file_size = (size_t)finfo.st_size;
+  buffer = xmalloc (1 + file_size);
 
-  if (read (fd, buffer, finfo.st_size) != finfo.st_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;
@@ -433,11 +483,11 @@ extract_info (filename, structfile, externfile)
 
   /* Build the array of lines. */
   i = 0;
-  while (i < finfo.st_size)
+  while (i < file_size)
     {
       array_add (&buffer[i], defs->lines);
 
-      while (buffer[i] != '\n' && i < finfo.st_size)
+      while (buffer[i] != '\n' && i < file_size)
        i++;
       buffer[i++] = '\0';
     }
@@ -548,6 +598,7 @@ free_builtin (builtin)
 }
 
 /* Free all of the memory allocated to a DEF_FILE. */
+void
 free_defs (defs)
      DEF_FILE *defs;
 {
@@ -563,10 +614,10 @@ free_defs (defs)
   if (defs->builtins)
     {
       for (i = 0; builtin = (BUILTIN_DESC *)defs->builtins->array[i]; i++)
-        {
+       {
          free_builtin (builtin);
          free (builtin);
-        }
+       }
       array_free (defs->builtins);
     }
   free (defs);
@@ -592,6 +643,7 @@ strip_whitespace (string)
 }
 
 /* Remove only the trailing whitespace from STRING. */
+void
 remove_trailing_whitespace (string)
      char *string;
 {
@@ -625,6 +677,7 @@ get_arg (for_whom, defs, string)
 }
 
 /* Error if not building a builtin. */
+void
 must_be_building (directive, defs)
      char *directive;
      DEF_FILE *defs;
@@ -640,11 +693,15 @@ current_builtin (directive, defs)
      DEF_FILE *defs;
 {
   must_be_building (directive, defs);
-  return ((BUILTIN_DESC *)defs->builtins->array[defs->builtins->sindex - 1]);
+  if (defs->builtins)
+    return ((BUILTIN_DESC *)defs->builtins->array[defs->builtins->sindex - 1]);
+  else
+    return ((BUILTIN_DESC *)NULL);
 }
 
 /* Add LINE to the long documentation for the current builtin.
    Ignore blank lines until the first non-blank line has been seen. */
+void
 add_documentation (defs, line)
      DEF_FILE *defs;
      char *line;
@@ -670,38 +727,42 @@ builtin_handler (self, defs, arg)
      char *self, *arg;
      DEF_FILE *defs;
 {
+  BUILTIN_DESC *new;
+  char *name;
+
   /* If we are already building a builtin, we cannot start a new one. */
   if (building_builtin)
-    return (line_error (defs, "%s found before $END", self));
+    {
+      line_error (defs, "%s found before $END", self);
+      return (-1);
+    }
 
   output_cpp_line_info++;
 
   /* Get the name of this builtin, and stick it in the array. */
-  {
-    BUILTIN_DESC *new;
-    char *name;
-
-    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;
-
-    array_add ((char *)new, defs->builtins);
-    building_builtin = 1;
-  }
+  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;
+
+  array_add ((char *)new, defs->builtins);
+  building_builtin = 1;
+
   return (0);
 }
 
@@ -715,6 +776,11 @@ function_handler (self, defs, arg)
 
   builtin = current_builtin (self, defs);
 
+  if (builtin == 0)
+    {
+      line_error (defs, "syntax error: no current builtin for $FUNCTION directive");
+      exit (1);
+    }
   if (builtin->function)
     line_error (defs, "%s already has a function (%s)",
                builtin->name, builtin->function);
@@ -744,6 +810,7 @@ docname_handler (self, defs, arg)
 }
 
 /* How to handle the $SHORT_DOC directive. */
+int
 short_doc_handler (self, defs, arg)
      char *self, *arg;
      DEF_FILE *defs;
@@ -762,13 +829,16 @@ short_doc_handler (self, defs, arg)
 }
 
 /* How to handle the $COMMENT directive. */
+int
 comment_handler (self, defs)
      char *self;
      DEF_FILE *defs;
 {
+  return (0);
 }
 
 /* How to handle the $DEPENDS_ON directive. */
+int
 depends_on_handler (self, defs, arg)
      char *self, *arg;
      DEF_FILE *defs;
@@ -788,6 +858,7 @@ depends_on_handler (self, defs, arg)
 }
 
 /* How to handle the $PRODUCES directive. */
+int
 produces_handler (self, defs, arg)
      char *self, *arg;
      DEF_FILE *defs;
@@ -820,12 +891,14 @@ produces_handler (self, defs, arg)
 }
 
 /* How to handle the $END directive. */
+int
 end_handler (self, defs, arg)
      char *self, *arg;
      DEF_FILE *defs;
 {
   must_be_building (self, defs);
   building_builtin = 0;
+  return (0);
 }
 
 /* **************************************************************** */
@@ -835,6 +908,7 @@ end_handler (self, defs, arg)
 /* **************************************************************** */
 
 /* Produce an error for DEFS with FORMAT and ARGS. */
+void
 line_error (defs, format, arg1, arg2)
      DEF_FILE *defs;
      char *format, *arg1, *arg2;
@@ -848,6 +922,7 @@ line_error (defs, format, arg1, arg2)
 }
 
 /* Print error message for FILENAME. */
+void
 file_error (filename)
      char *filename;
 {
@@ -895,7 +970,7 @@ xrealloc (pointer, bytes)
 static void
 memory_error_and_abort ()
 {
-  fprintf (stderr, "mkbuiltins: Out of virtual memory!\n");
+  fprintf (stderr, "mkbuiltins: out of virtual memory\n");
   abort ();
 }
 
@@ -915,9 +990,9 @@ copy_builtin (builtin)
 
   new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC));
 
-  new->name         = savestring (builtin->name);
-  new->shortdoc     = savestring (builtin->shortdoc);
-  new->longdoc      = copy_string_array (builtin->longdoc);
+  new->name = savestring (builtin->name);
+  new->shortdoc = savestring (builtin->shortdoc);
+  new->longdoc = copy_string_array (builtin->longdoc);
   new->dependencies = copy_string_array (builtin->dependencies);
 
   new->function =
@@ -929,6 +1004,7 @@ copy_builtin (builtin)
 }
 
 /* How to save away a builtin. */
+void
 save_builtin (builtin)
      BUILTIN_DESC *builtin;
 {
@@ -960,7 +1036,7 @@ char *structfile_header[] = {
   "",
   "   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 1, or (at your option)",
+  "   the Free Software Foundation; either version 2, or (at your option)",
   "   any later version.",
   "",
   "   Bash is distributed in the hope that it will be useful, but WITHOUT",
@@ -970,9 +1046,9 @@ char *structfile_header[] = {
   "",
   "   You should have received a copy of the GNU General Public License",
   "   along with Bash; see the file COPYING.  If not, write to the Free",
-  "   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */",
+  "   Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */",
   "",
-  "/* The list of shell builtins.  Each element is name, function, enabled-p,",
+  "/* The list of shell builtins.  Each element is name, function, flags,",
   "   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",
@@ -992,13 +1068,17 @@ char *structfile_footer[] = {
   "  { (char *)0x0, (Function *)0x0, 0, (char **)0x0, (char *)0x0 }",
   "};",
   "",
+  "struct builtin *shell_builtins = static_shell_builtins;",
+  "struct builtin *current_builtin;",
+  "",
   "int num_shell_builtins =",
-  "\tsizeof (shell_builtins) / sizeof (struct builtin) - 1;",
+  "\tsizeof (static_shell_builtins) / sizeof (struct builtin) - 1;",
   (char *)NULL
 };
 
 /* Write out any neccessary opening information for
    STRUCTFILE and EXTERNFILE. */
+void
 write_file_headers (structfile, externfile)
      FILE *structfile, *externfile;
 {
@@ -1011,7 +1091,7 @@ write_file_headers (structfile, externfile)
 
       fprintf (structfile, "#include \"%s\"\n",
               extern_filename ? extern_filename : "builtext.h");
-      fprintf (structfile, "\nstruct builtin shell_builtins[] = {\n");
+      fprintf (structfile, "\nstruct builtin static_shell_builtins[] = {\n");
     }
 
   if (externfile)
@@ -1022,6 +1102,7 @@ write_file_headers (structfile, externfile)
 
 /* Write out any necessary closing information for
    STRUCTFILE and EXTERNFILE. */
+void
 write_file_footers (structfile, externfile)
      FILE *structfile, *externfile;
 {
@@ -1037,6 +1118,7 @@ write_file_footers (structfile, externfile)
 
 /* Write out the information accumulated in DEFS to
    STRUCTFILE and EXTERNFILE. */
+void
 write_builtins (defs, structfile, externfile)
      DEF_FILE *defs;
      FILE *structfile, *externfile;
@@ -1057,8 +1139,7 @@ write_builtins (defs, structfile, externfile)
            {
              if (builtin->dependencies)
                {
-                 if (builtin->function)
-                   write_ifdefs (externfile, builtin->dependencies->array);
+                 write_ifdefs (externfile, builtin->dependencies->array);
                  write_ifdefs (structfile, builtin->dependencies->array);
                }
 
@@ -1070,7 +1151,7 @@ write_builtins (defs, structfile, externfile)
                             builtin->function);
 
                  fprintf (externfile, "extern char *%s_doc[];\n",
-                          builtin->docname ?builtin->docname : builtin->name);
+                          builtin->docname ? builtin->docname : builtin->name);
                }
 
              /* Write the structure definition. */
@@ -1083,20 +1164,14 @@ write_builtins (defs, structfile, externfile)
                  else
                    fprintf (structfile, "(Function *)0x0, ");
 
-#define SPECIAL_FLAG_STRING "BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN"
-#define NORMAL_FLAG_STRING "BUILTIN_ENABLED | STATIC_BUILTIN"
-
-                 fprintf (structfile, "%s, %s_doc,\n",
-                   (builtin->flags & BUILTIN_FLAG_SPECIAL) ?
-                       SPECIAL_FLAG_STRING :
-                       NORMAL_FLAG_STRING,
+                 fprintf (structfile, "%s%s%s, %s_doc,\n",
+                   "BUILTIN_ENABLED | STATIC_BUILTIN",
+                   (builtin->flags & BUILTIN_FLAG_SPECIAL) ? " | SPECIAL_BUILTIN" : "",
+                   (builtin->flags & BUILTIN_FLAG_ASSIGNMENT) ? " | ASSIGNMENT_BUILTIN" : "",
                    builtin->docname ? builtin->docname : builtin->name);
 
-#undef SPECIAL_FLAG_STRING
-#undef NORMAL_FLAG_STRING
-
                  fprintf
-                   (structfile, "     \"%s\" },\n",
+                   (structfile, "     \"%s\", (char *)NULL },\n",
                     builtin->shortdoc ? builtin->shortdoc : builtin->name);
 
                  /* Save away this builtin for later writing of the
@@ -1126,6 +1201,7 @@ write_builtins (defs, structfile, externfile)
 }
 
 /* Write out the long documentation strings in BUILTINS to STREAM. */
+void
 write_longdocs (stream, builtins)
      FILE *stream;
      ARRAY *builtins;
@@ -1157,6 +1233,7 @@ write_longdocs (stream, builtins)
    DEFINES is a null terminated array of define names.
    If a define is preceded by an `!', then the sense of the test is
    reversed. */
+void
 write_ifdefs (stream, defines)
      FILE *stream;
      char **defines;
@@ -1187,6 +1264,7 @@ write_ifdefs (stream, defines)
    of the immediately preceding code.
    STREAM is the stream to write the information to.
    DEFINES is a null terminated array of define names. */
+void
 write_endifs (stream, defines)
      FILE *stream;
      char **defines;
@@ -1211,6 +1289,7 @@ write_endifs (stream, defines)
 
 /* Write DOCUMENTAION to STREAM, perhaps surrounding it with double-quotes
    and quoting special characters in the string. */
+void
 write_documentation (stream, documentation, indentation, flags)
      FILE *stream;
      char **documentation;
@@ -1218,14 +1297,14 @@ write_documentation (stream, documentation, indentation, flags)
 {
   register int i, j;
   register char *line;
-  int string_array = (flags & STRING_ARRAY); /* Mutually exclusive. */
-  int texinfo = (flags & TEXINFO);
+  int string_array, texinfo;
 
   if (!stream)
     return;
 
+  string_array = flags & STRING_ARRAY;
   if (string_array)
-    fprintf (stream, " {\n");
+    fprintf (stream, " {\n#if defined (HELP_BUILTIN)\n");
 
 #if !defined (OLDCODE)
   /* XXX -- clean me up; for experiment only */
@@ -1233,7 +1312,7 @@ write_documentation (stream, documentation, indentation, flags)
     goto end_of_document;
 #endif /* !OLDCODE */
 
-  for (i = 0; line = documentation[i]; i++)
+  for (i = 0, texinfo = (flags & TEXINFO); line = documentation[i]; i++)
     {
       /* Allow #ifdef's to be written out verbatim. */
       if (*line == '#')
@@ -1295,17 +1374,44 @@ end_of_document:
 #endif /* !OLDCODE */
 
   if (string_array)
-    fprintf (stream, "  (char *)NULL\n};\n");
+    fprintf (stream, "#endif /* HELP_BUILTIN */\n  (char *)NULL\n};\n");
 }
 
 static int
-is_special_builtin (name)
-     char *name;
+_find_in_table (name, name_table)
+     char *name, *name_table[];
 {
   register int i;
 
-  for (i = 0; special_builtins[i]; i++)
-    if (strcmp (name, special_builtins[i]) == 0)
+  for (i = 0; name_table[i]; i++)
+    if (strcmp (name, name_table[i]) == 0)
       return 1;
   return 0;
 }
+
+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));
+}
+
+#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 */