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