2 static char *RCSid() { return RCSid("$Id: datafile.c,v 1.110.2.21 2009/03/26 04:29:10 sfeam Exp $"); }
5 /* GNUPLOT - datafile.c */
8 * Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
37 /* AUTHOR : David Denholm */
40 * this file provides the functions to handle data-file reading..
41 * takes care of all the pipe / stdin / index / using worries
45 /* couldn't decide how to implement 'thru' only for 2d and 'index'
46 * for only 3d, so I did them for both - I can see a use for
47 * index in 2d, especially for fit.
49 * I keep thru for backwards compatibility, and extend it to allow
50 * more natural plot 'data' thru f(y) - I (personally) prefer
51 * my syntax, but then I'm biased...
53 * - because I needed it, I have added a range of indexes...
54 * (s)plot 'data' [index i[:j]]
56 * also every a:b:c:d:e:f - plot every a'th point from c to e,
57 * in every b lines from d to f
58 * ie for (line=d; line<=f; line+=b)
59 * for (point=c; point >=e; point+=a)
62 * I dont like mixing this with the time series hack... I am
63 * very into modular code, so I would prefer to not have to
64 * have _anything_ to do with time series... for example,
65 * we just look at columns in file, and that is independent
66 * of 2d/3d. I really dont want to have to pass a flag to
67 * this is plot or splot.
69 * Now that df_2dbinary() and df_3dbinary() are here, I am seriously
70 * tempted to move get_data() and get_3ddata() in here too
72 * public variables declared in this file.
73 * int df_no_use_specs - number of columns specified with 'using'
74 * int df_no_tic_specs - count of additional ticlabel columns
75 * int df_line_number - for error reporting
76 * int df_datum - increases with each data point
77 * TBOOLEAN df_binary - it's a binary file
78 * [ might change this to return value from df_open() ]
79 * int df_eof - end of file
82 * int df_open(char *file_name, int max_using)
83 * parses thru / index / using on command line
84 * max_using is max no of 'using' columns allowed
85 * returns number of 'using' cols specified, or -1 on error (?)
87 * int df_readline(double vector[], int max)
88 * reads a line, does all the 'index' and 'using' manipulation
89 * deposits values into vector[]
91 * number of columns parsed [0=not blank line, but no valid data],
93 * DF_UNDEFINED - undefined result during eval of extended using spec
94 * DF_MISSING - requested column matched that of 'set missing <foo>'
95 * DF_FIRST_BLANK for first consecutive blank line
96 * DF_SECOND_BLANK for second consecutive blank line
97 * will return FIRST before SECOND
99 * if a using spec was given, lines not fulfilling spec are ignored.
100 * we will always return exactly the number of items specified
102 * if no spec given, we return number of consecutive columns we parsed.
104 * if we are processing indexes, separated by 'n' blank lines,
105 * we will return n-1 blank lines before noticing the index change
108 * closes a currently open file.
111 * void f_column() actions for expressions using $i, column(j), etc
115 * line parsing slightly differently from previous versions of gnuplot...
116 * given a line containing fewer columns than asked for, gnuplot used to make
117 * up values... I say that if I have explicitly said 'using 1:2:3', then if
118 * column 3 doesn't exist, I dont want this point...
120 * a column number of 0 means generate a value... as before, this value
121 * is useful in 2d as an x value, and is reset at blank lines.
122 * a column number of -1 means the (data) line number (not the file line
123 * number). splot 'file' using 1 is equivalent to
124 * splot 'file' using 0:-1:1
125 * column number -2 is the index. It was put in to kludge multi-branch
128 * 20/5/95 : accept 1.23d4 in place of e (but not in scanf string)
129 * : autoextend data line buffer and MAX_COLS
131 * 11/8/96 : add 'columns' -1 for suggested y value, and -2 for
133 * using 1:-1:-2 and column(-1) are supported.
134 * $-1 and $-2 are not yet supported, because of the
135 * way the parser works
140 /* Daniel Sebald: added general binary 2d data support. (20 August 2004)
143 #include "datafile.h"
151 #include "graphics.h"
156 #ifdef BINARY_DATA_FILE
157 #include "breaders.h"
160 /* test to see if the end of an inline datafile is reached */
161 #define is_EOF(c) ((c) == 'e' || (c) == 'E')
163 /* is it a comment line? */
164 #define is_comment(c) ((c) && (strchr(df_commentschars, (c)) != NULL))
168 static int get_time_cols __PROTO((char *fmt));
169 static void mod_def_usespec __PROTO((int specno, int jump));
171 static int check_missing __PROTO((char *s));
172 static char *df_gets __PROTO((void));
173 static int df_tokenise __PROTO((char *s));
174 #ifdef BINARY_DATA_FILE
175 static float *df_read_matrix __PROTO((int *rows, int *columns));
177 static float **df_read_matrix __PROTO((int *rows, int *columns));
179 static void plot_option_every __PROTO((void));
180 static void plot_option_index __PROTO((void));
181 static void plot_option_thru __PROTO((void));
182 static void plot_option_using __PROTO((int));
183 static TBOOLEAN valid_format __PROTO((const char *));
184 #ifdef EAM_DATASTRINGS
185 static void plot_ticlabel_using __PROTO((int));
186 static void df_parse_string_field __PROTO((char *, char *));
188 #ifdef EAM_HISTOGRAMS
189 static void add_key_entry __PROTO((char *temp_string, int df_datum));
196 #ifdef EAM_DATASTRINGS
197 enum COLUMN_TYPE { CT_DEFAULT, CT_STRING, CT_KEYLABEL,
198 CT_XTICLABEL, CT_X2TICLABEL, CT_YTICLABEL, CT_Y2TICLABEL,
199 CT_ZTICLABEL, CT_CBTICLABEL };
202 /* public variables client might access */
204 int df_no_use_specs; /* how many using columns were specified */
205 #ifdef EAM_HISTOGRAMS
206 struct curve_points *df_current_plot; /* set before calling df_readline() */
209 int df_datum; /* suggested x value if none given */
211 AXIS_INDEX df_axis[MAXDATACOLS];
212 TBOOLEAN df_matrix = FALSE; /* indicates if data originated from a 2D or 3D format */
213 TBOOLEAN df_binary = FALSE; /* this is a binary file */
215 /* jev -- the 'thru' function --- NULL means no dummy vars active */
216 /* HBB 990829: moved this here, from command.c */
217 struct udft_entry ydata_func;
219 /* string representing missing values in ascii datafiles */
220 char *missing_val = NULL;
222 /* input field separator, NUL if whitespace is the separator */
223 char df_separator = '\0';
226 char *df_commentschars = 0;
228 /* If any 'inline data' are in use for the current plot, flag this */
229 TBOOLEAN plotted_data_from_stdin = FALSE;
231 /* Setting this allows the parser to recognize Fortran D or Q */
232 /* format constants in the input file. But it slows things down */
233 TBOOLEAN df_fortran_constants = FALSE;
235 /* private variables */
237 /* in order to allow arbitrary data line length, we need to use the heap
238 * might consider free-ing it in df_close, especially for small systems
240 static char *line = NULL;
241 static size_t max_line_len = 0;
242 #define DATA_LINE_BUFSIZ 160
244 static FILE *data_fp = NULL;
246 static TBOOLEAN df_pipe_open = FALSE;
248 static TBOOLEAN mixed_data_fp = FALSE; /* inline data */
249 char *df_filename; /* name of data file */
251 #ifdef EAM_DATASTRINGS
252 static int df_no_tic_specs; /* ticlabel columns not counted in df_no_use_specs */
253 #define MAX_TOKEN_LENGTH 64
256 #ifndef MAXINT /* should there be one already defined ? */
257 # ifdef INT_MAX /* in limits.h ? */
258 # define MAXINT INT_MAX
260 # define MAXINT ((~0)>>1)
264 /* stuff for implementing index */
265 static int blank_count = 0; /* how many blank lines recently */
266 static int df_lower_index = 0; /* first mesh required */
267 static int df_upper_index = MAXINT;
268 static int df_index_step = 1; /* 'every' for indices */
269 static int df_current_index; /* current mesh */
271 /* stuff for every point:line */
272 static int everypoint = 1;
273 static int firstpoint = 0;
274 static int lastpoint = MAXINT;
275 static int everyline = 1;
276 static int firstline = 0;
277 static int lastline = MAXINT;
278 static int point_count = -1; /* point counter - preincrement and test 0 */
279 static int line_count = 0; /* line counter */
282 struct use_spec_s use_spec[MAXDATACOLS];
283 static char df_format[MAX_LINE_LEN + 1];
284 static TBOOLEAN evaluate_inside_using = FALSE;
286 /* rather than three arrays which all grow dynamically, make one
287 * dynamic array of this structure
290 typedef struct df_column_struct {
298 static df_column_struct *df_column = NULL; /* we'll allocate space as needed */
299 static int df_max_cols = 0; /* space allocated */
300 static int df_no_cols; /* cols read */
301 static int fast_columns; /* corey@cac optimization */
303 #ifdef EAM_DATASTRINGS
304 char *df_tokens[MAXDATACOLS]; /* filled in by df_tokenise */
305 #ifdef GP_STRING_VARS
306 static char *df_stringexpression[MAXDATACOLS] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
308 #define NO_COLUMN_HEADER (-99) /* some value that can never be a real column */
309 static int column_for_key_title = NO_COLUMN_HEADER;
310 static TBOOLEAN key_title_auto_col = FALSE;
311 static char df_key_title[MAX_TOKEN_LENGTH]; /* filled in from <col> in 1st row by df_tokenise */
314 #ifdef BINARY_DATA_FILE
316 /* Binary *read* variables used by df_readbinary(). The difference between matrix
317 * binary and general binary is that matrix binary requires an extra first column
318 * and extra first row giving the sample coordinates. Furthermore, note that if
319 * ASCII matrix data is converted to floats (i.e., binary) then it really falls in
320 * the general binary class, not the matrix binary class.
322 TBOOLEAN df_read_binary;
323 TBOOLEAN df_matrix_binary;
326 /* Define the following true of binary is to have it's own format string. */
327 #define BINARY_HAS_OWN_FORMAT_STRING 1
329 static int df_readascii __PROTO((double [], int));
330 static int df_readbinary __PROTO((double [], int));
332 static void initialize_use_spec __PROTO((void));
334 static void initialize_binary_vars __PROTO((void));
335 static void df_insert_scanned_use_spec __PROTO((int));
336 static void adjust_binary_use_spec __PROTO((void));
337 static void clear_binary_records __PROTO((df_records_type));
338 static void plot_option_binary_format __PROTO((void));
339 static void plot_option_binary __PROTO((TBOOLEAN, TBOOLEAN));
340 static void plot_option_array __PROTO((void));
341 static TBOOLEAN rotation_matrix_2D __PROTO((double R[][2], double));
342 static TBOOLEAN rotation_matrix_3D __PROTO((double P[][3], double *));
343 static int token2tuple __PROTO((double *, int));
344 static void df_determine_matrix_info __PROTO((FILE *));
345 static void df_swap_bytes_by_endianess __PROTO((char *, int, int));
347 typedef enum df_multivalue_type {
357 } df_multivalue_type;
358 static void plot_option_multivalued __PROTO((df_multivalue_type,int));
360 char *df_endian[DF_ENDIAN_TYPE_LENGTH] = {
363 "swapped pdp (dimmle)",
367 #define SUPPORT_MIDDLE_ENDIAN 1
369 #if SUPPORT_MIDDLE_ENDIAN
370 /* To generate a swap, take the bit-wise complement of the lowest two bits. */
371 typedef enum df_byte_read_order_type {
376 } df_byte_read_order_type;
378 /* First argument, this program's endianess. Second argument, file's endianess.
379 * Don't use directly. Use 'byte_read_order()' function instead.*/
380 static char df_byte_read_order_map[4][4] = {
381 {DF_0123, DF_1032, DF_2301, DF_3210},
382 {DF_1032, DF_0123, DF_1032, DF_2301},
383 {DF_2301, DF_1032, DF_0123, DF_1032},
384 {DF_3210, DF_2301, DF_1032, DF_0123}
387 static long long_0x2468 = 0x2468;
388 #define TEST_BIG_PDP ( (((char *)&long_0x2468)[0] < 3) ? DF_BIG_ENDIAN : DF_PDP_ENDIAN )
389 #define THIS_COMPILER_ENDIAN ( (((char *)&long_0x2468)[0] < 5) ? TEST_BIG_PDP : DF_LITTLE_ENDIAN )
391 #else /* ifdef BINARY_DATA_FILE */
393 typedef enum df_byte_read_order_type {
396 } df_byte_read_order_type;
398 static int int_1 = 1;
399 #define THIS_COMPILER_ENDIAN ( ((char *)&int_1)[0] ? DF_LITTLE_ENDIAN : DF_BIG_ENDIAN )
401 #endif /* ifdef BINARY_DATA_FILE */
403 /* Argument is file's endianess type. */
404 static df_byte_read_order_type byte_read_order __PROTO((df_endianess_type));
406 /* Logical variables indicating information about data file. */
407 TBOOLEAN df_binary_file;
408 TBOOLEAN df_matrix_file;
414 /* Initially set to default and then possibly altered by command line. */
415 df_binary_file_record_struct *df_bin_record = 0;
416 /* Default settings. */
417 df_binary_file_record_struct *df_bin_record_default = 0;
418 /* Settings that are transferred to default upon reset. */
419 df_binary_file_record_struct df_bin_record_reset = {
423 DF_TRANSLATE_DEFAULT,
428 {DF_SCAN_POINT, DF_SCAN_LINE, DF_SCAN_PLANE},
435 DF_TRANSLATE_DEFAULT,
441 int df_max_num_bin_records = 0, df_num_bin_records, df_bin_record_count;
442 int df_max_num_bin_records_default = 0, df_num_bin_records_default;
444 typedef struct df_bin_filetype_table_struct {
446 void (*function)(void);
447 } df_bin_filetype_table_struct;
449 static void gpbin_filetype_function __PROTO((void));
450 static void raw_filetype_function __PROTO((void));
451 static void avs_filetype_function __PROTO((void));
453 df_bin_filetype_table_struct df_bin_filetype_table[] = {
454 {"gpbin", gpbin_filetype_function},
455 {"raw", raw_filetype_function},
456 {"rgb", raw_filetype_function},
457 {"bin", raw_filetype_function},
459 {"avs", avs_filetype_function},
460 {"edf", edf_filetype_function},
461 {"ehf", edf_filetype_function},
463 {"auto", raw_filetype_function} /* "auto" is trapped, but if the actual file extension is "auto" then use raw. */
465 #define RAW_FILETYPE 1
467 /* Initially set to default and then possibly altered by command line. */
469 df_endianess_type df_bin_file_endianess;
470 /* Default setting. */
471 int df_bin_filetype_default;
472 df_endianess_type df_bin_file_endianess_default;
473 /* Setting that is transferred to default upon reset. */
474 int df_bin_filetype_reset = -1;
475 #define DF_BIN_FILE_ENDIANESS_RESET THIS_COMPILER_ENDIAN
477 typedef struct df_bin_scan_table_2D_struct {
479 df_sample_scan_type scan[3];
480 } df_bin_scan_table_2D_struct;
482 df_bin_scan_table_2D_struct df_bin_scan_table_2D[] = {
483 {"xy", {DF_SCAN_POINT, DF_SCAN_LINE, DF_SCAN_PLANE}},
484 {"yx", {DF_SCAN_LINE, DF_SCAN_POINT, DF_SCAN_PLANE}},
485 {"tr", {DF_SCAN_POINT, DF_SCAN_LINE, DF_SCAN_PLANE}},
486 {"rt", {DF_SCAN_LINE, DF_SCAN_POINT, DF_SCAN_PLANE}}
488 #define TRANSPOSE_INDEX 1
490 typedef struct df_bin_scan_table_3D_struct {
492 df_sample_scan_type scan[3];
493 } df_bin_scan_table_3D_struct;
495 df_bin_scan_table_3D_struct df_bin_scan_table_3D[] = {
496 {"xyz", {DF_SCAN_POINT, DF_SCAN_LINE, DF_SCAN_PLANE}},
497 {"zxy", {DF_SCAN_LINE, DF_SCAN_PLANE, DF_SCAN_POINT}},
498 {"yzx", {DF_SCAN_PLANE, DF_SCAN_POINT, DF_SCAN_LINE}},
499 {"yxz", {DF_SCAN_LINE, DF_SCAN_POINT, DF_SCAN_PLANE}},
500 {"xzy", {DF_SCAN_POINT, DF_SCAN_PLANE, DF_SCAN_LINE}},
501 {"zyx", {DF_SCAN_PLANE, DF_SCAN_LINE, DF_SCAN_POINT}},
502 {"trz", {DF_SCAN_POINT, DF_SCAN_LINE, DF_SCAN_PLANE}},
503 {"ztr", {DF_SCAN_LINE, DF_SCAN_PLANE, DF_SCAN_POINT}},
504 {"rzt", {DF_SCAN_PLANE, DF_SCAN_POINT, DF_SCAN_LINE}},
505 {"rtz", {DF_SCAN_LINE, DF_SCAN_POINT, DF_SCAN_PLANE}},
506 {"tzr", {DF_SCAN_POINT, DF_SCAN_PLANE, DF_SCAN_LINE}},
507 {"zrt", {DF_SCAN_PLANE, DF_SCAN_LINE, DF_SCAN_POINT}}
510 /* Names for machine dependent field sizes. */
511 char *ch_names[] = {"char","schar","c"};
512 char *uc_names[] = {"uchar"};
513 char *sh_names[] = {"short"};
514 char *us_names[] = {"ushort"};
515 char *in_names[] = {"int","sint","i","d"};
516 char *ui_names[] = {"uint","u"};
517 char *lo_names[] = {"long","ld"};
518 char *ul_names[] = {"ulong","lu"};
519 char *fl_names[] = {"float","f"};
520 char *db_names[] = {"double","lf"};
522 /* Machine independent names. */
523 char *byte_names[] = {"int8","byte"};
524 char *ubyte_names[] = {"uint8","ubyte"};
525 char *word_names[] = {"int16","word"};
526 char *uword_names[] = {"uint16","uword"};
527 char *word2_names[] = {"int32"};
528 char *uword2_names[] = {"uint32"};
529 char *word4_names[] = {"int64"};
530 char *uword4_names[] = {"uint64"};
531 char *float_names[] = {"float32"};
532 char *float2_names[] = {"float64"};
534 typedef struct df_binary_details_struct {
536 unsigned short no_names;
537 df_binary_type_struct type;
538 } df_binary_details_struct;
540 typedef struct df_binary_tables_struct {
541 df_binary_details_struct *group;
542 unsigned short group_length;
543 } df_binary_tables_struct;
545 df_binary_details_struct df_binary_details[] = {
546 {ch_names,sizeof(ch_names)/sizeof(ch_names[0]),{DF_CHAR,sizeof(char)}},
547 {uc_names,sizeof(uc_names)/sizeof(uc_names[0]),{DF_UCHAR,sizeof(unsigned char)}},
548 {sh_names,sizeof(sh_names)/sizeof(sh_names[0]),{DF_SHORT,sizeof(short)}},
549 {us_names,sizeof(us_names)/sizeof(us_names[0]),{DF_USHORT,sizeof(unsigned short)}},
550 {in_names,sizeof(in_names)/sizeof(in_names[0]),{DF_INT,sizeof(int)}},
551 {ui_names,sizeof(ui_names)/sizeof(ui_names[0]),{DF_UINT,sizeof(unsigned int)}},
552 {lo_names,sizeof(lo_names)/sizeof(lo_names[0]),{DF_LONG,sizeof(long)}},
553 {ul_names,sizeof(ul_names)/sizeof(ul_names[0]),{DF_ULONG,sizeof(unsigned long)}},
554 {fl_names,sizeof(fl_names)/sizeof(fl_names[0]),{DF_FLOAT,sizeof(float)}},
555 {db_names,sizeof(db_names)/sizeof(db_names[0]),{DF_DOUBLE,sizeof(double)}}
558 df_binary_details_struct df_binary_details_independent[] = {
559 {byte_names,sizeof(byte_names)/sizeof(byte_names[0]),{SIGNED_TEST(1),1}},
560 {ubyte_names,sizeof(ubyte_names)/sizeof(ubyte_names[0]),{UNSIGNED_TEST(1),1}},
561 {word_names,sizeof(word_names)/sizeof(word_names[0]),{SIGNED_TEST(2),2}},
562 {uword_names,sizeof(uword_names)/sizeof(uword_names[0]),{UNSIGNED_TEST(2),2}},
563 {word2_names,sizeof(word2_names)/sizeof(word2_names[0]),{SIGNED_TEST(4),4}},
564 {uword2_names,sizeof(uword2_names)/sizeof(uword2_names[0]),{UNSIGNED_TEST(4),4}},
565 {word4_names,sizeof(word4_names)/sizeof(word4_names[0]),{SIGNED_TEST(8),8}},
566 {uword4_names,sizeof(uword4_names)/sizeof(uword4_names[0]),{UNSIGNED_TEST(8),8}},
567 {float_names,sizeof(float_names)/sizeof(float_names[0]),{FLOAT_TEST(4),4}},
568 {float2_names,sizeof(float2_names)/sizeof(float2_names[0]),{FLOAT_TEST(8),8}}
571 int df_no_bin_cols; /* binary columns to read */
573 df_binary_tables_struct df_binary_tables[] = {
574 {df_binary_details,sizeof(df_binary_details)/sizeof(df_binary_details[0])},
575 {df_binary_details_independent,sizeof(df_binary_details_independent)/sizeof(df_binary_details_independent[0])}
578 /* Information about binary data structure, to be determined by the
579 * using and format options. This should be one greater than df_no_bin_cols.
581 static df_column_bininfo_struct *df_column_bininfo = NULL; /* allocate space as needed */
582 static int df_max_bininfo_cols = 0; /* space allocated */
584 static const char *matrix_general_binary_conflict_msg
585 = "Conflict between some matrix binary and general binary keywords";
592 /*{{{ static char *df_gets() */
598 /* HBB 20000526: prompt user for inline data, if in interactive mode */
599 if (mixed_data_fp && interactive)
600 fputs("input data ('e' ends) > ", stderr);
602 if (!fgets(line, max_line_len, data_fp))
609 len += strlen(line + len);
611 if (len > 0 && line[len - 1] == '\n') {
612 /* we have read an entire text-file line.
613 * Strip the trailing linefeed and return
618 /* buffer we provided may not be full - dont grab extra
619 * memory un-necessarily. This may trap a problem with last
620 * line in file not being properly terminated - each time
621 * through a replot loop, it was doubling buffer size
624 if ((max_line_len - len) < 32)
625 line = gp_realloc(line, max_line_len *= 2, "datafile line buffer");
627 if (!fgets(line + len, max_line_len - len, data_fp))
628 return line; /* unexpected end of file, but we have something to do */
637 /*{{{ static int df_tokenise(s) */
641 /* implement our own sscanf that takes 'missing' into account,
642 * and can understand fortran quad format
645 #ifdef EAM_DATASTRINGS
648 for (i = 0; i<MAXDATACOLS; i++)
651 #ifdef EAM_HISTOGRAMS
652 /* Auto-titling of histograms is a bit tricky because the x coord did not come */
653 /* from an explicit input column. This means our previous guess of what column */
654 /* to take the title from was probably wrong. */
655 if (key_title_auto_col && df_current_plot
656 && (df_current_plot->plot_style == HISTOGRAMS))
657 column_for_key_title = use_spec[0].column;
662 #define NOTSEP (*s != df_separator)
667 /* check store - double max cols or add 20, whichever is greater */
668 if (df_max_cols <= df_no_cols) {
669 int new_max = df_max_cols + (df_max_cols < 20 ? 20 : df_max_cols);
670 df_column = gp_realloc(df_column,
671 new_max * sizeof(df_column_struct),
673 while (df_max_cols < new_max)
674 df_column[df_max_cols++].datum = 0;
677 /* have always skipped spaces at this point */
678 df_column[df_no_cols].position = s;
681 #ifdef EAM_DATASTRINGS
682 /* Keep pointer to start of this token if user wanted it for
683 * anything, particularly if it is a string */
684 for (i = 0; i<MAXDATACOLS; i++) {
685 if (df_no_cols == use_spec[i].column-1) {
687 if (use_spec[i].expected_type == CT_STRING)
688 df_column[df_no_cols].good = DF_GOOD;
691 /* Particularly if it is supposed to be a key title */
692 if (df_no_cols == column_for_key_title-1)
693 strncpy(df_key_title,s,sizeof(df_key_title)-1);
696 /* CSV files must accept numbers inside quotes also,
697 * so we step past the quote */
698 if (*s == '"' && df_separator != '\0') {
700 df_column[df_no_cols].position = ++s;
704 /* treat contents of a quoted string as single column */
705 in_string = !in_string;
706 df_column[df_no_cols].good = DF_MISSING;
707 /* Allow timedata input to be contained in quotes */
708 if (axis_array[df_axis[df_no_cols]].timefmt)
709 df_column[df_no_cols].good = DF_STRINGDATA;
710 } else if (check_missing(s)) {
711 df_column[df_no_cols].good = DF_MISSING;
712 df_column[df_no_cols].datum = atof("NaN");
716 int dfncp1 = df_no_cols + 1;
718 /* optimizations by Corey Satten, corey@cac.washington.edu */
719 if ((fast_columns == 0)
720 || (df_no_use_specs == 0)
721 || ((df_no_use_specs > 0)
722 && (use_spec[0].column == dfncp1
723 || (df_no_use_specs > 1
724 && (use_spec[1].column == dfncp1
725 || (df_no_use_specs > 2
726 && (use_spec[2].column == dfncp1
727 || (df_no_use_specs > 3
728 && (use_spec[3].column == dfncp1
729 || (df_no_use_specs > 4
730 && (use_spec[4].column
732 || df_no_use_specs > 5)
745 /* This was the [slow] code used through version 4.0 */
746 count = sscanf(s, "%lf%n", &df_column[df_no_cols].datum, &used);
748 /* Use strtod() because
749 * - it is faster than sscanf()
750 * - sscanf(... %n ...) may not be portable
751 * - it allows error checking
752 * - atof() does not return a count or new position
755 df_column[df_no_cols].datum = gp_strtod(s, &next);
757 count = (used) ? 1 : 0;
760 /* skip any space at start of column */
761 /* HBB tells me that the cast must be to
762 * unsigned char instead of int. */
763 while (isspace((unsigned char) *s) && NOTSEP)
765 count = (*s && NOTSEP) ? 1 : 0;
766 /* skip chars to end of column */
768 if (df_separator != '\0' && in_string) {
771 while (*s && *s != '"');
774 while (!isspace((unsigned char) *s)
775 && (*s != NUL) && NOTSEP)
779 /* it might be a fortran double or quad precision.
780 * 'used' is only safe if count is 1
782 if (df_fortran_constants && count == 1 &&
783 (s[used] == 'd' || s[used] == 'D' ||
784 s[used] == 'q' || s[used] == 'Q')) {
785 /* HBB 20001221: avoid breaking parsing of time/date
786 * strings like 01Dec2000 that would be caused by
787 * overwriting the 'D' with an 'e'... */
789 char save_char = s[used];
791 /* might be fortran double */
794 df_column[df_no_cols].datum = gp_strtod(s, &endptr);
795 count = (endptr == s) ? 0 : 1;
799 df_column[df_no_cols].good = count == 1 ? DF_GOOD : DF_BAD;
801 if (isnan(df_column[df_no_cols].datum))
802 df_column[df_no_cols].good = DF_BAD;
808 /* EAM - 19 Aug 2002 If we are in a quoted string, skip to end
813 while (*s && (unsigned char) *s != '"');
816 /* skip to 1st character past next separator */
817 if (df_separator != '\0') {
820 if (*s == df_separator)
821 /* skip leading whitespace in next field */
824 while (*s && isspace((unsigned char) *s) && NOTSEP);
826 /* skip chars to end of column */
827 while ((!isspace((unsigned char) *s)) && (*s != '\0'))
829 /* skip spaces to start of next column */
830 while (isspace((unsigned char) *s))
841 #ifdef BINARY_DATA_FILE
842 /*{{{ static float *df_read_matrix() */
843 /* Reads a matrix from a text file and stores it as floats in allocated
846 * IMPORTANT NOTE: The routine returns the memory pointer for that matrix,
847 * but does not retain the pointer. Maintenance of the memory is left to
851 df_read_matrix(int *rows, int *cols)
855 float *linearized_matrix = NULL;
864 if (!(s = df_gets())) {
866 /* NULL if we have not read anything yet */
867 return linearized_matrix;
870 while (isspace((unsigned char) *s))
873 if (!*s || is_comment(*s)) {
874 if (linearized_matrix)
875 return linearized_matrix;
879 if (mixed_data_fp && is_EOF(*s)) {
881 return linearized_matrix;
886 return linearized_matrix;
888 if (*cols && c != *cols) {
889 /* its not regular */
890 if (linearized_matrix)
891 free(linearized_matrix);
892 int_error(NO_CARET, "Matrix does not represent a grid");
897 if (*rows > max_rows) {
898 max_rows = GPMAX(2*max_rows,1);
899 linearized_matrix = gp_realloc(linearized_matrix,
900 *cols * max_rows * sizeof(float),
908 for (i = 0; i < c; ++i) {
909 if (i < firstpoint && df_column[i].good != DF_GOOD) {
910 /* It's going to be skipped anyhow, so... */
911 linearized_matrix[index++] = 0;
913 linearized_matrix[index++] = (float) df_column[i].datum;
915 if (df_column[i].good != DF_GOOD) {
917 int_warn(NO_CARET,"matrix contains missing or undefined values");
925 #else /* BINARY_DATA_FILE */
927 /*{{{ static float **df_read_matrix() */
928 /* reads a matrix from a text file stores in same storage format as
930 /* FIXME HBB 20001207: doesn't respect 'index' at all, even though it
931 * could, and probably should. */
933 df_read_matrix(int *rows, int *cols)
937 float **rmatrix = NULL;
944 if (!(s = df_gets())) {
946 return rmatrix; /* NULL if we have not read anything yet */
948 while (isspace((unsigned char) *s))
951 if (!*s || is_comment(*s)) {
957 if (mixed_data_fp && is_EOF(*s)) {
966 if (*cols && c != *cols) {
967 /* its not regular */
968 int_error(NO_CARET, "Matrix does not represent a grid");
972 if (*rows >= max_rows) {
973 rmatrix = gp_realloc(rmatrix,
974 (max_rows += 10) * sizeof(float *),
978 /* allocate a row and store data */
981 float *row = rmatrix[*rows] = gp_alloc(c * sizeof(float),
984 for (i = 0; i < c; ++i) {
985 if (df_column[i].good != DF_GOOD && i >= firstpoint)
986 int_error(NO_CARET, "Bad number in matrix");
988 row[i] = (float) df_column[i].datum;
995 #endif /* BINARY_DATA_FILE */
999 initialize_use_spec()
1003 df_no_use_specs = 0;
1004 for (i = 0; i < MAXDATACOLS; ++i) {
1005 use_spec[i].column = i + 1; /* default column */
1006 #ifdef EAM_DATASTRINGS
1007 use_spec[i].expected_type = CT_DEFAULT; /* no particular expectation */
1009 if (use_spec[i].at) {
1010 free_at(use_spec[i].at);
1011 use_spec[i].at = NULL; /* no expression */
1013 df_axis[i] = -1; /* no timefmt for this output column */
1018 /*{{{ int df_open(char *file_name, max_using) */
1020 /* open file, parsing using/thru/index stuff return number of using
1021 * specs [well, we have to return something !]
1024 df_open(const char *cmd_filename, int max_using)
1026 int name_token = c_token - 1;
1027 TBOOLEAN duplication = FALSE;
1028 TBOOLEAN set_index = FALSE, set_every = FALSE, set_thru = FALSE;
1029 TBOOLEAN set_using = FALSE;
1030 #ifdef BINARY_DATA_FILE
1031 TBOOLEAN set_matrix = FALSE;
1034 fast_columns = 1; /* corey@cac */
1036 /*{{{ close file if necessary */
1041 /*{{{ initialise static variables */
1042 df_format[0] = NUL; /* no format string */
1044 #ifdef EAM_DATASTRINGS
1045 df_no_tic_specs = 0;
1047 df_key_title[0] = '\0';
1049 initialize_use_spec();
1051 df_datum = -1; /* it will be preincremented before use */
1052 df_line_number = 0; /* ditto */
1056 df_upper_index = MAXINT;
1058 df_current_index = 0;
1060 /* by initialising blank_count, leading blanks will be ignored */
1062 everypoint = everyline = 1; /* unless there is an every spec */
1063 firstpoint = firstline = 0;
1064 lastpoint = lastline = MAXINT;
1066 #ifdef BINARY_DATA_FILE
1067 df_binary_file = df_matrix_file = FALSE;
1072 #ifdef EAM_DATASTRINGS
1073 column_for_key_title = NO_COLUMN_HEADER;
1074 key_title_auto_col = FALSE;
1078 assert(max_using <= MAXDATACOLS);
1081 int_error(c_token, "missing filename");
1082 if (!cmd_filename[0]) {
1083 if (!df_filename || !*df_filename)
1084 int_error(c_token, "No previous filename");
1087 df_filename = gp_strdup(cmd_filename);
1090 /* defer opening until we have parsed the modifiers... */
1092 if (ydata_func.at) /* something for thru (?) */
1093 free_at(ydata_func.at);
1094 ydata_func.at = NULL;
1096 df_binary = df_matrix = FALSE;
1098 /* pm 25.11.2001 allow any order of options */
1099 while (!END_OF_COMMAND) {
1101 /* look for binary / matrix */
1102 if (almost_equals(c_token, "bin$ary")) {
1104 #ifdef BINARY_DATA_FILE
1105 if (df_binary_file) {
1109 df_binary_file = TRUE;
1110 /* Up to the time of adding the general binary code, only matrix
1111 * binary for 3d was defined. So, use matrix binary by default.
1113 df_matrix_file = TRUE;
1114 initialize_binary_vars();
1115 plot_option_binary(set_matrix, FALSE);
1127 /* deal with matrix */
1128 if (almost_equals(c_token, "mat$rix")) {
1130 #ifdef BINARY_DATA_FILE
1135 /* `binary` default is both df_matrix_file and df_binary_file.
1136 * So if df_binary_file is true, but df_matrix_file isn't, then
1137 * some keyword specific to general binary has been given.
1139 if (!df_matrix_file && df_binary_file)
1140 int_error(c_token, matrix_general_binary_conflict_msg);
1141 df_matrix_file = TRUE;
1144 if (df_matrix) { duplication=TRUE; break; }
1151 /* deal with index */
1152 if (almost_equals(c_token, "i$ndex")) {
1153 if (set_index) { duplication=TRUE; break; }
1154 plot_option_index();
1159 /* deal with every */
1160 if (almost_equals(c_token, "ev$ery")) {
1161 if (set_every) { duplication=TRUE; break; }
1162 plot_option_every();
1167 /* deal with thru */
1168 /* jev -- support for passing data from file thru user function */
1169 if (almost_equals(c_token, "thru$")) {
1170 if (set_thru) { duplication=TRUE; break; }
1176 /* deal with using */
1177 if (almost_equals(c_token, "u$sing")) {
1178 if (set_using) { duplication=TRUE; break; }
1179 plot_option_using(max_using);
1184 #ifdef EAM_DATASTRINGS
1185 /* Take key title from column head? */
1186 if (almost_equals(c_token, "t$itle")) {
1189 if (almost_equals(c_token, "col$umnheader") && equals(c_token+1,"(")) {
1191 column_for_key_title = (int)real(const_express(&a));
1193 } else if (almost_equals(c_token, "col$umnheader")) {
1194 key_title_auto_col = TRUE;
1195 if (df_no_use_specs == 1)
1196 column_for_key_title = use_spec[0].column;
1198 column_for_key_title = use_spec[1].column;
1200 } else if (!END_OF_COMMAND && isanumber(c_token)) {
1201 column_for_key_title = (int)real(const_express(&a));
1202 } else /* Let the general case parser handle it */
1207 break; /* unknown option */
1209 } /* while (!END_OF_COMMAND) */
1213 "duplicated or contradicting arguments in datafile options");
1215 #ifdef EAM_DATASTRINGS
1216 /* Check for auto-generation of key title from column header */
1217 if (column_for_key_title == NO_COLUMN_HEADER) {
1218 legend_key *key = &keyT;
1220 if (key->auto_titles == COLUMNHEAD_KEYTITLES) {
1221 key_title_auto_col = TRUE;
1222 if (df_no_use_specs == 1)
1223 column_for_key_title = use_spec[0].column;
1225 column_for_key_title = use_spec[1].column;
1230 /*{{{ more variable inits */
1231 point_count = -1; /* we preincrement */
1234 /* here so it's not done for every line in df_readline */
1235 if (max_line_len < DATA_LINE_BUFSIZ) {
1236 max_line_len = DATA_LINE_BUFSIZ;
1237 line = gp_alloc(max_line_len, "datafile line buffer");
1243 if (*df_filename == '<') {
1244 if ((data_fp = popen(df_filename + 1, "r")) == (FILE *) NULL)
1245 os_error(name_token, "cannot create pipe for data");
1247 df_pipe_open = TRUE;
1250 /* I don't want to call strcmp(). Does it make a difference? */
1251 if (*df_filename == '-' && strlen(df_filename) == 1) {
1252 plotted_data_from_stdin = TRUE;
1256 mixed_data_fp = TRUE; /* don't close command file */
1258 /* filename cannot be static array! */
1259 gp_expand_tilde(&df_filename);
1260 #ifdef HAVE_SYS_STAT_H
1262 struct stat statbuf;
1263 if ((stat(df_filename, &statbuf) > -1) &&
1264 !S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) {
1265 os_error(name_token, "\"%s\" is not a regular file or pipe",
1269 #endif /* HAVE_SYS_STAT_H */
1270 #ifdef BINARY_DATA_FILE
1271 if ((data_fp = loadpath_fopen(df_filename, df_binary_file ? "rb" : "r")) ==
1273 if ((data_fp = loadpath_fopen(df_filename, df_binary ? "rb" : "r")) ==
1276 int_warn(NO_CARET, "Skipping unreadable file \"%s\"", df_filename);
1283 #ifdef BINARY_DATA_FILE
1284 /* If the data is in binary matrix form, read in some values
1285 * to determine the nubmer of columns and rows. If data is in
1286 * ASCII matrix form, read in all the data to memory in preparation
1287 * for using df_readbinary() routine.
1290 df_determine_matrix_info(data_fp);
1292 /* General binary, matrix binary and ASCII matrix all use the
1293 * df_readbinary() routine.
1295 if (df_binary_file || df_matrix_file) {
1296 df_read_binary = TRUE;
1297 adjust_binary_use_spec();
1299 df_read_binary = FALSE;
1301 /* Make information about whether the data forms a grid or not
1302 * available to the outside world. */
1303 df_matrix = (df_matrix_file
1304 || ((df_num_bin_records == 1)
1305 && ((df_bin_record[0].cart_dim[1] > 0)
1306 || (df_bin_record[0].scan_dim[1] > 0))));
1308 /* Same idea, but try removing this one. I can't see why it is
1309 * important for the rest of the program to know if if the data
1310 * came from a binary file. (DJS 20 Aug 2004) */
1311 df_binary = df_binary_file;
1312 #endif /* BINARY_DATA_FILE */
1314 return df_no_use_specs;
1319 /*{{{ void df_close() */
1325 /* paranoid - mark $n and column(n) as invalid */
1331 if (ydata_func.at) {
1332 free_at(ydata_func.at);
1333 ydata_func.at = NULL;
1335 /*{{{ free any use expression storage */
1336 for (i = 0; i < MAXDATACOLS; ++i)
1337 if (use_spec[i].at) {
1338 free_at(use_spec[i].at);
1339 use_spec[i].at = NULL;
1343 if (!mixed_data_fp) {
1346 (void) pclose(data_fp);
1347 df_pipe_open = FALSE;
1350 (void) fclose(data_fp);
1352 mixed_data_fp = FALSE;
1358 /*{{{ void df_showdata() */
1359 /* display the current data file line for an error message
1364 if (data_fp && df_filename && line) {
1365 /* display no more than 77 characters */
1366 fprintf(stderr, "%.77s%s\n%s:%d:", line,
1367 (strlen(line) > 77) ? "..." : "",
1368 df_filename, df_line_number);
1380 fast_columns = 0; /* corey@cac */
1381 /* allow empty fields - every a:b:c::e we have already established
1384 if (!equals(++c_token, ":")) {
1385 everypoint = (int) real(const_express(&a));
1387 int_error(c_token, "Expected positive integer");
1389 /* if it fails on first test, no more tests will succeed. If it
1390 * fails on second test, next test will succeed with correct
1392 if (equals(c_token, ":") && !equals(++c_token, ":")) {
1393 everyline = (int) real(const_express(&a));
1395 int_error(c_token, "Expected positive integer");
1397 if (equals(c_token, ":") && !equals(++c_token, ":")) {
1398 firstpoint = (int) real(const_express(&a));
1400 int_error(c_token, "Expected non-negative integer");
1402 if (equals(c_token, ":") && !equals(++c_token, ":")) {
1403 firstline = (int) real(const_express(&a));
1405 int_error(c_token, "Expected non-negative integer");
1407 if (equals(c_token, ":") && !equals(++c_token, ":")) {
1408 lastpoint = (int) real(const_express(&a));
1409 if (lastpoint < firstpoint)
1410 int_error(c_token, "Last point must not be before first point");
1412 if (equals(c_token, ":")) {
1414 lastline = (int) real(const_express(&a));
1415 if (lastline < firstline)
1416 int_error(c_token, "Last line must not be before first line");
1426 #ifdef BINARY_DATA_FILE
1427 if (df_binary_file && df_matrix_file)
1428 int_error(c_token, "Binary matrix file format does not allow more than one surface per file");
1431 int_error(c_token, "Binary file format does not allow more than one surface per file");
1435 df_lower_index = (int) real(const_express(&a));
1436 if (equals(c_token, ":")) {
1438 df_upper_index = (int) magnitude(const_express(&a));
1439 if (df_upper_index < df_lower_index)
1440 int_error(c_token, "Upper index should be bigger than lower index");
1442 if (equals(c_token, ":")) {
1444 df_index_step = (int) magnitude(const_express(&a));
1445 if (df_index_step < 1)
1446 int_error(c_token, "Index step must be positive");
1449 df_upper_index = df_lower_index;
1457 strcpy(c_dummy_var[0], set_dummy_var[0]);
1458 /* allow y also as a dummy variable.
1459 * during plot, c_dummy_var[0] and [1] are 'sacred'
1460 * ie may be set by splot [u=1:2] [v=1:2], and these
1461 * names are stored only in c_dummy_var[]
1462 * so choose dummy var 2 - can anything vital be here ?
1464 dummy_func = &ydata_func;
1465 strcpy(c_dummy_var[2], "y");
1466 ydata_func.at = perm_at();
1472 plot_option_using(int max_using)
1475 int no_cols = 0; /* For general binary only. */
1477 #ifdef BINARY_DATA_FILE
1478 /* The filetype function may have set the using specs, so reset
1479 * them before processing tokens. */
1481 initialize_use_spec();
1484 if (!END_OF_COMMAND && !isstring(++c_token)) {
1487 do { /* must be at least one */
1488 if (df_no_use_specs >= max_using)
1489 int_error(c_token, "Too many columns in using specification");
1491 if (equals(c_token, ":")) {
1492 /* empty specification - use default */
1493 use_spec[df_no_use_specs].column = df_no_use_specs;
1494 if (df_no_use_specs > no_cols)
1495 no_cols = df_no_use_specs;
1497 /* do not increment c+token ; let while() find the : */
1498 } else if (equals(c_token, "(")) {
1499 fast_columns = 0; /* corey@cac */
1500 dummy_func = NULL; /* no dummy variables active */
1501 /* this will match ()'s: */
1502 at_highest_column_used = NO_COLUMN_HEADER;
1503 use_spec[df_no_use_specs].at = perm_at();
1504 if (no_cols < at_highest_column_used)
1505 no_cols = at_highest_column_used;
1506 /* Catch at least the simplest case of 'autotitle columnhead' using an expression */
1507 use_spec[df_no_use_specs++].column = at_highest_column_used;
1509 #ifdef EAM_DATASTRINGS
1510 /* FIXME EAM - It would be nice to handle these like any other */
1511 /* internal function via perm_at() but there are problems. */
1512 } else if (almost_equals(c_token, "xtic$labels")) {
1513 plot_ticlabel_using(CT_XTICLABEL);
1514 } else if (almost_equals(c_token, "x2tic$labels")) {
1515 plot_ticlabel_using(CT_X2TICLABEL);
1516 } else if (almost_equals(c_token, "ytic$labels")) {
1517 plot_ticlabel_using(CT_YTICLABEL);
1518 } else if (almost_equals(c_token, "y2tic$labels")) {
1519 plot_ticlabel_using(CT_Y2TICLABEL);
1520 } else if (almost_equals(c_token, "ztic$labels")) {
1521 plot_ticlabel_using(CT_ZTICLABEL);
1522 } else if (almost_equals(c_token, "cbtic$labels")) {
1523 plot_ticlabel_using(CT_CBTICLABEL);
1524 } else if (almost_equals(c_token, "key")) {
1525 plot_ticlabel_using(CT_KEYLABEL);
1526 #endif /* EAM_DATASTRINGS */
1528 int col = (int) real(const_express(&a));
1531 int_error(c_token, "Column must be >= -2");
1532 use_spec[df_no_use_specs++].column = col;
1536 } while (equals(c_token, ":") && ++c_token);
1538 #ifdef BINARY_DATA_FILE
1539 if (df_binary_file) {
1540 /* If the highest user column number is greater than number of binary
1541 * columns, set the unitialized columns binary info to that of the last
1542 * specified column or the default.
1544 df_extend_binary_columns(no_cols);
1547 if (!END_OF_COMMAND && isstring(c_token)) {
1548 #ifdef BINARY_DATA_FILE
1550 # if BINARY_HAS_OWN_FORMAT_STRING
1551 int_error(NO_CARET, "Place format string with `binary` keyword, i.e., \"binary format='...'\"\n\t or use \"binary filetype=...\" for in-file format if supported");
1554 int_error(c_token, matrix_general_binary_conflict_msg);
1555 plot_option_binary_format();
1556 # endif /* BINARY_HAS_OWN_FORMAT_STRING */
1557 #else /* BINARY_DATA_FILE */
1559 int_error(NO_CARET, "Format string meaningless with binary data");
1560 #endif /* BINARY_DATA_FILE */
1561 quote_str(df_format, c_token, MAX_LINE_LEN);
1562 if (!valid_format(df_format))
1564 "Please use between 1 and 7 conversions, of type double (%%lf)");
1566 c_token++; /* skip format */
1571 #ifdef EAM_DATASTRINGS
1573 void plot_ticlabel_using(int axis)
1580 #ifdef GP_STRING_VARS
1581 /* FIXME: What we really want is a test for a constant expression as */
1582 /* opposed to a dummy expression. This is similar to the problem with */
1583 /* with parsing the first argument of the plot command itself. */
1584 if (isanumber(c_token) || type_udv(c_token)==INTGR) {
1585 col = (int) real(const_express(&a));
1586 use_spec[df_no_use_specs+df_no_tic_specs].at = NULL;
1588 use_spec[df_no_use_specs+df_no_tic_specs].at = perm_at();
1589 fast_columns = 0; /* Force all columns to be evaluated */
1590 col = 1; /* Redundant because of the above */
1593 col = (int) real(const_express(&a));
1597 int_error(c_token, "ticlabels must come from a real column");
1599 use_spec[df_no_use_specs+df_no_tic_specs].expected_type = axis;
1600 use_spec[df_no_use_specs+df_no_tic_specs].column = col;
1603 #endif /* EAM_DATASTRINGS */
1606 /*{{{ int df_readline(v, max) */
1608 df_readline(double v[], int max)
1613 #ifdef BINARY_DATA_FILE
1615 /* General binary, matrix binary or matrix ascii
1616 * that's been converted to binary.
1618 return df_readbinary(v, max);
1621 return df_readascii(v, max);
1626 /* do the hard work... read lines from file,
1627 * - use blanks to get index number
1628 * - ignore lines outside range of indices required
1629 * - fill v[] based on using spec if given
1633 df_readascii(double v[], int max)
1637 assert(data_fp != NULL);
1638 assert(max_line_len); /* alloc-ed in df_open() */
1639 assert(max <= MAXDATACOLS);
1641 /* catch attempt to read past EOF on mixed-input */
1645 /*{{{ process line */
1646 while ((s = df_gets()) != NULL) {
1648 int output = 0; /* how many numbers written to v[] */
1653 /*{{{ check for blank lines, and reject by index/every */
1654 /*{{{ skip leading spaces */
1655 while (isspace((unsigned char) *s))
1656 ++s; /* will skip the \n too, to point at \0 */
1659 /*{{{ skip comments */
1661 continue; /* ignore comments */
1664 /*{{{ check EOF on mixed data */
1665 if (mixed_data_fp && is_EOF(*s)) {
1666 df_eof = 1; /* trap attempts to read past EOF */
1671 /*{{{ its a blank line - update counters and continue or return */
1673 /* argh - this is complicated ! we need to
1674 * ignore it if we haven't reached first index
1675 * report EOF if passed last index
1676 * report blank line unless we've already done 2 blank lines
1678 * - I have probably missed some obvious way of doing all this,
1679 * but its getting late
1682 point_count = -1; /* restart counter within line */
1684 if (++blank_count == 1) {
1685 /* first blank line */
1688 /* just reached end of a group/surface */
1689 if (blank_count == 2) {
1693 /* ignore line if current_index has just become
1694 * first required one - client doesn't want this
1695 * blank line. While we're here, check for <=
1696 * - we need to do it outside this conditional, but
1697 * probably no extra cost at assembler level
1699 if (df_current_index <= df_lower_index)
1700 continue; /* dont tell client */
1702 /* df_upper_index is MAXINT-1 if we are not doing index */
1703 if (df_current_index > df_upper_index) {
1704 /* oops - need to gobble rest of input if mixed */
1709 return DF_EOF; /* no point continuing */
1713 /* dont tell client if we haven't reached first index */
1714 if (df_current_index < df_lower_index)
1717 /* ignore blank lines after blank_index */
1718 if (blank_count > 2)
1721 return DF_FIRST_BLANK - (blank_count - 1);
1725 /* get here => was not blank */
1729 /*{{{ ignore points outside range of index */
1730 /* we try to return end-of-file as soon as we pass upper index,
1731 * but for mixed input stream, we must skip garbage
1734 if (df_current_index < df_lower_index ||
1735 df_current_index > df_upper_index ||
1736 ((df_current_index - df_lower_index) % df_index_step) != 0)
1740 /*{{{ reject points by every */
1741 /* accept only lines with (line_count%everyline) == 0 */
1743 if (line_count < firstline || line_count > lastline ||
1744 (line_count - firstline) % everyline != 0)
1747 /* update point_count. ignore point if point_count%everypoint != 0 */
1749 if (++point_count < firstpoint || point_count > lastpoint ||
1750 (point_count - firstpoint) % everypoint != 0)
1758 /*{{{ do a sscanf */
1761 assert(MAXDATACOLS == 7);
1763 /* check we have room for at least 7 columns */
1764 if (df_max_cols < 7) {
1766 df_column = gp_realloc(df_column,
1767 df_max_cols * sizeof(df_column_struct),
1768 "datafile columns");
1771 df_no_cols = sscanf(line, df_format,
1772 &df_column[0].datum,
1773 &df_column[1].datum,
1774 &df_column[2].datum,
1775 &df_column[3].datum,
1776 &df_column[4].datum,
1777 &df_column[5].datum,
1778 &df_column[6].datum);
1780 if (df_no_cols == EOF) {
1782 return DF_EOF; /* tell client */
1784 for (i = 0; i < df_no_cols; ++i) { /* may be zero */
1785 df_column[i].good = DF_GOOD;
1786 df_column[i].position = NULL; /* cant get a time */
1792 #ifdef EAM_DATASTRINGS
1793 /* If we are supposed to read plot or key titles from the
1794 * first line of the data then do that and nothing else. */
1795 if (column_for_key_title != NO_COLUMN_HEADER) {
1797 if (!(*df_key_title)) {
1799 "df_readline: missing column head for key title\n"));
1800 return(DF_KEY_TITLE_MISSING);
1802 df_parse_string_field(df_key_title, df_key_title);
1804 "df_readline: Found key title in col %d %s\n",
1805 column_for_key_title, df_key_title));
1806 column_for_key_title = NO_COLUMN_HEADER;
1807 key_title_auto_col = FALSE;
1808 return(DF_FOUND_KEY_TITLE);
1812 /*{{{ copy column[] to v[] via use[] */
1814 #ifdef EAM_DATASTRINGS
1815 int limit = (df_no_use_specs
1816 ? df_no_use_specs + df_no_tic_specs
1819 if (limit > max + df_no_tic_specs)
1820 limit = max + df_no_tic_specs;
1822 int limit = (df_no_use_specs ? df_no_use_specs : MAXDATACOLS);
1827 for (output = 0; output < limit; ++output) {
1828 /* if there was no using spec, column is output+1 and
1830 int column = use_spec[output].column;
1832 #ifdef EAM_DATASTRINGS
1833 /* Handle cases where column holds a meta-data string */
1834 /* Axis labels, plot titles, etc. */
1835 if (use_spec[output].expected_type >= CT_XTICLABEL) {
1836 char temp_string[MAX_TOKEN_LENGTH];
1840 switch (use_spec[output].expected_type) {
1843 axis = FIRST_X_AXIS;
1847 axis = SECOND_X_AXIS;
1851 axis = FIRST_Y_AXIS;
1855 axis = SECOND_Y_AXIS;
1859 axis = FIRST_Z_AXIS;
1863 /* EAM FIXME - Which column to set for cbtic? */
1868 /* FIXME EAM - Trap special case of only a single
1869 * 'using' column. But really we need to handle
1870 * general case of implicit column 0 */
1872 xpos = (axcol == 0) ? df_datum : v[axcol-1];
1875 #ifdef EAM_HISTOGRAMS
1877 && df_current_plot->plot_style == HISTOGRAMS) {
1878 if (output == 2) /* Can only happen for HT_ERRORBARS */
1879 xpos = (axcol == 0) ? df_datum : v[axcol-1];
1880 xpos += df_current_plot->histogram->start;
1884 #ifdef GP_STRING_VARS
1885 /* Tic label is generated by a string-valued function */
1886 if (use_spec[output].at) {
1888 evaluate_inside_using = TRUE;
1889 evaluate_at(use_spec[output].at, &a);
1890 evaluate_inside_using = FALSE;
1891 if (a.type == STRING) {
1892 add_tic_user(axis,a.v.string_val, xpos, -1);
1895 fprintf(stderr,"Tic label does not evaluate as string!\n");
1899 df_parse_string_field(temp_string,df_tokens[output]);
1900 add_tic_user(axis,temp_string, xpos, -1);
1902 #ifdef EAM_HISTOGRAMS
1903 } else if (use_spec[output].expected_type == CT_KEYLABEL) {
1904 char temp_string[MAX_TOKEN_LENGTH];
1905 df_parse_string_field(temp_string,df_tokens[output]);
1906 if (df_current_plot)
1907 add_key_entry(temp_string,df_datum);
1911 if (use_spec[output].at) {
1913 /* no dummy values to set up prior to... */
1914 evaluate_inside_using = TRUE;
1915 evaluate_at(use_spec[output].at, &a);
1916 evaluate_inside_using = FALSE;
1918 return DF_UNDEFINED; /* store undefined point in plot */
1920 #if defined(GP_STRING_VARS) && defined(EAM_DATASTRINGS)
1921 if (a.type == STRING) {
1922 /* This string value will get parsed as if it were a data column */
1923 /* so put it in quotes to allow embedded whitespace. */
1924 if (use_spec[output].expected_type == CT_STRING) {
1925 char *s = gp_alloc(strlen(a.v.string_val)+3,"quote");
1927 strcpy(s+1, a.v.string_val);
1929 free(df_stringexpression[output]);
1930 df_tokens[output] = df_stringexpression[output] = s;
1933 /* Check for timefmt string generated by a function */
1934 if ((df_axis[output] != -1)
1935 && axis_array[df_axis[output]].is_timedata) {
1937 if (gstrptime(a.v.string_val,
1938 axis_array[df_axis[output]].timefmt, &tm))
1939 v[output] = (double) gtimegm(&tm);
1940 else /* FIXME - Is this correct? Is it needed? */
1946 v[output] = real(&a);
1948 } else if (column == -2) {
1949 v[output] = df_current_index;
1950 } else if (column == -1) {
1951 v[output] = line_count;
1952 } else if (column == 0) {
1953 v[output] = df_datum; /* using 0 */
1954 } else if (column <= 0) /* really < -2, but */
1955 int_error(NO_CARET, "internal error: column <= 0 in datafile.c");
1956 else if ((df_axis[output] != -1)
1957 && (axis_array[df_axis[output]].is_timedata)) {
1959 if (column > df_no_cols ||
1960 df_column[column - 1].good == DF_MISSING ||
1961 !df_column[column - 1].position ||
1962 !gstrptime(df_column[column - 1].position,
1963 axis_array[df_axis[output]].timefmt, &tm)
1965 /* line bad only if user explicitly asked for this column */
1966 if (df_no_use_specs)
1969 /* return or ignore line depending on line_okay */
1972 v[output] = (double) gtimegm(&tm);
1973 #ifdef EAM_DATASTRINGS
1974 } else if (use_spec[output].expected_type == CT_STRING) {
1976 /* String tokens were loaded into df_tokens already. */
1980 if ((column <= df_no_cols)
1981 && df_column[column - 1].good == DF_GOOD)
1982 v[output] = df_column[column - 1].datum;
1983 /* EAM - Oct 2002 Distinguish between
1984 * DF_MISSING and DF_BAD. Previous versions
1985 * would never notify caller of either case.
1986 * Now missing data will be noted. Bad data
1987 * should arguably be noted also, but that
1988 * would change existing default behavior. */
1989 else if ((column <= df_no_cols)
1990 && (df_column[column - 1].good == DF_MISSING))
1993 /* line bad only if user explicitly asked
1994 * for this column */
1995 if (df_no_use_specs)
1997 break; /* return or ignore depending on line_okay */
2007 /* output == df_no_use_specs if using was specified -
2008 * actually, smaller of df_no_use_specs and max */
2009 #ifdef EAM_DATASTRINGS
2010 /* FIXME EAM - In theory it might be useful for the caller to
2011 * know whether or not tic specs were read from this line, but
2012 * all callers would have to be modified to deal with it one
2013 * way or the other. */
2014 output -= df_no_tic_specs;
2016 assert(df_no_use_specs == 0
2017 || output == df_no_use_specs
2025 /* get here => fgets failed */
2027 /* no longer needed - mark column(x) as invalid */
2036 #ifndef BINARY_DATA_FILE
2037 /*{{{ int df_2dbinary(this_plot) */
2039 df_2dbinary(struct curve_points *this_plot)
2041 (void) this_plot; /* avoid -Wunused warning */
2042 int_error(NO_CARET, "Binary file format for 2d data not yet defined");
2043 return 0; /* keep compiler happy */
2049 #ifndef BINARY_DATA_FILE /* NO LONGER REQUIRED FOR GENERAL BINARY DATA */
2050 /*{{{ int df_3dmatrix(this_plot, ret_this_iso) */
2052 * formerly in gnubin.c
2054 * modified by div for 3.6
2055 * obey the 'every' field from df_open
2056 * outrange points are marked as such, not omitted
2057 * obey using - treat x as column 1, y as col 2 and z as col 3
2058 * ( ie $1 gets x, $2 gets y, $3 gets z)
2060 * we are less optimal for case of log plot and no using spec,
2061 * (call log too often) but that is price for flexibility
2062 * I suspect it didn't do autoscaling of x and y for log scale
2065 * Trouble figuring out file format ! Is it
2067 width x1 x2 x3 x4 x5 ...
2068 y1 z11 z12 z13 z14 z15 ...
2069 y2 x21 z22 z23 .....
2074 * with perhaps x and y swapped...
2076 * - presumably rows continue to end of file, hence no indexing...
2078 * Last update: 3/3/92 for Gnuplot 3.24.
2079 * Created from code for written by RKC for gnuplot 2.0b.
2081 * 19 September 1992 Lawrence Crowl (crowl@cs.orst.edu)
2082 * Added user-specified bases for log scaling.
2084 * Copyright (c) 1991,1992 Robert K. Cunningham, MIT Lincoln Laboratory
2089 * Here we keep putting new plots onto the end of the linked list
2091 * We assume the data's x,y values have x1<x2, x2<x3... and
2093 * Actually, I think the assumption is less strong than that--it looks like
2094 * the direction just has to be the same.
2096 * This routine expects all the 'axis array' variables (now gathered
2097 * in axis.h) to be properly initialized
2099 * does the autoscaling into the array versions (min_array[], max_array[]) */
2102 df_3dmatrix(struct surface_points *this_plot, int need_palette)
2104 float GPFAR * GPFAR * dmatrix, GPFAR * rt, GPFAR * ct;
2108 struct iso_curve *this_iso;
2109 double used[4]; /* output from using manip */
2110 /* evaluate used[0..use_spec_34] */
2111 int use_spec_34 = (need_palette && df_no_use_specs == 4) ? 4 : 3;
2112 struct coordinate GPHUGE *point; /* HBB 980308: added 'GPHUGE' flag */
2117 return 0; /* hope caller understands this */
2120 if (!fread_matrix(data_fp, &dmatrix, &nr, &nc, &rt, &ct))
2121 int_error(NO_CARET, "Binary file read error: format unknown!");
2122 /* fread_matrix() drains the file */
2125 if (!(dmatrix = df_read_matrix(&nr, &nc))) {
2129 /* HBB 20001208: implement 'index' for matrix files: don't return
2130 * the data to caller if index is not among of the selected
2132 if (df_current_index < df_lower_index
2133 || df_current_index > df_upper_index
2134 || (df_current_index - df_lower_index) % df_index_step != 0
2136 free_matrix(dmatrix, 0, nr - 1, 0);
2137 df_current_index ++;
2145 if (nc == 0 || nr == 0)
2146 int_error(NO_CARET, "Read grid of zero height or zero width");
2148 this_plot->plot_type = DATA3D;
2149 this_plot->has_grid_topology = TRUE;
2151 if (df_no_use_specs != 0
2152 && df_no_use_specs != 3
2153 && df_no_use_specs != use_spec_34 /*3 or 4*/)
2154 int_error(NO_CARET, "Current implementation requires full `using` spec");
2156 if (need_palette && df_no_use_specs == 4)
2157 this_plot->pm3d_color_from_column = 1;
2159 /* columns are those in the binary data file, not those of `using` spec */
2160 if (df_max_cols < 3) {
2162 df_column = gp_realloc(df_column,
2163 df_max_cols * sizeof(df_column_struct),
2164 "datafile columns");
2168 df_column[0].good = df_column[1].good = df_column[2].good = DF_GOOD;
2170 assert(everyline > 0);
2171 assert(everypoint > 0);
2172 width = (nc - firstpoint + everypoint - 1) / everypoint; /* ? ? ? ? ? */
2173 height = (nr - firstline + everyline - 1) / everyline; /* ? ? ? ? ? */
2175 for (row = firstline; row < nr; row += everyline) {
2176 df_column[1].datum = rt ? rt[row] : row;
2178 /* Allocate the correct number of entries */
2179 this_iso = iso_alloc(width);
2181 point = this_iso->points;
2183 /* Cycle through data */
2184 for (col = firstpoint; col < nc; col += everypoint, ++point) {
2185 /*{{{ process one point */
2188 df_column[0].datum = ct ? ct[col] : col;
2189 df_column[2].datum = dmatrix[row][col];
2191 /*{{{ pass through using spec */
2192 for (i = 0; i < use_spec_34; ++i) {
2193 int column = use_spec[i].column;
2195 if (df_no_use_specs == 0)
2196 used[i] = df_column[i].datum;
2197 else if (use_spec[i].at) {
2199 evaluate_inside_using = TRUE;
2200 evaluate_at(use_spec[i].at, &a);
2201 evaluate_inside_using = FALSE;
2203 point->type = UNDEFINED;
2204 goto skip; /* continue _outer_ loop */
2207 } else if (column < 1 || column > df_no_cols) {
2208 point->type = UNDEFINED;
2211 used[i] = df_column[column - 1].datum;
2214 if (df_no_use_specs != 4)
2215 used[3] = used[2]; /* 3 parameters of `using` => 4th color-value equals z-value */
2217 point->type = INRANGE; /* so far */
2219 STORE_WITH_LOG_AND_UPDATE_RANGE(point->x, used[0], point->type, FIRST_X_AXIS, NOOP, goto skip);
2220 STORE_WITH_LOG_AND_UPDATE_RANGE(point->y, used[1], point->type, FIRST_Y_AXIS, NOOP, goto skip);
2221 STORE_WITH_LOG_AND_UPDATE_RANGE(point->z, used[2], point->type, FIRST_Z_AXIS, NOOP, goto skip);
2223 COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(point->CRD_COLOR, used[3], point->type, COLOR_AXIS, NOOP, goto skip);
2226 /* some of you won't like this, but I say goto is for this */
2229 ; /* ansi requires this */
2232 this_iso->p_count = width;
2233 this_iso->next = this_plot->iso_crvs;
2234 this_plot->iso_crvs = this_iso;
2235 this_plot->num_iso_read++;
2238 free_matrix(dmatrix, 0, nr - 1, 0);
2244 /* HBB 20001208: implement 'index' for matrix datafiles */
2245 df_current_index ++;
2252 #else /* REPLACED BY df_readbinary() READING JUST THE FIRST ROW AND SAVING FOR LATER USE. */
2254 char *read_error_msg = "Data file read error";
2255 double df_matrix_corner[2][2]; /* First argument is corner, second argument is x (0) or y(1). */
2258 df_read_a_float(FILE *fin) {
2260 if (fread(&fdummy, sizeof(fdummy), 1, fin) != 1) {
2262 int_error(NO_CARET, "Data file is empty");
2264 int_error(NO_CARET, read_error_msg);
2266 df_swap_bytes_by_endianess((char *)&fdummy, byte_read_order(df_bin_file_endianess), sizeof(fdummy));
2271 df_determine_matrix_info(FILE *fin)
2274 if (df_binary_file) {
2276 /* Binary matrix format. */
2281 /* Read first value for number of columns. */
2282 fdummy = df_read_a_float(fin);
2283 nc = ((size_t) fdummy);
2285 int_error(NO_CARET, "Read grid of zero width");
2287 int_error(NO_CARET, "Read grid width too large"); /* A sanity check on reading absurd numbers. */
2289 /* Read second value for corner_0 x. */
2290 fdummy = df_read_a_float(fin);
2291 df_matrix_corner[0][0] = fdummy;
2293 /* Read nc+1 value for corner_1 x. */
2295 fseek(fin, (nc-2)*sizeof(float), SEEK_CUR);
2296 fdummy = df_read_a_float(fin);
2298 df_matrix_corner[1][0] = fdummy;
2300 /* Read nc+2 value for corner_0 y. */
2301 df_matrix_corner[0][1] = df_read_a_float(fin);
2303 /* Compute length of file and number of columns. */
2304 fseek(fin, 0L, SEEK_END);
2305 flength = ftell(fin)/sizeof(float);
2306 nr = flength/(nc + 1);
2307 if (nr*(nc + 1) != flength)
2308 int_error(NO_CARET, "File doesn't factorize into full matrix");
2310 /* Read last value for corner_1 y */
2311 fseek(fin, -(nc + 1)*sizeof(float), SEEK_END);
2312 df_matrix_corner[1][1] = df_read_a_float(fin);
2314 /* Set up scan information for df_readbinary(). */
2315 df_bin_record[0].scan_dim[0] = nc;
2316 df_bin_record[0].scan_dim[1] = nr;
2318 /* Reset counter file pointer. */
2319 fseek(fin, 0L, SEEK_SET);
2323 /* ASCII matrix format, converted to binary memory format. */
2324 static float *matrix = NULL;
2327 /* Insurance against creating a matrix with df_read_matrix()
2328 * and then erroring out through df_add_binary_records().
2333 /* Set important binary variables, then free memory for all default
2334 * binary records and set number of records to 0. */
2335 initialize_binary_vars();
2336 clear_binary_records(DF_CURRENT_RECORDS);
2338 /* Keep reading matrices until file is empty. */
2340 if ((matrix = df_read_matrix(&nr, &nc)) != NULL) {
2341 int index = df_num_bin_records;
2342 /* *** Careful! Could error out in next step. "matrix" should
2343 * be static and test next time. ***
2345 df_add_binary_records(1, DF_CURRENT_RECORDS);
2346 df_bin_record[index].memory_data = (char *) matrix;
2348 df_bin_record[index].scan_dim[0] = nc;
2349 df_bin_record[index].scan_dim[1] = nr;
2350 df_bin_record[index].scan_dim[2] = 0;
2351 df_bin_file_endianess = THIS_COMPILER_ENDIAN;
2356 /* Data from file is now in memory. Make the rest of gnuplot think
2357 * that the data stream has not yet reached the end of file.
2367 /* stuff for implementing the call-backs for picking up data values
2368 * do it here so we can make the variables private to this file
2371 /*{{{ void f_dollars(x) */
2373 f_dollars(union argument *x)
2375 int column = x->v_arg.v.int_val - 1;
2376 /* we checked it was an integer >= 0 at compile time */
2380 push(Gcomplex(&a, (double) df_datum, 0.0)); /* $0 */
2381 } else if (column >= df_no_cols || df_column[column].good != DF_GOOD) {
2383 push(&(x->v_arg)); /* this okay ? */
2385 push(Gcomplex(&a, df_column[column].datum, 0.0));
2390 /*{{{ void f_column() */
2392 f_column(union argument *arg)
2397 (void) arg; /* avoid -Wunused warning */
2399 column = (int) real(&a);
2401 if (!evaluate_inside_using)
2402 int_error(c_token-1, "column() called from invalid context");
2405 push(Ginteger(&a, df_current_index));
2406 else if (column == -1)
2407 push(Ginteger(&a, line_count));
2408 else if (column == 0) /* $0 = df_datum */
2409 push(Gcomplex(&a, (double) df_datum, 0.0));
2411 || column > df_no_cols
2412 || df_column[column - 1].good != DF_GOOD
2415 push(&a); /* any objection to this ? */
2417 push(Gcomplex(&a, df_column[column - 1].datum, 0.0));
2420 /* Called from int_error() */
2422 df_reset_after_error()
2424 evaluate_inside_using = FALSE;
2427 #ifdef GP_STRING_VARS
2429 f_stringcolumn(union argument *arg)
2434 (void) arg; /* avoid -Wunused warning */
2436 column = (int) real(&a);
2438 if (!evaluate_inside_using)
2439 int_error(c_token-1, "stringcolumn() called from invalid context");
2441 if (column < 1 || column > df_no_cols) {
2443 push(&a); /* any objection to this ? */
2445 static char temp_string[MAX_TOKEN_LENGTH];
2446 df_parse_string_field(temp_string, df_column[column-1].position);
2447 push(Gstring(&a, temp_string ));
2452 /*{{{ void f_valid() */
2454 f_valid(union argument *arg)
2459 (void) arg; /* avoid -Wunused warning */
2461 column = (int) magnitude(&a) - 1;
2463 && column < df_no_cols
2464 && df_column[column].good == DF_GOOD;
2465 push(Ginteger(&a, good));
2470 /*{{{ void f_timecolumn() */
2471 /* HBB NOTE 20050505: this job is excessively tricky. We have one
2472 * timefmt string per axis. Back then, that was essentially the only
2473 * possibility, but it now poses a severe limitation. For simple
2474 * using specs, the time parsing format should be a function of the
2475 * column number in the datafile, not of the axis the data will be
2476 * used for. For extended using specs, the value to go on a given
2477 * axis could conceivably be built from multiple time/date entries in
2478 * the datafile, each with its own format. */
2479 /* HBB FIXME 20050505: this really should take two arguments, at
2480 * least. First, the datafile column number. Second either a timefmt
2481 * string (variable), or an axis index. For now, we have to try to
2482 * guess the right axis index */
2484 f_timecolumn(union argument *arg)
2488 AXIS_INDEX whichaxis;
2490 int limit = (df_no_use_specs ? df_no_use_specs : MAXDATACOLS);
2492 (void) arg; /* avoid -Wunused warning */
2494 column = (int) magnitude(&a); /* HBB 20050505: removed - 1*/
2496 if (!evaluate_inside_using)
2497 int_error(c_token-1, "timecolumn() called from invalid context");
2499 /* try to match datafile column with spec field number */
2500 whichaxis = FIRST_X_AXIS;
2501 for (spec = 0; spec<limit; spec++)
2502 if(use_spec[spec].column == column) {
2503 /* Found a 'using' specifier whose (default) column number
2504 * is the same as the column being referred to here. So
2505 * assume this spec's output axis is the one that we want
2506 * to use the timefmt of. */
2507 whichaxis = df_axis[spec];
2512 || column > df_no_cols
2513 || !df_column[column - 1].position
2514 || !gstrptime(df_column[column - 1].position,
2515 axis_array[whichaxis].timefmt, &tm)) {
2517 push(&a); /* any objection to this ? */
2519 push(Gcomplex(&a, gtimegm(&tm), 0.0));
2524 #if 0 /* not used */
2525 /*{{{ static int get_time_cols(fmt) */
2526 /* count columns in timefmt */
2528 get_time_cols(char *fmt)
2535 while (isspace((unsigned char) *p))
2538 int_error(NO_CARET, "Empty time-data format");
2540 for (i = 0; i < strlen(p) - 1; i++) {
2541 if (isspace((unsigned char) p[i])
2542 && !isspace((unsigned char) p[i + 1]))
2549 /*{{{ static void mod_def_usespec(specno,jump) */
2550 /* modify default use_spec, applies for no user spec and time datacolumns */
2553 int specno, /* which spec in ?:?:? */
2554 int jump) /* no of columns in timefmt (time data) */
2558 for (i = specno + 1; i < MAXDATACOLS; ++i)
2559 use_spec[i].column += jump; /* add no of columns in time to the rest */
2560 df_no_use_specs = 0;
2564 #endif /* not used */
2566 /*{{{ static int check_missing(s) */
2568 check_missing(char *s)
2570 if (missing_val != NULL) {
2571 size_t len = strlen(missing_val);
2572 if (strncmp(s, missing_val, len) == 0 &&
2573 (isspace((unsigned char) s[len]) || !s[len]))
2574 return 1; /* store undefined point in plot */
2582 /* formerly in misc.c, but only used here */
2583 /* check user defined format strings for valid double conversions */
2584 /* HBB 20040601: Added check that the number of format specifiers is
2585 * workable (between 0 and 7) */
2587 valid_format(const char *format)
2589 int formats_found = 0;
2592 if (!(format = strchr(format, '%'))) /* look for format spec */
2593 return (formats_found > 0 && formats_found <= 7);
2595 /* Found a % to check --- scan past option specifiers: */
2598 } while (strchr("+-#0123456789.", *format));
2600 /* Now at format modifier */
2602 case '*': /* Ignore '*' statements */
2603 case '%': /* Char '%' itself */
2606 case 'l': /* Now we found it !!! */
2607 if (!strchr("fFeEgG", format[1])) /* looking for a valid format */
2618 #ifdef EAM_DATASTRINGS
2620 * Plotting routines can call this prior to invoking df_readline() to indicate
2621 * that they expect a certain column to contain an ascii string rather than a
2625 expect_string(const char column)
2627 use_spec[column-1].expected_type = CT_STRING;
2628 FPRINTF((stderr,"expecting to find string in input column %d\n",use_spec[column-1].column));
2629 return(use_spec[column-1].column);
2633 * Load plot title for key box from the string found earlier by df_readline.
2634 * Called from get_data().
2637 df_set_key_title(struct curve_points *plot)
2639 #ifdef EAM_HISTOGRAMS
2640 if (plot->plot_style == HISTOGRAMS
2641 && histogram_opts.type == HT_STACKED_IN_TOWERS) {
2642 /* In this case it makes no sense to treat key titles in the usual */
2643 /* way, so we assume that it is supposed to be an xtic label. */
2644 /* FIXME EAM - This style should default to notitle! */
2645 double xpos = plot->histogram_sequence + plot->histogram->start;
2646 add_tic_user(FIRST_X_AXIS, df_key_title, xpos, -1);
2647 df_key_title[0] = '\0';
2652 /* What if there was already a title specified? */
2653 if (plot->title && !plot->title_is_filename)
2655 if (plot->title_is_suppressed)
2660 plot->title = gp_strdup(df_key_title);
2661 plot->title_no_enhanced = !keyT.enhanced;
2665 df_parse_string_field(char *string, char *field)
2667 char temp_string[MAX_TOKEN_LENGTH];
2668 temp_string[sizeof(temp_string)-1] = '\0';
2673 } else if (*field == '"') {
2674 strncpy(temp_string,&(field[1]),sizeof(temp_string)-1);
2675 temp_string[strcspn(temp_string,"\"")] = '\0';
2676 } else if (df_separator != '\0') {
2678 eor[0] = df_separator; eor[1] = '"'; eor[2] = '\0';
2679 strncpy(temp_string,field,sizeof(temp_string)-1);
2680 temp_string[strcspn(temp_string,eor)] = '\0';
2682 strncpy(temp_string,field,sizeof(temp_string)-1);
2683 temp_string[strcspn(temp_string,"\t ")] = '\0';
2685 parse_esc(temp_string);
2686 strcpy(string,temp_string);
2689 #ifdef EAM_HISTOGRAMS
2691 add_key_entry(char *temp_string, int df_datum)
2693 text_label *new_entry = gp_alloc(sizeof(text_label), "key entry");
2695 /* Associate this key list with the histogram it belongs to. */
2696 if (!df_current_plot->labels) {
2697 /* The first text_label structure in the list is a place-holder */
2698 df_current_plot->labels = gp_alloc(sizeof(text_label), "key entry");
2699 memset(df_current_plot->labels, 0, sizeof(text_label));
2700 df_current_plot->labels->tag = -1;
2703 new_entry->text = gp_strdup(temp_string);
2704 new_entry->tag = df_datum;
2705 new_entry->font = NULL;
2706 new_entry->next = df_current_plot->labels->next;
2707 df_current_plot->labels->next = new_entry;
2711 #endif /* EAM_DATASTRINGS */
2714 #ifdef BINARY_DATA_FILE
2716 /* Construct 2D rotation matrix. */
2717 /* R - Matrix to construct. */
2718 /* alpha - Rotation angle. */
2719 /* return - TRUE means a translation is required. */
2721 rotation_matrix_2D(double R[][2], double alpha)
2723 static double I[2][2] = {{1, 0},
2725 #define ANGLE_TOLERANCE 0.001
2726 if (fabs(alpha) < ANGLE_TOLERANCE) {
2727 /* Zero angle. Unity rotation. */
2728 memcpy(R, I, sizeof(I));
2731 R[0][0] = cos(alpha);
2732 R[0][1] = -sin(alpha);
2733 R[1][0] = sin(alpha);
2734 R[1][1] = cos(alpha);
2740 /* Construct 3D rotation matrix. */
2741 /* P - Matrix to construct. */
2742 /* p - Pointer to perpendicular vector. */
2743 /* return - TRUE means a translation is required. */
2745 rotation_matrix_3D(double P[][3], double *p)
2747 static double I[3][3] = {{1, 0, 0},
2750 double scale, C1, C2;
2754 C1 = sqrt(x*x + y*y + z*z);
2755 C2 = sqrt(x*x + y*y);
2756 /* ????? Is there a precision constant for doubles similar to what is in limits.h for other types? */
2757 if ((C1 < 10e-10) || (C2 < (10e-5*C1))) {
2758 /* Zero vector (invalid) || vector perpendiculat to x/y plane. Unity rotation. */
2759 memcpy(P, I, sizeof(I));
2762 scale = 1.0/(C1*C2);
2763 P[0][0] = x*z * scale;
2764 P[0][1] = -y*C1 * scale;
2765 P[0][2] = x*C2 * scale;
2766 P[1][0] = y*z * scale;
2767 P[1][1] = x*C1 * scale;
2768 P[1][2] = y*C2 * scale;
2769 P[2][0] = -C2*C2 * scale;
2771 P[2][2] = z*C2 * scale;
2780 df_byte_read_order_type
2781 byte_read_order (df_endianess_type file_endian)
2783 /* Range limit file endianess to ensure that future file type function
2784 * programmer doesn't incorrectly access array and cause segmentation
2785 * fault unknowingly.
2787 return df_byte_read_order_map[THIS_COMPILER_ENDIAN][GPMIN(file_endian, DF_ENDIAN_TYPE_LENGTH-1)];
2792 df_unset_datafile_binary(void)
2794 clear_binary_records(DF_DEFAULT_RECORDS);
2795 df_bin_filetype_default = df_bin_filetype_reset;
2796 df_bin_file_endianess_default = DF_BIN_FILE_ENDIANESS_RESET;
2801 df_set_datafile_binary()
2805 int_error(c_token, "option expected");
2806 clear_binary_records(DF_CURRENT_RECORDS);
2807 /* Set current records to default in order to retain current default settings. */
2808 if (df_bin_record_default) {
2809 df_bin_filetype = df_bin_filetype_default;
2810 df_bin_file_endianess = df_bin_file_endianess_default;
2811 df_add_binary_records(df_num_bin_records_default, DF_CURRENT_RECORDS);
2812 memcpy(df_bin_record, df_bin_record_default, df_num_bin_records*sizeof(df_binary_file_record_struct));
2814 df_bin_filetype = df_bin_filetype_reset;
2815 df_bin_file_endianess = DF_BIN_FILE_ENDIANESS_RESET;
2816 df_add_binary_records(1, DF_CURRENT_RECORDS);
2818 /* Process the binary tokens. */
2819 df_set_plot_mode(MODE_QUERY);
2820 plot_option_binary(FALSE, TRUE);
2821 /* Copy the modified settings as the new default settings. */
2822 df_bin_filetype_default = df_bin_filetype;
2823 df_bin_file_endianess_default = df_bin_file_endianess;
2824 clear_binary_records(DF_DEFAULT_RECORDS);
2825 df_add_binary_records(df_num_bin_records, DF_DEFAULT_RECORDS);
2826 memcpy(df_bin_record_default, df_bin_record, df_num_bin_records_default*sizeof(df_binary_file_record_struct));
2831 gpbin_filetype_function(void)
2833 /* Gnuplot binary. */
2834 df_matrix_file = TRUE;
2835 df_binary_file = TRUE;
2840 raw_filetype_function(void)
2842 /* No information in file, just data. */
2843 df_matrix_file = FALSE;
2844 df_binary_file = TRUE;
2849 avs_filetype_function(void)
2851 /* A very simple file format:
2852 * 8 byte header (width and height, 4 bytes each), unknown endian
2853 * followed by 4 bytes per pixel (alpha, red, green, blue).
2860 /* open (header) file */
2861 fp = loadpath_fopen(df_filename, "rb");
2863 os_error(NO_CARET, "Can't open data file \"%s\"", df_filename);
2865 /* read header: it is only 8 bytes */
2866 if (!fread(&M, 4, 1, fp))
2867 os_error(NO_CARET, "Can't read first dimension in data file \"%s\"", df_filename);
2869 read_order = DF_3210;
2870 df_swap_bytes_by_endianess((char *) &M, read_order, 4);
2871 if (!fread(&N, 4, 1, fp))
2872 os_error(NO_CARET, "Can't read second dimension in data file \"%s\"", df_filename);
2873 df_swap_bytes_by_endianess((char *) &N, read_order, 4);
2877 df_matrix_file = FALSE;
2878 df_binary_file = TRUE;
2880 df_bin_record[0].scan_skip[0] = 8;
2881 df_bin_record[0].scan_dim[0] = M;
2882 df_bin_record[0].scan_dim[1] = N;
2884 df_bin_record[0].scan_dir[0] = 1;
2885 df_bin_record[0].scan_dir[1] = -1;
2886 df_bin_record[0].scan_generate_coord = TRUE;
2887 df_bin_record[0].cart_scan[0] = DF_SCAN_POINT;
2888 df_bin_record[0].cart_scan[1] = DF_SCAN_LINE;
2890 /* The four components are 1 byte each. Treat as three components
2891 with the first one ignored. */
2892 df_extend_binary_columns(3);
2893 df_set_read_type(1, DF_UCHAR); /* Each pixel component is 1 byte */
2894 df_set_read_type(2, DF_UCHAR);
2895 df_set_read_type(3, DF_UCHAR);
2896 df_set_skip_before(1,1); /* Ignore the alpha component of 4-tuple */
2898 df_no_use_specs = 3;
2899 use_spec[0].column = 1;
2900 use_spec[1].column = 2;
2901 use_spec[2].column = 3;
2906 initialize_binary_vars()
2908 /* Initialize for the df_readline() routine. */
2909 df_bin_record_count = 0;
2910 df_M_count = df_N_count = df_O_count = 0;
2912 /* Set default binary data widths and skip paratemers. */
2914 df_set_skip_before(1, 0);
2916 /* Copy the default binary records to the active binary records. The number
2917 * of records will always be at least one in case "record", "array",
2918 * or "filetype" are not issued by the user.
2920 clear_binary_records(DF_CURRENT_RECORDS);
2921 if (df_num_bin_records_default) {
2922 df_bin_filetype = df_bin_filetype_default;
2923 df_bin_file_endianess = df_bin_file_endianess_default;
2924 df_add_binary_records(df_num_bin_records_default, DF_CURRENT_RECORDS);
2925 memcpy(df_bin_record, df_bin_record_default, df_num_bin_records*sizeof(df_binary_file_record_struct));
2927 df_bin_filetype = df_bin_filetype_reset;
2928 df_bin_file_endianess = DF_BIN_FILE_ENDIANESS_RESET;
2929 df_add_binary_records(1, DF_CURRENT_RECORDS);
2934 static char *too_many_cols_msg = "Too many columns in using specification and implied sampling array";
2937 /* Place a special marker in the using list to derive the x/y/z value
2938 * from the appropriate dimensional counter.
2941 df_insert_scanned_use_spec(int uspec)
2943 /* Place a special marker in the using list to derive the z value
2944 * from the third dimensional counter, which will be zero.
2946 if (df_no_use_specs >= MAXDATACOLS)
2947 int_error(NO_CARET, too_many_cols_msg);
2950 for (j=df_no_use_specs; j > uspec; j--)
2951 use_spec[j] = use_spec[j - 1];
2952 use_spec[uspec].column = (uspec == 2 ? DF_SCAN_PLANE : DF_SCAN_LINE);
2953 /* The at portion is set to NULL here, but this doesn't mash
2954 * a valid memory pointer because any valid memory pointers
2955 * were copied to new locations in the previous for loop.
2957 use_spec[uspec].at = NULL; /* Not a bad memory pointer overwrite!! */
2963 /* Not the most elegant way of defining the default columns, but I prefer
2964 * this to switch and conditional statements when there are so many styles.
2966 #define LAST_PLOT_STYLE 26
2967 typedef struct df_bin_default_columns {
2968 PLOT_STYLE plot_style;
2969 short excluding_gen_coords; /* Number of columns of information excluding generated coordinates. */
2970 short dimen_in_2d; /* Number of additional columns required (in 2D plot) if coordinates not generated. */
2971 } df_bin_default_columns;
2972 df_bin_default_columns default_style_cols[LAST_PLOT_STYLE + 1] = {
2976 {LINESPOINTS, 1, 1},
2980 {XYERRORBARS, 3, 1},
2988 {CANDLESTICKS, 4, 1},
2989 {FINANCEBARS, 4, 1},
2990 {XERRORLINES, 2, 1},
2991 {YERRORLINES, 2, 1},
2992 {XYERRORLINES, 3, 1},
2993 {FILLEDCURVES, 1, 1},
2994 {PM3DSURFACE, 1, 2},
2995 #ifdef EAM_DATASTRINGS
2996 {LABELPOINTS, 2, 1},
2998 #ifdef EAM_HISTOGRAMS
3009 adjust_binary_use_spec()
3012 char *nothing_known = "No default columns known for that plot style";
3013 enum PLOT_STYLE plot_style;
3017 /* This may appear strange, but ASCII matrix is not the same
3018 * format as gnuplot matrix binary. So, although the ASCII
3019 * *file* may be matrix, it's data structure is similar to
3020 * an M x N general binary file, i.e., no extra row and column
3021 * for sample coordinates.
3023 df_matrix_binary = (df_matrix_file && df_binary_file);
3025 c_token_copy = c_token;
3026 for (; !END_OF_COMMAND; c_token++)
3027 if (almost_equals(c_token, "w$ith"))
3029 if (!END_OF_COMMAND)
3030 plot_style = get_style();
3033 c_token = c_token_copy;
3035 /* Determine index. */
3036 for (ps_index = 0; ps_index < sizeof(default_style_cols)/sizeof(default_style_cols[0]); ps_index++) {
3037 if (default_style_cols[ps_index].plot_style == plot_style)
3040 if (ps_index == sizeof(default_style_cols)/sizeof(default_style_cols[0]))
3041 int_error(c_token_copy, nothing_known);
3043 /* Matrix format is interpretted as always having three columns. */
3044 if (df_matrix_file) {
3045 if (df_no_bin_cols > 3)
3046 int_error(NO_CARET, "Matrix data contains only three columns");
3047 df_extend_binary_columns(3);
3050 /* If nothing has been done to set the using specs, use the default using
3051 * characteristics for the style.
3053 if (!df_no_use_specs) {
3055 if (!df_matrix_file) {
3057 int no_cols = default_style_cols[ps_index].excluding_gen_coords;
3059 int_error(c_token_copy, nothing_known);
3061 /* If coordinates are generated, make sure this plot style allows it.
3062 * Otherwise, add in the number of generated coordinates and add an
3063 * extra column if using `splot`.
3065 if (df_num_bin_records && df_bin_record[0].scan_generate_coord) {
3066 if (default_style_cols[ps_index].dimen_in_2d == 0)
3067 int_error(c_token_copy, "Cannot generate coords for that plot style");
3069 /* If there aren't generated coordinates, then add the
3070 * amount of columns that would be generated.
3072 no_cols += default_style_cols[ps_index].dimen_in_2d;
3073 if (df_plot_mode == MODE_SPLOT)
3077 assert(no_cols <= MAXDATACOLS);
3079 /* Nothing need be done here to set the using specs because they
3080 * will have been initialized appropriately and left unaltered.
3081 * So just set the number of specs.
3083 df_no_use_specs = no_cols;
3084 df_extend_binary_columns(no_cols);
3088 /* Number of columns is fixed at three and no using specs given. Do what we can.
3089 * The obvious best combination is two dimensional coordinates and one information
3090 * value. One wonders what to do if a matrix is only one column; can be treated
3091 * as linear? This isn't implemented here, but if it were, this is where it
3095 if ((default_style_cols[ps_index].dimen_in_2d == 2)
3096 && (default_style_cols[ps_index].excluding_gen_coords == 1)) {
3097 df_no_use_specs = 3;
3098 } else if ((default_style_cols[ps_index].dimen_in_2d == 1)
3099 && (default_style_cols[ps_index].excluding_gen_coords == 1) ) {
3100 if (df_plot_mode == MODE_SPLOT)
3101 df_no_use_specs = 3;
3103 /* Command: plot 'foo' matrix with no using spec */
3104 /* Matix element treated as y value rather than z value */
3105 df_no_use_specs = 2;
3106 use_spec[1].column = 3;
3109 int_error(NO_CARET, "Plot style does not conform to three column data in this graph mode");
3114 /* Adjust for ASCII matrix format. The first two "columns" come from indices. */
3115 if (df_matrix_file && !df_binary_file) {
3118 if (df_num_bin_records && df_bin_record[0].scan_generate_coord && !df_matrix_file) {
3122 struct use_spec_s original_use_spec[MAXDATACOLS];
3123 int added_columns = 0;
3125 /* Keep record of the original using specs. */
3126 memcpy(original_use_spec, use_spec, sizeof(use_spec));
3128 /* Put in columns at front for generated variables. */
3129 for (i = 0; i < 3; i++) {
3130 if (df_bin_record[0].cart_dim[i] || df_bin_record[0].scan_dim[i])
3135 if ((df_no_use_specs + added_columns) >= MAXDATACOLS)
3136 int_error(NO_CARET, too_many_cols_msg);
3139 /* Shift the original columns over by added number of columns, but only
3140 * if not matrix data.
3142 memcpy(&use_spec[added_columns], original_use_spec, df_no_use_specs*sizeof(use_spec[0]));
3144 /* The at portion is set to NULL here, but this doesn't mash
3145 * a valid memory pointer because any valid memory pointers
3146 * were copied to new locations in the previous memcpy().
3148 for (i = 0; i < added_columns; i++) {
3149 use_spec[i].column = df_bin_record[0].cart_scan[i];
3150 use_spec[i].at = NULL; /* Not a bad memory pointer overwrite!! */
3153 df_no_use_specs += added_columns; /* Do not extend columns for generated coordinates. */
3156 if (df_plot_mode == MODE_SPLOT) {
3158 /* For binary data having an implied uniformly sampled grid, treat
3159 * less than three-dimensional data in special ways based upon what
3163 for (k = 0; k < df_num_bin_records; k++) {
3164 if ((df_bin_record[k].cart_dim[2] == 0) && (df_bin_record[k].scan_dim[2] == 0)) {
3165 if (default_style_cols[ps_index].dimen_in_2d > 2)
3166 int_error(NO_CARET, "Plot style requires higher than two-dimensional sampling array");
3168 if ((df_bin_record[k].cart_dim[1] == 0) && (df_bin_record[k].scan_dim[1] == 0)) {
3169 if (default_style_cols[ps_index].dimen_in_2d > 1)
3170 int_error(NO_CARET, "Plot style requires higher than one-dimensional sampling array");
3172 /* Place a special marker in the using list to derive the y value
3173 * from the second dimensional counter.
3175 df_insert_scanned_use_spec(1);
3178 /* Place a special marker in the using list to derive the z value
3179 * from the third dimensional counter.
3181 df_insert_scanned_use_spec(2);
3189 char *equal_symbol_msg = "Equal ('=') symbol required";
3193 plot_option_binary(TBOOLEAN set_matrix, TBOOLEAN set_default)
3195 #define MAX_FILE_EXT_LEN 10
3196 char file_ext[MAX_FILE_EXT_LEN+1];
3198 TBOOLEAN duplication = FALSE;
3199 TBOOLEAN set_record = FALSE;
3200 TBOOLEAN set_array = FALSE, set_dx = FALSE, set_dy = FALSE, set_dz = FALSE;
3201 TBOOLEAN set_center = FALSE, set_origin = FALSE, set_skip = FALSE, set_endian = FALSE;
3202 TBOOLEAN set_rotation = FALSE, set_perpendicular = FALSE;
3203 TBOOLEAN set_flip = FALSE, set_noflip = FALSE;
3204 TBOOLEAN set_flipx = FALSE, set_flipy = FALSE, set_flipz = FALSE;
3205 TBOOLEAN set_scan = FALSE;
3206 #if BINARY_HAS_OWN_FORMAT_STRING
3207 TBOOLEAN set_format = FALSE;
3210 /* Binary file type must be the first word in the command following `binary`" */
3211 if (almost_equals(c_token, "file$type") || (df_bin_filetype >= 0)) {
3214 /* Above keyword not part of pre-existing binary definition.
3215 * So use general binary. */
3217 int_error(c_token, matrix_general_binary_conflict_msg);
3218 df_matrix_file = FALSE;
3220 if (almost_equals(c_token, "file$type")) {
3222 #define EQUAL_SYMBOL_NOT_REQUIRED 0
3223 #if EQUAL_SYMBOL_NOT_REQUIRED
3224 /* Ignore or do not require equal symbol. */
3225 if (equals(c_token, "=")) c_token++;
3227 /* else equal symbol. */
3228 if (!equals(c_token, "="))
3229 int_error(c_token, equal_symbol_msg);
3232 copy_str(file_ext, c_token, MAX_FILE_EXT_LEN);
3234 for (i=0; i < (sizeof(df_bin_filetype_table)/sizeof(df_bin_filetype_table_struct)); i++) {
3235 if (!strcasecmp(file_ext, df_bin_filetype_table[i].extension)) {
3236 df_bin_filetype = i;
3240 if (i == (sizeof(df_bin_filetype_table)/sizeof(df_bin_filetype_table_struct)))
3241 int_error(c_token, "Unsupported file type");
3246 /* This section of code entails being able to read various types of
3247 * binary data files. Some decisions need to be made on exactly what
3248 * type or how many kinds should be allowed. Perhaps some system
3249 * similar to the terminal scheme can be devised so that volunteers
3250 * can provide code to read their favorite file type.
3252 * My suggestion for a good scheme would be to have short little
3253 * routines that look into the file in question and pull from the
3254 * header the necessary information to fill in the details about
3255 * "record", "array", "skip", etc. Then just let the current gnuplot
3256 * code continue on. If the data file in question has compressed
3257 * or encoded data, perhaps the data could be uncompressed or decoded
3258 * into an intermediate, temporary file. In that case, the file name
3259 * could be changed to the temporary file name and, again, just let
3260 * gnuplot continue. Other approaches are possible.
3262 if (!strcasecmp("auto", df_bin_filetype_table[df_bin_filetype].extension) && (df_plot_mode != MODE_QUERY)) {
3264 char *ext_start = strrchr (df_filename, '.');
3266 df_bin_filetype = RAW_FILETYPE;
3268 strncpy(file_ext, (ext_start+1), MAX_FILE_EXT_LEN);
3269 for (i=0; i < (sizeof(df_bin_filetype_table)/sizeof(df_bin_filetype_table_struct)); i++) {
3270 if (!strcasecmp(file_ext, df_bin_filetype_table[i].extension)) {
3271 df_bin_filetype = i;
3275 if (i == (sizeof(df_bin_filetype_table)/sizeof(df_bin_filetype_table_struct)))
3276 int_error(c_token, "Unsupported file type");
3280 /* Unless only querying settings, call the routine to prep binary data parameters. */
3281 if (df_plot_mode != MODE_QUERY)
3282 df_bin_filetype_table[df_bin_filetype].function();
3284 /* Now, at this point anything that was filled in for "scan" should
3285 * override the "cart" variables.
3287 for (i=0; i < df_num_bin_records; i++) {
3290 if (df_bin_record[i].scan_dim[0] != df_bin_record_reset.scan_dim[0])
3291 for (j=0; j < 3; j++)
3292 df_bin_record[i].cart_dim[j] = 0;
3294 for (j=0; j < 3; j++)
3295 if (df_bin_record[i].scan_delta[j] != 0.0) {
3297 for (k=0; k < 3; k++)
3298 if (df_bin_record[i].cart_scan[k] == (DF_SCAN_POINT - j))
3299 df_bin_record[i].cart_delta[k] = 0;
3302 if (df_bin_record[i].scan_trans != DF_TRANSLATE_DEFAULT)
3303 df_bin_record[i].cart_trans = DF_TRANSLATE_DEFAULT;
3308 while (!END_OF_COMMAND) {
3309 char origin_and_center_conflict_message[] = "Can specify `origin` or `center`, but not both";
3311 /* look for record */
3312 if (almost_equals(c_token, "rec$ord")) {
3313 if (set_record) { duplication=TRUE; break; }
3315 /* Above keyword not part of pre-existing binary definition. So use general binary. */
3317 int_error(c_token, matrix_general_binary_conflict_msg);
3318 df_matrix_file = FALSE;
3319 plot_option_array();
3324 /* look for array */
3325 if (almost_equals(c_token, "arr$ay")) {
3326 if (set_array) { duplication=TRUE; break; }
3328 /* Above keyword not part of pre-existing binary definition. So use general binary. */
3330 int_error(c_token, matrix_general_binary_conflict_msg);
3331 df_matrix_file = FALSE;
3332 plot_option_array();
3334 for (i = 0; i < df_num_bin_records; i++)
3335 df_bin_record[i].scan_generate_coord = TRUE; /* Indicate that coordinate info should be generated by gnuplot code. */
3341 /* deal with spacing between array points */
3342 if (equals(c_token, "dx") || equals(c_token, "dt")) {
3343 if (set_dx) { duplication=TRUE; break; }
3345 plot_option_multivalued(DF_DELTA, 0);
3348 for (i = 0; i < df_num_bin_records; i++)
3349 df_bin_record[i].cart_delta[1] = df_bin_record[i].cart_delta[0];
3353 for (i = 0; i < df_num_bin_records; i++)
3354 df_bin_record[i].cart_delta[2] = df_bin_record[i].cart_delta[0];
3360 if (equals(c_token, "dy") || equals(c_token, "dr")) {
3361 if (set_dy) { duplication=TRUE; break; }
3362 if (!set_array && !df_bin_record)
3363 int_error(c_token, "Must specify a sampling array size before indicating spacing in second dimension");
3365 plot_option_multivalued(DF_DELTA, 1);
3368 for (i = 0; i < df_num_bin_records; i++)
3369 df_bin_record[i].cart_delta[2] = df_bin_record[i].cart_delta[1];
3375 if (equals(c_token, "dz")) {
3376 int_error(c_token, "Currently not supporting three-dimensional sampling");
3377 if (set_dz) { duplication=TRUE; break; }
3378 if (!set_array && !df_bin_record)
3379 int_error(c_token, "Must specify a sampling array size before indicating spacing in third dimension");
3381 plot_option_multivalued(DF_DELTA, 2);
3386 /* deal with direction in which sampling increments */
3387 if (equals(c_token, "flipx")) {
3388 if (set_flipx) { duplication=TRUE; break; }
3390 /* If no equal sign, then set flip true for all records. */
3391 #if EQUAL_SYMBOL_NOT_REQUIRED
3392 if (!equals(c_token, "=") && !isanumber(c_token)) {
3394 if (!equals(c_token, "=")) {
3397 for (i = 0; i < df_num_bin_records; i++)
3398 df_bin_record[i].cart_dir[0] = -1;
3400 plot_option_multivalued(DF_FLIP_AXIS, 0);
3406 if (equals(c_token, "flipy")) {
3407 if (set_flipy) { duplication=TRUE; break; }
3408 if (!set_array && !df_bin_record)
3409 int_error(c_token, "Must specify a sampling array size before indicating flip in second dimension");
3411 /* If no equal sign, then set flip true for all records. */
3412 #if EQUAL_SYMBOL_NOT_REQUIRED
3413 if (!equals(c_token, "=") && !isanumber(c_token)) {
3415 if (!equals(c_token, "=")) {
3418 for (i = 0; i < df_num_bin_records; i++)
3419 df_bin_record[i].cart_dir[1] = -1;
3421 plot_option_multivalued(DF_FLIP_AXIS, 1);
3427 if (equals(c_token, "flipz")) {
3428 int_error(c_token, "Currently not supporting three-dimensional sampling");
3429 if (set_flipz) { duplication=TRUE; break; }
3430 if (!set_array && !df_bin_record)
3431 int_error(c_token, "Must specify a sampling array size before indicating spacing in third dimension");
3433 /* If no equal sign, then set flip true for all records. */
3434 #if EQUAL_SYMBOL_NOT_REQUIRED
3435 if (!equals(c_token, "=") && !isanumber(c_token)) {
3437 if (!equals(c_token, "=")) {
3440 for (i=0; i < df_num_bin_records; i++)
3441 df_bin_record[i].cart_dir[2] = -1;
3443 plot_option_multivalued(DF_FLIP_AXIS, 2);
3449 /* Deal with flipping data for individual records. */
3450 if (equals(c_token, "flip")) {
3451 if (set_flip) { duplication=TRUE; break; }
3453 plot_option_multivalued(DF_FLIP, -1);
3458 /* Deal with flipping data for individual records. */
3459 if (equals(c_token, "noflip")) {
3460 if (set_noflip) { duplication=TRUE; break; }
3462 plot_option_multivalued(DF_FLIP, 1);
3467 /* Deal with manner in which dimensions are scanned from file. */
3468 if (equals(c_token, "scan")) {
3469 if (set_scan) { duplication=TRUE; break; }
3471 plot_option_multivalued(DF_SCAN, 0);
3476 /* Deal with manner in which dimensions are scanned from file. */
3477 if (almost_equals(c_token, "trans$pose")) {
3479 if (set_scan) { duplication=TRUE; break; }
3481 for (i=0; i < df_num_bin_records; i++)
3482 memcpy(df_bin_record[i].cart_scan, df_bin_scan_table_2D[TRANSPOSE_INDEX].scan, sizeof(df_bin_record[0].cart_scan));
3487 /* deal with origin */
3488 if (almost_equals(c_token, "orig$in")) {
3490 int_error(c_token, origin_and_center_conflict_message);
3491 if (set_origin) { duplication=TRUE; break; }
3493 plot_option_multivalued(DF_ORIGIN, df_plot_mode);
3498 /* deal with origin */
3499 if (almost_equals(c_token, "cen$ter")) {
3501 int_error(c_token, origin_and_center_conflict_message);
3502 if (set_center) { duplication=TRUE; break; }
3504 plot_option_multivalued(DF_CENTER, df_plot_mode);
3509 /* deal with rotation angle */
3510 if (almost_equals(c_token, "rot$ation") || almost_equals(c_token, "rot$ate")) {
3511 if (set_rotation) { duplication=TRUE; break; }
3513 plot_option_multivalued(DF_ROTATION, 0);
3514 set_rotation = TRUE;
3518 /* deal with rotation angle */
3519 if (almost_equals(c_token, "perp$endicular")) {
3520 if (df_plot_mode == MODE_PLOT)
3521 int_error(c_token, "Key word `perpendicular` is not allowed with `plot` command");
3522 if (set_perpendicular) { duplication=TRUE; break; }
3524 plot_option_multivalued(DF_PERPENDICULAR, 0);
3525 set_perpendicular = TRUE;
3529 /* deal with number of bytes to skip before record */
3530 if (almost_equals(c_token, "skip")) {
3531 if (set_skip) { duplication=TRUE; break; }
3533 plot_option_multivalued(DF_SKIP, 0);
3538 /* deal with byte order */
3539 if (almost_equals(c_token, "end$ian")) {
3540 if (set_endian) { duplication=TRUE; break; }
3542 #if EQUAL_SYMBOL_NOT_REQUIRED
3543 /* Ignore or do not require equal symbol. */
3544 if (equals(c_token, "=")) c_token++;
3546 /* Require equal symbol. */
3547 if (!equals(c_token, "="))
3548 int_error(c_token, equal_symbol_msg);
3551 if (almost_equals(c_token, "def$ault"))
3552 df_bin_file_endianess = THIS_COMPILER_ENDIAN;
3553 else if (equals(c_token, "swap") || equals(c_token, "swab"))
3554 df_bin_file_endianess = (~df_bin_file_endianess)&3; /* complement and isolate lowest two bits */
3555 else if (almost_equals(c_token, "lit$tle"))
3556 df_bin_file_endianess = DF_LITTLE_ENDIAN;
3557 else if (equals(c_token, "big"))
3558 df_bin_file_endianess = DF_BIG_ENDIAN;
3559 #if SUPPORT_MIDDLE_ENDIAN
3560 else if (almost_equals(c_token, "mid$dle") || equals(c_token, "pdp"))
3561 df_bin_file_endianess = DF_PDP_ENDIAN;
3563 int_error(c_token, "Options are default, swap (swab), little, big, middle (pdp)");
3566 int_error(c_token, "Options are default, swap (swab), little, big");
3573 #if BINARY_HAS_OWN_FORMAT_STRING
3574 /* deal with various types of binary files */
3575 if (almost_equals(c_token, "form$at")) {
3577 int_error(c_token, "Sorry - default binary properties not fully implemented");
3578 if (set_format) { duplication=TRUE; break; }
3580 /* Format string not part of pre-existing binary definition. So use general binary. */
3582 int_error(c_token, matrix_general_binary_conflict_msg);
3583 df_matrix_file = FALSE;
3584 #if EQUAL_SYMBOL_NOT_REQUIRED
3585 /* Ignore or do not require equal symbol. */
3586 if (equals(c_token, "=")) c_token++;
3588 /* Require equal symbol. */
3589 if (!equals(c_token, "="))
3590 int_error(c_token, equal_symbol_msg);
3593 if (isstring(c_token))
3594 plot_option_binary_format();
3596 int_error(c_token, "Expecting format string");
3602 break; /* unknown option */
3604 } /* while (!END_OF_COMMAND) */
3607 int_error(c_token, "Duplicated or contradicting arguments in datafile options");
3613 df_add_binary_records(int num_records_to_add, df_records_type records_type)
3617 df_binary_file_record_struct **bin_record;
3618 int *num_bin_records;
3619 int *max_num_bin_records;
3621 if (records_type == DF_CURRENT_RECORDS) {
3622 bin_record = &df_bin_record;
3623 num_bin_records = &df_num_bin_records;
3624 max_num_bin_records = &df_max_num_bin_records;
3626 bin_record = &df_bin_record_default;
3627 num_bin_records = &df_num_bin_records_default;
3628 max_num_bin_records = &df_max_num_bin_records_default;
3631 new_number = *num_bin_records + num_records_to_add;
3633 if (new_number > *max_num_bin_records) {
3635 = gp_realloc(*bin_record,
3636 new_number * sizeof(df_binary_file_record_struct),
3637 "binary file data records");
3639 *max_num_bin_records = 0;
3641 "Error assigning memory for binary file data records");
3643 *max_num_bin_records = new_number;
3646 for (i = 0; i < num_records_to_add; i++) {
3647 memcpy(*bin_record + *num_bin_records,
3648 &df_bin_record_reset,
3649 sizeof(df_binary_file_record_struct));
3650 (*num_bin_records)++;
3656 clear_binary_records(df_records_type records_type)
3658 df_binary_file_record_struct *temp_bin_record;
3659 int *temp_num_bin_records;
3662 if (records_type == DF_CURRENT_RECORDS) {
3663 temp_bin_record = df_bin_record;
3664 temp_num_bin_records = &df_num_bin_records;
3666 temp_bin_record = df_bin_record_default;
3667 temp_num_bin_records = &df_num_bin_records_default;
3670 for (i = 0; i < *temp_num_bin_records; i++) {
3671 if (temp_bin_record[i].memory_data != NULL) {
3672 free(temp_bin_record[i].memory_data);
3673 temp_bin_record[i].memory_data = NULL;
3676 *temp_num_bin_records = 0;
3680 #define TUPLE_SEPARATOR_CHAR ":"
3681 #define LEFT_TUPLE_CHAR "(" /* Parser problems with (#,#) considered complex. */
3682 #define RIGHT_TUPLE_CHAR ")"
3685 plot_option_array(void)
3687 /* Process command line definition of array. */
3688 if (!END_OF_COMMAND) {
3689 int number_of_records = 0;
3691 TBOOLEAN expecting_number;
3693 int i_dimension = 0;
3695 #if EQUAL_SYMBOL_NOT_REQUIRED
3696 /* Ignore or do not require equal symbol. */
3697 if (equals(c_token, "="))
3700 /* Require equal symbol. */
3701 if (!equals(c_token, "="))
3702 int_error(c_token, equal_symbol_msg);
3706 /* Set true in case user starts string with a comma. */
3707 expecting_number = TRUE;
3709 /* If the user has no space between 'x' or 'X' and number, the
3710 * parser creates a single token x#. So, copy string and work
3711 * with that rather than the tokens directly. Null terminate
3712 * and point to empty string. */
3714 df_format[0] = '\0';
3715 token_string = df_format;
3718 if (*token_string == '\0') {
3720 if (END_OF_COMMAND) break;
3721 copy_str(df_format, c_token, MAX_LINE_LEN);
3722 token_string = df_format;
3725 if (expecting_number
3726 && !(isdigit(*token_string)
3727 || !strncasecmp(token_string, "Inf", 3)))
3730 if (!strcmp(token_string, TUPLE_SEPARATOR_CHAR)) {
3733 expecting_number = TRUE;
3737 if ((*token_string=='x') || (*token_string=='X') ) {
3739 if (i_dimension >= 2)
3741 "Currently do not support sampled array dimensions greater than 2");
3742 expecting_number = TRUE;
3747 if (!expecting_number
3748 && (isdigit(*token_string)
3749 || !strncasecmp(token_string, "Inf", 3))) {
3751 /* No dimension symbol required. */
3753 if (i_dimension >= 2)
3754 int_error(c_token, "Currently do not support sampled array dimensions greater than 2");
3756 /* Dimension symbol or comma required. */
3757 int_error(c_token, "Use '" TUPLE_SEPARATOR_CHAR "' between records or 'x' between dimensions");
3761 if (!isdigit(*token_string) && strncasecmp(token_string, "Inf", 3)) break;
3763 /* Read number, add records if necessary, record number, advance past number. */
3764 if (isdigit(*token_string)) {
3765 sscanf(token_string,"%d",&ival);
3766 while(isdigit(*token_string)) token_string++;
3768 int_error(c_token, "Sorry - Inf keyword not implemented");
3771 number_of_records++;
3772 if (number_of_records > df_num_bin_records)
3773 df_add_binary_records(1, DF_CURRENT_RECORDS);
3775 df_bin_record[df_num_bin_records - 1].cart_dim[i_dimension] = ival;
3776 expecting_number = FALSE;
3780 /* Don't allow ending while expecting a number. */
3781 if (expecting_number)
3782 int_error(c_token, "Missing a number");
3789 /* Evaluate a tuple of up to specified dimension. */
3791 token2tuple(double *tuple, int dimension)
3793 if (equals(c_token, LEFT_TUPLE_CHAR)) {
3794 TBOOLEAN expecting_number = TRUE;
3798 while (!END_OF_COMMAND) {
3799 if (expecting_number) {
3803 x = real(const_express(&a));
3808 int_error(c_token-1, "More than %d elements", N);
3809 expecting_number = FALSE;
3811 if (equals(c_token, ",")) {
3813 expecting_number = TRUE;
3814 } else if (equals(c_token, RIGHT_TUPLE_CHAR)) {
3818 int_error(c_token, "Expecting ',' or '" RIGHT_TUPLE_CHAR "'");
3828 /* Determine the 2D rotational matrix from the "rotation" qualifier. */
3830 plot_option_multivalued(df_multivalue_type type, int arg)
3832 int bin_record_count = 0;
3834 #if EQUAL_SYMBOL_NOT_REQUIRED
3835 /* Ignore or do not require equal symbol. */
3836 if (equals(c_token, "=")) c_token++;
3838 /* Require equal symbol. */
3839 if (!equals(c_token, "="))
3840 int_error(c_token, equal_symbol_msg);
3844 while (!END_OF_COMMAND) {
3850 case DF_PERPENDICULAR:
3851 test_val = token2tuple(tuple, sizeof(tuple)/sizeof(tuple[0]));
3855 /* Check if there are any characters in string that shouldn't be. */
3856 copy_str(df_format, c_token, MAX_LINE_LEN);
3857 test_val = ( (strlen(df_format) == strspn(df_format, "xXyYzZ")) || (strlen(df_format) == strspn(df_format, "tTrRzZ")) );
3860 /* Check if a valid number. */
3862 tuple[0] = real(const_express(&a));
3868 char const * cannot_flip_msg
3869 = "Cannot flip a non-existent dimension";
3871 if (bin_record_count >= df_num_bin_records)
3872 int_error(c_token, "\
3873 More parameters specified than data records specified");
3877 /* Set the spacing between grid points in the
3878 * specified dimension. */
3879 *(df_bin_record[bin_record_count].cart_delta + arg) = tuple[0];
3880 if (df_bin_record[bin_record_count].cart_delta[arg] <= 0)
3881 int_error(c_token - 2, "\
3882 Sample period must be positive. Try `flip` for changing direction");
3886 /* Set the direction of grid points increment in
3887 * the specified dimension. */
3888 if (df_bin_record[bin_record_count].cart_dim[0] > 0) {
3889 if (tuple[0] == 0.0)
3890 df_bin_record[bin_record_count].cart_dir[arg] = 0;
3891 else if (tuple[0] == 1.0)
3892 df_bin_record[bin_record_count].cart_dir[arg] = 1;
3894 int_error(c_token-1, "\
3895 Flipping dimension direction must be 1 or 0");
3897 int_error(c_token, cannot_flip_msg);
3901 /* Set the direction of grid points increment in
3902 * based upon letters for axes. Check if there are
3903 * any characters in string that shouldn't be. */
3904 copy_str(df_format, c_token, MAX_LINE_LEN);
3905 if (strlen(df_format) != strspn(df_format, "xXyYzZ"))
3906 int_error(c_token, "\
3907 Invalid character in dimension string. Only x, X, y, Y, z, or Z acceptable");
3908 /* Check for valid dimensions. */
3909 if (strpbrk(df_format, "xX")) {
3910 if (df_bin_record[bin_record_count].cart_dim[0] > 0)
3911 df_bin_record[bin_record_count].cart_dir[0] = arg;
3913 int_error(c_token, cannot_flip_msg);
3915 if (strpbrk(df_format, "yY")) {
3916 if (df_bin_record[bin_record_count].cart_dim[1] > 0)
3917 df_bin_record[bin_record_count].cart_dir[1] = arg;
3919 int_error(c_token, cannot_flip_msg);
3921 if (strpbrk(df_format, "zZ")) {
3922 if (df_bin_record[bin_record_count].cart_dim[2] > 0)
3923 df_bin_record[bin_record_count].cart_dir[2] = arg;
3925 int_error(c_token, cannot_flip_msg);
3931 /* Set the method in which data is scanned from
3932 * file. Compare against a set number of strings. */
3935 if (!(df_bin_record[bin_record_count].cart_dim[0]
3936 || df_bin_record[bin_record_count].scan_dim[0])
3937 || !(df_bin_record[bin_record_count].cart_dim[1]
3938 || df_bin_record[bin_record_count].scan_dim[1]))
3939 int_error(c_token, "\
3940 Cannot alter scanning method for one-dimensional data");
3941 else if (df_bin_record[bin_record_count].cart_dim[2]
3942 || df_bin_record[bin_record_count].scan_dim[2]) {
3944 i < sizeof(df_bin_scan_table_3D)
3945 /sizeof(df_bin_scan_table_3D_struct);
3948 df_bin_scan_table_3D[i].string)) {
3949 memcpy(df_bin_record[bin_record_count].cart_scan,
3950 df_bin_scan_table_3D[i].scan,
3951 sizeof(df_bin_record[0].cart_scan));
3954 if (i == sizeof(df_bin_scan_table_3D)
3955 /sizeof(df_bin_scan_table_3D_struct))
3956 int_error(c_token, "\
3957 Improper scanning string. Try 3 character string for 3D data");
3960 i < sizeof(df_bin_scan_table_2D)
3961 /sizeof(df_bin_scan_table_2D_struct); i++)
3963 df_bin_scan_table_2D[i].string)) {
3964 memcpy(df_bin_record[bin_record_count].cart_scan,
3965 df_bin_scan_table_2D[i].scan,
3966 sizeof(df_bin_record[0].cart_scan));
3969 if (i == sizeof(df_bin_scan_table_2D)
3970 /sizeof(df_bin_scan_table_2D_struct))
3971 int_error(c_token, "\
3972 Improper scanning string. Try 2 character string for 2D data");
3974 /* Remove the file supplied scan direction. */
3975 memcpy(df_bin_record[bin_record_count].scan_dir,
3976 df_bin_record_reset.scan_dir,
3977 sizeof(df_bin_record[0].scan_dir));
3983 /* Set the number of bytes to skip before reading
3985 df_bin_record[bin_record_count].scan_skip[0] = tuple[0];
3986 if (df_bin_record[bin_record_count].scan_skip[0] != tuple[0])
3987 int_error(c_token, "\
3988 The number of bytes to skip must be an integer");
3989 if (df_bin_record[bin_record_count].scan_skip[0] < 0)
3990 int_error(c_token, "\
3991 The number of bytes to skip must be positive");
3996 /* Set the origin or center of the image based upon
3998 if (type == DF_ORIGIN)
3999 df_bin_record[bin_record_count].cart_trans
4000 = DF_TRANSLATE_VIA_ORIGIN;
4002 df_bin_record[bin_record_count].cart_trans
4003 = DF_TRANSLATE_VIA_CENTER;
4004 if (arg == MODE_PLOT) {
4006 int_error(c_token, "\
4007 Two-dimensional tuple required for 2D plot");
4009 } else if (arg == MODE_SPLOT) {
4011 int_error(c_token, "\
4012 Three-dimensional tuple required for 3D plot");
4013 } else if (arg == MODE_QUERY) {
4015 int_error(c_token, "\
4016 Three-dimensional tuple required for setting binary parameters");
4018 int_error(c_token, "\
4019 Internal error (datafile.c): Unknown plot mode");
4021 memcpy(df_bin_record[bin_record_count].cart_cen_or_ori,
4022 tuple, sizeof(tuple));
4026 /* Allow user to enter angle in terms of pi or degrees. */
4027 if (equals(c_token, "pi")) {
4030 } else if (almost_equals(c_token, "d$egrees")) {
4031 tuple[0] *= M_PI/180;
4034 /* Construct 2D rotation matrix. */
4035 df_bin_record[bin_record_count].cart_alpha = tuple[0];
4038 case DF_PERPENDICULAR:
4039 /* Make sure in three dimensional plotting mode before
4040 * accepting the perpendicular vector for translation. */
4042 int_error(c_token, "Three-dimensional tuple required");
4043 /* Compare vector length against variable precision
4044 * to determine if this is the null vector */
4045 if ((tuple[0]*tuple[0]
4047 + tuple[2]*tuple[2]) < 100.*DBL_EPSILON)
4048 int_error(c_token, "\
4049 Perpendicular vector cannot be zero");
4050 memcpy(df_bin_record[bin_record_count].cart_p,
4056 int_error(NO_CARET, "\
4057 Internal error (datafile.c): Invalid comma separated type");
4060 int_error(c_token, "Invalid numeric or tuple form");
4063 if (equals(c_token, TUPLE_SEPARATOR_CHAR)) {
4075 /* Set the 'bytes' to skip before column 'col'. */
4077 df_set_skip_before(int col, int bytes)
4080 /* Check if we have room at least col columns */
4081 if (col > df_max_bininfo_cols) {
4082 df_column_bininfo = gp_realloc(df_column_bininfo,
4083 col * sizeof(df_column_bininfo_struct),
4084 "datafile columns binary information");
4085 df_max_bininfo_cols = col;
4087 df_column_bininfo[col-1].skip_bytes = bytes;
4091 /* Set the column data type. */
4093 df_set_read_type(int col, df_data_type type)
4096 /* Check if we have room at least col columns */
4097 if (col > df_max_bininfo_cols) {
4098 df_column_bininfo = gp_realloc(df_column_bininfo,
4099 col * sizeof(df_column_bininfo_struct),
4100 "datafile columns binary information");
4101 df_max_bininfo_cols = col;
4103 df_column_bininfo[col-1].column.read_type = type;
4104 df_column_bininfo[col-1].column.read_size
4105 = df_binary_details[type].type.read_size;
4109 /* Get the column data type. */
4111 df_get_read_type(int col)
4114 /* Check if we have room at least col columns */
4115 if (col < df_max_bininfo_cols)
4116 return(df_column_bininfo[col].column.read_type);
4122 /* Get the binary column data size. */
4124 df_get_read_size(int col)
4127 /* Check if we have room at least col columns */
4128 if (col < df_max_bininfo_cols)
4129 return(df_column_bininfo[col].column.read_size);
4135 /* If the column number is greater than number of binary columns, set
4136 * the unitialized columns binary info to that of the last specified
4137 * column or the default if none were set. */
4139 df_extend_binary_columns(int no_cols)
4141 if (no_cols > df_no_bin_cols) {
4144 if (df_no_bin_cols > 0)
4145 type = df_column_bininfo[df_no_bin_cols-1].column.read_type;
4147 type = DF_DEFAULT_TYPE;
4148 for (i = no_cols; i > df_no_bin_cols; i--) {
4149 df_set_skip_after(i, 0);
4150 df_set_read_type(i, type);
4152 df_no_bin_cols = no_cols;
4157 /* Determine binary data widths from the `using` (or `binary`) format
4160 plot_option_binary_format(void)
4163 int prev_read_type = DF_DEFAULT_TYPE; /* Defaults when none specified. */
4164 int i, no_fields = 0;
4166 /* Copy the token for our own analysis. */
4167 copy_str(df_format, c_token, MAX_LINE_LEN);
4170 df_format[i] != '\0'
4171 && df_format[i] != '\"'
4172 && df_format[i] != '\''
4173 && i <= MAX_LINE_LEN;
4175 if (df_format[i] == ' ') {
4178 } /* Ignore spaces. */
4180 if (df_format[i] == '%') {
4181 int ignore, field_repeat, j = 0, k = 0, m = 0, breakout;
4184 ignore = (df_format[i] == '*');
4188 /* Number of columns is less than a single digit, so check
4189 * only a single digit. If the user enters more than one
4190 * digit, the routine fails on the next pass. */
4191 if (isdigit(df_format[i])) {
4192 /* Convert to a number. Let zero be a valid entry. */
4193 field_repeat = df_format[i] - '0';
4198 /* Try finding the word among the valid type names. */
4199 for (j = 0, breakout = 0;
4200 j < (sizeof(df_binary_tables)
4201 /sizeof(df_binary_tables[0]));
4203 for (k = 0, breakout = 0;
4204 k < df_binary_tables[j].group_length;
4207 m < df_binary_tables[j].group[k].no_names;
4210 = strlen(df_binary_tables[j].group[k].name[m]);
4212 if (!strncmp(df_format + i,
4213 df_binary_tables[j].group[k].name[m],
4215 && strchr("%\'\" ", df_format[i + strl]) ) {
4216 i += strl; /* Advance pointer in array to next text. */
4220 for (n = 0; n < field_repeat; n++) {
4222 df_set_skip_after(no_fields, 0);
4223 df_set_read_type(no_fields,
4224 df_binary_tables[j].group[k].type.read_type);
4225 prev_read_type = df_binary_tables[j].group[k].type.read_type;
4228 df_column_bininfo[no_fields].skip_bytes
4230 * df_binary_tables[j].group[k].type.read_size;
4242 if (j == (sizeof(df_binary_tables)
4243 /sizeof(df_binary_tables[0]))
4244 && (k == df_binary_tables[j-1].group_length)
4245 && (m == df_binary_tables[j-1].group[k-1].no_names)) {
4246 int_error(c_token, "Unrecognized binary format specification");
4249 int_error(c_token, "Format specifier must begin with '%'");
4253 /* Any remaining unspecified fields are assumed to be of the same type
4254 * as the last specified field.
4256 for ( ; no_fields < df_no_bin_cols; no_fields++) {
4257 df_set_skip_after(no_fields, 0);
4258 df_set_skip_before(no_fields, 0);
4259 df_set_read_type(no_fields, prev_read_type);
4261 df_no_bin_cols = no_fields;
4263 c_token++; /* Advance to next token character. */
4269 df_show_binary(FILE *fp)
4272 df_binary_file_record_struct *bin_record;
4275 \tDefault binary data file settings (in-file settings may override):\n");
4277 if (!df_num_bin_records_default) {
4278 bin_record = &df_bin_record_reset;
4281 bin_record = df_bin_record_default;
4282 num_record = df_num_bin_records_default;
4285 fprintf(fp, "\n\t File Type: ");
4286 if (df_bin_filetype_default >= 0)
4288 df_bin_filetype_table[df_bin_filetype_default].extension);
4290 fprintf(fp, "none");
4291 fprintf(fp, "\n\t File Endianess: %s",
4292 df_endian[df_bin_file_endianess_default]);
4294 for (i = 0; i < num_record; i++) {
4297 fprintf(fp, "\n\t Record %d:\n", i);
4298 fprintf(fp, "\t Dimension: ");
4299 if (bin_record[i].cart_dim[0] < 0)
4302 fprintf(fp, "%d", bin_record[i].cart_dim[0]);
4303 if (bin_record[i].cart_dim[1] > 0) {
4305 fprintf(fp, "x%d", bin_record[i].cart_dim[1]);
4306 if (bin_record[i].cart_dim[2] > 0) {
4308 fprintf(fp, "x%d", bin_record[i].cart_dim[2]);
4312 fprintf(fp, "\n\t Generate coordinates: %s",
4313 (bin_record[i].scan_generate_coord ? "yes" : "no"));
4314 if (bin_record[i].scan_generate_coord) {
4316 TBOOLEAN no_flip = TRUE;
4318 fprintf(fp, "\n\t Direction: ");
4319 if (bin_record[i].cart_dir[0] == -1) {
4320 fprintf(fp, "flip x");
4323 if ((dimension > 1) && (bin_record[i].cart_dir[1] == -1)) {
4324 fprintf(fp, "%sflip y", (no_flip ? "" : ", "));
4327 if ((dimension > 2) && (bin_record[i].cart_dir[2] == -1)) {
4328 fprintf(fp, "%sflip z", (no_flip ? "" : ", "));
4332 fprintf(fp, "all forward");
4333 fprintf(fp, "\n\t Sample periods: dx=%f",
4334 bin_record[i].cart_delta[0]);
4336 fprintf(fp, ", dy=%f", bin_record[i].cart_delta[1]);
4338 fprintf(fp, ", dz=%f", bin_record[i].cart_delta[2]);
4339 if (bin_record[i].cart_trans == DF_TRANSLATE_VIA_ORIGIN)
4340 fprintf(fp, "\n\t Origin:");
4341 else if (bin_record[i].cart_trans == DF_TRANSLATE_VIA_CENTER)
4342 fprintf(fp, "\n\t Center:");
4343 if ((bin_record[i].cart_trans == DF_TRANSLATE_VIA_ORIGIN)
4344 || (bin_record[i].cart_trans == DF_TRANSLATE_VIA_CENTER))
4345 fprintf(fp, " (%f, %f, %f)",
4346 bin_record[i].cart_cen_or_ori[0],
4347 bin_record[i].cart_cen_or_ori[1],
4348 bin_record[i].cart_cen_or_ori[2]);
4349 fprintf(fp, "\n\t 2D rotation angle: %f",
4350 bin_record[i].cart_alpha);
4351 fprintf(fp, "\n\t 3D normal vector: (%f, %f, %f)",
4352 bin_record[i].cart_p[0],
4353 bin_record[i].cart_p[1],
4354 bin_record[i].cart_p[2]);
4356 j < (sizeof(df_bin_scan_table_3D)
4357 /sizeof(df_bin_scan_table_3D[0]));
4359 if (!strncmp((char *)bin_record[i].cart_scan,
4360 (char *)df_bin_scan_table_3D[j].scan,
4361 sizeof(bin_record[0].cart_scan)) ) {
4362 fprintf(fp, "\n\t Scan: ");
4364 (bin_record[i].cart_dim[2] ? "%s" : "%2.2s"),
4365 df_bin_scan_table_3D[j].string);
4369 fprintf(fp, "\n\t Skip bytes: %d before record",
4370 bin_record[i].scan_skip[0]);
4372 fprintf(fp, ", %d before line", bin_record[i].scan_skip[1]);
4374 fprintf(fp, ", %d before plane", bin_record[i].scan_skip[2]);
4382 df_show_datasizes(FILE *fp)
4386 fprintf(fp,"\tThe following binary data sizes are machine dependent:\n\n"
4387 "\t name (size in bytes)\n\n");
4389 i < sizeof(df_binary_details)/sizeof(df_binary_details[0]);
4394 for (j = 0; j < df_binary_details[i].no_names; j++) {
4395 fprintf(fp,"\"%s\" ",df_binary_details[i].name[j]);
4397 fprintf(fp,"(%d)\n",df_binary_details[i].type.read_size);
4401 \tThe following binary data sizes attempt to be machine independent:\n\n\
4402 \t name (size in bytes)\n\n");
4404 i < sizeof(df_binary_details_independent)
4405 /sizeof(df_binary_details_independent[0]);
4410 for (j = 0; j < df_binary_details_independent[i].no_names; j++) {
4411 fprintf(fp,"\"%s\" ",df_binary_details_independent[i].name[j]);
4413 fprintf(fp,"(%d)",df_binary_details_independent[i].type.read_size);
4414 if (df_binary_details_independent[i].type.read_type == DF_BAD_TYPE)
4415 fprintf(fp," -- processor does not support this size");
4422 df_show_filetypes(FILE *fp)
4426 fprintf(fp,"\tThe following binary file types are understood by gnuplot:\n\n");
4428 i < sizeof(df_bin_filetype_table)
4429 /sizeof(df_bin_filetype_table_struct);
4431 fprintf(fp, "\t %s\n", df_bin_filetype_table[i].extension);
4437 df_swap_bytes_by_endianess(char *data, int read_order, int read_size)
4439 if ((read_order == DF_3210)
4440 #if SUPPORT_MIDDLE_ENDIAN
4441 || (read_order == DF_2301)
4445 int k = read_size - 1;
4447 for (; j < k; j++, k--) {
4448 char temp = data[j];
4455 #if SUPPORT_MIDDLE_ENDIAN
4456 if ((read_order == DF_1032) || (read_order == DF_2301)) {
4457 int j= read_size - 1;
4459 for (; j > 0; j -= 2) {
4460 char temp = data[j-1];
4462 data[j-1] = data[j];
4470 /*{{{ int df_readbinary(v, max) */
4471 /* do the hard work... read lines from file,
4472 * - use blanks to get index number
4473 * - ignore lines outside range of indices required
4474 * - fill v[] based on using spec if given
4478 df_readbinary(double v[], int max)
4480 /* For general column structured binary. */
4481 static int scan_size[3];
4482 static double delta[3]; /* sampling periods */
4483 static double o[3]; /* add after rotations */
4484 static double c[3]; /* subtract before doing rotations */
4485 static double P[3][3]; /* 3D rotation matrix (perpendicular) */
4486 static double R[2][2]; /* 2D rotation matrix (rotate) */
4487 static int read_order;
4488 static int record_skip;
4489 static int end_of_scan_line;
4490 static int end_of_block;
4491 static TBOOLEAN translation_required;
4492 static char *memory_data;
4494 /* For matrix data structure (i.e., gnuplot binary). */
4495 static double first_matrix_column;
4496 static float *scanned_matrix_row = 0;
4497 static int first_matrix_row_col_count;
4498 TBOOLEAN saved_first_matrix_column = FALSE;
4500 assert(data_fp != NULL);
4501 assert(max <= MAXDATACOLS);
4502 assert(df_max_bininfo_cols > df_no_bin_cols);
4503 assert(df_no_bin_cols);
4505 /* catch attempt to read past EOF on mixed-input */
4509 /* Check if we have room for at least df_no_bin_cols columns */
4510 if (df_max_cols < df_no_bin_cols) {
4511 df_column = gp_realloc(df_column,
4512 df_no_bin_cols * sizeof(df_column_struct),
4513 "datafile columns");
4514 df_max_cols = df_no_bin_cols;
4517 /* In binary mode, the number of user specs was increased by the
4518 * number of dimensions in the underlying uniformly sampled grid
4519 * previously. Fill in those values. Also, compute elements of
4520 * formula x' = P*R*(x - c) + o */
4521 if (!df_M_count && !df_N_count && !df_O_count) {
4524 df_binary_file_record_struct *this_record
4525 = df_bin_record + df_bin_record_count;
4527 scan_size[0] = scan_size[1] = scan_size[2] = 0;
4529 D2 = rotation_matrix_2D(R, this_record->cart_alpha);
4530 D3 = rotation_matrix_3D(P, this_record->cart_p);
4531 translation_required = D2 || D3;
4533 if (df_matrix_file) {
4535 scan_size[0] = this_record->scan_dim[0];
4536 scan_size[1] = this_record->scan_dim[1];
4538 if (scan_size[0] == 0)
4539 int_error(NO_CARET, "Scan size of matrix is zero");
4541 /* To accomplish flipping in this case, multiply the
4542 * appropriate column of the rotation matrix by -1. */
4543 for (i = 0; i < 2; i++) {
4546 for (j = 0; j < 2; j++) {
4547 R[i][j] *= this_record->cart_dir[i];
4551 for (i = 0; i < 3; i++) {
4552 if (this_record->cart_trans != DF_TRANSLATE_DEFAULT) {
4553 o[i] = this_record->cart_cen_or_ori[i];
4555 /* Default is translate by center. */
4557 o[i] = (df_matrix_corner[1][i]
4558 + df_matrix_corner[0][i]) / 2;
4564 for (i = 0; i < 3; i++) {
4565 if (this_record->cart_trans == DF_TRANSLATE_VIA_ORIGIN) {
4567 c[i] = df_matrix_corner[0][i];
4572 c[i] = (df_matrix_corner[1][i]
4573 + df_matrix_corner[0][i]) / 2;
4579 first_matrix_row_col_count = 0;
4580 } else { /* general binary */
4581 for (i = 0; i < 3; i++) {
4584 /* How to direct the generated coordinates in regard
4585 * to scan direction */
4586 if (this_record->cart_dim[i] || this_record->scan_dim[i]) {
4587 if (this_record->scan_generate_coord)
4588 use_spec[i].column = this_record->cart_scan[i];
4592 map = DF_SCAN_POINT - this_record->cart_scan[i];
4593 if (this_record->cart_dim[i] > 0)
4594 scan_size[map] = this_record->cart_dim[i];
4597 = this_record->scan_dim[map];
4598 /* Sample periods */
4599 if (this_record->cart_delta[i])
4600 delta[map] = this_record->cart_delta[i];
4602 delta[map] = this_record->scan_delta[map];
4603 delta[map] = delta[map]
4604 * this_record->scan_dir[map]
4605 * this_record->cart_dir[i];
4607 if (this_record->cart_trans
4608 != DF_TRANSLATE_DEFAULT)
4609 o[i] = this_record->cart_cen_or_ori[i];
4610 else if (this_record->scan_trans != DF_TRANSLATE_DEFAULT)
4611 o[i] = this_record->scan_cen_or_ori[map];
4612 else if (scan_size[map] > 0)
4613 o[i] = (scan_size[map] - 1)*fabs(delta[map])/2;
4617 if (this_record->cart_trans == DF_TRANSLATE_VIA_ORIGIN
4618 || (this_record->cart_trans == DF_TRANSLATE_DEFAULT
4619 && this_record->scan_trans == DF_TRANSLATE_VIA_ORIGIN)
4621 if ((scan_size[map] > 0) && (delta[map] < 0))
4622 c[i] = (scan_size[map] - 1)*delta[map];
4626 if (scan_size[map] > 0)
4627 c[i] = (scan_size[map] - 1)*(delta[map]/2);
4634 /* Check if c and o are the same. */
4635 for (i = 0; i < 3; i++)
4636 translation_required = translation_required
4639 /* Should data come from memory? */
4640 memory_data = this_record->memory_data;
4642 /* byte read order */
4643 read_order = byte_read_order(df_bin_file_endianess);
4645 /* amount to skip before record */
4646 record_skip = this_record->scan_skip[0];
4648 end_of_scan_line = FALSE;
4649 end_of_block = FALSE;
4652 df_current_index = df_bin_record_count;
4656 /*{{{ process line */
4658 int output = 0; /* how many numbers written to v[] */
4659 int i, fread_ret = 0;
4660 int m_value, n_value, o_value;
4674 /* Scan in a number of floats based upon the largest index in
4675 * the use_specs array. If the largest index in the array is
4676 * greater than maximum columns then issue an error.
4679 /* Handle end of line or end of block on previous read. */
4680 if (end_of_scan_line) {
4681 end_of_scan_line = FALSE;
4684 return DF_FIRST_BLANK;
4687 end_of_block = FALSE;
4689 return DF_SECOND_BLANK;
4692 /* Possibly skip bytes before starting to read record. */
4693 while (record_skip) {
4696 } else if ((fread_ret = fread(&io_val.ch,
4700 if (feof(data_fp)) {
4704 int_error(NO_CARET, read_error_msg);
4707 } /* while(record_skip) */
4709 /* Bring in variables as described by the field parameters.
4710 * If less than than the appropriate number of bytes have been
4711 * read, issue an error stating not enough columns were found. */
4712 for (i = 0; ; i++) {
4713 int skip_bytes = df_column_bininfo[i].skip_bytes;
4717 memory_data += skip_bytes;
4718 } else if ((fread_ret = fread(&io_val.ch, sizeof(io_val.ch),
4719 skip_bytes, data_fp))
4721 if (feof(data_fp)) {
4725 int_error(NO_CARET, read_error_msg);
4729 /* Last entry only has skip bytes, no data. */
4730 if (i == df_no_bin_cols)
4733 /* Read in a "column", i.e., a binary value of various types. */
4736 fread_ret < df_column_bininfo[i].column.read_size;
4738 (&io_val.ch)[fread_ret] = *memory_data++;
4740 fread_ret = fread(&io_val.ch,
4741 df_column_bininfo[i].column.read_size,
4743 if (fread_ret != 1) {
4749 df_swap_bytes_by_endianess(&io_val.ch, read_order,
4750 df_column_bininfo[i].column.read_size);
4752 switch (df_column_bininfo[i].column.read_type) {
4754 df_column[i].datum = io_val.ch;
4757 df_column[i].datum = io_val.uc;
4760 df_column[i].datum = io_val.sh;
4763 df_column[i].datum = io_val.us;
4766 df_column[i].datum = io_val.in;
4769 df_column[i].datum = io_val.ui;
4772 df_column[i].datum = io_val.lo;
4775 df_column[i].datum = io_val.ul;
4778 df_column[i].datum = io_val.fl;
4781 df_column[i].datum = io_val.db;
4784 int_error(NO_CARET, "Binary data type unknown");
4787 df_column[i].good = DF_GOOD;
4788 df_column[i].position = NULL; /* cant get a time */
4790 /* Matrix file data is a special case. After reading
4791 * in just one binary value, stop then decide on what
4798 if (df_matrix_file) {
4799 if (df_matrix_binary) {
4800 /* Store just first column? */
4801 if (!df_M_count && !saved_first_matrix_column) {
4802 first_matrix_column = df_column[i].datum;
4803 saved_first_matrix_column = TRUE;
4807 /* Read reset of first row? */
4808 if (!df_M_count && !df_N_count && !df_O_count
4809 && first_matrix_row_col_count < scan_size[0]) {
4810 if (!first_matrix_row_col_count
4811 && ! (scanned_matrix_row =
4812 gp_realloc(scanned_matrix_row,
4813 scan_size[0]*sizeof(float),
4814 "gpbinary matrix row")))
4815 int_error(NO_CARET, "not enough memory to create vector");
4816 scanned_matrix_row[first_matrix_row_col_count]
4817 = df_column[i].datum;
4818 first_matrix_row_col_count++;
4819 if (first_matrix_row_col_count == scan_size[0]) {
4820 /* Start of the second row. */
4821 saved_first_matrix_column = FALSE;
4828 /* Update all the binary columns. Matrix binary and
4829 * matrix ASCII is a slight abuse of notation. At the
4830 * command line, 1 means first row, 2 means first
4831 * column. There can only be one column of data input
4832 * because it is a matrix of data, not columns. */
4836 df_datum = df_column[i].datum;
4838 /* Fill backward so that current read value is not
4840 for (j = df_no_bin_cols-1; j >= 0; j--) {
4844 ? scanned_matrix_row[df_M_count]
4849 ? first_matrix_column
4852 df_column[j].datum = df_column[i].datum;
4853 df_column[j].good = DF_GOOD;
4854 df_column[j].position = NULL;
4857 } else { /* Not matrix file, general binray. */
4858 df_datum = point_count + 1;
4859 if (i != df_no_bin_cols) {
4860 if (feof(data_fp)) {
4862 int_error(NO_CARET, "\
4863 Last point in the binary file did not match the specified `using` columns");
4867 int_error(NO_CARET, read_error_msg);
4872 m_value = df_M_count;
4873 n_value = df_N_count;
4874 o_value = df_O_count;
4876 if ((scan_size[0] > 0) && (df_M_count >= scan_size[0])) {
4877 /* This is a new "line". */
4880 end_of_scan_line = TRUE;
4881 if ((scan_size[1] >= 0) && (df_N_count >= scan_size[1])) {
4882 /* This is a "block". */
4885 if ((scan_size[2] >= 0) && (df_O_count >= scan_size[2])) {
4887 end_of_block = TRUE;
4888 if (++df_bin_record_count >= df_num_bin_records) {
4895 /*{{{ ignore points outside range of index */
4896 /* we try to return end-of-file as soon as we pass upper
4897 * index, but for mixed input stream, we must skip garbage */
4899 if (df_current_index < df_lower_index
4900 || df_current_index > df_upper_index
4901 || ((df_current_index - df_lower_index) % df_index_step) != 0)
4905 /*{{{ reject points by every */
4906 /* accept only lines with (line_count%everyline) == 0 */
4907 if (line_count < firstline
4908 || line_count > lastline
4909 || (line_count - firstline) % everyline != 0)
4912 /* update point_count. ignore point if
4913 point_count%everypoint != 0 */
4914 if (++point_count < firstpoint
4915 || point_count > lastpoint
4916 || (point_count - firstpoint) % everypoint != 0)
4920 /* At this point the binary columns have been read
4921 * successfully. Set df_no_cols to df_no_bin_cols for use
4922 * in the interpretation code. */
4923 df_no_cols = df_no_bin_cols;
4925 /*{{{ copy column[] to v[] via use[] */
4927 int limit = (df_no_use_specs ? df_no_use_specs : MAXDATACOLS);
4932 for (output = 0; output < limit; ++output) {
4933 int column = use_spec[output].column;
4935 /* if there was no using spec, column is output+1 and at=NULL */
4936 if (use_spec[output].at) {
4939 /* no dummy values to set up prior to... */
4940 evaluate_inside_using = TRUE;
4941 evaluate_at(use_spec[output].at, &a);
4942 evaluate_inside_using = FALSE;
4944 /* store undefined point in plot */
4945 return DF_UNDEFINED;
4947 v[output] = real(&a);
4948 } else if (column == -5) {
4949 /* Perhaps try using a switch statement to
4950 * avoid so many tests. */
4951 v[output] = o_value*delta[2];
4952 } else if (column == -4) {
4953 v[output] = n_value*delta[1];
4954 } else if (column == -3) {
4955 v[output] = m_value*delta[0];
4956 } else if (column == -2) {
4957 v[output] = df_current_index;
4958 } else if (column == -1) {
4959 v[output] = line_count;
4960 } else if (column == 0) {
4961 v[output] = df_datum;
4962 } else if (column <= 0)
4963 int_error(NO_CARET, "\
4964 internal error: unkown column type");
4965 else if ((df_axis[output] != -1)
4966 && (axis_array[df_axis[output]].is_timedata)) {
4969 if (column > df_no_cols
4970 || df_column[column - 1].good == DF_MISSING
4971 || !df_column[column - 1].position
4972 || !gstrptime(df_column[column - 1].position,
4973 axis_array[df_axis[output]].timefmt,
4975 /* line bad only if user explicitly asked
4976 * for this column */
4977 if (df_no_use_specs)
4980 /* return or ignore line depending on line_okay */
4983 v[output] = (double) gtimegm(&tm);
4984 } else if ((column <= df_no_cols)
4985 && df_column[column - 1].good == DF_GOOD)
4986 v[output] = df_column[column - 1].datum;
4988 /* EAM - Oct 2002 Distinguish between DF_MISSING
4989 * and DF_BAD. Previous versions would never
4990 * notify caller of either case. Now missing data
4991 * will be noted. Bad data should arguably be
4992 * noted also, but that would change existing
4993 * default behavior. */
4994 else if ((column <= df_no_cols)
4995 && (df_column[column - 1].good == DF_MISSING))
4998 /* line bad only if user explicitly asked
4999 * for this column */
5000 if (df_no_use_specs)
5002 break; /* return or ignore depending on line_okay */
5006 /* Linear translation. */
5007 if (translation_required) {
5013 v[0] = R[0][0] * x + R[0][1] * y;
5014 v[1] = R[1][0] * x + R[1][1] * y;
5015 if (df_plot_mode == MODE_SPLOT) {
5019 v[0] = P[0][0] * x + P[0][1] * y + P[0][2] * z;
5020 v[1] = P[1][0] * x + P[1][1] * y + P[1][2] * z;
5021 v[2] = P[2][0] * x + P[2][1] * y + P[2][2] * z;
5026 if (df_plot_mode == MODE_SPLOT)
5036 /* output == df_no_use_specs if using was specified -
5037 * actually, smaller of df_no_use_specs and max */
5038 assert(df_no_use_specs == 0
5039 || output == df_no_use_specs
5053 df_set_plot_mode(int mode)
5055 df_plot_mode = mode;
5057 #endif /* BINARY_DATA_FILE */