tools: Remove duplicate includes.
[wine] / tools / wrc / utils.c
1 /*
2  * Utility routines
3  *
4  * Copyright 1998 Bertho A. Stultiens
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This 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  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <ctype.h>
30
31 #include "wine/unicode.h"
32 #include "wrc.h"
33 #include "utils.h"
34 #include "parser.h"
35
36 /* #define WANT_NEAR_INDICATION */
37
38 #ifdef WANT_NEAR_INDICATION
39 void make_print(char *str)
40 {
41         while(*str)
42         {
43                 if(!isprint(*str))
44                         *str = ' ';
45                 str++;
46         }
47 }
48 #endif
49
50 static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
51 {
52         fprintf(stderr, "%s:%d:%d: %s: ", input_name ? input_name : "stdin", line_number, char_number, t);
53         vfprintf(stderr, s, ap);
54 #ifdef WANT_NEAR_INDICATION
55         {
56                 char *cpy;
57                 if(n)
58                 {
59                         cpy = xstrdup(n);
60                         make_print(cpy);
61                         fprintf(stderr, " near '%s'", cpy);
62                         free(cpy);
63                 }
64         }
65 #endif
66 }
67
68
69 int parser_error(const char *s, ...)
70 {
71         va_list ap;
72         va_start(ap, s);
73         generic_msg(s, "Error", parser_text, ap);
74         va_end(ap);
75         exit(1);
76         return 1;
77 }
78
79 int parser_warning(const char *s, ...)
80 {
81         va_list ap;
82         va_start(ap, s);
83         generic_msg(s, "Warning", parser_text, ap);
84         va_end(ap);
85         return 0;
86 }
87
88 void internal_error(const char *file, int line, const char *s, ...)
89 {
90         va_list ap;
91         va_start(ap, s);
92         fprintf(stderr, "Internal error (please report) %s %d: ", file, line);
93         vfprintf(stderr, s, ap);
94         va_end(ap);
95         exit(3);
96 }
97
98 void error(const char *s, ...)
99 {
100         va_list ap;
101         va_start(ap, s);
102         fprintf(stderr, "Error: ");
103         vfprintf(stderr, s, ap);
104         va_end(ap);
105         exit(2);
106 }
107
108 void warning(const char *s, ...)
109 {
110         va_list ap;
111         va_start(ap, s);
112         fprintf(stderr, "Warning: ");
113         vfprintf(stderr, s, ap);
114         va_end(ap);
115 }
116
117 void chat(const char *s, ...)
118 {
119         if(debuglevel & DEBUGLEVEL_CHAT)
120         {
121                 va_list ap;
122                 va_start(ap, s);
123                 fprintf(stderr, "FYI: ");
124                 vfprintf(stderr, s, ap);
125                 va_end(ap);
126         }
127 }
128
129 char *dup_basename(const char *name, const char *ext)
130 {
131         int namelen;
132         int extlen = strlen(ext);
133         char *base;
134         char *slash;
135
136         if(!name)
137                 name = "wrc.tab";
138
139         slash = strrchr(name, '/');
140         if (slash)
141                 name = slash + 1;
142
143         namelen = strlen(name);
144
145         /* +4 for later extension and +1 for '\0' */
146         base = xmalloc(namelen +4 +1);
147         strcpy(base, name);
148         if(!strcasecmp(name + namelen-extlen, ext))
149         {
150                 base[namelen - extlen] = '\0';
151         }
152         return base;
153 }
154
155 void *xmalloc(size_t size)
156 {
157     void *res;
158
159     assert(size > 0);
160     res = malloc(size);
161     if(res == NULL)
162     {
163         error("Virtual memory exhausted.\n");
164     }
165     memset(res, 0x55, size);
166     return res;
167 }
168
169
170 void *xrealloc(void *p, size_t size)
171 {
172     void *res;
173
174     assert(size > 0);
175     res = realloc(p, size);
176     if(res == NULL)
177     {
178         error("Virtual memory exhausted.\n");
179     }
180     return res;
181 }
182
183 char *xstrdup(const char *str)
184 {
185         char *s;
186
187         assert(str != NULL);
188         s = xmalloc(strlen(str)+1);
189         return strcpy(s, str);
190 }
191
192
193 /*
194  *****************************************************************************
195  * Function     : compare_name_id
196  * Syntax       : int compare_name_id(const name_id_t *n1, const name_id_t *n2)
197  * Input        :
198  * Output       :
199  * Description  :
200  * Remarks      :
201  *****************************************************************************
202 */
203 int compare_name_id(const name_id_t *n1, const name_id_t *n2)
204 {
205         if(n1->type == name_ord && n2->type == name_ord)
206         {
207                 return n1->name.i_name - n2->name.i_name;
208         }
209         else if(n1->type == name_str && n2->type == name_str)
210         {
211                 if(n1->name.s_name->type == str_char
212                 && n2->name.s_name->type == str_char)
213                 {
214                         return strcasecmp(n1->name.s_name->str.cstr, n2->name.s_name->str.cstr);
215                 }
216                 else if(n1->name.s_name->type == str_unicode
217                 && n2->name.s_name->type == str_unicode)
218                 {
219                         return strcmpiW(n1->name.s_name->str.wstr, n2->name.s_name->str.wstr);
220                 }
221                 else
222                 {
223                         internal_error(__FILE__, __LINE__, "Can't yet compare strings of mixed type\n");
224                 }
225         }
226         else if(n1->type == name_ord && n2->type == name_str)
227                 return 1;
228         else if(n1->type == name_str && n2->type == name_ord)
229                 return -1;
230         else
231                 internal_error(__FILE__, __LINE__, "Comparing name-ids with unknown types (%d, %d)\n",
232                                 n1->type, n2->type);
233
234         return 0; /* Keep the compiler happy */
235 }
236
237 string_t *convert_string(const string_t *str, enum str_e type, int codepage)
238 {
239     const union cptable *cptable = codepage ? wine_cp_get_table( codepage ) : NULL;
240     string_t *ret = xmalloc(sizeof(*ret));
241     int res;
242
243     if (!codepage && str->type != type)
244         parser_error( "Current language is Unicode only, cannot convert string\n" );
245
246     if((str->type == str_char) && (type == str_unicode))
247     {
248         ret->type = str_unicode;
249         ret->size = cptable ? wine_cp_mbstowcs( cptable, 0, str->str.cstr, str->size, NULL, 0 )
250                             : wine_utf8_mbstowcs( 0, str->str.cstr, str->size, NULL, 0 );
251         ret->str.wstr = xmalloc( (ret->size+1) * sizeof(WCHAR) );
252         if (cptable)
253             res = wine_cp_mbstowcs( cptable, MB_ERR_INVALID_CHARS, str->str.cstr, str->size,
254                                     ret->str.wstr, ret->size );
255         else
256             res = wine_utf8_mbstowcs( MB_ERR_INVALID_CHARS, str->str.cstr, str->size,
257                                       ret->str.wstr, ret->size );
258         if (res == -2)
259             parser_error( "Invalid character in string '%.*s' for codepage %u\n",
260                    str->size, str->str.cstr, codepage );
261         ret->str.wstr[ret->size] = 0;
262     }
263     else if((str->type == str_unicode) && (type == str_char))
264     {
265         ret->type = str_char;
266         ret->size = cptable ? wine_cp_wcstombs( cptable, 0, str->str.wstr, str->size, NULL, 0, NULL, NULL )
267                             : wine_utf8_wcstombs( 0, str->str.wstr, str->size, NULL, 0 );
268         ret->str.cstr = xmalloc( ret->size + 1 );
269         if (cptable)
270             wine_cp_wcstombs( cptable, 0, str->str.wstr, str->size, ret->str.cstr, ret->size, NULL, NULL );
271         else
272             wine_utf8_wcstombs( 0, str->str.wstr, str->size, ret->str.cstr, ret->size );
273         ret->str.cstr[ret->size] = 0;
274     }
275     else if(str->type == str_unicode)
276     {
277         ret->type     = str_unicode;
278         ret->size     = str->size;
279         ret->str.wstr = xmalloc(sizeof(WCHAR)*(ret->size+1));
280         memcpy( ret->str.wstr, str->str.wstr, ret->size * sizeof(WCHAR) );
281         ret->str.wstr[ret->size] = 0;
282     }
283     else /* str->type == str_char */
284     {
285         ret->type     = str_char;
286         ret->size     = str->size;
287         ret->str.cstr = xmalloc( ret->size + 1 );
288         memcpy( ret->str.cstr, str->str.cstr, ret->size );
289         ret->str.cstr[ret->size] = 0;
290     }
291     return ret;
292 }
293
294
295 void free_string(string_t *str)
296 {
297     if (str->type == str_unicode) free( str->str.wstr );
298     else free( str->str.cstr );
299     free( str );
300 }
301
302
303 int check_unicode_conversion( const string_t *str_a, const string_t *str_w, int codepage )
304 {
305     int ok;
306     string_t *teststr = convert_string( str_w, str_char, codepage );
307
308     ok = (teststr->size == str_a->size && !memcmp( teststr->str.cstr, str_a->str.cstr, str_a->size ));
309
310     if (!ok)
311     {
312         int i;
313
314         fprintf( stderr, "Source: %s", str_a->str.cstr );
315         for (i = 0; i < str_a->size; i++)
316             fprintf( stderr, " %02x", (unsigned char)str_a->str.cstr[i] );
317         fprintf( stderr, "\nUnicode: " );
318         for (i = 0; i < str_w->size; i++)
319             fprintf( stderr, " %04x", str_w->str.wstr[i] );
320         fprintf( stderr, "\nBack: %s", teststr->str.cstr );
321         for (i = 0; i < teststr->size; i++)
322             fprintf( stderr, " %02x", (unsigned char)teststr->str.cstr[i] );
323         fprintf( stderr, "\n" );
324     }
325     free_string( teststr );
326     return ok;
327 }
328
329
330 struct lang2cp
331 {
332     unsigned short lang;
333     unsigned short sublang;
334     unsigned int   cp;
335 } lang2cp_t;
336
337 /* language to codepage conversion table */
338 /* specific sublanguages need only be specified if their codepage */
339 /* differs from the default (SUBLANG_NEUTRAL) */
340 static const struct lang2cp lang2cps[] =
341 {
342     { LANG_AFRIKAANS,      SUBLANG_NEUTRAL,              1252 },
343     { LANG_ALBANIAN,       SUBLANG_NEUTRAL,              1250 },
344     { LANG_ARABIC,         SUBLANG_NEUTRAL,              1256 },
345     { LANG_ARMENIAN,       SUBLANG_NEUTRAL,              0    },
346     { LANG_AZERI,          SUBLANG_NEUTRAL,              1254 },
347     { LANG_AZERI,          SUBLANG_AZERI_CYRILLIC,       1251 },
348     { LANG_BASQUE,         SUBLANG_NEUTRAL,              1252 },
349     { LANG_BELARUSIAN,     SUBLANG_NEUTRAL,              1251 },
350 #ifdef LANG_BRETON
351     { LANG_BRETON,         SUBLANG_NEUTRAL,              1252 },
352 #endif /* LANG_BRETON */
353     { LANG_BULGARIAN,      SUBLANG_NEUTRAL,              1251 },
354     { LANG_CATALAN,        SUBLANG_NEUTRAL,              1252 },
355     { LANG_CHINESE,        SUBLANG_NEUTRAL,              950  },
356     { LANG_CHINESE,        SUBLANG_CHINESE_SINGAPORE,    936  },
357     { LANG_CHINESE,        SUBLANG_CHINESE_SIMPLIFIED,   936  },
358 #ifdef LANG_CORNISH
359     { LANG_CORNISH,        SUBLANG_NEUTRAL,              1252 },
360 #endif /* LANG_CORNISH */
361     { LANG_CROATIAN,       SUBLANG_NEUTRAL,              1250 },
362     { LANG_CZECH,          SUBLANG_NEUTRAL,              1250 },
363     { LANG_DANISH,         SUBLANG_NEUTRAL,              1252 },
364     { LANG_DIVEHI,         SUBLANG_NEUTRAL,              0    },
365     { LANG_DUTCH,          SUBLANG_NEUTRAL,              1252 },
366     { LANG_ENGLISH,        SUBLANG_NEUTRAL,              1252 },
367 #ifdef LANG_ESPERANTO
368     { LANG_ESPERANTO,      SUBLANG_NEUTRAL,              1252 },
369 #endif /* LANG_ESPERANTO */
370     { LANG_ESTONIAN,       SUBLANG_NEUTRAL,              1257 },
371     { LANG_FAEROESE,       SUBLANG_NEUTRAL,              1252 },
372     { LANG_FARSI,          SUBLANG_NEUTRAL,              1256 },
373     { LANG_FINNISH,        SUBLANG_NEUTRAL,              1252 },
374     { LANG_FRENCH,         SUBLANG_NEUTRAL,              1252 },
375 #ifdef LANG_GAELIC
376     { LANG_GAELIC,         SUBLANG_NEUTRAL,              1252 },
377 #endif /* LANG_GAELIC */
378     { LANG_GALICIAN,       SUBLANG_NEUTRAL,              1252 },
379     { LANG_GEORGIAN,       SUBLANG_NEUTRAL,              0    },
380     { LANG_GERMAN,         SUBLANG_NEUTRAL,              1252 },
381     { LANG_GREEK,          SUBLANG_NEUTRAL,              1253 },
382     { LANG_GUJARATI,       SUBLANG_NEUTRAL,              0    },
383     { LANG_HEBREW,         SUBLANG_NEUTRAL,              1255 },
384     { LANG_HINDI,          SUBLANG_NEUTRAL,              0    },
385     { LANG_HUNGARIAN,      SUBLANG_NEUTRAL,              1250 },
386     { LANG_ICELANDIC,      SUBLANG_NEUTRAL,              1252 },
387     { LANG_INDONESIAN,     SUBLANG_NEUTRAL,              1252 },
388     { LANG_ITALIAN,        SUBLANG_NEUTRAL,              1252 },
389     { LANG_JAPANESE,       SUBLANG_NEUTRAL,              932  },
390     { LANG_KANNADA,        SUBLANG_NEUTRAL,              0    },
391     { LANG_KAZAK,          SUBLANG_NEUTRAL,              1251 },
392     { LANG_KONKANI,        SUBLANG_NEUTRAL,              0    },
393     { LANG_KOREAN,         SUBLANG_NEUTRAL,              949  },
394     { LANG_KYRGYZ,         SUBLANG_NEUTRAL,              1251 },
395     { LANG_LATVIAN,        SUBLANG_NEUTRAL,              1257 },
396     { LANG_LITHUANIAN,     SUBLANG_NEUTRAL,              1257 },
397     { LANG_MACEDONIAN,     SUBLANG_NEUTRAL,              1251 },
398     { LANG_MALAY,          SUBLANG_NEUTRAL,              1252 },
399     { LANG_MARATHI,        SUBLANG_NEUTRAL,              0    },
400     { LANG_MONGOLIAN,      SUBLANG_NEUTRAL,              1251 },
401     { LANG_NEUTRAL,        SUBLANG_NEUTRAL,              1252 },
402     { LANG_NORWEGIAN,      SUBLANG_NEUTRAL,              1252 },
403     { LANG_POLISH,         SUBLANG_NEUTRAL,              1250 },
404     { LANG_PORTUGUESE,     SUBLANG_NEUTRAL,              1252 },
405     { LANG_PUNJABI,        SUBLANG_NEUTRAL,              0    },
406     { LANG_ROMANIAN,       SUBLANG_NEUTRAL,              1250 },
407     { LANG_RUSSIAN,        SUBLANG_NEUTRAL,              1251 },
408     { LANG_SANSKRIT,       SUBLANG_NEUTRAL,              0    },
409     { LANG_SERBIAN,        SUBLANG_NEUTRAL,              1250 },
410     { LANG_SERBIAN,        SUBLANG_SERBIAN_CYRILLIC,     1251 },
411     { LANG_SLOVAK,         SUBLANG_NEUTRAL,              1250 },
412     { LANG_SLOVENIAN,      SUBLANG_NEUTRAL,              1250 },
413     { LANG_SPANISH,        SUBLANG_NEUTRAL,              1252 },
414     { LANG_SWAHILI,        SUBLANG_NEUTRAL,              1252 },
415     { LANG_SWEDISH,        SUBLANG_NEUTRAL,              1252 },
416     { LANG_SYRIAC,         SUBLANG_NEUTRAL,              0    },
417     { LANG_TAMIL,          SUBLANG_NEUTRAL,              0    },
418     { LANG_TATAR,          SUBLANG_NEUTRAL,              1251 },
419     { LANG_TELUGU,         SUBLANG_NEUTRAL,              0    },
420     { LANG_THAI,           SUBLANG_NEUTRAL,              874  },
421     { LANG_TURKISH,        SUBLANG_NEUTRAL,              1254 },
422     { LANG_UKRAINIAN,      SUBLANG_NEUTRAL,              1251 },
423     { LANG_URDU,           SUBLANG_NEUTRAL,              1256 },
424     { LANG_UZBEK,          SUBLANG_NEUTRAL,              1254 },
425     { LANG_UZBEK,          SUBLANG_UZBEK_CYRILLIC,       1251 },
426     { LANG_VIETNAMESE,     SUBLANG_NEUTRAL,              1258 }
427 #ifdef LANG_WALON
428     , { LANG_WALON,          SUBLANG_NEUTRAL,              1252 }
429 #endif /* LANG_WALON */
430 #ifdef LANG_WELSH
431     , { LANG_WELSH,          SUBLANG_NEUTRAL,              1252 }
432 #endif /* LANG_WELSH */
433 };
434
435 int get_language_codepage( unsigned short lang, unsigned short sublang )
436 {
437     unsigned int i;
438     int cp = -1, defcp = -1;
439
440     for (i = 0; i < sizeof(lang2cps)/sizeof(lang2cps[0]); i++)
441     {
442         if (lang2cps[i].lang != lang) continue;
443         if (lang2cps[i].sublang == sublang)
444         {
445             cp = lang2cps[i].cp;
446             break;
447         }
448         if (lang2cps[i].sublang == SUBLANG_NEUTRAL) defcp = lang2cps[i].cp;
449     }
450
451     if (cp == -1) cp = defcp;
452     assert( cp <= 0 || wine_cp_get_table(cp) );
453     return cp;
454 }