1 /* load.c  */
2 /* COPYRIGHT (C) 2000 THE VICTORIA UNIVERSITY OF MANCHESTER and John Levon
3  * This program is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU General Public License as published by the Free
5  * Software Foundation; either version 2 of the License, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15  * Place - Suite 330, Boston, MA 02111-1307, USA.
16  */
17 /*
18  * $Log: load.c,v $
19  * Revision 1.2  2000/12/06 20:56:02  moz
20  * GPL stuff.
21  *
22  * Revision 1.1.1.1  2000/08/21 01:05:31  moz
23  *
24  *
25  * Revision 1.1.1.1  2000/07/19 22:45:30  moz
26  * CVS Import
27  *
28  * Revision 1.36  2000/03/13 02:47:28  moz
29  * Fill in useless text Object parameters.
30  *
31  * Revision 1.35  2000/03/13 00:05:55  moz
32  * Finally fixed compound-in-compound depth bug.
33  *
34  * Revision 1.34  2000/03/11 19:09:51  moz
35  * Compile fix for previous change.
36  *
37  * Revision 1.33  2000/03/07 21:13:56  moz
38  * Compile fixes.
39  *
40  * Revision 1.32  2000/03/04 23:33:50  moz
41  * Handle huge fonts more gracefully.
42  *
43  * Revision 1.31  2000/03/04 17:38:32  moz
44  * Remarkable simple fix for rot+not left just bug.
45  *
46  * Revision 1.30  2000/03/04 17:18:33  moz
47  * Rotated text just!=LEFT fix part 1 - don't adjust when rotated.
48  *
49  * Revision 1.29  2000/02/18 21:18:31  moz
50  * polyline.pic usage changed.
51  *
52  * Revision 1.28  2000/02/04 01:54:12  moz
53  * switch_icons() needs view
54  *
55  * Revision 1.27  2000/01/28 17:31:15  moz
56  * Skip ###FIGURINE correctly.
57  *
58  * Revision 1.26  2000/01/26 18:18:08  moz
59  * Don't use ++ in call to add_to_list (may be a ammacro).
60  *
61  * Revision 1.25  1999/11/17 01:14:52  moz
62  * Cut down foliage a little.
63  *
64  * Revision 1.24  1999/11/15 02:08:38  moz
65  * Use rounded trig.
66  * Name change.
67  *
68  * Revision 1.23  1999/06/17 19:09:12  moz
69  * Load saved attachment information and calculate the correct derries.
70  *
71  * Revision 1.22  1999/06/17 15:49:05  moz
72  * Plug text with NULL.
73  *
74  * Revision 1.21  1999/06/16 00:56:41  moz
75  * Slight change to error message for clarity.
76  *
77  * Revision 1.20  1999/05/23 21:20:08  moz
78  * Fixed fill style for black/white objects.
79  *
80  * Revision 1.19  1999/05/22 23:39:09  moz
81  *  Pedantic ANSI.
82  *
83  * Revision 1.18  1999/05/22 15:31:09  moz
84  * Handle text justifications other than LEFT
85  *
86  * Revision 1.17  1999/05/22 04:18:37  moz
87  * Slight improvement in compound depth handling.
88  *
89  * Revision 1.16  1999/05/22 04:12:09  moz
90  * Fixed 3dhouse.fig. Needed to reverse depth list.
91  *
92  * Revision 1.15  1999/05/22 03:53:12  moz
93  * Implicit depth ordering handled for normal objects.
94  * Still very broken for compounds (contrast transit.fig and greenpig.fig).
95  *
96  * Revision 1.14  1999/05/19 17:08:55  moz
97  * 1.0 Checkin.
98  *
99  * Revision 1.13  1999/05/04 18:16:54  moz
100  * Tints approximated.
101  *
102  * Revision 1.12  1999/04/29 03:57:46  moz
103  * Should delete font ascent from y1, not x1.
104  *
105  * Revision 1.11  1999/04/29 01:34:37  moz
106  * Correctly calculate the x,y topleft corner of the text.
107  *
108  * Revision 1.10  1999/04/28 20:14:26  moz
109  * Removed unused variables.
110  *
111  * Revision 1.9  1999/04/28 16:53:22  moz
112  * Fixed bbox calculation of rottext.
113  *
114  * Revision 1.8  1999/04/27 20:46:04  moz
115  * Fix ob.polyline.pic bug.
116  *
117  * Revision 1.7  1999/04/27 16:00:10  moz
118  * Flip text angle on load.
119  *
120  * Revision 1.6  1999/04/27 06:46:00  moz
121  * When on cmdline, create new document instead of rejecting filename.
122  *
123  * Revision 1.5  1999/04/27 04:11:05  moz
124  * Bug tagged FIX ME.
125  *
126  * Revision 1.4  1999/04/24 22:23:45  moz
127  * Load user-defined colours and store them.
128  *
129  * Revision 1.3  1999/04/20 03:13:48  moz
130  * Removed old code.
131  *
132  * Revision 1.2  1999/04/20 03:07:29  moz
133  * Changes to fix arcellipse loading.
134  *
135  * Revision 1.1  1999/03/30 00:05:21  moz
136  * Initial revision
137  *
138  */
139 
140 #include <ctype.h>
141 #include <string.h>
142 #include <math.h>
143 #include "include/figurine.h"
144 #include "include/extern.h"
145 
146 /* list of all objects loaded  */
147 List obs=NULL;
148 
149 /* temporary list of derry hosts - ob is host ob */
150 static List pderries=NULL;
151 /* temporary list of derry sources - ob is source ob  */
152 static List underried=NULL;
153 
154 /* maximum size of a line  */
155 #define MLINE 16384
156 
157 static FILE *fl=NULL;
158 static Document *doc;
159 static Boolean in_mm;
160 static char empty[] = "";
161 /* this is a pointer to a string
162 	containing the current line of the file */
163 static char *cp;
164 static ulong ob_depth=ULONG_MAX;
165 
166 /* fluff in a file is ignored  */
167 Boolean
is_fluff(char * c)168 is_fluff(char *c)
169 {
170 	if (is_vcomment(c))
171 		return FALSE;
172 
173  	return (c==NULL || *c=='\n' || *c=='#' || *c=='\0');
174 }
175 
176 /* returns up to end of line  */
177 char *
get_whole_line()178 get_whole_line()
179 {
180 	static char str[MLINE];
181 
182 	strcpy(str,"\n");
183 
184 	while (is_fluff(str) && fgets(str,MLINE,fl)!=NULL)
185 		;
186 
187 	while (strlen(str) && isspace(str[strlen(str)-1]))
188 		str[strlen(str)-1] = '\0';
189 
190 	while (str[0]!='\0' && isspace(str[0]))
191 		strcpy(str,str+1);
192 
193 	if (is_fluff(str))
194 		cp = empty;
195 	else
196 		cp = str;
197 
198 	return cp;
199 }
200 
201 /* read in paper size of document  */
202 void
parse_papersize()203 parse_papersize()
204 {
205 	char s[MLINE];
206 	int i;
207 
208 	strcpy(s,cp);
209 
210 	for (i=0; i<14; i++)
211 		{
212 		if (streq(s,sizes[i].fname))
213 			{
214 			strcpy(doc->canvas_name,sizes[i].fname);
215 			doc->width_in_inches = sizes[i].w;
216 			doc->height_in_inches = sizes[i].h;
217 			break;
218 			};
219 		};
220 
221 	if (i==14)
222 		{
223 		/* could be "Ledger" apparently  */
224 		/* assume Letter anyway  */
225 		strcpy(doc->canvas_name,sizes[0].fname);
226 		doc->width_in_inches = sizes[i].w;
227 		doc->height_in_inches = sizes[i].h;
228 		};
229 }
230 
231 /* convenience function  */
232 Boolean
string_eq(char * str)233 string_eq(char *str)
234 {
235 	Boolean b;
236 
237 	b = streq(cp,str);
238 	get_whole_line();
239 	return b;
240 }
241 
242 void
skip_to_space()243 skip_to_space()
244 {
245 	while (*cp!='\0' && !isspace(*cp))
246 		cp++;
247 
248 	while (*cp!='\0' && isspace(*cp))
249 		cp++;
250 }
251 
252 double
get_double()253 get_double()
254 {
255 	double d;
256 
257 	if (*cp=='\0')
258 		cp = get_whole_line();
259 
260 	sscanf(cp,"%lf",&d);
261 	skip_to_space();
262 
263 	return d;
264 }
265 
266 int
get_int()267 get_int()
268 {
269 	int i;
270 
271 	if (*cp=='\0')
272 		cp = get_whole_line();
273 
274 	if (*cp=='\0')
275 		return -1;
276 
277 	if (!sscanf(cp,"%d",&i))
278 		i = -1;
279 	skip_to_space();
280 
281 	return i;
282 }
283 
284 /* The following get routines pick out values as according
285 	to the file Doc/FORMAT3.2 for each object */
286 int
get_arc_open()287 get_arc_open()
288 {
289 	int i;
290 	/* NB xfig docs are WRONG. it is 1 for open and 2 for closed  */
291 	/* if we find a 0 it defaults to closed anyway  */
292 
293 	i = get_int();
294 	return (i==0 || i==2) ? FALSE : TRUE;
295 }
296 
297 int
get_line_style()298 get_line_style()
299 {
300 	int i;
301 
302 	i = get_int();
303 
304 	if (i==-1)
305 		i=0;
306 
307 	/* our defines match with the file settings */
308 	return i;
309 }
310 
311 int
get_fcolour()312 get_fcolour()
313 {
314 	int i;
315 
316 	i = get_int();
317 
318 	if (i==-1)
319 		i=0;
320 
321 	if (i>31 && !is_in_list(doc->cols, (uint)i))
322 		i=0;
323 
324 	return i+=STARTOFCOLOURS; /* move up into figurine style numbering */
325 }
326 
327 int
get_fill_fcolour()328 get_fill_fcolour()
329 {
330 	int i;
331 
332 	i = get_int();
333 
334 	if (i==-1)
335 		i=0;
336 
337 	if (i>31 && !is_in_list(doc->cols, (uint)i))
338 		i=0;
339 
340 	return i+=STARTOFFILLCOLOURS; /* move up into figurine style numbering */
341 }
342 
343 ulong
get_depth()344 get_depth()
345 {
346 	ulong i;
347 
348 	i = get_int();
349 	/* push depth to the back of our depth */
350 	i = 1000 - i;
351 	/* save depth for RAISE when loaded */
352 	ob_depth = min(ULONG_MAX-i,ob_depth);
353 	return ULONG_MAX - i;
354 }
355 
356 int
get_fillstyle(Object * ob)357 get_fillstyle(Object *ob)
358 {
359 	int i;
360 
361 	i = get_int();
362 
363 	if (ob->fillcolour==FILLCWHITE)
364 		{
365 		if (i==-1) return NONE;
366 		if (i==0)
367 			{
368 			ob->fillcolour = FILLCBLACK;
369 			return 0;
370 			};
371 		if (i<20) return 20-i;
372 		if (i==20) return SOLID;
373 		if (i<41) return 0;
374 
375 		return i-20;
376 		}
377 	else if (ob->fillcolour==FILLCBLACK)
378 		{
379 		if (i==-1) return NONE;
380 		if (i==0)
381 			{
382 			ob->fillcolour = FILLCWHITE;
383 			return 0;
384 			};
385 		if (i<20)
386 			{
387 			ob->fillcolour = FILLCWHITE;
388 			return i;
389 			};
390 		if (i==20) return SOLID;
391 		if (i<41) return 0;
392 
393 		return i-20;
394 		}
395 	else
396 		{
397 		if (i==-1) return i;
398 		if (i==0) return 20;
399 		if (i==20) return SOLID;
400 		if (i==40)
401 			{
402 			ob->fillcolour = FILLCWHITE;
403 			return SOLID;
404 			};
405 		if (i>40) return i-20;
406 		if (i>0 && i <20) return 20-i;
407 		if (i>20 && i<40)
408 			{
409 			/* better than nothing  */
410 			ob->colour = ob->fillcolour-(STARTOFFILLCOLOURS-STARTOFCOLOURS);
411 			ob->fillcolour = FILLCWHITE;
412 			return 20-(i-20);
413 			};
414 
415 		return 0;
416 		};
417 }
418 
419 int
get_capstyle()420 get_capstyle()
421 {
422 	switch (get_int())
423 		{
424 		case 0: return(CapButt); break;
425 		case 1: return(CapRound); break;
426 		case 2: return(CapProjecting); break;
427 		};
428 	return(CapRound);
429 }
430 
431 int
get_joinstyle()432 get_joinstyle()
433 {
434 	switch (get_int())
435 		{
436 		case 0: return(JoinMiter); break;
437 		case 1: return(JoinBevel); break;
438 		case 2: return(JoinRound); break;
439 		};
440 	return(JoinMiter);
441 }
442 
443 /* read in a point and unrelativise  */
444 VPoint *
parse_point(Object * ob)445 parse_point(Object *ob)
446 {
447 	VPoint *v;
448 
449 	v = (VPoint *)malloc(sizeof(VPoint));
450 
451 	v->x = get_int() - ob->bbox.x1;
452 	v->y = get_int() - ob->bbox.y1;
453 	v->derried = FALSE;
454 	return v;
455 
456 }
457 
458 /* read in a control point and unrelativise  */
459 SPoint *
parse_spoint(Object * ob)460 parse_spoint(Object *ob)
461 {
462 	SPoint *v;
463 
464 	v = (SPoint *)malloc(sizeof(SPoint));
465 
466 	v->x = get_int() - ob->bbox.x1;
467 	v->y = get_int() - ob->bbox.y1;
468 	v->derried = FALSE;
469 	return v;
470 
471 }
472 
473 /* parse an arrow definition  */
474 Arrow *
parse_arrow()475 parse_arrow()
476 {
477 	Arrow *a;
478 
479 	a = (Arrow *)malloc(sizeof(Arrow));
480 
481 	a->type = get_int();
482 	a->filled = get_int();
483 	a->lw = (long)get_double();
484 	a->w = (long)(80.0*get_double()/doc->ppi);
485 	a->h = (long)(80.0*get_double()/doc->ppi);
486 	return a;
487 }
488 
489 /* user-defined colour object  */
490 void
parse_colour_object()491 parse_colour_object()
492 {
493 	unsigned long planes[1];
494 	unsigned long colors[1];
495 	UColour *uc;
496 	XColor xcol;
497 	XVisualInfo xvi;
498 
499 	uc = (UColour *)malloc(sizeof(UColour));
500 	uc->tag = get_int();
501   	strcpy(uc->name,cp);
502 	get_whole_line();
503 
504 	if (!XMatchVisualInfo(display, screen, DefaultDepth(display,screen), PseudoColor, &xvi)
505 	    && !XMatchVisualInfo(display, screen, DefaultDepth(display,screen), DirectColor, &xvi))
506 	    	{
507 		if (!XMatchVisualInfo(display, screen, DefaultDepth(display,screen), TrueColor, &xvi))
508 			{
509 			fprintf(stderr,"figurine: wrong Visual: can't allocate read/write colorcell.\n");
510 			return;
511 			};
512 		/* TrueColor, so just parse the color, so get_colour for read-only */
513 		get_colour(&uc->colour,FALSE,"figurine.dummyargk","Figurine.Dummyargk", uc->name);
514 		doc->cols = add_to_list(doc->cols,(ulong)uc->tag,(ulong)uc->tag,(void *)uc);
515 		return;
516 		};
517 
518 	if (!XAllocColorCells(display, DefaultColormap(display,screen), False, planes,
519 								 1, colors, 1))
520 		{
521 		fprintf(stderr,"figurine: no colorcells left.\n");
522 		return;
523 		};
524 
525 	if (!XParseColor(display,DefaultColormap(display,screen), uc->name, &xcol))
526 		{
527 		fprintf(stderr,"figurine: couldn't allocate document colour %s\n", uc->name);
528 		return;
529 		};
530 
531 	xcol.flags = DoRed | DoGreen | DoBlue;
532 	xcol.pixel = colors[0];
533 	uc->colour = colors[0];
534 
535 	XStoreColor(display,DefaultColormap(display,screen),&xcol);
536 
537  	doc->cols = add_to_list(doc->cols,(ulong)uc->tag,(ulong)uc->tag,(void *)uc);
538 }
539 
540 void
parse_vcomment(Object * ob)541 parse_vcomment(Object *ob)
542 {
543 	PDerry *pd;
544 	int ci;
545 
546 	if (streq(cp,""))
547 		get_whole_line();
548 
549 	while (is_vcomment(cp))
550 		{
551 		ci = 0;
552 
553 		cp += 12; /* skip "###FIGURINE "  */
554 		if (numstreq(cp,"DERRY_SOURCE ",13))
555 			{
556 			cp += 13;
557 
558 			/* add to list of source derries */
559 			pd = (PDerry *)malloc(sizeof(PDerry));
560 
561 			pd->ob = ob;
562 			while (*cp!=' ')
563 				pd->tag[ci++] = *(cp++);
564 			pd->tag[ci]='\0';
565 			sscanf(cp,"%ld %ld",&pd->x,&pd->y);
566 
567 			underried = add_to_list(underried,0,0,(void *)pd);
568 			}
569 		else if (numstreq(cp,"DERRY ",6))
570 			{
571 			cp += 6;
572 
573 			/* add to list of host derries */
574 			pd = (PDerry *)malloc(sizeof(PDerry));
575 
576 			pd->ob = ob;
577 			while (*cp!=' ')
578 				pd->tag[ci++] = *(cp++);
579 			pd->tag[ci]='\0';
580 			sscanf(cp,"%ld %ld",&pd->x,&pd->y);
581 
582 			pderries = add_to_list(pderries,0,0,(void *)pd);
583 			};
584 
585 		get_whole_line();
586 		};
587 }
588 
589 Object *
parse_arc_ellipse()590 parse_arc_ellipse()
591 {
592 	Object *ob;
593 	Boolean farrow,barrow;
594 	char fooch=0;
595 	long x1,y1,x2,y2,x3,y3;
596 	double theta1,phi1,theta2,phi2,theta3,phi3;
597 
598 	ob = (Object *)malloc(sizeof(Object));
599 
600 	ob->type = ARCELLIPSE;
601 	ob->ticket = ob_ticket++;
602 	ob->derries = NULL;
603 	ob->ob.arcellipse.open = get_arc_open();
604 	ob->ls = get_line_style();
605 	ob->lw = get_int();
606 	ob->colour = get_fcolour();
607 	ob->fillcolour = get_fill_fcolour();
608 	ob->depth = get_depth();
609 	get_int(); /* pen_style, not used  */
610 	ob->fs = get_fillstyle(ob);
611 	get_double(); /* dash and dot, don't care  */
612 	ob->es = get_capstyle();
613 	ob->js = JoinRound; /* irrelevant  */
614 	get_int();  /* direction ...  */
615 	farrow = get_int();
616 	barrow = get_int();
617 	ob->ob.arcellipse.centre.x = (long)get_double();
618 	ob->ob.arcellipse.centre.y = (long)get_double();
619 	ob->ob.arcellipse.xradius = 1;
620 	ob->ob.arcellipse.yradius = 1;
621 	/* now xfig format gives three points on the circle. the first and last are
622 		end points of the arc, the middle point is for specifying the sweep direction
623 		*/
624 	x1 = get_int() - ob->ob.arcellipse.centre.x; y1 = get_int() - ob->ob.arcellipse.centre.y;
625 	x2 = get_int() - ob->ob.arcellipse.centre.x; y2 = get_int() - ob->ob.arcellipse.centre.y;
626 	x3 = get_int() - ob->ob.arcellipse.centre.x; y3 = get_int() - ob->ob.arcellipse.centre.y;
627 
628  	/* determine the correct start and end angles  */
629 	theta1 = atan2(((double)-y1),((double)x1));
630 	phi1 = atan(((double)-y1)/((double)x1));
631 	if (cosround(phi1)!=0)
632 		ob->ob.arcellipse.xradius = abs((long)(((double)x1)/cosround(phi1)));
633 	if (sinround(phi1)!=0)
634 		ob->ob.arcellipse.yradius = abs((long)(((double)-y1)/sinround(phi1)));
635 
636 	theta2 = atan2(((double)-y2),((double)x2));
637 	phi2 = atan(((double)-y2)/((double)x2));
638 	if (cosround(phi2)!=0)
639 		ob->ob.arcellipse.xradius = abs((long)(((double)x2)/cosround(phi2)));
640 	if (sinround(phi2)!=0)
641 		ob->ob.arcellipse.yradius = abs((long)(((double)-y2)/sinround(phi2)));
642 
643 	theta3 = atan2(((double)-y3),((double)x3));
644 	phi3 = atan(((double)-y3)/((double)x3));
645 	if (cosround(phi3)!=0)
646 		ob->ob.arcellipse.xradius = abs((long)(((double)x3)/cosround(phi3)));
647 	if (sinround(phi3)!=0)
648 		ob->ob.arcellipse.yradius = abs((long)(((double)-y3)/sinround(phi3)));
649 
650    while (theta1<0.0)
651 	   {
652 	   theta1+=2.0*PI;
653 		fooch=fooch | 1;
654 		};
655 
656    while (theta2<0.0)
657 	   {
658 	   theta2+=2.0*PI;
659 		};
660 
661    while (theta3<0.0)
662 	   {
663 	   theta3+=2.0*PI;
664 		fooch=fooch | 2;
665 		};
666 
667    if (!between(theta2,min(theta1,theta3),max(theta1,theta3)))
668 	   {
669 		switch(fooch)
670 			{
671 		   case(0):
672 			case(3):
673 				if (min(theta1,theta3)==theta1)
674 					theta1 += 2.0*PI;
675 				else
676 					theta3 += 2.0*PI;
677 				break;
678 			case(1): theta3+=2.0*PI; break;
679 			case(2): theta1+=2.0*PI; break;
680 			};
681 		};
682 
683 	ob->ob.arcellipse.start = (64.0*theta1*(180.0/PI));
684 	ob->ob.arcellipse.end = (64.0*theta3*(180.0/PI));
685 
686 	(farrow) ? (ob->farrow = parse_arrow()) : (ob->farrow = NULL);
687 	(barrow) ? (ob->barrow = parse_arrow()) : (ob->barrow = NULL);
688 
689 	ob->bbox.x1 = ob->ob.arcellipse.centre.x - ob->ob.arcellipse.xradius;
690 	ob->bbox.y1 = ob->ob.arcellipse.centre.y - ob->ob.arcellipse.yradius;
691 	ob->bbox.x2 = ob->ob.arcellipse.centre.x + ob->ob.arcellipse.xradius;
692 	ob->bbox.y2 = ob->ob.arcellipse.centre.y + ob->ob.arcellipse.yradius;
693 	ob->ob.arcellipse.centre.x -= ob->bbox.x1;
694 	ob->ob.arcellipse.centre.y -= ob->bbox.y1;
695 
696 	normalise_rectangle(&ob->bbox.x1, &ob->bbox.y1, &ob->bbox.x2, &ob->bbox.y2);
697 	ob->bbox.x2++;
698 	ob->bbox.y2++;
699 
700 	obs = add_to_list_neq(obs,ULONG_MAX-ob->depth,0,(void *)ob);
701 
702 	parse_vcomment(ob);
703 
704 	return ob;
705 }
706 
707 Object *
parse_compound(View * view)708 parse_compound(View *view)
709 {
710 	int i;
711 	Object *ob;
712 	Object *mob;
713 	List l=NULL,l2=NULL;
714 	unsigned long de;
715 
716 	ob = (Object *)malloc(sizeof(Object));
717 
718 	ob->type = COMPOUND;
719 	ob->ticket = ob_ticket++;
720 	ob->derries = NULL;
721 	ob->depth = ULONG_MAX;
722 	ob->ob.compound.obs = NULL;
723 	ob->farrow = NULL;
724 	ob->barrow = NULL;
725 	/* these are changed anyway, as they might be untrustworthy  */
726 	ob->bbox.x1 = get_int();
727 	ob->bbox.y1 = get_int();
728 	ob->bbox.x2 = get_int();
729 	ob->bbox.y2 = get_int();
730 	normalise_rectangle(&ob->bbox.x1, &ob->bbox.y1, &ob->bbox.x2, &ob->bbox.y2);
731 
732 	/* for each object, we parse it then immediately delete it
733 		from the document, to add to the compound. */
734 	while ((i = get_int())!=-6)
735 		{
736 		switch (i)
737 			{
738 			case 0: /* means broken fig file */
739 				parse_colour_object();
740 				break;
741 
742 			case 5:
743 				mob = parse_arc_ellipse();
744 				obs = delete_from_list_v(obs,(void *)mob);
745 				ob->bbox = merge_boxes(mob->bbox,ob->bbox);
746 				if (mob->depth<ob->depth)
747 					ob->depth = mob->depth-1;
748 				l = add_to_list_neq(l,ULONG_MAX-mob->depth,0,(void *)mob);
749 				break;
750 
751 			case 1:
752 				mob = parse_ellipse();
753 				ob->bbox = merge_boxes(mob->bbox,ob->bbox);
754 				obs = delete_from_list_v(obs,(void *)mob);
755 				if (mob->depth<ob->depth)
756 					ob->depth = mob->depth-1;
757 				l = add_to_list_neq(l,ULONG_MAX-mob->depth,0,(void *)mob);
758 				break;
759 
760 			case 2:
761 				mob = parse_polyline();
762 				ob->bbox = merge_boxes(mob->bbox,ob->bbox);
763 				obs = delete_from_list_v(obs,(void *)mob);
764 				if (mob->depth<ob->depth)
765 					ob->depth = mob->depth-1;
766 				l = add_to_list_neq(l,ULONG_MAX-mob->depth,0,(void *)mob);
767 				break;
768 
769 			case 3:
770 				mob = parse_spline();
771 				ob->bbox = merge_boxes(mob->bbox,ob->bbox);
772 				obs = delete_from_list_v(obs,(void *)mob);
773 				if (mob->depth<ob->depth)
774 					ob->depth = mob->depth-1;
775 				l = add_to_list_neq(l,ULONG_MAX-mob->depth,0,(void *)mob);
776 				break;
777 
778 			case 4:
779 				mob = parse_text(view);
780 				/* could cop out */
781 				if (!mob)
782 					break;
783 				ob->bbox = merge_boxes(mob->bbox,ob->bbox);
784 				obs = delete_from_list_v(obs,(void *)mob);
785 				if (mob->depth<ob->depth)
786 					ob->depth = mob->depth-1;
787 				l = add_to_list_neq(l,ULONG_MAX-mob->depth,0,(void *)mob);
788 				break;
789 
790 			case 6:
791 				mob = parse_compound(view);
792 				ob->bbox = merge_boxes(mob->bbox,ob->bbox);
793 				obs = delete_from_list_v(obs,(void *)mob);
794 				/* DON'T change depth for compounds-in-compounds (it's
795 				   meaningless). With all this we get sensible greenpig.fig
796 				   AND transit.fig :) */
797 				l = add_to_list_neq(l,ULONG_MAX-mob->depth,0,(void *)mob);
798 				break;
799 			};
800 		};
801 
802  	/* recalculate the depths  */
803  	de = ob_depth--;
804 	l2=l;
805 	while (l2!=NULL)
806 		{
807 		OB(l2)->depth = de--;
808 		ob->ob.compound.obs = add_to_list(ob->ob.compound.obs,ULONG_MAX-OB(l2)->depth,0,(void *)OB(l2));
809 		l2=l2->next;
810 		};
811 	delete_list(l);
812 
813 	obs = add_to_list_neq(obs,ULONG_MAX-ob->depth,0,(void *)ob);
814  	return ob;
815 }
816 
817 Object *
parse_ellipse()818 parse_ellipse()
819 {
820 	Object *ob;
821 
822 	ob = (Object *)malloc(sizeof(Object));
823 
824 	ob->type = ELLIPSE;
825 	ob->ticket = ob_ticket++;
826 	ob->derries = NULL;
827 	get_int(); /* don't care about subtype  */
828 	ob->ls = get_line_style();
829 	ob->lw = get_int();
830 	ob->colour = get_fcolour();
831 	ob->fillcolour = get_fill_fcolour();
832 	ob->depth = get_depth();
833 	get_int(); /* pen style, not used  */
834 	ob->fs = get_fillstyle(ob);
835 	get_double(); /* dash dot  */
836 	get_int(); /* direction always 1  */
837 	get_double(); /* this is rotation angle which we can't handle  */
838 	ob->farrow = NULL;
839 	ob->barrow = NULL;
840 	ob->ob.ellipse.centre.x = get_int();
841 	ob->ob.ellipse.centre.y = get_int();
842 	ob->ob.ellipse.xradius = get_int();
843 	ob->ob.ellipse.yradius = get_int();
844 	get_int(); get_int(); /* points entered  */
845 	get_int(); get_int();
846 	ob->bbox.x1 = ob->ob.ellipse.centre.x - ob->ob.ellipse.xradius;
847 	ob->bbox.y1 = ob->ob.ellipse.centre.y - ob->ob.ellipse.yradius;
848 	ob->bbox.x2 = ob->ob.ellipse.centre.x + ob->ob.ellipse.xradius;
849 	ob->bbox.y2 = ob->ob.ellipse.centre.y + ob->ob.ellipse.yradius;
850 	ob->ob.ellipse.centre.x -= ob->bbox.x1;
851 	ob->ob.ellipse.centre.y -= ob->bbox.y1;
852    normalise_rectangle(&ob->bbox.x1, &ob->bbox.y1, &ob->bbox.x2, &ob->bbox.y2);
853 
854 	obs = add_to_list_neq(obs,ULONG_MAX-ob->depth,0,(void *)ob);
855 
856    parse_vcomment(ob);
857 
858 	return ob;
859 }
860 
861 Object *
parse_polyline()862 parse_polyline()
863 {
864 	Object *ob;
865 	int subtype;
866 	Boolean farrow,barrow;
867 	int num;
868 	int radius;
869 	char *s;
870 	uint c=0;
871 	List l=NULL;
872 
873 	ob = (Object *)malloc(sizeof(Object));
874 
875 	subtype = get_int();
876 
877 	ob->ticket = ob_ticket++;
878 	ob->derries = NULL;
879 	ob->ls = get_line_style();
880 	ob->lw = get_int();
881 	ob->colour = get_fcolour();
882 	ob->fillcolour = get_fill_fcolour();
883 	ob->depth = get_depth();
884 	get_int(); /* pen_style  */
885 	ob->fs = get_fillstyle(ob);
886 	get_double(); /* dash dot  */
887 	ob->js = get_joinstyle();
888 	ob->es = get_capstyle();
889 	radius = get_int();
890 	farrow = get_int();
891 	barrow = get_int();
892 	num = get_int();
893 
894 	(farrow) ? (ob->farrow = parse_arrow()) : (ob->farrow = NULL);
895 	(barrow) ? (ob->barrow = parse_arrow()) : (ob->barrow = NULL);
896 
897 	/* use this temporarily for use in recalc_polyline_bbox  */
898 	ob->ob.polyline.points=NULL;
899 	/* need initial bbox */
900 	ob->bbox.x1 = 0;
901 	ob->bbox.y1 = 0;
902 	ob->bbox.x2 = 10;
903 	ob->bbox.y2 = 10;
904 
905 	if (subtype==5)
906 		{
907 		get_int();
908 		s = (char *)malloc(strlen(cp)+1);
909 		strcpy(s,cp);
910 		ob->ob.polyline.pic = s;
911 		get_whole_line();
912 		}
913 	else
914 		ob->ob.polyline.pic = NULL;
915 
916 	while (num>0)
917 		{
918 		ob->ob.polyline.points = add_to_list(ob->ob.polyline.points,c,0,(void *)parse_point(ob));
919 		c++;
920 		num--;
921 		};
922 
923 	recalc_polyline_bbox(ob,FALSE);
924 
925 	switch (subtype)
926 		{
927 		case 1: /* polyline  */
928 			if (ob->fs!=NONE)
929 				ob->type = POLYGON;
930 			else
931 				ob->type = POLYLINE;
932 			break;
933 
934 		case 5: /* imported pic bbox  */
935 			ob->type = POLYGON;
936 			break;
937 
938 		case 2: /* rectangle  */
939 		case 3: /* polygon */
940 			ob->type = POLYGON;
941 			/* remove last point coincident with first */
942 			l = ob->ob.polyline.points;
943 			while (l->next!=NULL)
944 				l = l->next;
945 			if (l->prev!=NULL)
946 				l->prev->next = NULL;
947 			free(POINT(l));
948 			free(l);
949 			break;
950 
951 		case 4: /* roundbox  */
952 			ob->type = ROUNDBOX;
953 			/* remove list, not used  */
954 			l = ob->ob.polyline.points;
955 			while (l!=NULL)
956 				{
957 				free (POINT(l));
958 				l = l->next;
959 				};
960 			delete_list(ob->ob.polyline.points);
961 			/* now use it as roundbox  */
962 			ob->ob.roundbox.radius = radius;
963 			break;
964 		};
965 
966 	obs = add_to_list_neq(obs,ULONG_MAX-ob->depth,0,(void *)ob);
967 
968 	parse_vcomment(ob);
969 
970 	return ob;
971 }
972 
973 Object *
parse_spline()974 parse_spline()
975 {
976 	Object *ob;
977 	Boolean farrow,barrow;
978 	int subtype;
979 	int num;
980 	uint c=0;
981 	List l=NULL;
982 
983 	ob = (Object *)malloc(sizeof(Object));
984 
985 	ob->type = SPLINE;
986 	ob->ticket = ob_ticket++;
987 	ob->derries = NULL;
988 	subtype = get_int();
989 	switch(subtype)
990 		{
991 		case 1:
992 		case 3:
993 		case 5:
994 			ob->ob.spline.closed = TRUE;
995 			break;
996 
997 		default:
998 			ob->ob.spline.closed = FALSE;
999 		};
1000 
1001 	ob->ls = get_line_style();
1002 	ob->lw = get_int();
1003 	ob->colour = get_fcolour();
1004 	ob->fillcolour = get_fill_fcolour();
1005 	ob->depth = get_depth();
1006 	get_int(); /* pen_style  */
1007 	ob->fs = get_fillstyle(ob);
1008 	get_double(); /* dash dot  */
1009 	ob->js = JoinRound;
1010 	ob->es = get_capstyle();
1011 	farrow = get_int();
1012 	barrow = get_int();
1013 	num = get_int();
1014 
1015 	(farrow) ? (ob->farrow = parse_arrow()) : (ob->farrow = NULL);
1016 	(barrow) ? (ob->barrow = parse_arrow()) : (ob->barrow = NULL);
1017 
1018 	/* need initial bbox */
1019 	ob->bbox.x1 = 0;
1020 	ob->bbox.y1 = 0;
1021 	ob->bbox.x2 = 10;
1022 	ob->bbox.y2 = 10;
1023 	ob->ob.spline.cache = NULL;
1024 	ob->ob.spline.points = NULL;
1025 
1026 	while (num>0)
1027 		{
1028 		ob->ob.spline.points = add_to_list(ob->ob.spline.points,c,0,(void *)parse_spoint(ob));
1029 		c++;
1030 		num--;
1031 		};
1032 
1033 	l = ob->ob.spline.points;
1034 
1035 	/* get our shape factors  */
1036 	while (l!=NULL)
1037 		{
1038 		SPOINT(l)->s = get_double();
1039 		l = l->next;
1040 		};
1041 
1042 
1043 	/* fill the cache  */
1044 	ob->ob.spline.cache = compute_spline_segment(ob->ob.spline.points,ob->ob.spline.closed);
1045 	recalc_polyline_bbox(ob,TRUE);
1046 
1047 	obs = add_to_list_neq(obs,ULONG_MAX-ob->depth,0,(void *)ob);
1048 
1049 	parse_vcomment(ob);
1050 	return ob;
1051 }
1052 
1053 Object *
parse_text(View * view)1054 parse_text(View *view)
1055 {
1056 	Object *ob;
1057 	TextLine *tl;
1058 	TextSection *ts=NULL;
1059 	int fontnum;
1060 	int fontsize;
1061 	int charpos = 0;
1062 	long w,h;
1063 	long x,y;
1064 	uint is=0;
1065 	Boolean more=TRUE;
1066 	VFont *vf;
1067 	char str[MLINE];
1068 
1069 	ob = (Object *)malloc(sizeof(Object));
1070 	ob->type = TEXT;
1071 	ob->ticket = ob_ticket++;
1072 	ob->derries = NULL;
1073 
1074 	ob->ob.text.node = FALSE;
1075 	ob->ob.text.ellipse = FALSE;
1076 
1077 	ob->farrow = NULL;
1078 	ob->barrow = NULL;
1079 	ob->ob.text.lines = NULL;
1080 	tl = (TextLine *)malloc(sizeof(TextLine));
1081 	tl->y = 0;
1082 	tl->h = 0;
1083 	tl->sections = NULL;
1084 	ob->ob.text.lines = add_to_list(ob->ob.text.lines,0,0,(void *)tl);
1085 
1086 	switch (get_int())
1087 		{
1088 		case 1: tl->just = CENTRE; break;
1089 		case 2: tl->just = RIGHT; break;
1090 		default: tl->just = LEFT; break;
1091 		};
1092 
1093 	ob->colour = get_fcolour();
1094 	ob->depth = get_depth();
1095 	ob->ls = 0;
1096 	ob->fs = 0;
1097 	ob->es = CapButt;
1098 	ob->lw = 0;
1099 	ob->js = JoinRound;
1100 	get_int(); /* pen_style  */
1101 	fontnum = get_int();
1102 	if (fontnum==-1) /* default ps */
1103 		fontnum++;
1104 	fontsize = (int)get_double();
1105 	ob->ob.text.angle = get_double();
1106 	ob->ob.text.angle = flip_angle_y(ob->ob.text.angle);
1107 	if (!(4 & get_int())) /* latex font  */
1108 		{
1109 		if (fontnum==0) /* default latex  */
1110 			fontnum = 35;
1111 		else
1112 			fontnum += 34;
1113 		};
1114 
1115 	h = (long)get_double();
1116 	w = (long)get_double();
1117 	x = get_int();
1118 	y = get_int();
1119 
1120 	ob->ob.text.bbox.x1 = x;
1121 	ob->ob.text.bbox.y1 = y;
1122 
1123 	/* pick out characters delimited by \001  */
1124 	while (more)
1125 		{
1126 		if (*cp=='\0')
1127 			{
1128 			fgets(str,MLINE,fl);
1129 			cp = &str[0];
1130 			};
1131 
1132 		if (*cp=='\n')
1133 			{
1134 			fgets(str,MLINE,fl);
1135 			cp = &str[0];
1136 			};
1137 
1138 		if (ts==NULL || strlen(ts->text)==18)
1139 			{
1140 			TextSection *tsp;
1141 
1142 			tsp = (TextSection *)malloc(sizeof(TextSection));
1143 			tsp->x = 0;
1144 			tsp->w = 10;
1145 			tsp->isReturn = FALSE;
1146 			tsp->num = fontnum;
1147 			tsp->size = fontsize;
1148 
1149 			charpos = 0;
1150 			tl->sections = add_to_list(tl->sections,is,0,(void *)tsp);
1151 			is++;
1152 			ts = tsp;
1153 			};
1154 
1155 	 	if (*cp != '\\')
1156 			{
1157 			ts->text[charpos] = *cp;
1158 			ts->text[++charpos]='\0';
1159 			}
1160 		else
1161 			{
1162 			cp++;
1163 
1164 			if (*cp!='\\') /* ie octal code  */
1165 				{
1166 				char a[10];
1167 				int i;
1168 
1169 				a[0] = *cp;
1170 				cp++;
1171 				a[1] = *cp;
1172 				cp++;
1173 				a[2] = *cp;
1174 				a[3] = '\0';
1175 
1176 				if (streq("001",a)) /* finish */
1177 					more = FALSE;
1178 				else
1179 					{
1180 					sscanf(a,"%o", &i);
1181 
1182 					ts->text[charpos] = (unsigned char)i;
1183 					ts->text[++charpos] = '\0';
1184 					};
1185 				}
1186 			else /* escaped backslash */
1187 				{
1188 				ts->text[charpos] = '\\';
1189 				ts->text[++charpos]='\0';
1190 				};
1191 			};
1192 
1193 		cp++;
1194 		};
1195 
1196 	ts->text[charpos] = '\0';
1197 
1198 	/* calculate the text box  */
1199 	recalc_text_box(view,ob, FALSE, TRUE);
1200 
1201 	/* we need to subtract the .ascent  */
1202 	/* if the text if rotated, the .ascent subtraction
1203 		needs to be as well */
1204 	vf = get_font(fontnum,ZPO(fontsize,view));
1205 	if (vf==NULL)
1206 		{
1207 		List l,l2;
1208 
1209 		l = ob->ob.text.lines;
1210 		while (l!=NULL)
1211 			{
1212 			l2 = TEXTLINE(l)->sections;
1213 			while (l2!=NULL)
1214 				{
1215 				free(TEXTSEC(l2));
1216 				l2=l2->next;
1217 				};
1218 			delete_list(TEXTLINE(l)->sections);
1219 			free(TEXTLINE(l));
1220 			l=l->next;
1221 			};
1222 		delete_list(ob->ob.text.lines);
1223 		free(ob);
1224 		return NULL;
1225 		};
1226 
1227 	if (ob->ob.text.angle)
1228 		{
1229 		double sina,cosa;
1230 		long cx,cy;
1231 		long ox,oy;
1232 
1233 		sina=sinround(ob->ob.text.angle);
1234 		cosa=cosround(ob->ob.text.angle);
1235 		cx = (ob->ob.text.bbox.x2-ob->ob.text.bbox.x1)/2;
1236 		cy = (ob->ob.text.bbox.y2-ob->ob.text.bbox.y1)/2;
1237 
1238 		if (tl->just==CENTRE)
1239 			ox = (ob->ob.text.bbox.x2-ob->ob.text.bbox.x1)/2;
1240 		else if (tl->just==RIGHT)
1241 			ox = ob->ob.text.bbox.x2-ob->ob.text.bbox.x1;
1242 		else
1243 			ox = 0;
1244 
1245 		oy = P2D(vf->x->max_bounds.ascent,view);
1246 
1247  		ob->ob.text.bbox.x1 -= cx + cosa*(ox-cx)-sina*(oy-cy);
1248 		ob->ob.text.bbox.y1 -= cy + sina*(ox-cx)+cosa*(oy-cy);
1249 
1250 		}
1251 	else
1252 		{
1253 		if (tl->just==CENTRE)
1254 			{
1255 			long dx;
1256 			dx = (ob->ob.text.bbox.x2-ob->ob.text.bbox.x1)/2;
1257 			ob->ob.text.bbox.x1 -= dx;
1258 			ob->ob.text.bbox.x2 -= dx;
1259 			}
1260 		else if (tl->just==RIGHT)
1261 			{
1262 			long dx;
1263 			dx = ob->ob.text.bbox.x2-ob->ob.text.bbox.x1;
1264 			ob->ob.text.bbox.x1 -= dx;
1265 			ob->ob.text.bbox.x2 -= dx;
1266 			};
1267 
1268 		ob->ob.text.bbox.y1 -= P2D(vf->x->max_bounds.ascent,view);
1269 		};
1270 
1271 	recalc_text_box(view,ob, FALSE, TRUE);
1272 
1273 	obs = add_to_list_neq(obs,ULONG_MAX-ob->depth,0,(void *)ob);
1274 	return ob;
1275 }
1276 
1277 void
load(char * file,Boolean cmdline)1278 load(char *file,Boolean cmdline)
1279 {
1280 	char s[FIGURINE_PATH_MAX];
1281 	int c=strlen(file);
1282 
1283 	Document *d;
1284 	d = new_doc(FALSE);
1285 
1286 	strcpy(s,file);
1287 	while (strlen(s) && s[strlen(s)-1]!='/')
1288 		{
1289 		s[strlen(s)-1] = '\0';
1290 		c--;
1291 		};
1292 
1293 	if (streq("",s))
1294 		strcpy(d->pathname,state.cwd);
1295 	else
1296 		strcpy(d->pathname,s);
1297 
1298 	strcpy(d->filename,file+c);
1299 	new_view0(d);
1300 
1301 	insert_file(d,file,TRUE,cmdline);
1302 }
1303 
insert_file(Document * d,char * file,Boolean isload,Boolean cmdline)1304 void insert_file(Document *d, char *file,Boolean isload,Boolean cmdline)
1305 {
1306 	static char s[MLINE];
1307 	char *c;
1308 	List l,l2,l3;
1309 	unsigned long de;
1310 	Derry *der;
1311 
1312 	fl = fopen(file,"r");
1313 
1314 	doc = d;
1315 
1316 	c = &file[strlen(file)];
1317 	while (*(c-1)!='/' && c>file)
1318 		c--;
1319 
1320 	if (isload)
1321 		{
1322 		strcpy(doc->filename,c);
1323 		if (c==file)
1324 			strcpy(doc->pathname,state.cwd);
1325 		else
1326 			{
1327 			strncpy(doc->pathname,file,(uint)(c-file));
1328 			doc->pathname[c-file] = '\0';
1329 			};
1330 		};
1331 
1332 	if (fl==NULL)
1333 		{
1334 		if (cmdline)
1335 			{
1336 			/* specifically requested on cmdline, open new document  */
1337 			XMapWindow(display,VIEW(doc->views)->window.win);
1338 			switch_icons(VIEW(doc->views));
1339 			return;
1340 			};
1341 		strcpy(s,"File ");
1342 		strncat(s,file,MLINE);
1343 		strcat(s," could not be read.");
1344 		stk_open_info(s);
1345 		if (isload)
1346 			{
1347 			really_close_view(VIEW(doc->views));
1348 			docs = delete_from_list_v(docs,(void *)doc);
1349 			free(doc);
1350 			};
1351 		return;
1352 		};
1353 
1354 	/* first line should be #FIG 3.2  */
1355 	fgets(s,MLINE,fl);
1356 	s[8] = '\0';
1357 	if (!streq(s,"#FIG 3.2"))
1358 		{
1359 		strcpy(s,"File ");
1360 		strncat(s,file,MLINE);
1361 		strcat(s," is not a FIG 3.2 file");
1362 		stk_open_info(s);
1363 		if (isload)
1364 			{
1365 			really_close_view(VIEW(doc->views));
1366 			docs = delete_from_list_v(docs,(void *)doc);
1367 			free(doc);
1368 			};
1369 		fclose(fl);
1370 		return;
1371   		};
1372 
1373 	get_whole_line();
1374 	if (isload)
1375 		{
1376 		string_eq("Landscape") ? (doc->landscape=TRUE) : (doc->landscape=FALSE);
1377 		string_eq("Center") ? (doc->centred=TRUE) : (doc->centred=FALSE);
1378 		string_eq("Metric") ? (in_mm=TRUE) : (in_mm=FALSE);
1379 		parse_papersize();
1380 		}
1381 	else
1382 		{
1383 		get_whole_line();
1384 		get_whole_line();
1385 		get_whole_line();
1386 		};
1387 
1388 	get_whole_line();
1389 	if (isload)
1390 		doc->magnify = get_double();
1391 	else
1392 		get_double();
1393 	get_whole_line();
1394 	if (isload)
1395 		{
1396 		string_eq("Multiple") ? (doc->mpage=TRUE) : (doc->mpage=FALSE);
1397 		doc->transcolour = get_int();
1398 		doc->ppi = get_int();
1399 		}
1400 	else
1401 		{
1402 		get_whole_line();
1403 		get_int();
1404 		get_int();
1405 		};
1406 
1407 	get_int(); /* second val on line is ignored here */
1408 
1409 	obs = NULL;
1410 
1411 	/* objects now */
1412 
1413 	while (!feof(fl))
1414 		{
1415 		switch (get_int())
1416 			{
1417 			case 0: parse_colour_object(); break;
1418 			case 5: parse_arc_ellipse(); break;
1419 			case 1: parse_ellipse(); break;
1420 			case 2: parse_polyline(); break;
1421 			case 3: parse_spline(); break;
1422 			case 4: parse_text(VIEW(doc->views)); break;
1423 			case 6: parse_compound(VIEW(doc->views)); break;
1424 			default: break;
1425 			};
1426 		};
1427 
1428 	de = ULONG_MAX;
1429 	l = obs;
1430 	while (l!=NULL)
1431 		{
1432 		OB(l)->depth = de--;
1433 		doc->o = add_object(doc->o, &doc->lo, OB(l));
1434 		l=l->next;
1435 		};
1436 
1437 	doc->ob_depth = de;
1438 
1439 	if (isload)
1440 		{
1441 		/* open the view window of loaded file  */
1442 		XMapWindow(display,VIEW(doc->views)->window.win);
1443 		switch_icons(VIEW(doc->views));
1444 		};
1445 	delete_list(obs);
1446 	doc = NULL;
1447 	fclose(fl);
1448 
1449 	/* now run through the derries list and match them up  */
1450 
1451 	l=pderries;
1452 
1453 	while (l!=NULL)
1454 		{
1455 		l2=underried;
1456 		while (l2!=NULL)
1457 			{
1458 			if (streq(PDERRY(l)->tag,PDERRY(l2)->tag) &&
1459 			    PDERRY(l)->x == PDERRY(l2)->x &&
1460 				 PDERRY(l)->y == PDERRY(l2)->y)
1461 				{
1462 				/* match: PDERRY(l)->ob is host, PDERRY(l2)->ob is source  */
1463 				der = (Derry *)malloc(sizeof(Derry));
1464 				der->ticket = PDERRY(l2)->ob->ticket;
1465 
1466 				if (PDERRY(l2)->ob->type==SPLINE || PDERRY(l2)->ob->type==ARC)
1467 					l3 = PDERRY(l2)->ob->ob.spline.points;
1468 				else
1469 					l3 = PDERRY(l2)->ob->ob.polyline.points;
1470 
1471 				while (l3!=NULL)
1472 					{
1473 					if (POINT(l3)->x+PDERRY(l2)->ob->bbox.x1==PDERRY(l)->x &&
1474 						 POINT(l3)->y+PDERRY(l2)->ob->bbox.y1==PDERRY(l)->y)
1475 						{
1476 						/* found the matching point */
1477 						POINT(l3)->derried=TRUE;
1478 						der->point = POINT(l3);
1479 						break;
1480 						};
1481 					l3=l3->next;
1482 					};
1483 
1484 				PDERRY(l)->ob->derries = add_to_list(PDERRY(l)->ob->derries,der->ticket,0,(void *)der);
1485 				break;
1486 				};
1487 
1488 			l2=l2->next;
1489 			};
1490 		l=l->next;
1491 		};
1492 
1493 	l=pderries;
1494 	while (l!=NULL)
1495 		{
1496 		free(l->data);
1497 		l=l->next;
1498 		};
1499 
1500 	l=underried;
1501 	while (l!=NULL)
1502 		{
1503 		free(l->data);
1504 		l=l->next;
1505 		};
1506 
1507 	delete_list(pderries);
1508 	delete_list(underried);
1509 	pderries=NULL;
1510 	underried=NULL;
1511 }
1512