iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / intl / gettext / bindtextdom.c
blob179528fa0f7a426e2b756d21c5b02ce538f06dd1
1 /* Implementation of the bindtextdomain(3) function
2 Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #include "elinks.h"
28 #include "intl/gettext/libintl.h"
29 #include "intl/gettext/gettextP.h"
30 #include "util/string.h"
32 /* Contains the default location of the message catalogs. */
33 extern const unsigned char _nl_default_dirname__[];
35 /* List with bindings of specific domains. */
36 extern struct binding *_nl_domain_bindings__;
38 /* Prototypes for local functions. */
39 static void set_binding_values(const unsigned char *domainname,
40 const unsigned char **dirnamep,
41 const unsigned char **codesetp);
43 /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
44 to be used for the DOMAINNAME message catalog.
45 If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
46 modified, only the current value is returned.
47 If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
48 modified nor returned. */
49 static void
50 set_binding_values(const unsigned char *domainname,
51 const unsigned char **dirnamep,
52 const unsigned char **codesetp)
54 struct binding *binding;
55 int modified;
57 /* Some sanity checks. */
58 if (domainname == NULL || domainname[0] == '\0') {
59 if (dirnamep)
60 *dirnamep = NULL;
61 if (codesetp)
62 *codesetp = NULL;
63 return;
66 modified = 0;
68 for (binding = _nl_domain_bindings__; binding != NULL;
69 binding = binding->next) {
70 int compare = strcmp(domainname, binding->domainname);
72 if (compare == 0)
73 /* We found it! */
74 break;
75 if (compare < 0) {
76 /* It is not in the list. */
77 binding = NULL;
78 break;
82 if (binding != NULL) {
83 if (dirnamep) {
84 const unsigned char *dirname = *dirnamep;
86 if (dirname == NULL)
87 /* The current binding has be to returned. */
88 *dirnamep = binding->dirname;
89 else {
90 /* The domain is already bound. If the new value and the old
91 one are equal we simply do nothing. Otherwise replace the
92 old binding. */
93 unsigned char *result = binding->dirname;
95 if (strcmp(dirname, result) != 0) {
96 if (strcmp(dirname, _nl_default_dirname__)
97 == 0)
98 result = (unsigned char *)
99 _nl_default_dirname__;
100 else {
101 result = strdup(dirname);
104 if (result != NULL) {
105 if (binding->dirname !=
106 _nl_default_dirname__)
107 free(binding->dirname);
109 binding->dirname = result;
110 modified = 1;
113 *dirnamep = result;
117 if (codesetp) {
118 const unsigned char *codeset = *codesetp;
120 if (codeset == NULL)
121 /* The current binding has be to returned. */
122 *codesetp = binding->codeset;
123 else {
124 /* The domain is already bound. If the new value and the old
125 one are equal we simply do nothing. Otherwise replace the
126 old binding. */
127 unsigned char *result = binding->codeset;
129 if (result == NULL
130 || strcmp(codeset, result) != 0) {
131 result = strdup(codeset);
133 if (result != NULL) {
134 if (binding->codeset != NULL)
135 free(binding->codeset);
137 binding->codeset = result;
138 binding->codeset_cntr++;
139 modified = 1;
142 *codesetp = result;
145 } else if ((dirnamep == NULL || *dirnamep == NULL)
146 && (codesetp == NULL || *codesetp == NULL)) {
147 /* Simply return the default values. */
148 if (dirnamep)
149 *dirnamep = _nl_default_dirname__;
150 if (codesetp)
151 *codesetp = NULL;
152 } else {
153 /* We have to create a new binding. */
154 size_t len = strlen(domainname) + 1;
155 struct binding *new_binding =
156 (struct binding *)
157 malloc(offsetof(struct binding, domainname) + len);
159 if (new_binding == NULL)
160 goto failed;
162 memcpy(new_binding->domainname, domainname, len);
164 if (dirnamep) {
165 const unsigned char *dirname = *dirnamep;
167 if (dirname == NULL)
168 /* The default value. */
169 dirname = _nl_default_dirname__;
170 else {
171 if (strcmp(dirname, _nl_default_dirname__) == 0)
172 dirname = _nl_default_dirname__;
173 else {
174 unsigned char *result;
176 result = strdup(dirname);
177 if (result == NULL)
178 goto failed_dirname;
179 dirname = result;
182 *dirnamep = dirname;
183 new_binding->dirname = (unsigned char *) dirname;
184 } else
185 /* The default value. */
186 new_binding->dirname = (unsigned char *) _nl_default_dirname__;
188 new_binding->codeset_cntr = 0;
190 if (codesetp) {
191 const unsigned char *codeset = *codesetp;
193 if (codeset != NULL) {
194 unsigned char *result;
196 result = strdup(codeset);
197 if (result == NULL)
198 goto failed_codeset;
199 codeset = result;
200 new_binding->codeset_cntr++;
202 *codesetp = codeset;
203 new_binding->codeset = (unsigned char *) codeset;
204 } else
205 new_binding->codeset = NULL;
207 /* Now enqueue it. */
208 if (_nl_domain_bindings__ == NULL
209 || strcmp(domainname, _nl_domain_bindings__->domainname) < 0)
211 new_binding->next = _nl_domain_bindings__;
212 _nl_domain_bindings__ = new_binding;
213 } else {
214 binding = _nl_domain_bindings__;
215 while (binding->next != NULL
216 && strcmp(domainname,
217 binding->next->domainname) > 0)
218 binding = binding->next;
220 new_binding->next = binding->next;
221 binding->next = new_binding;
224 modified = 1;
226 /* Here we deal with memory allocation failures. */
227 if (0) {
228 failed_codeset:
229 if (new_binding->dirname != _nl_default_dirname__)
230 free(new_binding->dirname);
231 failed_dirname:
232 free(new_binding);
233 failed:
234 if (dirnamep)
235 *dirnamep = NULL;
236 if (codesetp)
237 *codesetp = NULL;
241 /* If we modified any binding, we flush the caches. */
242 if (modified)
243 ++_nl_msg_cat_cntr;
247 /* Specify that the DOMAINNAME message catalog will be found
248 in DIRNAME rather than in the system locale data base. */
249 unsigned char *
250 bindtextdomain__(const unsigned char *domainname, const unsigned char *dirname)
252 set_binding_values(domainname, &dirname, NULL);
253 return (unsigned char *) dirname;
256 /* Specify the character encoding in which the messages from the
257 DOMAINNAME message catalog will be returned. */
258 unsigned char *
259 bind_textdomain_codeset__(const unsigned char *domainname, const unsigned char *codeset)
261 set_binding_values(domainname, NULL, &codeset);
262 return (unsigned char *) codeset;