OSDN Git Service

(This trying to counter the effect of the PR 195 check in -- this should
[pf3gnuchains/gcc-fork.git] / texinfo / util / install-info.c
index 6e5fc90..91b599d 100644 (file)
@@ -1,43 +1,27 @@
 /* install-info -- create Info directory entry(ies) for an Info file.
-   Copyright (C) 1996 Free Software Foundation, Inc.
+   $Id: install-info.c,v 1.1.1.3 1998/03/24 18:20:30 law Exp $
 
-$Id: install-info.c,v 1.1.1.1 1997/08/21 22:58:12 jason Exp $
+   Copyright (C) 1996, 97, 98 Free Software Foundation, Inc.
 
-This program 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 2 of the License, or
-(at your option) any later version.
+   This program 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 2 of the License, or
+   (at your option) any later version.
 
-This program 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.
+   This program 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 this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/
 
-#define INSTALL_INFO_VERSION_STRING "GNU install-info (Texinfo 3.9) 1.2"
-
-#include <stdio.h>
-#include <errno.h>
+#include "system.h"
 #include <getopt.h>
-#include <sys/types.h>
-
-#if defined (HAVE_STRING_H)
-#include <string.h>
-#else
-#include <strings.h>
-#endif /* !HAVE_STRING_H */
-
-/* Get O_RDONLY.  */
-#ifdef HAVE_SYS_FCNTL_H
-#include <sys/fcntl.h>
-#else
-#include <fcntl.h>
-#endif /* !HAVE_SYS_FCNTL_H */
-#ifdef HAVE_SYS_FILE_H
-#include <sys/file.h>
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
 #endif
 
 /* Name this program was invoked with.  */
@@ -45,7 +29,6 @@ char *progname;
 
 char *readfile ();
 struct line_data *findlines ();
-char *my_strerror ();
 void fatal ();
 void insert_entry_here ();
 int compare_section_names ();
@@ -54,9 +37,8 @@ struct spec_entry;
 \f
 /* Data structures.  */
 
-/* Record info about a single line from a file
-   as read into core.  */
 
+/* Record info about a single line from a file as read into core.  */
 struct line_data
 {
   /* The start of the line.  */
@@ -73,9 +55,9 @@ struct line_data
   int delete;
 };
 
+
 /* This is used for a list of the specified menu section names
    in which entries should be added.  */
-
 struct spec_section
 {
   struct spec_section *next;
@@ -85,16 +67,16 @@ struct spec_section
   int missing;
 };
 
-/* This is used for a list of the entries specified to be added.  */
 
+/* This is used for a list of the entries specified to be added.  */
 struct spec_entry
 {
   struct spec_entry *next;
   char *text;
 };
-\f
-/* This is used for a list of nodes found by parsing the dir file.  */
 
+
+/* This is used for a list of nodes found by parsing the dir file.  */
 struct node
 {
   struct node *next;
@@ -115,9 +97,9 @@ struct node
   struct menu_section *last_section;
 };
 
+
 /* This is used for a list of sections found in a node's menu.
    Each  struct node  has such a list in the  sections  field.  */
-
 struct menu_section
 {
   struct menu_section *next;
@@ -131,7 +113,6 @@ struct menu_section
 /* Memory allocation and string operations.  */
 
 /* Like malloc but get fatal error if memory is exhausted.  */
-
 void *
 xmalloc (size)
      unsigned int size;
@@ -139,12 +120,11 @@ xmalloc (size)
   extern void *malloc ();
   void *result = malloc (size);
   if (result == NULL)
-    fatal ("virtual memory exhausted", 0);
+    fatal (_("virtual memory exhausted"), 0);
   return result;
 }
 
-/* Like malloc but get fatal error if memory is exhausted.  */
-
+/* Like realloc but get fatal error if memory is exhausted.  */
 void *
 xrealloc (obj, size)
      void *obj;
@@ -153,12 +133,12 @@ xrealloc (obj, size)
   extern void *realloc ();
   void *result = realloc (obj, size);
   if (result == NULL)
-    fatal ("virtual memory exhausted", 0);
+    fatal (_("virtual memory exhausted"), 0);
   return result;
 }
 
-/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
-
+/* Return a newly-allocated string
+   whose contents concatenate those of S1, S2, S3.  */
 char *
 concat (s1, s2, s3)
      char *s1, *s2, *s3;
@@ -192,7 +172,7 @@ copy_string (string, size)
 \f
 /* Error message functions.  */
 
-/* Print error message.  `s1' is printf control string, `s2' is arg for it. */
+/* Print error message.  S1 is printf control string, S2 and S3 args for it. */
 
 /* VARARGS1 */
 void
@@ -201,7 +181,7 @@ error (s1, s2, s3)
 {
   fprintf (stderr, "%s: ", progname);
   fprintf (stderr, s1, s2, s3);
-  fprintf (stderr, "\n");
+  putc ('\n', stderr);
 }
 
 /* VARARGS1 */
@@ -209,9 +189,9 @@ void
 warning (s1, s2, s3)
      char *s1, *s2, *s3;
 {
-  fprintf (stderr, "%s: Warning: ", progname);
+  fprintf (stderr, _("%s: warning: "), progname);
   fprintf (stderr, s1, s2, s3);
-  fprintf (stderr, "\n");
+  putc ('\n', stderr);
 }
 
 /* Print error message and exit.  */
@@ -230,7 +210,7 @@ void
 pfatal_with_name (name)
      char *name;
 {
-  char *s = concat ("", my_strerror (errno), " for %s");
+  char *s = concat ("", strerror (errno), _(" for %s"));
   fatal (s, name);
 }
 \f
@@ -299,7 +279,7 @@ extract_menu_file_name (item_text)
 void
 suggest_asking_for_help ()
 {
-  fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n",
+  fprintf (stderr, _("\tTry `%s --help' for a complete list of options.\n"),
            progname);
   exit (1);
 }
@@ -307,8 +287,9 @@ suggest_asking_for_help ()
 void
 print_help ()
 {
-  printf ("%s [OPTION]... [INFO-FILE [DIR-FILE]]\n\
-  Install INFO-FILE in the Info directory file DIR-FILE.\n\
+  printf (_("Usage: %s [OPTION]... [INFO-FILE [DIR-FILE]]\n\
+\n\
+Install INFO-FILE in the Info directory file DIR-FILE.\n\
 \n\
 Options:\n\
 --delete          Delete existing entries in INFO-FILE;\n\
@@ -336,28 +317,57 @@ Options:\n\
                     from information in the Info file itself.\n\
 --version         Display version information and exit.\n\
 \n\
-Email bug reports to bug-texinfo@prep.ai.mit.edu.\n\
-", progname);
+Email bug reports to bug-texinfo@gnu.org.\n\
+"), progname);
 }
 
-/* Convert an errno value into a string describing the error.
-   We define this function here rather than using strerror
-   because not all systems have strerror.  */
+\f
+/* If DIRFILE does not exist, create a minimal one (or abort).  If it
+   already exists, do nothing.  */
 
-char *
-my_strerror (errnum)
-     int errnum;
+void
+ensure_dirfile_exists (dirfile)
+     char *dirfile;
 {
-#ifdef HAVE_STRERROR
-  return strerror(errnum);
-#else
-  extern char *sys_errlist[];
-  extern int sys_nerr;
-
-  if (errnum >= 0 && errnum < sys_nerr)
-    return sys_errlist[errnum];
-  return (char *) "Unknown error";
-#endif
+  int desc = open (dirfile, O_RDONLY);
+  if (desc < 0 && errno == ENOENT)
+    {
+      FILE *f;
+      char *readerr = strerror (errno);
+      close (desc);
+      f = fopen (dirfile, "w");
+      if (f)
+        {
+          fputs (_("This is the file .../info/dir, which contains the\n\
+topmost node of the Info hierarchy, called (dir)Top.\n\
+The first time you invoke Info you start off looking at this node.\n\
+\1f\n\
+File: dir,\tNode: Top,\tThis is the top of the INFO tree\n\
+\n\
+  This (the Directory node) gives a menu of major topics.\n\
+  Typing \"q\" exits, \"?\" lists all Info commands, \"d\" returns here,\n\
+  \"h\" gives a primer for first-timers,\n\
+  \"mEmacs<Return>\" visits the Emacs manual, etc.\n\
+\n\
+  In Emacs, you can click mouse button 2 on a menu item or cross reference\n\
+  to select it.\n\
+\n\
+* Menu:\n\
+"), f);
+          if (fclose (f) < 0)
+            pfatal_with_name (dirfile);
+        }
+      else
+        {
+          /* Didn't exist, but couldn't open for writing.  */
+          fprintf (stderr,
+                   _("%s: could not read (%s) and could not create (%s)\n"),
+                   dirfile, readerr, strerror (errno));
+          exit (1);
+        }
+    }
+  else
+    close (desc); /* It already existed, so fine.  */
 }
 \f
 /* This table defines all the long-named options, says whether they
@@ -365,20 +375,22 @@ my_strerror (errnum)
 
 struct option longopts[] =
 {
-  { "delete",                   no_argument, NULL, 'r' },
-  { "dir-file",                 required_argument, NULL, 'd' },
-  { "entry",                    required_argument, NULL, 'e' },
-  { "help",                     no_argument, NULL, 'h' },
-  { "info-dir",                 required_argument, NULL, 'D' },
-  { "info-file",                required_argument, NULL, 'i' },
-  { "item",                     required_argument, NULL, 'e' },
-  { "quiet",                    no_argument, NULL, 'q' },
-  { "remove",                   no_argument, NULL, 'r' },
-  { "section",                  required_argument, NULL, 's' },
-  { "version",                  no_argument, NULL, 'V' },
+  { "delete",    no_argument, NULL, 'r' },
+  { "dir-file",  required_argument, NULL, 'd' },
+  { "entry",     required_argument, NULL, 'e' },
+  { "help",      no_argument, NULL, 'h' },
+  { "info-dir",  required_argument, NULL, 'D' },
+  { "info-file", required_argument, NULL, 'i' },
+  { "item",      required_argument, NULL, 'e' },
+  { "quiet",     no_argument, NULL, 'q' },
+  { "remove",    no_argument, NULL, 'r' },
+  { "section",   required_argument, NULL, 's' },
+  { "version",   no_argument, NULL, 'V' },
   { 0 }
 };
+
 \f
+int
 main (argc, argv)
      int argc;
      char **argv;
@@ -420,6 +432,15 @@ main (argc, argv)
 
   progname = argv[0];
 
+#ifdef HAVE_SETLOCALE
+  /* Set locale via LC_ALL.  */
+  setlocale (LC_ALL, "");
+#endif
+
+  /* Set the text message domain.  */
+  bindtextdomain (PACKAGE, LOCALEDIR);
+  textdomain (PACKAGE);
+
   while (1)
     {
       int opt = getopt_long (argc, argv, "i:d:e:s:hHr", longopts, 0);
@@ -440,7 +461,7 @@ main (argc, argv)
         case 'd':
           if (dirfile)
             {
-              fprintf (stderr, "%s: Specify the Info directory only once.\n",
+              fprintf (stderr, _("%s: Specify the Info directory only once.\n"),
                        progname);
               suggest_asking_for_help ();
             }
@@ -450,7 +471,7 @@ main (argc, argv)
         case 'D':
           if (dirfile)
             {
-              fprintf (stderr, "%s: Specify the Info directory only once.\n",
+              fprintf (stderr, _("%s: Specify the Info directory only once.\n"),
                        progname);
               suggest_asking_for_help ();
             }
@@ -478,7 +499,7 @@ main (argc, argv)
         case 'i':
           if (infile)
             {
-              fprintf (stderr, "%s: Specify the Info file only once.\n",
+              fprintf (stderr, _("%s: Specify the Info file only once.\n"),
                        progname);
               suggest_asking_for_help ();
             }
@@ -505,12 +526,13 @@ main (argc, argv)
           break;
 
         case 'V':
-          puts (INSTALL_INFO_VERSION_STRING);
-puts ("Copyright (C) 1996 Free Software Foundation, Inc.\n\
+          printf ("install-info (GNU %s) %s\n", PACKAGE, VERSION);
+         printf (_("Copyright (C) %s Free Software Foundation, Inc.\n\
 There is NO warranty.  You may redistribute this software\n\
 under the terms of the GNU General Public License.\n\
-For more information about these matters, see the files named COPYING.");
-              exit (0);
+For more information about these matters, see the files named COPYING.\n"),
+                 "1998");
+          exit (0);
 
         default:
           suggest_asking_for_help ();
@@ -525,13 +547,13 @@ For more information about these matters, see the files named COPYING.");
       else if (dirfile == 0)
         dirfile = argv[optind];
       else
-        error ("excess command line argument `%s'", argv[optind]);
+        error (_("excess command line argument `%s'"), argv[optind]);
     }
 
   if (!infile)
-    fatal ("No input file specified");
+    fatal (_("No input file specified; try --help for more information."));
   if (!dirfile)
-    fatal ("No dir file specified");
+    fatal (_("No dir file specified; try --help for more information."));
 
   /* Read the Info file and parse it into lines.  */
 
@@ -583,7 +605,7 @@ For more information about these matters, see the files named COPYING.");
               && sizeof ("START-INFO-DIR-ENTRY") - 1 == input_lines[i].size)
             {
               if (start_of_this_entry != 0)
-                fatal ("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY");
+                fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
               start_of_this_entry = input_lines[i + 1].start;
             }
           if (!strncmp ("END-INFO-DIR-ENTRY", input_lines[i].start,
@@ -602,18 +624,26 @@ For more information about these matters, see the files named COPYING.");
                   start_of_this_entry = 0;
                 }
               else
-                fatal ("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY");
+                fatal (_("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY"));
             }
         }
       if (start_of_this_entry != 0)
-        fatal ("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY");
+        fatal (_("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY"));
     }
 
   if (!delete_flag)
     if (entries_to_add == 0)
-      fatal ("no info dir entry in `%s'", infile);
+      { /* No need to abort here, the original info file may not have
+           the requisite Texinfo commands.  This is not something an
+           installer should have to correct (it's a problem for the
+           maintainer), and there's no need to cause subsequent parts of
+           `make install' to fail.  */
+        warning (_("no info dir entry in `%s'"), infile);
+        exit (0);
+      }
 
   /* Now read in the Info dir file.  */
+  ensure_dirfile_exists (dirfile);
   dir_data = readfile (dirfile, &dir_size);
   dir_lines = findlines (dir_data, dir_size, &dir_nlines);
 
@@ -622,7 +652,6 @@ For more information about these matters, see the files named COPYING.");
      .info suffix.  */
   {
     unsigned basename_len;
-    extern char *strrchr ();
     char *infile_basename = strrchr (infile, '/');
     if (infile_basename)
       infile_basename++;
@@ -743,8 +772,12 @@ For more information about these matters, see the files named COPYING.");
               if ((dir_lines[i].size
                    > (p - dir_lines[i].start + infilelen_sans_info))
                   && !strncmp (p, infile_sans_info, infilelen_sans_info)
-                  && p[infilelen_sans_info] == ')')
-                dir_lines[i].delete = 1;
+                  && (p[infilelen_sans_info] == ')'
+                      || !strncmp (p + infilelen_sans_info, ".info)", 6)))
+                {
+                  dir_lines[i].delete = 1;
+                  something_deleted = 1;
+                }
             }
         }
       /* Treat lines that start with whitespace
@@ -816,7 +849,7 @@ For more information about these matters, see the files named COPYING.");
                                                 dir_lines[i].start,
                                                 dir_lines[i].size)
                             && !dir_lines[i].delete)
-                          fatal ("menu item `%s' already exists, for file `%s'",
+                          fatal (_("menu item `%s' already exists, for file `%s'"),
                                  extract_menu_item_name (entry->text),
                                  extract_menu_file_name (dir_lines[i].start));
                         if (dir_lines[i].start[0] == '*'
@@ -839,7 +872,7 @@ For more information about these matters, see the files named COPYING.");
     }
 
   if (delete_flag && !something_deleted && !quiet_flag)
-    warning ("no entries found for `%s'; nothing deleted", infile);
+    warning (_("no entries found for `%s'; nothing deleted"), infile);
 
   /* Output the old dir file, interpolating the new sections
      and/or new entries where appropriate.  */
@@ -931,19 +964,49 @@ readfile (filename, sizep)
      char *filename;
      int *sizep;
 {
+  int desc;
   int data_size = 1024;
   char *data = (char *) xmalloc (data_size);
   int filled = 0;
   int nread = 0;
+#ifdef HAVE_LIBZ
+  int isGZ = 0;
+  gzFile zdesc;
+#endif
 
-  int desc = open (filename, O_RDONLY);
-
+  desc = open (filename, O_RDONLY);
   if (desc < 0)
     pfatal_with_name (filename);
 
+#ifdef HAVE_LIBZ
+  /* The file should always be two bytes long.  */
+  if (read (desc, data, 2) != 2)
+    pfatal_with_name (filename);
+
+  /* Undo that read.  */
+  lseek (desc, 0, SEEK_SET);
+
+  /* If we see gzip magic, use gzdopen. */
+  if (data[0] == '\x1f' && data[1] == '\x8b')
+    {
+      isGZ = 1;
+      zdesc = gzdopen (desc, "r");
+      if (zdesc == NULL) {
+        close (desc);
+        pfatal_with_name (filename);
+      }
+    }
+#endif /* HAVE_LIBZ */
+
   while (1)
     {
-      nread = read (desc, data + filled, data_size - filled);
+#ifdef HAVE_LIBZ
+      if (isGZ)
+       nread = gzread (zdesc, data + filled, data_size - filled);
+      else
+#endif
+        nread = read (desc, data + filled, data_size - filled);
+
       if (nread < 0)
         pfatal_with_name (filename);
       if (nread == 0)
@@ -958,6 +1021,14 @@ readfile (filename, sizep)
     }
 
   *sizep = filled;
+
+#ifdef HAVE_LIBZ
+  if (isGZ)
+    gzclose (zdesc);
+  else
+#endif
+    close(desc);
+
   return data;
 }
 \f