Make fdwalk work when /proc isn't mounted
[kopensolaris-gnu/glibc.git] / catgets / gencat.c
index 0200ca4..d8ce7af 100644 (file)
@@ -1,24 +1,23 @@
-/* Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2005, 2006, 2007 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@redhat.com>, 1996.
 
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library 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; version 2 of the License, or
+   (at your option) any later version.
 
-   The GNU C Library is distributed in the hope that it will be useful,
+   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
-   Library General Public License for more details.
+   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 Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  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.  */
 
 #ifdef HAVE_CONFIG_H
-# include <config.h>
+# include "config.h"
 #endif
 
 #include <argp.h>
@@ -152,10 +151,11 @@ static void write_out (struct catalog *result, const char *output_name,
                       const char *header_name);
 static struct set_list *find_set (struct catalog *current, int number);
 static void normalize_line (const char *fname, size_t line, iconv_t cd,
-                           wchar_t *string, wchar_t quote_char);
+                           wchar_t *string, wchar_t quote_char,
+                           wchar_t escape_char);
 static void read_old (struct catalog *catalog, const char *file_name);
 static int open_conversion (const char *codesetp, iconv_t *cd_towcp,
-                           iconv_t *cd_tombp);
+                           iconv_t *cd_tombp, wchar_t *escape_charp);
 
 
 int
@@ -196,7 +196,7 @@ main (int argc, char *argv[])
   if (result != NULL)
     write_out (result, output_name, header_name);
 
-  return EXIT_SUCCESS;
+  return error_message_count != 0;
 }
 
 
@@ -230,7 +230,8 @@ more_help (int key, const char *text, void *input)
     case ARGP_KEY_HELP_EXTRA:
       /* We print some extra information.  */
       return strdup (gettext ("\
-Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n"));
+For bug reporting instructions, please see:\n\
+<http://www.gnu.org/software/libc/bugs.html>.\n"));
     default:
       break;
     }
@@ -246,7 +247,7 @@ print_version (FILE *stream, struct argp_state *state)
 Copyright (C) %s Free Software Foundation, Inc.\n\
 This is free software; see the source for copying conditions.  There is NO\n\
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2000");
+"), "2007");
   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
 }
 
@@ -272,6 +273,7 @@ read_input_file (struct catalog *current, const char *fname)
   size_t wbufsize;
   iconv_t cd_towc = (iconv_t) -1;
   iconv_t cd_tomb = (iconv_t) -1;
+  wchar_t escape_char = L'\\';
   char *codeset = NULL;
 
   if (strcmp (fname, "-") == 0 || strcmp (fname, "/dev/stdin") == 0)
@@ -323,15 +325,29 @@ read_input_file (struct catalog *current, const char *fname)
          ++line_number;
 
          /* It the line continued?  */
+         continued = 0;
          if (buf[act_len - 1] == '\n')
            {
              --act_len;
-             continued = buf[act_len - 1] == '\\';
-             if (continued)
-               --act_len;
+
+             /* There might be more than one backslash at the end of
+                the line.  Only if there is an odd number of them is
+                the line continued.  */
+             if (act_len > 0 && buf[act_len - 1] == '\\')
+               {
+                 int temp_act_len = act_len;
+
+                 do
+                   {
+                     --temp_act_len;
+                     continued = !continued;
+                   }
+                 while (temp_act_len > 0 && buf[temp_act_len - 1] == '\\');
+
+                 if (continued)
+                   --act_len;
+               }
            }
-         else
-           continued = 0;
 
          /* Append to currently selected line.  */
          obstack_grow (&current->mem_pool, buf, act_len);
@@ -522,7 +538,8 @@ this is the first definition"));
 
              /* We need the conversion.  */
              if (cd_towc == (iconv_t) -1
-                 && open_conversion (codeset, &cd_towc, &cd_tomb) != 0)
+                 && open_conversion (codeset, &cd_towc, &cd_tomb,
+                                     &escape_char) != 0)
                /* Something is wrong.  */
                goto out;
 
@@ -563,13 +580,14 @@ this is the first definition"));
       else if (isalnum (this_line[0]) || this_line[0] == '_')
        {
          const char *ident = this_line;
+         char *line = this_line;
          int message_number;
 
          do
-           ++this_line;
-         while (this_line[0] != '\0' && !isspace (this_line[0]));
-         if (this_line[0] != '\0')
-           *this_line++ = '\0';        /* Terminate the identifier.  */
+           ++line;
+         while (line[0] != '\0' && !isspace (line[0]));
+         if (line[0] != '\0')
+           *line++ = '\0';     /* Terminate the identifier.  */
 
          /* Now we found the beginning of the message itself.  */
 
@@ -595,11 +613,40 @@ this is the first definition"));
                {
                  /* Oh, oh.  There is already a message with this
                     number in the message set.  */
-                 error_at_line (0, 0, fname, start_line,
-                                gettext ("duplicated message number"));
-                 error_at_line (0, 0, runp->fname, runp->line,
-                                gettext ("this is the first definition"));
-                 message_number = 0;
+                 if (runp->symbol == NULL)
+                   {
+                     /* The existing message had its number specified
+                        by the user.  Fatal collision type uh, oh.  */
+                     error_at_line (0, 0, fname, start_line,
+                                    gettext ("duplicated message number"));
+                     error_at_line (0, 0, runp->fname, runp->line,
+                                    gettext ("this is the first definition"));
+                     message_number = 0;
+                   }
+                 else
+                   {
+                     /* Collision was with number auto-assigned to a
+                        symbolic.  Change existing symbolic number
+                        and move to end the list (if not already there).  */
+                     runp->number = ++current->current_set->last_message;
+
+                     if (runp->next != NULL)
+                       {
+                         struct message_list *endp;
+
+                         if (lastp == NULL)
+                           current->current_set->messages=runp->next;
+                         else
+                           lastp->next=runp->next;
+
+                         endp = runp->next;
+                         while (endp->next != NULL)
+                           endp = endp->next;
+
+                         endp->next = runp;
+                         runp->next = NULL;
+                       }
+                   }
                }
              ident = NULL;     /* We don't have a symbol.  */
 
@@ -644,11 +691,13 @@ duplicated message identifier"));
              char *outbuf;
              size_t outlen;
              struct message_list *newp;
-             size_t this_line_len = strlen (this_line) + 1;
+             size_t line_len = strlen (line) + 1;
+             size_t ident_len = 0;
 
              /* We need the conversion.  */
              if (cd_towc == (iconv_t) -1
-                 && open_conversion (codeset, &cd_towc, &cd_tomb) != 0)
+                 && open_conversion (codeset, &cd_towc, &cd_tomb,
+                                     &escape_char) != 0)
                /* Something is wrong.  */
                goto out;
 
@@ -658,8 +707,8 @@ duplicated message identifier"));
                 message is stateful.  */
              while (1)
                {
-                 inbuf = this_line;
-                 inlen = this_line_len;
+                 inbuf = line;
+                 inlen = line_len;
                  outbuf = (char *) wbuf;
                  outlen = wbufsize;
 
@@ -689,26 +738,31 @@ invalid character: message ignored"));
                  wbuf = (wchar_t *) xrealloc (wbuf, wbufsize);
                }
 
-             used = 1; /* Yes, we use the line.  */
-
              /* Strip quote characters, change escape sequences into
                 correct characters etc.  */
              normalize_line (fname, start_line, cd_towc, wbuf,
-                             current->quote_char);
+                             current->quote_char, escape_char);
+
+             if (ident)
+               ident_len = line - this_line;
 
              /* Now the string is free of escape sequences.  Convert it
                 back into a multibyte character string.  First free the
                 memory allocated for the original string.  */
              obstack_free (&current->mem_pool, this_line);
 
+             used = 1; /* Yes, we use the line.  */
+
              /* Now fill in the new string.  It should never happen that
                 the replaced string is longer than the original.  */
              inbuf = (char *) wbuf;
              inlen = (wcslen (wbuf) + 1) * sizeof (wchar_t);
 
              outlen = obstack_room (&current->mem_pool);
-             start_line = (char *) obstack_alloc (&current->mem_pool, outlen);
-             outbuf = start_line;
+             obstack_blank (&current->mem_pool, outlen);
+             this_line = (char *) obstack_base (&current->mem_pool);
+             outbuf = this_line + ident_len;
+             outlen -= ident_len;
 
              /* Flush the state.  */
              iconv (cd_tomb, NULL, NULL, NULL, NULL);
@@ -723,13 +777,14 @@ invalid character: message ignored"));
              assert (outbuf[-1] == '\0');
 
              /* Free the memory in the obstack we don't use.  */
-             obstack_free (&current->mem_pool, outbuf);
+             obstack_blank (&current->mem_pool, -(int) outlen);
+             line = obstack_finish (&current->mem_pool);
 
              newp = (struct message_list *) xmalloc (sizeof (*newp));
              newp->number = message_number;
-             newp->message = this_line;
+             newp->message = line + ident_len;
              /* Remember symbolic name; is NULL if no is given.  */
-             newp->symbol = ident;
+             newp->symbol = ident ? line : NULL;
              /* Remember where we found the character.  */
              newp->fname = fname;
              newp->line = start_line;
@@ -1053,7 +1108,7 @@ find_set (struct catalog *current, int number)
    and quote characters.  */
 static void
 normalize_line (const char *fname, size_t line, iconv_t cd, wchar_t *string,
-               wchar_t quote_char)
+               wchar_t quote_char, wchar_t escape_char)
 {
   int is_quoted;
   wchar_t *rp = string;
@@ -1072,7 +1127,7 @@ normalize_line (const char *fname, size_t line, iconv_t cd, wchar_t *string,
       /* We simply end the string when we find the first time an
         not-escaped quote character.  */
        break;
-    else if (*rp == L'\\')
+    else if (*rp == escape_char)
       {
        ++rp;
        if (quote_char != L'\0' && *rp == quote_char)
@@ -1106,10 +1161,6 @@ normalize_line (const char *fname, size_t line, iconv_t cd, wchar_t *string,
              *wp++ = L'\f';
              ++rp;
              break;
-           case L'\\':
-             *wp++ = L'\\';
-             ++rp;
-             break;
            case L'0' ... L'7':
              {
                int number;
@@ -1147,7 +1198,13 @@ normalize_line (const char *fname, size_t line, iconv_t cd, wchar_t *string,
              }
              break;
            default:
-             /* Simply ignore the backslash character.  */
+             if (*rp == escape_char)
+               {
+                 *wp++ = escape_char;
+                 ++rp;
+               }
+             else
+               /* Simply ignore the backslash character.  */;
              break;
            }
       }
@@ -1173,21 +1230,15 @@ read_old (struct catalog *catalog, const char *file_name)
   int last_set = -1;
   size_t cnt;
 
-  old_cat_obj.status = closed;
-  old_cat_obj.cat_name = file_name;
-  old_cat_obj.nlspath = NULL;
-  __libc_lock_init (old_cat_obj.lock);
-
   /* Try to open catalog, but don't look through the NLSPATH.  */
-  __open_catalog (&old_cat_obj);
-
-  if (old_cat_obj.status != mmapped && old_cat_obj.status != malloced)
+  if (__open_catalog (file_name, NULL, NULL, &old_cat_obj) != 0)
     {
       if (errno == ENOENT)
        /* No problem, the catalog simply does not exist.  */
        return;
       else
-       error (EXIT_FAILURE, errno, gettext ("while opening old catalog file"));
+       error (EXIT_FAILURE, errno,
+              gettext ("while opening old catalog file"));
     }
 
   /* OK, we have the catalog loaded.  Now read all messages and merge
@@ -1255,8 +1306,16 @@ read_old (struct catalog *catalog, const char *file_name)
 
 
 static int
-open_conversion (const char *codeset, iconv_t *cd_towcp, iconv_t *cd_tombp)
+open_conversion (const char *codeset, iconv_t *cd_towcp, iconv_t *cd_tombp,
+                wchar_t *escape_charp)
 {
+  char buf[2];
+  char *bufptr;
+  size_t bufsize;
+  wchar_t wbuf[2];
+  char *wbufptr;
+  size_t wbufsize;
+
   /* If the input file does not specify the codeset use the locale's.  */
   if (codeset == NULL)
     {
@@ -1277,5 +1336,30 @@ open_conversion (const char *codeset, iconv_t *cd_towcp, iconv_t *cd_tombp)
       return 1;
     }
 
+  /* One special case for historical reasons is the backslash
+     character.  In some codesets the byte value 0x5c is not mapped to
+     U005c in Unicode.  These charsets then don't have a backslash
+     character at all.  Therefore we have to live with whatever the
+     codeset provides and recognize, instead of the U005c, the character
+     the byte value 0x5c is mapped to.  */
+  buf[0] = '\\';
+  buf[1] = '\0';
+  bufptr = buf;
+  bufsize = 2;
+
+  wbufptr = (char *) wbuf;
+  wbufsize = sizeof (wbuf);
+
+  iconv (*cd_towcp, &bufptr, &bufsize, &wbufptr, &wbufsize);
+  if (bufsize != 0 || wbufsize != 0)
+    {
+      /* Something went wrong, we couldn't convert the byte 0x5c.  Go
+        on with using U005c.  */
+      error (0, 0, gettext ("cannot determine escape character"));
+      *escape_charp = L'\\';
+    }
+  else
+    *escape_charp = wbuf[0];
+
   return 0;
 }