utils.c 14.4 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4 5
/*
 * Utility routines
 *
 * Copyright 1998 Bertho A. Stultiens
 *
6 7 8 9 10 11 12 13 14 15 16 17
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */

21
#include "config.h"
22
#include "wine/port.h"
23

24
#include <assert.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25 26 27 28 29 30 31
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>

32
#include "wine/unicode.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33 34
#include "wrc.h"
#include "utils.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
35
#include "parser.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36

37
/* #define WANT_NEAR_INDICATION */
Alexandre Julliard's avatar
Alexandre Julliard committed
38 39 40 41 42 43 44 45 46 47 48 49 50

#ifdef WANT_NEAR_INDICATION
void make_print(char *str)
{
	while(*str)
	{
		if(!isprint(*str))
			*str = ' ';
		str++;
	}
}
#endif

51
static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
Alexandre Julliard's avatar
Alexandre Julliard committed
52
{
53
	fprintf(stderr, "%s:%d:%d: %s: ", input_name ? input_name : "stdin", line_number, char_number, t);
Alexandre Julliard's avatar
Alexandre Julliard committed
54 55 56
	vfprintf(stderr, s, ap);
#ifdef WANT_NEAR_INDICATION
	{
57 58 59 60 61 62 63 64
		char *cpy;
		if(n)
		{
			cpy = xstrdup(n);
			make_print(cpy);
			fprintf(stderr, " near '%s'", cpy);
			free(cpy);
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
65 66
	}
#endif
67 68 69 70
	fprintf(stderr, "\n");
}


71
int parser_error(const char *s, ...)
72 73 74
{
	va_list ap;
	va_start(ap, s);
75
	generic_msg(s, "Error", parser_text, ap);
Alexandre Julliard's avatar
Alexandre Julliard committed
76 77 78 79 80
	va_end(ap);
	exit(1);
	return 1;
}

81
int parser_warning(const char *s, ...)
Alexandre Julliard's avatar
Alexandre Julliard committed
82 83 84
{
	va_list ap;
	va_start(ap, s);
85
	generic_msg(s, "Warning", parser_text, ap);
Alexandre Julliard's avatar
Alexandre Julliard committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
	va_end(ap);
	return 0;
}

void internal_error(const char *file, int line, const char *s, ...)
{
	va_list ap;
	va_start(ap, s);
	fprintf(stderr, "Internal error (please report) %s %d: ", file, line);
	vfprintf(stderr, s, ap);
	fprintf(stderr, "\n");
	va_end(ap);
	exit(3);
}

void error(const char *s, ...)
{
	va_list ap;
	va_start(ap, s);
	fprintf(stderr, "Error: ");
	vfprintf(stderr, s, ap);
	fprintf(stderr, "\n");
	va_end(ap);
	exit(2);
}

void warning(const char *s, ...)
{
Alexandre Julliard's avatar
Alexandre Julliard committed
114
	va_list ap;
Alexandre Julliard's avatar
Alexandre Julliard committed
115 116 117 118 119 120 121 122
	va_start(ap, s);
	fprintf(stderr, "Warning: ");
	vfprintf(stderr, s, ap);
	fprintf(stderr, "\n");
	va_end(ap);
}

void chat(const char *s, ...)
Alexandre Julliard's avatar
Alexandre Julliard committed
123
{
Alexandre Julliard's avatar
Alexandre Julliard committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
	if(debuglevel & DEBUGLEVEL_CHAT)
	{
		va_list ap;
		va_start(ap, s);
		fprintf(stderr, "FYI: ");
		vfprintf(stderr, s, ap);
		fprintf(stderr, "\n");
		va_end(ap);
	}
}

char *dup_basename(const char *name, const char *ext)
{
	int namelen;
	int extlen = strlen(ext);
	char *base;
Alexandre Julliard's avatar
Alexandre Julliard committed
140
	char *slash;
Alexandre Julliard's avatar
Alexandre Julliard committed
141 142 143 144

	if(!name)
		name = "wrc.tab";

Alexandre Julliard's avatar
Alexandre Julliard committed
145 146 147 148
	slash = strrchr(name, '/');
	if (slash)
		name = slash + 1;

Alexandre Julliard's avatar
Alexandre Julliard committed
149 150 151
	namelen = strlen(name);

	/* +4 for later extension and +1 for '\0' */
152
	base = xmalloc(namelen +4 +1);
Alexandre Julliard's avatar
Alexandre Julliard committed
153
	strcpy(base, name);
154
	if(!strcasecmp(name + namelen-extlen, ext))
Alexandre Julliard's avatar
Alexandre Julliard committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
	{
		base[namelen - extlen] = '\0';
	}
	return base;
}

void *xmalloc(size_t size)
{
    void *res;

    assert(size > 0);
    res = malloc(size);
    if(res == NULL)
    {
	error("Virtual memory exhausted.\n");
    }
171
    memset(res, 0x55, size);
Alexandre Julliard's avatar
Alexandre Julliard committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    return res;
}


void *xrealloc(void *p, size_t size)
{
    void *res;

    assert(size > 0);
    res = realloc(p, size);
    if(res == NULL)
    {
	error("Virtual memory exhausted.\n");
    }
    return res;
}

char *xstrdup(const char *str)
{
191 192 193
	char *s;

	assert(str != NULL);
194
	s = xmalloc(strlen(str)+1);
Alexandre Julliard's avatar
Alexandre Julliard committed
195 196 197 198
	return strcpy(s, str);
}


199 200 201
/*
 *****************************************************************************
 * Function	: compare_name_id
202
 * Syntax	: int compare_name_id(const name_id_t *n1, const name_id_t *n2)
203 204 205 206 207 208
 * Input	:
 * Output	:
 * Description	:
 * Remarks	:
 *****************************************************************************
*/
209
int compare_name_id(const name_id_t *n1, const name_id_t *n2)
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
{
	if(n1->type == name_ord && n2->type == name_ord)
	{
		return n1->name.i_name - n2->name.i_name;
	}
	else if(n1->type == name_str && n2->type == name_str)
	{
		if(n1->name.s_name->type == str_char
		&& n2->name.s_name->type == str_char)
		{
			return strcasecmp(n1->name.s_name->str.cstr, n2->name.s_name->str.cstr);
		}
		else if(n1->name.s_name->type == str_unicode
		&& n2->name.s_name->type == str_unicode)
		{
225
			return strcmpiW(n1->name.s_name->str.wstr, n2->name.s_name->str.wstr);
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
		}
		else
		{
			internal_error(__FILE__, __LINE__, "Can't yet compare strings of mixed type");
		}
	}
	else if(n1->type == name_ord && n2->type == name_str)
		return 1;
	else if(n1->type == name_str && n2->type == name_ord)
		return -1;
	else
		internal_error(__FILE__, __LINE__, "Comparing name-ids with unknown types (%d, %d)",
				n1->type, n2->type);

	return 0; /* Keep the compiler happy */
}

243
string_t *convert_string(const string_t *str, enum str_e type, int codepage)
244
{
245
    const union cptable *cptable = codepage ? wine_cp_get_table( codepage ) : NULL;
246
    string_t *ret = xmalloc(sizeof(*ret));
247
    int res;
248

249 250
    if (!codepage && str->type != type)
        parser_error( "Current language is Unicode only, cannot convert string" );
251 252 253

    if((str->type == str_char) && (type == str_unicode))
    {
254 255 256
        ret->type = str_unicode;
        ret->size = cptable ? wine_cp_mbstowcs( cptable, 0, str->str.cstr, str->size, NULL, 0 )
                            : wine_utf8_mbstowcs( 0, str->str.cstr, str->size, NULL, 0 );
257
        ret->str.wstr = xmalloc( (ret->size+1) * sizeof(WCHAR) );
258 259 260 261 262 263 264 265 266
        if (cptable)
            res = wine_cp_mbstowcs( cptable, MB_ERR_INVALID_CHARS, str->str.cstr, str->size,
                                    ret->str.wstr, ret->size );
        else
            res = wine_utf8_mbstowcs( MB_ERR_INVALID_CHARS, str->str.cstr, str->size,
                                      ret->str.wstr, ret->size );
        if (res == -2)
            parser_error( "Invalid character in string '%.*s' for codepage %u\n",
                   str->size, str->str.cstr, codepage );
267 268 269 270
        ret->str.wstr[ret->size] = 0;
    }
    else if((str->type == str_unicode) && (type == str_char))
    {
271 272
        ret->type = str_char;
        ret->size = cptable ? wine_cp_wcstombs( cptable, 0, str->str.wstr, str->size, NULL, 0, NULL, NULL )
273
                            : wine_utf8_wcstombs( 0, str->str.wstr, str->size, NULL, 0 );
274
        ret->str.cstr = xmalloc( ret->size + 1 );
275 276 277
        if (cptable)
            wine_cp_wcstombs( cptable, 0, str->str.wstr, str->size, ret->str.cstr, ret->size, NULL, NULL );
        else
278
            wine_utf8_wcstombs( 0, str->str.wstr, str->size, ret->str.cstr, ret->size );
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
        ret->str.cstr[ret->size] = 0;
    }
    else if(str->type == str_unicode)
    {
        ret->type     = str_unicode;
        ret->size     = str->size;
        ret->str.wstr = xmalloc(sizeof(WCHAR)*(ret->size+1));
        memcpy( ret->str.wstr, str->str.wstr, ret->size * sizeof(WCHAR) );
        ret->str.wstr[ret->size] = 0;
    }
    else /* str->type == str_char */
    {
        ret->type     = str_char;
        ret->size     = str->size;
        ret->str.cstr = xmalloc( ret->size + 1 );
        memcpy( ret->str.cstr, str->str.cstr, ret->size );
        ret->str.cstr[ret->size] = 0;
    }
    return ret;
}


void free_string(string_t *str)
{
    if (str->type == str_unicode) free( str->str.wstr );
    else free( str->str.cstr );
    free( str );
}


int check_unicode_conversion( const string_t *str_a, const string_t *str_w, int codepage )
{
    int ok;
    string_t *teststr = convert_string( str_w, str_char, codepage );

    ok = (teststr->size == str_a->size && !memcmp( teststr->str.cstr, str_a->str.cstr, str_a->size ));

    if (!ok)
    {
        int i;

        fprintf( stderr, "Source: %s", str_a->str.cstr );
        for (i = 0; i < str_a->size; i++)
            fprintf( stderr, " %02x", (unsigned char)str_a->str.cstr[i] );
        fprintf( stderr, "\nUnicode: " );
        for (i = 0; i < str_w->size; i++)
            fprintf( stderr, " %04x", str_w->str.wstr[i] );
        fprintf( stderr, "\nBack: %s", teststr->str.cstr );
        for (i = 0; i < teststr->size; i++)
            fprintf( stderr, " %02x", (unsigned char)teststr->str.cstr[i] );
        fprintf( stderr, "\n" );
    }
    free_string( teststr );
    return ok;
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
}


struct lang2cp
{
    unsigned short lang;
    unsigned short sublang;
    unsigned int   cp;
} lang2cp_t;

/* language to codepage conversion table */
/* specific sublanguages need only be specified if their codepage */
/* differs from the default (SUBLANG_NEUTRAL) */
static const struct lang2cp lang2cps[] =
{
    { LANG_AFRIKAANS,      SUBLANG_NEUTRAL,              1252 },
    { LANG_ALBANIAN,       SUBLANG_NEUTRAL,              1250 },
350
    { LANG_ARABIC,         SUBLANG_NEUTRAL,              1256 },
351 352 353
    { LANG_ARMENIAN,       SUBLANG_NEUTRAL,              0    },
    { LANG_AZERI,          SUBLANG_NEUTRAL,              1254 },
    { LANG_AZERI,          SUBLANG_AZERI_CYRILLIC,       1251 },
354
    { LANG_BASQUE,         SUBLANG_NEUTRAL,              1252 },
355
    { LANG_BELARUSIAN,     SUBLANG_NEUTRAL,              1251 },
356
#ifdef LANG_BRETON
357
    { LANG_BRETON,         SUBLANG_NEUTRAL,              1252 },
358
#endif /* LANG_BRETON */
359 360
    { LANG_BULGARIAN,      SUBLANG_NEUTRAL,              1251 },
    { LANG_CATALAN,        SUBLANG_NEUTRAL,              1252 },
361 362 363
    { LANG_CHINESE,        SUBLANG_NEUTRAL,              950  },
    { LANG_CHINESE,        SUBLANG_CHINESE_SINGAPORE,    936  },
    { LANG_CHINESE,        SUBLANG_CHINESE_SIMPLIFIED,   936  },
364
#ifdef LANG_CORNISH
365
    { LANG_CORNISH,        SUBLANG_NEUTRAL,              1252 },
366
#endif /* LANG_CORNISH */
367
    { LANG_CROATIAN,       SUBLANG_NEUTRAL,              1250 },
368 369
    { LANG_CZECH,          SUBLANG_NEUTRAL,              1250 },
    { LANG_DANISH,         SUBLANG_NEUTRAL,              1252 },
370
    { LANG_DIVEHI,         SUBLANG_NEUTRAL,              0    },
371 372
    { LANG_DUTCH,          SUBLANG_NEUTRAL,              1252 },
    { LANG_ENGLISH,        SUBLANG_NEUTRAL,              1252 },
373
#ifdef LANG_ESPERANTO
374
    { LANG_ESPERANTO,      SUBLANG_NEUTRAL,              1252 },
375
#endif /* LANG_ESPERANTO */
376
    { LANG_ESTONIAN,       SUBLANG_NEUTRAL,              1257 },
377
    { LANG_FAEROESE,       SUBLANG_NEUTRAL,              1252 },
378
    { LANG_FARSI,          SUBLANG_NEUTRAL,              1256 },
379 380
    { LANG_FINNISH,        SUBLANG_NEUTRAL,              1252 },
    { LANG_FRENCH,         SUBLANG_NEUTRAL,              1252 },
381
#ifdef LANG_GAELIC
382
    { LANG_GAELIC,         SUBLANG_NEUTRAL,              1252 },
383
#endif /* LANG_GAELIC */
384 385
    { LANG_GALICIAN,       SUBLANG_NEUTRAL,              1252 },
    { LANG_GEORGIAN,       SUBLANG_NEUTRAL,              0    },
386 387
    { LANG_GERMAN,         SUBLANG_NEUTRAL,              1252 },
    { LANG_GREEK,          SUBLANG_NEUTRAL,              1253 },
388
    { LANG_GUJARATI,       SUBLANG_NEUTRAL,              0    },
389
    { LANG_HEBREW,         SUBLANG_NEUTRAL,              1255 },
390
    { LANG_HINDI,          SUBLANG_NEUTRAL,              0    },
391 392 393 394 395
    { LANG_HUNGARIAN,      SUBLANG_NEUTRAL,              1250 },
    { LANG_ICELANDIC,      SUBLANG_NEUTRAL,              1252 },
    { LANG_INDONESIAN,     SUBLANG_NEUTRAL,              1252 },
    { LANG_ITALIAN,        SUBLANG_NEUTRAL,              1252 },
    { LANG_JAPANESE,       SUBLANG_NEUTRAL,              932  },
396 397 398
    { LANG_KANNADA,        SUBLANG_NEUTRAL,              0    },
    { LANG_KAZAK,          SUBLANG_NEUTRAL,              1251 },
    { LANG_KONKANI,        SUBLANG_NEUTRAL,              0    },
399
    { LANG_KOREAN,         SUBLANG_NEUTRAL,              949  },
400
    { LANG_KYRGYZ,         SUBLANG_NEUTRAL,              1251 },
401 402 403
    { LANG_LATVIAN,        SUBLANG_NEUTRAL,              1257 },
    { LANG_LITHUANIAN,     SUBLANG_NEUTRAL,              1257 },
    { LANG_MACEDONIAN,     SUBLANG_NEUTRAL,              1251 },
404
    { LANG_MALAY,          SUBLANG_NEUTRAL,              1252 },
405 406
    { LANG_MARATHI,        SUBLANG_NEUTRAL,              0    },
    { LANG_MONGOLIAN,      SUBLANG_NEUTRAL,              1251 },
407
    { LANG_NEUTRAL,        SUBLANG_NEUTRAL,              1252 },
408 409 410
    { LANG_NORWEGIAN,      SUBLANG_NEUTRAL,              1252 },
    { LANG_POLISH,         SUBLANG_NEUTRAL,              1250 },
    { LANG_PORTUGUESE,     SUBLANG_NEUTRAL,              1252 },
411
    { LANG_PUNJABI,        SUBLANG_NEUTRAL,              0    },
412 413
    { LANG_ROMANIAN,       SUBLANG_NEUTRAL,              1250 },
    { LANG_RUSSIAN,        SUBLANG_NEUTRAL,              1251 },
414 415 416
    { LANG_SANSKRIT,       SUBLANG_NEUTRAL,              0    },
    { LANG_SERBIAN,        SUBLANG_NEUTRAL,              1250 },
    { LANG_SERBIAN,        SUBLANG_SERBIAN_CYRILLIC,     1251 },
417 418 419
    { LANG_SLOVAK,         SUBLANG_NEUTRAL,              1250 },
    { LANG_SLOVENIAN,      SUBLANG_NEUTRAL,              1250 },
    { LANG_SPANISH,        SUBLANG_NEUTRAL,              1252 },
420
    { LANG_SWAHILI,        SUBLANG_NEUTRAL,              1252 },
421
    { LANG_SWEDISH,        SUBLANG_NEUTRAL,              1252 },
422 423 424 425
    { LANG_SYRIAC,         SUBLANG_NEUTRAL,              0    },
    { LANG_TAMIL,          SUBLANG_NEUTRAL,              0    },
    { LANG_TATAR,          SUBLANG_NEUTRAL,              1251 },
    { LANG_TELUGU,         SUBLANG_NEUTRAL,              0    },
426 427 428
    { LANG_THAI,           SUBLANG_NEUTRAL,              874  },
    { LANG_TURKISH,        SUBLANG_NEUTRAL,              1254 },
    { LANG_UKRAINIAN,      SUBLANG_NEUTRAL,              1251 },
429 430 431
    { LANG_URDU,           SUBLANG_NEUTRAL,              1256 },
    { LANG_UZBEK,          SUBLANG_NEUTRAL,              1254 },
    { LANG_UZBEK,          SUBLANG_UZBEK_CYRILLIC,       1251 },
432 433 434 435 436 437 438
    { LANG_VIETNAMESE,     SUBLANG_NEUTRAL,              1258 }
#ifdef LANG_WALON
    , { LANG_WALON,          SUBLANG_NEUTRAL,              1252 }
#endif /* LANG_WALON */
#ifdef LANG_WELSH
    , { LANG_WELSH,          SUBLANG_NEUTRAL,              1252 }
#endif /* LANG_WELSH */
439 440
};

441
int get_language_codepage( unsigned short lang, unsigned short sublang )
442
{
443
    unsigned int i;
444
    int cp = -1, defcp = -1;
445 446 447 448 449 450 451 452 453 454 455 456

    for (i = 0; i < sizeof(lang2cps)/sizeof(lang2cps[0]); i++)
    {
        if (lang2cps[i].lang != lang) continue;
        if (lang2cps[i].sublang == sublang)
        {
            cp = lang2cps[i].cp;
            break;
        }
        if (lang2cps[i].sublang == SUBLANG_NEUTRAL) defcp = lang2cps[i].cp;
    }

457
    if (cp == -1) cp = defcp;
458
    assert( cp <= 0 || wine_cp_get_table(cp) );
459
    return cp;
460
}