xref: /netbsd-src/external/gpl2/grep/dist/intl/l10nflist.c (revision a8fa202a6440953be7b92a8960a811bff58203f4)
1 /*	$NetBSD: l10nflist.c,v 1.1.1.1 2016/01/10 21:36:18 christos Exp $	*/
2 
3 /* Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
4    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
5 
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU Library General Public License as published
8    by the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public
17    License along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19    USA.  */
20 
21 /* Tell glibc's <string.h> to provide a prototype for stpcpy().
22    This must come before <config.h> because <config.h> may include
23    <features.h>, and once <features.h> has been included, it's too late.  */
24 #ifndef _GNU_SOURCE
25 # define _GNU_SOURCE	1
26 #endif
27 
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31 
32 #include <string.h>
33 
34 #if defined _LIBC || defined HAVE_ARGZ_H
35 # include <argz.h>
36 #endif
37 #include <ctype.h>
38 #include <sys/types.h>
39 #include <stdlib.h>
40 
41 #include "loadinfo.h"
42 
43 /* On some strange systems still no definition of NULL is found.  Sigh!  */
44 #ifndef NULL
45 # if defined __STDC__ && __STDC__
46 #  define NULL ((void *) 0)
47 # else
48 #  define NULL 0
49 # endif
50 #endif
51 
52 /* @@ end of prolog @@ */
53 
54 #ifdef _LIBC
55 /* Rename the non ANSI C functions.  This is required by the standard
56    because some ANSI C functions will require linking with this object
57    file and the name space must not be polluted.  */
58 # ifndef stpcpy
59 #  define stpcpy(dest, src) __stpcpy(dest, src)
60 # endif
61 #else
62 # ifndef HAVE_STPCPY
63 static char *stpcpy PARAMS ((char *dest, const char *src));
64 # endif
65 #endif
66 
67 /* Define function which are usually not available.  */
68 
69 #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
70 /* Returns the number of strings in ARGZ.  */
71 static size_t argz_count__ PARAMS ((const char *argz, size_t len));
72 
73 static size_t
argz_count__(argz,len)74 argz_count__ (argz, len)
75      const char *argz;
76      size_t len;
77 {
78   size_t count = 0;
79   while (len > 0)
80     {
81       size_t part_len = strlen (argz);
82       argz += part_len + 1;
83       len -= part_len + 1;
84       count++;
85     }
86   return count;
87 }
88 # undef __argz_count
89 # define __argz_count(argz, len) argz_count__ (argz, len)
90 #endif	/* !_LIBC && !HAVE___ARGZ_COUNT */
91 
92 #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
93 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
94    except the last into the character SEP.  */
95 static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
96 
97 static void
argz_stringify__(argz,len,sep)98 argz_stringify__ (argz, len, sep)
99      char *argz;
100      size_t len;
101      int sep;
102 {
103   while (len > 0)
104     {
105       size_t part_len = strlen (argz);
106       argz += part_len;
107       len -= part_len + 1;
108       if (len > 0)
109 	*argz++ = sep;
110     }
111 }
112 # undef __argz_stringify
113 # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
114 #endif	/* !_LIBC && !HAVE___ARGZ_STRINGIFY */
115 
116 #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
117 static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
118 				  const char *entry));
119 
120 static char *
argz_next__(argz,argz_len,entry)121 argz_next__ (argz, argz_len, entry)
122      char *argz;
123      size_t argz_len;
124      const char *entry;
125 {
126   if (entry)
127     {
128       if (entry < argz + argz_len)
129         entry = strchr (entry, '\0') + 1;
130 
131       return entry >= argz + argz_len ? NULL : (char *) entry;
132     }
133   else
134     if (argz_len > 0)
135       return argz;
136     else
137       return 0;
138 }
139 # undef __argz_next
140 # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
141 #endif	/* !_LIBC && !HAVE___ARGZ_NEXT */
142 
143 
144 /* Return number of bits set in X.  */
145 static int pop PARAMS ((int x));
146 
147 static inline int
pop(x)148 pop (x)
149      int x;
150 {
151   /* We assume that no more than 16 bits are used.  */
152   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
153   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
154   x = ((x >> 4) + x) & 0x0f0f;
155   x = ((x >> 8) + x) & 0xff;
156 
157   return x;
158 }
159 
160 
161 struct loaded_l10nfile *
_nl_make_l10nflist(l10nfile_list,dirlist,dirlist_len,mask,language,territory,codeset,normalized_codeset,modifier,special,sponsor,revision,filename,do_allocate)162 _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
163 		    territory, codeset, normalized_codeset, modifier, special,
164 		    sponsor, revision, filename, do_allocate)
165      struct loaded_l10nfile **l10nfile_list;
166      const char *dirlist;
167      size_t dirlist_len;
168      int mask;
169      const char *language;
170      const char *territory;
171      const char *codeset;
172      const char *normalized_codeset;
173      const char *modifier;
174      const char *special;
175      const char *sponsor;
176      const char *revision;
177      const char *filename;
178      int do_allocate;
179 {
180   char *abs_filename;
181   struct loaded_l10nfile *last = NULL;
182   struct loaded_l10nfile *retval;
183   char *cp;
184   size_t entries;
185   int cnt;
186 
187   /* Allocate room for the full file name.  */
188   abs_filename = (char *) malloc (dirlist_len
189 				  + strlen (language)
190 				  + ((mask & TERRITORY) != 0
191 				     ? strlen (territory) + 1 : 0)
192 				  + ((mask & XPG_CODESET) != 0
193 				     ? strlen (codeset) + 1 : 0)
194 				  + ((mask & XPG_NORM_CODESET) != 0
195 				     ? strlen (normalized_codeset) + 1 : 0)
196 				  + (((mask & XPG_MODIFIER) != 0
197 				      || (mask & CEN_AUDIENCE) != 0)
198 				     ? strlen (modifier) + 1 : 0)
199 				  + ((mask & CEN_SPECIAL) != 0
200 				     ? strlen (special) + 1 : 0)
201 				  + (((mask & CEN_SPONSOR) != 0
202 				      || (mask & CEN_REVISION) != 0)
203 				     ? (1 + ((mask & CEN_SPONSOR) != 0
204 					     ? strlen (sponsor) + 1 : 0)
205 					+ ((mask & CEN_REVISION) != 0
206 					   ? strlen (revision) + 1 : 0)) : 0)
207 				  + 1 + strlen (filename) + 1);
208 
209   if (abs_filename == NULL)
210     return NULL;
211 
212   retval = NULL;
213   last = NULL;
214 
215   /* Construct file name.  */
216   memcpy (abs_filename, dirlist, dirlist_len);
217   __argz_stringify (abs_filename, dirlist_len, PATH_SEPARATOR);
218   cp = abs_filename + (dirlist_len - 1);
219   *cp++ = '/';
220   cp = stpcpy (cp, language);
221 
222   if ((mask & TERRITORY) != 0)
223     {
224       *cp++ = '_';
225       cp = stpcpy (cp, territory);
226     }
227   if ((mask & XPG_CODESET) != 0)
228     {
229       *cp++ = '.';
230       cp = stpcpy (cp, codeset);
231     }
232   if ((mask & XPG_NORM_CODESET) != 0)
233     {
234       *cp++ = '.';
235       cp = stpcpy (cp, normalized_codeset);
236     }
237   if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
238     {
239       /* This component can be part of both syntaces but has different
240 	 leading characters.  For CEN we use `+', else `@'.  */
241       *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
242       cp = stpcpy (cp, modifier);
243     }
244   if ((mask & CEN_SPECIAL) != 0)
245     {
246       *cp++ = '+';
247       cp = stpcpy (cp, special);
248     }
249   if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
250     {
251       *cp++ = ',';
252       if ((mask & CEN_SPONSOR) != 0)
253 	cp = stpcpy (cp, sponsor);
254       if ((mask & CEN_REVISION) != 0)
255 	{
256 	  *cp++ = '_';
257 	  cp = stpcpy (cp, revision);
258 	}
259     }
260 
261   *cp++ = '/';
262   stpcpy (cp, filename);
263 
264   /* Look in list of already loaded domains whether it is already
265      available.  */
266   last = NULL;
267   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
268     if (retval->filename != NULL)
269       {
270 	int compare = strcmp (retval->filename, abs_filename);
271 	if (compare == 0)
272 	  /* We found it!  */
273 	  break;
274 	if (compare < 0)
275 	  {
276 	    /* It's not in the list.  */
277 	    retval = NULL;
278 	    break;
279 	  }
280 
281 	last = retval;
282       }
283 
284   if (retval != NULL || do_allocate == 0)
285     {
286       free (abs_filename);
287       return retval;
288     }
289 
290   retval = (struct loaded_l10nfile *)
291     malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
292 				* (1 << pop (mask))
293 				* sizeof (struct loaded_l10nfile *)));
294   if (retval == NULL)
295     return NULL;
296 
297   retval->filename = abs_filename;
298   retval->decided = (__argz_count (dirlist, dirlist_len) != 1
299 		     || ((mask & XPG_CODESET) != 0
300 			 && (mask & XPG_NORM_CODESET) != 0));
301   retval->data = NULL;
302 
303   if (last == NULL)
304     {
305       retval->next = *l10nfile_list;
306       *l10nfile_list = retval;
307     }
308   else
309     {
310       retval->next = last->next;
311       last->next = retval;
312     }
313 
314   entries = 0;
315   /* If the DIRLIST is a real list the RETVAL entry corresponds not to
316      a real file.  So we have to use the DIRLIST separation mechanism
317      of the inner loop.  */
318   cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
319   for (; cnt >= 0; --cnt)
320     if ((cnt & ~mask) == 0
321 	&& ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
322 	&& ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
323       {
324 	/* Iterate over all elements of the DIRLIST.  */
325 	char *dir = NULL;
326 
327 	while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
328 	       != NULL)
329 	  retval->successor[entries++]
330 	    = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
331 				  language, territory, codeset,
332 				  normalized_codeset, modifier, special,
333 				  sponsor, revision, filename, 1);
334       }
335   retval->successor[entries] = NULL;
336 
337   return retval;
338 }
339 
340 /* Normalize codeset name.  There is no standard for the codeset
341    names.  Normalization allows the user to use any of the common
342    names.  The return value is dynamically allocated and has to be
343    freed by the caller.  */
344 const char *
_nl_normalize_codeset(codeset,name_len)345 _nl_normalize_codeset (codeset, name_len)
346      const char *codeset;
347      size_t name_len;
348 {
349   int len = 0;
350   int only_digit = 1;
351   char *retval;
352   char *wp;
353   size_t cnt;
354 
355   for (cnt = 0; cnt < name_len; ++cnt)
356     if (isalnum ((unsigned char) codeset[cnt]))
357       {
358 	++len;
359 
360 	if (isalpha ((unsigned char) codeset[cnt]))
361 	  only_digit = 0;
362       }
363 
364   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
365 
366   if (retval != NULL)
367     {
368       if (only_digit)
369 	wp = stpcpy (retval, "iso");
370       else
371 	wp = retval;
372 
373       for (cnt = 0; cnt < name_len; ++cnt)
374 	if (isalpha ((unsigned char) codeset[cnt]))
375 	  *wp++ = tolower ((unsigned char) codeset[cnt]);
376 	else if (isdigit ((unsigned char) codeset[cnt]))
377 	  *wp++ = codeset[cnt];
378 
379       *wp = '\0';
380     }
381 
382   return (const char *) retval;
383 }
384 
385 
386 /* @@ begin of epilog @@ */
387 
388 /* We don't want libintl.a to depend on any other library.  So we
389    avoid the non-standard function stpcpy.  In GNU C Library this
390    function is available, though.  Also allow the symbol HAVE_STPCPY
391    to be defined.  */
392 #if !_LIBC && !HAVE_STPCPY
393 static char *
stpcpy(dest,src)394 stpcpy (dest, src)
395      char *dest;
396      const char *src;
397 {
398   while ((*dest++ = *src++) != '\0')
399     /* Do nothing. */ ;
400   return dest - 1;
401 }
402 #endif
403