transfig/0008-Replace-most-calls-to-fgets-by-getline-in-read.c.patch
Hans de Goede cccfee3cdc New upstream release 3.2.7b
Add patch fixing CVE-2019-19746 (rhbz#1787040)
Add patch fixing CVE-2019-19797 (rhbz#1786726)
2020-01-15 22:29:34 +01:00

1858 lines
56 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 41b9bb838a3d544539f6e68aa4f87d70ef7d45ce Mon Sep 17 00:00:00 2001
From: Thomas Loimer <thomas.loimer@tuwien.ac.at>
Date: Sun, 5 Jan 2020 19:22:12 +0100
Subject: [PATCH 8/8] Replace most calls to fgets() by getline() in read.c
Also, fig files version 1.4 must begin with `#FIG 1.4`. Previously, a `#` in the
first line was sufficient to detect at least a version 1.4 fig file.
Move some variables with file scope into functions.
This commit fixes tickets #58, #59, #61, #62, #67, #78 and #79.
In fig2dev/lib/, replacements are provided for some library functions used in
fig2dev, e.g., strncasecmp(), strrchr(), etc. The getline() function was
introduced more recently than any of the functions provided in fig2dev/lib.
Nevertheless, for getline() a replacement function is not provided. It seems,
that all the replacement functions do not work, but nobody noticed. Therefore,
only provide a replacement function for getline() if that turns out to
be useful.
The replacement functions do not work, because a header file providing the
necessary function declarations is missing.
---
configure.ac | 3 +-
fig2dev/fig2dev.c | 4 +-
fig2dev/fig2dev.h | 4 +-
fig2dev/read.c | 904 +++++++++++++++++++++++-------------------
fig2dev/read1_3.c | 12 +-
fig2dev/tests/read.at | 29 +-
6 files changed, 533 insertions(+), 423 deletions(-)
diff --git a/configure.ac b/configure.ac
index 8e955ee..881a39d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,7 +5,7 @@ AC_COPYRIGHT([Fig2dev: Translate Fig code to various Devices
Copyright (c) 1991 by Micah Beck
Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
Parts Copyright (c) 1989-2015 by Brian V. Smith
-Parts Copyright (c) 2015-2019 by Thomas Loimer
+Parts Copyright (c) 2015-2020 by Thomas Loimer
Any party obtaining a copy of these files is granted, free of charge, a
full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -327,6 +327,7 @@ dnl Just provide our own pi
# example.
AC_HEADER_STDBOOL
AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
#
# Checks for library functions.
diff --git a/fig2dev/fig2dev.c b/fig2dev/fig2dev.c
index d8c5e2a..62ec099 100644
--- a/fig2dev/fig2dev.c
+++ b/fig2dev/fig2dev.c
@@ -3,7 +3,7 @@
* Copyright (c) 1991 by Micah Beck
* Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
* Parts Copyright (c) 1989-2015 by Brian V. Smith
- * Parts Copyright (c) 2015-2019 by Thomas Loimer
+ * Parts Copyright (c) 2015-2020 by Thomas Loimer
*
* Any party obtaining a copy of these files is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -83,7 +83,7 @@ bool bgspec = false; /* flag to say -g was specified */
bool support_i18n = false;
#endif
char gif_transparent[20]="\0"; /* GIF transp color hex name (e.g. #ff00dd) */
-char papersize[20]; /* paper size */
+char papersize[]; /* paper size */
char boundingbox[64]; /* boundingbox */
char lang[40]; /* selected output language */
RGB background; /* background (if specified by -g) */
diff --git a/fig2dev/fig2dev.h b/fig2dev/fig2dev.h
index 9b6515f..25cc86b 100644
--- a/fig2dev/fig2dev.h
+++ b/fig2dev/fig2dev.h
@@ -3,7 +3,7 @@
* Copyright (c) 1991 by Micah Beck
* Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
* Parts Copyright (c) 1989-2015 by Brian V. Smith
- * Parts Copyright (c) 2015-2019 by Thomas Loimer
+ * Parts Copyright (c) 2015-2020 by Thomas Loimer
*
* Any party obtaining a copy of these files is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -101,7 +101,7 @@ extern bool bgspec; /* flag to say -g was specified */
extern bool support_i18n;
#endif
extern char gif_transparent[];/* GIF transp color hex name (e.g. #ff00dd) */
-extern char papersize[]; /* paper size */
+extern char papersize[16]; /* paper size */
extern char boundingbox[]; /* boundingbox */
extern char lang[]; /* selected output language */
extern const char *Fig_color_names[]; /* hex names for Fig colors */
diff --git a/fig2dev/read.c b/fig2dev/read.c
index 9500091..aea9537 100644
--- a/fig2dev/read.c
+++ b/fig2dev/read.c
@@ -3,7 +3,7 @@
* Copyright (c) 1991 by Micah Beck
* Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
* Parts Copyright (c) 1989-2015 by Brian V. Smith
- * Parts Copyright (c) 2015-2019 by Thomas Loimer
+ * Parts Copyright (c) 2015-2020 by Thomas Loimer
*
* Any party obtaining a copy of these files is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -45,28 +45,34 @@ extern F_arrow *make_arrow(int type, int style, /* arrow.c */
User_color user_colors[MAX_USR_COLS]; /* fig2dev.h */
int user_col_indx[MAX_USR_COLS]; /* fig2dev.h */
int num_usr_cols; /* fig2dev.h */
-int num_object; /* read1_3.c */
/* flags, psfonts.h, genps.c */
int v2_flag; /* Protocol V2.0 or higher */
int v21_flag; /* Protocol V2.1 or higher */
int v30_flag; /* Protocol V3.0 or higher */
int v32_flag; /* Protocol V3.2 or higher */
-static void read_colordef(void);
-static F_ellipse *read_ellipseobject(void);
-static F_line *read_lineobject(FILE *fp);
-static F_text *read_textobject(FILE *fp);
-static F_spline *read_splineobject(FILE *fp);
-static F_arc *read_arcobject(FILE *fp);
-static F_compound *read_compoundobject(FILE *fp);
+static void read_colordef(char *line, int line_no);
+static F_ellipse *read_ellipseobject(char *line, int line_no);
+static F_line *read_lineobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static F_text *read_textobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static F_spline *read_splineobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static F_arc *read_arcobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static F_compound *read_compoundobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
static F_comment *attach_comments(void);
-static void count_lines_correctly(FILE *fp);
-static void init_pats_used(void);
-static int read_objects(FILE *fp, F_compound *obj);
-static int get_line(FILE *fp);
-static void skip_line(FILE *fp);
-static int backslash_count(char cp[], int start);
-static int save_comment(void);
+static void count_lines_correctly(FILE *fp, int *line_no);
+static void init_pats_used(void);
+static int read_objects(FILE *fp, F_compound *obj);
+static ssize_t get_line(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static void skip_line(FILE *fp);
+static ptrdiff_t backslash_count(const char *restrict cp,
+ ptrdiff_t start);
+
static char Err_incomp[] = "Incomplete %s object at line %d.";
static char Err_invalid[] = "Invalid %s object at line %d.";
static char Err_arrow[] = "Invalid %s arrow at line %d.";
@@ -77,9 +83,6 @@ static char Err_arrow[] = "Invalid %s arrow at line %d.";
/* max number of comments that can be stored with each object */
#define MAXCOMMENTS 100
-static int gif_colnum = 0;
-static char buf[BUFSIZ];
-static int line_no = 0;
static char *comments[MAXCOMMENTS]; /* comments saved for current object */
static int numcom; /* current comment index */
static bool com_alloc = false; /* whether or not the comment array
@@ -148,7 +151,6 @@ readfp_fig(FILE *fp, F_compound *obj)
char c;
int i, status;
- num_object = 0;
num_usr_cols = 0;
init_pats_used();
@@ -157,15 +159,14 @@ readfp_fig(FILE *fp, F_compound *obj)
/* initialize the comment array */
if (!com_alloc)
for (i = 0; i < MAXCOMMENTS; ++i)
- comments[i] = (char *) NULL;
+ comments[i] = (char *)NULL;
com_alloc = true;
- memset((char*)obj, '\0', COMOBJ_SIZE);
+ memset((void *)obj, '\0', COMOBJ_SIZE);
/* read first character to see if it is "#" (#FIG 1.4 and newer) */
c = fgetc(fp);
if (feof(fp))
return -2;
- memset((char*)obj, '\0', COMOBJ_SIZE);
/* put the character back */
ungetc(c, fp);
if (c == '#')
@@ -185,25 +186,30 @@ read_objects(FILE *fp, F_compound *obj)
F_spline *s, *ls = NULL;
F_arc *a, *la = NULL;
F_compound *c, *lc = NULL;
- int object, coord_sys, len;
-
- memset((char*)obj, '\0', COMOBJ_SIZE);
-
- (void) fgets(buf, BUFSIZ, fp); /* get the version line */
- if (strncmp(buf, "#FIG ", 5)) {
- put_msg("Incorrect format string in first line of input file.");
+ bool objects = false;
+ int object, coord_sys;
+ int line_no;
+ int gif_colnum = 0;
+ char *line;
+ char buf[16];
+ size_t line_len = 256;
+
+ /* Get the 15 chars of the first line.
+ Use fgets(), because get_line() would store the line as a comment */
+ if (fgets(buf, sizeof buf, fp) == NULL) {
+ put_msg("Could not read input file.");
return -1;
}
+ /* seek to the end of the first line */
+ if (strchr(buf, '\n') == NULL) {
+ int c;
+ do
+ c = fgetc(fp);
+ while (c != '\n' && c != EOF);
+ }
- /* remove newline and any carriage return (from a PC, perhaps) */
- len = strlen(buf);
- if (buf[len-1] == '\n') {
- if (buf[len-2] == '\r')
- buf[len-2] = '\0';
- else
- buf[len-1] = '\0';
- } else { /* fgets() only stops at newline and end-of-file */
- put_msg("File is truncated at first line.");
+ if (strncmp(buf, "#FIG ", 5)) {
+ put_msg("Incorrect format string in first line of input file.");
return -1;
}
@@ -211,49 +217,65 @@ read_objects(FILE *fp, F_compound *obj)
v2_flag = (!strncmp(buf, "#FIG 2", 6) || !strncmp(buf, "#FIG 3", 6));
/* v21_flag is for version 2.1 or higher */
v21_flag = (!strncmp(buf, "#FIG 2.1", 8) || !strncmp(buf, "#FIG 3", 6));
- /* version 2.2 was only beta - 3.0 is the official release (they are identical) */
+ /* version 2.2 was only beta - 3.0 is the official release
+ (they are identical) */
v30_flag = (!strncmp(buf, "#FIG 3", 6) || !strncmp(buf, "#FIG 2.2", 8));
- /* version 3.2 contains paper size, magnif, multiple page and transparent color
- in Fig file */
+ /* version 3.2 contains paper size, magnif, multiple page
+ and transparent color in Fig file */
v32_flag = (!strncmp(buf, "#FIG 3.2", 8));
if (strncmp(&buf[5], PACKAGE_VERSION, 3) > 0) {
- put_msg("Fig file format (%s) newer than this version of fig2dev (%s), exiting",
- &buf[5], PACKAGE_VERSION);
- exit(1);
+ put_msg("Fig file format (%s) newer than this version of fig2dev (%s), exiting",
+ &buf[5], PACKAGE_VERSION);
+ exit(EXIT_FAILURE);
+ }
+
+ if ((v2_flag | v21_flag | v30_flag | v32_flag) == 0 &&
+ strncmp(buf, "#FIG 1.4", 8)) {
+ put_msg("Cannot determine fig file format from string '%s'.",
+ &buf[5]);
+ exit(EXIT_FAILURE);
+ }
+
+ if ((line = malloc(line_len)) == NULL) {
+ put_msg(Err_mem);
+ return -1;
}
+ line_no = 1;
if (v30_flag) {
/* read the orientation spec (landscape/portrait) */
- line_no=1;
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at landscape/portrait specification.");
+ free(line);
return -1;
}
/* but set only if the user didn't specify the orientation
on the command line */
if (!orientspec)
- landscape = !strncasecmp(buf,"land",4);
+ landscape = !strncasecmp(line, "land", 4);
/* now read the metric/inches spec OR centering spec */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at metric/inches or centering specification.");
+ free(line);
return -1;
}
/* read justification spec */
- if ((strncasecmp(buf,"center",6) == 0) ||
- (strncasecmp(buf,"flush",5) == 0)) {
+ if ((strncasecmp(line, "center", 6) == 0) ||
+ (strncasecmp(line, "flush", 5) == 0)) {
/* but set only if user didn't specify it */
if (!centerspec)
- center = strncasecmp(buf,"flush",5);
+ center = strncasecmp(line, "flush", 5);
/* now read metric/inches spec */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at metric/inches specification.");
+ free(line);
return -1;
}
}
/* read metric/inches spec */
/* if metric, scale magnification to correct for xfig display error */
- if (strncasecmp(buf,"metric", 6) == 0) {
+ if (strncasecmp(line, "metric", 6) == 0) {
metric = 1;
} else {
metric = 0;
@@ -261,56 +283,67 @@ read_objects(FILE *fp, F_compound *obj)
/* new stuff in 3.2 */
if (v32_flag) {
- char *p;
/* read the paper size */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at paper size specification.");
+ free(line);
return -1;
}
if (!paperspec) {
- strcpy(papersize,buf);
- /* and truncate at first blank, if any */
- if ((p=strchr(papersize,' ')))
+ char *p;
+ /* truncate at first blank, if any */
+ if ((p = strchr(line, ' ')))
*p = '\0';
+ if (strlen(line) + 1 > sizeof papersize) {
+ put_msg("Invalid paper size specification at line %d: %s",
+ line_no, line);
+ free(line);
+ return -1;
+ }
+ strcpy(papersize, line);
}
/* read the magnification */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at magnification specification.");
+ free(line);
return -1;
}
- /* if the users hasn't specified a magnification on the command line,
- use the one in the file */
+ /* if the users hasn't specified a magnification on
+ the command line, use the one in the file */
if (!magspec) {
- mag = atof(buf)/100.0;
+ mag = atof(line)/100.0;
if (mag <= 0.)
mag = 1.;
fontmag = mag;
}
/* read the multiple page flag */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at multiple page specification.");
+ free(line);
return -1;
}
if (!multispec)
- multi_page = (strncasecmp(buf,"multiple",8) == 0);
+ multi_page = (strncasecmp(line, "multiple", 8) == 0);
/* Read the GIF transparent color. */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at transparent color specification.");
+ free(line);
return -1;
}
if (!transspec) {
- gif_colnum = atoi(buf);
+ gif_colnum = atoi(line);
if (gif_colnum < -3) {
put_msg("Invalid color number for transparent color.");
+ free(line);
return -1;
}
/* if standard color, get the name from the array */
/* for user colors, wait till we've read in the file to get the value */
if (gif_colnum < NUM_STD_COLS && gif_colnum >= 0)
- strcpy(gif_transparent,Fig_color_names[gif_colnum]);
+ strcpy(gif_transparent, Fig_color_names[gif_colnum]);
}
}
} else {
@@ -329,17 +362,20 @@ read_objects(FILE *fp, F_compound *obj)
}
/* now read for resolution and coord_sys (coord_sys is not used) */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at resolution specification.");
+ free(line);
return -1;
}
- if (sscanf(buf,"%lf%d\n", &ppi, &coord_sys) != 2) {
+ if (sscanf(line, "%lf%d", &ppi, &coord_sys) != 2) {
put_msg("Incomplete resolution information at line %d.", line_no);
+ free(line);
return -1;
}
if (ppi <= 0.) {
put_msg("Invalid resolution information (%g) at line %d.",
ppi, line_no);
+ free(line);
return -1;
}
@@ -349,24 +385,28 @@ read_objects(FILE *fp, F_compound *obj)
/* attach any comments found thus far to the whole figure */
obj->comments = attach_comments();
- while (get_line(fp) > 0) {
- if (sscanf(buf, "%d", &object) != 1) {
+ while (get_line(fp, &line, &line_len, &line_no) > 0) {
+ if (sscanf(line, "%d", &object) != 1) {
put_msg("Incorrect format at line %d.", line_no);
+ free(line);
return -1;
}
switch (object) {
case OBJ_COLOR_DEF:
- read_colordef();
- if (num_object) {
+ if (objects) {
put_msg("Color definitions must come before other objects (line %d).",
line_no);
- return (-1);
+ free(line);
+ return -1;
}
- ++num_usr_cols;
+ read_colordef(line, line_no);
break;
case OBJ_POLYLINE :
- if ((l = read_lineobject(fp)) == NULL)
+ if ((l = read_lineobject(fp, &line, &line_len, &line_no)) ==
+ NULL) {
+ free(line);
return -1;
+ }
#ifdef V4_0
if ((l->pic != NULL) && (l->pic->figure != NULL)) {
if (lc)
@@ -388,79 +428,97 @@ read_objects(FILE *fp, F_compound *obj)
ll = (ll->next = l);
else
ll = obj->lines = l;
- num_object++;
+ objects = true;
break;
#endif /* V4_0 */
case OBJ_SPLINE :
- if ((s = read_splineobject(fp)) == NULL) {
+ if ((s = read_splineobject(fp, &line, &line_len, &line_no))
+ == NULL) {
+ free(line);
return -1;
- }
+ }
if (v32_flag){ /* s is a line */
if (ll)
ll = (ll->next = (F_line *) s);
else
ll = obj->lines = (F_line *) s;
- num_object++;
+ objects = true;
break;
}
if (ls)
ls = (ls->next = s);
else
ls = obj->splines = s;
- num_object++;
+ objects = true;
break;
case OBJ_ELLIPSE :
- if ((e = read_ellipseobject()) == NULL)
+ if ((e = read_ellipseobject(line, line_no)) == NULL) {
+ free(line);
return -1;
+ }
if (le)
le = (le->next = e);
else
le = obj->ellipses = e;
- num_object++;
+ objects = true;
break;
case OBJ_ARC :
- if ((a = read_arcobject(fp)) == NULL)
+ if ((a = read_arcobject(fp, &line, &line_len, &line_no)) ==
+ NULL) {
+ free(line);
return -1;
+ }
if (la)
la = (la->next = a);
else
la = obj->arcs = a;
- num_object++;
+ objects = true;
break;
case OBJ_TEXT :
- if ((t = read_textobject(fp)) == NULL)
+ if ((t = read_textobject(fp, &line, &line_len, &line_no)) ==
+ NULL) {
+ free(line);
return -1;
+ }
if (lt)
lt = (lt->next = t);
else
lt = obj->texts = t;
- num_object++;
+ objects = true;
break;
case OBJ_COMPOUND :
- if ((c = read_compoundobject(fp)) == NULL)
+ if ((c = read_compoundobject(fp, &line, &line_len,&line_no))
+ == NULL) {
+ free(line);
return -1;
+ }
if (lc)
lc = (lc->next = c);
else
lc = obj->compounds = c;
- num_object++;
+ objects = true;
break;
default :
put_msg("Incorrect object code at line %d.", line_no);
+ free(line);
return -1;
} /* switch */
- } /* while (get_line(fp)) */
+ } /* while (get_line(...)) */
+ free(line);
/* if user color was requested for GIF transparent color, get the
rgb values from the user color array now that we've read them in */
if (gif_colnum >= NUM_STD_COLS) {
int i;
- for (i=0; i<num_usr_cols; ++i)
+ /* read_colordef() counted, but ignored too many user colors */
+ if (num_usr_cols > MAX_USR_COLS)
+ num_usr_cols = MAX_USR_COLS;
+ for (i=0; i < num_usr_cols; ++i)
if (user_col_indx[i] == gif_colnum)
break;
if (i < num_usr_cols)
- sprintf(gif_transparent,"#%2x%2x%2x",
- user_colors[i].r,user_colors[i].g,user_colors[i].b);
+ sprintf(gif_transparent, "#%2x%2x%2x",
+ user_colors[i].r, user_colors[i].g, user_colors[i].b);
}
if (feof(fp))
@@ -474,55 +532,72 @@ read_objects(FILE *fp, F_compound *obj)
} /* read_objects */
static void
-read_colordef(void)
+read_colordef(char *line, int line_no)
{
- int c;
- unsigned int r,g,b;
-
- if ((sscanf(buf, "%*d %d #%2x%2x%2x", &c, &r, &g, &b) != 4) ||
- (c < NUM_STD_COLS)) {
- buf[strlen(buf)-1]='\0'; /* remove the newline */
- put_msg("Invalid color definition: %s, setting to black (#00000).",buf);
- r=g=b=0;
- }
- user_col_indx[num_usr_cols] = c;
- user_colors[num_usr_cols].r = r;
- user_colors[num_usr_cols].g = g;
- user_colors[num_usr_cols].b = b;
+ int c;
+ unsigned int r,g,b;
+
+ if (num_usr_cols >= MAX_USR_COLS) {
+ if (num_usr_cols == MAX_USR_COLS) {
+ put_msg("Maximum number of color definitions (%d) exceeded at line %d.",
+ MAX_USR_COLS, line_no);
+ ++num_usr_cols;
+ }
+ /* ignore additional colors */
+ return;
+ }
+ if (sscanf(line, "%*d %d #%2x%2x%2x", &c, &r, &g, &b) != 4) {
+ if (c >= NUM_STD_COLS && c < NUM_STD_COLS + MAX_USR_COLS) {
+ put_msg("Invalid color definition at line %d: %s, setting to black (#00000).",
+ line_no, line);
+ r = g = b = 0;
+ } else {
+ put_msg("User color number at line %d out of range (%d), should be between %d and %d.",
+ line_no, c, NUM_STD_COLS,
+ NUM_STD_COLS + MAX_USR_COLS - 1);
+ return;
+ }
+ }
+ user_col_indx[num_usr_cols] = c;
+ user_colors[num_usr_cols].r = r;
+ user_colors[num_usr_cols].g = g;
+ user_colors[num_usr_cols].b = b;
+ ++num_usr_cols;
}
static void
-fix_and_note_color(int *color)
+fix_and_note_color(int *color, int line_no)
{
- int i;
- if (*color < DEFAULT) {
- put_msg("Invalid color number %d at line %d, using default color.",
- *color, line_no);
- *color = DEFAULT;
- return;
- }
- if (*color < NUM_STD_COLS) {
- if (*color >= BLACK_COLOR) {
- std_color_used[*color] = true;
+ int i;
+
+ if (*color < DEFAULT) {
+ put_msg("Invalid color number %d at line %d, using default color.",
+ *color, line_no);
+ *color = DEFAULT;
+ return;
}
- return;
- }
- for (i=0; i<num_usr_cols; ++i)
- if (*color == user_col_indx[i]) {
- *color = i + NUM_STD_COLS;
+ if (*color < NUM_STD_COLS) {
+ if (*color >= BLACK_COLOR) {
+ std_color_used[*color] = true;
+ }
return;
}
- put_msg("Cannot locate user color %d, using default color at line %d.",
- *color, line_no);
- *color = DEFAULT;
- return;
+ for (i = 0; i < MIN(num_usr_cols, MAX_USR_COLS); ++i)
+ if (*color == user_col_indx[i]) {
+ *color = i + NUM_STD_COLS;
+ return;
+ }
+ put_msg("Cannot locate user color %d, using default color at line %d.",
+ *color, line_no);
+ *color = DEFAULT;
+ return;
}
static void
-note_fill(int fill, int *color)
+note_fill(int fill, int *color, int line_no)
{
if (fill != UNFILLED) {
- fix_and_note_color(color);
+ fix_and_note_color(color, line_no);
if (fill >= NUMSHADES + NUMTINTS) {
pattern_used[fill - NUMSHADES - NUMTINTS] = true;
pats_used = true;
@@ -531,7 +606,7 @@ note_fill(int fill, int *color)
}
static F_arc *
-read_arcobject(FILE *fp)
+read_arcobject(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
{
F_arc *a;
int n, fa, ba;
@@ -548,7 +623,7 @@ read_arcobject(FILE *fp)
a->back_arrow = NULL;
a->next = NULL;
if (v30_flag) {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%lf%lf%d%d%d%d%d%d\n",
+ n = sscanf(*line,"%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%lf%lf%d%d%d%d%d%d",
&a->type, &a->style, &a->thickness,
&a->pen_color, &a->fill_color, &a->depth, &a->pen, &a->fill_style,
&a->style_val, &a->cap_style,
@@ -558,7 +633,7 @@ read_arcobject(FILE *fp)
&a->point[1].x, &a->point[1].y,
&a->point[2].x, &a->point[2].y);
} else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d%d%lf%lf%d%d%d%d%d%d\n",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d%d%lf%lf%d%d%d%d%d%d",
&a->type, &a->style, &a->thickness,
&a->pen_color, &a->depth, &a->pen, &a->fill_style,
&a->style_val, &a->direction, &fa, &ba,
@@ -570,45 +645,45 @@ read_arcobject(FILE *fp)
a->cap_style = 0; /* butt line cap */
}
if ((v30_flag && n != 21) || (!v30_flag && n != 19)) {
- put_msg(Err_incomp, "arc", line_no);
+ put_msg(Err_incomp, "arc", *line_no);
free(a);
return NULL;
}
a->thickness *= round(THICK_SCALE);
a->fill_style = FILL_CONVERT(a->fill_style);
if (INVALID_ARC(a)) {
- put_msg(Err_invalid, "arc", line_no);
+ put_msg(Err_invalid, "arc", *line_no);
free(a);
return NULL;
}
- fix_and_note_color(&a->pen_color);
- note_fill(a->fill_style, &a->fill_color);
+ fix_and_note_color(&a->pen_color, *line_no);
+ note_fill(a->fill_style, &a->fill_color, *line_no);
if (fa) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "arc", line_no);
+ put_msg(Err_incomp, "arc", *line_no);
free(a);
return NULL;
}
if ((a->for_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "forward", line_no);
+ put_msg(Err_arrow, "forward", *line_no);
free(a);
return NULL;
}
}
if (ba) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "arc", line_no);
+ put_msg(Err_incomp, "arc", *line_no);
free(a);
return NULL;
}
if ((a->back_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "backward", line_no);
+ put_msg(Err_arrow, "backward", *line_no);
free(a);
return NULL;
}
@@ -618,7 +693,8 @@ read_arcobject(FILE *fp)
}
static F_compound *
-read_compoundobject(FILE *fp)
+read_compoundobject(FILE *fp, char **restrict line, size_t *line_len,
+ int *line_no)
{
F_arc *a, *la = NULL;
F_ellipse *e, *le = NULL;
@@ -638,22 +714,23 @@ read_compoundobject(FILE *fp)
com->next = NULL;
com->comments = attach_comments(); /* attach any comments */
- n = sscanf(buf, "%*d%d%d%d%d\n", &com->nwcorner.x, &com->nwcorner.y,
+ n = sscanf(*line, "%*d%d%d%d%d", &com->nwcorner.x, &com->nwcorner.y,
&com->secorner.x, &com->secorner.y);
if (n != 4) {
- put_msg(Err_incomp, "compound", line_no);
+ put_msg(Err_incomp, "compound", *line_no);
free(com);
return NULL;
}
- while (get_line(fp) > 0) {
- if (sscanf(buf, "%d", &object) != 1) {
- put_msg(Err_incomp, "compound", line_no);
+ while (get_line(fp, line, line_len, line_no) > 0) {
+ if (sscanf(*line, "%d", &object) != 1) {
+ put_msg(Err_incomp, "compound", *line_no);
free_compound(&com);
return NULL;
- }
+ }
switch (object) {
case OBJ_POLYLINE :
- if ((l = read_lineobject(fp)) == NULL) {
+ if ((l = read_lineobject(fp, line, line_len, line_no)) ==
+ NULL) {
return NULL;
}
#ifdef V4_0
@@ -674,7 +751,8 @@ read_compoundobject(FILE *fp)
#endif /* V4_0 */
break;
case OBJ_SPLINE :
- if ((s = read_splineobject(fp)) == NULL) {
+ if ((s = read_splineobject(fp, line, line_len, line_no)) ==
+ NULL) {
return NULL;
}
if (v32_flag){ /* s is a line */
@@ -690,7 +768,7 @@ read_compoundobject(FILE *fp)
ls = com->splines = s;
break;
case OBJ_ELLIPSE :
- if ((e = read_ellipseobject()) == NULL) {
+ if ((e = read_ellipseobject(*line, *line_no)) == NULL) {
return NULL;
}
if (le)
@@ -699,7 +777,8 @@ read_compoundobject(FILE *fp)
le = com->ellipses = e;
break;
case OBJ_ARC :
- if ((a = read_arcobject(fp)) == NULL) {
+ if ((a = read_arcobject(fp, line, line_len, line_no)) ==
+ NULL) {
return NULL;
}
if (la)
@@ -708,7 +787,8 @@ read_compoundobject(FILE *fp)
la = com->arcs = a;
break;
case OBJ_TEXT :
- if ((t = read_textobject(fp)) == NULL) {
+ if ((t = read_textobject(fp, line, line_len, line_no)) ==
+ NULL) {
return NULL;
}
if (lt)
@@ -717,7 +797,8 @@ read_compoundobject(FILE *fp)
lt = com->texts = t;
break;
case OBJ_COMPOUND :
- if ((c = read_compoundobject(fp)) == NULL) {
+ if ((c = read_compoundobject(fp, line, line_len, line_no))
+ == NULL) {
return NULL;
}
if (lc)
@@ -728,7 +809,7 @@ read_compoundobject(FILE *fp)
case OBJ_END_COMPOUND :
return com;
default :
- put_msg("Wrong object code at line %d", line_no);
+ put_msg("Wrong object code at line %d", *line_no);
return NULL;
} /* switch */
}
@@ -739,7 +820,7 @@ read_compoundobject(FILE *fp)
}
static F_ellipse *
-read_ellipseobject(void)
+read_ellipseobject(char *line, int line_no)
{
F_ellipse *e;
int n;
@@ -749,7 +830,7 @@ read_ellipseobject(void)
e->pen = 0;
e->next = NULL;
if (v30_flag) {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d\n",
+ n = sscanf(line, "%*d%d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d",
&e->type, &e->style, &e->thickness,
&e->pen_color, &e->fill_color, &e->depth, &e->pen, &e->fill_style,
&e->style_val, &e->direction, &e->angle,
@@ -758,7 +839,7 @@ read_ellipseobject(void)
&e->start.x, &e->start.y,
&e->end.x, &e->end.y);
} else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d\n",
+ n = sscanf(line, "%*d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d",
&e->type, &e->style, &e->thickness,
&e->pen_color, &e->depth, &e->pen, &e->fill_style,
&e->style_val, &e->direction, &e->angle,
@@ -773,7 +854,7 @@ read_ellipseobject(void)
free(e);
return NULL;
}
- fix_and_note_color(&e->pen_color);
+ fix_and_note_color(&e->pen_color, line_no);
e->thickness *= round(THICK_SCALE);
e->fill_style = FILL_CONVERT(e->fill_style);
if (e->radiuses.x < 0)
@@ -785,7 +866,7 @@ read_ellipseobject(void)
free(e);
return NULL;
}
- note_fill(e->fill_style, &e->fill_color);
+ note_fill(e->fill_style, &e->fill_color, line_no);
e->comments = attach_comments(); /* attach any comments */
return e;
}
@@ -804,8 +885,9 @@ read_ellipseobject(void)
*/
static int
sanitize_lineobject(
- F_line *l, /* the line */
- F_point *p /* the last point of the line */
+ F_line *l, /* the line */
+ F_point *p, /* the last point of the line */
+ int line_no
)
{
F_point *q;
@@ -912,7 +994,7 @@ sanitize_lineobject(
}
static F_line *
-read_lineobject(FILE *fp)
+read_lineobject(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
{
F_line *l;
F_point *o = NULL, *p, *q;
@@ -933,40 +1015,38 @@ read_lineobject(FILE *fp)
l->pic = NULL;
l->comments = NULL;
- sscanf(buf,"%*d%d",&l->type); /* get the line type */
+ sscanf(*line, "%*d%d", &l->type); /* get the line type */
radius_flag = v30_flag || v21_flag || (v2_flag && l->type == T_ARC_BOX);
if (radius_flag) {
if (v30_flag) {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%d%d",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%d%d",
&l->type,&l->style,&l->thickness,&l->pen_color,&l->fill_color,
&l->depth,&l->pen,&l->fill_style,&l->style_val,
&l->join_style,&l->cap_style,
&l->radius,&fa,&ba,&npts);
} else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d%d",
- &l->type,&l->style,&l->thickness,&l->pen_color,
- &l->depth,&l->pen,&l->fill_style,&l->style_val,&l->radius,&fa, &ba);
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d%d",
+ &l->type,&l->style,&l->thickness,&l->pen_color,&l->depth,
+ &l->pen,&l->fill_style,&l->style_val,&l->radius,&fa, &ba);
l->fill_color = l->pen_color;
}
}
/* old format uses pen for radius of arc-box corners */
else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d",
&l->type,&l->style,&l->thickness,&l->pen_color,
&l->depth,&l->pen,&l->fill_style,&l->style_val,&fa,&ba);
l->fill_color = l->pen_color;
- if (l->type == T_ARC_BOX)
- {
- l->radius = (int) l->pen;
+ if (l->type == T_ARC_BOX) {
+ l->radius = l->pen;
l->pen = 0;
- }
- else
+ } else
l->radius = 0;
}
if ((!radius_flag && n!=10) ||
(radius_flag && ((!v30_flag && n!=11)||(v30_flag && n!=15)))) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free(l);
return NULL;
}
@@ -974,45 +1054,47 @@ read_lineobject(FILE *fp)
l->thickness *= round(THICK_SCALE);
l->fill_style = FILL_CONVERT(l->fill_style);
if (INVALID_LINE(l)) {
- put_msg(Err_invalid, "line", line_no);
+ put_msg(Err_invalid, "line", *line_no);
free(l);
return NULL;
}
- note_fill(l->fill_style, &l->fill_color);
- fix_and_note_color(&l->pen_color);
+ note_fill(l->fill_style, &l->fill_color, *line_no);
+ fix_and_note_color(&l->pen_color, *line_no);
if (fa) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free(l);
return NULL;
}
if ((l->for_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "forward", line_no);
+ put_msg(Err_arrow, "forward", *line_no);
free(l);
return NULL;
}
}
if (ba) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free_linestorage(l);
return NULL;
}
if ((l->back_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "backward", line_no);
+ put_msg(Err_arrow, "backward", *line_no);
free_linestorage(l);
return NULL;
}
}
if (l->type == T_PIC_BOX) {
- char file[BUFSIZ], *c;
+ char *file, *c;
+ int pos;
size_t len;
+ ssize_t chars;
if ((Pic_malloc(l->pic)) == NULL) {
free(l);
@@ -1026,21 +1108,22 @@ read_lineobject(FILE *fp)
XpmCreateXpmImageFromBuffer("", &l->pic->xpmimage, NULL);
#endif
- /* %[^\n]: really, read until first '\0' in buf */
- if (get_line(fp) < 0 || sscanf(buf, "%d %[^\n]",
- &l->pic->flipped, file) != 2) {
- put_msg(Err_incomp, "picture", line_no);
- free(l);
- return NULL;
+ if ((chars = get_line(fp, line, line_len, line_no)) < 0 ||
+ sscanf(*line, "%d %n", &l->pic->flipped, &pos) != 1) {
+ put_msg(Err_incomp, "picture", *line_no);
+ free(l);
+ return NULL;
}
+ file = *line + pos;
+ len = chars - pos; /* strlen(file) */
+
/* if there is a path in the .fig filename, and the path of the
* imported picture filename is NOT absolute, prepend the
* .fig file path to it
*/
if (from && (c = strrchr(from, '/')) && file[0] != '/') {
- if ((l->pic->file = malloc((size_t)(c - from + 2) +
- (len = strlen(file)))) ==
- NULL) {
+ if ((l->pic->file = malloc((size_t)(c - from + 2) + len)) ==
+ NULL) {
put_msg(Err_mem);
free(l); /* Points not read yet. */
return NULL;
@@ -1049,8 +1132,8 @@ read_lineobject(FILE *fp)
memcpy(l->pic->file + (c - from + 1), file, len + 1);
} else {
/* either absolute picture path or no path in .fig filename */
- l->pic->file = malloc(len = strlen(file) + 1);
- memcpy(l->pic->file, file, len);
+ l->pic->file = malloc(len + 1);
+ memcpy(l->pic->file, file, len + 1);
}
}
@@ -1062,9 +1145,9 @@ read_lineobject(FILE *fp)
p->next = NULL;
/* read first point of line */
- ++line_no;
+ ++(*line_no);
if (fscanf(fp, "%d%d", &p->x, &p->y) != 2) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free_linestorage(l);
return NULL;
}
@@ -1072,9 +1155,9 @@ read_lineobject(FILE *fp)
if (!v30_flag)
npts = 1000000;
for (--npts; npts > 0; --npts) {
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if (fscanf(fp, "%d%d", &x, &y) != 2) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free_linestorage(l);
return NULL;
}
@@ -1103,7 +1186,7 @@ read_lineobject(FILE *fp)
l->last[1].y = o->y;
}
- if (sanitize_lineobject(l, p)) {
+ if (sanitize_lineobject(l, p, *line_no)) {
free_linestorage(l);
return NULL;
}
@@ -1115,7 +1198,8 @@ read_lineobject(FILE *fp)
}
static F_spline *
-read_splineobject(FILE *fp)
+read_splineobject(FILE *fp, char **restrict line, size_t *line_len,
+ int *line_no)
{
F_spline *s;
F_line *l;
@@ -1137,58 +1221,58 @@ read_splineobject(FILE *fp)
s->next = NULL;
if (v30_flag) {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d",
&s->type, &s->style, &s->thickness,
&s->pen_color, &s->fill_color,
&s->depth, &s->pen, &s->fill_style, &s->style_val,
&s->cap_style, &fa, &ba, &npts);
} else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d",
&s->type, &s->style, &s->thickness, &s->pen_color,
&s->depth, &s->pen, &s->fill_style, &s->style_val, &fa, &ba);
s->fill_color = s->pen_color;
s->cap_style = 0; /* butt line cap */
}
if ((v30_flag && n != 13) || (!v30_flag && n != 10)) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free(s);
return NULL;
}
s->thickness *= round(THICK_SCALE);
s->fill_style = FILL_CONVERT(s->fill_style);
if (INVALID_SPLINE(s)) {
- put_msg(Err_invalid, "spline", line_no);
+ put_msg(Err_invalid, "spline", *line_no);
free(s);
return NULL;
}
- note_fill(s->fill_style, &s->fill_color);
- fix_and_note_color(&s->pen_color);
+ note_fill(s->fill_style, &s->fill_color, *line_no);
+ fix_and_note_color(&s->pen_color, *line_no);
if (fa) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free(s);
return NULL;
}
if ((s->for_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "forward", line_no);
+ put_msg(Err_arrow, "forward", *line_no);
free(s);
return NULL;
}
}
if (ba) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
}
if ((s->back_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "backward", line_no);
+ put_msg(Err_arrow, "backward", *line_no);
free_splinestorage(s);
return NULL;
}
@@ -1196,9 +1280,9 @@ read_splineobject(FILE *fp)
/* Read points */
/* read first point of line */
- ++line_no;
+ ++(*line_no);
if ((n = fscanf(fp, "%d%d", &x, &y)) != 2) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
};
@@ -1212,15 +1296,15 @@ read_splineobject(FILE *fp)
if (!v30_flag)
npts = 1000000;
if (npts < 2) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
}
for (--npts; npts > 0; --npts) {
/* keep track of newlines for line counter */
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if (fscanf(fp, "%d%d", &x, &y) != 2) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
};
@@ -1250,9 +1334,9 @@ read_splineobject(FILE *fp)
ptr = s->controls;
while (ptr) { /* read controls */
/* keep track of newlines for line counter */
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if ((n = fscanf(fp, "%lf", &control_s)) != 1) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
}
@@ -1275,9 +1359,9 @@ read_splineobject(FILE *fp)
}
/* Read controls from older versions */
/* keep track of newlines for line counter */
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if ((n = fscanf(fp, "%lf%lf%lf%lf", &lx, &ly, &rx, &ry)) != 4) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
}
@@ -1290,9 +1374,9 @@ read_splineobject(FILE *fp)
cp->rx = rx; cp->ry = ry;
while (--c) {
/* keep track of newlines for line counter */
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if (fscanf(fp, "%lf%lf%lf%lf", &lx, &ly, &rx, &ry) != 4) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
cp->next = NULL;
free_splinestorage(s);
return NULL;
@@ -1315,13 +1399,37 @@ read_splineobject(FILE *fp)
return s;
}
+static char *
+find_end(const char *str, int v30flag)
+{
+ const char endmark[] = "\\001";
+ char *end;
+
+ if (v30flag) {
+ /* A string is terminated with the literal '\001',
+ and 8-bit characters may be represented as \xxx */
+ end = strstr(str, endmark);
+ /* is this not '\\001', or '\\\\001', etc? */
+ while (end && backslash_count(str, end - str) % 2 == 0)
+ end = strstr(end + 3, endmark);
+ } else {
+ /* The text object is terminated by a CONTROL-A.
+ If there is no CONTROL-A on this line, then this
+ must be a multi-line text object. */
+ end = strchr(str, '\1');
+ }
+ return end;
+}
+
+
static F_text *
-read_textobject(FILE *fp)
+read_textobject(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
{
F_text *t;
- int n, ignore = 0;
- char s[BUFSIZ], s_temp[BUFSIZ], junk[2];
- int more, len, l;
+ bool freestart = false;
+ int i, n;
+ char *end, *start;
+ size_t len;
Text_malloc(t);
t->font = 0;
@@ -1329,32 +1437,101 @@ read_textobject(FILE *fp)
t->comments = NULL;
t->next = NULL;
- if (v30_flag) { /* order of parms is more like other objects now,
- string is now terminated with the literal '\001',
- and 8-bit characters are represented as \xxx */
+ n = sscanf(*line, "%*d%d%d%d%d%d%lf%lf%d%lf%lf%d%d %n",
+ &t->type, &t->color, &t->depth, &t->pen, &t->font,
+ &t->size, &t->angle, &t->flags, &t->height, &t->length,
+ &t->base_x, &t->base_y, &i);
+ if (n != 12) {
+ put_msg(Err_incomp, "text", *line_no);
+ free(t);
+ return NULL;
+ }
+ start = *line + i;
+ end = find_end(start, v30_flag);
- n = sscanf(buf, "%*d%d%d%d%d%d%lf%lf%d%lf%lf%d%d%[^\n]",
- &t->type, &t->color, &t->depth, &t->pen,
- &t->font, &t->size, &t->angle,
- &t->flags, &t->height, &t->length,
- &t->base_x, &t->base_y, s);
+ if (end) {
+ *end = '\0';
+ len = end - start;
} else {
- /* The text object is terminated by a CONTROL-A, so we read
- everything up to the CONTROL-A and then read that character.
- If we do not find the CONTROL-A on this line then this must
- be a multi-line text object and we will have to read more. */
-
- n = sscanf(buf,"%*d%d%d%lf%d%d%d%lf%d%lf%lf%d%d%[^\1]%1[\1]",
- &t->type, &t->font, &t->size, &t->pen,
- &t->color, &t->depth, &t->angle,
- &t->flags, &t->height, &t->length,
- &t->base_x, &t->base_y, s, junk);
+ ssize_t chars;
+ char *next;
+
+ len = strlen(start);
+ start[len++] = '\n'; /* put back the newline */
+
+ /* allocate plenty of space */
+ next = malloc(len + BUFSIZ);
+ if (next == NULL) {
+ put_msg(Err_mem);
+ free(t);
+ return NULL;
+ }
+ memcpy(next, start, len);
+
+ while ((chars = getline(line, line_len, fp)) != -1) {
+ ++(*line_no);
+ end = find_end(*line, v30_flag);
+ if (end) {
+ *end = '\0';
+ next = realloc(next, len + end - *line + 1);
+ memcpy(next + len, *line, end - *line + 1);
+ len += end - *line;
+ break;
+ } else {
+ if (**line + chars - 1 == '\n' && chars > 1 &&
+ **line + chars - 2 == '\r')
+ (*line)[chars-- - 2] = '\n';
+ next = realloc(next, len + chars + 1);
+ memcpy(next + len, *line, chars + 1);
+ len += chars;
+ }
+ }
+ start = next;
+ freestart = true;
+ }
+
+ /* convert any \xxx to characters */
+ if (v30_flag && (end = strchr(start, '\\'))) {
+ unsigned char num;
+ char *c = start;
+ size_t l;
+
+ len = end - start;
+ l = len;
+ while (c[l] != '\0') {
+ if (c[l] == '\\') {
+ /* convert 3 digit octal value */
+ if (isdigit(c[l+1]) && c[l+2] != '\0' &&
+ c[l+3] != '\0') {
+ if (sscanf(c+l+1, "%3hho", &num) != 1) {
+ put_msg("Error in parsing text string on line %d",
+ *line_no);
+ return NULL;
+ }
+ /* no check of unsigned char overflow */
+ c[len++] = num;
+ l += 3;
+ } else {
+ /* an escaped char is un-escaped */
+ c[len++] = c[++l];
+ }
+ } else {
+ c[len++] = c[l];
+ }
+ ++l;
+ }
+ c[len] = '\0'; /* terminate */
}
- if ((n != 14) && (n != 13)) {
- put_msg(Err_incomp, "text", line_no);
- free(t);
- return NULL;
+
+ t->cstring = malloc(len + 1);
+ if (t->cstring == NULL) {
+ put_msg(Err_mem);
+ free(t);
+ return NULL;
}
+ memcpy(t->cstring, start, len + 1);
+ if (freestart)
+ free(start);
if (font_size != 0.0) {
/* scale length/height of text by ratio of requested font size to actual size */
@@ -1364,89 +1541,6 @@ read_textobject(FILE *fp)
}
if (t->size <= 0.0)
t->size = (float) DEFAULT_FONT_SIZE;
- more = 0;
- if (!v30_flag && n == 13)
- more = 1; /* in older xfig there is more if ^A wasn't found yet */
- else if (v30_flag) { /* in 3.0 there is more if \001 wasn't found */
- len = strlen(s);
- if ((strcmp(&s[len-4],"\\001") == 0) && /* if we find '\000' */
- !(backslash_count(s, len-5) % 2)) { /* and not '\\000' */
- more = 0; /* then there are no more lines */
- s[len-4]='\0'; /* and get rid of the '\001' */
- } else {
- more = 1;
- s[len++]='\n'; /* put back the end of line char */
- s[len] = '\0'; /* and terminate it */
- }
- }
- if (more) {
- /* Read in the subsequent lines of the text if there are more */
- do {
- ++line_no; /* As is done in get_line */
- if (fgets(s_temp, BUFSIZ, fp) == NULL)
- break;
- len = strlen(s_temp)-1; /* ignore newline */
- if (len > 0 && s_temp[len-1] == '\r') { /* strip any trailing CR */
- s_temp[len-1] = '\0';
- len--;
- }
- if (v30_flag) {
- if ((strncmp(&s_temp[len-4],"\\001",4) == 0) &&
- !(backslash_count(s_temp, len-5) % 2)) {
- n=0; /* found the '\001', set n to stop */
- s_temp[len-4]='\0'; /* and get rid of the '\001' */
- } else {
- n=1; /* keep going (more lines) */
- }
- } else {
- n = sscanf(buf, "%[^\1]%[\1]", s_temp, junk);
- }
- /* Safety check */
- if (strlen(s)+1 + strlen(s_temp)+1 > BUFSIZ) {
- /* Too many characters. Ignore the rest. */
- ignore = 1;
- }
- if (!ignore)
- strcat(s, s_temp);
- } while (n == 1);
- }
-
- if (v30_flag) { /* now convert any \xxx to ascii characters */
- if (strchr(s,'\\')) {
- unsigned int num;
- len = strlen(s);
- for (l=0,n=0; l < len; ++l) {
- if (s[l]=='\\') {
- /* a backslash, see if a digit follows */
- if (l < len && isdigit(s[l+1])) {
- /* yes, scan for 3 digit octal value */
- if (sscanf(&s[l+1],"%3o",&num)!=1) {
- put_msg("Error in parsing text string on line %d",
- line_no);
- return NULL;
- }
- buf[n++]= (unsigned char) num; /* put char in */
- l += 3; /* skip over digits */
- } else {
- buf[n++] = s[++l]; /* some other escaped character */
- }
- } else {
- buf[n++] = s[l]; /* ordinary character */
- }
- }
- buf[n]='\0'; /* terminate */
- strcpy(s,buf); /* copy back to s */
- }
- }
- if (strlen(s) == 0)
- (void)strcpy(s, " ");
- t->cstring = calloc((unsigned)(strlen(s)), sizeof(char));
- if (NULL == t->cstring) {
- put_msg(Err_mem);
- free(t);
- return NULL;
- }
- (void)strcpy(t->cstring, s+1);
if (!v21_flag && (t->font == 0 || t->font == DEFAULT))
t->flags = ((t->flags != DEFAULT) ? t->flags : 0)
@@ -1457,11 +1551,11 @@ read_textobject(FILE *fp)
| PSFONT_TEXT;
if (INVALID_TEXT(t)) {
- put_msg(Err_invalid, "text", line_no);
+ put_msg(Err_invalid, "text", *line_no);
free_text(&t);
return NULL;
}
- fix_and_note_color(&t->color);
+ fix_and_note_color(&t->color, *line_no);
t->comments = attach_comments(); /* attach any comments */
return t;
}
@@ -1469,18 +1563,19 @@ read_textobject(FILE *fp)
/* count consecutive backslashes backwards */
-static int
-backslash_count(char cp[], int start)
+static ptrdiff_t
+backslash_count(const char *restrict cp, ptrdiff_t start)
{
- int i, count = 0;
+ ptrdiff_t i;
+ ptrdiff_t count = 0;
- for(i=start; i>=0; i--) {
- if (cp[i] == '\\')
- count++;
- else
- break;
- }
- return count;
+ for(i = start; i >= 0; --i) {
+ if (cp[i] == '\\')
+ ++count;
+ else
+ break;
+ }
+ return count;
}
/* attach comments in linked list */
@@ -1509,54 +1604,63 @@ attach_comments(void)
return icomp;
}
+/* save a comment line to be stored with the *subsequent* object */
+
static int
-get_line(FILE *fp)
+save_comment(char *restrict line, size_t len)
{
- int len;
- while (1) {
- if (NULL == fgets(buf, BUFSIZ, fp)) {
- return -1;
+ int i;
+
+ /* skip too many comment lines */
+ if (numcom == MAXCOMMENTS)
+ return 2;
+
+ /* remove one leading blank from the comment, if there is one */
+ i = 1;
+ if (line[i] == ' ')
+ i = 2;
+
+ /* see if we've allocated space for this comment */
+ if (comments[numcom])
+ free(comments[numcom]);
+ if ((comments[numcom] = malloc(len + (1 - i))) == NULL)
+ return -1;
+
+ strcpy(comments[numcom++], &line[i]);
+ return 1;
+}
+
+static ssize_t
+get_line(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
+{
+ ssize_t chars;
+
+ while ((chars = getline(line, line_len, fp)) != -1) {
+ ++(*line_no);
+ /* skip empty lines */
+ if (**line == '\n' || (**line == '\r' &&
+ chars == 2 && (*line)[1] == '\n'))
+ continue;
+ /* remove newline and possibly a carriage return */
+ if ((*line)[chars-1] == '\n') {
+ chars -= (*line)[chars - 2] == '\r' ? 2 : 1;
+ (*line)[chars] = '\0';
}
- ++line_no;
- if (*buf == '#') { /* save any comments */
- if (save_comment() < 0)
+ /* save any comments */
+ if (**line == '#') {
+ if (save_comment(*line, (size_t)chars) < 0)
return -1;
- /* skip empty lines */
- } else if (*buf != '\n' || !(*buf == '\r' && buf[1] == '\n')) {
- len = strlen(buf);
- /* remove newline and possibly a carriage return */
- if (buf[len-1] == '\n')
- buf[len - (buf[len-2] == '\r' ? 2 : 1)] = '\0';
- return 1;
+ continue;
}
+ /* return the line */
+ return chars;
}
+ /* chars == -1 */
+ return chars;
+ /* getline() only fails with EINVAL, and probably ENOMEM from malloc().
+ No use to check for errno. */
}
-/* save a comment line to be stored with the *subsequent* object */
-
-static int
-save_comment(void)
-{
- int i;
-
- /* skip too many comment lines */
- if (numcom == MAXCOMMENTS)
- return 2;
- i=strlen(buf);
- /* see if we've allocated space for this comment */
- if (comments[numcom])
- free(comments[numcom]);
- if ((comments[numcom] = malloc(i+1)) == NULL)
- return -1;
- /* remove any newline */
- if (buf[i-1] == '\n')
- buf[i-1] = '\0';
- i=1;
- if (buf[1] == ' ') /* remove one leading blank from the comment, if there is one */
- i=2;
- strcpy(comments[numcom++], &buf[i]);
- return 1;
-}
/* skip to the end of the current line and any subsequent blank lines */
@@ -1714,15 +1818,15 @@ static int pop() {
*/
static void
-count_lines_correctly(FILE *fp)
+count_lines_correctly(FILE *fp, int *line_no)
{
int cc;
do {
- cc = getc(fp);
- if (cc == '\n') {
- ++line_no;
- cc=getc(fp);
- }
+ cc = getc(fp);
+ if (cc == '\n') {
+ ++(*line_no);
+ cc=getc(fp);
+ }
} while (cc == ' ' || cc == '\t');
ungetc(cc,fp);
}
diff --git a/fig2dev/read1_3.c b/fig2dev/read1_3.c
index 64c7819..3b7a263 100644
--- a/fig2dev/read1_3.c
+++ b/fig2dev/read1_3.c
@@ -2,8 +2,8 @@
* Fig2dev: Translate Fig code to various Devices
* Copyright (c) 1991 by Micah Beck
* Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
- * Parts Copyright (c) 1989-2012 by Brian V. Smith
- * Parts Copyright (c) 2015-2019 by Thomas Loimer
+ * Parts Copyright (c) 1989-2015 by Brian V. Smith
+ * Parts Copyright (c) 2015-2020 by Thomas Loimer
*
* Any party obtaining a copy of these files is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -51,8 +51,6 @@
extern F_arrow *forward_arrow(void), *backward_arrow(void);
extern int figure_modified;
-//extern int line_no;
-extern int num_object;
static F_ellipse *read_ellipseobject(FILE *fp);
static F_line *read_lineobject(FILE *fp);
@@ -103,7 +101,6 @@ read_1_3_objects(FILE *fp, F_compound *obj)
ll = (ll->next = l);
else
ll = obj->lines = l;
- num_object++;
break;
case OBJ_SPLINE :
if ((s = read_splineobject(fp)) == NULL) return(-1);
@@ -111,7 +108,6 @@ read_1_3_objects(FILE *fp, F_compound *obj)
ls = (ls->next = s);
else
ls = obj->splines = s;
- num_object++;
break;
case OBJ_ELLIPSE :
if ((e = read_ellipseobject(fp)) == NULL) return(-1);
@@ -119,7 +115,6 @@ read_1_3_objects(FILE *fp, F_compound *obj)
le = (le->next = e);
else
le = obj->ellipses = e;
- num_object++;
break;
case OBJ_ARC :
if ((a = read_arcobject(fp)) == NULL) return(-1);
@@ -127,7 +122,6 @@ read_1_3_objects(FILE *fp, F_compound *obj)
la = (la->next = a);
else
la = obj->arcs = a;
- num_object++;
break;
case OBJ_TEXT :
if ((t = read_textobject(fp)) == NULL) return(-1);
@@ -135,7 +129,6 @@ read_1_3_objects(FILE *fp, F_compound *obj)
lt = (lt->next = t);
else
lt = obj->texts = t;
- num_object++;
break;
case OBJ_COMPOUND :
if ((c = read_compoundobject(fp)) == NULL) return(-1);
@@ -143,7 +136,6 @@ read_1_3_objects(FILE *fp, F_compound *obj)
lc = (lc->next = c);
else
lc = obj->compounds = c;
- num_object++;
break;
default:
put_msg("Incorrect object code %d", object);
diff --git a/fig2dev/tests/read.at b/fig2dev/tests/read.at
index 4ef8747..9b34bfb 100644
--- a/fig2dev/tests/read.at
+++ b/fig2dev/tests/read.at
@@ -2,7 +2,7 @@ dnl Fig2dev: Translate Fig code to various Devices
dnl Copyright (c) 1991 by Micah Beck
dnl Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
dnl Parts Copyright (c) 1989-2015 by Brian V. Smith
-dnl Parts Copyright (c) 2015-2019 by Thomas Loimer
+dnl Parts Copyright (c) 2015-2020 by Thomas Loimer
dnl
dnl Any party obtaining a copy of these files is granted, free of charge, a
dnl full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -14,7 +14,7 @@ dnl party to do so, with the only requirement being that the above copyright
dnl and this permission notice remain intact.
dnl read.at
-dnl Author: Thomas Loimer, 2017-2019
+dnl Author: Thomas Loimer, 2017-2020
AT_BANNER([Sanitize and harden input.])
@@ -279,7 +279,7 @@ AT_CHECK([fig2dev -L box <<EOF
3 0 0 0 0 0 0 0 0. 0 1
0
EOF
-],1,ignore,[Incomplete spline object at line 3.
+],1,ignore,[Incomplete spline object at line 4.
])
AT_CLEANUP
@@ -287,7 +287,7 @@ AT_SETUP([allow last line without newline, ticket #28])
AT_KEYWORDS([read.c])
AT_CHECK([AS_ECHO_N(['#FIG 2
0']) | fig2dev -L box],
-1, ignore, [Incomplete resolution information at line 1.
+1, ignore, [Incomplete resolution information at line 2.
])
AT_CLEANUP
@@ -299,7 +299,7 @@ AT_CHECK([fig2dev -L box <<EOF
2 1 1 1 -1 50 0 0 0. 0 0
0
EOF
-], 1, ignore, [Incomplete line object at line 3.
+], 1, ignore, [Incomplete line object at line 4.
])
AT_CLEANUP
@@ -345,7 +345,7 @@ AT_CHECK([fig2dev -L pict2e <<EOF
2 1 1 1 -502350 50 0 0 0. 0 0
0 0 100 100 9999 0
EOF
-],0,ignore-nolog,[Invalid color number -502350 at line 2, using default color.
+],0,ignore-nolog,[Invalid color number -502350 at line 3, using default color.
])
AT_CLEANUP
@@ -387,9 +387,22 @@ AT_KEYWORDS([read.c])
AT_CHECK([fig2dev -L box <<EOF
#FIG 2
1200 2
-4 2 0 0 1 0 0 390 306 110 376 639 5 Text
+4 2 0 0 1 0 0 0 6 110 376 639 5 Text
EOF
-], 1, ignore, [Invalid text object at line 2.
+], 0, ignore)
+AT_CLEANUP
+
+AT_SETUP([reject too long papersize specification])
+AT_KEYWORDS([read.c])
+AT_CHECK([fig2dev -L box <<EOF
+#FIG 3.2
+Landscape
+Center
+Inches
+Papersize_name_too_long
+EOF
+], 1, ignore,
+ [Invalid paper size specification at line 5: Papersize_name_too_long
])
AT_CLEANUP
--
2.24.1