1 /* 2 * Wrc preprocessor syntax analysis 3 * 4 * Copyright 1999-2000 Bertho A. Stultiens (BS) 5 * 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 * 21 * History: 22 * 24-Apr-2000 BS Restructured the lot to fit the new scanner 23 * and reintegrate into the wine-tree. 24 * 01-Jan-2000 BS FIXME: win16 preprocessor calculates with 25 * 16 bit ints and overflows...? 26 * 26-Dec-1999 BS Started this file 27 * 28 */ 29 30 %{ 31 #include "config.h" 32 #include "wine/port.h" 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <stdarg.h> 37 #include <assert.h> 38 #include <ctype.h> 39 #include <string.h> 40 41 #include "wpp_private.h" 42 43 44 #define UNARY_OP(r, v, OP) \ 45 switch(v.type) \ 46 { \ 47 case cv_sint: r.val.si = OP v.val.si; break; \ 48 case cv_uint: r.val.ui = OP v.val.ui; break; \ 49 case cv_slong: r.val.sl = OP v.val.sl; break; \ 50 case cv_ulong: r.val.ul = OP v.val.ul; break; \ 51 case cv_sll: r.val.sll = OP v.val.sll; break; \ 52 case cv_ull: r.val.ull = OP v.val.ull; break; \ 53 } 54 55 #define cv_signed(v) ((v.type & FLAG_SIGNED) != 0) 56 57 #define BIN_OP_INT(r, v1, v2, OP) \ 58 r.type = v1.type; \ 59 if(cv_signed(v1) && cv_signed(v2)) \ 60 r.val.si = v1.val.si OP v2.val.si; \ 61 else if(cv_signed(v1) && !cv_signed(v2)) \ 62 r.val.si = v1.val.si OP (signed) v2.val.ui; \ 63 else if(!cv_signed(v1) && cv_signed(v2)) \ 64 r.val.si = (signed) v1.val.ui OP v2.val.si; \ 65 else \ 66 r.val.ui = v1.val.ui OP v2.val.ui; 67 68 #define BIN_OP_LONG(r, v1, v2, OP) \ 69 r.type = v1.type; \ 70 if(cv_signed(v1) && cv_signed(v2)) \ 71 r.val.sl = v1.val.sl OP v2.val.sl; \ 72 else if(cv_signed(v1) && !cv_signed(v2)) \ 73 r.val.sl = v1.val.sl OP (signed long) v2.val.ul; \ 74 else if(!cv_signed(v1) && cv_signed(v2)) \ 75 r.val.sl = (signed long) v1.val.ul OP v2.val.sl; \ 76 else \ 77 r.val.ul = v1.val.ul OP v2.val.ul; 78 79 #define BIN_OP_LONGLONG(r, v1, v2, OP) \ 80 r.type = v1.type; \ 81 if(cv_signed(v1) && cv_signed(v2)) \ 82 r.val.sll = v1.val.sll OP v2.val.sll; \ 83 else if(cv_signed(v1) && !cv_signed(v2)) \ 84 r.val.sll = v1.val.sll OP (wrc_sll_t) v2.val.ull; \ 85 else if(!cv_signed(v1) && cv_signed(v2)) \ 86 r.val.sll = (wrc_sll_t) v1.val.ull OP v2.val.sll; \ 87 else \ 88 r.val.ull = v1.val.ull OP v2.val.ull; 89 90 #define BIN_OP(r, v1, v2, OP) \ 91 switch(v1.type & SIZE_MASK) \ 92 { \ 93 case SIZE_INT: BIN_OP_INT(r, v1, v2, OP); break; \ 94 case SIZE_LONG: BIN_OP_LONG(r, v1, v2, OP); break; \ 95 case SIZE_LONGLONG: BIN_OP_LONGLONG(r, v1, v2, OP); break; \ 96 default: pp_internal_error(__FILE__, __LINE__, "Invalid type indicator (0x%04x)", v1.type); \ 97 } 98 99 100 /* 101 * Prototypes 102 */ 103 static int boolean(cval_t *v); 104 static void promote_equal_size(cval_t *v1, cval_t *v2); 105 static void cast_to_sint(cval_t *v); 106 static void cast_to_uint(cval_t *v); 107 static void cast_to_slong(cval_t *v); 108 static void cast_to_ulong(cval_t *v); 109 static void cast_to_sll(cval_t *v); 110 static void cast_to_ull(cval_t *v); 111 static marg_t *new_marg(char *str, def_arg_t type); 112 static marg_t *add_new_marg(char *str, def_arg_t type); 113 static int marg_index(char *id); 114 static mtext_t *new_mtext(char *str, int idx, def_exp_t type); 115 static mtext_t *combine_mtext(mtext_t *tail, mtext_t *mtp); 116 static char *merge_text(char *s1, char *s2); 117 118 /* 119 * Local variables 120 */ 121 static marg_t **macro_args; /* Macro parameters array while parsing */ 122 static int nmacro_args; 123 124 %} 125 126 %union{ 127 int sint; 128 unsigned int uint; 129 long slong; 130 unsigned long ulong; 131 wrc_sll_t sll; 132 wrc_ull_t ull; 133 int *iptr; 134 char *cptr; 135 cval_t cval; 136 marg_t *marg; 137 mtext_t *mtext; 138 } 139 140 %token tRCINCLUDE 141 %token tIF tIFDEF tIFNDEF tELSE tELIF tENDIF tDEFINED tNL 142 %token tINCLUDE tLINE tGCCLINE tERROR tWARNING tPRAGMA tPPIDENT 143 %token tUNDEF tMACROEND tCONCAT tELIPSIS tSTRINGIZE 144 %token <cptr> tIDENT tLITERAL tMACRO tDEFINE 145 %token <cptr> tDQSTRING tSQSTRING tIQSTRING 146 %token <uint> tUINT 147 %token <sint> tSINT 148 %token <ulong> tULONG 149 %token <slong> tSLONG 150 %token <ull> tULONGLONG 151 %token <sll> tSLONGLONG 152 %token <cptr> tRCINCLUDEPATH 153 154 %right '?' ':' 155 %left tLOGOR 156 %left tLOGAND 157 %left '|' 158 %left '^' 159 %left '&' 160 %left tEQ tNE 161 %left '<' tLTE '>' tGTE 162 %left tLSHIFT tRSHIFT 163 %left '+' '-' 164 %left '*' '/' 165 %right '~' '!' 166 167 %type <cval> pp_expr 168 %type <marg> emargs margs 169 %type <mtext> opt_mtexts mtexts mtext 170 %type <sint> allmargs 171 %type <cptr> opt_text text 172 173 /* 174 ************************************************************************** 175 * The parser starts here 176 ************************************************************************** 177 */ 178 179 %% 180 181 pp_file : /* Empty */ 182 | pp_file preprocessor 183 ; 184 185 preprocessor 186 : tINCLUDE tDQSTRING tNL { pp_do_include($2, 1); } 187 | tINCLUDE tIQSTRING tNL { pp_do_include($2, 0); } 188 | tIF pp_expr tNL { pp_next_if_state(boolean(&$2)); } 189 | tIFDEF tIDENT tNL { pp_next_if_state(pplookup($2) != NULL); free($2); } 190 | tIFNDEF tIDENT tNL { 191 int t = pplookup($2) == NULL; 192 if(pp_incl_state.state == 0 && t && !pp_incl_state.seen_junk) 193 { 194 pp_incl_state.state = 1; 195 pp_incl_state.ppp = $2; 196 pp_incl_state.ifdepth = pp_get_if_depth(); 197 } 198 else if(pp_incl_state.state != 1) 199 { 200 pp_incl_state.state = -1; 201 free($2); 202 } 203 else 204 free($2); 205 pp_next_if_state(t); 206 if(pp_status.debug) 207 fprintf(stderr, "tIFNDEF: %s:%d: include_state=%d, include_ppp='%s', include_ifdepth=%d\n", 208 pp_status.input, pp_status.line_number, pp_incl_state.state, pp_incl_state.ppp, pp_incl_state.ifdepth); 209 } 210 | tELIF pp_expr tNL { 211 pp_if_state_t s = pp_pop_if(); 212 switch(s) 213 { 214 case if_true: 215 case if_elif: 216 pp_push_if(if_elif); 217 break; 218 case if_false: 219 pp_push_if(boolean(&$2) ? if_true : if_false); 220 break; 221 case if_ignore: 222 pp_push_if(if_ignore); 223 break; 224 case if_elsetrue: 225 case if_elsefalse: 226 ppy_error("#elif cannot follow #else"); 227 break; 228 case if_error: 229 break; 230 default: 231 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #elif directive", s); 232 } 233 } 234 | tELSE tNL { 235 pp_if_state_t s = pp_pop_if(); 236 switch(s) 237 { 238 case if_true: 239 pp_push_if(if_elsefalse); 240 break; 241 case if_elif: 242 pp_push_if(if_elif); 243 break; 244 case if_false: 245 pp_push_if(if_elsetrue); 246 break; 247 case if_ignore: 248 pp_push_if(if_ignore); 249 break; 250 case if_elsetrue: 251 case if_elsefalse: 252 ppy_error("#else clause already defined"); 253 break; 254 case if_error: 255 break; 256 default: 257 pp_internal_error(__FILE__, __LINE__, "Invalid pp_if_state (%d) in #else directive", s); 258 } 259 } 260 | tENDIF tNL { 261 if(pp_pop_if() != if_error) 262 { 263 if(pp_incl_state.ifdepth == pp_get_if_depth() && pp_incl_state.state == 1) 264 { 265 pp_incl_state.state = 2; 266 pp_incl_state.seen_junk = 0; 267 } 268 else if(pp_incl_state.state != 1) 269 { 270 pp_incl_state.state = -1; 271 } 272 if(pp_status.debug) 273 fprintf(stderr, "tENDIF: %s:%d: include_state=%d, include_ppp='%s', include_ifdepth=%d\n", 274 pp_status.input, pp_status.line_number, pp_incl_state.state, pp_incl_state.ppp, pp_incl_state.ifdepth); 275 } 276 } 277 | tUNDEF tIDENT tNL { pp_del_define($2); free($2); } 278 | tDEFINE opt_text tNL { pp_add_define($1, $2); free($1); free($2); } 279 | tMACRO res_arg allmargs tMACROEND opt_mtexts tNL { 280 pp_add_macro($1, macro_args, nmacro_args, $5); 281 } 282 | tLINE tSINT tDQSTRING tNL { if($3) pp_writestring("# %d %s\n", $2 , $3); free($3); } 283 | tGCCLINE tSINT tDQSTRING tNL { if($3) pp_writestring("# %d %s\n", $2 , $3); free($3); } 284 | tGCCLINE tSINT tDQSTRING tSINT tNL 285 { if($3) pp_writestring("# %d %s %d\n", $2, $3, $4); free($3); } 286 | tGCCLINE tSINT tDQSTRING tSINT tSINT tNL 287 { if($3) pp_writestring("# %d %s %d %d\n", $2 ,$3, $4, $5); free($3); } 288 | tGCCLINE tSINT tDQSTRING tSINT tSINT tSINT tNL 289 { if($3) pp_writestring("# %d %s %d %d %d\n", $2 ,$3 ,$4 ,$5, $6); free($3); } 290 | tGCCLINE tSINT tDQSTRING tSINT tSINT tSINT tSINT tNL 291 { if($3) pp_writestring("# %d %s %d %d %d %d\n", $2 ,$3 ,$4 ,$5, $6, $7); free($3); } 292 | tGCCLINE tNL /* The null-token */ 293 | tERROR opt_text tNL { ppy_error("#error directive: '%s'", $2); free($2); } 294 | tWARNING opt_text tNL { ppy_warning("#warning directive: '%s'", $2); free($2); } 295 | tPRAGMA opt_text tNL { pp_writestring("#pragma %s\n", $2 ? $2 : ""); free($2); } 296 | tPPIDENT opt_text tNL { if(pp_status.pedantic) ppy_warning("#ident ignored (arg: '%s')", $2); free($2); } 297 | tRCINCLUDE tRCINCLUDEPATH { 298 if($2) 299 { 300 int nl=strlen($2) +3; 301 char *fn=pp_xmalloc(nl); 302 if(fn) 303 { 304 sprintf(fn,"\"%s\"",$2); 305 pp_do_include(fn,1); 306 } 307 free($2); 308 } 309 } 310 | tRCINCLUDE tDQSTRING { 311 pp_do_include($2,1); 312 } 313 /*| tNL*/ 314 ; 315 316 opt_text: /* Empty */ { $$ = NULL; } 317 | text { $$ = $1; } 318 ; 319 320 text : tLITERAL { $$ = $1; } 321 | tDQSTRING { $$ = $1; } 322 | tSQSTRING { $$ = $1; } 323 | text tLITERAL { $$ = merge_text($1, $2); } 324 | text tDQSTRING { $$ = merge_text($1, $2); } 325 | text tSQSTRING { $$ = merge_text($1, $2); } 326 ; 327 328 res_arg : /* Empty */ { macro_args = NULL; nmacro_args = 0; } 329 ; 330 331 allmargs: /* Empty */ { $$ = 0; macro_args = NULL; nmacro_args = 0; } 332 | emargs { $$ = nmacro_args; } 333 ; 334 335 emargs : margs { $$ = $1; } 336 | margs ',' tELIPSIS { $$ = add_new_marg(NULL, arg_list); nmacro_args *= -1; } 337 ; 338 339 margs : margs ',' tIDENT { $$ = add_new_marg($3, arg_single); } 340 | tIDENT { $$ = add_new_marg($1, arg_single); } 341 ; 342 343 opt_mtexts 344 : /* Empty */ { $$ = NULL; } 345 | mtexts { 346 for($$ = $1; $$ && $$->prev; $$ = $$->prev) 347 ; 348 } 349 ; 350 351 mtexts : mtext { $$ = $1; } 352 | mtexts mtext { $$ = combine_mtext($1, $2); } 353 ; 354 355 mtext : tLITERAL { $$ = new_mtext($1, 0, exp_text); } 356 | tDQSTRING { $$ = new_mtext($1, 0, exp_text); } 357 | tSQSTRING { $$ = new_mtext($1, 0, exp_text); } 358 | tCONCAT { $$ = new_mtext(NULL, 0, exp_concat); } 359 | tSTRINGIZE tIDENT { 360 int mat = marg_index($2); 361 if(mat < 0) 362 ppy_error("Stringification identifier must be an argument parameter"); 363 else 364 $$ = new_mtext(NULL, mat, exp_stringize); 365 } 366 | tIDENT { 367 int mat = marg_index($1); 368 if(mat >= 0) 369 $$ = new_mtext(NULL, mat, exp_subst); 370 else if($1) 371 $$ = new_mtext($1, 0, exp_text); 372 } 373 ; 374 375 pp_expr : tSINT { $$.type = cv_sint; $$.val.si = $1; } 376 | tUINT { $$.type = cv_uint; $$.val.ui = $1; } 377 | tSLONG { $$.type = cv_slong; $$.val.sl = $1; } 378 | tULONG { $$.type = cv_ulong; $$.val.ul = $1; } 379 | tSLONGLONG { $$.type = cv_sll; $$.val.sll = $1; } 380 | tULONGLONG { $$.type = cv_ull; $$.val.ull = $1; } 381 | tDEFINED tIDENT { $$.type = cv_sint; $$.val.si = pplookup($2) != NULL; } 382 | tDEFINED '(' tIDENT ')' { $$.type = cv_sint; $$.val.si = pplookup($3) != NULL; } 383 | tIDENT { $$.type = cv_sint; $$.val.si = 0; } 384 | pp_expr tLOGOR pp_expr { $$.type = cv_sint; $$.val.si = boolean(&$1) || boolean(&$3); } 385 | pp_expr tLOGAND pp_expr { $$.type = cv_sint; $$.val.si = boolean(&$1) && boolean(&$3); } 386 | pp_expr tEQ pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, ==); } 387 | pp_expr tNE pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, !=); } 388 | pp_expr '<' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, <); } 389 | pp_expr '>' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, >); } 390 | pp_expr tLTE pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, <=); } 391 | pp_expr tGTE pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, >=); } 392 | pp_expr '+' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, +); } 393 | pp_expr '-' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, -); } 394 | pp_expr '^' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, ^); } 395 | pp_expr '&' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, &); } 396 | pp_expr '|' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, |); } 397 | pp_expr '*' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, *); } 398 | pp_expr '/' pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, /); } 399 | pp_expr tLSHIFT pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, <<); } 400 | pp_expr tRSHIFT pp_expr { promote_equal_size(&$1, &$3); BIN_OP($$, $1, $3, >>); } 401 | '+' pp_expr { $$ = $2; } 402 | '-' pp_expr { UNARY_OP($$, $2, -); } 403 | '~' pp_expr { UNARY_OP($$, $2, ~); } 404 | '!' pp_expr { $$.type = cv_sint; $$.val.si = !boolean(&$2); } 405 | '(' pp_expr ')' { $$ = $2; } 406 | pp_expr '?' pp_expr ':' pp_expr { $$ = boolean(&$1) ? $3 : $5; } 407 ; 408 409 %% 410 411 /* 412 ************************************************************************** 413 * Support functions 414 ************************************************************************** 415 */ 416 417 static void cast_to_sint(cval_t *v) 418 { 419 switch(v->type) 420 { 421 case cv_sint: break; 422 case cv_uint: break; 423 case cv_slong: v->val.si = v->val.sl; break; 424 case cv_ulong: v->val.si = v->val.ul; break; 425 case cv_sll: v->val.si = v->val.sll; break; 426 case cv_ull: v->val.si = v->val.ull; break; 427 } 428 v->type = cv_sint; 429 } 430 431 static void cast_to_uint(cval_t *v) 432 { 433 switch(v->type) 434 { 435 case cv_sint: break; 436 case cv_uint: break; 437 case cv_slong: v->val.ui = v->val.sl; break; 438 case cv_ulong: v->val.ui = v->val.ul; break; 439 case cv_sll: v->val.ui = v->val.sll; break; 440 case cv_ull: v->val.ui = v->val.ull; break; 441 } 442 v->type = cv_uint; 443 } 444 445 static void cast_to_slong(cval_t *v) 446 { 447 switch(v->type) 448 { 449 case cv_sint: v->val.sl = v->val.si; break; 450 case cv_uint: v->val.sl = v->val.ui; break; 451 case cv_slong: break; 452 case cv_ulong: break; 453 case cv_sll: v->val.sl = v->val.sll; break; 454 case cv_ull: v->val.sl = v->val.ull; break; 455 } 456 v->type = cv_slong; 457 } 458 459 static void cast_to_ulong(cval_t *v) 460 { 461 switch(v->type) 462 { 463 case cv_sint: v->val.ul = v->val.si; break; 464 case cv_uint: v->val.ul = v->val.ui; break; 465 case cv_slong: break; 466 case cv_ulong: break; 467 case cv_sll: v->val.ul = v->val.sll; break; 468 case cv_ull: v->val.ul = v->val.ull; break; 469 } 470 v->type = cv_ulong; 471 } 472 473 static void cast_to_sll(cval_t *v) 474 { 475 switch(v->type) 476 { 477 case cv_sint: v->val.sll = v->val.si; break; 478 case cv_uint: v->val.sll = v->val.ui; break; 479 case cv_slong: v->val.sll = v->val.sl; break; 480 case cv_ulong: v->val.sll = v->val.ul; break; 481 case cv_sll: break; 482 case cv_ull: break; 483 } 484 v->type = cv_sll; 485 } 486 487 static void cast_to_ull(cval_t *v) 488 { 489 switch(v->type) 490 { 491 case cv_sint: v->val.ull = v->val.si; break; 492 case cv_uint: v->val.ull = v->val.ui; break; 493 case cv_slong: v->val.ull = v->val.sl; break; 494 case cv_ulong: v->val.ull = v->val.ul; break; 495 case cv_sll: break; 496 case cv_ull: break; 497 } 498 v->type = cv_ull; 499 } 500 501 502 static void promote_equal_size(cval_t *v1, cval_t *v2) 503 { 504 #define cv_sizeof(v) ((int)(v->type & SIZE_MASK)) 505 int s1 = cv_sizeof(v1); 506 int s2 = cv_sizeof(v2); 507 #undef cv_sizeof 508 509 if(s1 == s2) 510 return; 511 else if(s1 > s2) 512 { 513 switch(v1->type) 514 { 515 case cv_sint: cast_to_sint(v2); break; 516 case cv_uint: cast_to_uint(v2); break; 517 case cv_slong: cast_to_slong(v2); break; 518 case cv_ulong: cast_to_ulong(v2); break; 519 case cv_sll: cast_to_sll(v2); break; 520 case cv_ull: cast_to_ull(v2); break; 521 } 522 } 523 else 524 { 525 switch(v2->type) 526 { 527 case cv_sint: cast_to_sint(v1); break; 528 case cv_uint: cast_to_uint(v1); break; 529 case cv_slong: cast_to_slong(v1); break; 530 case cv_ulong: cast_to_ulong(v1); break; 531 case cv_sll: cast_to_sll(v1); break; 532 case cv_ull: cast_to_ull(v1); break; 533 } 534 } 535 } 536 537 538 static int boolean(cval_t *v) 539 { 540 switch(v->type) 541 { 542 case cv_sint: return v->val.si != (int)0; 543 case cv_uint: return v->val.ui != (unsigned int)0; 544 case cv_slong: return v->val.sl != (long)0; 545 case cv_ulong: return v->val.ul != (unsigned long)0; 546 case cv_sll: return v->val.sll != (wrc_sll_t)0; 547 case cv_ull: return v->val.ull != (wrc_ull_t)0; 548 } 549 return 0; 550 } 551 552 static marg_t *new_marg(char *str, def_arg_t type) 553 { 554 marg_t *ma = pp_xmalloc(sizeof(marg_t)); 555 if(!ma) 556 return NULL; 557 ma->arg = str; 558 ma->type = type; 559 ma->nnl = 0; 560 return ma; 561 } 562 563 static marg_t *add_new_marg(char *str, def_arg_t type) 564 { 565 marg_t **new_macro_args; 566 marg_t *ma; 567 if(!str) 568 return NULL; 569 new_macro_args = pp_xrealloc(macro_args, (nmacro_args+1) * sizeof(macro_args[0])); 570 if(!new_macro_args) 571 return NULL; 572 macro_args = new_macro_args; 573 ma = new_marg(str, type); 574 if(!ma) 575 return NULL; 576 macro_args[nmacro_args] = ma; 577 nmacro_args++; 578 return ma; 579 } 580 581 static int marg_index(char *id) 582 { 583 int t; 584 if(!id) 585 return -1; 586 for(t = 0; t < nmacro_args; t++) 587 { 588 if(!strcmp(id, macro_args[t]->arg)) 589 break; 590 } 591 return t < nmacro_args ? t : -1; 592 } 593 594 static mtext_t *new_mtext(char *str, int idx, def_exp_t type) 595 { 596 mtext_t *mt = pp_xmalloc(sizeof(mtext_t)); 597 if(!mt) 598 return NULL; 599 if(str == NULL) 600 mt->subst.argidx = idx; 601 else 602 mt->subst.text = str; 603 mt->type = type; 604 mt->next = mt->prev = NULL; 605 return mt; 606 } 607 608 static mtext_t *combine_mtext(mtext_t *tail, mtext_t *mtp) 609 { 610 if(!tail) 611 return mtp; 612 613 if(!mtp) 614 return tail; 615 616 if(tail->type == exp_text && mtp->type == exp_text) 617 { 618 char *new_text; 619 new_text = pp_xrealloc(tail->subst.text, strlen(tail->subst.text)+strlen(mtp->subst.text)+1); 620 if(!new_text) 621 return mtp; 622 tail->subst.text = new_text; 623 strcat(tail->subst.text, mtp->subst.text); 624 free(mtp->subst.text); 625 free(mtp); 626 return tail; 627 } 628 629 if(tail->type == exp_concat && mtp->type == exp_concat) 630 { 631 free(mtp); 632 return tail; 633 } 634 635 if(tail->type == exp_concat && mtp->type == exp_text) 636 { 637 int len = strlen(mtp->subst.text); 638 while(len) 639 { 640 /* FIXME: should delete space from head of string */ 641 if(isspace(mtp->subst.text[len-1] & 0xff)) 642 mtp->subst.text[--len] = '\0'; 643 else 644 break; 645 } 646 647 if(!len) 648 { 649 free(mtp->subst.text); 650 free(mtp); 651 return tail; 652 } 653 } 654 655 if(tail->type == exp_text && mtp->type == exp_concat) 656 { 657 int len = strlen(tail->subst.text); 658 while(len) 659 { 660 if(isspace(tail->subst.text[len-1] & 0xff)) 661 tail->subst.text[--len] = '\0'; 662 else 663 break; 664 } 665 666 if(!len) 667 { 668 mtp->prev = tail->prev; 669 mtp->next = tail->next; 670 if(tail->prev) 671 tail->prev->next = mtp; 672 free(tail->subst.text); 673 free(tail); 674 return mtp; 675 } 676 } 677 678 tail->next = mtp; 679 mtp->prev = tail; 680 681 return mtp; 682 } 683 684 static char *merge_text(char *s1, char *s2) 685 { 686 int l1; 687 int l2; 688 char *snew; 689 if(!s1) 690 return s2; 691 if(!s2) 692 return s1; 693 l1 = strlen(s1); 694 l2 = strlen(s2); 695 snew = pp_xrealloc(s1, l1+l2+1); 696 if(!snew) 697 { 698 free(s2); 699 return s1; 700 } 701 s1 = snew; 702 memcpy(s1+l1, s2, l2+1); 703 free(s2); 704 return s1; 705 } 706