1 /*
2  * FIG : Facility for Interactive Generation of figures
3  * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4  * Parts Copyright (c) 1989-2015 by Brian V. Smith
5  * Parts Copyright (c) 1991 by Paul King
6  * Parts Copyright (c) 2016-2020 by Thomas Loimer
7  *
8  * Any party obtaining a copy of these files is granted, free of charge, a
9  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10  * nonexclusive right and license to deal in this software and documentation
11  * files (the "Software"), including without limitation the rights to use,
12  * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
13  * the Software, and to permit persons who receive copies from any such
14  * party to do so, with the only requirement being that the above copyright
15  * and this permission notice remain intact.
16  *
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 #include "f_read.h"
23 
24 #include <ctype.h>		/* isdigit() */
25 #include <errno.h>
26 #include <limits.h>		/* PATH_MAX */
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #ifdef HAVE_STRINGS_H
31 #include <strings.h>
32 #endif
33 #ifdef I18N
34 #include <locale.h>
35 #endif
36 
37 #include "resources.h"
38 #include "object.h"
39 #include "mode.h"
40 
41 #include "d_spline.h"
42 #include "e_update.h"
43 #include "f_picobj.h"
44 #include "f_util.h"
45 #include "u_bound.h"
46 #include "u_create.h"
47 #include "u_fonts.h"
48 #include "u_free.h"
49 #include "u_scale.h"
50 #include "u_translate.h"
51 #include "w_canvas.h"
52 #include "w_color.h"
53 #include "w_drawprim.h"
54 #include "w_file.h"
55 #include "w_layers.h"
56 #include "w_msgpanel.h"
57 #include "w_setup.h"
58 #include "w_util.h"
59 #include "w_zoom.h"
60 
61 #include "xfig_math.h"
62 
63 extern int	read_1_3_objects(FILE *fp, char *buf, F_compound *obj,
64 				int *resolution);	/* f_readold.c */
65 
66 /* EXPORTS */
67 
68 int	defer_update_layers = 0; /* if != 0, update_layers() doesn't update */
69 void	fix_angle (float *angle);
70 int	line_no, save_line;	/* current input line number */
71 int	num_object;		/* current number of objects */
72 char	*read_file_name;	/* current input file name */
73 void	swap_colors (void);
74 
75 /* LOCAL */
76 
77 static char	Err_incomp[] = "Incomplete %s object at line %d.";
78 
79 static void        read_colordef(void);
80 static F_ellipse  *read_ellipseobject(void);
81 static F_line     *read_lineobject(FILE *fp);
82 static F_text     *read_textobject(FILE *fp);
83 static F_spline   *read_splineobject(FILE *fp);
84 static F_arc      *read_arcobject(FILE *fp);
85 static F_compound *read_compoundobject(FILE *fp);
86 static int	  save_comment(void);
87 static char	  *attach_comments(void);
88 static void	   count_lines_correctly(FILE *fp);
89 static int	   read_return(int status);
90 static Boolean	   contains_picture(F_compound *compound);
91 
92 #define FILL_CONVERT(f) \
93 	   ((proto >= 22) ? (f): \
94 	     (((proto>=20) || (f) == 0 || !TFX) ?  \
95 		(f-1) : (!TFX? (NUMFILLPATS-1) - ((f)-1)*5: UNFILLED)))
96 
97 
98 /* max number of comments that can be stored with each object */
99 #define MAXCOMMENTS	100
100 
101 /* input buffer length */
102 #define	BUF_SIZE	1024
103 
104 static char	buf[BUF_SIZE];		/* input buffer */
105 static char	*comments[MAXCOMMENTS];	/* comments saved for current object */
106 static int	numcom;			/* current comment index */
107 static Boolean	com_alloc = False;	/* whether or not the comment array
108 					   has been initialized */
109 static int	TFX;			/* true for 1.4TFX protocol */
110 static int	proto;			/* file protocol*10 */
111 static float	fproto, xfigproto;	/* floating values for protocol of
112 					   figure file and current protocol */
113 
114 /* initialize the user color counter - then read figure file.
115    Called from load_file(), merge_file(), preview_figure(), load_lib_obj(),
116    and paste(), but NOT from read_figure() (import Fig as picture) */
117 
118 static void	merge_colors (F_compound *objects);
119 static int	readfp_fig (FILE *fp, F_compound *obj, Boolean merge, int xoff,
120 				int yoff, fig_settings *settings);
121 static int	read_line (FILE *fp);
122 static int	read_objects (FILE *fp, F_compound *obj, int *res);
123 static void	scale_figure (F_compound *obj, float mul, int offset);
124 static void	shift_figure (F_compound *obj);
125 static void	fix_depth (int *depth);
126 static void	check_color (int *color);
127 static void	convert_arrow (int *type, float *wd, float *ht);
128 static void	skip_line (FILE *fp);
129 static int	backslash_count (char *cp, int start);
130 static void	renumber_comp (F_compound *compound);
131 static void	renumber (int *color);
132 
133 int
read_figc(char * file_name,F_compound * obj,Boolean merge,Boolean remapimages,int xoff,int yoff,fig_settings * settings)134 read_figc(char *file_name, F_compound *obj, Boolean merge, Boolean remapimages,
135 		int xoff, int yoff, fig_settings *settings)
136 {
137     int i,status;
138 
139     n_num_usr_cols = -1;
140     for (i=0; i<MAX_USR_COLS; i++)
141 	n_colorFree[i] = True;
142 
143     /* now read the file */
144     status = read_fig(file_name, obj, merge, xoff, yoff, settings);
145 
146     if (status != 0)
147 	return status;
148 
149     if (merge) {
150 	/* merge any user colors from the new file just read into the current figure */
151 	merge_colors(obj);
152     } else {
153 	/* now swap old figure colors with new colors (if any) */
154 	swap_colors();
155 	current_memory = -1;
156 	show_pencolor();
157 	show_fillcolor();
158     }
159 
160     /* and remap colors for all pictures */
161     /* but only if a picture object is in the new file */
162     if (remapimages && contains_picture(obj))
163 	remap_imagecolors();
164 
165     return status;
166 }
167 
168 static Boolean
contains_picture(F_compound * compound)169 contains_picture(F_compound *compound)
170 {
171     F_line	   *l;
172     F_compound	   *c;
173     /* traverse the compounds in this compound */
174     for (c = compound->compounds; c != NULL; c = c->next) {
175 	if (contains_picture(c))
176 	    return True;
177     }
178     for (l = compound->lines; l != NULL; l = l->next) {
179 	if (l->type == T_PICTURE)
180 	    return True;
181     }
182     return False;
183 }
184 
185 /**********************************************************
186 Read_fig returns :
187 
188            0 : successful read.
189   BAD_FORMAT : File is in incorrect format
190   EMPTY_FILE : File is empty
191   NO_VERSION : No version was found in "#FIG" header
192       err_no : if file can not be read for various reasons
193 		(from /usr/include/sys/errno.h)
194 
195 The resolution (ppi) is stored in resolution.
196 The coordinate system is 1 for lower left at 0,0 and
197 2 for upper left at 0,0, but this value is not used,
198 because xfig only uses 2 for the coordinate system.
199 
200 If "merge" is True, the user colors are merged into the color
201 set, else they replace the current user colors.
202 
203 Also, if merging, if the file being merged into the main figure
204 has different units (inches/cm) it is rescaled to match the
205 main figure.
206 
207 If update_figs is false, any imported images are read in, otherwise
208 they are not.  The latter case is used for the -update command-line
209 option where the user just wants to read and re-write Fig files
210 to bring them up-to-date.
211 **********************************************************/
212 
213 int
read_fig(char * file_name,F_compound * obj,Boolean merge,int xoff,int yoff,fig_settings * settings)214 read_fig(char *file_name, F_compound *obj, Boolean merge, int xoff, int yoff, fig_settings *settings)
215 {
216     FILE	   *fp;
217     int		    status;
218 
219     read_file_name = file_name;
220     first_file_msg = True;
221     if (uncompress_file(file_name) == False)
222 	return ENOENT;		/* doesn't exist */
223     if ((fp = fopen(file_name, "r")) == NULL)
224 	return errno;
225     else {
226 	if (!update_figs)
227 	    put_msg("Reading objects from \"%s\" ...", file_name);
228 #ifdef I18N
229 	/* set the numeric locale to C so we get decimal points for numbers */
230 	setlocale(LC_NUMERIC, "C");
231 #endif  /* I18N */
232 	status = readfp_fig(fp, obj, merge, xoff, yoff, settings);
233 #ifdef I18N
234 	/* reset to original locale */
235 	setlocale(LC_NUMERIC, "");
236 #endif  /* I18N */
237 	fclose(fp);
238 	/* so subsequent file_msg() calls don't print wrong file name */
239 	first_file_msg = False;
240 	return status;
241     }
242 }
243 
244 static int
readfp_fig(FILE * fp,F_compound * obj,Boolean merge,int xoff,int yoff,fig_settings * settings)245 readfp_fig(FILE *fp, F_compound *obj, Boolean merge, int xoff, int yoff, fig_settings *settings)
246 {
247     int		    status;
248     int		    i;
249     int		    resolution;
250     char	    versstring[10];
251 
252     defer_update_layers = 1;	/* prevent update_layers() from updating */
253 
254     /* initialize settings structure in case we read an older Fig format */
255     settings->landscape = appres.landscape;
256     settings->flushleft = appres.flushleft;
257     settings->units	= appres.INCHES;
258     settings->papersize	= appres.papersize;
259     settings->magnification = appres.magnification;
260     settings->multiple	= appres.multiple;
261     settings->transparent = appres.transparent;
262 
263     num_object = 0;
264     /* reset comment number */
265     numcom = 0;
266     /* initialize the comment array */
267     if (!com_alloc)
268 	for (i=0; i<MAXCOMMENTS; i++)
269 	    comments[i] = (char *) NULL;
270     com_alloc = True;
271     memset(obj, 0, COMOBJ_SIZE);
272     line_no = 1;
273     /* read the version header line (e.g. #FIG 3.2) */
274     if (fgets(buf, BUF_SIZE, fp) == 0)
275 	return read_return(EMPTY_FILE);
276     if (strncmp(buf, "#FIG", 4) == 0) {		/* versions 1.4/later have #FIG in first line */
277 	if (strlen(buf) <= 6) {
278 	    return read_return(NO_VERSION);	/* Short line - say corrupt */
279 	}
280 	if ((sscanf((char*)(strchr(buf, ' ') + 1), "%f", &fproto)) == 0)  /* assume 1.4 */
281 	    proto = 14;
282 	else
283 	    proto = (fproto + .01) * 10;	/* protocol version*10 */
284 
285 	/* if file protocol != current protocol, give message */
286 	strcpy(versstring, PROTOCOL_VERSION);	/* copy because gcc doesn't allow writing */
287 	sscanf(versstring,"%f",&xfigproto);	/* to const strings. sscanf does ungetc */
288 	if (fproto > xfigproto) {
289 	    file_msg("You must have a NEWER version of Xfig to load this figure (%.1f).",
290 			fproto);
291 	    return read_return(BAD_FORMAT);
292 	}
293 	/* Protocol 2.2 was only beta test - 3.0 is the release (and is identical) */
294 	if (proto == 22)
295 	    proto = 30;
296 
297 	TFX = False;
298 	if (strstr(buf, "TFX") != NULL)
299 	    TFX = True;
300 
301 	if (proto >= 30) {
302 	    /* read Portrait/Landscape indicator now */
303 	    if (read_line(fp) < 0) {
304 		file_msg("No Portrait/Landscape specification");
305 		return read_return(BAD_FORMAT);		/* error */
306 	    }
307 	    settings->landscape = (strncasecmp(buf,"landscape",9) == 0);
308 
309 	    /* read Centering indicator now */
310 	    if (read_line(fp) < 0) {
311 		file_msg("No Center/Flushleft specification");
312 		return read_return(BAD_FORMAT);		/* error */
313 	    }
314 	    if ((strncasecmp(buf,"center",6) == 0) ||
315 		(strncasecmp(buf,"flush",5) == 0)) {
316 		    /* use negative to ensure 1/0 (strcmp may return 3 or 4 for false) */
317 		    settings->flushleft = !strncasecmp(buf,"flush",5);
318 		    /* NOW read metric/inches indicator */
319 		    if (read_line(fp) < 0) {
320 			file_msg("No Metric/Inches specification");
321 			return read_return(BAD_FORMAT);		/* error */
322 		    }
323 	    }
324 	    /* set metric/inches mode appropriately */
325 	    settings->units = (strncasecmp(buf,"metric",5) != 0);
326 
327 	    /* paper size, magnification, multiple page flag and transparent color
328 	       (for GIF export) new in 3.2 */
329 	    if (proto >= 32) {
330 		/* read paper size now */
331 		if (read_line(fp) < 0) {
332 		    file_msg("No Paper size specification");
333 		    return read_return(BAD_FORMAT);		/* error */
334 		}
335 		/* parse the paper size */
336 		settings->papersize = parse_papersize(buf);
337 
338 		/* read magnification now */
339 		if (read_line(fp) < 0) {
340 		    file_msg("No Magnification specification");
341 		    return read_return(BAD_FORMAT);		/* error */
342 		}
343 		settings->magnification = atoi(buf);
344 		if (settings->magnification <= 0.) {
345 		    file_msg("Negative Magnification is not supported");
346 		    return read_return(BAD_FORMAT);
347 		}
348 
349 		/* read multiple page flag now */
350 		if (read_line(fp) < 0) {
351 		    file_msg("No Multiple page flag specification");
352 		    return read_return(BAD_FORMAT);		/* error */
353 		}
354 		if (strncasecmp(buf,"multiple",8) != 0 &&
355 		    strncasecmp(buf,"single",6) != 0) {
356 		    file_msg("No Multiple page flag specification");
357 		    return read_return(BAD_FORMAT);
358 		}
359 		settings->multiple = (strncasecmp(buf,"multiple",8) == 0);
360 
361 		/* read transparent color now */
362 		if (read_line(fp) < 0) {
363 		    file_msg("No Transparent color specification");
364 		    return read_return(BAD_FORMAT);		/* error */
365 		}
366 		settings->transparent = atoi(buf);
367 		if (settings->transparent < CANVAS_BG) { /* see object.h */
368 		    file_msg("Invalid transparent color specification");
369 		    return read_return(BAD_FORMAT);
370 		}
371 	    }
372 	}
373 	/* now read the figure itself */
374 	status = read_objects(fp, obj, &resolution);
375 
376     } else {
377 	file_msg("Seeing if this figure is Fig format 1.3");
378 	file_msg("If this doesn't work then this is not a Fig file.");
379 	proto = 13;
380 	status = read_1_3_objects(fp, buf, obj, &resolution);
381     }
382     /* don't go any further if there was an error in reading the figure */
383     if (status != 0) {
384 	return read_return(status);
385     }
386 
387     n_num_usr_cols++;	/* number of user colors = max index + 1 */
388     /***************************************************************************
389 	The older versions of xfig (1.3 to 2.1) used values that ended in 4 or 9
390 	for coordinates on the "grid".  When multiplied by 15 for the 3.0
391 	resolution these values ended up 14 "new" pixels off the grid.
392 
393 	For 3.0 files, 1 is added to the coordinates, and in addition, the USER
394 	is supposed to set the x and y offset in the file panel both to the
395 	amount necessary to correct the problem.
396 	For older files 1 is first added to coordinates then they are multiplied
397 	by 15.
398     ***************************************************************************/
399     /* See also doc/FORMAT3.0 */
400 
401     /* I do not see, where 1 is first added. */
402     if (proto == 30 || proto == 13) {
403 	    /* Fig 1.3 objects seem to lie on "nice" coordinates. */
404        scale_figure(obj,((float)PIX_PER_INCH)/resolution,0);
405     } else if (resolution != PIX_PER_INCH) {
406        if (proto == 21 && resolution == 76 && !settings->units)
407 	  scale_figure(obj,((float)PIX_PER_INCH)/80,15); /* for 2.1.8S, HWS */
408        else
409           scale_figure(obj,((float)PIX_PER_INCH)/resolution,15);
410     }
411 
412     /* if merging a figure with different units, rescale for mixed units, HWS */
413     if (merge && (proto >= 30)) {
414        if (!appres.INCHES && settings->units)
415 	   read_scale_compound(obj,(2.54*PIX_PER_CM)/((float)PIX_PER_INCH),0);
416        if (appres.INCHES && !settings->units)
417 	   read_scale_compound(obj,((float)PIX_PER_INCH)/(2.54*PIX_PER_CM),0);
418     }
419     /* if the user wants to scale the figure */
420     if (scale_factor != 1.0)
421 	read_scale_compound(obj, scale_factor, 0);
422 
423     /* shift the figure by the amount in the x and y offsets from the file panel */
424     translate_compound(obj, xoff, yoff);
425 
426     /* get bounding box of whole figure */
427     compound_bound(obj,&obj->nwcorner.x,&obj->nwcorner.y,&obj->secorner.x,&obj->secorner.y);
428 
429     /* ask the user if the figure should be shifted
430        if there are negative coords */
431     if (!update_figs) {
432 	shift_figure(obj);
433 
434 	/* now update the grid/ruler units */
435 	if (settings->units) {
436 	    /* inches */
437 	    if (strcasecmp(appres.tgrid_unit, "default") != 0) {
438 		/* the user specified a units when he started, try to keep it */
439 		if (strcasecmp(appres.tgrid_unit, "tenth") == 0 ||
440 			strcasecmp(appres.tgrid_unit, "ten") == 0 ||
441 			strcasecmp(appres.tgrid_unit, "1/10") == 0 ||
442 			strcasecmp(appres.tgrid_unit, "10") == 0)
443 		    settings->grid_unit = TENTH_UNIT;
444 		else
445 		    settings->grid_unit = FRACT_UNIT;
446 	    } else {
447 		settings->grid_unit = FRACT_UNIT;
448 	    }
449 	} else {
450 	    /* metric, only choice */
451 	    settings->grid_unit = MM_UNIT;
452 	}
453     } /* !update_figs */
454 
455     /* return with status */
456     return read_return(status);
457     }
458 
459 /* clear defer_update_layers counter, update the layer buttons and return status */
460 
461 static int
read_return(int status)462 read_return(int status)
463 {
464     defer_update_layers = 0;
465     if (!update_figs)
466 	update_layers();
467     return status;
468 }
469 
470 static int
read_objects(FILE * fp,F_compound * obj,int * res)471 read_objects(FILE *fp, F_compound *obj, int *res)
472 {
473     F_ellipse	   *e, *le = NULL;
474     F_line	   *l, *ll = NULL;
475     F_text	   *t, *lt = NULL;
476     F_spline	   *s, *ls = NULL;
477     F_arc	   *a, *la = NULL;
478     F_compound	   *c, *lc = NULL;
479     int		    object, ppi, coord_sys;
480 
481     if (read_line(fp) < 0) {
482 	file_msg("No Resolution specification; figure is empty");
483 	return BAD_FORMAT;
484     }
485 
486     /* read the resolution (ppi) and the coordinate system used (upper-left or lower-left) */
487     if (sscanf(buf, "%d%d\n", &ppi, &coord_sys) != 2) {
488 	file_msg("Figure resolution or coordinate specifier missing in line %d.", line_no);
489 	return BAD_FORMAT;
490     }
491 
492     if (ppi <= 0.) {
493 	file_msg("Negative figure resolution (%g) is not supported in line %d.",
494 			ppi, line_no);
495 	return BAD_FORMAT;
496     }
497 
498     /* attach any comments found thus far to the whole figure */
499     obj->comments = attach_comments();
500 
501     /* save the resolution for caller */
502     *res = ppi;
503 
504     while (read_line(fp) > 0) {
505 	if (sscanf(buf, "%d", &object) != 1) {
506 	    file_msg("Incorrect format at line %d.", line_no);
507 	    return (num_object != 0? 0: BAD_FORMAT);	/* ok if any objects have been read */
508 	}
509 	switch (object) {
510 	case O_COLOR_DEF:
511 	    read_colordef();
512 	    if (num_object) {
513 		file_msg("Color definitions must come before other objects (line %d).",
514 			line_no);
515 	    }
516 	    break;
517 	case O_POLYLINE:
518 	    if ((l = read_lineobject(fp)) == NULL)
519 		continue;
520 	    if (ll)
521 		ll = (ll->next = l);
522 	    else
523 		ll = obj->lines = l;
524 	    num_object++;
525 	    break;
526 	case O_SPLINE:
527 	    if ((s = read_splineobject(fp)) == NULL)
528 		continue;
529 	    if (ls)
530 		ls = (ls->next = s);
531 	    else
532 		ls = obj->splines = s;
533 	    num_object++;
534 	    break;
535 	case O_ELLIPSE:
536 	    if ((e = read_ellipseobject()) == NULL)
537 		continue;
538 	    if (le)
539 		le = (le->next = e);
540 	    else
541 		le = obj->ellipses = e;
542 	    num_object++;
543 	    break;
544 	case O_ARC:
545 	    if ((a = read_arcobject(fp)) == NULL)
546 		continue;
547 	    if (la)
548 		la = (la->next = a);
549 	    else
550 		la = obj->arcs = a;
551 	    num_object++;
552 	    break;
553 	case O_TXT:
554 	    if ((t = read_textobject(fp)) == NULL)
555 		continue;
556 	    if (lt)
557 		lt = (lt->next = t);
558 	    else
559 		lt = obj->texts = t;
560 	    num_object++;
561 	    break;
562 	case O_COMPOUND:
563 	    if ((c = read_compoundobject(fp)) == NULL)
564 		continue;
565 	    if (lc)
566 		lc = (lc->next = c);
567 	    else
568 		lc = obj->compounds = c;
569 	    num_object++;
570 	    break;
571 	default:
572 	    file_msg("Incorrect object code at line %d.", line_no);
573 	    continue;
574 	} /* switch */
575 
576     } /* while */
577 
578     if (feof(fp))
579 	return 0;
580     else
581 	return errno;
582 }				/* read_objects */
583 
584 int
parse_papersize(char * size)585 parse_papersize(char *size)
586 {
587     int i,len;
588     char *c;
589 
590     /* first get rid of trailing newline */
591     if (size[strlen(size)-1]=='\n')
592 	size[strlen(size)-1]='\0';
593     /* then truncate at first space or parenthesis "(" in passed size */
594     if (((c=strchr(size,' '))!= NULL)||((c=strchr(size,'(')) != NULL)) {
595 	*c ='\0';
596     }
597     len = strlen(size);
598     /* change ledger (deprecated) to tabloid */
599     if (strncasecmp(size,"ledger",len) == 0)
600 	strcpy(size,"tabloid");
601     for (i=0; i<NUMPAPERSIZES; i++) {
602 	if (strncasecmp(size,paper_sizes[i].sname,len) == 0)
603 	    break;
604     }
605     /* return entry 0 for bad papersize */
606     if (i >= NUMPAPERSIZES)
607 	return 0;
608     return i;
609 }
610 
611 static void
read_colordef(void)612 read_colordef(void)
613 {
614     int		    c,r,g,b;
615 
616     if ((sscanf(buf, "%*d %d #%02x%02x%02x", &c, &r, &g, &b) != 4) ||
617 		(c < NUM_STD_COLS) || (c >= MAX_USR_COLS+NUM_STD_COLS)) {
618 	buf[strlen(buf)-1]='\0';	/* remove the newline */
619 	file_msg("Invalid color definition: %s, setting to black (#00000).",buf);
620 	r=g=b=0;
621 	c = NUM_STD_COLS;
622     }
623     /* make in the range 0...MAX_USR_COLS */
624     c -= NUM_STD_COLS;
625     n_user_colors[c].red = r*256;
626     n_user_colors[c].green = g*256;
627     n_user_colors[c].blue = b*256;
628     n_colorFree[c] = False;
629     /* keep track of highest color number */
630     n_num_usr_cols = max2(c, n_num_usr_cols);
631 }
632 
633 static F_arc   *
read_arcobject(FILE * fp)634 read_arcobject(FILE *fp)
635 {
636     F_arc	   *a;
637     int		    n, fa, ba;
638     int		    type, style;
639     float	    thickness, wd, ht;
640 
641     if ((a = create_arc()) == NULL){
642 	numcom=0;
643 	return NULL;
644     }
645 
646     save_line = line_no;
647     a->next = NULL;
648     a->for_arrow = a->back_arrow = NULL;
649     if (proto >= 30) {
650 	n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%f%d%d%d%d%f%f%d%d%d%d%d%d\n",
651 	       &a->type, &a->style, &a->thickness,
652 	       &a->pen_color, &a->fill_color, &a->depth,
653 	       &a->pen_style, &a->fill_style,
654 	       &a->style_val, &a->cap_style,
655 	       &a->direction, &fa, &ba,
656 	       &a->center.x, &a->center.y,
657 	       &a->point[0].x, &a->point[0].y,
658 	       &a->point[1].x, &a->point[1].y,
659 	       &a->point[2].x, &a->point[2].y);
660     } else {
661 	n = sscanf(buf, "%*d%d%d%d%d%d%d%d%f%d%d%d%f%f%d%d%d%d%d%d\n",
662 	       &a->type, &a->style, &a->thickness,
663 	       &a->pen_color, &a->depth,
664 	       &a->pen_style, &a->fill_style,
665 	       &a->style_val, &a->direction, &fa, &ba,
666 	       &a->center.x, &a->center.y,
667 	       &a->point[0].x, &a->point[0].y,
668 	       &a->point[1].x, &a->point[1].y,
669 	       &a->point[2].x, &a->point[2].y);
670 	a->fill_color = a->pen_color;
671 	a->cap_style = CAP_BUTT;	/* butt line cap */
672     }
673     a->type--;	/* internally, 0=open arc, 1=pie wedge */
674     if (((proto < 22) && (n != 19)) || ((proto >= 30) && (n != 21))) {
675 	file_msg(Err_incomp, "arc", save_line);
676 	free((char *) a);
677 	numcom=0;
678 	return NULL;
679     }
680     a->fill_style = FILL_CONVERT(a->fill_style);
681     fix_depth(&a->depth);
682     check_color(&a->pen_color);
683     check_color(&a->fill_color);
684     fix_fillstyle(a);	/* make sure that black/white have legal fill styles */
685 
686     a->comments = attach_comments();		/* attach any comments */
687 
688     /* forward arrow */
689     if (fa) {
690 	if (read_line(fp) == -1)
691 	    return a;
692 	if (sscanf(buf, "%d%d%f%f%f", &type, &style, &thickness, &wd, &ht) != 5) {
693 	    file_msg(Err_incomp, "arc", save_line);
694 	    return a;
695 	}
696 	/* throw away any arrow heads on pie-wedge arcs */
697 	if (a->type == T_OPEN_ARC) {
698 	    /* make sure arrowhead is legal and convert units */
699 	    convert_arrow(&type, &wd, &ht);
700 	    a->for_arrow = new_arrow(type, style, thickness, wd, ht);
701 	}
702     }
703 
704     /* backward arrow */
705     if (ba) {
706 	if (read_line(fp) == -1)
707 	    return a;
708 	if (sscanf(buf, "%d%d%f%f%f", &type, &style, &thickness, &wd, &ht) != 5) {
709 	    file_msg(Err_incomp, "arc", save_line);
710 	    return a;
711 	}
712 	/* throw away any arrow heads on pie-wedge arcs */
713 	if (a->type == T_OPEN_ARC) {
714 	    /* make sure arrowhead is legal and convert units */
715 	    convert_arrow(&type, &wd, &ht);
716 	    a->back_arrow = new_arrow(type, style, thickness, wd, ht);
717 	}
718     }
719     return a;
720 }
721 
722 static F_compound *
read_compoundobject(FILE * fp)723 read_compoundobject(FILE *fp)
724 {
725     F_arc	   *a, *la = NULL;
726     F_ellipse	   *e, *le = NULL;
727     F_line	   *l, *ll = NULL;
728     F_spline	   *s, *ls = NULL;
729     F_text	   *t, *lt = NULL;
730     F_compound	   *com, *c, *lc = NULL;
731     int		    n, object;
732 
733     if ((com = create_compound()) == NULL){
734         numcom=0;
735 	return NULL;
736     }
737 
738     com->arcs = NULL;
739     com->ellipses = NULL;
740     com->lines = NULL;
741     com->splines = NULL;
742     com->texts = NULL;
743     com->compounds = NULL;
744     com->next = NULL;
745     com->comments = attach_comments();		/* attach any comments */
746 
747     save_line = line_no;
748     /* read bounding info for compound */
749     n = sscanf(buf, "%*d%d%d%d%d\n", &com->nwcorner.x, &com->nwcorner.y,
750 	       &com->secorner.x, &com->secorner.y);
751     /* if compound spec has no bounds, set to 0 and calculate later */
752     if (n <= 0) {
753 	com->nwcorner.x = com->nwcorner.y =
754 		com->secorner.x = com->secorner.y = 0;
755     } else if (n != 4) {
756 	/* otherwise, if there aren't 4 numbers, complain */
757 	file_msg(Err_incomp, "compound", save_line);
758 	free((char *) com);
759 	numcom=0;
760 	return NULL;
761     }
762     while (read_line(fp) > 0) {
763 	if (sscanf(buf, "%d", &object) != 1) {
764 	    file_msg(Err_incomp, "compound", save_line);
765 	    free((char *) com);
766 	    numcom=0;
767 	    return NULL;
768 	}
769 	switch (object) {
770 	case O_POLYLINE:
771 	    if ((l = read_lineobject(fp)) == NULL)
772 		continue;
773 	    if (ll)
774 		ll = (ll->next = l);
775 	    else
776 		ll = com->lines = l;
777 	    break;
778 	case O_SPLINE:
779 	    if ((s = read_splineobject(fp)) == NULL)
780 		continue;
781 	    if (ls)
782 		ls = (ls->next = s);
783 	    else
784 		ls = com->splines = s;
785 	    break;
786 	case O_ELLIPSE:
787 	    if ((e = read_ellipseobject()) == NULL)
788 		continue;
789 	    if (le)
790 		le = (le->next = e);
791 	    else
792 		le = com->ellipses = e;
793 	    break;
794 	case O_ARC:
795 	    if ((a = read_arcobject(fp)) == NULL)
796 		continue;
797 	    if (la)
798 		la = (la->next = a);
799 	    else
800 		la = com->arcs = a;
801 	    break;
802 	case O_TXT:
803 	    if ((t = read_textobject(fp)) == NULL)
804 		continue;
805 	    if (lt)
806 		lt = (lt->next = t);
807 	    else
808 		lt = com->texts = t;
809 	    break;
810 	case O_COMPOUND:
811 	    if ((c = read_compoundobject(fp)) == NULL)
812 		continue;
813 	    if (lc)
814 		lc = (lc->next = c);
815 	    else
816 		lc = com->compounds = c;
817 	    break;
818 	case O_END_COMPOUND:
819 	    /* if compound def had no bounds or all zeroes, calculate bounds now */
820 	    if (com->nwcorner.x == 0 && com->nwcorner.y == 0 &&
821 			com->secorner.x == 0 && com->secorner.y == 0)
822 		compound_bound(com, &com->nwcorner.x, &com->nwcorner.y,
823 					&com->secorner.x, &com->secorner.y);
824 	    return com;
825 	default:
826 	    file_msg("Incorrect object code at line %d.", save_line);
827 	    continue;
828 	}			/* switch */
829     } /* while (read_line(fp) > 0) */
830 
831     if (feof(fp)) {
832 	compound_bound(com, &com->nwcorner.x, &com->nwcorner.y,
833 	           &com->secorner.x, &com->secorner.y);
834 	return com;
835     } else {
836 	numcom=0;
837 	return NULL;
838     }
839 }
840 
841 static F_ellipse *
read_ellipseobject(void)842 read_ellipseobject(void)
843 {
844     F_ellipse	   *e;
845     int		    n;
846 
847     if ((e = create_ellipse()) == NULL){
848 	numcom=0;
849 	return NULL;
850     }
851 
852     save_line = line_no;
853     e->next = NULL;
854     if (proto >= 30) {
855 	n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%f%d%f%d%d%d%d%d%d%d%d\n",
856 	       &e->type, &e->style, &e->thickness,
857 	       &e->pen_color, &e->fill_color, &e->depth,
858 	       &e->pen_style, &e->fill_style,
859 	       &e->style_val, &e->direction, &e->angle,
860 	       &e->center.x, &e->center.y,
861 	       &e->radiuses.x, &e->radiuses.y,
862 	       &e->start.x, &e->start.y,
863 	       &e->end.x, &e->end.y);
864     } else {
865 	n = sscanf(buf, "%*d%d%d%d%d%d%d%d%f%d%f%d%d%d%d%d%d%d%d\n",
866 	       &e->type, &e->style, &e->thickness,
867 	       &e->pen_color, &e->depth, &e->pen_style, &e->fill_style,
868 	       &e->style_val, &e->direction, &e->angle,
869 	       &e->center.x, &e->center.y,
870 	       &e->radiuses.x, &e->radiuses.y,
871 	       &e->start.x, &e->start.y,
872 	       &e->end.x, &e->end.y);
873 	e->fill_color = e->pen_color;
874     }
875     if (((proto < 22) && (n != 18)) || ((proto >= 30) && (n != 19))) {
876 	file_msg(Err_incomp, "ellipse", save_line);
877 	free((char *) e);
878 	numcom=0;
879 	return NULL;
880     }
881     e->fill_style = FILL_CONVERT(e->fill_style);
882     fix_angle(&e->angle);	/* make sure angle is 0 to 2PI */
883     fix_depth(&e->depth);
884     check_color(&e->pen_color);
885     check_color(&e->fill_color);
886     fix_fillstyle(e);	/* make sure that black/white have legal fill styles */
887     e->comments = attach_comments();		/* attach any comments */
888     return e;
889 }
890 
891 static F_line  *
read_lineobject(FILE * fp)892 read_lineobject(FILE *fp)
893 {
894     F_line	   *l;
895     F_point	   *p, *q;
896     int		    n, x, y, fa, ba, npts, cnpts;
897     int		    type, style, radius_flag;
898     float	    thickness, wd, ht;
899     int		    ox, oy;
900     char	    picfile[PATH_MAX];
901     Boolean	    dum;
902 
903     if ((l = create_line()) == NULL){
904 	numcom=0;
905 	return NULL;
906     }
907 
908     save_line = line_no;
909     l->points = NULL;
910     l->for_arrow = l->back_arrow = NULL;
911     l->next = NULL;
912 
913     sscanf(buf, "%*d%d", &l->type);
914 
915     /* 2.0 has radius parm only for arc-box objects */
916     /* 2.1 or later has radius parm for all line objects */
917     /* 3.0(experimental 2.2) or later additionally has number of points parm for
918 	all line objects and fill color separate from border color */
919     radius_flag = ((proto >= 21) || (l->type == T_ARCBOX && proto == 20));
920     if (proto >= 30) {
921 	n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%f%d%d%d%d%d%d",
922 		   &l->type, &l->style, &l->thickness, &l->pen_color, &l->fill_color,
923 		   &l->depth, &l->pen_style, &l->fill_style, &l->style_val,
924 		   &l->join_style, &l->cap_style, &l->radius, &fa, &ba, &npts);
925     } else {	/* v2.1 and earlier */
926 	if (radius_flag) {
927 	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%f%d%d%d",
928 		   &l->type, &l->style, &l->thickness, &l->pen_color, &l->depth,
929 	      &l->pen_style, &l->fill_style, &l->style_val, &l->radius, &fa, &ba);
930 	} else { /* old format uses pen for radius of arc-box * corners */
931 	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%f%d%d",
932 		   &l->type, &l->style, &l->thickness, &l->pen_color,
933 	           &l->depth, &l->pen_style, &l->fill_style, &l->style_val, &fa, &ba);
934 	    if (l->type == T_ARCBOX) {
935 		l->radius = l->pen_style;
936 		l->pen_style = -1;
937 	    } else
938 		l->radius = DEFAULT;
939 	}
940 	l->fill_color = l->pen_color;
941 	l->join_style = JOIN_MITER;	/* miter joint */
942 	l->cap_style = CAP_BUTT;	/* butt line cap */
943     }
944     if ((!radius_flag && n != 10) ||
945 	(radius_flag && ((proto == 21 && n != 11) ||
946 			((proto >= 30) && n != 15)))) {
947 	    file_msg(Err_incomp, "line", save_line);
948 	    free((char *) l);
949 	    numcom=0;
950 	    return NULL;
951     }
952     l->fill_style = FILL_CONVERT(l->fill_style);
953     fix_depth(&l->depth);
954     check_color(&l->pen_color);
955     check_color(&l->fill_color);
956     fix_fillstyle(l);	/* make sure that black/white have legal fill styles */
957     /* forward arrow */
958     if (fa) {
959 	if (read_line(fp) == -1){
960 	    numcom=0;
961 	    return NULL;
962 	}
963 	if (sscanf(buf, "%d%d%f%f%f", &type, &style, &thickness, &wd, &ht) != 5) {
964 	    file_msg(Err_incomp, "line", save_line);
965 	    numcom=0;
966 	    return NULL;
967 	}
968 	/* make sure arrowhead is legal and convert units */
969 	convert_arrow(&type, &wd, &ht);
970 	l->for_arrow = new_arrow(type, style, thickness, wd, ht);
971     }
972     /* backward arrow */
973     if (ba) {
974 	if (read_line(fp) == -1){
975 	    numcom=0;
976 	    return NULL;
977 	}
978 	if (sscanf(buf, "%d%d%f%f%f", &type, &style, &thickness, &wd, &ht) != 5) {
979 	    file_msg(Err_incomp, "line", save_line);
980 	    numcom=0;
981 	    return NULL;
982 	}
983 	/* make sure arrowhead is legal and convert units */
984 	convert_arrow(&type, &wd, &ht);
985 	l->back_arrow = new_arrow(type, style, thickness, wd, ht);
986     }
987     if (l->type == T_PICTURE) {
988 	char s1[PATH_MAX];
989 
990 	if (read_line(fp) == -1) {
991 	    free((char *) l);
992 	    numcom=0;
993 	    return NULL;
994 	}
995 	if ((l->pic = create_pic()) == NULL) {
996 	    free((char *) l);
997 	    numcom=0;
998 	    return NULL;
999 	}
1000 	if (sscanf(buf, "%d %[^\n]", &l->pic->flipped, s1) != 2) {
1001 	    file_msg(Err_incomp, "Picture Object", save_line);
1002 	    free((char *) l);
1003 	    numcom=0;
1004 	    return NULL;
1005 	}
1006 
1007 	/* if path is relative convert it to absolute path */
1008 	if (s1[0] != '/')
1009 	    sprintf(picfile, "%s/%s", cur_file_dir, s1);
1010 	else
1011 	    strcpy(picfile, s1);
1012 
1013 	if (!update_figs) {
1014 	    /* only read in the image if update_figs is False */
1015 	    read_picobj(l->pic, picfile, l->pen_color, False, &dum);
1016 	} else {
1017 	    /* otherwise just make a pseudo entry with the filename */
1018 	    l->pic->pic_cache = create_picture_entry();
1019 	    l->pic->pic_cache->file = strdup(picfile);
1020 	}
1021 	/* we've read in a pic object - merge_file uses this info to decide
1022 	   whether or not to remap any picture colors in first figure */
1023 	pic_obj_read = True;
1024     } else
1025 	l->pic = NULL;
1026 
1027     if ((p = create_point()) == NULL) {
1028 	free((char *) l);
1029 	numcom=0;
1030 	return NULL;
1031     }
1032 
1033     l->points = p;
1034     p->next = NULL;
1035 
1036     /* read first point */
1037     line_no++;
1038     if (fscanf(fp, "%d%d", &p->x, &p->y) != 2) {
1039 	file_msg(Err_incomp, "line", save_line);
1040 	free_linestorage(l);
1041 	numcom=0;
1042 	return NULL;
1043     }
1044     ox = p->x;
1045     oy = p->y;
1046     /* read subsequent points */
1047     if (proto < 22)
1048 	npts = 1000000;	/* loop until we find 9999 9999 for previous fig files */
1049     cnpts = 1;		/* keep track of actual number of points read */
1050     for (--npts; npts > 0; npts--) {
1051 	count_lines_correctly(fp);
1052 	if (fscanf(fp, "%d%d", &x, &y) != 2) {
1053 	    file_msg(Err_incomp, "line", save_line);
1054 	    free_linestorage(l);
1055 	    numcom=0;
1056 	    return NULL;
1057 	}
1058 	if (proto < 22 && x == 9999)
1059 	    break;
1060 	/* ignore identical consecutive points */
1061 	if (ox == x && oy == y)
1062 	    continue;
1063 	ox = x;
1064 	oy = y;
1065 	if ((q = create_point()) == NULL) {
1066 	    free_linestorage(l);
1067 	    numcom=0;
1068 	    return NULL;
1069 	}
1070 	q->x = x;
1071 	q->y = y;
1072 	q->next = NULL;
1073 	p->next = q;
1074 	p = q;
1075 	cnpts++;
1076     }
1077     /* also, if it has fewer than 5 points and is a box, picture, or arcbox,
1078        or if it has fewer than 3 points and it is a polygon remove it */
1079     if ((cnpts < 5 && (l->type == T_BOX || l->type == T_ARCBOX || l->type == T_PICTURE)) ||
1080 	(cnpts < 3 && l->type == T_POLYGON)) {
1081 	    if (l->type == T_POLYGON) {
1082 		file_msg("Deleting polygon containing fewer than 3 points at line %d",
1083 			save_line);
1084 	    } else {
1085 		file_msg("Deleting zero-size %s at line %d",
1086 			l->type==T_BOX? "box" : l->type==T_ARCBOX? "arcbox" : "picture",
1087 			save_line);
1088 	    }
1089 	    free_linestorage(l);
1090 	    numcom=0;
1091 	    return NULL;
1092     }
1093     /* if the line has only one point, delete any arrowheads it might have now */
1094     if (l->points->next == NULL) {
1095 	if (l->for_arrow) {
1096 	    free((char *) l->for_arrow);
1097 	    l->for_arrow = (F_arrow *) NULL;
1098 	}
1099 	if (l->back_arrow) {
1100 	    free((char *) l->back_arrow);
1101 	    l->back_arrow = (F_arrow *) NULL;
1102 	}
1103     }
1104     l->comments = attach_comments();		/* attach any comments */
1105     /* skip to the next line */
1106     skip_line(fp);
1107     return l;
1108 }
1109 
1110 static F_spline *
read_splineobject(FILE * fp)1111 read_splineobject(FILE *fp)
1112 {
1113     F_spline	   *s;
1114     F_point	   *p, *q;
1115     F_sfactor	   *cp, *cq;
1116     int		    c, n, x, y, fa, ba, npts, numpts;
1117     int		    type, style;
1118     float	    thickness, wd, ht;
1119     double	    s_param;
1120     float	    lx, ly, rx, ry;
1121 
1122     if ((s = create_spline()) == NULL){
1123 	numcom=0;
1124 	return NULL;
1125     }
1126 
1127     save_line = line_no;
1128     s->points = NULL;
1129     s->sfactors = NULL;
1130     s->for_arrow = s->back_arrow = NULL;
1131     s->next = NULL;
1132 
1133     /* 3.0(experimental 2.2) or later has number of points parm for all spline
1134 	objects and fill color separate from border color */
1135     if (proto >= 30) {
1136 	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%f%d%d%d%d",
1137 		    &s->type, &s->style, &s->thickness, &s->pen_color, &s->fill_color,
1138 		    &s->depth, &s->pen_style, &s->fill_style, &s->style_val,
1139 		    &s->cap_style, &fa, &ba, &npts);
1140     } else {
1141 	    n = sscanf(buf, "%*d%d%d%d%d%d%d%d%f%d%d",
1142 		    &s->type, &s->style, &s->thickness, &s->pen_color,
1143 		    &s->depth, &s->pen_style, &s->fill_style, &s->style_val, &fa, &ba);
1144 	    s->fill_color = s->pen_color;
1145 	    s->cap_style = CAP_BUTT;	/* butt line cap */
1146     }
1147     if (((proto < 22) && (n != 10)) || ((proto >= 30) && n != 13)) {
1148 	file_msg(Err_incomp, "spline", save_line);
1149 	free((char *) s);
1150 	numcom=0;
1151 	return NULL;
1152     }
1153     s->fill_style = FILL_CONVERT(s->fill_style);
1154     fix_depth(&s->depth);
1155     check_color(&s->pen_color);
1156     check_color(&s->fill_color);
1157     fix_fillstyle(s);	/* make sure that black/white have legal fill styles */
1158     /* forward arrow */
1159     if (fa) {
1160 	if (read_line(fp) == -1){
1161 	    numcom=0;
1162 	    return NULL;
1163 	}
1164 	if (sscanf(buf, "%d%d%f%f%f", &type, &style, &thickness, &wd, &ht) != 5) {
1165 	    file_msg(Err_incomp, "spline", save_line);
1166 	    numcom=0;
1167 	    return NULL;
1168 	}
1169 	/* make sure arrowhead is legal and convert units */
1170 	convert_arrow(&type, &wd, &ht);
1171 	s->for_arrow = new_arrow(type, style, thickness, wd, ht);
1172     }
1173     /* backward arrow */
1174     if (ba) {
1175 	if (read_line(fp) == -1){
1176 	    numcom=0;
1177 	    return NULL;
1178 	}
1179 	if (sscanf(buf, "%d%d%f%f%f", &type, &style, &thickness, &wd, &ht) != 5) {
1180 	    file_msg(Err_incomp, "spline", save_line);
1181 	    numcom=0;
1182 	    return NULL;
1183 	}
1184 	/* make sure arrowhead is legal and convert units */
1185 	convert_arrow(&type, &wd, &ht);
1186 	s->back_arrow = new_arrow(type, style, thickness, wd, ht);
1187     }
1188 
1189     /* read first point */
1190     line_no++;
1191     if ((n = fscanf(fp, "%d%d", &x, &y)) != 2) {
1192 	file_msg(Err_incomp, "spline", save_line);
1193 	free_splinestorage(s);
1194 	numcom=0;
1195 	return NULL;
1196     };
1197     if ((p = create_point()) == NULL) {
1198 	free_splinestorage(s);
1199 	numcom=0;
1200 	return NULL;
1201     }
1202     s->points = p;
1203     p->x = x;
1204     p->y = y;
1205     c = 1;
1206     /* read subsequent points */
1207     if (proto < 22)
1208 	npts = 1000000;	/* loop until we find 9999 9999 for previous fig files */
1209     numpts = 1;
1210     for (--npts; npts > 0; npts--) {
1211 	count_lines_correctly(fp);
1212 	if (fscanf(fp, "%d%d", &x, &y) != 2) {
1213 	    file_msg(Err_incomp, "spline", save_line);
1214 	    p->next = NULL;
1215 	    free_splinestorage(s);
1216 	    numcom=0;
1217 	    return NULL;
1218 	};
1219 	if (proto < 22 && x == 9999)
1220 	    break;
1221 	if ((q = create_point()) == NULL) {
1222 	    free_splinestorage(s);
1223 	    numcom=0;
1224 	    return NULL;
1225 	}
1226 	q->x = x;
1227 	q->y = y;
1228 	p->next = q;
1229 	p = q;
1230 	c++;
1231 	numpts++;
1232     }
1233     p->next = NULL;
1234 
1235     if (proto <= 31) {		/* to read files from version 3.1 and older */
1236 	if int_spline(s) {
1237 	                        /* 2 control points per point given by user in
1238 			           version 3.1 and older : don't read them */
1239           while (c--) {
1240             count_lines_correctly(fp);
1241             if (fscanf(fp, "%f%f%f%f", &lx, &ly, &rx, &ry) != 4) {
1242               file_msg(Err_incomp, "spline", save_line);
1243 	      free_splinestorage(s);
1244 	      numcom=0;
1245               return NULL;
1246             }
1247           }
1248         }
1249 	if (closed_spline(s)) {
1250 	    F_point *ptr   = s->points;
1251 	    s->points = s->points->next;
1252 	    free (ptr);
1253 	}
1254 	if (! make_sfactors(s)) {
1255 	    free_splinestorage(s);
1256 	    numcom=0;
1257 	    return NULL;
1258 	}
1259 	return s;
1260     }
1261 
1262     /* Read sfactors - the s parameter for splines */
1263 
1264     count_lines_correctly(fp);
1265     if ((n = fscanf(fp, "%lf", &s_param)) != 1) {
1266 	file_msg(Err_incomp, "spline", save_line);
1267 	free_splinestorage(s);
1268 	numcom=0;
1269 	return NULL;
1270     };
1271     if ((cp = create_sfactor()) == NULL) {
1272 	free_splinestorage(s);
1273 	numcom=0;
1274 	return NULL;
1275     }
1276     s->sfactors = cp;
1277     cp->s = s_param;
1278     while (--c) {
1279 	count_lines_correctly(fp);
1280 	if (fscanf(fp, "%lf", &s_param) != 1) {
1281 	    file_msg(Err_incomp, "spline", save_line);
1282 	    cp->next = NULL;
1283 	    free_splinestorage(s);
1284 	    numcom=0;
1285 	    return NULL;
1286 	};
1287 	if ((cq = create_sfactor()) == NULL) {
1288 	    cp->next = NULL;
1289 	    free_splinestorage(s);
1290 	    numcom=0;
1291 	    return NULL;
1292 	}
1293 	cq->s=s_param;
1294 	cp->next = cq;
1295 	cp = cq;
1296     }
1297     if (closed_spline(s) && numpts < 3) {
1298 	file_msg("Closed splines must have 3 or more points, removing spline at line %d", save_line);
1299 	free_splinestorage(s);
1300 	numcom=0;
1301 	return NULL;
1302     } else if (numpts < 2) {
1303 	file_msg("Open splines must have 2 or more points, removing spline at line %d", save_line);
1304 	free_splinestorage(s);
1305 	numcom=0;
1306 	return NULL;
1307     }
1308     cp->next = NULL;
1309     s->comments = attach_comments();		/* attach any comments */
1310 
1311     /* skip to the end of the line */
1312     skip_line(fp);
1313     return s;
1314 }
1315 
1316 static F_text  *
read_textobject(FILE * fp)1317 read_textobject(FILE *fp)
1318 {
1319     F_text	   *t;
1320     int		    l,n,len;
1321     int		    ignore = 0;
1322     char	    s[BUF_SIZE], s_temp[BUF_SIZE], junk[2];
1323     float	    tx_size;
1324     float	    length, height;
1325     Boolean	    more;
1326     PR_SIZE	    tx_dim;
1327 
1328     if ((t = create_text()) == NULL){
1329 	numcom=0;
1330 	return NULL;
1331     }
1332 
1333     save_line = line_no;
1334     t->next = NULL;
1335     /*
1336      * The text object is terminated by a CONTROL-A, so we read everything up
1337      * to the CONTROL-A and then read that character. If we do not find the
1338      * CONTROL-A on this line then this must be a multi-line text object and
1339      * we will have to read more.
1340      *
1341      * We read text size, height and length as floats because TransFig uses
1342      * floats for these, but they are rounded to ints internally to xfig.
1343      */
1344     /* read the leading blanks for the string, but delete the first one later */
1345 
1346     /*
1347      * NOTE: The height, length and descent will be recalculated from the
1348      *	     actual font structure in read_scale_text().
1349      */
1350 
1351     if (proto >= 30) {	/* order of parms is more like other objects now;
1352 			   string is now terminated with the literal '\001',
1353 			   and 8-bit characters are represented as \xxx */
1354 	n = sscanf(buf, "%*d%d%d%d%d%d%f%f%d%f%f%d%d%[^\n]",
1355 		&t->type, &t->color, &t->depth, &t->pen_style,
1356 		&t->font, &tx_size, &t->angle, &t->flags,
1357 		&height, &length, &t->base_x, &t->base_y, s);
1358     } else {
1359 	n = sscanf(buf, "%*d%d%d%f%d%d%d%f%d%f%f%d%d%[^\1]%[\1]",
1360 		&t->type, &t->font, &tx_size, &t->pen_style,
1361 		&t->color, &t->depth, &t->angle, &t->flags,
1362 		&height, &length, &t->base_x, &t->base_y, s, junk);
1363     }
1364     /* remove newline */
1365     buf[strlen(buf)-1] = '\0';
1366     if (buf[strlen(buf)-1] == '\r')
1367 	buf[strlen(buf)-1] = '\0';
1368     /* remove any trailing carriage returns (^M, possibly from a PC) */
1369     if (s[strlen(s)-1] == '\r')
1370 	s[strlen(s)-1] = '\0';
1371     /* use these for now, but recalculate later in read_scale_text if not update_figs */
1372     t->ascent = round(height);
1373     t->descent = 0;
1374     t->length = round(length);
1375 
1376     if (n < 11) {
1377 	file_msg(Err_incomp, "text", save_line);
1378 	free((char *) t);
1379 	numcom=0;
1380 	return NULL;
1381     }
1382 
1383     /* now round size to int */
1384 
1385     /* change DEFAULT (-1) or 0 size to default size */
1386     if ((int) tx_size == DEFAULT || (int) tx_size == 0)
1387 	t->size = DEF_FONTSIZE;
1388     else
1389 	t->size = round(tx_size);
1390 
1391     /* set some limits */
1392     if (t->size < MIN_FONT_SIZE)
1393 	t->size = MIN_FONT_SIZE;
1394     else if (t->size > MAX_FONT_SIZE)
1395 	t->size = MAX_FONT_SIZE;
1396 
1397     /* make sure angle is 0 to 2PI */
1398     fix_angle(&t->angle);
1399 
1400     /* convert all pre-2.1 NON-TFX text flags (used to be font_style) to PostScript
1401        and all pre-2.1 TFX flags to PostScript + Special */
1402     if (proto <= 20) {
1403 	t->flags = PSFONT_TEXT;
1404 	if (TFX)
1405 		t->flags |= SPECIAL_TEXT;
1406     }
1407 
1408     /* check for valid font number */
1409     if (t->font >= MAXFONT(t)) {
1410 	file_msg("Invalid text font (%d) at line %d, setting to DEFAULT.",
1411 		t->font, save_line);
1412 	t->font = DEFAULT;
1413     }
1414 
1415     /* get the UNZOOMED font struct */
1416     if (!update_figs)
1417 	t->fontstruct = lookfont(x_fontnum(psfont_text(t), t->font), t->size);
1418 
1419     fix_depth(&t->depth);
1420     check_color(&t->color);
1421     more = False;
1422     if (proto < 22 && n == 13)
1423 	more = True;		/* in older xfig there is more if ^A wasn't found yet */
1424     else if (proto >= 30) {	/* in 3.0(2.2) there is more if \001 wasn't found */
1425 	len = strlen(s);
1426 	if ((strcmp(&s[len-4],"\\001") == 0) &&	/* if we find '\000' */
1427 	    !(backslash_count(s, len-5) % 2)) { /* and not '\\000' */
1428 		more = False;			/* then there are no more lines */
1429 		s[len-4]='\0';			/* and get rid of the '\001' */
1430 	} else {
1431 		more = True;
1432 		s[len++]='\n';			/* put back the end of line char */
1433 		s[len] = '\0';			/* and terminate it */
1434 	}
1435     }
1436     if (more) {
1437 	/* Read in the subsequent lines of the text object if there is more than one. */
1438 	do {
1439 	    line_no++;		/* As is done in read_line */
1440 	    if (fgets(buf, BUF_SIZE, fp) == NULL)
1441 		break;
1442 	    /* remove newline */
1443 	    buf[strlen(buf)-1] = '\0';
1444 	    if (buf[strlen(buf)-1] == '\r')
1445 		buf[strlen(buf)-1] = '\0';
1446 	    if (proto < 22) {
1447 		n = sscanf(buf, "%[^\1]%[\1]", s_temp, junk);
1448 	    } else {
1449 		strcpy(s_temp,buf);
1450 		len = strlen(s_temp);
1451 		if ((strncmp(&s_temp[len-4],"\\001",4) == 0) &&
1452 		    !(backslash_count(s, len-5) % 2)) {
1453 			n=0;			/* found the '\001', set n to stop */
1454 			s_temp[len-4]='\0';	/* and get rid of the '\001' */
1455 		} else {
1456 			n=1;			/* keep going (more lines) */
1457 		}
1458 	    }
1459 	    /* Safety check */
1460 	    if (strlen(s) + 1 + strlen(s_temp) + 1 > BUF_SIZE) {
1461 		/* Too many characters.	 Ignore the rest. */
1462 		if (!ignore)
1463 		    file_msg("Truncating TEXT object to %d chars in line %d.",
1464 				BUF_SIZE, save_line);
1465 		ignore = 1;
1466 	    }
1467 	    if (!ignore)
1468 		strcat(s, s_temp);
1469 	} while (n == 1);
1470     }
1471     if (proto >= 30) {
1472 	/* now convert any \xxx to ascii characters */
1473 	if (strchr(s,'\\')) {
1474 		int num;
1475 		len = strlen(s);
1476 		for (l=0,n=0; l < len; l++) {
1477 		    if (s[l]=='\\') {
1478 			/* a backslash, see if a digit follows */
1479 			if (l < len && isdigit(s[l+1])) {
1480 			    /* yes, allow exactly 3 digits following the \ for the octal value */
1481 			    if (sscanf(&s[l+1],"%3o",&num)!=1) {
1482 				file_msg("Error in parsing text string on line.", save_line);
1483 				free((char *) t);
1484 				numcom=0;
1485 				return NULL;
1486 			    }
1487 			    buf[n++]= (unsigned char) num;	/* put char in */
1488 			    l += 3;			/* skip over digits */
1489 			} else {
1490 			    buf[n++] = s[++l];		/* some other escaped character */
1491 			}
1492 		    } else {
1493 			buf[n++] = s[l];		/* ordinary character */
1494 		    }
1495 		}
1496 		buf[n]='\0';		/* terminate */
1497 		strcpy(s,buf);		/* copy back to s */
1498 	}
1499     }
1500 
1501     if (t->type > T_RIGHT_JUSTIFIED) {
1502 	file_msg("Invalid text justification at line %d, setting to LEFT.", save_line);
1503 	t->type = T_LEFT_JUSTIFIED;
1504     }
1505 
1506     if (strlen(s) <= 1) {
1507 	s[0]=' ';s[1]=0;
1508     }
1509     /* skip first blank from input file by starting at s[1] */
1510     if ((t->cstring = new_string(strlen(&s[1]))) == NULL) {
1511 	free((char *) t);
1512 	numcom=0;
1513 	return NULL;
1514     }
1515     /* copy string to text object */
1516     (void) strcpy(t->cstring, &s[1]);
1517 
1518     if (!update_figs) {
1519 	/* now calculate the actual length and height of the string in fig units */
1520 	tx_dim = textsize(t->fontstruct, strlen(t->cstring), t->cstring);
1521 	t->length = round(tx_dim.length);
1522 	t->ascent = round(tx_dim.ascent);
1523 	t->descent = round(tx_dim.descent);
1524 	/* now get the zoomed font struct */
1525 	t->zoom = zoomscale;
1526 	if (display_zoomscale != 1.0)
1527 	    t->fontstruct = lookfont(x_fontnum(psfont_text(t), t->font),
1528 				round(t->size*display_zoomscale));
1529     }
1530 
1531     t->comments = attach_comments();		/* attach any comments */
1532     return t;
1533 }
1534 
1535 /* akm 28/2/95 - count consecutive backslashes backwards */
1536 static int
backslash_count(char * cp,int start)1537 backslash_count(char *cp, int start)
1538 {
1539   int i, count = 0;
1540 
1541   for(i=start; i>=0; i--) {
1542     if (cp[i] == '\\')
1543 	count++;
1544     else
1545 	break;
1546   }
1547   return count;
1548 }
1549 
1550 /* attach comments together */
1551 
1552 static char *
attach_comments(void)1553 attach_comments(void)
1554 {
1555     int		    i,len;
1556     char	   *comp;
1557 
1558     if (appres.DEBUG && (numcom > 0))
1559 	fprintf(stderr,"Comments:\n");
1560     /* add up length of all comment lines */
1561     len = 0;
1562     for (i=0; i<numcom; i++)
1563 	len += strlen(comments[i])+1;
1564     if ((comp = new_string(len)) == NULL) {
1565 	numcom = 0;
1566 	return NULL;
1567     }
1568     /* now make them into one string */
1569     comp[0] = '\0';
1570     for (i=0; i<numcom; i++) {
1571 	if (appres.DEBUG)
1572 	    fprintf(stderr,"%2d: %s\n",i,comments[i]);
1573 	strcat(comp, comments[i]);
1574 	/* don't put trailing newline for last comment line */
1575 	if (i<numcom-1)
1576 	    strcat(comp,"\n");
1577     }
1578     /* reset comment number */
1579     numcom = 0;
1580     return comp;
1581 }
1582 
1583 static int
read_line(FILE * fp)1584 read_line(FILE *fp)
1585 {
1586     while (1) {
1587 	if (NULL == fgets(buf, BUF_SIZE, fp)) {
1588 	    return -1;
1589 	}
1590 	line_no++;
1591 	if (*buf == '#') {		/* save any comments */
1592 	    if (save_comment() < 0)
1593 		return -1;
1594 	} else if (*buf != '\n')	/* Skip empty lines */
1595 	    return 1;
1596     }
1597 }
1598 
1599 /* save a comment line to be stored with the *subsequent* object */
1600 
1601 static int
save_comment(void)1602 save_comment(void)
1603 {
1604 	size_t	i;
1605 
1606 	/* skip too many comment lines */
1607 	if (numcom == MAXCOMMENTS)
1608 		return 2;
1609 
1610 	i = strlen(buf);
1611 	/* see if we've allocated space for this comment */
1612 	if (comments[numcom])
1613 		free(comments[numcom]);
1614 	if ((comments[numcom] = (char*)new_string(i+1)) == NULL)
1615 		return -1;
1616 	/* remove any newline */
1617 	if (buf[i-1] == '\n')
1618 		buf[i-1] = '\0';
1619 	i = 1;
1620 	if (buf[1] == ' ')
1621 		/* remove one leading blank from the comment, if there is one */
1622 		i = 2;
1623 	strcpy(comments[numcom++], &buf[i]);
1624 	return 1;
1625 }
1626 
1627 /* skip to the end of the current line */
1628 
1629 static void
skip_line(FILE * fp)1630 skip_line(FILE *fp)
1631 {
1632     while (fgetc(fp) != '\n') {
1633 	if (feof(fp))
1634 	    return;
1635     }
1636 }
1637 
1638 /* make sure angle is 0 to 2PI */
1639 
1640 void
fix_angle(float * angle)1641 fix_angle(float *angle)
1642 {
1643     while (*angle < 0.0)
1644 	*angle += M_2PI;
1645     while (*angle >= M_2PI)
1646 	*angle -= M_2PI;
1647 }
1648 
1649 static void
fix_depth(int * depth)1650 fix_depth(int *depth)
1651 {
1652     if (*depth>MAX_DEPTH) {
1653 	    *depth=MAX_DEPTH;
1654 	    file_msg("Depth > Maximum allowed (%d), setting to %d in line %d.",
1655 			MAX_DEPTH, save_line, MAX_DEPTH);
1656 	}
1657 	else if (*depth<0 || proto<21) {
1658 	    *depth=0;
1659 	    if (proto>=21)
1660 		file_msg("Depth < 0, setting to 0 in line %d.", save_line);
1661 	}
1662 }
1663 
1664 
1665 static void
shift_figure(F_compound * obj)1666 shift_figure(F_compound *obj)
1667 {
1668     F_ellipse	   *e;
1669     F_arc	   *a;
1670     F_line	   *l;
1671     F_spline	   *s;
1672     F_compound	   *c;
1673     F_text	   *t;
1674     int		    lowx,lowy,dx,dy;
1675     int		    rnd;
1676     char shift_msg[] = "The figure has objects which have negative coordinates,\ndo you wish to shift it back on the page?";
1677 
1678     /* if user is allowing negative coords, return */
1679     if (appres.allownegcoords)
1680 	return;
1681 
1682     lowx = obj->nwcorner.x;
1683     lowy = obj->nwcorner.y;
1684 
1685     /* check if any part of the figure has negative coords */
1686     if (lowx >= 0 && lowy >= 0)
1687 	return;				/* no, ok */
1688 
1689     /* ask the user */
1690     if (!preview_in_progress && (popup_query(QUERY_YESNO, shift_msg)==RESULT_NO))
1691 	return;
1692 
1693     /* shift the whole figure to keep it "on the page" */
1694     dx = dy = 0;
1695     rnd = point_spacing();
1696     if (lowx < 0) {
1697 	dx = -lowx+rnd;	/* and round up to small grid */
1698     }
1699     if (lowy < 0) {
1700 	dy = -lowy+rnd;
1701     }
1702     if (!preview_in_progress)
1703 	file_msg("Shifting entire figure %d units right and %d units down to keep on page.",
1704 		    dx,dy);
1705     for (e = obj->ellipses; e != NULL; e = e->next)
1706 	translate_ellipse(e, dx, dy);
1707     for (a = obj->arcs; a != NULL; a = a->next)
1708 	translate_arc(a, dx, dy);
1709     for (l = obj->lines; l != NULL; l = l->next)
1710 	translate_line(l, dx, dy);
1711     for (s = obj->splines; s != NULL; s = s->next)
1712 	translate_spline(s, dx, dy);
1713     for (c = obj->compounds; c != NULL; c = c->next)
1714 	translate_compound(c, dx, dy);
1715     for (t = obj->texts; t != NULL; t = t->next)
1716 	translate_text(t, dx, dy);
1717 }
1718 
1719 static void
scale_figure(F_compound * obj,float mul,int offset)1720 scale_figure(F_compound *obj, float mul, int offset)
1721 {
1722     /* scale the whole figure for new pixels per inch */
1723     if (mul != 1.0)
1724 	put_msg("Scaling figure by a factor of %.1f for new %d pixel per inch resolution.",
1725 		mul,PIX_PER_INCH);
1726     read_scale_ellipses(obj->ellipses, mul, offset);
1727     read_scale_arcs(obj->arcs, mul, offset);
1728     read_scale_lines(obj->lines, mul, offset);
1729     read_scale_splines(obj->splines, mul, offset);
1730     read_scale_compounds(obj->compounds, mul, offset);
1731     read_scale_texts(obj->texts, mul, offset);
1732 
1733 }
1734 
1735 /* check if user color <color> is defined */
1736 
1737 void
check_color(int * color)1738 check_color(int *color)
1739 {
1740     if (*color < NUM_STD_COLS)
1741 	return;
1742     if (!n_colorFree[*color-NUM_STD_COLS])
1743 	return;
1744     file_msg("Cannot locate user color %d, using default color for line %d.",
1745 		*color,line_no);
1746     *color = DEFAULT;
1747     return;
1748 }
1749 
1750 /* swap new colors (n_...) with current for file load or undo load */
1751 
swap_colors(void)1752 void swap_colors(void)
1753 {
1754     int		i,num;
1755     Boolean	saveFree[MAX_USR_COLS];
1756 
1757     if (appres.DEBUG)
1758 	fprintf(stderr,"Swapping colors. Before: colors_are_swapped = %d\n",colors_are_swapped);
1759 
1760     colors_are_swapped = True;
1761 
1762     /* first save the current colors because del_color_cell destroys them */
1763     for (i=0; i<num_usr_cols; i++)
1764 	save_colors[i] = user_colors[i];
1765     /* and save Free entries */
1766     for (i=0; i<num_usr_cols; i++)
1767 	saveFree[i] = colorFree[i];
1768     /* now free any previously defined user colors */
1769     for (i=0; i<num_usr_cols; i++) {
1770 	    del_color_cell(i);		/* remove widget and colormap entry */
1771     }
1772     /* now swap old colors with new */
1773     for (i=0; i<n_num_usr_cols; i++)
1774 	user_colors[i] = n_user_colors[i];
1775     for (i=0; i<num_usr_cols; i++)
1776 	n_user_colors[i] = save_colors[i];
1777     /* and swap Free entries */
1778     for (i=0; i<n_num_usr_cols; i++)
1779 	colorFree[i] = n_colorFree[i];
1780     for (i=0; i<num_usr_cols; i++)
1781 	n_colorFree[i] = saveFree[i];
1782 
1783     num = num_usr_cols;
1784     num_usr_cols = n_num_usr_cols;
1785     n_num_usr_cols = num;
1786 
1787     /* now try to allocate the new colors */
1788     if (num_usr_cols > 0) {
1789 	num = num_usr_cols;
1790 	num_usr_cols = 0;
1791 	/* fill the colormap and the color memories */
1792 	for (i=0; i<num; i++) {
1793 	    if (colorFree[i]) {
1794 		colorUsed[i] = False;
1795 	    } else {
1796 		/* and add a widget and colormap entry */
1797 		if (add_color_cell(USE_EXISTING_COLOR, i, user_colors[i].red/256,
1798 			user_colors[i].green/256,
1799 			user_colors[i].blue/256) == -1) {
1800 			    file_msg("Can't allocate more than %d user colors, not enough colormap entries",
1801 					num_usr_cols);
1802 			    return;
1803 			}
1804 	        colorUsed[i] = True;
1805 	    }
1806 	}
1807     }
1808 }
1809 
1810 /* Merge any user colors from the new file just merged into the current figure.
1811    Look through the new color definitions n_... and see if any color numbers
1812    conflict with the current color defs. If so, renumber those to new, free
1813    color numbers.
1814    This is called when doing a "merge read" or a "paste" function. */
1815 
1816 static int    renum[MAX_USR_COLS];
1817 
1818 static void
merge_colors(F_compound * objects)1819 merge_colors(F_compound *objects)
1820 {
1821     Boolean	    found_exist;
1822     int		    i,j,newval;
1823     int		    x_colorFree[MAX_USR_COLS];
1824 
1825     if (n_num_usr_cols == 0)
1826 	return;
1827 
1828     newval = -1;
1829 
1830     /* look for the first free color number */
1831     for (i=0; i<MAX_USR_COLS; i++)
1832 	if (colorFree[i])
1833 	    break;
1834 
1835     if (i<MAX_USR_COLS)
1836 	newval = i;
1837 
1838     /* we need a tri-state value for n_colorFree[] so make local copy */
1839     for (i=0; i<MAX_USR_COLS; i++)
1840 	x_colorFree[i] = (int) n_colorFree[i];
1841 
1842     for (i=0; i<n_num_usr_cols; i++) {
1843 	renum[i] = -1;
1844 	if (x_colorFree[i] == 0) {
1845 		x_colorFree[i] = 1;	/* we're not using this number anymore */
1846 		/* see if it is identical to an existing color */
1847 		found_exist = False;
1848 		for (j=0; j<num_usr_cols; j++)
1849 		    /* compare only the upper 8-bits because the server may change the lower */
1850 		    if (colorUsed[j] &&
1851 			 (user_colors[j].red>>8 == n_user_colors[i].red>>8) &&
1852 			 (user_colors[j].green>>8 == n_user_colors[i].green>>8) &&
1853 			 (user_colors[j].blue>>8 == n_user_colors[i].blue>>8)) {
1854 			    renum[i] = j;	/* yes, use it */
1855 			    found_exist=True;
1856 			    break;		/* skip to next */
1857 		    }
1858 		if (!found_exist) {
1859 		    if (newval == -1) {
1860 			renum[i] = 0;		/* out of user colors, use 0 */
1861 		    } else {
1862 			renum[i] = newval;	/* assign it a new color number */
1863 			/* find the next free color number */
1864 			while (newval < MAX_USR_COLS) {
1865 			    newval++;
1866 			    if (colorFree[newval])
1867 				break;
1868 			}
1869 			if (newval >= MAX_USR_COLS)
1870 			    newval = -1;
1871 		    }
1872 		    x_colorFree[renum[i]] = -1;	/* we are using this number now */
1873 		    n_user_colors[renum[i]] = n_user_colors[i];	/* copy rgb values */
1874 		}
1875 	}
1876     }
1877 
1878     /* renumber them now */
1879     n_num_usr_cols = max2(newval,num_usr_cols);	/* new upper limit on color number */
1880     renumber_comp(objects);
1881 
1882     /* now create colorcells for the new colors */
1883     for (i=0; i<n_num_usr_cols; i++) {
1884 	if (x_colorFree[i] != 1) {
1885 	    user_colors[i] = n_user_colors[i];
1886 	    /* and add a widget and colormap entry */
1887 	    if (add_color_cell(USE_EXISTING_COLOR, i,
1888 		user_colors[i].red/256,
1889 		user_colors[i].green/256,
1890 		user_colors[i].blue/256) == -1) {
1891 		    file_msg("Can't allocate more than %d user colors, not enough colormap entries",
1892 				n_num_usr_cols);
1893 		    return;
1894 	    }
1895 	    colorFree[i] = False;
1896 	    colorUsed[i] = True;
1897 	}
1898     }
1899     num_usr_cols = n_num_usr_cols;
1900 }
1901 
1902 static void
renumber_comp(F_compound * compound)1903 renumber_comp(F_compound *compound)
1904 {
1905 	F_arc	   *a;
1906 	F_text	   *t;
1907 	F_compound *c;
1908 	F_ellipse  *e;
1909 	F_line	   *l;
1910 	F_spline   *s;
1911 
1912 	/* first renumber colors in the compounds */
1913 	for (c = compound->compounds; c != NULL; c = c->next)
1914 	    renumber_comp(c);
1915 
1916 	/* now the primitives */
1917 	for (a = compound->arcs; a != NULL; a = a->next) {
1918 	    renumber(&a->fill_color);
1919 	    renumber(&a->pen_color);
1920 	}
1921 	for (t = compound->texts; t != NULL; t = t->next) {
1922 	    renumber(&t->color);
1923 	}
1924 	for (e = compound->ellipses; e != NULL; e = e->next) {
1925 	    renumber(&e->fill_color);
1926 	    renumber(&e->pen_color);
1927 	}
1928 	for (l = compound->lines; l != NULL; l = l->next) {
1929 	    renumber(&l->fill_color);
1930 	    renumber(&l->pen_color);
1931 	}
1932 	for (s = compound->splines; s != NULL; s = s->next) {
1933 	    renumber(&s->fill_color);
1934 	    renumber(&s->pen_color);
1935 	}
1936 }
1937 
1938 static void
renumber(int * color)1939 renumber(int *color)
1940 {
1941     if (*color < NUM_STD_COLS)
1942 	return;
1943     if (renum[*color-NUM_STD_COLS] != -1)
1944 	*color = renum[*color-NUM_STD_COLS]+NUM_STD_COLS;
1945 }
1946 
1947 /* this function is to count line numbers correctly while reading
1948  * input files.
1949  * It skips all tabs and spaces and increments the global
1950  * variable line_no if a newline was found.
1951  * If any other character is read, it is put back to the input
1952  * stream and the function returns.
1953  * It should be called from within the point reading loops
1954  * in the read_{line,spline}object functions, where the point
1955  * coordinates may be given in an arbitrary number of lines.
1956  * Added by Andreas_Bagge@maush2.han.de (A.Bagge), 14.12.94
1957  */
1958 
1959 static void
count_lines_correctly(FILE * fp)1960 count_lines_correctly(FILE *fp)
1961 {
1962     int cc;
1963     do{
1964 	cc=getc(fp);
1965 	if (cc=='\n') {
1966 	   line_no++;
1967 	   cc=getc(fp);
1968 	}
1969     } while (cc==' '||cc=='\t');
1970     ungetc(cc,fp);
1971 }
1972 
1973 /* make sure arrow style value is legal and convert arrow width and height to
1974  * same units as thickness in V4.0 and later we will save the values in these units */
1975 
1976 static void
convert_arrow(int * type,float * wd,float * ht)1977 convert_arrow(int *type, float *wd, float *ht)
1978 {
1979     if (*type >= NUM_ARROW_TYPES/2)
1980 	*type = 0;
1981     if (proto < 40) {
1982 	*wd /= ZOOM_FACTOR;
1983 	*ht /= ZOOM_FACTOR;
1984     }
1985 }
1986