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