Starting fixing character set handling to handle multi-byte encodings.
[kopensolaris-gnu/glibc.git] / locale / programs / charset.c
1 /* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <alloca.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <limits.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "error.h"
33 #include "charset.h"
34
35
36 unsigned int
37 charset_find_value (const hash_table *ht, const char *name, size_t len)
38 {
39   void *result;
40
41   if (find_entry ((hash_table *) ht, name, len, &result) < 0)
42     return ILLEGAL_CHAR_VALUE;
43
44   return (unsigned int) ((unsigned long int) result);
45 }
46
47
48 void
49 charset_new_char (struct linereader *lr, hash_table *ht, int bytes,
50                   unsigned int value, const char *from, const char *to)
51 {
52   char *from_end;
53   char *to_end;
54   const char *cp;
55   char *buf;
56   int prefix_len, len1, len2;
57   unsigned int from_nr, to_nr, cnt;
58
59   if (to == NULL)
60     {
61       if (insert_entry (ht, from, strlen (from),
62                         (void *) (unsigned long int) value)
63           < 0)
64         lr_error (lr, _("duplicate character name `%s'"), from);
65
66       return;
67     }
68
69   /* We have a range: the names must have names with equal prefixes
70      and an equal number of digits, where the second number is greater
71      or equal than the first.  */
72   len1 = strlen (from);
73   len2 = strlen (to);
74
75   if (len1 != len2)
76     {
77     illegal_range:
78       lr_error (lr, _("illegal names for character range"));
79       return;
80     }
81
82   cp = &from[len1 - 1];
83   while (isdigit (*cp) && cp >= from)
84     --cp;
85
86   prefix_len = (cp - from) + 1;
87
88   if (cp == &from[len1 - 1] || strncmp (from, to, prefix_len) != 0)
89     goto illegal_range;
90
91   errno = 0;
92   from_nr = strtoul (&from[prefix_len], &from_end, 10);
93   if (*from_end != '\0' || (from_nr == ULONG_MAX && errno == ERANGE)
94       || ((to_nr = strtoul (&to[prefix_len], &to_end, 10)) == ULONG_MAX
95           && errno == ERANGE)
96       || *to_end != '\0')
97     {
98       lr_error (lr, _("<%s> and <%s> are illegal names for range"));
99       return;
100     }
101
102   if (from_nr > to_nr)
103     {
104       lr_error (lr, _("upper limit in range is not smaller then lower limit"));
105       return;
106     }
107
108   buf = alloca (len1 + 1);
109   memcpy (buf, from, prefix_len);
110
111   for (cnt = from_nr; cnt <= to_nr; ++cnt)
112     {
113       sprintf (&buf[prefix_len], "%0*d", len1 - prefix_len, cnt);
114
115       if (insert_entry (ht, buf, len1,
116                         (void *) (unsigned long int) (value + (cnt - from_nr)))
117           < 0)
118         lr_error (lr, _("duplicate character name `%s'"), buf);
119     }
120 }