wined3d: Pass a wined3d_context_gl structure to shader_glsl_generate_compute_shader().
[wine.git] / libs / wpp / preproc.c
blob1bd10cd578cdd80a1db50cadf784148d4be5c600
1 /*
2 * Copyright 1998 Bertho A. Stultiens (BS)
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.
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.
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
19 #include "config.h"
20 #include "wine/port.h"
22 #include <assert.h>
23 #include <ctype.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
33 #include "wine/wpp.h"
34 #include "wpp_private.h"
36 struct pp_status pp_status;
38 #define HASHKEY 2039
40 typedef struct pp_def_state
42 struct pp_def_state *next;
43 pp_entry_t *defines[HASHKEY];
44 } pp_def_state_t;
46 static pp_def_state_t *pp_def_state;
48 #define MAXIFSTACK 64
49 static pp_if_state_t if_stack[MAXIFSTACK];
50 static int if_stack_idx = 0;
52 #if 0
53 void pp_print_status(void) __attribute__((destructor));
54 void pp_print_status(void)
56 int i;
57 int sum;
58 int total = 0;
59 pp_entry_t *ppp;
61 fprintf(stderr, "Defines statistics:\n");
62 for(i = 0; i < HASHKEY; i++)
64 sum = 0;
65 for(ppp = pp_def_state->defines[i]; ppp; ppp = ppp->next)
66 sum++;
67 total += sum;
68 if (sum) fprintf(stderr, "%4d, %3d\n", i, sum);
70 fprintf(stderr, "Total defines: %d\n", total);
72 #endif
74 void *pp_xmalloc(size_t size)
76 void *res;
78 assert(size > 0);
79 res = malloc(size);
80 if(res == NULL)
82 /* Set the error flag */
83 pp_status.state = 1;
85 return res;
88 void *pp_xrealloc(void *p, size_t size)
90 void *res;
92 assert(size > 0);
93 res = realloc(p, size);
94 if(res == NULL)
96 /* Set the error flag */
97 pp_status.state = 1;
99 return res;
102 char *pp_xstrdup(const char *str)
104 char *s;
105 int len;
107 assert(str != NULL);
108 len = strlen(str)+1;
109 s = pp_xmalloc(len);
110 if(!s)
111 return NULL;
112 return memcpy(s, str, len);
115 static char *wpp_default_lookup(const char *name, int type, const char *parent_name,
116 char **include_path, int include_path_count)
118 char *cpy;
119 char *cptr;
120 char *path;
121 const char *ccptr;
122 int i, fd;
124 cpy = pp_xmalloc(strlen(name)+1);
125 if(!cpy)
126 return NULL;
127 cptr = cpy;
129 for(ccptr = name; *ccptr; ccptr++)
131 /* Convert to forward slash */
132 if(*ccptr == '\\') {
133 /* kill double backslash */
134 if(ccptr[1] == '\\')
135 ccptr++;
136 *cptr = '/';
137 }else {
138 *cptr = *ccptr;
140 cptr++;
142 *cptr = '\0';
144 if(type && parent_name)
146 /* Search directory of parent include and then -I path */
147 const char *p;
149 if ((p = strrchr( parent_name, '/' ))) p++;
150 else p = parent_name;
151 path = pp_xmalloc( (p - parent_name) + strlen(cpy) + 1 );
152 if(!path)
154 free(cpy);
155 return NULL;
157 memcpy( path, parent_name, p - parent_name );
158 strcpy( path + (p - parent_name), cpy );
159 fd = open( path, O_RDONLY );
160 if (fd != -1)
162 close( fd );
163 free( cpy );
164 return path;
166 free( path );
168 /* Search -I path */
169 for(i = 0; i < include_path_count; i++)
171 path = pp_xmalloc(strlen(include_path[i]) + strlen(cpy) + 2);
172 if(!path)
174 free(cpy);
175 return NULL;
177 strcpy(path, include_path[i]);
178 strcat(path, "/");
179 strcat(path, cpy);
180 fd = open( path, O_RDONLY );
181 if (fd != -1)
183 close( fd );
184 free( cpy );
185 return path;
187 free( path );
189 free( cpy );
190 return NULL;
193 static void *wpp_default_open(const char *filename, int type) {
194 return fopen(filename,"rt");
197 static void wpp_default_close(void *file) {
198 fclose(file);
201 static int wpp_default_read(void *file, char *buffer, unsigned int len){
202 return fread(buffer, 1, len, file);
205 static void wpp_default_write( const char *buffer, unsigned int len ) {
206 fwrite(buffer, 1, len, ppy_out);
209 /* Don't comment on the hash, it's primitive but functional... */
210 static int pphash(const char *str)
212 int sum = 0;
213 while(*str)
214 sum += *str++;
215 return sum % HASHKEY;
218 pp_entry_t *pplookup(const char *ident)
220 int idx;
221 pp_entry_t *ppp;
223 if(!ident)
224 return NULL;
225 idx = pphash(ident);
226 for(ppp = pp_def_state->defines[idx]; ppp; ppp = ppp->next)
228 if(!strcmp(ident, ppp->ident))
229 return ppp;
231 return NULL;
234 static void free_pp_entry( pp_entry_t *ppp, int idx )
236 if(ppp->iep)
238 if(ppp->iep == pp_includelogiclist)
240 pp_includelogiclist = ppp->iep->next;
241 if(pp_includelogiclist)
242 pp_includelogiclist->prev = NULL;
244 else
246 ppp->iep->prev->next = ppp->iep->next;
247 if(ppp->iep->next)
248 ppp->iep->next->prev = ppp->iep->prev;
250 free(ppp->iep->filename);
251 free(ppp->iep);
254 if(pp_def_state->defines[idx] == ppp)
256 pp_def_state->defines[idx] = ppp->next;
257 if(pp_def_state->defines[idx])
258 pp_def_state->defines[idx]->prev = NULL;
260 else
262 ppp->prev->next = ppp->next;
263 if(ppp->next)
264 ppp->next->prev = ppp->prev;
267 free(ppp);
270 /* push a new (empty) define state */
271 int pp_push_define_state(void)
273 pp_def_state_t *state = pp_xmalloc( sizeof(*state) );
274 if(!state)
275 return 1;
277 memset( state->defines, 0, sizeof(state->defines) );
278 state->next = pp_def_state;
279 pp_def_state = state;
280 return 0;
283 /* pop the current define state */
284 void pp_pop_define_state(void)
286 int i;
287 pp_entry_t *ppp;
288 pp_def_state_t *state;
290 for (i = 0; i < HASHKEY; i++)
292 while ((ppp = pp_def_state->defines[i]) != NULL) pp_del_define( ppp->ident );
294 state = pp_def_state;
295 pp_def_state = state->next;
296 free( state );
299 void pp_del_define(const char *name)
301 pp_entry_t *ppp;
302 int idx = pphash(name);
304 if((ppp = pplookup(name)) == NULL)
306 if(pp_status.pedantic)
307 ppy_warning("%s was not defined", name);
308 return;
311 if(pp_status.debug)
312 printf("Deleting (%s, %d) <%s>\n", pp_status.input, pp_status.line_number, name);
314 free( ppp->ident );
315 free( ppp->subst.text );
316 free( ppp->filename );
317 free_pp_entry( ppp, idx );
320 pp_entry_t *pp_add_define(const char *def, const char *text)
322 int len;
323 char *cptr;
324 int idx;
325 pp_entry_t *ppp;
327 if(!def)
328 return NULL;
329 idx = pphash(def);
330 if((ppp = pplookup(def)) != NULL)
332 if(pp_status.pedantic)
333 ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", def, ppp->filename, ppp->linenumber);
334 pp_del_define(def);
336 ppp = pp_xmalloc(sizeof(pp_entry_t));
337 if(!ppp)
338 return NULL;
339 memset( ppp, 0, sizeof(*ppp) );
340 ppp->ident = pp_xstrdup(def);
341 if(!ppp->ident)
342 goto error;
343 ppp->type = def_define;
344 ppp->subst.text = text ? pp_xstrdup(text) : NULL;
345 if(text && !ppp->subst.text)
346 goto error;
347 ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
348 if(!ppp->filename)
349 goto error;
350 ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
351 ppp->next = pp_def_state->defines[idx];
352 pp_def_state->defines[idx] = ppp;
353 if(ppp->next)
354 ppp->next->prev = ppp;
355 if(ppp->subst.text)
357 /* Strip trailing white space from subst text */
358 len = strlen(ppp->subst.text);
359 while(len && strchr(" \t\r\n", ppp->subst.text[len-1]))
361 ppp->subst.text[--len] = '\0';
363 /* Strip leading white space from subst text */
364 for(cptr = ppp->subst.text; *cptr && strchr(" \t\r", *cptr); cptr++)
366 if(ppp->subst.text != cptr)
367 memmove(ppp->subst.text, cptr, strlen(cptr)+1);
369 if(pp_status.debug)
370 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)");
372 return ppp;
374 error:
375 free(ppp->ident);
376 free(ppp->subst.text);
377 free(ppp);
378 return NULL;
381 pp_entry_t *pp_add_macro(char *id, marg_t *args[], int nargs, mtext_t *exp)
383 int idx;
384 pp_entry_t *ppp;
386 if(!id)
387 return NULL;
388 idx = pphash(id);
389 if((ppp = pplookup(id)) != NULL)
391 if(pp_status.pedantic)
392 ppy_warning("Redefinition of %s\n\tPrevious definition: %s:%d", id, ppp->filename, ppp->linenumber);
393 pp_del_define(id);
395 ppp = pp_xmalloc(sizeof(pp_entry_t));
396 if(!ppp)
397 return NULL;
398 memset( ppp, 0, sizeof(*ppp) );
399 ppp->ident = id;
400 ppp->type = def_macro;
401 ppp->margs = args;
402 ppp->nargs = nargs;
403 ppp->subst.mtext= exp;
404 ppp->filename = pp_xstrdup(pp_status.input ? pp_status.input : "<internal or cmdline>");
405 if(!ppp->filename)
407 free(ppp);
408 return NULL;
410 ppp->linenumber = pp_status.input ? pp_status.line_number : 0;
411 ppp->next = pp_def_state->defines[idx];
412 pp_def_state->defines[idx] = ppp;
413 if(ppp->next)
414 ppp->next->prev = ppp;
416 if(pp_status.debug)
418 fprintf(stderr, "Added macro (%s, %d) <%s(%d)> to <", pp_status.input, pp_status.line_number, ppp->ident, nargs);
419 for(; exp; exp = exp->next)
421 switch(exp->type)
423 case exp_text:
424 fprintf(stderr, " \"%s\" ", exp->subst.text);
425 break;
426 case exp_stringize:
427 fprintf(stderr, " #(%d) ", exp->subst.argidx);
428 break;
429 case exp_concat:
430 fprintf(stderr, "##");
431 break;
432 case exp_subst:
433 fprintf(stderr, " <%d> ", exp->subst.argidx);
434 break;
437 fprintf(stderr, ">\n");
439 return ppp;
444 *-------------------------------------------------------------------------
445 * Include management
446 *-------------------------------------------------------------------------
448 #if defined(_WIN32) || defined(__MSDOS__)
449 #define INCLUDESEPARATOR ";"
450 #else
451 #define INCLUDESEPARATOR ":"
452 #endif
454 static char **includepath;
455 static int nincludepath = 0;
457 int wpp_add_include_path(const char *path)
459 char *tok;
460 char *cpy = pp_xstrdup(path);
461 if(!cpy)
462 return 1;
464 tok = strtok(cpy, INCLUDESEPARATOR);
465 while(tok)
467 if(*tok) {
468 char *dir;
469 char *cptr;
470 char **new_path;
472 dir = pp_xstrdup(tok);
473 if(!dir)
475 free(cpy);
476 return 1;
478 for(cptr = dir; *cptr; cptr++)
480 /* Convert to forward slash */
481 if(*cptr == '\\')
482 *cptr = '/';
484 /* Kill eventual trailing '/' */
485 if(*(cptr = dir + strlen(dir)-1) == '/')
486 *cptr = '\0';
488 /* Add to list */
489 new_path = pp_xrealloc(includepath, (nincludepath+1) * sizeof(*includepath));
490 if(!new_path)
492 free(dir);
493 free(cpy);
494 return 1;
496 includepath = new_path;
497 includepath[nincludepath] = dir;
498 nincludepath++;
500 tok = strtok(NULL, INCLUDESEPARATOR);
502 free(cpy);
503 return 0;
506 char *wpp_find_include(const char *name, const char *parent_name)
508 return wpp_default_lookup(name, !!parent_name, parent_name, includepath, nincludepath);
511 void *pp_open_include(const char *name, int type, const char *parent_name, char **newpath)
513 char *path;
514 void *fp;
516 if (!(path = wpp_callbacks->lookup(name, type, parent_name, includepath,
517 nincludepath))) return NULL;
518 fp = wpp_callbacks->open(path, type);
520 if (fp)
522 if (pp_status.debug)
523 printf("Going to include <%s>\n", path);
524 if (newpath) *newpath = path;
525 else free( path );
526 return fp;
528 free( path );
529 return NULL;
533 *-------------------------------------------------------------------------
534 * #if, #ifdef, #ifndef, #else, #elif and #endif state management
536 * #if state transitions are made on basis of the current TOS and the next
537 * required state. The state transitions are required to housekeep because
538 * #if:s can be nested. The ignore case is activated to prevent output from
539 * within a false clause.
540 * Some special cases come from the fact that the #elif cases are not
541 * binary, but three-state. The problem is that all other elif-cases must
542 * be false when one true one has been found. A second problem is that the
543 * #else clause is a final clause. No extra #else:s may follow.
545 * The states mean:
546 * if_true Process input to output
547 * if_false Process input but no output
548 * if_ignore Process input but no output
549 * if_elif Process input but no output
550 * if_elsefalse Process input but no output
551 * if_elsettrue Process input to output
553 * The possible state-sequences are [state(stack depth)] (rest can be deduced):
554 * TOS #if 1 #else #endif
555 * if_true(n) if_true(n+1) if_elsefalse(n+1)
556 * if_false(n) if_ignore(n+1) if_ignore(n+1)
557 * if_elsetrue(n) if_true(n+1) if_elsefalse(n+1)
558 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1)
559 * if_elif(n) if_ignore(n+1) if_ignore(n+1)
560 * if_ignore(n) if_ignore(n+1) if_ignore(n+1)
562 * TOS #if 1 #elif 0 #else #endif
563 * if_true(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
564 * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
565 * if_elsetrue(n) if_true(n+1) if_elif(n+1) if_elif(n+1)
566 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
567 * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
568 * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
570 * TOS #if 0 #elif 1 #else #endif
571 * if_true(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
572 * if_false(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
573 * if_elsetrue(n) if_false(n+1) if_true(n+1) if_elsefalse(n+1)
574 * if_elsefalse(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
575 * if_elif(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
576 * if_ignore(n) if_ignore(n+1) if_ignore(n+1) if_ignore(n+1)
578 *-------------------------------------------------------------------------
580 static const char * const pp_if_state_str[] = {
581 "if_false",
582 "if_true",
583 "if_elif",
584 "if_elsefalse",
585 "if_elsetrue",
586 "if_ignore"
589 void pp_push_if(pp_if_state_t s)
591 if(if_stack_idx >= MAXIFSTACK)
592 pp_internal_error(__FILE__, __LINE__, "#if-stack overflow; #{if,ifdef,ifndef} nested too deeply (> %d)", MAXIFSTACK);
594 if(pp_flex_debug)
595 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);
597 if_stack[if_stack_idx++] = s;
599 switch(s)
601 case if_true:
602 case if_elsetrue:
603 break;
604 case if_false:
605 case if_elsefalse:
606 case if_elif:
607 case if_ignore:
608 pp_push_ignore_state();
609 break;
610 default:
611 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
615 pp_if_state_t pp_pop_if(void)
617 if(if_stack_idx <= 0)
619 ppy_error("#{endif,else,elif} without #{if,ifdef,ifndef} (#if-stack underflow)");
620 return if_error;
623 switch(pp_if_state())
625 case if_true:
626 case if_elsetrue:
627 break;
628 case if_false:
629 case if_elsefalse:
630 case if_elif:
631 case if_ignore:
632 pp_pop_ignore_state();
633 break;
634 default:
635 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d)", (int)pp_if_state());
638 if(pp_flex_debug)
639 fprintf(stderr, "Pop if %s:%d: %s(%d) -> %s(%d)\n",
640 pp_status.input,
641 pp_status.line_number,
642 pp_if_state_str[pp_if_state()],
643 if_stack_idx,
644 pp_if_state_str[if_stack[if_stack_idx <= 1 ? if_true : if_stack_idx-2]],
645 if_stack_idx-1);
647 return if_stack[--if_stack_idx];
650 pp_if_state_t pp_if_state(void)
652 if(!if_stack_idx)
653 return if_true;
654 else
655 return if_stack[if_stack_idx-1];
659 void pp_next_if_state(int i)
661 switch(pp_if_state())
663 case if_true:
664 case if_elsetrue:
665 pp_push_if(i ? if_true : if_false);
666 break;
667 case if_false:
668 case if_elsefalse:
669 case if_elif:
670 case if_ignore:
671 pp_push_if(if_ignore);
672 break;
673 default:
674 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #{if,ifdef,ifndef} directive", (int)pp_if_state());
678 int pp_get_if_depth(void)
680 return if_stack_idx;
683 /* #define WANT_NEAR_INDICATION */
685 static void generic_msg(const char *s, const char *t, const char *n, va_list ap)
687 fprintf(stderr, "%s:%d:%d: %s: ", pp_status.input ? pp_status.input : "stdin",
688 pp_status.line_number, pp_status.char_number, t);
689 vfprintf(stderr, s, ap);
690 #ifdef WANT_NEAR_INDICATION
692 char *cpy, *p;
693 if(n)
695 cpy = pp_xstrdup(n);
696 if(!cpy)
697 goto end;
698 for (p = cpy; *p; p++) if(!isprint(*p)) *p = ' ';
699 fprintf(stderr, " near '%s'", cpy);
700 free(cpy);
703 end:
704 #endif
705 fprintf(stderr, "\n");
708 static void wpp_default_error(const char *file, int line, int col, const char *near, const char *msg, va_list ap)
710 generic_msg(msg, "Error", near, ap);
711 exit(1);
714 static void wpp_default_warning(const char *file, int line, int col, const char *near, const char *msg, va_list ap)
716 generic_msg(msg, "Warning", near, ap);
719 static const struct wpp_callbacks default_callbacks =
721 wpp_default_lookup,
722 wpp_default_open,
723 wpp_default_close,
724 wpp_default_read,
725 wpp_default_write,
726 wpp_default_error,
727 wpp_default_warning,
730 const struct wpp_callbacks *wpp_callbacks = &default_callbacks;
732 int ppy_error(const char *s, ...)
734 va_list ap;
735 va_start(ap, s);
736 wpp_callbacks->error(pp_status.input, pp_status.line_number, pp_status.char_number, ppy_text, s, ap);
737 va_end(ap);
738 pp_status.state = 1;
739 return 1;
742 int ppy_warning(const char *s, ...)
744 va_list ap;
745 va_start(ap, s);
746 wpp_callbacks->warning(pp_status.input, pp_status.line_number, pp_status.char_number, ppy_text, s, ap);
747 va_end(ap);
748 return 0;
751 void pp_internal_error(const char *file, int line, const char *s, ...)
753 va_list ap;
754 va_start(ap, s);
755 fprintf(stderr, "Internal error (please report) %s %d: ", file, line);
756 vfprintf(stderr, s, ap);
757 fprintf(stderr, "\n");
758 va_end(ap);
759 exit(3);