Replace the old lexer by the new preprocessor.
[cparser] / input.c
1 #include "config.h"
2
3 #include "input.h"
4
5 #include <ctype.h>
6
7 typedef size_t (*decode_func)(input_t *input, utf32 *buffer, size_t buffer_size);
8
9 typedef enum {
10         INPUT_FILE,
11         INPUT_STRING
12 } input_kind_t;
13
14 struct input_t {
15         input_kind_t kind;
16         union {
17                 FILE *file;
18                 const char *string;
19         } in;
20         decode_func decode;
21
22         /* state for utf-8 decoder */
23         utf32  utf8_part_decoded_min_code;
24         utf32  utf8_part_decoded_char;
25         size_t utf8_part_decoded_rest_len;
26 };
27
28 static input_error_callback_func input_error;
29
30 void set_input_error_callback(input_error_callback_func new_func)
31 {
32         input_error = new_func;
33 }
34
35 static size_t read_block(input_t *input, unsigned char *const read_buf,
36                          size_t const n)
37 {
38         if (input->kind == INPUT_FILE) {
39                 FILE *file = input->in.file;
40                 size_t const s = fread(read_buf, 1, n, file);
41                 if (s == 0) {
42                         /* on OS/X ferror appears to return true on eof as well when running
43                          * the application in gdb... */
44                         if (!feof(file) && ferror(file))
45                                 input_error(0, 0, "read from input failed");
46                         return 0;
47                 }
48                 return s;
49         } else {
50                 assert(input->kind == INPUT_STRING);
51                 size_t len = strlen(input->in.string);
52                 if (len > n)
53                         len = n;
54                 memcpy(read_buf, input->in.string, len);
55                 input->in.string += len;
56                 return len;
57         }
58 }
59
60 static size_t decode_iso_8859_1(input_t *input, utf32 *buffer,
61                                 size_t buffer_size)
62 {
63         unsigned char read_buf[buffer_size];
64         size_t const s = read_block(input, read_buf, sizeof(read_buf));
65
66         unsigned char const *src = read_buf;
67         unsigned char const *end = read_buf + s;
68         utf32               *dst = buffer;
69         while (src != end)
70                 *dst++ = *src++;
71
72         return s;
73 }
74
75 static size_t decode_iso_8859_15(input_t *input, utf32 *buffer,
76                                  size_t buffer_size)
77 {
78         unsigned char read_buf[buffer_size];
79         size_t const s = read_block(input, read_buf, sizeof(read_buf));
80
81         unsigned char const *src = read_buf;
82         unsigned char const *end = read_buf + s;
83         utf32               *dst = buffer;
84         while (src != end) {
85                 utf32 tc = *src++;
86                 switch (tc) {
87                         case 0xA4: tc = 0x20AC; break; // €
88                         case 0xA6: tc = 0x0160; break; // Š
89                         case 0xA8: tc = 0x0161; break; // š
90                         case 0xB4: tc = 0x017D; break; // Ž
91                         case 0xB8: tc = 0x017E; break; // ž
92                         case 0xBC: tc = 0x0152; break; // Œ
93                         case 0xBD: tc = 0x0153; break; // œ
94                         case 0xBE: tc = 0x0178; break; // Ÿ
95                 }
96                 *dst++ = tc;
97         }
98
99         return s;
100 }
101
102 static size_t decode_utf8(input_t *input, utf32 *buffer, size_t buffer_size)
103 {
104         unsigned char read_buf[buffer_size];
105
106         for (;;) {
107                 size_t const s = read_block(input, read_buf, sizeof(read_buf));
108                 if (s == 0) {
109                         if (input->utf8_part_decoded_rest_len > 0)
110                                 input_error(0, 0, "incomplete input char at end of input");
111                         return 0;
112                 }
113
114                 unsigned char const *src = read_buf;
115                 unsigned char const *end = read_buf + s;
116                 utf32               *dst = buffer;
117                 utf32                decoded;
118                 utf32                min_code;
119
120                 if (input->utf8_part_decoded_rest_len != 0) {
121                         min_code              = input->utf8_part_decoded_min_code;
122                         decoded               = input->utf8_part_decoded_char;
123                         size_t const rest_len = input->utf8_part_decoded_rest_len;
124                         input->utf8_part_decoded_rest_len = 0;
125                         switch (rest_len) {
126                                 case 4:  goto realign;
127                                 case 3:  goto three_more;
128                                 case 2:  goto two_more;
129                                 default: goto one_more;
130                         }
131                 }
132
133                 while (src != end) {
134                         if ((*src & 0x80) == 0) {
135                                 decoded = *src++;
136                         } else if ((*src & 0xE0) == 0xC0) {
137                                 min_code = 0x80;
138                                 decoded  = *src++ & 0x1F;
139 one_more:
140                                 if (src == end) {
141                                         input->utf8_part_decoded_min_code = min_code;
142                                         input->utf8_part_decoded_char     = decoded;
143                                         input->utf8_part_decoded_rest_len = 1;
144                                         break;
145                                 }
146                                 if ((*src & 0xC0) == 0x80) {
147                                         decoded = (decoded << 6) | (*src++ & 0x3F);
148                                 } else {
149                                         goto invalid_char;
150                                 }
151                                 if (decoded < min_code                      ||
152                                                 decoded > 0x10FFFF                      ||
153                                                 (0xD800 <= decoded && decoded < 0xE000) || // high/low surrogates
154                                                 (0xFDD0 <= decoded && decoded < 0xFDF0) || // noncharacters
155                                                 (decoded & 0xFFFE) == 0xFFFE) {            // noncharacters
156                                         input_error(0, 0, "invalid byte sequence in input");
157                                 }
158                         } else if ((*src & 0xF0) == 0xE0) {
159                                 min_code = 0x800;
160                                 decoded  = *src++ & 0x0F;
161 two_more:
162                                 if (src == end) {
163                                         input->utf8_part_decoded_min_code = min_code;
164                                         input->utf8_part_decoded_char     = decoded;
165                                         input->utf8_part_decoded_rest_len = 2;
166                                         break;
167                                 }
168                                 if ((*src & 0xC0) == 0x80) {
169                                         decoded = (decoded << 6) | (*src++ & 0x3F);
170                                 } else {
171                                         goto invalid_char;
172                                 }
173                                 goto one_more;
174                         } else if ((*src & 0xF8) == 0xF0) {
175                                 min_code = 0x10000;
176                                 decoded  = *src++ & 0x07;
177 three_more:
178                                 if (src == end) {
179                                         input->utf8_part_decoded_min_code = min_code;
180                                         input->utf8_part_decoded_char     = decoded;
181                                         input->utf8_part_decoded_rest_len = 3;
182                                         break;
183                                 }
184                                 if ((*src & 0xC0) == 0x80) {
185                                         decoded = (decoded << 6) | (*src++ & 0x3F);
186                                 } else {
187                                         goto invalid_char;
188                                 }
189                                 goto two_more;
190                         } else {
191 invalid_char:
192                                 input_error(0, 0, "invalid byte sequence in input");
193 realign:
194                                 do {
195                                         ++src;
196                                         if (src == end) {
197                                                 input->utf8_part_decoded_rest_len = 4;
198                                                 break;
199                                         }
200                                 } while ((*src & 0xC0) == 0x80 || (*src & 0xF8) == 0xF8);
201                                 continue;
202                         }
203                         *dst++ = decoded;
204                 }
205
206                 /* we're done when we could read more than 1 char */
207                 if (buffer != dst)
208                         return dst - buffer;
209         }
210 }
211
212 static size_t decode_windows_1252(input_t *input, utf32 *buffer,
213                                   size_t buffer_size)
214 {
215         unsigned char read_buf[buffer_size];
216         size_t const s = read_block(input, read_buf, sizeof(read_buf));
217
218         unsigned char const *src = read_buf;
219         unsigned char const *end = read_buf + s;
220         utf32               *dst = buffer;
221         while (src != end) {
222                 utf32 tc = *src++;
223                 switch (tc) {
224                         case 0x80: tc = 0x20AC; break; // €
225                         case 0x82: tc = 0x201A; break; // ‚
226                         case 0x83: tc = 0x0192; break; // ƒ
227                         case 0x84: tc = 0x201E; break; // „
228                         case 0x85: tc = 0x2026; break; // …
229                         case 0x86: tc = 0x2020; break; // †
230                         case 0x87: tc = 0x2021; break; // ‡
231                         case 0x88: tc = 0x02C6; break; // ˆ
232                         case 0x89: tc = 0x2030; break; // ‰
233                         case 0x8A: tc = 0x0160; break; // Š
234                         case 0x8B: tc = 0x2039; break; // ‹
235                         case 0x8C: tc = 0x0152; break; // Œ
236                         case 0x8E: tc = 0x017D; break; // Ž
237                         case 0x91: tc = 0x2018; break; // ‘
238                         case 0x92: tc = 0x2019; break; // ’
239                         case 0x93: tc = 0x201C; break; // “
240                         case 0x94: tc = 0x201D; break; // ”
241                         case 0x95: tc = 0x2022; break; // •
242                         case 0x96: tc = 0x2013; break; // –
243                         case 0x97: tc = 0x2014; break; // —
244                         case 0x98: tc = 0x02DC; break; // ˜
245                         case 0x99: tc = 0x2122; break; // ™
246                         case 0x9A: tc = 0x0161; break; // š
247                         case 0x9B: tc = 0x203A; break; // ›
248                         case 0x9C: tc = 0x0153; break; // œ
249                         case 0x9E: tc = 0x017E; break; // ž
250                         case 0x9F: tc = 0x0178; break; // Ÿ
251                 }
252                 *dst++ = tc;
253         }
254
255         return s;
256 }
257
258 typedef struct named_decoder_t {
259         char const *name;
260         decode_func decoder;
261 } named_decoder_t;
262
263 static named_decoder_t const decoders[] = {
264         { "CP819",           decode_iso_8859_1   }, // official alias
265         { "IBM819",          decode_iso_8859_1   }, // official alias
266         { "ISO-8859-1",      decode_iso_8859_1   }, // official alias
267         { "ISO-8859-15",     decode_iso_8859_15  }, // official name
268         { "ISO8859-1",       decode_iso_8859_1   },
269         { "ISO8859-15",      decode_iso_8859_15  },
270         { "ISO_8859-1",      decode_iso_8859_1   }, // official alias
271         { "ISO_8859-15",     decode_iso_8859_15  }, // official alias
272         { "ISO_8859-1:1987", decode_iso_8859_1   }, // official name
273         { "Latin-9",         decode_iso_8859_15  }, // official alias
274         { "UTF-8",           decode_utf8         }, // official name
275         { "csISOLatin1",     decode_iso_8859_1   }, // official alias
276         { "cp1252",          decode_windows_1252 },
277         { "iso-ir-100",      decode_iso_8859_1   }, // official alias
278         { "l1",              decode_iso_8859_1   }, // official alias
279         { "latin1",          decode_iso_8859_1   }, // official alias
280         { "windows-1252",    decode_windows_1252 }, // official name
281
282         { NULL,              NULL                }
283 };
284
285 /** strcasecmp is not part of C99 so we need our own implementation here */
286 static int my_strcasecmp(const char *s1, const char *s2)
287 {
288         for ( ; *s1 != 0; ++s1, ++s2) {
289                 if (tolower(*s1) != tolower(*s2))
290                         break;
291         }
292         return (unsigned char)*s1 - (unsigned char)*s2;
293 }
294
295 static void choose_decoder(input_t *result, const char *encoding)
296 {
297         if (encoding == NULL) {
298                 result->decode = decode_utf8;
299         } else {
300                 for (named_decoder_t const *i = decoders; i->name != NULL; ++i) {
301                         if (my_strcasecmp(encoding, i->name) != 0)
302                                 continue;
303                         result->decode = i->decoder;
304                         break;
305                 }
306                 if (result->decode == NULL) {
307                         fprintf(stderr, "error: input encoding \"%s\" not supported\n",
308                                         encoding);
309                         result->decode = decode_utf8;
310                 }
311         }
312 }
313
314 input_t *input_from_stream(FILE *file, const char *encoding)
315 {
316         input_t *result = XMALLOCZ(input_t);
317         result->kind    = INPUT_FILE;
318         result->in.file = file;
319
320         choose_decoder(result, encoding);
321
322         return result;
323 }
324
325 input_t *input_from_string(const char *string, const char *encoding)
326 {
327         input_t *result   = XMALLOCZ(input_t);
328         result->kind      = INPUT_STRING;
329         result->in.string = string;
330
331         choose_decoder(result, encoding);
332
333         return result;
334 }
335
336 size_t decode(input_t *input, utf32 *buffer, size_t buffer_size)
337 {
338         return input->decode(input, buffer, buffer_size);
339 }
340
341 void input_free(input_t *input)
342 {
343         xfree(input);
344 }