Update.
[platform/upstream/glibc.git] / iconv / skeleton.c
1 /* Skeleton for a converison module.
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.
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 /* This file can be included to provide definitions of several things
22    many modules have in common.  It can be customized using the following
23    macros:
24
25      DEFINE_INIT        define the default initializer.  This requires the
26                         following symbol to be defined.
27
28      CHARSET_NAME       string with official name of the coded character
29                         set (in all-caps)
30
31      DEFINE_FINI        define the default destructor function.
32
33      MIN_NEEDED_FROM    minimal number of bytes needed for the from-charset.
34      MIN_NEEDED_TO      likewise for the to-charset.
35
36      MAX_NEEDED_FROM    maximal number of bytes needed for the from-charset.
37                         This macro is optional, it defaults to MIN_NEEDED_FROM.
38      MAX_NEEDED_TO      likewise for the to-charset.
39
40      DEFINE_DIRECTION_OBJECTS
41                         two objects will be defined to be used when the
42                         `gconv' function must only distinguish two
43                         directions.  This is implied by DEFINE_INIT.
44                         If this macro is not defined the following
45                         macro must be available.
46
47      FROM_DIRECTION     this macro is supposed to return a value != 0
48                         if we convert from the current character set,
49                         otherwise it return 0.
50
51      EMIT_SHIFT_TO_INIT this symbol is optional.  If it is defined it
52                         defines some code which writes out a sequence
53                         of characters which bring the current state into
54                         the initial state.
55
56      FROM_LOOP          name of the function implementing the conversion
57                         from the current characters.
58      TO_LOOP            likewise for the other direction
59
60      RESET_STATE        in case of an error we must reset the state for
61                         the rerun so this macro must be defined for
62                         stateful encodings.  It takes an argument which
63                         is nonzero when saving.
64
65      RESET_INPUT_BUFFER If the input character sets allow this the macro
66                         can be defined to reset the input buffer pointers
67                         to cover only those characters up to the error.
68
69      FUNCTION_NAME      if not set the conversion function is named `gconv'.
70  */
71
72 #include <assert.h>
73 #include <gconv.h>
74 #include <string.h>
75 #define __need_size_t
76 #define __need_NULL
77 #include <stddef.h>
78
79
80 /* The direction objects.  */
81 #if DEFINE_DIRECTION_OBJECTS || DEFINE_INIT
82 static int from_object;
83 static int to_object;
84
85 # ifndef FROM_DIRECTION
86 #  define FROM_DIRECTION step->data == &from_object
87 # endif
88 #else
89 # ifndef FROM_DIRECTION
90 #  error "FROM_DIRECTION must be provided if direction objects are not used"
91 # endif
92 #endif
93
94
95 /* How many bytes are needed at most for the from-charset.  */
96 #ifndef MAX_NEEDED_FROM
97 # define MAX_NEEDED_FROM        MIN_NEEDED_FROM
98 #endif
99
100 /* Same for the to-charset.  */
101 #ifndef MAX_NEEDED_TO
102 # define MAX_NEEDED_TO          MIN_NEEDED_TO
103 #endif
104
105
106 /* For conversions from a fixed width character sets to another fixed width
107    character set we we can define RESET_INPUT_BUFFER is necessary.  */
108 #if !defined RESET_INPUT_BUFFER && !defined SAVE_RESET_STATE
109 # if MIN_NEEDED_FROM == MAX_NEEDED_FROM && MIN_NEEDED_TO == MAX_NEEDED_TO
110 /* We have to used these `if's here since the compiler cannot know that
111    (outbuf - outerr) is always divisible by MIN_NEEDED_TO.  */
112 #  define RESET_INPUT_BUFFER \
113   if (MIN_NEEDED_FROM % MIN_NEEDED_TO == 0)                                   \
114     *inbuf -= (outbuf - outerr) * (MIN_NEEDED_FROM / MIN_NEEDED_TO);          \
115   else if (MIN_NEEDED_TO % MIN_NEEDED_FROM == 0)                              \
116     *inbuf -= (outbuf - outerr) / (MIN_NEEDED_TO / MIN_NEEDED_FROM);          \
117   else                                                                        \
118     *inbuf -= ((outbuf - outerr) / MIN_NEEDED_TO) * MIN_NEEDED_FROM
119 # endif
120 #endif
121
122
123 /* The default init function.  It simply matches the name and initializes
124    the step data to point to one of the objects above.  */
125 #if DEFINE_INIT
126 # ifndef CHARSET_NAME
127 #  error "CHARSET_NAME not defined"
128 # endif
129
130 int
131 gconv_init (struct gconv_step *step)
132 {
133   /* Determine which direction.  */
134   if (__strcasestr (step->from_name, CHARSET_NAME) != NULL)
135     step->data = &from_object;
136   else if (__strcasestr (step->to_name, CHARSET_NAME) != NULL)
137     step->data = &to_object;
138   else
139     return GCONV_NOCONV;
140
141   step->min_needed_from = MIN_NEEDED_FROM;
142   step->max_needed_from = MAX_NEEDED_FROM;
143   step->min_needed_to = MIN_NEEDED_TO;
144   step->max_needed_to = MAX_NEEDED_TO;
145
146 #ifdef RESET_STATE
147   step->stateful = 1;
148 #else
149   step->stateful = 0;
150 #endif
151
152   return GCONV_OK;
153 }
154 #endif
155
156
157 /* The default destructor function does nothing in the moment and so
158    be define it at all.  But we still provide the macro just in case
159    we need it some day.  */
160 #if DEFINE_FINI
161 #endif
162
163
164 /* This is the actual conversion function.  */
165 #ifndef FUNCTION_NAME
166 # define FUNCTION_NAME  gconv
167 #endif
168
169 int
170 FUNCTION_NAME (struct gconv_step *step, struct gconv_step_data *data,
171                const char **inbuf, const char *inbufend, size_t *written,
172                int do_flush)
173 {
174   struct gconv_step *next_step = step + 1;
175   struct gconv_step_data *next_data = data + 1;
176   gconv_fct fct = next_step->fct;
177   int status;
178
179   /* If the function is called with no input this means we have to reset
180      to the initial state.  The possibly partly converted input is
181      dropped.  */
182   if (do_flush)
183     {
184       /* Call the steps down the chain if there are any.  */
185       if (data->is_last)
186         status = GCONV_OK;
187       else
188         {
189 #ifdef EMIT_SHIFT_TO_INIT
190           status = GCONV_OK;
191
192           EMIT_SHIFT_TO_INIT;
193
194           if (status == GCONV_OK)
195 #endif
196             /* Give the modules below the same chance.  */
197             status = (*fct) (next_step, next_data, NULL, NULL, written, 1);
198         }
199     }
200   else
201     {
202       /* This variable is used to count the number of characters we
203          actually converted.  */
204       size_t converted = 0;
205       size_t last_converted;
206
207       /* We preserve the initial values of the pointer variables.  */
208       const char *inptr = *inbuf;
209       char *outbuf = data->outbuf;
210       char *outend = data->outbufend;
211       char *outptr;
212
213       do
214         {
215           /* Remember the start value for this round.  */
216           inptr = *inbuf;
217           /* The outbuf buffer is empty.  */
218           outptr = outbuf;
219
220           /* Save the state.  */
221           last_converted = converted;
222 #ifdef SAVE_RESET_STATE
223           SAVE_RESET_STATE (1);
224 #endif
225
226           if (FROM_DIRECTION)
227             /* Run the conversion loop.  */
228             status = FROM_LOOP ((const unsigned char **) inbuf,
229                                 (const unsigned char *) inbufend,
230                                 (unsigned char **) &outbuf,
231                                 (unsigned char *) outend,
232                                 data->statep, step->data, &converted);
233           else
234             /* Run the conversion loop.  */
235             status = TO_LOOP ((const unsigned char **) inbuf,
236                               (const unsigned char *) inbufend,
237                               (unsigned char **) &outbuf,
238                               (unsigned char *) outend,
239                               data->statep, step->data, &converted);
240
241           /* If this is the last step leave the loop, there is nothgin
242              we can do.  */
243           if (data->is_last)
244             {
245               /* Store information about how many bytes are available.  */
246               data->outbuf = outbuf;
247               break;
248             }
249
250           /* Write out all output which was produced.  */
251           if (outbuf > outptr)
252             {
253               const char *outerr = data->outbuf;
254               int result;
255
256               result = (*fct) (next_step, next_data, &outerr, outbuf,
257                                written, 0);
258
259               if (result != GCONV_EMPTY_INPUT)
260                 {
261                   if (outerr != outbuf)
262                     {
263 #ifdef RESET_INPUT_BUFFER
264                       RESET_INPUT_BUFFER;
265 #else
266                       /* We have a problem with the in on of the functions
267                          below.  Undo the conversion upto the error point.  */
268                       size_t nstatus;
269
270                       /* Reload the pointers.  */
271                       *inbuf = inptr;
272                       outbuf = outptr;
273
274                       /* Reset the state.  */
275                       converted = last_converted;
276 # ifdef SAVE_RESET_STATE
277                       SAVE_RESET_STATE (0);
278 # endif
279
280                       if (FROM_DIRECTION)
281                         /* Run the conversion loop.  */
282                         nstatus = FROM_LOOP ((const unsigned char **) inbuf,
283                                              (const unsigned char *) inbufend,
284                                              (unsigned char **) &outbuf,
285                                              (unsigned char *) outerr,
286                                              data->statep, step->data,
287                                              &converted);
288                       else
289                         /* Run the conversion loop.  */
290                         nstatus = TO_LOOP ((const unsigned char **) inbuf,
291                                            (const unsigned char *) inbufend,
292                                            (unsigned char **) &outbuf,
293                                            (unsigned char *) outerr,
294                                            data->statep, step->data,
295                                            &converted);
296
297                       /* We must run out of output buffer space in this
298                          rerun.  */
299                       assert (outbuf == outerr);
300                       assert (nstatus == GCONV_FULL_OUTPUT);
301 #endif  /* reset input buffer */
302                     }
303
304                   /* Change the status.  */
305                   status = result;
306                 }
307               else
308                 /* All the output is consumed, we can make another run
309                    if everything was ok.  */
310                 if (status == GCONV_FULL_OUTPUT)
311                   status = GCONV_OK;
312             }
313         }
314       while (status == GCONV_OK);
315
316       /* Remember how many characters we converted.  */
317       *written += converted;
318     }
319
320   return status;
321 }
322
323 #undef DEFINE_INIT
324 #undef CHARSET_NAME
325 #undef DEFINE_FINI
326 #undef MIN_NEEDED_FROM
327 #undef MIN_NEEDED_TO
328 #undef MAX_NEEDED_FROM
329 #undef MAX_NEEDED_TO
330 #undef DEFINE_DIRECTION_OBJECTS
331 #undef FROM_DIRECTION
332 #undef EMIT_SHIFT_TO_INIT
333 #undef FROM_LOOP
334 #undef TO_LOOP
335 #undef RESET_STATE
336 #undef RESET_INPUT_BUFFER
337 #undef FUNCTION_NAME