Skeleton for gconv module.
[kopensolaris-gnu/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   return GCONV_OK;
147 }
148 #endif
149
150
151 /* The default destructor function does nothing in the moment and so
152    be define it at all.  But we still provide the macro just in case
153    we need it some day.  */
154 #if DEFINE_FINI
155 #endif
156
157
158 /* This is the actual conversion function.  */
159 #ifndef FUNCTION_NAME
160 # define FUNCTION_NAME  gconv
161 #endif
162
163 int
164 FUNCTION_NAME (struct gconv_step *step, struct gconv_step_data *data,
165                const char **inbuf, const char *inbufend, size_t *written,
166                int do_flush)
167 {
168   struct gconv_step *next_step = step + 1;
169   struct gconv_step_data *next_data = data + 1;
170   gconv_fct fct = next_step->fct;
171   int status;
172
173   /* If the function is called with no input this means we have to reset
174      to the initial state.  The possibly partly converted input is
175      dropped.  */
176   if (do_flush)
177     {
178       /* Call the steps down the chain if there are any.  */
179       if (data->is_last)
180         status = GCONV_OK;
181       else
182         {
183 #ifdef EMIT_SHIFT_TO_INIT
184           status = GCONV_OK;
185
186           EMIT_SHIFT_TO_INIT;
187
188           if (status == GCONV_OK)
189 #endif
190             /* Give the modules below the same chance.  */
191             status = (*fct) (next_step, next_data, NULL, NULL, written, 1);
192         }
193     }
194   else
195     {
196       /* This variable is used to count the number of characters we
197          actually converted.  */
198       size_t converted = 0;
199
200       /* We preserve the initial values of the pointer variables.  */
201       const char *inptr = *inbuf;
202       char *outbuf = data->outbuf;
203       char *outend = data->outbufend;
204       char *outptr;
205
206       do
207         {
208           /* Remember the start value for this round.  */
209           inptr = *inbuf;
210           /* The outbuf buffer is empty.  */
211           outptr = outbuf;
212
213           /* Save the state.  */
214 #ifdef SAVE_RESET_STATE
215           SAVE_RESET_STATE (1);
216 #endif
217
218           if (FROM_DIRECTION)
219             /* Run the conversion loop.  */
220             status = FROM_LOOP ((const unsigned char **) inbuf,
221                                 (const unsigned char *) inbufend,
222                                 (unsigned char **) &outbuf,
223                                 (unsigned char *) outend,
224                                 data->statep, step->data, &converted);
225           else
226             /* Run the conversion loop.  */
227             status = TO_LOOP ((const unsigned char **) inbuf,
228                               (const unsigned char *) inbufend,
229                               (unsigned char **) &outbuf,
230                               (unsigned char *) outend,
231                               data->statep, step->data, &converted);
232
233           /* If this is the last step leave the loop, there is nothgin
234              we can do.  */
235           if (data->is_last)
236             {
237               /* Store information about how many bytes are available.  */
238               data->outbuf = outbuf;
239               break;
240             }
241
242           /* Write out all output which was produced.  */
243           if (outbuf > outptr)
244             {
245               const char *outerr = outbuf;
246               int result;
247
248               result = (*fct) (next_step, next_data, &outerr, outbuf,
249                                written, 0);
250
251               if (result != GCONV_EMPTY_INPUT)
252                 {
253                   if (outerr != outbuf)
254                     {
255 #ifdef RESET_INPUT_BUFFER
256                       RESET_INPUT_BUFFER;
257 #else
258                       /* We have a problem with the in on of the functions
259                          below.  Undo the conversion upto the error point.  */
260                       size_t nstatus;
261
262                       /* Reload the pointers.  */
263                       *inbuf = inptr;
264                       outbuf = outptr;
265
266                       /* Reset the state.  */
267 # ifdef SAVE_RESET_STATE
268                       SAVE_RESET_STATE (0);
269 # endif
270
271                       if (FROM_DIRECTION)
272                         /* Run the conversion loop.  */
273                         nstatus = FROM_LOOP ((const unsigned char **) inbuf,
274                                              (const unsigned char *) inbufend,
275                                              (unsigned char **) &outbuf,
276                                              (unsigned char *) outerr,
277                                              data->statep, step->data,
278                                              &converted);
279                       else
280                         /* Run the conversion loop.  */
281                         nstatus = TO_LOOP ((const unsigned char **) inbuf,
282                                            (const unsigned char *) inbufend,
283                                            (unsigned char **) &outbuf,
284                                            (unsigned char *) outerr,
285                                            data->statep, step->data,
286                                            &converted);
287
288                       /* We must run out of output buffer space in this
289                          rerun.  */
290                       assert (nstatus == GCONV_FULL_OUTPUT
291                               && outbuf == outerr);
292 #endif  /* reset input buffer */
293                     }
294
295                   /* Change the status.  */
296                   status = result;
297                 }
298               else
299                 /* All the output is consumed, we can make another run
300                    if everything was ok.  */
301                 if (status == GCONV_FULL_OUTPUT)
302                   status = GCONV_OK;
303             }
304         }
305       while (status == GCONV_OK);
306
307       /* Remember how many characters we converted.  */
308       *written += converted;
309     }
310
311   return status;
312 }
313
314 #undef DEFINE_INIT
315 #undef CHARSET_NAME
316 #undef DEFINE_FINI
317 #undef MIN_NEEDED_FROM
318 #undef MIN_NEEDED_TO
319 #undef MAX_NEEDED_FROM
320 #undef MAX_NEEDED_TO
321 #undef DEFINE_DIRECTION_OBJECTS
322 #undef FROM_DIRECTION
323 #undef EMIT_SHIFT_TO_INIT
324 #undef FROM_LOOP
325 #undef TO_LOOP
326 #undef RESET_STATE
327 #undef RESET_INPUT_BUFFER
328 #undef FUNCTION_NAME