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