1 /*@z07.c:Object Service:SplitIsDefinite(), DisposeObject()@*******************/
2 /* */
3 /* THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.39) */
4 /* COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston */
5 /* */
6 /* Jeffrey H. Kingston (jeff@it.usyd.edu.au) */
7 /* School of Information Technologies */
8 /* The University of Sydney 2006 */
9 /* AUSTRALIA */
10 /* */
11 /* This program is free software; you can redistribute it and/or modify */
12 /* it under the terms of the GNU General Public License as published by */
13 /* the Free Software Foundation; either Version 3, or (at your option) */
14 /* any later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19 /* GNU General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU General Public License */
22 /* along with this program; if not, write to the Free Software */
23 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA */
24 /* */
25 /* FILE: z07.c */
26 /* MODULE: Object Service */
27 /* EXTERNS: MakeWord(), MakeWordTwo(), MakeWordThree(), */
28 /* DisposeObject(), CopyObject(), */
29 /* SplitIsDefinite(), InsertObject() */
30 /* */
31 /*****************************************************************************/
32 #include "externs.h"
33
34
35 /*****************************************************************************/
36 /* */
37 /* BOOLEAN SplitIsDefinite(x) */
38 /* */
39 /* Return TRUE if x is a definite SPLIT object (both children definite) */
40 /* */
41 /*****************************************************************************/
42
SplitIsDefinite(OBJECT x)43 BOOLEAN SplitIsDefinite(OBJECT x)
44 { OBJECT y1, y2;
45 assert( type(x) == SPLIT, "SplitIsDefinite: x not a SPLIT!" );
46 Child(y1, DownDim(x, COLM));
47 Child(y2, DownDim(x, ROWM));
48 return is_definite(type(y1)) && is_definite(type(y2));
49 } /* end SplitIsDefinite */
50
51
52 /*****************************************************************************/
53 /* */
54 /* DisposeSplitObject(x) */
55 /* */
56 /* Dispose SPLIT object x, taking care to handle COL_THR and ROW_THR */
57 /* children properly. */
58 /* */
59 /*****************************************************************************/
60
DisposeSplitObject(OBJECT x)61 static void DisposeSplitObject(OBJECT x)
62 { int i, count;
63 OBJECT y, link, uplink;
64 debug1(DOS, DDD, "[ DisposeSplitObject( %ld )", (long) x);
65 assert(type(x) == SPLIT, "DisposeSplitObject: type(x) != SPLIT!");
66 assert(Down(x) != x, "DisposeSplitObject: x has no children!")
67 assert(LastDown(x) != Down(x), "DisposeSplitObject: x has one child!")
68 assert(LastDown(x) == NextDown(Down(x)), "DisposeSplitObject: children!")
69
70 /* handle first child */
71 CountChild(y, Down(x), count);
72 if( type(y) == COL_THR )
73 {
74 /* find corresponding child link out of y and delete that link */
75 for( link = Down(y), uplink = Up(y), i = 1;
76 link != y && uplink != y && i < count;
77 link = NextDown(link), uplink = NextUp(uplink), i++ );
78 assert( link != y && uplink != y, "DisposeSplitObject: link (a)!" );
79 DisposeChild(link);
80 }
81 DisposeChild(Down(x));
82
83 /* handle second child */
84 CountChild(y, LastDown(x), count);
85 if( type(y) == ROW_THR )
86 {
87 /* find corresponding child link out of y and delete that link */
88 for( link = Down(y), uplink = Up(y), i = 1;
89 link != y && uplink != y && i < count;
90 link = NextDown(link), uplink = NextUp(uplink), i++ );
91 assert( link != y && uplink != y, "DisposeSplitObject: link (b)!" );
92 DisposeChild(link);
93 }
94 DisposeChild(LastDown(x));
95 debug0(DOS, DDD, "] DisposeSplitObject returning");
96 } /* end DisposeSplitObject */
97
98
99 /*****************************************************************************/
100 /* */
101 /* DisposeObject(x) */
102 /* */
103 /* Dispose object x recursively, leaving intact any shared descendants. */
104 /* We return a useless integer so that we can use this in expresssions. */
105 /* */
106 /* If x is a SPLIT object then one or both of its children could be */
107 /* COL_THR or ROW_THR objects. If such thread object is has this SPLIT */
108 /* as its ith parent, then we need to dispose its ith child. */
109 /* */
110 /*****************************************************************************/
111
DisposeObject(OBJECT x)112 int DisposeObject(OBJECT x)
113 { debug2(DOS,DDD,"[DisposeObject( %ld ), type = %s, x =", (long) x, Image(type(x)));
114 ifdebug(DOS, DDD, DebugObject(x));
115 assert( Up(x) == x, "DisposeObject: x has a parent!" );
116 if( type(x) == SPLIT )
117 DisposeSplitObject(x);
118 else
119 { while( Down(x) != x ) DisposeChild(Down(x));
120 Dispose(x);
121 }
122 debug0(DOS, DDD, "]DisposeObject returning.");
123 return 0;
124 } /* end DisposeObject */
125
126
127 /*@::MakeWord(), MakeWordTwo()@***********************************************/
128 /* */
129 /* OBJECT MakeWord(typ, str, pos) */
130 /* */
131 /* Return an unsized WORD or QWORD made from the given string and fpos. */
132 /* */
133 /*****************************************************************************/
134
MakeWord(unsigned typ,FULL_CHAR * str,FILE_POS * pos)135 OBJECT MakeWord(unsigned typ, FULL_CHAR *str, FILE_POS *pos)
136 { OBJECT res;
137 NewWord(res, typ, StringLength(str), pos);
138 StringCopy(string(res), str);
139 FposCopy(fpos(res), *pos);
140 debug4(DOS, DDD, "MakeWord(%s, %s, %s) returning %s",
141 Image(typ), str, EchoFilePos(pos), EchoObject(res));
142 return res;
143 } /* end MakeWord */
144
145
146 /*****************************************************************************/
147 /* */
148 /* OBJECT MakeWordTwo(typ, str1, str2, pos) */
149 /* */
150 /* Return an unsized WORD or QWORD made from the two strings and fpos. */
151 /* */
152 /*****************************************************************************/
153
MakeWordTwo(unsigned typ,FULL_CHAR * str1,FULL_CHAR * str2,FILE_POS * pos)154 OBJECT MakeWordTwo(unsigned typ, FULL_CHAR *str1, FULL_CHAR *str2, FILE_POS *pos)
155 { int len1 = StringLength(str1);
156 int len2 = StringLength(str2);
157 OBJECT res;
158 debug4(DOS, DDD, "MakeWordTwo(%s, %s, %s, %s)",
159 Image(typ), str1, str2, EchoFilePos(pos));
160 NewWord(res, typ, len1 + len2, pos);
161 StringCopy(string(res), str1);
162 StringCopy(&string(res)[len1], str2);
163 FposCopy(fpos(res), *pos);
164 debug5(DOS, DDD, "MakeWordTwo(%s, %s, %s, %s) returning %s",
165 Image(typ), str1, str2, EchoFilePos(pos), EchoObject(res));
166 return res;
167 } /* end MakeWordTwo */
168
169
170 /*****************************************************************************/
171 /* */
172 /* OBJECT MakeWordThree(s1, s2, s3) */
173 /* */
174 /* Return an unsized WORD containing these three strings. */
175 /* */
176 /*****************************************************************************/
177
MakeWordThree(FULL_CHAR * s1,FULL_CHAR * s2,FULL_CHAR * s3)178 OBJECT MakeWordThree(FULL_CHAR *s1, FULL_CHAR *s2, FULL_CHAR *s3)
179 { int len1 = StringLength(s1);
180 int len2 = StringLength(s2);
181 int len3 = StringLength(s3);
182 OBJECT res;
183 debug3(DOS, DDD, "MakeWordThree(%s, %s, %s)", s1, s2, s3);
184 NewWord(res, WORD, len1 + len2 + len3, no_fpos);
185 StringCopy(string(res), s1);
186 StringCopy(&string(res)[len1], s2);
187 StringCopy(&string(res)[len1 + len2], s3);
188 debug4(DOS, DDD, "MakeWordThree(%s, %s, %s) returning %s",
189 s1, s2, s3, EchoObject(res));
190 return res;
191 } /* end MakeWordThree */
192
193
194 /*@::CopyObject()@************************************************************/
195 /* */
196 /* OBJECT CopyObject(x, pos) */
197 /* */
198 /* Make a copy of unsized object x, setting all file positions to *pos, */
199 /* unless *pos is no_fpos, in which case set all file positions to what */
200 /* they are in the object being copied. */
201 /* */
202 /*****************************************************************************/
203
CopyObject(OBJECT x,FILE_POS * pos)204 OBJECT CopyObject(OBJECT x, FILE_POS *pos)
205 { OBJECT y, link, res, tmp;
206
207 debug2(DOS, DDD, "[ CopyObject(%s, %s)", EchoObject(x), EchoFilePos(pos));
208 switch( type(x) )
209 {
210
211 case WORD:
212 case QWORD:
213
214 NewWord(res, type(x), StringLength(string(x)), pos);
215 StringCopy(string(res), string(x));
216 break;
217
218
219 case GAP_OBJ:
220
221 New(res, GAP_OBJ);
222 GapCopy(gap(res), gap(x));
223 hspace(res) = hspace(x);
224 vspace(res) = vspace(x);
225 if( Down(x) != x )
226 { Child(y, Down(x));
227 tmp = CopyObject(y, pos);
228 Link(res, tmp);
229 }
230 break;
231
232
233 /* case HEAD: */
234 case NULL_CLOS:
235 case PAGE_LABEL:
236 case CROSS:
237 case FORCE_CROSS:
238 case BEGIN_HEADER:
239 case END_HEADER:
240 case SET_HEADER:
241 case CLEAR_HEADER:
242 case ONE_COL:
243 case ONE_ROW:
244 case WIDE:
245 case HIGH:
246 case HSHIFT:
247 case VSHIFT:
248 case HMIRROR:
249 case VMIRROR:
250 case HSCALE:
251 case VSCALE:
252 case HCOVER:
253 case VCOVER:
254 case SCALE:
255 case KERN_SHRINK:
256 case HCONTRACT:
257 case VCONTRACT:
258 case HLIMITED:
259 case VLIMITED:
260 case HEXPAND:
261 case VEXPAND:
262 case START_HVSPAN:
263 case START_HSPAN:
264 case START_VSPAN:
265 case HSPAN:
266 case VSPAN:
267 case PADJUST:
268 case HADJUST:
269 case VADJUST:
270 case ROTATE:
271 case BACKGROUND:
272 case RAW_VERBATIM:
273 case VERBATIM:
274 case CASE:
275 case YIELD:
276 case BACKEND:
277 case XCHAR:
278 case FONT:
279 case SPACE:
280 case YUNIT:
281 case ZUNIT:
282 case SET_CONTEXT:
283 case GET_CONTEXT:
284 case BREAK:
285 case UNDERLINE:
286 case UNDERLINE_COLOUR:
287 case COLOUR:
288 case TEXTURE:
289 case OUTLINE:
290 case LANGUAGE:
291 case CURR_LANG:
292 case CURR_FAMILY:
293 case CURR_FACE:
294 case CURR_YUNIT:
295 case CURR_ZUNIT:
296 case COMMON:
297 case RUMP:
298 case MELD:
299 case INSERT:
300 case ONE_OF:
301 case NEXT:
302 case PLUS:
303 case MINUS:
304 case OPEN:
305 case TAGGED:
306 case INCGRAPHIC:
307 case SINCGRAPHIC:
308 case PLAIN_GRAPHIC:
309 case GRAPHIC:
310 case LINK_SOURCE:
311 case LINK_DEST:
312 case LINK_DEST_NULL:
313 case LINK_URL:
314 case VCAT:
315 case HCAT:
316 case ACAT:
317 case ENV_OBJ:
318
319 New(res, type(x));
320 for( link = Down(x); link != x; link = NextDown(link) )
321 { Child(y, link);
322 tmp = CopyObject(y, pos);
323 Link(res, tmp);
324 }
325 break;
326
327
328 case FILTERED:
329
330 New(res, type(x));
331 for( link = Down(x); link != x; link = NextDown(link) )
332 { Child(y, link);
333 Link(res, y); /* do not copy children of FILTERED */
334 }
335 debug3(DFH, D, "copying FILTERED %d into %d %s",
336 (int) x, (int) res, EchoObject(res));
337 break;
338
339
340 case ENV:
341
342 res = x; /* do not copy environments */
343 break;
344
345
346 case PAR:
347
348 New(res, PAR);
349 actual(res) = actual(x);
350 assert( Down(x) != x, "CopyObject: PAR child!" );
351 Child(y, Down(x));
352 tmp = CopyObject(y, pos);
353 Link(res, tmp);
354 break;
355
356
357 case CLOSURE:
358
359 New(res, CLOSURE);
360 for( link = Down(x); link != x; link = NextDown(link) )
361 { Child(y, link);
362 assert( type(y) != CLOSURE, "CopyObject: CLOSURE!" );
363 tmp = CopyObject(y, pos);
364 Link(res, tmp);
365 }
366 actual(res) = actual(x);
367 StyleCopy(save_style(res), save_style(x));
368 break;
369
370
371 default:
372
373 assert1(FALSE, "CopyObject:", Image(type(x)));
374 res = nilobj;
375 break;
376
377 } /* end switch */
378 if( pos == no_fpos ) FposCopy(fpos(res), fpos(x));
379 else FposCopy(fpos(res), *pos);
380 debug1(DOS, DDD, "] CopyObject returning %s", EchoObject(res));
381 return res;
382 } /* end CopyObject */
383
384
385 /*****************************************************************************/
386 /* */
387 /* OBJECT InsertObject(OBJECT x, OBJECT *ins, STYLE *style) */
388 /* */
389 /* Search through manifested object x for an ACAT where ins may be */
390 /* attached. If successful, set *ins to nilobj after the attachment. */
391 /* */
392 /*****************************************************************************/
393
InsertObject(OBJECT x,OBJECT * ins,STYLE * style)394 OBJECT InsertObject(OBJECT x, OBJECT *ins, STYLE *style)
395 { OBJECT link, y, g, res;
396 debug2(DOS, D, "InsertObject(%s, %s)", EchoObject(x), EchoObject(*ins));
397 switch( type(x) )
398 {
399 case WORD:
400 case QWORD:
401
402 New(res, ACAT);
403 FposCopy(fpos(res), fpos(x));
404 ReplaceNode(res, x);
405 Link(res, x);
406 StyleCopy(save_style(res), *style);
407 adjust_cat(res) = padjust(*style);
408 res = InsertObject(res, ins, style);
409 break;
410
411
412 case NULL_CLOS:
413 case BEGIN_HEADER:
414 case END_HEADER:
415 case SET_HEADER:
416 case CLEAR_HEADER:
417 case HEAD:
418 case CROSS:
419 case FORCE_CROSS:
420 case PAGE_LABEL:
421 case CLOSURE:
422 case INCGRAPHIC:
423 case SINCGRAPHIC:
424 case HSPAN:
425 case VSPAN:
426
427 res = x;
428 break;
429
430
431 case HCAT:
432 case VCAT:
433 case COL_THR:
434 case ROW_THR:
435 case SPLIT:
436
437 for( link = Down(x); link != x && *ins != nilobj; link = NextDown(link) )
438 { Child(y, link);
439 y = InsertObject(y, ins, style);
440 }
441 res = x;
442 break;
443
444
445 case ONE_COL:
446 case ONE_ROW:
447 case PADJUST:
448 case HADJUST:
449 case VADJUST:
450 case HCONTRACT:
451 case VCONTRACT:
452 case HLIMITED:
453 case VLIMITED:
454 case HEXPAND:
455 case VEXPAND:
456 case HMIRROR:
457 case VMIRROR:
458 case HSCALE:
459 case VSCALE:
460 case HCOVER:
461 case VCOVER:
462 case PLAIN_GRAPHIC:
463 case GRAPHIC:
464 case LINK_SOURCE:
465 case LINK_DEST:
466 case LINK_DEST_NULL:
467 case LINK_URL:
468 case ROTATE:
469 case BACKGROUND:
470 case SCALE:
471 case KERN_SHRINK:
472 case WIDE:
473 case HIGH:
474 case HSHIFT:
475 case VSHIFT:
476 case START_HVSPAN:
477 case START_HSPAN:
478 case START_VSPAN:
479
480 Child(y, LastDown(x));
481 y = InsertObject(y, ins, style);
482 res = x;
483 break;
484
485
486 case ACAT:
487
488 New(g, GAP_OBJ);
489 SetGap(gap(g), FALSE, FALSE, TRUE, FIXED_UNIT, EDGE_MODE, 0);
490 hspace(g) = vspace(g) = 0;
491 underline(g) = UNDER_OFF;
492 Link(Down(x), g);
493 Link(Down(x), *ins);
494 underline(*ins) = UNDER_OFF;
495 *ins = nilobj;
496 res = x;
497 break;
498
499
500 default:
501
502 assert1(FALSE, "InsertObject:", Image(type(x)));
503 res = x;
504 break;
505
506 }
507 debug2(DOS, D, "InsertObject returning (%s) %s",
508 *ins == nilobj ? "success" : "failure", EchoObject(res));
509 return res;
510 } /* end InsertObject */
511
512
513 /*****************************************************************************/
514 /* */
515 /* Meld(x, y) */
516 /* */
517 /* Return the meld of x with y. */
518 /* */
519 /*****************************************************************************/
520 #define NO_DIR 0
521 #define X_DIR 1
522 #define Y_DIR 2
523 #define XY_DIR 3
524 #define MAX_MELD 32
525
Meld(OBJECT x,OBJECT y)526 OBJECT Meld(OBJECT x, OBJECT y)
527 { OBJECT res;
528 char table[MAX_MELD][MAX_MELD], dir[MAX_MELD][MAX_MELD];
529 OBJECT xcomp[MAX_MELD], ycomp[MAX_MELD];
530 OBJECT xgaps[MAX_MELD], ygaps[MAX_MELD];
531 BOOLEAN is_equal;
532 OBJECT link, z = nilobj, g; BOOLEAN jn;
533 int xlen, ylen, xi, yi;
534 debug2(DOS, D, "Meld(%s, %s)", EchoObject(x), EchoObject(y));
535 assert(type(x) == ACAT, "Meld: type(x) != ACAT");
536 assert(type(y) == ACAT, "Meld: type(y) != ACAT");
537
538 /* initialize xcomp, xgaps, xlen */
539 debug0(DOS, DD, " initializing xcomp[]");
540 xlen = 0;
541 xcomp[xlen] = nilobj;
542 xlen++;
543 g = nilobj;
544 FirstDefinite(x, link, z, jn);
545 while( link != x )
546 { if( xlen >= MAX_MELD )
547 Error(7, 1, "%s: maximum paragraph length (%d) exceeded", FATAL, &fpos(x),
548 KW_MELD, MAX_MELD-1);
549 assert( type(z) != ACAT, "Meld: xcomp is ACAT!");
550 if( g == nilobj || width(gap(g)) != 0 )
551 {
552 debug3(DOS, DD, " initializing xcomp[%d] to %s %s",
553 xlen, Image(type(z)), EchoObject(z));
554 xcomp[xlen] = z;
555 xgaps[xlen] = g;
556 xlen++;
557 }
558 else
559 {
560 debug3(DOS, DD, " extending xcomp[%d] with %s %s",
561 xlen-1, Image(type(z)), EchoObject(z));
562 if( type(xcomp[xlen-1]) != ACAT )
563 {
564 New(res, ACAT);
565 StyleCopy(save_style(res), save_style(x));
566 Link(res, xcomp[xlen-1]);
567 xcomp[xlen-1] = res;
568 }
569 Link(xcomp[xlen-1], g);
570 Link(xcomp[xlen-1], z);
571 }
572 NextDefiniteWithGap(x, link, z, g, jn)
573 }
574
575 /* initialize ycomp, ygaps, ylen */
576 debug0(DOS, DD, " initializing ycomp[]");
577 ylen = 0;
578 ycomp[ylen] = nilobj;
579 ylen++;
580 g = nilobj;
581 FirstDefinite(y, link, z, jn);
582 while( link != y )
583 { if( ylen >= MAX_MELD )
584 Error(7, 1, "%s: maximum paragraph length (%d) exceeded", FATAL, &fpos(y),
585 KW_MELD, MAX_MELD-1);
586 assert( type(z) != ACAT, "Meld: ycomp is ACAT!");
587 if( g == nilobj || width(gap(g)) != 0 )
588 {
589 debug3(DOS, DD, " initializing ycomp[%d] to %s %s",
590 ylen, Image(type(z)), EchoObject(z));
591 ycomp[ylen] = z;
592 ygaps[ylen] = g;
593 ylen++;
594 }
595 else
596 {
597 debug3(DOS, DD, " extending ycomp[%d] with %s %s",
598 ylen-1, Image(type(z)), EchoObject(z));
599 if( type(ycomp[ylen-1]) != ACAT )
600 {
601 New(res, ACAT);
602 StyleCopy(save_style(res), save_style(x));
603 Link(res, ycomp[ylen-1]);
604 ycomp[ylen-1] = res;
605 }
606 Link(ycomp[ylen-1], g);
607 Link(ycomp[ylen-1], z);
608 }
609 NextDefiniteWithGap(y, link, z, g, jn)
610 }
611
612 /* initialize table and dir */
613 debug0(DOS, DD, " initializing table[]");
614 table[0][0] = 0;
615 dir[0][0] = NO_DIR;
616 for( xi = 1; xi < xlen; xi++ )
617 { table[xi][0] = 0;
618 dir[xi][0] = X_DIR;
619 }
620 for( yi = 1; yi < ylen; yi++ )
621 { table[0][yi] = 0;
622 dir[0][yi] = Y_DIR;
623 }
624 for( xi = 1; xi < xlen; xi++ )
625 {
626 for( yi = 1; yi < ylen; yi++ )
627 {
628 is_equal = EqualManifested(xcomp[xi], ycomp[yi]);
629 if( is_equal )
630 {
631 table[xi][yi] = 1 + table[xi - 1][yi - 1];
632 dir[xi][yi] = XY_DIR;
633 debug3(DOS, DD, " assigning (XY) table[%d][%d] = %d", xi, yi,
634 table[xi][yi]);
635 }
636 else if( table[xi - 1][yi] > table[xi][yi - 1] )
637 {
638 table[xi][yi] = table[xi - 1][yi];
639 dir[xi][yi] = X_DIR;
640 debug3(DOS, DD, " assigning (X) table[%d][%d] = %d", xi, yi,
641 table[xi][yi]);
642 }
643 else
644 {
645 table[xi][yi] = table[xi][yi - 1];
646 dir[xi][yi] = Y_DIR;
647 debug3(DOS, DD, " assigning (Y) table[%d][%d] = %d", xi, yi,
648 table[xi][yi]);
649 }
650 }
651 }
652
653 /* traverse table from [xlen-l][ylen-1] back to [0][0], finding who's in */
654 debug0(DOS, DD, " traversing table[]");
655 New(res, ACAT);
656 StyleCopy(save_style(res), save_style(x));
657 for( xi = xlen - 1, yi = ylen - 1; dir[xi][yi] != NO_DIR; )
658 {
659 switch( dir[xi][yi] )
660 {
661 case XY_DIR:
662
663 debug3(DOS, DD, " at table[%d][%d] (XY) linking %s",
664 xi, yi, EchoObject(xcomp[xi]));
665 if( type(xcomp[xi]) != ACAT )
666 {
667 Link(Down(res), xcomp[xi]);
668 }
669 else
670 TransferLinks(Down(xcomp[xi]), xcomp[xi], Down(res));
671 g = xgaps[xi];
672 xi--;
673 yi--;
674 break;
675
676
677 case Y_DIR:
678
679 debug3(DOS, DD, " at table[%d][%d] (ydec) linking %s",
680 xi, yi, EchoObject(ycomp[yi]));
681 if( type(ycomp[yi]) != ACAT )
682 {
683 Link(Down(res), ycomp[yi]);
684 }
685 else
686 TransferLinks(Down(ycomp[yi]), ycomp[yi], Down(res));
687 g = ygaps[yi];
688 yi--;
689 break;
690
691
692 case X_DIR:
693
694 debug3(DOS, DD, " at table[%d][%d] (xdec) linking %s",
695 xi, yi, EchoObject(xcomp[xi]));
696 if( type(xcomp[xi]) != ACAT )
697 {
698 Link(Down(res), xcomp[xi]);
699 }
700 else
701 TransferLinks(Down(xcomp[xi]), xcomp[xi], Down(res));
702 g = xgaps[xi];
703 xi--;
704 }
705
706 /* add gap if not last time; either g or one we make up */
707 if( dir[xi][yi] != NO_DIR )
708 {
709 if( g == nilobj )
710 {
711 OBJECT tmp;
712 New(g, GAP_OBJ);
713 hspace(g) = 1; vspace(g) = 0;
714 FposCopy(fpos(g), *no_fpos);
715 SetGap(gap(g), FALSE, FALSE, TRUE, FIXED_UNIT, EDGE_MODE,
716 width(space_gap(save_style(res))));
717 tmp = MakeWord(WORD, AsciiToFull("1s"), &fpos(g));
718 Link(g, tmp);
719 Link(Down(res), g);
720 }
721 else
722 {
723 assert(Up(g) == LastUp(g), "Meld: g!" );
724 Link(Down(res), g);
725 }
726 }
727 }
728
729 debug1(DOS, D, "Meld returning %s", EchoObject(res));
730 return res;
731 }
732
733
734 /*****************************************************************************/
735 /* */
736 /* static BOOLEAN EqualChildren(x, y) */
737 /* */
738 /* Return TRUE if manifested objects x and y have equal children. */
739 /* */
740 /*****************************************************************************/
741
EqualChildren(OBJECT x,OBJECT y)742 static BOOLEAN EqualChildren(OBJECT x, OBJECT y)
743 { OBJECT xl, yl, xc, yc;
744 xl = Down(x), yl = Down(y);
745 for( ; xl != x && yl != y; xl = NextDown(xl), yl = NextDown(yl) )
746 {
747 Child(xc, xl);
748 Child(yc, yl);
749 if( !EqualManifested(xc, yc) )
750 return FALSE;
751 }
752 return xl == x && yl == y;
753 }
754
755
756 /*****************************************************************************/
757 /* */
758 /* BOOLEAN EqualManifested(x, y) */
759 /* */
760 /* Return TRUE if manifested objects x and y are equal. */
761 /* */
762 /*****************************************************************************/
763
EqualManifested(OBJECT x,OBJECT y)764 BOOLEAN EqualManifested(OBJECT x, OBJECT y)
765 { OBJECT xc, yc;
766
767 if( is_word(type(x)) && is_word(type(y)) )
768 {
769 return StringEqual(string(x), string(y));
770 }
771 else if( type(x) != type(y) )
772 {
773 return FALSE;
774 }
775 else switch( type(x) )
776 {
777 case GAP_OBJ:
778
779 /* objects are equal if the two gaps are equal */
780 return GapEqual(gap(x), gap(y));
781 break;
782
783
784 case CLOSURE:
785
786 /* objects are equal if it's the same symbol and same parameters */
787 if( actual(x) != actual(y) )
788 return FALSE;
789 return EqualChildren(x, y);
790 break;
791
792
793 case PAGE_LABEL:
794 case NULL_CLOS:
795 case CROSS:
796 case FORCE_CROSS:
797 case HEAD:
798 case SPLIT:
799 case HSPANNER:
800 case VSPANNER:
801 case COL_THR:
802 case ROW_THR:
803 case ACAT:
804 case HCAT:
805 case VCAT:
806 case HMIRROR:
807 case VMIRROR:
808 case HSCALE:
809 case VSCALE:
810 case BEGIN_HEADER:
811 case SET_HEADER:
812 case END_HEADER:
813 case CLEAR_HEADER:
814 case ONE_COL:
815 case ONE_ROW:
816 case HCOVER:
817 case VCOVER:
818 case HCONTRACT:
819 case VCONTRACT:
820 case HEXPAND:
821 case VEXPAND:
822 case START_HSPAN:
823 case START_VSPAN:
824 case START_HVSPAN:
825 case HSPAN:
826 case VSPAN:
827 case KERN_SHRINK:
828 case BACKGROUND:
829 case GRAPHIC:
830 case PLAIN_GRAPHIC:
831 case LINK_DEST:
832 case LINK_DEST_NULL:
833 case LINK_URL:
834 case INCGRAPHIC:
835 case SINCGRAPHIC:
836 case PAR:
837
838 /* objects are equal if the children are equal */
839 return EqualChildren(x, y);
840 break;
841
842
843 case LINK_SOURCE:
844
845 /* objects are equal if right children are equal */
846 Child(xc, LastDown(x));
847 Child(yc, LastDown(y));
848 return EqualManifested(xc, yc);
849 break;
850
851
852 case WIDE:
853 case HIGH:
854
855 /* objects are equal if constraints and children are equal */
856 return EqualConstraint(constraint(x), constraint(y)) &&
857 EqualChildren(x, y);
858 break;
859
860
861 case HSHIFT:
862 case VSHIFT:
863
864 /* objects are equal if constraints and children are equal */
865 return shift_type(x) == shift_type(y) &&
866 GapEqual(shift_gap(x), shift_gap(y)) && EqualChildren(x, y);
867 break;
868
869
870 case SCALE:
871
872 /* objects are equal if constraints and children are equal */
873 return bc(constraint(x)) == bc(constraint(y)) &&
874 fc(constraint(x)) == fc(constraint(y)) &&
875 EqualChildren(x, y);
876 break;
877
878
879 case ROTATE:
880
881 /* objects are equal if angle is equal and children are equal */
882 return sparec(constraint(x)) == sparec(constraint(y)) &&
883 EqualChildren(x, y);
884 break;
885
886
887 default:
888
889 Error(7, 2, "EqualUnsized: type == %s", FATAL, &fpos(x), Image(type(x)));
890 return FALSE;
891 break;
892 }
893 }
894