(Old-style number conversion): Correct some typos.
[kopensolaris-gnu/glibc.git] / iconvdata / iso8859-1.c
1 /* Conversion to and from ISO 8859-1.
2    Copyright (C) 1997 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
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.
10
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.
15
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.  */
20
21 #include <gconv.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 /* Direction of the transformation.  */
26 enum direction
27 {
28   illegal,
29   to_iso88591,
30   from_iso88591
31 };
32
33 struct iso88591_data
34 {
35   enum direction dir;
36 };
37
38
39 int
40 gconv_init (struct gconv_step *step, struct gconv_step_data *data)
41 {
42   /* Determine which direction.  */
43   struct iso88591_data *new_data;
44   enum direction dir;
45   int result;
46
47   if (__strcasestr (step->from_name, "ISO-8859-1") != NULL)
48     dir = from_iso88591;
49   else if (__strcasestr (step->to_name, "ISO-8859-1") != NULL)
50     dir = to_iso88591;
51   else
52     dir = illegal;
53
54   result = GCONV_NOCONV;
55   if (dir != illegal
56       && ((new_data
57            = (struct iso88591_data *) malloc (sizeof (struct iso88591_data)))
58           != NULL))
59     {
60       new_data->dir = dir;
61       data->data = new_data;
62       result = GCONV_OK;
63     }
64
65   return result;
66 }
67
68
69 void
70 gconv_end (struct gconv_step_data *data)
71 {
72   free (data->data);
73 }
74
75
76 int
77 gconv (struct gconv_step *step, struct gconv_step_data *data,
78        const char *inbuf, size_t *inbufsize, size_t *written, int do_flush)
79 {
80   struct gconv_step *next_step = step + 1;
81   struct gconv_step_data *next_data = data + 1;
82   gconv_fct fct = next_step->fct;
83   size_t do_write;
84   int result;
85
86   /* If the function is called with no input this means we have to reset
87      to the initial state.  The possibly partly converted input is
88      dropped.  */
89   if (do_flush)
90     {
91       do_write = 0;
92
93       /* Call the steps down the chain if there are any.  */
94       if (data->is_last)
95         result = GCONV_OK;
96       else
97         {
98           struct gconv_step *next_step = step + 1;
99           struct gconv_step_data *next_data = data + 1;
100
101           result = (*fct) (next_step, next_data, NULL, 0, written, 1);
102
103           /* Clear output buffer.  */
104           data->outbufavail = 0;
105         }
106     }
107   else
108     {
109       enum direction dir = ((struct iso88591_data *) data->data)->dir;
110
111       do_write = 0;
112
113       do
114         {
115           result = GCONV_OK;
116
117           if (dir == from_iso88591)
118             {
119               size_t inchars = *inbufsize;
120               size_t outwchars = data->outbufavail;
121               char *outbuf = data->outbuf;
122               size_t cnt = 0;
123
124               while (cnt < inchars
125                      && (outwchars + sizeof (wchar_t) <= data->outbufsize))
126                 {
127                   *((wchar_t *) (outbuf + outwchars)) = inbuf[cnt];
128                   ++do_write;
129                   outwchars += sizeof (wchar_t);
130                   ++cnt;
131                 }
132               *inbufsize -= cnt;
133               data->outbufavail = outwchars;
134             }
135           else
136             {
137               size_t inwchars = *inbufsize;
138               size_t outchars = data->outbufavail;
139               char *outbuf = data->outbuf;
140               size_t cnt = 0;
141
142               while (inwchars >= cnt + sizeof (wchar_t)
143                      && outchars < data->outbufsize)
144                 {
145                   if (*((wchar_t *) (inbuf + cnt)) >= L'\0'
146                       && *((wchar_t *) (inbuf + cnt)) <= L'\377')
147                     outbuf[outchars] = *((wchar_t *) (inbuf + cnt));
148                   else
149                     /* Here is where the transliteration would enter the
150                        scene.  */
151                     break;
152
153                   ++do_write;
154                   ++outchars;
155                   cnt += sizeof (wchar_t);
156                 }
157               *inbufsize -= cnt;
158               data->outbufavail = outchars;
159
160               if (outchars < data->outbufsize)
161                 {
162                   /* If there is still room in the output buffer something
163                      is wrong with the input.  */
164                   if (inwchars >= cnt + sizeof (wchar_t))
165                     {
166                       /* An error occurred.  */
167                       result = GCONV_ILLEGAL_INPUT;
168                       break;
169                     }
170                   if (inwchars != cnt)
171                     {
172                       /* There are some unprocessed bytes at the end of the
173                          input buffer.  */
174                       result = GCONV_INCOMPLETE_INPUT;
175                       break;
176                     }
177                 }
178             }
179
180           if (result != GCONV_OK)
181             break;
182
183           if (data->is_last)
184             {
185               /* This is the last step.  */
186               result = (*inbufsize > (dir == from_iso88591
187                                       ? 0 : sizeof (wchar_t) - 1)
188                         ? GCONV_FULL_OUTPUT : GCONV_EMPTY_INPUT);
189               break;
190             }
191
192           /* Status so far.  */
193           result = GCONV_EMPTY_INPUT;
194
195           if (data->outbufavail > 0)
196             {
197               /* Call the functions below in the chain.  */
198               size_t newavail = data->outbufavail;
199
200               result = (*fct) (next_step, next_data, data->outbuf, &newavail,
201                                written, 0);
202
203               /* Correct the output buffer.  */
204               if (newavail != data->outbufavail && newavail > 0)
205                 {
206                   memmove (data->outbuf,
207                            &data->outbuf[data->outbufavail - newavail],
208                            newavail);
209                   data->outbufavail = newavail;
210                 }
211             }
212         }
213       while (*inbufsize > 0 && result == GCONV_EMPTY_INPUT);
214     }
215
216   if (written != NULL && data->is_last)
217     *written = do_write;
218
219   return result;
220 }