preproc.c 17.5 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Copyright 1998 Bertho A. Stultiens (BS)
 *
4 5 6 7 8 9 10 11 12 13 14 15
 * 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
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
17 18
 */

19
#include "config.h"
Jon Griffiths's avatar
Jon Griffiths committed
20
#include "wine/port.h"
21

22
#include <assert.h>
23
#include <ctype.h>
24
#include <fcntl.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25 26 27
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
28
#include <stdarg.h>
29 30 31
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
32 33 34
#ifdef HAVE_IO_H
# include <io.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
35

36
#include "wine/wpp.h"
37
#include "wpp_private.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38

39
struct pp_status pp_status;
Alexandre Julliard's avatar
Alexandre Julliard committed
40 41

#define HASHKEY		2039
42 43 44 45 46 47 48 49

typedef struct pp_def_state
{
    struct pp_def_state *next;
    pp_entry_t          *defines[HASHKEY];
} pp_def_state_t;

static pp_def_state_t *pp_def_state;
Alexandre Julliard's avatar
Alexandre Julliard committed
50 51

#define MAXIFSTACK	64
52
static pp_if_state_t if_stack[MAXIFSTACK];
53
static int if_stack_idx = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
54 55

#if 0
56 57
void pp_print_status(void) __attribute__((destructor));
void pp_print_status(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
58 59 60 61
{
	int i;
	int sum;
	int total = 0;
62
	pp_entry_t *ppp;
Alexandre Julliard's avatar
Alexandre Julliard committed
63

64
	fprintf(stderr, "Defines statistics:\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
65 66 67
	for(i = 0; i < HASHKEY; i++)
	{
		sum = 0;
68
		for(ppp = pp_def_state->defines[i]; ppp; ppp = ppp->next)
Alexandre Julliard's avatar
Alexandre Julliard committed
69 70
			sum++;
		total += sum;
71
		if (sum) fprintf(stderr, "%4d, %3d\n", i, sum);
Alexandre Julliard's avatar
Alexandre Julliard committed
72
	}
73
	fprintf(stderr, "Total defines: %d\n", total);
Alexandre Julliard's avatar
Alexandre Julliard committed
74 75 76
}
#endif

77 78 79 80 81 82 83 84
void *pp_xmalloc(size_t size)
{
    void *res;

    assert(size > 0);
    res = malloc(size);
    if(res == NULL)
    {
85 86
        /* Set the error flag */
        pp_status.state = 1;
87 88 89 90 91 92 93 94 95 96 97 98
    }
    return res;
}

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

    assert(size > 0);
    res = realloc(p, size);
    if(res == NULL)
    {
99 100
        /* Set the error flag */
        pp_status.state = 1;
101 102 103 104 105 106 107
    }
    return res;
}

char *pp_xstrdup(const char *str)
{
	char *s;
Jacek Caban's avatar
Jacek Caban committed
108
	int len;
109 110

	assert(str != NULL);
Jacek Caban's avatar
Jacek Caban committed
111 112
	len = strlen(str)+1;
	s = pp_xmalloc(len);
113 114
	if(!s)
		return NULL;
Jacek Caban's avatar
Jacek Caban committed
115
	return memcpy(s, str, len);
116 117
}

118
static char *wpp_default_lookup(const char *name, int type, const char *parent_name,
Matteo Bruni's avatar
Matteo Bruni committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
                                char **include_path, int include_path_count)
{
    char *cpy;
    char *cptr;
    char *path;
    const char *ccptr;
    int i, fd;

    cpy = pp_xmalloc(strlen(name)+1);
    if(!cpy)
        return NULL;
    cptr = cpy;

    for(ccptr = name; *ccptr; ccptr++)
    {
        /* Convert to forward slash */
        if(*ccptr == '\\') {
            /* kill double backslash */
            if(ccptr[1] == '\\')
                ccptr++;
            *cptr = '/';
        }else {
            *cptr = *ccptr;
        }
        cptr++;
    }
    *cptr = '\0';

147
    if(type && parent_name)
Matteo Bruni's avatar
Matteo Bruni committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    {
        /* Search directory of parent include and then -I path */
        const char *p;

        if ((p = strrchr( parent_name, '/' ))) p++;
        else p = parent_name;
        path = pp_xmalloc( (p - parent_name) + strlen(cpy) + 1 );
        if(!path)
        {
            free(cpy);
            return NULL;
        }
        memcpy( path, parent_name, p - parent_name );
        strcpy( path + (p - parent_name), cpy );
        fd = open( path, O_RDONLY );
        if (fd != -1)
        {
            close( fd );
            free( cpy );
            return path;
        }
        free( path );
    }
    /* Search -I path */
    for(i = 0; i < include_path_count; i++)
    {
        path = pp_xmalloc(strlen(include_path[i]) + strlen(cpy) + 2);
        if(!path)
        {
            free(cpy);
            return NULL;
        }
        strcpy(path, include_path[i]);
        strcat(path, "/");
        strcat(path, cpy);
        fd = open( path, O_RDONLY );
        if (fd != -1)
        {
            close( fd );
            free( cpy );
            return path;
        }
        free( path );
    }
    free( cpy );
    return NULL;
}

static void *wpp_default_open(const char *filename, int type) {
    return fopen(filename,"rt");
}

static void wpp_default_close(void *file) {
    fclose(file);
}

static int wpp_default_read(void *file, char *buffer, unsigned int len){
    return fread(buffer, 1, len, file);
}

static void wpp_default_write( const char *buffer, unsigned int len ) {
    fwrite(buffer, 1, len, ppy_out);
}

212
/* Don't comment on the hash, it's primitive but functional... */
213
static int pphash(const char *str)
Alexandre Julliard's avatar
Alexandre Julliard committed
214 215 216 217 218 219 220
{
	int sum = 0;
	while(*str)
		sum += *str++;
	return sum % HASHKEY;
}

221
pp_entry_t *pplookup(const char *ident)
Alexandre Julliard's avatar
Alexandre Julliard committed
222
{
223
	int idx;
224 225
	pp_entry_t *ppp;

226 227 228
	if(!ident)
		return NULL;
	idx = pphash(ident);
229
	for(ppp = pp_def_state->defines[idx]; ppp; ppp = ppp->next)
Alexandre Julliard's avatar
Alexandre Julliard committed
230 231 232 233 234 235 236
	{
		if(!strcmp(ident, ppp->ident))
			return ppp;
	}
	return NULL;
}

237
static void free_pp_entry( pp_entry_t *ppp, int idx )
Alexandre Julliard's avatar
Alexandre Julliard committed
238
{
239
	if(ppp->iep)
Alexandre Julliard's avatar
Alexandre Julliard committed
240
	{
241
		if(ppp->iep == pp_includelogiclist)
242
		{
243 244 245
			pp_includelogiclist = ppp->iep->next;
			if(pp_includelogiclist)
				pp_includelogiclist->prev = NULL;
246 247 248 249 250 251 252 253 254 255 256
		}
		else
		{
			ppp->iep->prev->next = ppp->iep->next;
			if(ppp->iep->next)
				ppp->iep->next->prev = ppp->iep->prev;
		}
		free(ppp->iep->filename);
		free(ppp->iep);
	}

257
	if(pp_def_state->defines[idx] == ppp)
258
	{
259 260 261
		pp_def_state->defines[idx] = ppp->next;
		if(pp_def_state->defines[idx])
			pp_def_state->defines[idx]->prev = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
262 263 264 265 266 267 268
	}
	else
	{
		ppp->prev->next = ppp->next;
		if(ppp->next)
			ppp->next->prev = ppp->prev;
	}
269

Alexandre Julliard's avatar
Alexandre Julliard committed
270
	free(ppp);
271 272 273
}

/* push a new (empty) define state */
274
int pp_push_define_state(void)
275 276
{
    pp_def_state_t *state = pp_xmalloc( sizeof(*state) );
277 278
    if(!state)
        return 1;
279 280 281 282

    memset( state->defines, 0, sizeof(state->defines) );
    state->next = pp_def_state;
    pp_def_state = state;
283
    return 0;
284 285 286 287 288 289 290 291 292 293 294
}

/* pop the current define state */
void pp_pop_define_state(void)
{
    int i;
    pp_entry_t *ppp;
    pp_def_state_t *state;

    for (i = 0; i < HASHKEY; i++)
    {
295
        while ((ppp = pp_def_state->defines[i]) != NULL) pp_del_define( ppp->ident );
296 297 298 299 300 301 302 303 304
    }
    state = pp_def_state;
    pp_def_state = state->next;
    free( state );
}

void pp_del_define(const char *name)
{
	pp_entry_t *ppp;
305
	int idx = pphash(name);
306 307 308 309

	if((ppp = pplookup(name)) == NULL)
	{
		if(pp_status.pedantic)
310
			ppy_warning("%s was not defined", name);
311 312 313
		return;
	}

314 315 316
	if(pp_status.debug)
		printf("Deleting (%s, %d) <%s>\n", pp_status.input, pp_status.line_number, name);

317 318 319
	free( ppp->ident );
	free( ppp->subst.text );
	free( ppp->filename );
320
	free_pp_entry( ppp, idx );
Alexandre Julliard's avatar
Alexandre Julliard committed
321 322
}

323
pp_entry_t *pp_add_define(const char *def, const char *text)
Alexandre Julliard's avatar
Alexandre Julliard committed
324 325 326
{
	int len;
	char *cptr;
327
	int idx;
328 329
	pp_entry_t *ppp;

330 331 332
	if(!def)
		return NULL;
	idx = pphash(def);
333
	if((ppp = pplookup(def)) != NULL)
Alexandre Julliard's avatar
Alexandre Julliard committed
334
	{
335
		if(pp_status.pedantic)
336
			ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", def, ppp->filename, ppp->linenumber);
337
		pp_del_define(def);
Alexandre Julliard's avatar
Alexandre Julliard committed
338
	}
339
	ppp = pp_xmalloc(sizeof(pp_entry_t));
340 341
	if(!ppp)
		return NULL;
342
	memset( ppp, 0, sizeof(*ppp) );
343 344 345
	ppp->ident = pp_xstrdup(def);
	if(!ppp->ident)
		goto error;
346
	ppp->type = def_define;
347 348 349
	ppp->subst.text = text ? pp_xstrdup(text) : NULL;
	if(text && !ppp->subst.text)
		goto error;
350
	ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
351
	if(!ppp->filename)
352
		goto error;
353
	ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
354 355
	ppp->next = pp_def_state->defines[idx];
	pp_def_state->defines[idx] = ppp;
Alexandre Julliard's avatar
Alexandre Julliard committed
356 357
	if(ppp->next)
		ppp->next->prev = ppp;
358
	if(ppp->subst.text)
Alexandre Julliard's avatar
Alexandre Julliard committed
359
	{
360
		/* Strip trailing white space from subst text */
361 362
		len = strlen(ppp->subst.text);
		while(len && strchr(" \t\r\n", ppp->subst.text[len-1]))
363
		{
364
			ppp->subst.text[--len] = '\0';
365 366
		}
		/* Strip leading white space from subst text */
367
		for(cptr = ppp->subst.text; *cptr && strchr(" \t\r", *cptr); cptr++)
Alexandre Julliard's avatar
Alexandre Julliard committed
368
		;
369 370
		if(ppp->subst.text != cptr)
			memmove(ppp->subst.text, cptr, strlen(cptr)+1);
371
	}
372
	if(pp_status.debug)
373
		printf("Added define (%s, %d) <%s> to <%s>\n", pp_status.input, pp_status.line_number, ppp->ident, ppp->subst.text ? ppp->subst.text : "(null)");
374 375

	return ppp;
376 377 378 379 380 381

error:
	free(ppp->ident);
	free(ppp->subst.text);
	free(ppp);
	return NULL;
382 383
}

384
pp_entry_t *pp_add_macro(char *id, marg_t *args[], int nargs, mtext_t *exp)
385
{
386
	int idx;
387 388
	pp_entry_t *ppp;

389 390 391
	if(!id)
		return NULL;
	idx = pphash(id);
392 393
	if((ppp = pplookup(id)) != NULL)
	{
394
		if(pp_status.pedantic)
395
			ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", id, ppp->filename, ppp->linenumber);
396
		pp_del_define(id);
397
	}
398
	ppp = pp_xmalloc(sizeof(pp_entry_t));
399 400
	if(!ppp)
		return NULL;
401
	memset( ppp, 0, sizeof(*ppp) );
402 403 404 405 406
	ppp->ident	= id;
	ppp->type	= def_macro;
	ppp->margs	= args;
	ppp->nargs	= nargs;
	ppp->subst.mtext= exp;
407
	ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
408 409 410 411 412
	if(!ppp->filename)
	{
		free(ppp);
		return NULL;
	}
413
	ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
414 415
	ppp->next	= pp_def_state->defines[idx];
	pp_def_state->defines[idx] = ppp;
416 417 418
	if(ppp->next)
		ppp->next->prev = ppp;

419
	if(pp_status.debug)
420
	{
421
		fprintf(stderr, "Added macro (%s, %d) <%s(%d)> to <", pp_status.input, pp_status.line_number, ppp->ident, nargs);
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
		for(; exp; exp = exp->next)
		{
			switch(exp->type)
			{
			case exp_text:
				fprintf(stderr, " \"%s\" ", exp->subst.text);
				break;
			case exp_stringize:
				fprintf(stderr, " #(%d) ", exp->subst.argidx);
				break;
			case exp_concat:
				fprintf(stderr, "##");
				break;
			case exp_subst:
				fprintf(stderr, " <%d> ", exp->subst.argidx);
				break;
			}
		}
		fprintf(stderr, ">\n");
	}
	return ppp;
Alexandre Julliard's avatar
Alexandre Julliard committed
443 444
}

445 446 447 448 449 450

/*
 *-------------------------------------------------------------------------
 * Include management
 *-------------------------------------------------------------------------
 */
451
#if defined(_WIN32) || defined(__MSDOS__)
Alexandre Julliard's avatar
Alexandre Julliard committed
452 453 454 455 456 457 458 459
#define INCLUDESEPARATOR	";"
#else
#define INCLUDESEPARATOR	":"
#endif

static char **includepath;
static int nincludepath = 0;

460
int wpp_add_include_path(const char *path)
Alexandre Julliard's avatar
Alexandre Julliard committed
461 462
{
	char *tok;
463
	char *cpy = pp_xstrdup(path);
464 465
	if(!cpy)
		return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
466 467 468 469

	tok = strtok(cpy, INCLUDESEPARATOR);
	while(tok)
	{
Jacek Caban's avatar
Jacek Caban committed
470 471 472
		if(*tok) {
			char *dir;
			char *cptr;
473 474
			char **new_path;

Jacek Caban's avatar
Jacek Caban committed
475
			dir = pp_xstrdup(tok);
476 477 478 479 480
			if(!dir)
			{
				free(cpy);
				return 1;
			}
Jacek Caban's avatar
Jacek Caban committed
481 482 483 484 485 486 487 488 489 490 491
			for(cptr = dir; *cptr; cptr++)
			{
				/* Convert to forward slash */
				if(*cptr == '\\')
					*cptr = '/';
			}
			/* Kill eventual trailing '/' */
			if(*(cptr = dir + strlen(dir)-1) == '/')
				*cptr = '\0';

			/* Add to list */
492 493 494 495 496 497 498 499 500
			new_path = pp_xrealloc(includepath, (nincludepath+1) * sizeof(*includepath));
			if(!new_path)
			{
				free(dir);
				free(cpy);
				return 1;
			}
			includepath = new_path;
			includepath[nincludepath] = dir;
Jacek Caban's avatar
Jacek Caban committed
501
			nincludepath++;
Alexandre Julliard's avatar
Alexandre Julliard committed
502 503 504 505
		}
		tok = strtok(NULL, INCLUDESEPARATOR);
	}
	free(cpy);
506
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
507 508
}

509
char *wpp_find_include(const char *name, const char *parent_name)
Alexandre Julliard's avatar
Alexandre Julliard committed
510
{
511
    return wpp_default_lookup(name, !!parent_name, parent_name, includepath, nincludepath);
512
}
Alexandre Julliard's avatar
Alexandre Julliard committed
513

514
void *pp_open_include(const char *name, int type, const char *parent_name, char **newpath)
515 516
{
    char *path;
Matteo Bruni's avatar
Matteo Bruni committed
517
    void *fp;
518

519
    if (!(path = wpp_callbacks->lookup(name, type, parent_name, includepath,
Matteo Bruni's avatar
Matteo Bruni committed
520
                                       nincludepath))) return NULL;
521
    fp = wpp_callbacks->open(path, type);
522 523 524 525 526 527 528 529 530 531 532

    if (fp)
    {
        if (pp_status.debug)
            printf("Going to include <%s>\n", path);
        if (newpath) *newpath = path;
        else free( path );
        return fp;
    }
    free( path );
    return NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
533 534
}

535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
/*
 *-------------------------------------------------------------------------
 * #if, #ifdef, #ifndef, #else, #elif and #endif state management
 *
 * #if state transitions are made on basis of the current TOS and the next
 * required state. The state transitions are required to housekeep because
 * #if:s can be nested. The ignore case is activated to prevent output from
 * within a false clause.
 * Some special cases come from the fact that the #elif cases are not
 * binary, but three-state. The problem is that all other elif-cases must
 * be false when one true one has been found. A second problem is that the
 * #else clause is a final clause. No extra #else:s may follow.
 *
 * The states mean:
 * if_true	Process input to output
 * if_false	Process input but no output
 * if_ignore	Process input but no output
 * if_elif	Process input but no output
 * if_elsefalse	Process input but no output
 * if_elsettrue	Process input to output
 *
 * The possible state-sequences are [state(stack depth)] (rest can be deduced):
 *	TOS		#if 1		#else			#endif
 *	if_true(n)	if_true(n+1)	if_elsefalse(n+1)
 *	if_false(n)	if_ignore(n+1)	if_ignore(n+1)
 *	if_elsetrue(n)	if_true(n+1)	if_elsefalse(n+1)
 *	if_elsefalse(n)	if_ignore(n+1)	if_ignore(n+1)
 *	if_elif(n)	if_ignore(n+1)	if_ignore(n+1)
 *	if_ignore(n)	if_ignore(n+1)	if_ignore(n+1)
 *
 *	TOS		#if 1		#elif 0		#else		#endif
 *	if_true(n)	if_true(n+1)	if_elif(n+1)	if_elif(n+1)
 *	if_false(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
 *	if_elsetrue(n)	if_true(n+1)	if_elif(n+1)	if_elif(n+1)
 *	if_elsefalse(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
 *	if_elif(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
 *	if_ignore(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
 *
 *	TOS		#if 0		#elif 1		#else		#endif
 *	if_true(n)	if_false(n+1)	if_true(n+1)	if_elsefalse(n+1)
 *	if_false(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
 *	if_elsetrue(n)	if_false(n+1)	if_true(n+1)	if_elsefalse(n+1)
 *	if_elsefalse(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
 *	if_elif(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
 *	if_ignore(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
 *
 *-------------------------------------------------------------------------
 */
583
static const char * const pp_if_state_str[] = {
584 585 586 587 588 589 590 591
	"if_false",
	"if_true",
	"if_elif",
	"if_elsefalse",
	"if_elsetrue",
	"if_ignore"
};

592
void pp_push_if(pp_if_state_t s)
Alexandre Julliard's avatar
Alexandre Julliard committed
593
{
594
	if(if_stack_idx >= MAXIFSTACK)
595
		pp_internal_error(__FILE__, __LINE__, "#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)", MAXIFSTACK);
596

597 598
	if(pp_flex_debug)
		fprintf(stderr, "Push if %s:%d: %s(%d) -> %s(%d)\n", pp_status.input, pp_status.line_number, pp_if_state_str[pp_if_state()], if_stack_idx, pp_if_state_str[s], if_stack_idx+1);
599 600 601 602 603 604 605 606 607 608 609 610

	if_stack[if_stack_idx++] = s;

	switch(s)
	{
	case if_true:
	case if_elsetrue:
		break;
	case if_false:
	case if_elsefalse:
	case if_elif:
	case if_ignore:
611
		pp_push_ignore_state();
612
		break;
613 614
	default:
		pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
615 616 617
	}
}

618
pp_if_state_t pp_pop_if(void)
619 620
{
	if(if_stack_idx <= 0)
621
	{
622
		ppy_error("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
623 624
		return if_error;
	}
625

626
	switch(pp_if_state())
627 628 629 630 631 632 633 634
	{
	case if_true:
	case if_elsetrue:
		break;
	case if_false:
	case if_elsefalse:
	case if_elif:
	case if_ignore:
635
		pp_pop_ignore_state();
636
		break;
637 638
	default:
		pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
639 640
	}

641
	if(pp_flex_debug)
642
		fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
643 644 645
				pp_status.input,
				pp_status.line_number,
				pp_if_state_str[pp_if_state()],
646
				if_stack_idx,
647
				pp_if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
648 649 650
				if_stack_idx-1);

	return if_stack[--if_stack_idx];
Alexandre Julliard's avatar
Alexandre Julliard committed
651 652
}

653
pp_if_state_t pp_if_state(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
654
{
655 656 657 658 659 660 661
	if(!if_stack_idx)
		return if_true;
	else
		return if_stack[if_stack_idx-1];
}


662
void pp_next_if_state(int i)
663
{
664
	switch(pp_if_state())
665 666 667
	{
	case if_true:
	case if_elsetrue:
668
		pp_push_if(i ? if_true : if_false);
669 670 671 672 673
		break;
	case if_false:
	case if_elsefalse:
	case if_elif:
	case if_ignore:
674
		pp_push_if(if_ignore);
675 676
		break;
	default:
677
		pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #{if,ifdef,ifndef} directive", (int)pp_if_state());
678
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
679 680
}

681
int pp_get_if_depth(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
682
{
683
	return if_stack_idx;
Alexandre Julliard's avatar
Alexandre Julliard committed
684 685
}

686 687 688 689 690 691 692 693 694 695 696 697 698
/* #define WANT_NEAR_INDICATION */

static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
{
	fprintf(stderr, "%s:%d:%d: %s: ", pp_status.input ? pp_status.input : "stdin",
                pp_status.line_number, pp_status.char_number, t);
	vfprintf(stderr, s, ap);
#ifdef WANT_NEAR_INDICATION
	{
		char *cpy, *p;
		if(n)
		{
			cpy = pp_xstrdup(n);
699 700
			if(!cpy)
				goto end;
701 702 703 704 705
			for (p = cpy; *p; p++) if(!isprint(*p)) *p = ' ';
			fprintf(stderr, " near '%s'", cpy);
			free(cpy);
		}
	}
706
end:
707 708 709 710
#endif
	fprintf(stderr, "\n");
}

711 712 713 714 715 716 717 718 719 720 721 722 723
static void wpp_default_error(const char *file, int line, int col, const char *near, const char *msg, va_list ap)
{
	generic_msg(msg, "Error", near, ap);
	exit(1);
}

static void wpp_default_warning(const char *file, int line, int col, const char *near, const char *msg, va_list ap)
{
	generic_msg(msg, "Warning", near, ap);
}

static const struct wpp_callbacks default_callbacks =
{
Matteo Bruni's avatar
Matteo Bruni committed
724 725 726 727 728
	wpp_default_lookup,
	wpp_default_open,
	wpp_default_close,
	wpp_default_read,
	wpp_default_write,
729 730 731 732 733 734
	wpp_default_error,
	wpp_default_warning,
};

const struct wpp_callbacks *wpp_callbacks = &default_callbacks;

735
int ppy_error(const char *s, ...)
736 737 738
{
	va_list ap;
	va_start(ap, s);
739
	wpp_callbacks->error(pp_status.input, pp_status.line_number, pp_status.char_number, ppy_text, s, ap);
740
	va_end(ap);
741
	pp_status.state = 1;
742 743 744
	return 1;
}

745
int ppy_warning(const char *s, ...)
746 747 748
{
	va_list ap;
	va_start(ap, s);
749
	wpp_callbacks->warning(pp_status.input, pp_status.line_number, pp_status.char_number, ppy_text, s, ap);
750 751 752 753 754 755 756 757 758 759 760 761 762 763
	va_end(ap);
	return 0;
}

void pp_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);
}