1 /* Conversion to and from the various ISO 646 CCS.
2 Copyright (C) 1998 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library 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.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* The implementation of the conversion which can be performed by this
22 module are not very sophisticated and not tuned at all. There are
23 zillions of ISO 646 derivates and supporting them all in a separate
24 module is overkill since these coded character sets are hardly ever
25 used anymore (except ANSI_X3.4-1968 == ASCII, which is compatible
26 with ISO 8859-1). The European variants are superceded by the
27 various ISO 8859-? standards and the Asian variants are embedded in
28 larger character sets. Therefore this implementation is simply
29 here to make it possible to do the conversion if it is necessary.
30 The cost in the gconv-modules file is set to `2' and therefore
31 allows one to easily provide a tuned implementation in case this
32 proofs to be necessary. */
38 /* Direction of the transformation. */
49 US, /* ANSI_X3.4-1968 */
61 gconv_init (struct gconv_step *step, struct gconv_step_data *data)
63 /* Determine which direction. */
64 struct iso646_data *new_data;
69 if (strcasestr (step->from_name, "ANSI_X3.4-1968") != NULL)
74 else if (strcasestr (step->from_name, "BS_4730") != NULL)
79 else if (strcasestr (step->to_name, "ANSI_X3.4-1968") != NULL)
84 else if (strcasestr (step->to_name, "BS_4730") != NULL)
95 result = GCONV_NOCONV;
96 if (dir != illegal_dir
98 = (struct iso646_data *) malloc (sizeof (struct iso646_data)))
103 data->data = new_data;
112 gconv_end (struct gconv_step_data *data)
119 gconv (struct gconv_step *step, struct gconv_step_data *data,
120 const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
122 struct gconv_step *next_step = step + 1;
123 struct gconv_step_data *next_data = data + 1;
124 gconv_fct fct = next_step->fct;
128 /* If the function is called with no input this means we have to reset
129 to the initial state. The possibly partly converted input is
135 /* Call the steps down the chain if there are any. */
140 struct gconv_step *next_step = step + 1;
141 struct gconv_step_data *next_data = data + 1;
143 result = (*fct) (next_step, next_data, NULL, 0, written, 1);
145 /* Clear output buffer. */
146 data->outbufavail = 0;
151 enum direction dir = ((struct iso646_data *) data->data)->dir;
152 enum variant var = ((struct iso646_data *) data->data)->var;
160 if (dir == from_iso646)
162 size_t inchars = *inbufsize;
163 size_t outwchars = data->outbufavail;
164 char *outbuf = data->outbuf;
168 && (outwchars + sizeof (wchar_t) <= data->outbufsize))
170 switch ((unsigned char) inbuf[cnt])
174 *((wchar_t *) (outbuf + outwchars)) = 0xa3;
176 *((wchar_t *) (outbuf + outwchars)) = 0x23;
180 *((wchar_t *) (outbuf + outwchars)) = 0x203e;
182 *((wchar_t *) (outbuf + outwchars)) = 0x75;
185 *((wchar_t *) (outbuf + outwchars)) =
186 (unsigned char) inbuf[cnt];
187 case '\x80' ... '\xff':
188 /* Illegal character. */
189 result = GCONV_ILLEGAL_INPUT;
193 outwchars += sizeof (wchar_t);
198 data->outbufavail = outwchars;
202 size_t inwchars = *inbufsize;
203 size_t outchars = data->outbufavail;
204 unsigned char *outbuf = data->outbuf;
207 while (inwchars >= cnt + sizeof (wchar_t)
208 && outchars < data->outbufsize)
210 switch (*((wchar_t *) (inbuf + cnt)))
215 outbuf[outchars] = 0x23;
220 outbuf[outchars] = 0x75;
225 outbuf[outchars] = 0x23;
230 outbuf[outchars] = 0x75;
233 if (*((wchar_t *) (inbuf + cnt)) > 0x7f)
236 (unsigned char) *((wchar_t *) (inbuf + cnt));
242 cnt += sizeof (wchar_t);
246 data->outbufavail = outchars;
248 if (outchars < data->outbufsize)
250 /* If there is still room in the output buffer something
251 is wrong with the input. */
252 if (inwchars >= cnt + sizeof (wchar_t))
254 /* An error occurred. */
255 result = GCONV_ILLEGAL_INPUT;
260 /* There are some unprocessed bytes at the end of the
262 result = GCONV_INCOMPLETE_INPUT;
268 if (result != GCONV_OK)
273 /* This is the last step. */
274 result = (*inbufsize > (dir == from_iso646
275 ? 0 : sizeof (wchar_t) - 1)
276 ? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
281 result = GCONV_EMPTY_INPUT;
283 if (data->outbufavail > 0)
285 /* Call the functions below in the chain. */
286 size_t newavail = data->outbufavail;
288 result = (*fct) (next_step, next_data, data->outbuf, &newavail,
291 /* Correct the output buffer. */
292 if (newavail != data->outbufavail && newavail > 0)
294 memmove (data->outbuf,
295 &data->outbuf[data->outbufavail - newavail],
297 data->outbufavail = newavail;
301 while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
304 if (written != NULL && data->is_last)