1 /*
2  * Copyright 1998 Bertho A. Stultiens (BS)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * 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
17  */
18 
19 #include <assert.h>
20 #include <ctype.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 
27 #include "wpp_private.h"
28 
29 struct pp_status pp_status;
30 
31 #define HASHKEY		2039
32 
33 typedef struct pp_def_state
34 {
35     struct pp_def_state *next;
36     pp_entry_t          *defines[HASHKEY];
37 } pp_def_state_t;
38 
39 static pp_def_state_t *pp_def_state;
40 
41 #define MAXIFSTACK	64
42 static pp_if_state_t if_stack[MAXIFSTACK];
43 static int if_stack_idx = 0;
44 
45 void *pp_xmalloc(size_t size)
46 {
47     void *res;
48 
49     assert(size > 0);
50     res = malloc(size);
51     if(res == NULL)
52     {
53         /* Set the error flag */
54         pp_status.state = 1;
55     }
56     return res;
57 }
58 
59 void *pp_xrealloc(void *p, size_t size)
60 {
61     void *res;
62 
63     assert(size > 0);
64     res = realloc(p, size);
65     if(res == NULL)
66     {
67         /* Set the error flag */
68         pp_status.state = 1;
69     }
70     return res;
71 }
72 
73 char *pp_xstrdup(const char *str)
74 {
75 	char *s;
76 	int len;
77 
78 	assert(str != NULL);
79 	len = strlen(str)+1;
80 	s = pp_xmalloc(len);
81 	if(!s)
82 		return NULL;
83 	return memcpy(s, str, len);
84 }
85 
86 /* Don't comment on the hash, it's primitive but functional... */
87 static int pphash(const char *str)
88 {
89 	int sum = 0;
90 	while(*str)
91 		sum += *str++;
92 	return sum % HASHKEY;
93 }
94 
95 pp_entry_t *pplookup(const char *ident)
96 {
97 	int idx;
98 	pp_entry_t *ppp;
99 
100 	if(!ident)
101 		return NULL;
102 	idx = pphash(ident);
103 	for(ppp = pp_def_state->defines[idx]; ppp; ppp = ppp->next)
104 	{
105 		if(!strcmp(ident, ppp->ident))
106 			return ppp;
107 	}
108 	return NULL;
109 }
110 
111 static void free_pp_entry( pp_entry_t *ppp, int idx )
112 {
113 	if(ppp->iep)
114 	{
115 		if(ppp->iep == pp_includelogiclist)
116 		{
117 			pp_includelogiclist = ppp->iep->next;
118 			if(pp_includelogiclist)
119 				pp_includelogiclist->prev = NULL;
120 		}
121 		else
122 		{
123 			ppp->iep->prev->next = ppp->iep->next;
124 			if(ppp->iep->next)
125 				ppp->iep->next->prev = ppp->iep->prev;
126 		}
127 		free(ppp->iep->filename);
128 		free(ppp->iep);
129 	}
130 
131 	if(pp_def_state->defines[idx] == ppp)
132 	{
133 		pp_def_state->defines[idx] = ppp->next;
134 		if(pp_def_state->defines[idx])
135 			pp_def_state->defines[idx]->prev = NULL;
136 	}
137 	else
138 	{
139 		ppp->prev->next = ppp->next;
140 		if(ppp->next)
141 			ppp->next->prev = ppp->prev;
142 	}
143 
144 	free(ppp);
145 }
146 
147 /* push a new (empty) define state */
148 int pp_push_define_state(void)
149 {
150     pp_def_state_t *state = pp_xmalloc( sizeof(*state) );
151     if(!state)
152         return 1;
153 
154     memset( state->defines, 0, sizeof(state->defines) );
155     state->next = pp_def_state;
156     pp_def_state = state;
157     return 0;
158 }
159 
160 /* pop the current define state */
161 void pp_pop_define_state(void)
162 {
163     int i;
164     pp_entry_t *ppp;
165     pp_def_state_t *state;
166 
167     for (i = 0; i < HASHKEY; i++)
168     {
169         while ((ppp = pp_def_state->defines[i]) != NULL) pp_del_define( ppp->ident );
170     }
171     state = pp_def_state;
172     pp_def_state = state->next;
173     free( state );
174 }
175 
176 void pp_del_define(const char *name)
177 {
178 	pp_entry_t *ppp;
179 	int idx = pphash(name);
180 
181 	if((ppp = pplookup(name)) == NULL)
182 	{
183 		if(pp_status.pedantic)
184 			ppy_warning("%s was not defined", name);
185 		return;
186 	}
187 
188 	free( ppp->ident );
189 	free( ppp->subst.text );
190 	free( ppp->filename );
191 	free_pp_entry( ppp, idx );
192 }
193 
194 pp_entry_t *pp_add_define(const char *def, const char *text)
195 {
196 	int len;
197 	char *cptr;
198 	int idx;
199 	pp_entry_t *ppp;
200 
201 	if(!def)
202 		return NULL;
203 	idx = pphash(def);
204 	if((ppp = pplookup(def)) != NULL)
205 	{
206 		if(pp_status.pedantic)
207 			ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", def, ppp->filename, ppp->linenumber);
208 		pp_del_define(def);
209 	}
210 	ppp = pp_xmalloc(sizeof(pp_entry_t));
211 	if(!ppp)
212 		return NULL;
213 	memset( ppp, 0, sizeof(*ppp) );
214 	ppp->ident = pp_xstrdup(def);
215 	if(!ppp->ident)
216 		goto error;
217 	ppp->type = def_define;
218 	ppp->subst.text = text ? pp_xstrdup(text) : NULL;
219 	if(text && !ppp->subst.text)
220 		goto error;
221 	ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
222 	if(!ppp->filename)
223 		goto error;
224 	ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
225 	ppp->next = pp_def_state->defines[idx];
226 	pp_def_state->defines[idx] = ppp;
227 	if(ppp->next)
228 		ppp->next->prev = ppp;
229 	if(ppp->subst.text)
230 	{
231 		/* Strip trailing white space from subst text */
232 		len = strlen(ppp->subst.text);
233 		while(len && strchr(" \t\r\n", ppp->subst.text[len-1]))
234 		{
235 			ppp->subst.text[--len] = '\0';
236 		}
237 		/* Strip leading white space from subst text */
238 		for(cptr = ppp->subst.text; *cptr && strchr(" \t\r", *cptr); cptr++)
239 		;
240 		if(ppp->subst.text != cptr)
241 			memmove(ppp->subst.text, cptr, strlen(cptr)+1);
242 	}
243 	return ppp;
244 
245 error:
246 	free(ppp->ident);
247 	free(ppp->subst.text);
248 	free(ppp);
249 	return NULL;
250 }
251 
252 pp_entry_t *pp_add_macro(char *id, marg_t *args[], int nargs, mtext_t *exp)
253 {
254 	int idx;
255 	pp_entry_t *ppp;
256 
257 	if(!id)
258 		return NULL;
259 	idx = pphash(id);
260 	if((ppp = pplookup(id)) != NULL)
261 	{
262 		if(pp_status.pedantic)
263 			ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", id, ppp->filename, ppp->linenumber);
264 		pp_del_define(id);
265 	}
266 	ppp = pp_xmalloc(sizeof(pp_entry_t));
267 	if(!ppp)
268 		return NULL;
269 	memset( ppp, 0, sizeof(*ppp) );
270 	ppp->ident	= id;
271 	ppp->type	= def_macro;
272 	ppp->margs	= args;
273 	ppp->nargs	= nargs;
274 	ppp->subst.mtext= exp;
275 	ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
276 	if(!ppp->filename)
277 	{
278 		free(ppp);
279 		return NULL;
280 	}
281 	ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
282 	ppp->next	= pp_def_state->defines[idx];
283 	pp_def_state->defines[idx] = ppp;
284 	if(ppp->next)
285 		ppp->next->prev = ppp;
286 	return ppp;
287 }
288 
289 
290 void *pp_open_include(const char *name, int type, const char *parent_name, char **newpath)
291 {
292     char *path;
293     void *fp;
294 
295     if (!(path = wpp_lookup(name, type, parent_name))) return NULL;
296     fp = wpp_open(path, type);
297 
298     if (fp)
299     {
300         if (newpath) *newpath = path;
301         else free( path );
302         return fp;
303     }
304     free( path );
305     return NULL;
306 }
307 
308 /*
309  *-------------------------------------------------------------------------
310  * #if, #ifdef, #ifndef, #else, #elif and #endif state management
311  *
312  * #if state transitions are made on basis of the current TOS and the next
313  * required state. The state transitions are required to housekeep because
314  * #if:s can be nested. The ignore case is activated to prevent output from
315  * within a false clause.
316  * Some special cases come from the fact that the #elif cases are not
317  * binary, but three-state. The problem is that all other elif-cases must
318  * be false when one true one has been found. A second problem is that the
319  * #else clause is a final clause. No extra #else:s may follow.
320  *
321  * The states mean:
322  * if_true	Process input to output
323  * if_false	Process input but no output
324  * if_ignore	Process input but no output
325  * if_elif	Process input but no output
326  * if_elsefalse	Process input but no output
327  * if_elsettrue	Process input to output
328  *
329  * The possible state-sequences are [state(stack depth)] (rest can be deduced):
330  *	TOS		#if 1		#else			#endif
331  *	if_true(n)	if_true(n+1)	if_elsefalse(n+1)
332  *	if_false(n)	if_ignore(n+1)	if_ignore(n+1)
333  *	if_elsetrue(n)	if_true(n+1)	if_elsefalse(n+1)
334  *	if_elsefalse(n)	if_ignore(n+1)	if_ignore(n+1)
335  *	if_elif(n)	if_ignore(n+1)	if_ignore(n+1)
336  *	if_ignore(n)	if_ignore(n+1)	if_ignore(n+1)
337  *
338  *	TOS		#if 1		#elif 0		#else		#endif
339  *	if_true(n)	if_true(n+1)	if_elif(n+1)	if_elif(n+1)
340  *	if_false(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
341  *	if_elsetrue(n)	if_true(n+1)	if_elif(n+1)	if_elif(n+1)
342  *	if_elsefalse(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
343  *	if_elif(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
344  *	if_ignore(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
345  *
346  *	TOS		#if 0		#elif 1		#else		#endif
347  *	if_true(n)	if_false(n+1)	if_true(n+1)	if_elsefalse(n+1)
348  *	if_false(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
349  *	if_elsetrue(n)	if_false(n+1)	if_true(n+1)	if_elsefalse(n+1)
350  *	if_elsefalse(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
351  *	if_elif(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
352  *	if_ignore(n)	if_ignore(n+1)	if_ignore(n+1)	if_ignore(n+1)
353  *
354  *-------------------------------------------------------------------------
355  */
356 
357 void pp_push_if(pp_if_state_t s)
358 {
359 	if(if_stack_idx >= MAXIFSTACK)
360 		pp_internal_error(__FILE__, __LINE__, "#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)", MAXIFSTACK);
361 
362 	if_stack[if_stack_idx++] = s;
363 
364 	switch(s)
365 	{
366 	case if_true:
367 	case if_elsetrue:
368 		break;
369 	case if_false:
370 	case if_elsefalse:
371 	case if_elif:
372 	case if_ignore:
373 		pp_push_ignore_state();
374 		break;
375 	default:
376 		pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
377 	}
378 }
379 
380 pp_if_state_t pp_pop_if(void)
381 {
382 	if(if_stack_idx <= 0)
383 	{
384 		ppy_error("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
385 		return if_error;
386 	}
387 
388 	switch(pp_if_state())
389 	{
390 	case if_true:
391 	case if_elsetrue:
392 		break;
393 	case if_false:
394 	case if_elsefalse:
395 	case if_elif:
396 	case if_ignore:
397 		pp_pop_ignore_state();
398 		break;
399 	default:
400 		pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
401 	}
402 	return if_stack[--if_stack_idx];
403 }
404 
405 pp_if_state_t pp_if_state(void)
406 {
407 	if(!if_stack_idx)
408 		return if_true;
409 	else
410 		return if_stack[if_stack_idx-1];
411 }
412 
413 
414 void pp_next_if_state(int i)
415 {
416 	switch(pp_if_state())
417 	{
418 	case if_true:
419 	case if_elsetrue:
420 		pp_push_if(i ? if_true : if_false);
421 		break;
422 	case if_false:
423 	case if_elsefalse:
424 	case if_elif:
425 	case if_ignore:
426 		pp_push_if(if_ignore);
427 		break;
428 	default:
429 		pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #{if,ifdef,ifndef} directive", (int)pp_if_state());
430 	}
431 }
432 
433 int pp_get_if_depth(void)
434 {
435 	return if_stack_idx;
436 }
437 
438 void WINAPIV pp_internal_error(const char *file, int line, const char *s, ...)
439 {
440 	__ms_va_list ap;
441 	__ms_va_start(ap, s);
442 	fprintf(stderr, "Internal error (please report) %s %d: ", file, line);
443 	vfprintf(stderr, s, ap);
444 	fprintf(stderr, "\n");
445 	__ms_va_end(ap);
446 	exit(3);
447 }
448