| /* | |
| * Copyright 1998 Bertho A. Stultiens (BS) | |
| * | |
| */ | |
| #include "config.h" | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "wrc.h" | |
| #include "utils.h" | |
| #include "preproc.h" | |
| #include "parser.h" | |
| extern void set_pp_ignore(int); /* From parser.l */ | |
| static char *current_define; | |
| #define HASHKEY 2039 | |
| static struct pp_entry *pp_defines[HASHKEY]; | |
| #define MAXIFSTACK 64 | |
| static struct if_state ifstack[MAXIFSTACK]; | |
| static int ifstackidx = 0; | |
| #if 0 | |
| void pp_status(void) | |
| { | |
| int i; | |
| int sum; | |
| int total = 0; | |
| struct pp_entry *ppp; | |
| printf("Defines statistics:\n"); | |
| for(i = 0; i < HASHKEY; i++) | |
| { | |
| sum = 0; | |
| for(ppp = pp_defines[i]; ppp; ppp = ppp->next) | |
| sum++; | |
| total += sum; | |
| printf("%4d, %3d\n", i, sum); | |
| } | |
| printf("Total defines: %d\n", total); | |
| } | |
| #pragma exit pp_status | |
| #endif | |
| /* Don't comment on the hash, its primitive but functional... */ | |
| int pp_hash(char *str) | |
| { | |
| int sum = 0; | |
| while(*str) | |
| sum += *str++; | |
| return sum % HASHKEY; | |
| } | |
| struct pp_entry *pp_lookup(char *ident) | |
| { | |
| int index = pp_hash(ident); | |
| struct pp_entry *ppp; | |
| for(ppp = pp_defines[index]; ppp; ppp = ppp->next) | |
| { | |
| if(!strcmp(ident, ppp->ident)) | |
| return ppp; | |
| } | |
| return NULL; | |
| } | |
| void set_define(char *name) | |
| { | |
| current_define = xstrdup(name); | |
| } | |
| void del_define(char *name) | |
| { | |
| int index; | |
| struct pp_entry *ppp; | |
| if((ppp = pp_lookup(name)) == NULL) | |
| { | |
| if(pedantic) | |
| yywarning("%s was not defined", name); | |
| return; | |
| } | |
| index = pp_hash(name); | |
| if(pp_defines[index] == ppp) | |
| { | |
| pp_defines[index] = ppp->next; | |
| if(pp_defines[index]) | |
| pp_defines[index]->prev = NULL; | |
| } | |
| else | |
| { | |
| ppp->prev->next = ppp->next; | |
| if(ppp->next) | |
| ppp->next->prev = ppp->prev; | |
| } | |
| free(ppp); | |
| } | |
| void add_define(char *text) | |
| { | |
| int len; | |
| char *cptr; | |
| int index = pp_hash(current_define); | |
| struct pp_entry *ppp; | |
| if(pp_lookup(current_define) != NULL) | |
| { | |
| if(pedantic) | |
| yywarning("Redefinition of %s", current_define); | |
| del_define(current_define); | |
| } | |
| ppp = (struct pp_entry *)xmalloc(sizeof(struct pp_entry)); | |
| ppp->ident = current_define; | |
| ppp->subst = xstrdup(text); | |
| ppp->next = pp_defines[index]; | |
| pp_defines[index] = ppp; | |
| if(ppp->next) | |
| ppp->next->prev = ppp; | |
| /* Strip trailing white space from subst text */ | |
| len = strlen(ppp->subst); | |
| while(len && strchr(" \t\r\n", ppp->subst[len-1])) | |
| { | |
| ppp->subst[--len] = '\0'; | |
| } | |
| /* Strip leading white space from subst text */ | |
| for(cptr = ppp->subst; *cptr && strchr(" \t\r", *cptr); cptr++) | |
| ; | |
| if(ppp->subst != cptr) | |
| memmove(ppp->subst, cptr, strlen(cptr)+1); | |
| if(yydebug) | |
| printf("Added (%s, %d) <%s> to <%s>\n", input_name, line_number, ppp->ident, ppp->subst); | |
| } | |
| void add_cmdline_define(char *set) | |
| { | |
| char *cpy = xstrdup(set); /* Because gcc passes a R/O string */ | |
| char *cptr = strchr(cpy, '='); | |
| if(cptr) | |
| *cptr = '\0'; | |
| set_define(cpy); | |
| add_define(cptr ? cptr+1 : ""); | |
| free(cpy); | |
| } | |
| #if defined(_Windows) || defined(__MSDOS__) | |
| #define INCLUDESEPARATOR ";" | |
| #else | |
| #define INCLUDESEPARATOR ":" | |
| #endif | |
| static char **includepath; | |
| static int nincludepath = 0; | |
| void add_include_path(char *path) | |
| { | |
| char *tok; | |
| char *cpy = xstrdup(path); | |
| tok = strtok(cpy, INCLUDESEPARATOR); | |
| while(tok) | |
| { | |
| char *dir; | |
| char *cptr; | |
| if(strlen(tok) == 0) | |
| continue; | |
| dir = xstrdup(tok); | |
| 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 */ | |
| nincludepath++; | |
| includepath = (char **)xrealloc(includepath, nincludepath * sizeof(*includepath)); | |
| includepath[nincludepath-1] = dir; | |
| tok = strtok(NULL, INCLUDESEPARATOR); | |
| } | |
| free(cpy); | |
| } | |
| FILE *open_include(const char *name, int search) | |
| { | |
| char *cpy = xstrdup(name); | |
| char *cptr; | |
| FILE *fp; | |
| int i; | |
| for(cptr = cpy; *cptr; cptr++) | |
| { | |
| /* kill double backslash */ | |
| if(*cptr == '\\' && *(cptr+1) == '\\') | |
| memmove(cptr, cptr+1, strlen(cptr)); | |
| /* Convert to forward slash */ | |
| if(*cptr == '\\') | |
| *cptr = '/'; | |
| } | |
| if(search) | |
| { | |
| /* Search current dir and then -I path */ | |
| fp = fopen(name, "rt"); | |
| if(fp) | |
| { | |
| if(yydebug) | |
| printf("Going to include <%s>\n", name); | |
| free(cpy); | |
| return fp; | |
| } | |
| } | |
| /* Search -I path */ | |
| for(i = 0; i < nincludepath; i++) | |
| { | |
| char *path; | |
| path = (char *)xmalloc(strlen(includepath[i]) + strlen(cpy) + 2); | |
| strcpy(path, includepath[i]); | |
| strcat(path, "/"); | |
| strcat(path, cpy); | |
| fp = fopen(path, "rt"); | |
| if(fp && yydebug) | |
| printf("Going to include <%s>\n", path); | |
| free(path); | |
| if(fp) | |
| { | |
| free(cpy); | |
| return fp; | |
| } | |
| } | |
| free(cpy); | |
| return NULL; | |
| } | |
| void push_if(int truecase, int wastrue, int nevertrue) | |
| { | |
| if(ifstackidx >= MAXIFSTACK-1) | |
| internal_error(__FILE__, __LINE__, "#if stack overflow"); | |
| ifstack[ifstackidx].current = truecase && !wastrue; | |
| ifstack[ifstackidx].hasbeentrue = wastrue; | |
| ifstack[ifstackidx].nevertrue = nevertrue; | |
| if(nevertrue || !(truecase && !wastrue)) | |
| set_pp_ignore(1); | |
| if(yydebug) | |
| printf("push_if: %d %d %d (%d %d %d)\n", | |
| truecase, | |
| wastrue, | |
| nevertrue, | |
| ifstack[ifstackidx].current, | |
| ifstack[ifstackidx].hasbeentrue, | |
| ifstack[ifstackidx].nevertrue); | |
| ifstackidx++; | |
| } | |
| int pop_if(void) | |
| { | |
| if(ifstackidx <= 0) | |
| yyerror("#endif without #if|#ifdef|#ifndef (#if stack underflow)"); | |
| ifstackidx--; | |
| if(yydebug) | |
| printf("pop_if: %d %d %d\n", | |
| ifstack[ifstackidx].current, | |
| ifstack[ifstackidx].hasbeentrue, | |
| ifstack[ifstackidx].nevertrue); | |
| if(ifstack[ifstackidx].nevertrue || !ifstack[ifstackidx].current) | |
| set_pp_ignore(0); | |
| return ifstack[ifstackidx].hasbeentrue || ifstack[ifstackidx].current; | |
| } | |
| int isnevertrue_if(void) | |
| { | |
| return ifstackidx > 0 && ifstack[ifstackidx-1].nevertrue; | |
| } | |