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