From 41b9bb838a3d544539f6e68aa4f87d70ef7d45ce Mon Sep 17 00:00:00 2001 From: Thomas Loimer 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 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= 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 <