]>
Commit | Line | Data |
---|---|---|
00de59a6 | 1 | /* Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
6d52618b UD |
2 | This file is part of the GNU C Library. |
3 | Written by Ulrich Drepper, <drepper@gnu.ai.mit.edu>. | |
19bc17a9 | 4 | |
6d52618b UD |
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. | |
19bc17a9 | 9 | |
6d52618b UD |
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. | |
19bc17a9 | 14 | |
6d52618b UD |
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. */ | |
19bc17a9 RM |
19 | |
20 | #include <alloca.h> | |
0393dfd6 RM |
21 | #include <langinfo.h> |
22 | #include "localeinfo.h" | |
19bc17a9 RM |
23 | |
24 | #ifndef STRING_TYPE | |
25 | # error STRING_TYPE not defined | |
26 | #endif | |
27 | ||
28 | #ifndef USTRING_TYPE | |
29 | # error USTRING_TYPE not defined | |
30 | #endif | |
31 | ||
32 | typedef struct weight_t | |
33 | { | |
34 | struct weight_t *prev; | |
35 | struct weight_t *next; | |
0393dfd6 RM |
36 | struct data_pair |
37 | { | |
7a12c6bb | 38 | int number; |
0393dfd6 RM |
39 | const u_int32_t *value; |
40 | } data[0]; | |
19bc17a9 RM |
41 | } weight_t; |
42 | ||
43 | ||
6d52618b UD |
44 | /* The following five macros grant access to the values in the |
45 | collate locale file that do not depend on byte order. */ | |
c84142e8 UD |
46 | #ifndef USE_IN_EXTENDED_LOCALE_MODEL |
47 | # define collate_nrules \ | |
19bc17a9 | 48 | (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES)) |
c84142e8 | 49 | # define collate_hash_size \ |
19bc17a9 | 50 | (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_HASH_SIZE)) |
c84142e8 | 51 | # define collate_hash_layers \ |
19bc17a9 | 52 | (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_HASH_LAYERS)) |
c84142e8 | 53 | # define collate_undefined \ |
19bc17a9 | 54 | (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_UNDEFINED)) |
c84142e8 | 55 | # define collate_rules \ |
00de59a6 | 56 | ((u_int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_RULES)) |
19bc17a9 | 57 | |
19bc17a9 RM |
58 | static __inline int get_weight (const STRING_TYPE **str, weight_t *result); |
59 | static __inline int | |
60 | get_weight (const STRING_TYPE **str, weight_t *result) | |
c84142e8 UD |
61 | #else |
62 | # define collate_nrules \ | |
63 | current->values[_NL_ITEM_INDEX (_NL_COLLATE_NRULES)].word | |
64 | # define collate_hash_size \ | |
65 | current->values[_NL_ITEM_INDEX (_NL_COLLATE_HASH_SIZE)].word | |
66 | # define collate_hash_layers \ | |
67 | current->values[_NL_ITEM_INDEX (_NL_COLLATE_HASH_LAYERS)].word | |
68 | # define collate_undefined \ | |
69 | current->values[_NL_ITEM_INDEX (_NL_COLLATE_UNDEFINED)].word | |
70 | # define collate_rules \ | |
71 | ((u_int32_t *) current->values[_NL_ITEM_INDEX (_NL_COLLATE_RULES)].string) | |
72 | ||
73 | static __inline int get_weight (const STRING_TYPE **str, weight_t *result, | |
74 | struct locale_data *current, | |
75 | const u_int32_t *__collate_table, | |
76 | const u_int32_t *__collate_extra); | |
77 | static __inline int | |
78 | get_weight (const STRING_TYPE **str, weight_t *result, | |
79 | struct locale_data *current, const u_int32_t *__collate_table, | |
80 | const u_int32_t *__collate_extra) | |
81 | #endif | |
19bc17a9 RM |
82 | { |
83 | unsigned int ch = *((USTRING_TYPE *) (*str))++; | |
84 | size_t slot; | |
85 | ||
86 | if (sizeof (STRING_TYPE) == 1) | |
87 | slot = ch * (collate_nrules + 1); | |
88 | else | |
89 | { | |
90 | const size_t level_size = collate_hash_size * (collate_nrules + 1); | |
91 | size_t level; | |
92 | ||
00de59a6 | 93 | slot = (ch % collate_hash_size) * (collate_nrules + 1); |
19bc17a9 RM |
94 | |
95 | level = 0; | |
0393dfd6 | 96 | while (__collate_table[slot] != (u_int32_t) ch) |
19bc17a9 RM |
97 | { |
98 | if (__collate_table[slot + 1] == 0 | |
99 | || ++level >= collate_hash_layers) | |
100 | { | |
101 | size_t idx = collate_undefined; | |
102 | size_t cnt; | |
103 | ||
104 | for (cnt = 0; cnt < collate_nrules; ++cnt) | |
105 | { | |
106 | result->data[cnt].number = __collate_extra[idx++]; | |
107 | result->data[cnt].value = &__collate_extra[idx]; | |
108 | idx += result->data[cnt].number; | |
109 | } | |
110 | return 0; | |
111 | } | |
112 | slot += level_size; | |
113 | } | |
114 | } | |
115 | ||
503054c0 | 116 | if (__collate_table[slot + 1] != (u_int32_t) FORWARD_CHAR) |
19bc17a9 RM |
117 | { |
118 | /* We have a simple form. One one value for each weight. */ | |
119 | size_t cnt; | |
120 | ||
121 | for (cnt = 0; cnt < collate_nrules; ++cnt) | |
122 | { | |
123 | result->data[cnt].number = 1; | |
124 | result->data[cnt].value = &__collate_table[slot + 1 + cnt]; | |
125 | } | |
126 | return ch == 0; | |
127 | } | |
128 | ||
129 | /* We now look for any collation element which starts with CH. | |
130 | There might none, but the last list member is a catch-all case | |
131 | because it is simple the character CH. The value of this entry | |
132 | might be the same as UNDEFINED. */ | |
133 | slot = __collate_table[slot + 2]; | |
134 | ||
135 | while (1) | |
136 | { | |
137 | size_t idx; | |
138 | ||
7a12c6bb | 139 | /* This is a comparison between a u_int32_t array (aka wchar_t) and |
19bc17a9 RM |
140 | an 8-bit string. */ |
141 | for (idx = 0; __collate_extra[slot + 2 + idx] != 0; ++idx) | |
7e3be507 | 142 | if (__collate_extra[slot + 2 + idx] != (u_int32_t) (*str)[idx]) |
19bc17a9 RM |
143 | break; |
144 | ||
145 | /* When the loop finished with all character of the collation | |
146 | element used, we found the longest prefix. */ | |
147 | if (__collate_extra[slot + 2 + idx] == 0) | |
148 | { | |
149 | size_t cnt; | |
150 | ||
7e3be507 | 151 | *str += idx; |
19bc17a9 RM |
152 | idx += slot + 3; |
153 | for (cnt = 0; cnt < collate_nrules; ++cnt) | |
154 | { | |
155 | result->data[cnt].number = __collate_extra[idx++]; | |
156 | result->data[cnt].value = &__collate_extra[idx]; | |
157 | idx += result->data[cnt].number; | |
158 | } | |
159 | return 0; | |
160 | } | |
161 | ||
162 | /* To next entry in list. */ | |
163 | slot += __collate_extra[slot]; | |
164 | } | |
165 | /* NOTREACHED */ | |
166 | return 0; /* To calm down gcc. */ | |
167 | } | |
168 | ||
169 | ||
170 | /* To process a string efficiently we retrieve all information about | |
171 | the string at once. The following macro constructs a double linked | |
172 | list of this information. It is a macro because we use `alloca' | |
173 | and we use a double linked list because of the backward collation | |
c84142e8 UD |
174 | order. |
175 | ||
176 | We have this strange extra macro since the functions which use the | |
177 | given locale (not the global one) canot use the global tables. */ | |
178 | #ifndef USE_IN_EXTENDED_LOCALE_MODEL | |
179 | # define call_get_weight(strp, newp) get_weight ((strp), (newp)) | |
180 | #else | |
181 | # define call_get_weight(strp, newp) \ | |
182 | get_weight ((strp), (newp), current, collate_table, collate_extra) | |
183 | #endif | |
184 | ||
19bc17a9 RM |
185 | #define get_string(str, forw, backw) \ |
186 | do \ | |
187 | { \ | |
188 | weight_t *newp; \ | |
189 | do \ | |
190 | { \ | |
191 | newp = (weight_t *) alloca (sizeof (weight_t) \ | |
192 | + (collate_nrules \ | |
193 | * sizeof (struct data_pair))); \ | |
194 | \ | |
195 | newp->prev = backw; \ | |
196 | if (backw == NULL) \ | |
197 | forw = newp; \ | |
198 | else \ | |
199 | backw->next = newp; \ | |
200 | newp->next = NULL; \ | |
201 | backw = newp; \ | |
202 | } \ | |
c84142e8 | 203 | while (call_get_weight (&str, newp) == 0); \ |
19bc17a9 RM |
204 | } \ |
205 | while (0) |