* stdlib/strtol.c [_LIBC]: Define STDC_HEADERS.
[platform/upstream/linaro-glibc.git] / locale / locfile-parse.c
1 /* Copyright (C) 1995 Free Software Foundation, Inc.
2
3 The GNU C Library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Library General Public License as
5 published by the Free Software Foundation; either version 2 of the
6 License, or (at your option) any later version.
7
8 The GNU C Library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public
14 License along with the GNU C Library; see the file COPYING.LIB.  If
15 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
16 Cambridge, MA 02139, USA.  */
17
18 #include <assert.h>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <langinfo.h>
22 #include <libintl.h>
23 #include <limits.h>
24 #include <obstack.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <sys/uio.h>
31
32 #include "localedef.h"
33 #include "localeinfo.h"
34 #include "token.h"
35
36 /* We don't have these constants defined because we don't use them.  Give
37    default values.  */
38 #define CTYPE_MB_CUR_MIN 0
39 #define CTYPE_MB_CUR_MAX 0
40 #define CTYPE_HASH_SIZE 0
41 #define CTYPE_HASH_LAYERS 0
42 #define CTYPE_CLASS 0
43 #define CTYPE_TOUPPER_EB 0
44 #define CTYPE_TOLOWER_EB 0
45 #define CTYPE_TOUPPER_EL 0
46 #define CTYPE_TOLOWER_EL 0
47  
48
49 /* We have all categories defined in `categories.def'.  Now construct
50    the description and data structure used for all categories.  */
51 #define DEFINE_CATEGORY(category, name, items, postload, in, check, out)      \
52     struct cat_item category##_desc[] =                                       \
53       {                                                                       \
54         NO_PAREN items                                                        \
55       };                                                                      \
56                                                                               \
57     char *category##_values[NELEMS (category##_desc) - 1] = { NULL, };
58 #include "categories.def"
59 #undef DEFINE_CATEGORY
60
61 struct category category[] =
62   {
63 #define DEFINE_CATEGORY(category, name, items, postload, in, check, out)      \
64     [category] = { _NL_NUM_##category, name, NELEMS (category##_desc) - 1,    \
65                    category##_desc, category##_values, in, check, out },
66 #include "categories.def"
67 #undef DEFINE_CATEGORY
68   };
69 #define NCATEGORIES NELEMS (category)
70
71
72 #define SYNTAX_ERROR                                                          \
73     error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"),  \
74            locfile_data.filename, locfile_data.line_no)
75
76
77 /* Prototypes for local functions.  */
78 static int get_byte (char *byte_ptr);
79 static char *is_locale_name (int cat_no, const char *str, int len);
80
81
82 /* Read a locale definition file FILE.  The format is defined in
83    POSIX.2 2.5.3.  */
84 void
85 locfile_read (const char *fname)
86 {
87   /* Pointer to text of last token.  */
88   char *ptr;
89   /* Length of last token (or if NUMBER the value itself).  */
90   int len;
91   /* The last returned token.  */
92   int token;
93   /* For error correction we remember whether the last token was correct.  */
94   int correct_token = 1;
95
96   /* Open the desired input file on stdin.  */
97   locfile_open (fname);
98
99   while ((token = locfile_lex (&ptr, &len)) != 0)
100     {
101       int cat_no;
102
103       for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
104         if (token == category[cat_no].cat_id)
105           break;
106
107       if (cat_no >= NCATEGORIES)
108         /* A syntax error occured.  No valid category defintion starts.  */
109         {
110           if (correct_token != 0)
111             error (0, 0, gettext ("%s:%Zd: locale category start expected"),
112                    locfile_data.filename, locfile_data.line_no);
113
114           /* To prevent following errors mark as error case.  */
115           correct_token = 0;
116
117           /* Synchronization point is the beginning of a new category.
118              Overread all line upto this silently.  */
119           ignore_to_eol (0, 0);
120           continue;
121         }
122
123       /* Rest of the line should be empty.  */
124       ignore_to_eol (0, 1);
125
126       /* Perhaps these category is already specified.  We simply give a
127          warning and overwrite the values.  */
128       if (category[cat_no].filled != 0)
129         error (0, 0, gettext ("%s:%Zd: multiple definition of locale "
130                               "category %s"), locfile_data.filename,
131                locfile_data.line_no, category[cat_no].name);
132
133       /* We read the first token because this could be the copy statement.  */
134       token = xlocfile_lex (&ptr, &len);
135
136       if (token == TOK_COPY)
137         /* Copying the definitions from an existing locale is requested.  */
138         {
139           char *str;
140
141           /* Get the name of the locale to copy from.  */
142           token = xlocfile_lex (&ptr, &len);
143           if (token != TOK_IDENT && token != TOK_STRING)
144             /* No name, then mark error and ignore everything upto next
145                start of an category section.  */
146             {
147               /* To prevent following errors mark as error case.  */
148               correct_token = 0;
149
150               /* Synchronization point is the beginning of a new category.
151                  Overread all line upto this silently.  */
152               ignore_to_eol (0, 0);
153             }
154           else if ((str = is_locale_name (cat_no, ptr, len)) != NULL)
155             /* Yes the name really names an existing locale file.  We are
156                returned the complete file name.  Store it so that we can
157                copy it in the output phase.  */
158             {
159               category[cat_no].copy_locale = str;
160               category[cat_no].filled = 1;
161               
162               ignore_to_eol (0, 1);
163             }
164           else
165             /* No, the name does not address a valid locale file.  Mark
166                error case and ignore rest of category.  */
167             {
168               char tmp[len + 1];
169               memcpy (tmp, ptr, len);
170               tmp[len] = '\0';
171               error (0, 0, gettext ("%s:%Zd: invalid locale `%s' in copy "
172                                     "statement"), locfile_data.filename,
173                          locfile_data.line_no, tmp);
174               correct_token = 0;
175               ignore_to_eol (0, 0);
176             }
177
178           /* This should END as the next token.  */
179           token = xlocfile_lex (&ptr, &len);
180
181           if (token == TOK_END)
182             /* This is the end of the category.  */
183             {
184               token = xlocfile_lex (&ptr, &len);
185
186               if (token != category[cat_no].cat_id)
187                 /* Wrong category name after END.  */
188                 {
189                   error (0, 0, gettext ("%s:%Zd: category `%s' does not "
190                                         "end with `END %s'"),
191                          locfile_data.filename, locfile_data.line_no,
192                          category[cat_no].name, category[cat_no].name);
193                   ignore_to_eol (0, 0);
194                 }
195               else
196                 ignore_to_eol (0, 1);
197
198               correct_token = 1;
199             }
200           else
201             /* No END following copy.  Give error while not in error case.  */
202             {
203               if (correct_token != 0)
204                 error (0, 0, gettext ("%s:%Zd: `copy' must be sole rule"),
205                        locfile_data.filename, locfile_data.line_no);
206               correct_token = 0;
207               ignore_to_eol (0, 0);
208             }
209
210           continue;
211         }
212
213       /* Now it's time to mark as mentioned in the locale file.  */
214       category[cat_no].filled = 1;
215
216       if (category[cat_no].infct != NULL)
217         /* The category needs a special input handling.  */
218         {
219           category[cat_no].infct(token);
220           continue;
221         }
222
223       /* Now process the given items.  */
224       while (1)
225         {
226           int item_no;
227
228           if (token == TOK_END)
229             /* This is the end of the category.  */
230             {
231               token = xlocfile_lex (&ptr, &len);
232
233               if (token != category[cat_no].cat_id)
234                 {
235                   error (0, 0, gettext ("%s:%Zd: category `%s' does not end "
236                                         "with `END %s'"),
237                          locfile_data.filename, locfile_data.line_no,
238                          category[cat_no].name, category[cat_no].name);
239                   ignore_to_eol (0, 0);
240                 }
241               else
242                 ignore_to_eol (0, 1);
243
244               /* Start next category.  */
245               break;
246             }
247
248           /* All other lines should describe valid items of the category.  */
249           for (item_no = 0; item_no < category[cat_no].number; ++item_no)
250             if (category[cat_no].item_desc[item_no].item_id == token)
251               break;
252
253           if (item_no >= category[cat_no].number)
254             /* This is not a valid item of the category.  */
255             {
256               SYNTAX_ERROR;
257               ignore_to_eol (0, 0);
258
259               token = xlocfile_lex (&ptr, &len);
260
261               /* And process next item.  */
262               continue;
263             }
264
265           /* Test whether already a value is defined.  */
266           if (category[cat_no].item_value[item_no] != NULL)
267             error (0, 0, gettext ("%s:%Zd: category item `%s' already "
268                                   "defined"),
269                    locfile_data.filename, locfile_data.line_no,
270                    category[cat_no].item_desc[item_no].name);
271
272           switch (category[cat_no].item_desc[item_no].value_type)
273             {
274             case string:
275               /* Get next token.  This is the argument to the item.  */
276               token = xlocfile_lex (&ptr, &len);
277
278               if (token != TOK_STRING)
279                 SYNTAX_ERROR;
280               else
281                 category[cat_no].item_value[item_no] = strdup (ptr);
282               ignore_to_eol (0, ptr != NULL);
283               break;
284             case stringarray:
285               /* This is a difficult case.  The number of strings in
286                  the array may vary.  But for now its only necessary
287                  with ALT_DIGITS from LC_TIME.  This item is the last
288                  so be can solve it by storing the number of string in
289                  the first place and the string indeces following
290                  that.  */
291               {
292                 int cnt;
293                 char **buffer;
294                 if (category[cat_no].item_value[item_no] != NULL)
295                   buffer = (char **) category[cat_no].item_value[item_no];
296                 else
297                   buffer = (char **) xmalloc (
298                     sizeof (char *) * category[cat_no].item_desc[item_no].max);
299
300                 category[cat_no].item_value[item_no] = (char *) buffer;
301
302                 /* As explained we may need a place to store the real number
303                    of strings.  */
304                 if (category[cat_no].item_desc[item_no].min
305                     != category[cat_no].item_desc[item_no].max)
306                   ++buffer;
307
308                 cnt = 0;
309                 do
310                   {
311                     token = xlocfile_lex (&ptr, &len);
312                     if (token != TOK_STRING)
313                       {
314                         SYNTAX_ERROR;
315                         break;
316                       }
317
318                     if (cnt >= category[cat_no].item_desc[item_no].max)
319                       {
320                         error (0, 0, gettext ("%s:%Zd: too many elements "
321                                               "for item `%s`"),
322                                locfile_data.filename, locfile_data.line_no,
323                                category[cat_no].item_desc[item_no].name);
324                         break;
325                       }
326
327                     buffer[cnt++] = strdup (ptr);
328
329                     token = locfile_lex (&ptr, &len);
330                   }
331                 while (token == TOK_CHAR && len == ';');
332
333                 ignore_to_eol (token, ptr != NULL);
334
335                 if (cnt < category[cat_no].item_desc[item_no].min)
336                   error (0, 0, gettext ("%s:%Zd: too few elements for item "
337                                         "`%s'"),
338                          locfile_data.filename, locfile_data.line_no,
339                          category[cat_no].item_desc[item_no].name);
340
341                 if (category[cat_no].item_desc[item_no].min
342                     != category[cat_no].item_desc[item_no].max)
343                   *(int *) category[cat_no].item_value[item_no] = cnt;
344               }
345               break;
346             case byte:
347               {
348                 int ok;
349                 category[cat_no].item_value[item_no] = (char *) xmalloc (
350                   __alignof__ (char));
351                 ok = get_byte (category[cat_no].item_value[item_no]);
352                 ignore_to_eol (0, ok);
353               }
354               break;
355             case bytearray:
356               {
357                 char *buffer;
358                 int maxsize;
359                 int cnt;
360                 char byte;
361                 int ok;
362
363                 buffer = (char *) xmalloc ((maxsize = 30));
364                 cnt = 0;
365
366                 while ((ok = get_byte (&byte)))
367                   {
368                     if (cnt >= maxsize)
369                       buffer = (char *) xmalloc ((maxsize *= 2));
370
371                     buffer[cnt++] = byte;
372
373                     token = locfile_lex (&ptr, &len);
374                     if (token != TOK_CHAR || len != ';')
375                       break;
376                   }
377
378                 buffer[cnt] = '\0';
379                 category[cat_no].item_value[item_no] = buffer;
380                 ignore_to_eol (token, ok);
381               }
382               break;
383             default:
384               error (5, 0, gettext ("internal error in %s, line %u"),
385                      __FUNCTION__, __LINE__);
386               /* NOTREACHED */
387             }
388
389           /* Get next token.  */
390           token = xlocfile_lex (&ptr, &len);
391         } /* while (1) */
392     }
393 }
394
395
396 /* Check given values for categories for consistency.  */
397 void
398 categories_check (void)
399 {
400   int cat_no;
401
402   for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
403     if (category[cat_no].copy_locale == NULL)
404       if (category[cat_no].filled != 0)
405         if (category[cat_no].checkfct)
406           category[cat_no].checkfct();
407         else
408           {
409             int item_no;
410
411             for (item_no = 0; item_no < category[cat_no].number; ++item_no)
412               if (category[cat_no].item_value[item_no] == NULL)
413                 {
414                   int errcode;
415
416                   /* If the item is defined in the standard is it an error to
417                      have it not defined.  */
418                   errcode = category[cat_no].item_desc[item_no].status == std
419                             ? 5 : 0;
420
421                   error (errcode, 0, gettext ("item `%s' of category `%s' "
422                                               "undefined"),
423                          category[cat_no].item_desc[item_no].name,
424                          category[cat_no].name);
425                 }
426           }
427       else
428         error (0, 0, gettext ("category `%s' not defined"),
429                category[cat_no].name);
430 }
431
432
433 /* Write out the binary representation of the category data which can be
434    loaded by setlocale(1).  */
435 void
436 categories_write (void)
437 {
438   struct locale_file
439   {
440       int magic;
441       int n;
442       int idx[0];
443   } *data;
444   struct obstack obstk;
445   int cat_no;
446
447 #define obstack_chunk_alloc xmalloc
448 #define obstack_chunk_free free
449   obstack_init (&obstk);
450
451   for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
452     {
453       int result = 0;
454
455       if (category[cat_no].copy_locale != NULL)
456         /* Simply copy the addressed locale file of the specified
457            category.  Please note that this is tried before the distinction
458            between categories which need special handling is made.  */
459         {
460           int source;
461
462           /* Open source file.  */
463           source = open (category[cat_no].copy_locale, O_RDONLY);
464           if (source < 0)
465             error (0, 0, gettext ("cannot copy locale definition file `%s'"),
466                    category[cat_no].copy_locale);
467           else
468             {
469               /* Construct file name of output file and open for writing.  */
470               char path[strlen (output_path)
471                         + strlen(category[cat_no].name) + 1];
472               int dest;
473               char *t;
474
475               t = stpcpy (path, output_path);
476               strcpy (t, category[cat_no].name);
477
478               dest = creat (path, 0666);
479               if (dest == -1)
480                 error (0, 0, gettext ("cannot open output file `%s': %m"),
481                        path);
482               else
483                 {
484                   char buffer[BUFSIZ];
485                   int size;
486                   
487                   /* Copy the files.  */
488                   do
489                     {
490                       size = read (source, buffer, BUFSIZ);
491                       write (dest, buffer, size);
492                     }
493                   while (size > 0);
494
495                   close (dest);
496
497                   /* Show success.  */
498                   puts (category[cat_no].name);
499                 }
500               close (source);
501             }
502
503           /* Next category.   */
504           continue;
505         }
506
507       if (category[cat_no].outfct)
508         result = category[cat_no].outfct();
509       else
510         {
511           char *path, *t;
512           int fd;
513           struct iovec *iov;
514           int item_no, len, slen, cnt;
515           int elems = 0;
516
517           /* Count number of elements.  */
518           for (item_no = 0; item_no < category[cat_no].number; ++item_no)
519             {
520               switch (category[cat_no].item_desc[item_no].value_type)
521                 {
522                 case string:
523                 case byte:
524                 case bytearray:
525                   ++elems;
526                   break;
527                 case stringarray:
528                   elems += category[cat_no].item_desc[item_no].max;
529                   break;
530                 default:
531                   error (5, 0, gettext ("internal error in %s, line %u"),
532                          __FUNCTION__, __LINE__);
533                   /* NOTREACHED */
534                 }
535             }
536
537           /* We now have the number of elements.  We build the structure
538              and a helper structure for writing all out.  */
539           len = sizeof (struct locale_file) + elems * sizeof (int);
540           data = obstack_alloc (&obstk, len);
541           iov = obstack_alloc (&obstk, (elems + 1) * sizeof (struct iovec));
542
543           data->magic = LIMAGIC (cat_no);
544           data->n = elems;
545           iov[0].iov_base = data;
546           iov[0].iov_len = len;
547
548           cnt = 0;
549           for (item_no = 0; item_no < category[cat_no].number; ++item_no)
550             if (category[cat_no].item_value[item_no] == NULL)
551               {
552                 switch (category[cat_no].item_desc[item_no].value_type)
553                   {
554                   case string:
555                   case byte:
556                   case bytearray:
557                     data->idx[cnt] = len;
558                     ++len;  /* We reserve one single byte for this entry.  */
559                     iov[1 + cnt].iov_base = (char *) "";
560                     iov[1 + cnt].iov_len = 1;
561                     ++cnt;
562                     break;
563                   case stringarray:
564                     {
565                       int max;
566                       int nstr;
567
568                       max = category[cat_no].item_desc[item_no].max;
569
570                       for (nstr = 0; nstr < max; ++nstr)
571                         {
572                           data->idx[cnt] = len;
573                           ++len;
574                           iov[1 + cnt].iov_base = (char *) "";
575                           iov[1 + cnt].iov_len = 1;
576                           ++cnt;
577                         }
578                     }
579                   }
580               }
581             else
582               switch (category[cat_no].item_desc[item_no].value_type)
583                 {
584                 case string:
585                 case bytearray:
586                   data->idx[cnt] = len;
587                   slen = strlen (category[cat_no].item_value[item_no]) + 1;
588                   len += slen;
589                   iov[1 + cnt].iov_base = category[cat_no].item_value[item_no];
590                   iov[1 + cnt].iov_len = slen;
591                   ++cnt;
592                   break;
593                 case byte:
594                   data->idx[cnt] = len;
595                   slen = 1;
596                   len += slen;
597                   iov[1 + cnt].iov_base = category[cat_no].item_value[item_no];
598                   iov[1 + cnt].iov_len = slen;
599                   ++cnt;
600                   break;
601                 case stringarray:
602                   {
603                     int nstr, nact;
604                     char **first;
605                   
606                     if (category[cat_no].item_desc[item_no].min
607                         == category[cat_no].item_desc[item_no].max)
608                       {
609                         nstr = category[cat_no].item_desc[item_no].min;
610                         first = (char **) category[cat_no].item_value[item_no];
611                       }
612                     else
613                       {
614                         nstr = *(int *) category[cat_no].item_value[item_no];
615                         first =
616                           ((char **) category[cat_no].item_value[item_no]) + 1;
617                       }
618                     nact = nstr;
619                     while (nstr > 0)
620                       {
621                         data->idx[cnt] = len;
622                         if (*first != NULL)
623                           {
624                             slen = strlen (*first) + 1;
625                             iov[1 + cnt].iov_base = *first;
626                           }
627                         else
628                           {
629                             slen = 1;
630                             iov[1 + cnt].iov_base = (char *) "";
631                           }
632                         len += slen;
633                         iov[1 + cnt].iov_len = slen;
634                         ++cnt;
635                         ++first;
636                         --nstr;
637                       }
638                     while (nact < category[cat_no].item_desc[item_no].max)
639                       {
640                         data->idx[cnt] = len;
641                         len += 1;
642                         iov[1 + cnt].iov_base = (char *) "";
643                         iov[1 + cnt].iov_len = 1;
644                         ++cnt;
645                         ++nact;
646                       }
647                   }
648                   break;
649                 default:
650                   /* Cannot happen.  */
651                   break;
652                 }
653           assert (cnt <= elems);
654
655           /* Construct the output filename from the argument given to
656              localedef on the command line.  */
657           path = (char *) obstack_alloc (&obstk, strlen (output_path) +
658                                          2 * strlen (category[cat_no].name) + 5);
659           t = stpcpy (path, output_path);
660           strcpy (t, category[cat_no].name);
661
662           fd = creat (path, 0666);
663
664           if (fd == -1)
665             {
666               /* Check whether it failed because the named file is a directory.
667                  In that case we use the file .../LC_xxx/SYS_LC_xxx, as the
668                  loading functions of the C Library do.  */
669               struct stat st;
670
671               if (stat (path, &st) == 0 && S_ISDIR (st.st_mode))
672                 {
673                   stpcpy (stpcpy (strchr (path, '\0'), "/SYS_"),
674                           category[cat_no].name);
675                   fd = creat (path, 0666);
676                 }
677             }
678
679           if (fd == -1)
680             {
681               error (0, 0, gettext ("cannot open output file `%s': %m"),
682                      path);
683               result = 1;
684             }
685           else
686             {
687               if (writev (fd, iov, cnt + 1) == -1)
688                 {
689                   error (0, 0, gettext ("cannot write output file `%s': %m"),
690                          path);
691                   result = 1;
692                 }
693
694 if (elems==0) write(fd, &elems, 10);
695
696               close (fd);
697             }
698           /* The old data is not needed anymore, but keep the obstack
699              intact.  */
700           obstack_free (&obstk, data);
701         }
702
703       if (result == 0)
704         puts (category[cat_no].name);
705     }
706   /* Now the whole obstack can be removed.  */
707   obstack_free (&obstk, NULL);
708 }
709
710
711 /* Get the representation of a number.  This is a positive integer or
712    the number -1 which is handled as a special symbol by the scanner.  */
713 static int
714 get_byte (char *byte_ptr)
715 {
716   int token;
717   char *ptr;
718   int len;
719
720   token = locfile_lex (&ptr, &len);
721   if (token != TOK_NUMBER && token != TOK_MINUS1)
722     /* None of the valid number format.  */
723     {
724       error (0, 0, gettext ("%s:%Zd: number expected"),
725              locfile_data.filename, locfile_data.line_no);
726       *byte_ptr = 0;
727       return 0;
728     }
729
730   if (token == TOK_MINUS1)
731     {
732       *byte_ptr = CHAR_MAX;
733       return 1;
734     }
735
736   if (len > CHAR_MAX)
737     /* The value of the numbers has to be less than CHAR_MAX.  This is
738        ok for the information they have to express.  */
739     {
740       error (0, 0, gettext ("%s:%Zd: invalid number"),
741              locfile_data.filename, locfile_data.line_no);
742       *byte_ptr = 0;
743       return 0;
744     }
745
746   *byte_ptr = len;
747   return 1;
748 }
749
750
751 /* Test whether the string STR with length LEN is the name of an existing
752    locale and whether a file for category CAT_NO is found in this directory.
753    This categories are looked for in the system locale definition file
754    directory.
755    Return the complete file name for the category file.  */
756 static char *
757 is_locale_name (int cat_no, const char *str, int len)
758 {
759   static char **locale_names = NULL;
760   static int max_count = 0;
761   static int locale_count = 0;
762   int cnt, exist, fd;
763   char *fname;
764   struct stat st;
765
766   if (locale_names == NULL)
767     /* Read in the list of all available locales.  */
768     {
769       DIR *dir;
770       struct dirent *dirent;
771       
772       /* LOCALE_NAMES is not NULL anymore, but LOCALE_COUNT == 0.  */
773       ++locale_names;
774           
775       dir = opendir (LOCALE_PATH);
776       if (dir == NULL)
777         {
778           error (1, errno, gettext ("cannot read locale directory `%s'"),
779                  LOCALE_PATH);
780
781           return NULL;
782         }
783
784       /* Now we can look for all files in the directory.  */
785       while ((dirent = readdir (dir)) != NULL)
786         if (strcmp (dirent->d_name, ".") != 0
787             && strcmp (dirent->d_name, "..") != 0)
788           {
789             if (max_count == 0)
790               locale_names = (char **) xmalloc ((max_count = 10)
791                                                 * sizeof (char *));
792             else if (locale_count >= max_count)
793               locale_names = (char **) xrealloc (locale_names,
794                                                  (max_count *= 2)
795                                                  * sizeof (char *));
796             locale_names[locale_count++] = strdup (dirent->d_name);
797           }
798       closedir (dir);
799     }
800
801   for (cnt = 0; cnt < locale_count; ++cnt)
802     if (strncmp (str, locale_names[cnt], len) == 0
803         && locale_names[cnt][len] == '\0')
804       break;
805   
806   if (cnt >= locale_count)
807     return NULL;
808   
809   /* Now search for this specific locale file.  */
810   asprintf (&fname, "%s/%s/%s", LOCALE_PATH, locale_names[cnt],
811             category[cat_no].name);
812   
813   fd = open (fname, O_RDONLY);
814   if (fd < 0)
815     {
816       free (fname);
817       return NULL;
818     }
819   
820   exist = fstat (fd, &st);
821   close (fd);
822   
823   if (exist < 0)
824     {
825       free (fname);
826       return NULL;
827     }
828
829   return fname;
830 }
831
832 /*
833  * Local Variables:
834  *  mode:c
835  *  c-basic-offset:2
836  * End:
837  */