| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #include "sys-defines.h" |
| #include "libcommon.h" |
| #include "extern.h" |
| |
| |
| |
| #define NEW_POINT_ARRAY_LENGTH(old_len) \ |
| ((old_len)*sizeof(Point) < 10000000 ? 2 * (old_len) : (old_len) + 10000000/sizeof(Point)) |
| |
| struct ReaderStruct /* point reader datatype */ |
| { |
| |
| |
| bool transpose_axes; |
| int log_axis; |
| |
| FILE *input; |
| data_type format_type; |
| bool auto_abscissa; |
| double delta_x; |
| double initial_abscissa; |
| bool auto_bump; |
| |
| int symbol; |
| double symbol_size; |
| const char *symbol_font_name; |
| int linemode; |
| double line_width; |
| double fill_fraction; |
| bool use_color; |
| |
| bool need_break; |
| double abscissa; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| typedef enum { IN_PROGRESS, ENDED_BY_EOF, ENDED_BY_DATASET_TERMINATOR, ENDED_BY_MODE_CHANGE } dataset_status_t; |
| |
| |
| static bool skip_some_whitespace (FILE *stream); |
| static dataset_status_t read_and_plot_dataset (Reader *reader, Multigrapher *multigrapher); |
| static dataset_status_t read_dataset (Reader *reader, Point **p, int *length, int *no_of_points); |
| static dataset_status_t read_point (Reader *reader, Point *point); |
| static dataset_status_t read_point_ascii (Reader *reader, Point *point); |
| static dataset_status_t read_point_ascii_errorbar (Reader *reader, Point *point); |
| static dataset_status_t read_point_binary (Reader *reader, Point *point); |
| static dataset_status_t read_point_gnuplot (Reader *reader, Point *point); |
| static void reset_reader (Reader *reader); |
| static void skip_all_whitespace (FILE *stream); |
| |
| |
| |
| |
| |
| |
| Reader * |
| new_reader (FILE *input, data_type format_type, bool auto_abscissa, double delta_x, double abscissa, bool transpose_axes, int log_axis, bool auto_bump, int symbol, double symbol_size, const char *symbol_font_name, int linemode, double line_width, double fill_fraction, bool use_color) |
| |
| { |
| Reader *reader; |
| |
| reader = (Reader *)xmalloc (sizeof (Reader)); |
| |
| reader->need_break = true; |
| reader->input = input; |
| reader->format_type = format_type; |
| reader->auto_abscissa = auto_abscissa; |
| reader->delta_x = delta_x; |
| reader->initial_abscissa = abscissa; |
| reader->abscissa = reader->initial_abscissa; |
| reader->transpose_axes = transpose_axes; |
| reader->log_axis = log_axis; |
| reader->auto_bump = auto_bump; |
| reader->symbol = symbol; |
| reader->symbol_size = symbol_size; |
| reader->symbol_font_name = symbol_font_name; |
| reader->linemode = linemode; |
| reader->line_width = line_width; |
| reader->fill_fraction = fill_fraction; |
| reader->use_color = use_color; |
| |
| return reader; |
| } |
| |
| void |
| delete_reader (Reader *reader) |
| { |
| free (reader); |
| return; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void |
| alter_reader_parameters (Reader *reader, FILE *input, data_type format_type, bool auto_abscissa, double delta_x, double abscissa, int symbol, double symbol_size, const char *symbol_font_name, int linemode, double line_width, double fill_fraction, bool use_color, bool new_symbol, bool new_symbol_size, bool new_symbol_font_name, bool new_linemode, bool new_line_width, bool new_fill_fraction, bool new_use_color) |
| { |
| reader->need_break = true; |
| reader->input = input; |
| reader->format_type = format_type; |
| reader->auto_abscissa = auto_abscissa; |
| reader->delta_x = delta_x; |
| reader->initial_abscissa = abscissa; |
| reader->abscissa = reader->initial_abscissa; |
| |
| if (new_symbol) |
| reader->symbol = symbol; |
| if (new_symbol_size) |
| reader->symbol_size = symbol_size; |
| if (new_symbol_font_name) |
| reader->symbol_font_name = symbol_font_name; |
| if (new_linemode) |
| reader->linemode = linemode; |
| if (new_line_width) |
| reader->line_width = line_width; |
| if (new_fill_fraction) |
| reader->fill_fraction = fill_fraction; |
| if (new_use_color) |
| reader->use_color = use_color; |
| |
| return; |
| } |
| |
| |
| |
| |
| |
| |
| static dataset_status_t |
| read_point (Reader *reader, Point *point) |
| { |
| dataset_status_t status; |
| |
| |
| point->symbol = reader->symbol; |
| point->symbol_size = reader->symbol_size; |
| point->symbol_font_name = reader->symbol_font_name; |
| point->linemode = reader->linemode; |
| point->line_width = reader->line_width; |
| point->fill_fraction = reader->fill_fraction; |
| point->use_color = reader->use_color; |
| point->have_x_errorbar = false; |
| point->have_y_errorbar = (reader->format_type == T_ASCII_ERRORBAR ? true : false); |
| |
| head: |
| |
| switch (reader->format_type) |
| { |
| case T_ASCII: |
| default: |
| status = read_point_ascii (reader, point); |
| break; |
| case T_SINGLE: |
| case T_DOUBLE: |
| case T_INTEGER: |
| status = read_point_binary (reader, point); |
| break; |
| case T_ASCII_ERRORBAR: |
| status = read_point_ascii_errorbar (reader, point); |
| break; |
| case T_GNUPLOT: |
| status = read_point_gnuplot (reader, point); |
| break; |
| } |
| |
| if (status == IN_PROGRESS) |
| |
| { |
| bool bad_point = false; |
| |
| |
| |
| |
| if (reader->log_axis & X_AXIS) |
| { |
| if (point->x > 0.0) |
| point->x = log10 (point->x); |
| else |
| bad_point = true; |
| if (point->have_x_errorbar) |
| { |
| if (point->xmin > 0.0) |
| point->xmin = log10 (point->xmin); |
| else |
| bad_point = true; |
| if (point->xmax > 0.0) |
| point->xmax = log10 (point->xmax); |
| else |
| bad_point = true; |
| } |
| |
| if (bad_point) |
| { |
| fprintf (stderr, "%s: the inappropriate point (%g,%g) is dropped, as this is a log plot\n", |
| progname, point->x, point->y); |
| reader->need_break = true; |
| goto head; |
| } |
| } |
| if (reader->log_axis & Y_AXIS) |
| { |
| if (point->y > 0.0) |
| point->y = log10 (point->y); |
| else |
| bad_point = true; |
| |
| if (point->have_y_errorbar) |
| { |
| if (point->ymin > 0.0) |
| point->ymin = log10 (point->ymin); |
| else |
| bad_point = true; |
| if (point->ymax > 0.0) |
| point->ymax = log10 (point->ymax); |
| else |
| bad_point = true; |
| } |
| |
| if (bad_point) |
| { |
| fprintf (stderr, "%s: the inappropriate point (%g,%g) is dropped, as this is a log plot\n", |
| progname, point->x, point->y); |
| reader->need_break = true; |
| goto head; |
| } |
| } |
| |
| if (reader->transpose_axes) |
| { |
| double tmp; |
| bool tmp_bool; |
| |
| tmp = point->x; |
| point->x = point->y; |
| point->y = tmp; |
| tmp = point->xmin; |
| point->xmin = point->ymin; |
| point->ymin = tmp; |
| tmp = point->xmax; |
| point->xmax = point->ymax; |
| point->ymax = tmp; |
| tmp_bool = point->have_x_errorbar; |
| point->have_x_errorbar = point->have_y_errorbar; |
| point->have_y_errorbar = tmp_bool; |
| } |
| |
| |
| if (reader->need_break) |
| point->pendown = false; |
| else |
| point->pendown = true; |
| |
| |
| reader->need_break = false; |
| } |
| |
| return status; |
| } |
| |
| static dataset_status_t |
| read_point_ascii (Reader *reader, Point *point) |
| { |
| int items_read, lookahead; |
| bool two_newlines; |
| FILE *input = reader->input; |
| |
| head: |
| |
| |
| two_newlines = skip_some_whitespace (input); |
| if (two_newlines) |
| return ENDED_BY_DATASET_TERMINATOR; |
| if (feof (input)) |
| return ENDED_BY_EOF; |
| |
| |
| lookahead = getc (input); |
| ungetc (lookahead, input); |
| if (lookahead == (int)'#') |
| { |
| int new_symbol, new_linemode; |
| int items_read; |
| |
| items_read = fscanf (input, |
| "# m = %d, S = %d", &new_linemode, &new_symbol); |
| if (items_read == 2) |
| { |
| reader->linemode = new_linemode; |
| reader->symbol = new_symbol; |
| return ENDED_BY_MODE_CHANGE; |
| } |
| else |
| { |
| char c; |
| |
| do |
| { |
| items_read = fread (&c, sizeof (c), 1, input); |
| if (items_read <= 0) |
| return ENDED_BY_EOF; |
| } |
| while (c != '\n'); |
| ungetc ((int)'\n', input); |
| goto head; |
| } |
| } |
| |
| |
| if (reader->auto_abscissa) |
| { |
| point->x = reader->abscissa; |
| reader->abscissa += reader->delta_x; |
| } |
| else |
| { |
| items_read = fscanf (input, "%lf", &(point->x)); |
| if (items_read != 1) |
| return ENDED_BY_EOF; |
| } |
| |
| items_read = fscanf (input, "%lf", &(point->y)); |
| if (items_read == 1) |
| return IN_PROGRESS; |
| else |
| { |
| if (!reader->auto_abscissa) |
| fprintf (stderr, "%s: an input file terminated prematurely\n", progname); |
| return ENDED_BY_EOF; |
| } |
| } |
| |
| static dataset_status_t |
| read_point_ascii_errorbar (Reader *reader, Point *point) |
| { |
| int items_read, lookahead; |
| bool two_newlines; |
| double error_size; |
| FILE *input = reader->input; |
| |
| head: |
| |
| |
| two_newlines = skip_some_whitespace (input); |
| if (two_newlines) |
| return ENDED_BY_DATASET_TERMINATOR; |
| if (feof (input)) |
| return ENDED_BY_EOF; |
| |
| |
| lookahead = getc (input); |
| ungetc (lookahead, input); |
| if (lookahead == (int)'#') |
| { |
| int new_symbol, new_linemode; |
| int items_read; |
| |
| items_read = fscanf (input, |
| "# m = %d, S = %d", &new_linemode, &new_symbol); |
| if (items_read == 2) |
| { |
| reader->linemode = new_linemode; |
| reader->symbol = new_symbol; |
| return ENDED_BY_MODE_CHANGE; |
| } |
| else |
| { |
| char c; |
| |
| do |
| { |
| items_read = fread (&c, sizeof (c), 1, input); |
| if (items_read <= 0) |
| return ENDED_BY_EOF; |
| } |
| while (c != '\n'); |
| ungetc ((int)'\n', input); |
| goto head; |
| } |
| } |
| |
| |
| if (reader->auto_abscissa) |
| { |
| point->x = reader->abscissa; |
| reader->abscissa += reader->delta_x; |
| } |
| else |
| { |
| items_read = fscanf (input, "%lf", &(point->x)); |
| if (items_read != 1) |
| return ENDED_BY_EOF; |
| } |
| |
| items_read = fscanf (input, "%lf", &(point->y)); |
| if (items_read != 1) |
| { |
| if (!reader->auto_abscissa) |
| fprintf (stderr, "%s: an input file (in errorbar format) terminated prematurely\n", progname); |
| return ENDED_BY_EOF; |
| } |
| |
| items_read = fscanf (input, "%lf", &error_size); |
| if (items_read != 1) |
| { |
| fprintf (stderr, "%s: an input file (in errorbar format) terminated prematurely\n", progname); |
| return ENDED_BY_EOF; |
| } |
| |
| point->ymin = point->y - error_size; |
| point->ymax = point->y + error_size; |
| |
| |
| point->xmin = 0.0; |
| point->xmax = 0.0; |
| |
| return IN_PROGRESS; |
| } |
| |
| static dataset_status_t |
| read_point_binary (Reader *reader, Point *point) |
| { |
| int items_read; |
| data_type format_type = reader->format_type; |
| FILE *input = reader->input; |
| |
| |
| if (reader->auto_abscissa) |
| { |
| point->x = reader->abscissa; |
| reader->abscissa += reader->delta_x; |
| } |
| else |
| { |
| switch (format_type) |
| { |
| case T_DOUBLE: |
| default: |
| items_read = |
| fread ((void *) &(point->x), sizeof (double), 1, input); |
| break; |
| case T_SINGLE: |
| { |
| float fx; |
| |
| items_read = |
| fread ((void *) &fx, sizeof (fx), 1, input); |
| point->x = fx; |
| } |
| break; |
| case T_INTEGER: |
| { |
| int ix; |
| |
| items_read = |
| fread ((void *) &ix, sizeof (ix), 1, input); |
| point->x = ix; |
| } |
| break; |
| } |
| if (items_read <= 0) |
| return ENDED_BY_EOF; |
| } |
| |
| if ((format_type == T_DOUBLE && point->x == DBL_MAX) |
| || (format_type == T_SINGLE && point->x == (double)FLT_MAX) |
| || (format_type == T_INTEGER && point->x == (double)INT_MAX)) |
| return ENDED_BY_DATASET_TERMINATOR; |
| |
| switch (format_type) |
| { |
| case T_DOUBLE: |
| default: |
| items_read = |
| fread ((void *) &(point->y), sizeof (double), 1, input); |
| break; |
| case T_SINGLE: |
| { |
| float fy; |
| |
| items_read = |
| fread ((void *) &fy, sizeof (fy), 1, input); |
| point->y = fy; |
| } |
| break; |
| case T_INTEGER: |
| { |
| int iy; |
| |
| items_read = |
| fread ((void *) &iy, sizeof (iy), 1, input); |
| point->y = iy; |
| } |
| break; |
| } |
| |
| if (items_read != 1) |
| { |
| if (!reader->auto_abscissa) |
| fprintf (stderr, "%s: an input file (in binary format) terminated prematurely\n", progname); |
| return ENDED_BY_EOF; |
| } |
| else if (point->x != point->x || point->y != point->y) |
| { |
| fprintf (stderr, "%s: a NaN (not-a-number) was encountered in a binary input file\n", |
| progname); |
| return ENDED_BY_EOF; |
| } |
| else |
| return IN_PROGRESS; |
| } |
| |
| |
| |
| |
| |
| static dataset_status_t |
| read_point_gnuplot (Reader *reader, Point *point) |
| { |
| int lookahead, items_read; |
| char directive, c; |
| bool two_newlines; |
| double x, y; |
| FILE *input = reader->input; |
| |
| head: |
| |
| |
| two_newlines = skip_some_whitespace (input); |
| if (two_newlines) |
| |
| { |
| skip_all_whitespace (input); |
| if (feof (input)) |
| return ENDED_BY_EOF; |
| else |
| return ENDED_BY_DATASET_TERMINATOR; |
| } |
| |
| lookahead = getc (input); |
| ungetc (lookahead, input); |
| switch (lookahead) |
| { |
| case 'C': |
| case '#': |
| do |
| { |
| items_read = fread (&c, sizeof (c), 1, input); |
| if (items_read <= 0) |
| return ENDED_BY_EOF; |
| } |
| while (c != '\n'); |
| ungetc ((int)'\n', input); |
| goto head; |
| |
| case 'i': |
| case 'o': |
| |
| items_read = fscanf (input, |
| "%c x=%lf y=%lf", |
| &directive, &x, &y); |
| if (items_read == 3) |
| { |
| point->x = x; |
| point->y = y; |
| return IN_PROGRESS; |
| } |
| else |
| { |
| fprintf (stderr, |
| "%s: an input file in gnuplot format could not be parsed\n", |
| progname); |
| return ENDED_BY_EOF; |
| } |
| |
| case 'u': |
| |
| do |
| { |
| items_read = fread (&c, sizeof (c), 1, input); |
| if (items_read <= 0) |
| { |
| fprintf (stderr, |
| "%s: an input file in gnuplot format could not be parsed\n", |
| progname); |
| return ENDED_BY_EOF; |
| } |
| } |
| while (c != '\n'); |
| |
| reader->need_break = true; |
| goto head; |
| |
| default: |
| items_read = fscanf (input, |
| "%lf %lf %c", |
| &x, &y, &directive); |
| if (items_read == 3 |
| && (directive == 'i' || directive == 'o' || directive == 'u')) |
| { |
| if (directive == 'u') |
| { |
| |
| |
| reader->need_break = true; |
| goto head; |
| } |
| else |
| { |
| point->x = x; |
| point->y = y; |
| return IN_PROGRESS; |
| } |
| } |
| else |
| { |
| fprintf (stderr, |
| "%s: an input file in gnuplot format could not be parsed\n", |
| progname); |
| return ENDED_BY_EOF; |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| static dataset_status_t |
| read_dataset (Reader *reader, Point **p_addr, int *length, int *no_of_points) |
| { |
| Point *p = *p_addr; |
| dataset_status_t status; |
| |
| for ( ; ; ) |
| { |
| |
| |
| |
| if (*no_of_points >= *length) |
| { |
| int old_length, new_length; |
| |
| old_length = *length; |
| new_length = NEW_POINT_ARRAY_LENGTH(old_length); |
| p = (Point *)xrealloc (p, new_length * sizeof (Point)); |
| *length = new_length; |
| } |
| |
| status = read_point (reader, &(p[*no_of_points])); |
| if (status != IN_PROGRESS) |
| |
| break; |
| |
| (*no_of_points)++; |
| } |
| |
| *p_addr = p; |
| |
| return status; |
| } |
| |
| |
| |
| |
| |
| |
| |
| void |
| read_file (Reader *reader, Point **p_addr, int *length, int *no_of_points) |
| { |
| dataset_status_t status; |
| |
| do |
| { |
| status = read_dataset (reader, p_addr, length, no_of_points); |
| |
| |
| |
| |
| |
| |
| if (status == ENDED_BY_MODE_CHANGE) |
| { |
| bool saved_auto_bump; |
| |
| saved_auto_bump = reader->auto_bump; |
| reader->auto_bump = false; |
| reset_reader (reader); |
| reader->auto_bump = saved_auto_bump; |
| } |
| else |
| reset_reader (reader); |
| } |
| while (status != ENDED_BY_EOF); |
| } |
| |
| |
| |
| |
| |
| static void |
| reset_reader (Reader *reader) |
| { |
| reader->need_break = true; |
| |
| |
| if (reader->auto_bump) |
| reader->linemode += ((reader->linemode > 0) ? 1 : -1); |
| |
| |
| if (reader->auto_abscissa) |
| reader->abscissa = reader->initial_abscissa; |
| |
| return; |
| } |
| |
| |
| |
| |
| |
| |
| |
| static bool |
| skip_some_whitespace (FILE *stream) |
| { |
| int lookahead; |
| int nlcount = 0; |
| |
| do |
| { |
| lookahead = getc (stream); |
| if (lookahead == (int)'\n') |
| nlcount++; |
| } |
| while (lookahead != EOF |
| && isspace((unsigned char)lookahead) |
| && nlcount < 2); |
| |
| if (lookahead == EOF) |
| return false; |
| |
| ungetc (lookahead, stream); |
| return (nlcount == 2 ? true : false); |
| } |
| |
| |
| |
| |
| |
| static void |
| skip_all_whitespace (FILE *stream) |
| { |
| int lookahead; |
| |
| do |
| lookahead = getc (stream); |
| while (lookahead != EOF |
| && isspace((unsigned char)lookahead)); |
| |
| if (lookahead == EOF) |
| return; |
| else |
| ungetc (lookahead, stream); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static dataset_status_t |
| read_and_plot_dataset (Reader *reader, Multigrapher *multigrapher) |
| { |
| dataset_status_t status; |
| |
| for ( ; ; ) |
| { |
| Point point; |
| |
| status = read_point (reader, &point); |
| if (status != IN_PROGRESS) |
| |
| break; |
| else |
| plot_point (multigrapher, &point); |
| } |
| |
| return status; |
| } |
| |
| |
| |
| |
| |
| void |
| read_and_plot_file (Reader *reader, Multigrapher *multigrapher) |
| { |
| dataset_status_t status; |
| |
| do |
| { |
| status = read_and_plot_dataset (reader, multigrapher); |
| |
| |
| |
| |
| |
| if (status == ENDED_BY_MODE_CHANGE) |
| { |
| bool saved_auto_bump; |
| |
| saved_auto_bump = reader->auto_bump; |
| reader->auto_bump = false; |
| reset_reader (reader); |
| reader->auto_bump = saved_auto_bump; |
| } |
| else |
| reset_reader (reader); |
| |
| |
| |
| |
| end_polyline_and_flush (multigrapher); |
| } |
| while (status != ENDED_BY_EOF); |
| } |