(gmp-objs): Add inlines.
[kopensolaris-gnu/glibc.git] / iconv / loop.c
1 /* Conversion loop frame work.
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 provides a frame for the reader loop in all conversion modules.
22    The actual code must (of course) be provided in the actual module source
23    code but certain actions can be written down generically, with some
24    customization options which are these:
25
26      MIN_NEEDED_INPUT   minimal number of input bytes needed for the next
27                         conversion.
28      MIN_NEEDED_OUTPUT  minimal number of bytes produced by the next round
29                         of conversion.
30
31      MAX_NEEDED_INPUT   you guess it, this is the maximal number of input
32                         bytes needed.  It defaults to MIN_NEEDED_INPUT
33      MAX_NEEDED_OUTPUT  likewise for output bytes.
34
35      LOOPFCT            name of the function created.  If not specified
36                         the name is `loop' but this prevents the use
37                         of multiple functions in the same file.
38
39      COUNT_CONVERTED    optional macro which is used to count the actual
40                         number of characters converted.  For some conversion
41                         it is easy to compute the value afterwards, but for
42                         others explicit counting is cheaper.
43
44      BODY               this is supposed to expand to the body of the loop.
45                         The user must provide this.
46
47      EXTRA_LOOP_DECLS   extra arguments passed from converion loop call.
48
49      INIT_PARAMS        code to define and initialize variables from params.
50      UPDATE_PARAMS      code to store result in params.
51 */
52
53 #include <gconv.h>
54 #include <sys/param.h>          /* For MIN.  */
55 #define __need_size_t
56 #include <stddef.h>
57
58
59 /* We need at least one byte for the next round.  */
60 #ifndef MIN_NEEDED_INPUT
61 # error "MIN_NEEDED_INPUT definition missing"
62 #endif
63
64 /* Let's see how many bytes we produce.  */
65 #ifndef MAX_NEEDED_INPUT
66 # define MAX_NEEDED_INPUT       MIN_NEEDED_INPUT
67 #endif
68
69 /* We produce at least one byte in the next round.  */
70 #ifndef MIN_NEEDED_OUTPUT
71 # error "MIN_NEEDED_OUTPUT definition missing"
72 #endif
73
74 /* Let's see how many bytes we produce.  */
75 #ifndef MAX_NEEDED_OUTPUT
76 # define MAX_NEEDED_OUTPUT      MIN_NEEDED_OUTPUT
77 #endif
78
79 /* Default name for the function.  */
80 #ifndef LOOPFCT
81 # define LOOPFCT                loop
82 #endif
83
84 /* Make sure we have a loop body.  */
85 #ifndef BODY
86 # error "Definition of BODY missing for function" LOOPFCT
87 #endif
88
89 /* We can calculate the number of converted characters easily if one
90    of the character sets has a fixed width.  */
91 #ifndef COUNT_CONVERTED
92 # if MIN_NEEDED_INPUT == MAX_NEEDED_INPUT
93 #  if MIN_NEEDED_OUTPUT == MAX_NEEDED_OUTPUT
94 /* Decide whether one of the charsets has size 1.  */
95 #   if MIN_NEEDED_INPUT == 1
96 #    define COUNT_CONVERTED     (inptr - *inptrp)
97 #   elif MIN_NEEDED_OUTPUT == 1
98 #    define COUNT_CONVERTED     (outptr - *outptrp)
99 #   else
100 /* Else we should see whether one of the two numbers is a power of 2.  */
101 #    define COUNT_CONVERTED \
102   ((MIN_NEEDED_INPUT & (-MIN_NEEDED_INPUT)) == MIN_NEEDED_INPUT               \
103    ? (inptr - *inptrp) : (outptr - *outptrp))
104 #   endif
105 #  else
106 #   define COUNT_CONVERTED      ((inptr - *inptrp) / MIN_NEEDED_INPUT)
107 #  endif
108 # elif MIN_NEEDED_OUTPUT == MAX_NEEDED_OUTPUT
109 #  define COUNT_CONVERTED       ((outptr - *outptrp) / MIN_NEEDED_OUTPUT)
110 # endif
111 #endif
112
113
114 /* If no arguments have to passed to the loop function define the macro
115    as empty.  */
116 #ifndef EXTRA_LOOP_DECLS
117 # define EXTRA_LOOP_DECLS
118 #endif
119
120
121 /* The function returns the status, as defined in gconv.h.  */
122 static inline int
123 LOOPFCT (const unsigned char **inptrp, const unsigned char *inend,
124          unsigned char **outptrp, unsigned char *outend, mbstate_t *state,
125          void *data, size_t *converted EXTRA_LOOP_DECLS)
126 {
127   int result = GCONV_OK;
128   const unsigned char *inptr = *inptrp;
129   unsigned char *outptr = *outptrp;
130 #ifndef COUNT_CONVERTED
131   size_t done = 0;
132 #endif
133
134   /* We run one loop where we avoid checks for underflow/overflow of the
135      buffers to speed up the conversion a bit.  */
136   size_t min_in_rounds = (inend - inptr) / MAX_NEEDED_INPUT;
137   size_t min_out_rounds = (outend - outptr) / MAX_NEEDED_OUTPUT;
138   size_t min_rounds = MIN (min_in_rounds, min_out_rounds);
139
140 #ifdef INIT_PARAMS
141   INIT_PARAMS;
142 #endif
143
144 #undef NEED_LENGTH_TEST
145 #define NEED_LENGTH_TEST        0
146   while (min_rounds-- > 0)
147     {
148       /* Here comes the body the user provides.  It can stop with RESULT
149          set to GCONV_INCOMPLETE_INPUT (if the size of the input characters
150          vary in size), GCONV_ILLEGAL_INPUT, or GCONV_FULL_OUTPUT (if the
151          output characters vary in size.  */
152       BODY
153
154       /* If necessary count the successful conversion.  */
155 #ifndef COUNT_CONVERTED
156       ++done;
157 #endif
158     }
159
160   if (result == GCONV_OK)
161     {
162 #if MIN_NEEDED_INPUT == MAX_NEEDED_INPUT \
163     && MIN_NEEDED_OUTPUT == MAX_NEEDED_OUTPUT
164       /* We don't need to start another loop since we were able to determine
165          the maximal number of characters to copy in advance.  What remains
166          to be determined is the status.  */
167       if (inptr == inend)
168         /* No more input.  */
169         result = GCONV_EMPTY_INPUT;
170       else if ((MIN_NEEDED_OUTPUT != 1 && outptr + MIN_NEEDED_OUTPUT > outend)
171                || (MIN_NEEDED_OUTPUT == 1 && outptr >= outend))
172         /* Overflow in the output buffer.  */
173         result = GCONV_FULL_OUTPUT;
174       else
175         /* We have something left in the input buffer.  */
176         result = GCONV_INCOMPLETE_INPUT;
177 #else
178       result = GCONV_EMPTY_INPUT;
179
180 # undef NEED_LENGTH_TEST
181 # define NEED_LENGTH_TEST       1
182       while (inptr != inend)
183         {
184           /* `if' cases for MIN_NEEDED_OUTPUT ==/!= 1 is made to help the
185              compiler generating better code.  It will optimized away
186              since MIN_NEEDED_OUTPUT is always a constant.  */
187           if ((MIN_NEEDED_OUTPUT != 1 && outptr + MIN_NEEDED_OUTPUT > outend)
188               || (MIN_NEEDED_OUTPUT == 1 && outptr >= outend))
189             {
190               /* Overflow in the output buffer.  */
191               result = GCONV_FULL_OUTPUT;
192               break;
193             }
194           if (MIN_NEEDED_INPUT > 1 && inptr + MIN_NEEDED_INPUT > inend)
195             {
196               /* We don't have enough input for another complete input
197                  character.  */
198               result = GCONV_INCOMPLETE_INPUT;
199               break;
200             }
201
202           /* Here comes the body the user provides.  It can stop with
203              RESULT set to GCONV_INCOMPLETE_INPUT (if the size of the
204              input characters vary in size), GCONV_ILLEGAL_INPUT, or
205              GCONV_FULL_OUTPUT (if the output characters vary in size).  */
206           BODY
207
208           /* If necessary count the successful conversion.  */
209 # ifndef COUNT_CONVERTED
210           ++done;
211 # endif
212         }
213 #endif  /* Input and output charset are not both fixed width.  */
214     }
215
216   /* Add the number of characters we actually converted.  */
217 #ifdef COUNT_CONVERTED
218   *converted += COUNT_CONVERTED;
219 #else
220   *converted += done;
221 #endif
222
223   /* Update the pointers pointed to by the parameters.  */
224   *inptrp = inptr;
225   *outptrp = outptr;
226 #ifdef UPDATE_PARAMS
227   UPDATE_PARAMS;
228 #endif
229
230   return result;
231 }
232
233
234 /* We remove the macro definitions so that we can include this file again
235    for the definition of another function.  */
236 #undef MIN_NEEDED_INPUT
237 #undef MAX_NEEDED_INPUT
238 #undef MIN_NEEDED_OUTPUT
239 #undef MAX_NEEDED_OUTPUT
240 #undef LOOPFCT
241 #undef COUNT_CONVERTED
242 #undef BODY
243 #undef LOOPFCT
244 #undef EXTRA_LOOP_DECLS
245 #undef INIT_PARAMS
246 #undef UPDATE_PARAMS