/* cpp.c */

#include <stdio.h>
#include "types.h"


/* quick hack to get a cpp front end going */

cpp_parse(buf,cpp_stack,symtab)
char		*buf;
CPPN		**cpp_stack;
SYMENT		**symtab;
{
	char		tok[BUFSIZE];
	char		tok2[BUFSIZE];
	int		cp = 0;

	if (buf[0] != '#')
		return(0);
	if ((cp = gettok(NULL,buf,tok,cp,NULL,NULL)) < 0)
		return(0);
	if ((cp = gettok(NULL,buf,tok,cp,NULL,NULL)) < 0)
		return(0);
	if (!strcmp("define",tok) && cpp_useline(cpp_stack)) {
		if ((cp = gettok(NULL,buf,tok,cp,NULL,NULL)) < 0)
			return(0);
		add_sym(symtab,tok);
	}
	else if (!strcmp("undef",tok) && cpp_useline(cpp_stack)) {
		if ((cp = gettok(NULL,buf,tok,cp,NULL,NULL)) < 0)
			return(0);
		del_sym(symtab,tok);
	}
	else if (!strcmp("ifdef",tok) && cpp_useline(cpp_stack)) {
#ifdef DEBUG
		printf("#ifdef\n");
#endif
		if ((cp = gettok(NULL,buf,tok,cp,NULL,NULL)) < 0)
			return(0);
		if (find_sym(symtab,tok))
			push_if(cpp_stack,1);
		else
			push_if(cpp_stack,0);
	}
	else if (!strcmp("ifndef",tok) && cpp_useline(cpp_stack)) {
#ifdef DEBUG
		printf("#ifndef\n");
#endif
		if ((cp = gettok(NULL,buf,tok,cp,NULL,NULL)) < 0)
			return(0);
		if (!find_sym(symtab,tok))
			push_if(cpp_stack,1);
		else
			push_if(cpp_stack,0);
	}
	else if (!strcmp("if",tok) && cpp_useline(cpp_stack)) {
#ifdef DEBUG
		printf("#if\n");
#endif
		/* fprintf(stderr,"Warning:  #if not supported\n"); */
		push_if(cpp_stack,1);
	}
	else if (!strcmp("else",tok)) {
#ifdef DEBUG
		printf("#else\n");
#endif
		set_else(cpp_stack);
	}
	else if (!strcmp("endif",tok)) {
#ifdef DEBUG
		printf("#endif\n");
#endif
		pop_if(cpp_stack);
	}
	else if (!strcmp("include",tok) && cpp_useline(cpp_stack)) {
		if ((cp = gettok(NULL,buf,tok,cp,NULL,NULL)) < 0)
			return(0);
		if (tok[0] == '<') {
			char	itok[BUFSIZE];

			itok[0] = '\0';
			if ((cp = gettok(NULL,buf,tok,cp,NULL,NULL)) < 0)
				return(0);
			while (tok[0] != '>') {
				strcat(itok,tok);
				if ((cp = gettok(NULL,buf,tok,cp,NULL,NULL)) < 0)
					return(0);
			}
			sprintf(tok2,"%s%s",INCLUDE_DIR, itok);
			if (!cpp_include(cpp_stack,symtab,tok2))
				return(-1);
		} else if (tok[0] == '\"') {
			int i;
			
			for (i = 1; tok[i] != '\"' && tok[i] != '\0'; i++)
				tok2[i-1] = tok[i];
			tok2[i-1] = '\0';
			if (!cpp_include(cpp_stack,symtab,tok2))
				return(-1);
		}
	}
	return(1);
}

cpp_useline(cpp_stack)
CPPN		**cpp_stack;
{
	CPPN		*cur;

	if (*cpp_stack == NULL) {
		return(1);
	}
	cur = *cpp_stack;
	if (cur->expr_val != 0 && cur->in_else == 0) {
		return(1);
	}
	else if (cur->expr_val == 0 && cur->in_else != 0) {
		return(1);
	}
	else {
		return(0);
	}
}

cpp_rel(cpp_stack,symtab)
CPPN		**cpp_stack;
SYMENT		**symtab;
{
	CPPN	*cur;
	CPPN	*next;
	SYMENT	*scur;
	SYMENT	*snext;

	cur = *cpp_stack;
	while (cur != NULL) {
		next = cur->next;
		free(cur);
		cur = next;
	}	
	free(cpp_stack);
	scur = *symtab;
	while (scur != NULL) {
		snext = scur->next;
		free(scur->name);
		free(scur);
		scur = snext;
	}
	free(symtab);
}

add_sym(symtab,name)
SYMENT		**symtab;
char		*name;
{
	SYMENT		*cur;
	SYMENT		*prev;
	SYMENT		*new;

	if (find_sym(symtab,name) != NULL)
		return(1);
	prev = NULL;
	cur = *symtab;
	while (cur != NULL) {
		prev = cur;
		if (!strcmp(cur->name,name))
			break;
		cur = cur->next;
	}
	if (cur != NULL)
		return(1);
	new = (SYMENT *)malloc(sizeof(SYMENT));
	new->name = (char *)malloc(strlen(name)+1);
	strcpy(new->name,name);
	new->next = NULL;
	if (prev == NULL)
		*symtab = new;
	else
		prev->next = new;
	return(1);
}

del_sym(symtab,name)
SYMENT		**symtab;
char		*name;
{
	SYMENT		*cur;
	SYMENT		*prev;

	prev = NULL;
	cur = *symtab;
	while (cur != NULL) {
		if (!strcmp(cur->name,name))
			break;
		prev = cur;
		cur = cur->next;
	}
	if (cur == NULL)
		return(0);
	if (prev == NULL) {
		free(cur->name);
		free(cur);
		*symtab = NULL;
	}
	else {
		prev->next = cur->next;
		free(cur->name);
		free(cur);
	}
	return(1);
}

find_sym(symtab,name)
SYMENT		**symtab;
char		*name;
{
	SYMENT		*cur;

	cur = *symtab;
	while (cur != NULL) {
#ifdef DEBUG
		printf("cur->name = '%s'\n",cur->name);
#endif
		if (!strcmp(cur->name,name))
			break;
		cur = cur->next;
	}
	if (cur != NULL)
		return(1);
	return(0);
}

push_if(cpp_stack,val)
CPPN		**cpp_stack;
int		val;
{
	CPPN		*new;

	new = (CPPN *)malloc(sizeof(CPPN));
	new->expr_val = val;
	new->in_else = 0;
	new->next = *cpp_stack;
	*cpp_stack = new;
}

set_else(cpp_stack)
CPPN		**cpp_stack;
{
	CPPN		*cur;

	cur = *cpp_stack;
	if (cur == NULL) {
/*
		fprintf(stderr,"#else without matching #if[[n]def]\n");
*/
		return;
	}
	cur->in_else = 1;
}

pop_if(cpp_stack)
CPPN		**cpp_stack;
{
	CPPN		*next;
	CPPN		*cur;

	cur = *cpp_stack;
	if (cur == NULL) {
/*
		fprintf(stderr,"#endif without matching #if[[n]def]\n");
*/
		return;
	}
	next = cur->next;
	free(cur);
	*cpp_stack = next;
}

cpp_include(cpp_stack,symtab,name)
CPPN		**cpp_stack;
SYMENT		**symtab;
char		*name;
{
	char		buf[BUFSIZE];
	char		tok[BUFSIZE];
	int		cp;
	FILE		*fp;

#ifdef DEBUG
	printf("#include file = '%s'\n",name);
#endif
	if ((fp = fopen(name,"r")) == NULL) {
		fprintf(stderr,"cpp_include():  can't open file '%s'\n",name);
		return(0);
	}
	buf[0] = '\0';
	cp = 0;
	while ((cp = gettok(fp,buf,tok,cp,cpp_stack,symtab)) >= 0)
		;
#ifdef DEBUG
	printf("ending #include file = '%s'\n",name);
#endif
	fclose(fp);
	return(1);
}
