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      PREPARE_LOOP       optional code preparing the conversion loop.  Can
72                         contain variable definitions.
73
74      EXTRA_LOOP_ARGS    optional macro specifying extra arguments passed
75                         to loop function.
76  */
77
78 #include <assert.h>
79 #include <gconv.h>
80 #include <string.h>
81 #define __need_size_t
82 #define __need_NULL
83 #include <stddef.h>
84
85
86 /* The direction objects.  */
87 #if DEFINE_DIRECTION_OBJECTS || DEFINE_INIT
88 static int from_object;
89 static int to_object;
90
91 # ifndef FROM_DIRECTION
92 #  define FROM_DIRECTION step->data == &from_object
93 # endif
94 #else
95 # ifndef FROM_DIRECTION
96 #  error "FROM_DIRECTION must be provided if direction objects are not used"
97 # endif
98 #endif
99
100
101 /* How many bytes are needed at most for the from-charset.  */
102 #ifndef MAX_NEEDED_FROM
103 # define MAX_NEEDED_FROM        MIN_NEEDED_FROM
104 #endif
105
106 /* Same for the to-charset.  */
107 #ifndef MAX_NEEDED_TO
108 # define MAX_NEEDED_TO          MIN_NEEDED_TO
109 #endif
110
111
112 /* For conversions from a fixed width character sets to another fixed width
113    character set we we can define RESET_INPUT_BUFFER is necessary.  */
114 #if !defined RESET_INPUT_BUFFER && !defined SAVE_RESET_STATE
115 # if MIN_NEEDED_FROM == MAX_NEEDED_FROM && MIN_NEEDED_TO == MAX_NEEDED_TO
116 /* We have to used these `if's here since the compiler cannot know that
117    (outbuf - outerr) is always divisible by MIN_NEEDED_TO.  */
118 #  define RESET_INPUT_BUFFER \
119   if (MIN_NEEDED_FROM % MIN_NEEDED_TO == 0)                                   \
120     *inbuf -= (outbuf - outerr) * (MIN_NEEDED_FROM / MIN_NEEDED_TO);          \
121   else if (MIN_NEEDED_TO % MIN_NEEDED_FROM == 0)                              \
122     *inbuf -= (outbuf - outerr) / (MIN_NEEDED_TO / MIN_NEEDED_FROM);          \
123   else                                                                        \
124     *inbuf -= ((outbuf - outerr) / MIN_NEEDED_TO) * MIN_NEEDED_FROM
125 # endif
126 #endif
127
128
129 /* The default init function.  It simply matches the name and initializes
130    the step data to point to one of the objects above.  */
131 #if DEFINE_INIT
132 # ifndef CHARSET_NAME
133 #  error "CHARSET_NAME not defined"
134 # endif
135
136 int
137 gconv_init (struct gconv_step *step)
138 {
139   /* Determine which direction.  */
140   if (__strcasecmp (step->from_name, CHARSET_NAME) == 0)
141     step->data = &from_object;
142   else if (__strcasecmp (step->to_name, CHARSET_NAME) == 0)
143     step->data = &to_object;
144   else
145     return GCONV_NOCONV;
146
147   step->min_needed_from = MIN_NEEDED_FROM;
148   step->max_needed_from = MAX_NEEDED_FROM;
149   step->min_needed_to = MIN_NEEDED_TO;
150   step->max_needed_to = MAX_NEEDED_TO;
151
152 #ifdef RESET_STATE
153   step->stateful = 1;
154 #else
155   step->stateful = 0;
156 #endif
157
158   return GCONV_OK;
159 }
160 #endif
161
162
163 /* The default destructor function does nothing in the moment and so
164    be define it at all.  But we still provide the macro just in case
165    we need it some day.  */
166 #if DEFINE_FINI
167 #endif
168
169
170 /* If no arguments have to passed to the loop function define the macro
171    as empty.  */
172 #ifndef EXTRA_LOOP_ARGS
173 # define EXTRA_LOOP_ARGS
174 #endif
175
176
177 /* This is the actual conversion function.  */
178 #ifndef FUNCTION_NAME
179 # define FUNCTION_NAME  gconv
180 #endif
181
182 int
183 FUNCTION_NAME (struct gconv_step *step, struct gconv_step_data *data,
184                const char **inbuf, const char *inbufend, size_t *written,
185                int do_flush)
186 {
187   struct gconv_step *next_step = step + 1;
188   struct gconv_step_data *next_data = data + 1;
189   gconv_fct fct = next_step->fct;
190   int status;
191
192   /* If the function is called with no input this means we have to reset
193      to the initial state.  The possibly partly converted input is
194      dropped.  */
195   if (do_flush)
196     {
197       /* Call the steps down the chain if there are any.  */
198       if (data->is_last)
199         status = GCONV_OK;
200       else
201         {
202 #ifdef EMIT_SHIFT_TO_INIT
203           status = GCONV_OK;
204
205           EMIT_SHIFT_TO_INIT;
206
207           if (status == GCONV_OK)
208 #endif
209             /* Give the modules below the same chance.  */
210             status = (*fct) (next_step, next_data, NULL, NULL, written, 1);
211         }
212     }
213   else
214     {
215       /* This variable is used to count the number of characters we
216          actually converted.  */
217       size_t converted = 0;
218       size_t last_converted;
219
220       /* We preserve the initial values of the pointer variables.  */
221       const char *inptr = *inbuf;
222       char *outbuf = data->outbuf;
223       char *outend = data->outbufend;
224       char *outptr;
225
226 #ifdef PREPARE_LOOP
227       PREPARE_LOOP
228 #endif
229
230       do
231         {
232           /* Remember the start value for this round.  */
233           inptr = *inbuf;
234           /* The outbuf buffer is empty.  */
235           outptr = outbuf;
236
237           /* Save the state.  */
238           last_converted = converted;
239 #ifdef SAVE_RESET_STATE
240           SAVE_RESET_STATE (1);
241 #endif
242
243           if (FROM_DIRECTION)
244             /* Run the conversion loop.  */
245             status = FROM_LOOP ((const unsigned char **) inbuf,
246                                 (const unsigned char *) inbufend,
247                                 (unsigned char **) &outbuf,
248                                 (unsigned char *) outend,
249                                 data->statep, step->data, &converted
250                                 EXTRA_LOOP_ARGS);
251           else
252             /* Run the conversion loop.  */
253             status = TO_LOOP ((const unsigned char **) inbuf,
254                               (const unsigned char *) inbufend,
255                               (unsigned char **) &outbuf,
256                               (unsigned char *) outend,
257                               data->statep, step->data, &converted
258                               EXTRA_LOOP_ARGS);
259
260           /* If this is the last step leave the loop, there is nothgin
261              we can do.  */
262           if (data->is_last)
263             {
264               /* Store information about how many bytes are available.  */
265               data->outbuf = outbuf;
266               break;
267             }
268
269           /* Write out all output which was produced.  */
270           if (outbuf > outptr)
271             {
272               const char *outerr = data->outbuf;
273               int result;
274
275               result = (*fct) (next_step, next_data, &outerr, outbuf,
276                                written, 0);
277
278               if (result != GCONV_EMPTY_INPUT)
279                 {
280                   if (outerr != outbuf)
281                     {
282 #ifdef RESET_INPUT_BUFFER
283                       RESET_INPUT_BUFFER;
284 #else
285                       /* We have a problem with the in on of the functions
286                          below.  Undo the conversion upto the error point.  */
287                       size_t nstatus;
288
289                       /* Reload the pointers.  */
290                       *inbuf = inptr;
291                       outbuf = outptr;
292
293                       /* Reset the state.  */
294                       converted = last_converted;
295 # ifdef SAVE_RESET_STATE
296                       SAVE_RESET_STATE (0);
297 # endif
298
299                       if (FROM_DIRECTION)
300                         /* Run the conversion loop.  */
301                         nstatus = FROM_LOOP ((const unsigned char **) inbuf,
302                                              (const unsigned char *) inbufend,
303                                              (unsigned char **) &outbuf,
304                                              (unsigned char *) outerr,
305                                              data->statep, step->data,
306                                              &converted EXTRA_LOOP_ARGS);
307                       else
308                         /* Run the conversion loop.  */
309                         nstatus = TO_LOOP ((const unsigned char **) inbuf,
310                                            (const unsigned char *) inbufend,
311                                            (unsigned char **) &outbuf,
312                                            (unsigned char *) outerr,
313                                            data->statep, step->data,
314                                            &converted EXTRA_LOOP_ARGS);
315
316                       /* We must run out of output buffer space in this
317                          rerun.  */
318                       assert (outbuf == outerr);
319                       assert (nstatus == GCONV_FULL_OUTPUT);
320 #endif  /* reset input buffer */
321                     }
322
323                   /* Change the status.  */
324                   status = result;
325                 }
326               else
327                 /* All the output is consumed, we can make another run
328                    if everything was ok.  */
329                 if (status == GCONV_FULL_OUTPUT)
330                   status = GCONV_OK;
331             }
332         }
333       while (status == GCONV_OK);
334
335       /* Remember how many characters we converted.  */
336       *written += converted;
337     }
338
339   return status;
340 }
341
342 #undef DEFINE_INIT
343 #undef CHARSET_NAME
344 #undef DEFINE_FINI
345 #undef MIN_NEEDED_FROM
346 #undef MIN_NEEDED_TO
347 #undef MAX_NEEDED_FROM
348 #undef MAX_NEEDED_TO
349 #undef DEFINE_DIRECTION_OBJECTS
350 #undef FROM_DIRECTION
351 #undef EMIT_SHIFT_TO_INIT
352 #undef FROM_LOOP
353 #undef TO_LOOP
354 #undef RESET_STATE
355 #undef RESET_INPUT_BUFFER
356 #undef FUNCTION_NAME