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