15bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o/* Handle aliases for locale names.
2b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o   Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc.
35bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
4a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   This program is free software; you can redistribute it and/or modify it
5a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   under the terms of the GNU Library General Public License as published
6a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   by the Free Software Foundation; either version 2, or (at your option)
75bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o   any later version.
85bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
95bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o   This program is distributed in the hope that it will be useful,
105bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o   but WITHOUT ANY WARRANTY; without even the implied warranty of
11a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   Library General Public License for more details.
13a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
14a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   You should have received a copy of the GNU Library General Public
15a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   License along with this program; if not, write to the Free Software
16a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   USA.  */
18a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
19a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Tell glibc's <string.h> to provide a prototype for mempcpy().
20a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   This must come before <config.h> because <config.h> may include
21a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o   <features.h>, and once <features.h> has been included, it's too late.  */
22a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifndef _GNU_SOURCE
23a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define _GNU_SOURCE    1
24a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
255bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
265bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#ifdef HAVE_CONFIG_H
275bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o# include <config.h>
285bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#endif
295bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
305bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#include <ctype.h>
315bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#include <stdio.h>
32a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#if defined _LIBC || defined HAVE___FSETLOCKING
33a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# include <stdio_ext.h>
34a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
355bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#include <sys/types.h>
365bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
375bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#ifdef __GNUC__
38b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# undef alloca
395bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o# define alloca __builtin_alloca
405bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o# define HAVE_ALLOCA 1
415bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#else
42b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# ifdef _MSC_VER
43b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#  include <malloc.h>
44b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#  define alloca _alloca
455bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o# else
46b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#  if defined HAVE_ALLOCA_H || defined _LIBC
47b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#   include <alloca.h>
485bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#  else
49b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#   ifdef _AIX
50b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o #pragma alloca
51b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#   else
52b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#    ifndef alloca
535bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'ochar *alloca ();
54b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#    endif
555bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#   endif
565bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#  endif
575bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o# endif
585bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#endif
595bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
60a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include <stdlib.h>
61a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#include <string.h>
625bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
635bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#include "gettextP.h"
645bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
65b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#if ENABLE_RELOCATABLE
66b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# include "relocatable.h"
67b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#else
68b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# define relocate(pathname) (pathname)
69b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#endif
70b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o
715bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o/* @@ end of prolog @@ */
725bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
735bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#ifdef _LIBC
745bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o/* Rename the non ANSI C functions.  This is required by the standard
755bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o   because some ANSI C functions will require linking with this object
765bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o   file and the name space must not be polluted.  */
775bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o# define strcasecmp __strcasecmp
785bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
79a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# ifndef mempcpy
80a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#  define mempcpy __mempcpy
81a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# endif
825bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o# define HAVE_MEMPCPY	1
83a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define HAVE___FSETLOCKING	1
845bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
855bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o/* We need locking here since we can be called from different places.  */
865bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o# include <bits/libc-lock.h>
875bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
885bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o__libc_lock_define_initialized (static, lock);
895bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#endif
905bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
91a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifndef internal_function
92a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define internal_function
93a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
945bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
95a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* Some optimizations for glibc.  */
96a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef _LIBC
97a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define FEOF(fp)		feof_unlocked (fp)
98a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define FGETS(buf, n, fp)	fgets_unlocked (buf, n, fp)
99a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#else
100a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define FEOF(fp)		feof (fp)
101a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define FGETS(buf, n, fp)	fgets (buf, n, fp)
102a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
103a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
104a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o/* For those losing systems which don't have `alloca' we have to add
1055bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o   some additional code emulating it.  */
1065bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#ifdef HAVE_ALLOCA
107a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define freea(p) /* nothing */
1085bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#else
109a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define alloca(n) malloc (n)
110a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define freea(p) free (p)
111a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
112a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
113b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#if defined _LIBC_REENTRANT || HAVE_DECL_FGETS_UNLOCKED
114a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# undef fgets
115a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
116a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
117b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#if defined _LIBC_REENTRANT || HAVE_DECL_FEOF_UNLOCKED
118a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# undef feof
119a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o# define feof(s) feof_unlocked (s)
120a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
1215bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1225bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1235bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'ostruct alias_map
1245bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o{
1255bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  const char *alias;
1265bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  const char *value;
1275bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o};
1285bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1295bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
130b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#ifndef _LIBC
131b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o# define libc_freeres_ptr(decl) decl
132b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o#endif
133b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o
134b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'olibc_freeres_ptr (static char *string_space);
135a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic size_t string_space_act;
136a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic size_t string_space_max;
137b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'olibc_freeres_ptr (static struct alias_map *map);
138a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic size_t nmap;
139a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic size_t maxmap;
1405bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1415bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1425bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o/* Prototypes for local functions.  */
143b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ostatic size_t read_alias_file (const char *fname, int fname_len)
1445bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o     internal_function;
145b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ostatic int extend_alias_table (void);
146b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'ostatic int alias_compare (const struct alias_map *map1,
147b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o			  const struct alias_map *map2);
1485bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1495bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1505bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'oconst char *
151b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o_nl_expand_alias (const char *name)
1525bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o{
153a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  static const char *locale_alias_path;
1545bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  struct alias_map *retval;
1555bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  const char *result = NULL;
1565bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  size_t added;
1575bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1585bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#ifdef _LIBC
1595bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  __libc_lock_lock (lock);
1605bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#endif
1615bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
162a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  if (locale_alias_path == NULL)
163a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    locale_alias_path = LOCALE_ALIAS_PATH;
164a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
1655bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  do
1665bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o    {
1675bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      struct alias_map item;
1685bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1695bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      item.alias = name;
1705bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1715bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      if (nmap > 0)
1725bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	retval = (struct alias_map *) bsearch (&item, map, nmap,
1735bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o					       sizeof (struct alias_map),
174b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o					       (int (*) (const void *,
175b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o							 const void *)
1765bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o						) alias_compare);
1775bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      else
1785bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	retval = NULL;
1795bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1805bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      /* We really found an alias.  Return the value.  */
1815bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      if (retval != NULL)
1825bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	{
1835bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  result = retval->value;
1845bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  break;
1855bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	}
1865bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
1875bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      /* Perhaps we can find another alias file.  */
1885bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      added = 0;
1895bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      while (added == 0 && locale_alias_path[0] != '\0')
1905bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	{
1915bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  const char *start;
1925bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
193a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  while (locale_alias_path[0] == PATH_SEPARATOR)
1945bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	    ++locale_alias_path;
1955bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  start = locale_alias_path;
1965bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
197a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  while (locale_alias_path[0] != '\0'
198a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		 && locale_alias_path[0] != PATH_SEPARATOR)
1995bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	    ++locale_alias_path;
2005bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2015bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  if (start < locale_alias_path)
2025bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	    added = read_alias_file (start, locale_alias_path - start);
2035bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	}
2045bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o    }
2055bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  while (added != 0);
2065bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2075bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#ifdef _LIBC
2085bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  __libc_lock_unlock (lock);
2095bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#endif
2105bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2115bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  return result;
2125bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o}
2135bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2145bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2155bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'ostatic size_t
2165bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'ointernal_function
217b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'oread_alias_file (const char *fname, int fname_len)
2185bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o{
2195bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  FILE *fp;
2205bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  char *full_fname;
2215bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  size_t added;
2225bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  static const char aliasfile[] = "/locale.alias";
2235bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2245bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  full_fname = (char *) alloca (fname_len + sizeof aliasfile);
2255bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#ifdef HAVE_MEMPCPY
2265bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  mempcpy (mempcpy (full_fname, fname, fname_len),
2275bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	   aliasfile, sizeof aliasfile);
2285bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#else
2295bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  memcpy (full_fname, fname, fname_len);
2305bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
2315bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#endif
2325bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
233b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o  fp = fopen (relocate (full_fname), "r");
234a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  freea (full_fname);
2355bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  if (fp == NULL)
236a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    return 0;
237a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
238a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#ifdef HAVE___FSETLOCKING
239a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  /* No threads present.  */
240a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  __fsetlocking (fp, FSETLOCKING_BYCALLER);
241a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o#endif
2425bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2435bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  added = 0;
244a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  while (!FEOF (fp))
2455bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o    {
2465bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      /* It is a reasonable approach to use a fix buffer here because
2475bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	 a) we are only interested in the first two fields
2485bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	 b) these fields must be usable as file names and so must not
2495bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	    be that long
250b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	 We avoid a multi-kilobyte buffer here since this would use up
251b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	 stack space which we might not have if the program ran out of
252b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	 memory.  */
253b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o      char buf[400];
254a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      char *alias;
255a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      char *value;
256a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      char *cp;
2575bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
258a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      if (FGETS (buf, sizeof buf, fp) == NULL)
2595bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	/* EOF reached.  */
2605bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	break;
2615bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2625bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      cp = buf;
2635bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      /* Ignore leading white space.  */
264a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o      while (isspace ((unsigned char) cp[0]))
2655bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	++cp;
2665bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2675bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      /* A leading '#' signals a comment line.  */
2685bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      if (cp[0] != '\0' && cp[0] != '#')
2695bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	{
2705bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  alias = cp++;
271a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
2725bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	    ++cp;
2735bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  /* Terminate alias name.  */
2745bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  if (cp[0] != '\0')
2755bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	    *cp++ = '\0';
2765bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2775bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  /* Now look for the beginning of the value.  */
278a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	  while (isspace ((unsigned char) cp[0]))
2795bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	    ++cp;
2805bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2815bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	  if (cp[0] != '\0')
2825bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	    {
2835bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      size_t alias_len;
2845bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      size_t value_len;
2855bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
2865bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      value = cp++;
287a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o	      while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
2885bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		++cp;
2895bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      /* Terminate value.  */
2905bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      if (cp[0] == '\n')
2915bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		{
2925bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		  /* This has to be done to make the following test
2935bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		     for the end of line possible.  We are looking for
2945bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		     the terminating '\n' which do not overwrite here.  */
2955bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		  *cp++ = '\0';
2965bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		  *cp = '\n';
2975bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		}
2985bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      else if (cp[0] != '\0')
2995bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		*cp++ = '\0';
3005bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3015bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      if (nmap >= maxmap)
302a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		if (__builtin_expect (extend_alias_table (), 0))
303a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  return added;
3045bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3055bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      alias_len = strlen (alias) + 1;
3065bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      value_len = strlen (value) + 1;
3075bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3085bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      if (string_space_act + alias_len + value_len > string_space_max)
3095bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		{
3105bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		  /* Increase size of memory pool.  */
3115bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		  size_t new_size = (string_space_max
3125bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o				     + (alias_len + value_len > 1024
3135bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o					? alias_len + value_len : 1024));
3145bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		  char *new_pool = (char *) realloc (string_space, new_size);
3155bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		  if (new_pool == NULL)
316a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		    return added;
317a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
318a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		  if (__builtin_expect (string_space != new_pool, 0))
3195bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		    {
320a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      size_t i;
321a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
322a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o		      for (i = 0; i < nmap; i++)
323a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			{
324a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			  map[i].alias += new_pool - string_space;
325a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			  map[i].value += new_pool - string_space;
326a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o			}
3275bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		    }
328a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o
3295bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		  string_space = new_pool;
3305bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		  string_space_max = new_size;
3315bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o		}
3325bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3335bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      map[nmap].alias = memcpy (&string_space[string_space_act],
3345bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o					alias, alias_len);
3355bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      string_space_act += alias_len;
3365bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3375bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      map[nmap].value = memcpy (&string_space[string_space_act],
3385bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o					value, value_len);
3395bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      string_space_act += value_len;
3405bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3415bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      ++nmap;
3425bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	      ++added;
3435bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	    }
3445bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	}
345b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o
346b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o      /* Possibly not the whole line fits into the buffer.  Ignore
347b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	 the rest of the line.  */
348b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o      while (strchr (buf, '\n') == NULL)
349b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	if (FGETS (buf, sizeof buf, fp) == NULL)
350b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	  /* Make sure the inner loop will be left.  The outer loop
351b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	     will exit at the `feof' test.  */
352b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	  break;
3535bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o    }
3545bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3555bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  /* Should we test for ferror()?  I think we have to silently ignore
3565bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o     errors.  --drepper  */
3575bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  fclose (fp);
3585bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3595bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  if (added > 0)
3605bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o    qsort (map, nmap, sizeof (struct alias_map),
361b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'o	   (int (*) (const void *, const void *)) alias_compare);
3625bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3635bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  return added;
3645bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o}
3655bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3665bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
367a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'ostatic int
3685bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'oextend_alias_table ()
3695bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o{
3705bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  size_t new_size;
3715bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  struct alias_map *new_map;
3725bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3735bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  new_size = maxmap == 0 ? 100 : 2 * maxmap;
3745bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  new_map = (struct alias_map *) realloc (map, (new_size
3755bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o						* sizeof (struct alias_map)));
3765bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  if (new_map == NULL)
3775bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o    /* Simply don't extend: we don't have any more core.  */
378a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o    return -1;
3795bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3805bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  map = new_map;
3815bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  maxmap = new_size;
382a04eba3f8868af1d9b7b504d3d430c55ed3dc777Theodore Ts'o  return 0;
3835bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o}
3845bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3855bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3865bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'ostatic int
387b0cacab066000b940551d59aad3e4553d4bad268Theodore Ts'oalias_compare (const struct alias_map *map1, const struct alias_map *map2)
3885bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o{
3895bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#if defined _LIBC || defined HAVE_STRCASECMP
3905bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  return strcasecmp (map1->alias, map2->alias);
3915bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#else
3925bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  const unsigned char *p1 = (const unsigned char *) map1->alias;
3935bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  const unsigned char *p2 = (const unsigned char *) map2->alias;
3945bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  unsigned char c1, c2;
3955bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3965bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  if (p1 == p2)
3975bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o    return 0;
3985bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
3995bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  do
4005bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o    {
4015bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      /* I know this seems to be odd but the tolower() function in
4025bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	 some systems libc cannot handle nonalpha characters.  */
4035bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      c1 = isupper (*p1) ? tolower (*p1) : *p1;
4045bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      c2 = isupper (*p2) ? tolower (*p2) : *p2;
4055bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      if (c1 == '\0')
4065bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o	break;
4075bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      ++p1;
4085bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o      ++p2;
4095bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o    }
4105bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  while (c1 == c2);
4115bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o
4125bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o  return c1 - c2;
4135bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o#endif
4145bc5a89c2a5c07b0237c13d37d869c986b5435fbTheodore Ts'o}
415