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