1*63eb84d1Schristos /* Handle aliases for locale names.
2*63eb84d1Schristos    Copyright (C) 1995-1999, 2000-2001, 2003, 2005 Free Software Foundation, Inc.
3*63eb84d1Schristos 
4*63eb84d1Schristos    This program is free software; you can redistribute it and/or modify it
5*63eb84d1Schristos    under the terms of the GNU Library General Public License as published
6*63eb84d1Schristos    by the Free Software Foundation; either version 2, or (at your option)
7*63eb84d1Schristos    any later version.
8*63eb84d1Schristos 
9*63eb84d1Schristos    This program is distributed in the hope that it will be useful,
10*63eb84d1Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
11*63eb84d1Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12*63eb84d1Schristos    Library General Public License for more details.
13*63eb84d1Schristos 
14*63eb84d1Schristos    You should have received a copy of the GNU Library General Public
15*63eb84d1Schristos    License along with this program; if not, write to the Free Software
16*63eb84d1Schristos    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17*63eb84d1Schristos    USA.  */
18*63eb84d1Schristos 
19*63eb84d1Schristos /* Tell glibc's <string.h> to provide a prototype for mempcpy().
20*63eb84d1Schristos    This must come before <config.h> because <config.h> may include
21*63eb84d1Schristos    <features.h>, and once <features.h> has been included, it's too late.  */
22*63eb84d1Schristos #ifndef _GNU_SOURCE
23*63eb84d1Schristos # define _GNU_SOURCE    1
24*63eb84d1Schristos #endif
25*63eb84d1Schristos 
26*63eb84d1Schristos #ifdef HAVE_CONFIG_H
27*63eb84d1Schristos # include <config.h>
28*63eb84d1Schristos #endif
29*63eb84d1Schristos 
30*63eb84d1Schristos #include <ctype.h>
31*63eb84d1Schristos #include <stdio.h>
32*63eb84d1Schristos #if defined _LIBC || defined HAVE___FSETLOCKING
33*63eb84d1Schristos # include <stdio_ext.h>
34*63eb84d1Schristos #endif
35*63eb84d1Schristos #include <sys/types.h>
36*63eb84d1Schristos 
37*63eb84d1Schristos #ifdef __GNUC__
38*63eb84d1Schristos # undef alloca
39*63eb84d1Schristos # define alloca __builtin_alloca
40*63eb84d1Schristos # define HAVE_ALLOCA 1
41*63eb84d1Schristos #else
42*63eb84d1Schristos # ifdef _MSC_VER
43*63eb84d1Schristos #  include <malloc.h>
44*63eb84d1Schristos #  define alloca _alloca
45*63eb84d1Schristos # else
46*63eb84d1Schristos #  if defined HAVE_ALLOCA_H || defined _LIBC
47*63eb84d1Schristos #   include <alloca.h>
48*63eb84d1Schristos #  else
49*63eb84d1Schristos #   ifdef _AIX
50*63eb84d1Schristos  #pragma alloca
51*63eb84d1Schristos #   else
52*63eb84d1Schristos #    ifndef alloca
53*63eb84d1Schristos char *alloca ();
54*63eb84d1Schristos #    endif
55*63eb84d1Schristos #   endif
56*63eb84d1Schristos #  endif
57*63eb84d1Schristos # endif
58*63eb84d1Schristos #endif
59*63eb84d1Schristos 
60*63eb84d1Schristos #include <stdlib.h>
61*63eb84d1Schristos #include <string.h>
62*63eb84d1Schristos 
63*63eb84d1Schristos #include "gettextP.h"
64*63eb84d1Schristos 
65*63eb84d1Schristos #if ENABLE_RELOCATABLE
66*63eb84d1Schristos # include "relocatable.h"
67*63eb84d1Schristos #else
68*63eb84d1Schristos # define relocate(pathname) (pathname)
69*63eb84d1Schristos #endif
70*63eb84d1Schristos 
71*63eb84d1Schristos /* @@ end of prolog @@ */
72*63eb84d1Schristos 
73*63eb84d1Schristos #ifdef _LIBC
74*63eb84d1Schristos /* Rename the non ANSI C functions.  This is required by the standard
75*63eb84d1Schristos    because some ANSI C functions will require linking with this object
76*63eb84d1Schristos    file and the name space must not be polluted.  */
77*63eb84d1Schristos # define strcasecmp __strcasecmp
78*63eb84d1Schristos 
79*63eb84d1Schristos # ifndef mempcpy
80*63eb84d1Schristos #  define mempcpy __mempcpy
81*63eb84d1Schristos # endif
82*63eb84d1Schristos # define HAVE_MEMPCPY	1
83*63eb84d1Schristos # define HAVE___FSETLOCKING	1
84*63eb84d1Schristos #endif
85*63eb84d1Schristos 
86*63eb84d1Schristos /* Handle multi-threaded applications.  */
87*63eb84d1Schristos #ifdef _LIBC
88*63eb84d1Schristos # include <bits/libc-lock.h>
89*63eb84d1Schristos #else
90*63eb84d1Schristos # include "lock.h"
91*63eb84d1Schristos #endif
92*63eb84d1Schristos 
93*63eb84d1Schristos #ifndef internal_function
94*63eb84d1Schristos # define internal_function
95*63eb84d1Schristos #endif
96*63eb84d1Schristos 
97*63eb84d1Schristos /* Some optimizations for glibc.  */
98*63eb84d1Schristos #ifdef _LIBC
99*63eb84d1Schristos # define FEOF(fp)		feof_unlocked (fp)
100*63eb84d1Schristos # define FGETS(buf, n, fp)	fgets_unlocked (buf, n, fp)
101*63eb84d1Schristos #else
102*63eb84d1Schristos # define FEOF(fp)		feof (fp)
103*63eb84d1Schristos # define FGETS(buf, n, fp)	fgets (buf, n, fp)
104*63eb84d1Schristos #endif
105*63eb84d1Schristos 
106*63eb84d1Schristos /* For those losing systems which don't have `alloca' we have to add
107*63eb84d1Schristos    some additional code emulating it.  */
108*63eb84d1Schristos #ifdef HAVE_ALLOCA
109*63eb84d1Schristos # define freea(p) /* nothing */
110*63eb84d1Schristos #else
111*63eb84d1Schristos # define alloca(n) malloc (n)
112*63eb84d1Schristos # define freea(p) free (p)
113*63eb84d1Schristos #endif
114*63eb84d1Schristos 
115*63eb84d1Schristos #if defined _LIBC_REENTRANT || HAVE_DECL_FGETS_UNLOCKED
116*63eb84d1Schristos # undef fgets
117*63eb84d1Schristos # define fgets(buf, len, s) fgets_unlocked (buf, len, s)
118*63eb84d1Schristos #endif
119*63eb84d1Schristos #if defined _LIBC_REENTRANT || HAVE_DECL_FEOF_UNLOCKED
120*63eb84d1Schristos # undef feof
121*63eb84d1Schristos # define feof(s) feof_unlocked (s)
122*63eb84d1Schristos #endif
123*63eb84d1Schristos 
124*63eb84d1Schristos 
125*63eb84d1Schristos __libc_lock_define_initialized (static, lock)
126*63eb84d1Schristos 
127*63eb84d1Schristos 
128*63eb84d1Schristos struct alias_map
129*63eb84d1Schristos {
130*63eb84d1Schristos   const char *alias;
131*63eb84d1Schristos   const char *value;
132*63eb84d1Schristos };
133*63eb84d1Schristos 
134*63eb84d1Schristos 
135*63eb84d1Schristos #ifndef _LIBC
136*63eb84d1Schristos # define libc_freeres_ptr(decl) decl
137*63eb84d1Schristos #endif
138*63eb84d1Schristos 
139*63eb84d1Schristos libc_freeres_ptr (static char *string_space);
140*63eb84d1Schristos static size_t string_space_act;
141*63eb84d1Schristos static size_t string_space_max;
142*63eb84d1Schristos libc_freeres_ptr (static struct alias_map *map);
143*63eb84d1Schristos static size_t nmap;
144*63eb84d1Schristos static size_t maxmap;
145*63eb84d1Schristos 
146*63eb84d1Schristos 
147*63eb84d1Schristos /* Prototypes for local functions.  */
148*63eb84d1Schristos static size_t read_alias_file (const char *fname, int fname_len)
149*63eb84d1Schristos      internal_function;
150*63eb84d1Schristos static int extend_alias_table (void);
151*63eb84d1Schristos static int alias_compare (const struct alias_map *map1,
152*63eb84d1Schristos 			  const struct alias_map *map2);
153*63eb84d1Schristos 
154*63eb84d1Schristos 
155*63eb84d1Schristos const char *
_nl_expand_alias(const char * name)156*63eb84d1Schristos _nl_expand_alias (const char *name)
157*63eb84d1Schristos {
158*63eb84d1Schristos   static const char *locale_alias_path;
159*63eb84d1Schristos   struct alias_map *retval;
160*63eb84d1Schristos   const char *result = NULL;
161*63eb84d1Schristos   size_t added;
162*63eb84d1Schristos 
163*63eb84d1Schristos   __libc_lock_lock (lock);
164*63eb84d1Schristos 
165*63eb84d1Schristos   if (locale_alias_path == NULL)
166*63eb84d1Schristos     locale_alias_path = LOCALE_ALIAS_PATH;
167*63eb84d1Schristos 
168*63eb84d1Schristos   do
169*63eb84d1Schristos     {
170*63eb84d1Schristos       struct alias_map item;
171*63eb84d1Schristos 
172*63eb84d1Schristos       item.alias = name;
173*63eb84d1Schristos 
174*63eb84d1Schristos       if (nmap > 0)
175*63eb84d1Schristos 	retval = (struct alias_map *) bsearch (&item, map, nmap,
176*63eb84d1Schristos 					       sizeof (struct alias_map),
177*63eb84d1Schristos 					       (int (*) (const void *,
178*63eb84d1Schristos 							 const void *)
179*63eb84d1Schristos 						) alias_compare);
180*63eb84d1Schristos       else
181*63eb84d1Schristos 	retval = NULL;
182*63eb84d1Schristos 
183*63eb84d1Schristos       /* We really found an alias.  Return the value.  */
184*63eb84d1Schristos       if (retval != NULL)
185*63eb84d1Schristos 	{
186*63eb84d1Schristos 	  result = retval->value;
187*63eb84d1Schristos 	  break;
188*63eb84d1Schristos 	}
189*63eb84d1Schristos 
190*63eb84d1Schristos       /* Perhaps we can find another alias file.  */
191*63eb84d1Schristos       added = 0;
192*63eb84d1Schristos       while (added == 0 && locale_alias_path[0] != '\0')
193*63eb84d1Schristos 	{
194*63eb84d1Schristos 	  const char *start;
195*63eb84d1Schristos 
196*63eb84d1Schristos 	  while (locale_alias_path[0] == PATH_SEPARATOR)
197*63eb84d1Schristos 	    ++locale_alias_path;
198*63eb84d1Schristos 	  start = locale_alias_path;
199*63eb84d1Schristos 
200*63eb84d1Schristos 	  while (locale_alias_path[0] != '\0'
201*63eb84d1Schristos 		 && locale_alias_path[0] != PATH_SEPARATOR)
202*63eb84d1Schristos 	    ++locale_alias_path;
203*63eb84d1Schristos 
204*63eb84d1Schristos 	  if (start < locale_alias_path)
205*63eb84d1Schristos 	    added = read_alias_file (start, locale_alias_path - start);
206*63eb84d1Schristos 	}
207*63eb84d1Schristos     }
208*63eb84d1Schristos   while (added != 0);
209*63eb84d1Schristos 
210*63eb84d1Schristos   __libc_lock_unlock (lock);
211*63eb84d1Schristos 
212*63eb84d1Schristos   return result;
213*63eb84d1Schristos }
214*63eb84d1Schristos 
215*63eb84d1Schristos 
216*63eb84d1Schristos static size_t
217*63eb84d1Schristos internal_function
read_alias_file(const char * fname,int fname_len)218*63eb84d1Schristos read_alias_file (const char *fname, int fname_len)
219*63eb84d1Schristos {
220*63eb84d1Schristos   FILE *fp;
221*63eb84d1Schristos   char *full_fname;
222*63eb84d1Schristos   size_t added;
223*63eb84d1Schristos   static const char aliasfile[] = "/locale.alias";
224*63eb84d1Schristos 
225*63eb84d1Schristos   full_fname = (char *) alloca (fname_len + sizeof aliasfile);
226*63eb84d1Schristos #ifdef HAVE_MEMPCPY
227*63eb84d1Schristos   mempcpy (mempcpy (full_fname, fname, fname_len),
228*63eb84d1Schristos 	   aliasfile, sizeof aliasfile);
229*63eb84d1Schristos #else
230*63eb84d1Schristos   memcpy (full_fname, fname, fname_len);
231*63eb84d1Schristos   memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
232*63eb84d1Schristos #endif
233*63eb84d1Schristos 
234*63eb84d1Schristos #ifdef _LIBC
235*63eb84d1Schristos   /* Note the file is opened with cancellation in the I/O functions
236*63eb84d1Schristos      disabled.  */
237*63eb84d1Schristos   fp = fopen (relocate (full_fname), "rc");
238*63eb84d1Schristos #else
239*63eb84d1Schristos   fp = fopen (relocate (full_fname), "r");
240*63eb84d1Schristos #endif
241*63eb84d1Schristos   freea (full_fname);
242*63eb84d1Schristos   if (fp == NULL)
243*63eb84d1Schristos     return 0;
244*63eb84d1Schristos 
245*63eb84d1Schristos #ifdef HAVE___FSETLOCKING
246*63eb84d1Schristos   /* No threads present.  */
247*63eb84d1Schristos   __fsetlocking (fp, FSETLOCKING_BYCALLER);
248*63eb84d1Schristos #endif
249*63eb84d1Schristos 
250*63eb84d1Schristos   added = 0;
251*63eb84d1Schristos   while (!FEOF (fp))
252*63eb84d1Schristos     {
253*63eb84d1Schristos       /* It is a reasonable approach to use a fix buffer here because
254*63eb84d1Schristos 	 a) we are only interested in the first two fields
255*63eb84d1Schristos 	 b) these fields must be usable as file names and so must not
256*63eb84d1Schristos 	    be that long
257*63eb84d1Schristos 	 We avoid a multi-kilobyte buffer here since this would use up
258*63eb84d1Schristos 	 stack space which we might not have if the program ran out of
259*63eb84d1Schristos 	 memory.  */
260*63eb84d1Schristos       char buf[400];
261*63eb84d1Schristos       char *alias;
262*63eb84d1Schristos       char *value;
263*63eb84d1Schristos       char *cp;
264*63eb84d1Schristos       int complete_line;
265*63eb84d1Schristos 
266*63eb84d1Schristos       if (FGETS (buf, sizeof buf, fp) == NULL)
267*63eb84d1Schristos 	/* EOF reached.  */
268*63eb84d1Schristos 	break;
269*63eb84d1Schristos 
270*63eb84d1Schristos       /* Determine whether the line is complete.  */
271*63eb84d1Schristos       complete_line = strchr (buf, '\n') != NULL;
272*63eb84d1Schristos 
273*63eb84d1Schristos       cp = buf;
274*63eb84d1Schristos       /* Ignore leading white space.  */
275*63eb84d1Schristos       while (isspace ((unsigned char) cp[0]))
276*63eb84d1Schristos 	++cp;
277*63eb84d1Schristos 
278*63eb84d1Schristos       /* A leading '#' signals a comment line.  */
279*63eb84d1Schristos       if (cp[0] != '\0' && cp[0] != '#')
280*63eb84d1Schristos 	{
281*63eb84d1Schristos 	  alias = cp++;
282*63eb84d1Schristos 	  while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
283*63eb84d1Schristos 	    ++cp;
284*63eb84d1Schristos 	  /* Terminate alias name.  */
285*63eb84d1Schristos 	  if (cp[0] != '\0')
286*63eb84d1Schristos 	    *cp++ = '\0';
287*63eb84d1Schristos 
288*63eb84d1Schristos 	  /* Now look for the beginning of the value.  */
289*63eb84d1Schristos 	  while (isspace ((unsigned char) cp[0]))
290*63eb84d1Schristos 	    ++cp;
291*63eb84d1Schristos 
292*63eb84d1Schristos 	  if (cp[0] != '\0')
293*63eb84d1Schristos 	    {
294*63eb84d1Schristos 	      value = cp++;
295*63eb84d1Schristos 	      while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
296*63eb84d1Schristos 		++cp;
297*63eb84d1Schristos 	      /* Terminate value.  */
298*63eb84d1Schristos 	      if (cp[0] == '\n')
299*63eb84d1Schristos 		{
300*63eb84d1Schristos 		  /* This has to be done to make the following test
301*63eb84d1Schristos 		     for the end of line possible.  We are looking for
302*63eb84d1Schristos 		     the terminating '\n' which do not overwrite here.  */
303*63eb84d1Schristos 		  *cp++ = '\0';
304*63eb84d1Schristos 		  *cp = '\n';
305*63eb84d1Schristos 		}
306*63eb84d1Schristos 	      else if (cp[0] != '\0')
307*63eb84d1Schristos 		*cp++ = '\0';
308*63eb84d1Schristos 
309*63eb84d1Schristos #ifdef IN_LIBGLOCALE
310*63eb84d1Schristos 	      /* glibc's locale.alias contains entries for ja_JP and ko_KR
311*63eb84d1Schristos 		 that make it impossible to use a Japanese or Korean UTF-8
312*63eb84d1Schristos 		 locale under the name "ja_JP" or "ko_KR".  Ignore these
313*63eb84d1Schristos 		 entries.  */
314*63eb84d1Schristos 	      if (strchr (alias, '_') == NULL)
315*63eb84d1Schristos #endif
316*63eb84d1Schristos 		{
317*63eb84d1Schristos 		  size_t alias_len;
318*63eb84d1Schristos 		  size_t value_len;
319*63eb84d1Schristos 
320*63eb84d1Schristos 		  if (nmap >= maxmap)
321*63eb84d1Schristos 		    if (__builtin_expect (extend_alias_table (), 0))
322*63eb84d1Schristos 		      goto out;
323*63eb84d1Schristos 
324*63eb84d1Schristos 		  alias_len = strlen (alias) + 1;
325*63eb84d1Schristos 		  value_len = strlen (value) + 1;
326*63eb84d1Schristos 
327*63eb84d1Schristos 		  if (string_space_act + alias_len + value_len > string_space_max)
328*63eb84d1Schristos 		    {
329*63eb84d1Schristos 		      /* Increase size of memory pool.  */
330*63eb84d1Schristos 		      size_t new_size = (string_space_max
331*63eb84d1Schristos 					 + (alias_len + value_len > 1024
332*63eb84d1Schristos 					    ? alias_len + value_len : 1024));
333*63eb84d1Schristos 		      char *new_pool = (char *) realloc (string_space, new_size);
334*63eb84d1Schristos 		      if (new_pool == NULL)
335*63eb84d1Schristos 			goto out;
336*63eb84d1Schristos 
337*63eb84d1Schristos 		      if (__builtin_expect (string_space != new_pool, 0))
338*63eb84d1Schristos 			{
339*63eb84d1Schristos 			  size_t i;
340*63eb84d1Schristos 
341*63eb84d1Schristos 			  for (i = 0; i < nmap; i++)
342*63eb84d1Schristos 			    {
343*63eb84d1Schristos 			      map[i].alias += new_pool - string_space;
344*63eb84d1Schristos 			      map[i].value += new_pool - string_space;
345*63eb84d1Schristos 			    }
346*63eb84d1Schristos 			}
347*63eb84d1Schristos 
348*63eb84d1Schristos 		      string_space = new_pool;
349*63eb84d1Schristos 		      string_space_max = new_size;
350*63eb84d1Schristos 		    }
351*63eb84d1Schristos 
352*63eb84d1Schristos 		  map[nmap].alias = memcpy (&string_space[string_space_act],
353*63eb84d1Schristos 					    alias, alias_len);
354*63eb84d1Schristos 		  string_space_act += alias_len;
355*63eb84d1Schristos 
356*63eb84d1Schristos 		  map[nmap].value = memcpy (&string_space[string_space_act],
357*63eb84d1Schristos 					    value, value_len);
358*63eb84d1Schristos 		  string_space_act += value_len;
359*63eb84d1Schristos 
360*63eb84d1Schristos 		  ++nmap;
361*63eb84d1Schristos 		  ++added;
362*63eb84d1Schristos 		}
363*63eb84d1Schristos 	    }
364*63eb84d1Schristos 	}
365*63eb84d1Schristos 
366*63eb84d1Schristos       /* Possibly not the whole line fits into the buffer.  Ignore
367*63eb84d1Schristos 	 the rest of the line.  */
368*63eb84d1Schristos       if (! complete_line)
369*63eb84d1Schristos 	do
370*63eb84d1Schristos 	  if (FGETS (buf, sizeof buf, fp) == NULL)
371*63eb84d1Schristos 	    /* Make sure the inner loop will be left.  The outer loop
372*63eb84d1Schristos 	       will exit at the `feof' test.  */
373*63eb84d1Schristos 	    break;
374*63eb84d1Schristos 	while (strchr (buf, '\n') == NULL);
375*63eb84d1Schristos     }
376*63eb84d1Schristos 
377*63eb84d1Schristos  out:
378*63eb84d1Schristos   /* Should we test for ferror()?  I think we have to silently ignore
379*63eb84d1Schristos      errors.  --drepper  */
380*63eb84d1Schristos   fclose (fp);
381*63eb84d1Schristos 
382*63eb84d1Schristos   if (added > 0)
383*63eb84d1Schristos     qsort (map, nmap, sizeof (struct alias_map),
384*63eb84d1Schristos 	   (int (*) (const void *, const void *)) alias_compare);
385*63eb84d1Schristos 
386*63eb84d1Schristos   return added;
387*63eb84d1Schristos }
388*63eb84d1Schristos 
389*63eb84d1Schristos 
390*63eb84d1Schristos static int
extend_alias_table()391*63eb84d1Schristos extend_alias_table ()
392*63eb84d1Schristos {
393*63eb84d1Schristos   size_t new_size;
394*63eb84d1Schristos   struct alias_map *new_map;
395*63eb84d1Schristos 
396*63eb84d1Schristos   new_size = maxmap == 0 ? 100 : 2 * maxmap;
397*63eb84d1Schristos   new_map = (struct alias_map *) realloc (map, (new_size
398*63eb84d1Schristos 						* sizeof (struct alias_map)));
399*63eb84d1Schristos   if (new_map == NULL)
400*63eb84d1Schristos     /* Simply don't extend: we don't have any more core.  */
401*63eb84d1Schristos     return -1;
402*63eb84d1Schristos 
403*63eb84d1Schristos   map = new_map;
404*63eb84d1Schristos   maxmap = new_size;
405*63eb84d1Schristos   return 0;
406*63eb84d1Schristos }
407*63eb84d1Schristos 
408*63eb84d1Schristos 
409*63eb84d1Schristos static int
alias_compare(const struct alias_map * map1,const struct alias_map * map2)410*63eb84d1Schristos alias_compare (const struct alias_map *map1, const struct alias_map *map2)
411*63eb84d1Schristos {
412*63eb84d1Schristos #if defined _LIBC || defined HAVE_STRCASECMP
413*63eb84d1Schristos   return strcasecmp (map1->alias, map2->alias);
414*63eb84d1Schristos #else
415*63eb84d1Schristos   const unsigned char *p1 = (const unsigned char *) map1->alias;
416*63eb84d1Schristos   const unsigned char *p2 = (const unsigned char *) map2->alias;
417*63eb84d1Schristos   unsigned char c1, c2;
418*63eb84d1Schristos 
419*63eb84d1Schristos   if (p1 == p2)
420*63eb84d1Schristos     return 0;
421*63eb84d1Schristos 
422*63eb84d1Schristos   do
423*63eb84d1Schristos     {
424*63eb84d1Schristos       /* I know this seems to be odd but the tolower() function in
425*63eb84d1Schristos 	 some systems libc cannot handle nonalpha characters.  */
426*63eb84d1Schristos       c1 = isupper (*p1) ? tolower (*p1) : *p1;
427*63eb84d1Schristos       c2 = isupper (*p2) ? tolower (*p2) : *p2;
428*63eb84d1Schristos       if (c1 == '\0')
429*63eb84d1Schristos 	break;
430*63eb84d1Schristos       ++p1;
431*63eb84d1Schristos       ++p2;
432*63eb84d1Schristos     }
433*63eb84d1Schristos   while (c1 == c2);
434*63eb84d1Schristos 
435*63eb84d1Schristos   return c1 - c2;
436*63eb84d1Schristos #endif
437*63eb84d1Schristos }
438