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