Icons are changed
[gnuplot] / src / datafile.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: datafile.c,v 1.110.2.21 2009/03/26 04:29:10 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - datafile.c */
6
7 /*[
8  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
9  *
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.
15  *
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,
20  * provided you
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
28  *    software.
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.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /* AUTHOR : David Denholm */
38
39 /*
40  * this file provides the functions to handle data-file reading..
41  * takes care of all the pipe / stdin / index / using worries
42  */
43
44 /*{{{  notes */
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.
48  *
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...
52  *
53  * - because I needed it, I have added a range of indexes...
54  * (s)plot 'data' [index i[:j]]
55  *
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)
60  *
61  *
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.
68  *
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
71  *
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
80  *
81  * functions
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 (?)
86  *
87  *   int df_readline(double vector[], int max)
88  *      reads a line, does all the 'index' and 'using' manipulation
89  *      deposits values into vector[]
90  *      returns
91  *          number of columns parsed  [0=not blank line, but no valid data],
92  *          DF_EOF for EOF
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
98  *
99  * if a using spec was given, lines not fulfilling spec are ignored.
100  * we will always return exactly the number of items specified
101  *
102  * if no spec given, we return number of consecutive columns we parsed.
103  *
104  * if we are processing indexes, separated by 'n' blank lines,
105  * we will return n-1 blank lines before noticing the index change
106  *
107  *   void df_close()
108  *     closes a currently open file.
109  *
110  *    void f_dollars(x)
111  *    void f_column()    actions for expressions using $i, column(j), etc
112  *    void f_valid()
113  *
114  *
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...
119  *
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
126  * fitting.
127  *
128  * 20/5/95 : accept 1.23d4 in place of e (but not in scanf string)
129  *         : autoextend data line buffer and MAX_COLS
130  *
131  * 11/8/96 : add 'columns' -1 for suggested y value, and -2 for
132  *           current index.
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
136  *
137  */
138 /*}}} */
139
140 /* Daniel Sebald: added general binary 2d data support. (20 August 2004)
141  */
142
143 #include "datafile.h"
144
145 #include "alloc.h"
146 #include "axis.h"
147 #include "binary.h"
148 #include "command.h"
149 #include "eval.h"
150 #include "gp_time.h"
151 #include "graphics.h"
152 #include "misc.h"
153 #include "parse.h"
154 #include "plot.h"
155 #include "util.h"
156 #ifdef BINARY_DATA_FILE
157 #include "breaders.h"
158 #endif
159
160 /* test to see if the end of an inline datafile is reached */
161 #define is_EOF(c) ((c) == 'e' || (c) == 'E')
162
163 /* is it a comment line? */
164 #define is_comment(c) ((c) && (strchr(df_commentschars, (c)) != NULL))
165
166 /*{{{  static fns */
167 #if 0                           /* not used */
168 static int get_time_cols __PROTO((char *fmt));
169 static void mod_def_usespec __PROTO((int specno, int jump));
170 #endif
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));
176 #else
177 static float **df_read_matrix __PROTO((int *rows, int *columns));
178 #endif
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 *));
187 #endif
188 #ifdef EAM_HISTOGRAMS
189 static void add_key_entry __PROTO((char *temp_string, int df_datum));
190 #endif
191
192 /*}}} */
193
194 /*{{{  variables */
195
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 };
200 #endif
201
202 /* public variables client might access */
203
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() */
207 #endif
208 int df_line_number;
209 int df_datum;                   /* suggested x value if none given */
210 int df_eof = 0;
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 */
214
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;
218
219 /* string representing missing values in ascii datafiles */
220 char *missing_val = NULL;
221
222 /* input field separator, NUL if whitespace is the separator */
223 char df_separator = '\0';
224
225 /* comments chars */
226 char *df_commentschars = 0;
227
228 /* If any 'inline data' are in use for the current plot, flag this */
229 TBOOLEAN plotted_data_from_stdin = FALSE;
230
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;
234
235 /* private variables */
236
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
239  */
240 static char *line = NULL;
241 static size_t max_line_len = 0;
242 #define DATA_LINE_BUFSIZ 160
243
244 static FILE *data_fp = NULL;
245 #if defined(PIPES)
246 static TBOOLEAN df_pipe_open = FALSE;
247 #endif
248 static TBOOLEAN mixed_data_fp = FALSE; /* inline data */
249 char *df_filename;      /* name of data file */
250
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
254 #endif
255
256 #ifndef MAXINT                  /* should there be one already defined ? */
257 # ifdef INT_MAX                 /* in limits.h ? */
258 #  define MAXINT INT_MAX
259 # else
260 #  define MAXINT ((~0)>>1)
261 # endif
262 #endif
263
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 */
270
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 */
280
281 /* parsing stuff */
282 struct use_spec_s use_spec[MAXDATACOLS];
283 static char df_format[MAX_LINE_LEN + 1];
284 static TBOOLEAN evaluate_inside_using = FALSE;
285
286 /* rather than three arrays which all grow dynamically, make one
287  * dynamic array of this structure
288  */
289
290 typedef struct df_column_struct {
291     double datum;
292     enum {
293         DF_BAD, DF_GOOD
294     } good;
295     char *position;
296 } df_column_struct;
297
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 */
302
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};
307 #endif
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 */
312 #endif
313
314 #ifdef BINARY_DATA_FILE
315
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.
321  */
322 TBOOLEAN df_read_binary;
323 TBOOLEAN df_matrix_binary;
324 int df_plot_mode;
325
326 /* Define the following true of binary is to have it's own format string. */
327 #define BINARY_HAS_OWN_FORMAT_STRING 1
328
329 static int df_readascii __PROTO((double [], int));
330 static int df_readbinary __PROTO((double [], int));
331
332 static void initialize_use_spec __PROTO((void));
333
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));
346
347 typedef enum df_multivalue_type {
348     DF_DELTA,
349     DF_FLIP_AXIS,
350     DF_FLIP,
351     DF_SCAN,
352     DF_ORIGIN,
353     DF_CENTER,
354     DF_ROTATION,
355     DF_PERPENDICULAR,
356     DF_SKIP
357 } df_multivalue_type;
358 static void plot_option_multivalued __PROTO((df_multivalue_type,int));
359
360 char *df_endian[DF_ENDIAN_TYPE_LENGTH] = {
361     "little",
362     "pdp (middle)",
363     "swapped pdp (dimmle)",
364     "big"
365 };
366
367 #define SUPPORT_MIDDLE_ENDIAN 1
368
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 {
372     DF_0123,
373     DF_1032,
374     DF_2301,
375     DF_3210
376 } df_byte_read_order_type;
377
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}
385 };
386
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 )
390
391 #else /* ifdef BINARY_DATA_FILE */
392
393 typedef enum df_byte_read_order_type {
394     DF_01,
395     DF_10
396 } df_byte_read_order_type;
397
398 static int int_1 = 1;
399 #define THIS_COMPILER_ENDIAN ( ((char *)&int_1)[0] ? DF_LITTLE_ENDIAN : DF_BIG_ENDIAN )
400
401 #endif /* ifdef BINARY_DATA_FILE */
402
403 /* Argument is file's endianess type. */
404 static df_byte_read_order_type byte_read_order __PROTO((df_endianess_type));
405
406 /* Logical variables indicating information about data file. */
407 TBOOLEAN df_binary_file;
408 TBOOLEAN df_matrix_file;
409
410 int df_M_count;
411 int df_N_count;
412 int df_O_count;
413
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 = {
420     {-1, 0, 0},
421     {1, 1, 1},
422     {1, 1, 1},
423     DF_TRANSLATE_DEFAULT,
424     {0, 0, 0},
425     0,
426     {0, 0, 1},
427
428     {DF_SCAN_POINT, DF_SCAN_LINE, DF_SCAN_PLANE},
429     FALSE,
430     {0, 0, 0},
431
432     {0, 0, 0},
433     {1, 1, 1},
434     {0, 0, 0},
435     DF_TRANSLATE_DEFAULT,
436     {0, 0, 0},
437
438     NULL
439 };
440
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;
443
444 typedef struct df_bin_filetype_table_struct {
445     char *extension;
446     void (*function)(void);
447 } df_bin_filetype_table_struct;
448
449 static void gpbin_filetype_function __PROTO((void));
450 static void raw_filetype_function __PROTO((void));
451 static void avs_filetype_function __PROTO((void));
452
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},
458 #if 1
459     {"avs", avs_filetype_function},
460     {"edf", edf_filetype_function},
461     {"ehf", edf_filetype_function},
462 #endif
463     {"auto", raw_filetype_function}  /* "auto" is trapped, but if the actual file extension is "auto" then use raw. */
464 };
465 #define RAW_FILETYPE 1
466
467 /* Initially set to default and then possibly altered by command line. */
468 int df_bin_filetype;
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
476
477 typedef struct df_bin_scan_table_2D_struct {
478     char *string;
479     df_sample_scan_type scan[3];
480 } df_bin_scan_table_2D_struct;
481
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}}
487 };
488 #define TRANSPOSE_INDEX 1
489
490 typedef struct df_bin_scan_table_3D_struct {
491     char *string;
492     df_sample_scan_type scan[3];
493 } df_bin_scan_table_3D_struct;
494
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}}
508 };
509
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"};
521
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"};
533
534 typedef struct df_binary_details_struct {
535     char **name;
536     unsigned short no_names;
537     df_binary_type_struct type;
538 } df_binary_details_struct;
539
540 typedef struct df_binary_tables_struct {
541     df_binary_details_struct *group;
542     unsigned short group_length;
543 } df_binary_tables_struct;
544
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)}}
556 };
557
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}}
569 };
570
571 int df_no_bin_cols;             /* binary columns to read */
572
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])}
576 };
577
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.
580  */
581 static df_column_bininfo_struct *df_column_bininfo = NULL;      /* allocate space as needed */
582 static int df_max_bininfo_cols = 0;     /* space allocated */
583
584 static const char *matrix_general_binary_conflict_msg
585     = "Conflict between some matrix binary and general binary keywords";
586
587 #endif
588
589 /*}}} */
590
591
592 /*{{{  static char *df_gets() */
593 static char *
594 df_gets()
595 {
596     int len = 0;
597
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);
601
602     if (!fgets(line, max_line_len, data_fp))
603         return NULL;
604
605     if (mixed_data_fp)
606         ++inline_num;
607
608     for (;;) {
609         len += strlen(line + len);
610
611         if (len > 0 && line[len - 1] == '\n') {
612             /* we have read an entire text-file line.
613              * Strip the trailing linefeed and return
614              */
615             line[len - 1] = 0;
616             return line;
617         }
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
622          */
623
624         if ((max_line_len - len) < 32)
625             line = gp_realloc(line, max_line_len *= 2, "datafile line buffer");
626
627         if (!fgets(line + len, max_line_len - len, data_fp))
628             return line;        /* unexpected end of file, but we have something to do */
629     }
630
631     /* NOTREACHED */
632     return NULL;
633 }
634
635 /*}}} */
636
637 /*{{{  static int df_tokenise(s) */
638 static int
639 df_tokenise(char *s)
640 {
641     /* implement our own sscanf that takes 'missing' into account,
642      * and can understand fortran quad format
643      */
644     TBOOLEAN in_string;
645 #ifdef EAM_DATASTRINGS
646     int i;
647
648     for (i = 0; i<MAXDATACOLS; i++)
649         df_tokens[i] = NULL;
650
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;
658 #endif
659 #endif
660
661
662 #define NOTSEP (*s != df_separator)
663
664     df_no_cols = 0;
665
666     while (*s) {
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),
672                                 "datafile column");
673             while (df_max_cols < new_max)
674                 df_column[df_max_cols++].datum = 0;
675         }
676
677         /* have always skipped spaces at this point */
678         df_column[df_no_cols].position = s;
679         in_string = FALSE;
680
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) {
686                 df_tokens[i] = s;
687                 if (use_spec[i].expected_type == CT_STRING)
688                     df_column[df_no_cols].good = DF_GOOD;
689             }
690         }
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);
694 #endif
695
696         /* CSV files must accept numbers inside quotes also,
697          * so we step past the quote */
698         if (*s == '"' && df_separator != '\0') {
699             in_string = TRUE;
700             df_column[df_no_cols].position = ++s;
701         }
702
703         if (*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");
713         } else {
714             int used;
715             int count;
716             int dfncp1 = df_no_cols + 1;
717
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
731                                                 == dfncp1
732                                                 || df_no_use_specs > 5)
733                                             )
734                                         )
735                                     )
736                                 )
737                                     )
738                                 )
739                             )
740                         )
741                     )
742                 ) {
743
744 #if (0)
745                 /* This was the [slow] code used through version 4.0 */
746                 count = sscanf(s, "%lf%n", &df_column[df_no_cols].datum, &used);
747 #else
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
753                  */
754                  char *next;
755                  df_column[df_no_cols].datum = gp_strtod(s, &next);
756                  used = next - s;
757                  count = (used) ? 1 : 0;
758 #endif
759             } else {
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)
764                     ++s;
765                 count = (*s && NOTSEP) ? 1 : 0;
766                 /* skip chars to end of column */
767                 used = 0;
768                 if (df_separator != '\0' && in_string) {
769                     do
770                         ++s;
771                     while (*s && *s != '"');
772                     in_string = FALSE;
773                 }
774                 while (!isspace((unsigned char) *s)
775                        && (*s != NUL) && NOTSEP)
776                     ++s;
777             }
778
779             /* it might be a fortran double or quad precision.
780              * 'used' is only safe if count is 1
781              */
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'... */
788                 char *endptr;
789                 char save_char = s[used];
790
791                 /* might be fortran double */
792                 s[used] = 'e';
793                 /* and try again */
794                 df_column[df_no_cols].datum = gp_strtod(s, &endptr);
795                 count = (endptr == s) ? 0 : 1;
796                 s[used] = save_char;
797             }
798
799             df_column[df_no_cols].good = count == 1 ? DF_GOOD : DF_BAD;
800 #ifdef HAVE_ISNAN
801             if (isnan(df_column[df_no_cols].datum))
802                 df_column[df_no_cols].good = DF_BAD;
803 #endif
804         }
805
806         ++df_no_cols;
807
808         /* EAM - 19 Aug 2002 If we are in a quoted string, skip to end
809          * of quote */
810         if (in_string) {
811             do
812                 s++;
813             while (*s && (unsigned char) *s != '"');
814         }
815
816         /* skip to 1st character past next separator */
817         if (df_separator != '\0') {
818             while (*s && NOTSEP)
819                 ++s;
820             if (*s == df_separator)
821                 /* skip leading whitespace in next field */
822                 do
823                     ++s;
824                 while (*s && isspace((unsigned char) *s) && NOTSEP);
825         } else {
826             /* skip chars to end of column */
827             while ((!isspace((unsigned char) *s)) && (*s != '\0'))
828                 ++s;
829             /* skip spaces to start of next column */
830             while (isspace((unsigned char) *s))
831                 ++s;
832         }
833     }
834
835     return df_no_cols;
836 #undef NOTSEP
837 }
838
839 /*}}} */
840
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
844  * memory.
845  *
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
848  * the calling code.
849  */
850 static float *
851 df_read_matrix(int *rows, int *cols)
852 {
853     int max_rows = 0;
854     int c;
855     float *linearized_matrix = NULL;
856     int bad_data = 0;
857     char *s;
858     int index = 0;
859
860     *rows = 0;
861     *cols = 0;
862
863     for (;;) {
864         if (!(s = df_gets())) {
865             df_eof = 1;
866             /* NULL if we have not read anything yet */
867             return linearized_matrix;   
868         }
869
870         while (isspace((unsigned char) *s))
871             ++s;
872
873         if (!*s || is_comment(*s)) {
874             if (linearized_matrix)
875                 return linearized_matrix;
876             else
877                 continue;
878         }
879         if (mixed_data_fp && is_EOF(*s)) {
880             df_eof = 1;
881             return linearized_matrix;
882         }
883         c = df_tokenise(s);
884
885         if (!c)
886             return linearized_matrix;
887
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");
893         }
894         *cols = c;
895
896         ++*rows;
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),
901                                    "df_matrix");
902         }
903
904         /* store data */
905         {
906             int i;
907             
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;
912                 } else
913                     linearized_matrix[index++] = (float) df_column[i].datum;
914
915                 if (df_column[i].good != DF_GOOD) {
916                     if (bad_data++ == 0)
917                         int_warn(NO_CARET,"matrix contains missing or undefined values");
918                 }
919             }
920         }
921     }
922 }
923 /*}}} */
924
925 #else /* BINARY_DATA_FILE */
926
927 /*{{{  static float **df_read_matrix() */
928 /* reads a matrix from a text file stores in same storage format as
929  * fread_matrix */
930 /* FIXME HBB 20001207: doesn't respect 'index' at all, even though it
931  * could, and probably should. */
932 static float **
933 df_read_matrix(int *rows, int *cols)
934 {
935     int max_rows = 0;
936     int c;
937     float **rmatrix = NULL;
938     char *s;
939
940     *rows = 0;
941     *cols = 0;
942
943     for (;;) {
944         if (!(s = df_gets())) {
945             df_eof = 1;
946             return rmatrix;     /* NULL if we have not read anything yet */
947         }
948         while (isspace((unsigned char) *s))
949             ++s;
950
951         if (!*s || is_comment(*s)) {
952             if (rmatrix)
953                 return rmatrix;
954             else
955                 continue;
956         }
957         if (mixed_data_fp && is_EOF(*s)) {
958             df_eof = 1;
959             return rmatrix;
960         }
961         c = df_tokenise(s);
962
963         if (!c)
964             return rmatrix;
965
966         if (*cols && c != *cols) {
967             /* its not regular */
968             int_error(NO_CARET, "Matrix does not represent a grid");
969         }
970         *cols = c;
971
972         if (*rows >= max_rows) {
973             rmatrix = gp_realloc(rmatrix,
974                                  (max_rows += 10) * sizeof(float *),
975                                  "df_matrix");
976         }
977         
978         /* allocate a row and store data */
979         {
980             int i;
981             float *row = rmatrix[*rows] = gp_alloc(c * sizeof(float),
982                                            "df_matrix row");
983
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");
987
988                 row[i] = (float) df_column[i].datum;
989             }
990             ++*rows;
991         }
992     }
993 }
994 /*}}} */
995 #endif /* BINARY_DATA_FILE */
996
997
998 static void
999 initialize_use_spec()
1000 {
1001     int i;
1002     
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 */
1008 #endif
1009         if (use_spec[i].at) {
1010             free_at(use_spec[i].at);
1011             use_spec[i].at = NULL;  /* no expression */
1012         }
1013         df_axis[i] = -1; /* no timefmt for this output column */
1014     }
1015 }
1016
1017
1018 /*{{{  int df_open(char *file_name, max_using) */
1019
1020 /* open file, parsing using/thru/index stuff return number of using
1021  * specs [well, we have to return something !]
1022  */
1023 int
1024 df_open(const char *cmd_filename, int max_using)
1025 {
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;
1032 #endif
1033
1034     fast_columns = 1;           /* corey@cac */
1035
1036     /*{{{  close file if necessary */
1037     if (data_fp)
1038         df_close();
1039     /*}}} */
1040
1041     /*{{{  initialise static variables */
1042     df_format[0] = NUL;         /* no format string */
1043
1044 #ifdef EAM_DATASTRINGS
1045     df_no_tic_specs = 0;
1046 #endif
1047     df_key_title[0] = '\0';
1048
1049     initialize_use_spec();
1050
1051     df_datum = -1;              /* it will be preincremented before use */
1052     df_line_number = 0;         /* ditto */
1053
1054     df_lower_index = 0;
1055     df_index_step = 1;
1056     df_upper_index = MAXINT;
1057
1058     df_current_index = 0;
1059     blank_count = 2;
1060     /* by initialising blank_count, leading blanks will be ignored */
1061
1062     everypoint = everyline = 1; /* unless there is an every spec */
1063     firstpoint = firstline = 0;
1064     lastpoint = lastline = MAXINT;
1065
1066 #ifdef BINARY_DATA_FILE
1067     df_binary_file = df_matrix_file = FALSE;
1068 #endif
1069
1070     df_eof = 0;
1071
1072 #ifdef EAM_DATASTRINGS
1073     column_for_key_title = NO_COLUMN_HEADER;
1074     key_title_auto_col = FALSE;
1075 #endif
1076     /*}}} */
1077
1078     assert(max_using <= MAXDATACOLS);
1079
1080     if (!cmd_filename)
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");
1085     } else {
1086         free(df_filename);
1087         df_filename = gp_strdup(cmd_filename);
1088     }
1089
1090     /* defer opening until we have parsed the modifiers... */
1091
1092     if (ydata_func.at) /* something for thru (?) */
1093         free_at(ydata_func.at);
1094     ydata_func.at = NULL;
1095
1096     df_binary = df_matrix = FALSE;
1097
1098     /* pm 25.11.2001 allow any order of options */
1099     while (!END_OF_COMMAND) {
1100
1101         /* look for binary / matrix */
1102         if (almost_equals(c_token, "bin$ary")) {
1103             c_token++;
1104 #ifdef BINARY_DATA_FILE
1105             if (df_binary_file) {
1106                 duplication=TRUE;
1107                 break;
1108             }
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.
1112              */
1113             df_matrix_file = TRUE;
1114             initialize_binary_vars();
1115             plot_option_binary(set_matrix, FALSE);
1116 #else
1117             if (df_matrix) {
1118                 duplication=TRUE;
1119                 break;
1120             }
1121             df_binary = TRUE;
1122             df_matrix = TRUE;
1123 #endif
1124             continue;
1125         }
1126
1127         /* deal with matrix */
1128         if (almost_equals(c_token, "mat$rix")) {
1129             c_token++;
1130 #ifdef BINARY_DATA_FILE
1131             if (set_matrix) {
1132                 duplication=TRUE;
1133                 break;
1134             }
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.
1138              */
1139             if (!df_matrix_file && df_binary_file)
1140                 int_error(c_token, matrix_general_binary_conflict_msg);
1141             df_matrix_file = TRUE;
1142             set_matrix = TRUE;
1143 #else
1144             if (df_matrix) { duplication=TRUE; break; }
1145             df_matrix = TRUE;
1146 #endif
1147             fast_columns = 0;
1148             continue;
1149     }
1150
1151         /* deal with index */
1152     if (almost_equals(c_token, "i$ndex")) {
1153             if (set_index) { duplication=TRUE; break; }
1154         plot_option_index();
1155             set_index = TRUE;
1156             continue;
1157     }
1158
1159         /* deal with every */
1160     if (almost_equals(c_token, "ev$ery")) {
1161             if (set_every) { duplication=TRUE; break; }
1162         plot_option_every();
1163             set_every = TRUE;
1164             continue;
1165     }
1166
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; }
1171         plot_option_thru();
1172             set_thru = TRUE;
1173             continue;
1174     }
1175
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);
1180             set_using = TRUE;
1181             continue;
1182     }
1183
1184 #ifdef EAM_DATASTRINGS
1185         /* Take key title from column head? */
1186         if (almost_equals(c_token, "t$itle")) {
1187             struct value a;
1188             c_token++;
1189             if (almost_equals(c_token, "col$umnheader") && equals(c_token+1,"(")) {
1190                 c_token += 2;
1191                 column_for_key_title = (int)real(const_express(&a));
1192                 c_token++;
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;
1197                 else
1198                     column_for_key_title = use_spec[1].column;
1199                 c_token++;
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 */
1203                 c_token--;
1204             break;
1205         }
1206 #endif
1207         break; /* unknown option */
1208
1209     } /* while (!END_OF_COMMAND) */
1210
1211     if (duplication)
1212         int_error(c_token,
1213                   "duplicated or contradicting arguments in datafile options");
1214
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;
1219         
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;
1224             else
1225                 column_for_key_title = use_spec[1].column;
1226         }
1227     }
1228 #endif
1229
1230     /*{{{  more variable inits */
1231     point_count = -1;           /* we preincrement */
1232     line_count = 0;
1233
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");
1238     }
1239     /*}}} */
1240
1241     /*{{{  open file */
1242 #if defined(PIPES)
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");
1246         else
1247             df_pipe_open = TRUE;
1248     } else
1249 #endif /* PIPES */
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;
1253         data_fp = lf_top();
1254         if (!data_fp)
1255             data_fp = stdin;
1256         mixed_data_fp = TRUE;   /* don't close command file */
1257     } else {
1258         /* filename cannot be static array! */
1259         gp_expand_tilde(&df_filename);
1260 #ifdef HAVE_SYS_STAT_H
1261         {
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",
1266                         df_filename);
1267             }
1268         }
1269 #endif /* HAVE_SYS_STAT_H */
1270 #ifdef BINARY_DATA_FILE
1271         if ((data_fp = loadpath_fopen(df_filename, df_binary_file ? "rb" : "r")) ==
1272 #else
1273         if ((data_fp = loadpath_fopen(df_filename, df_binary ? "rb" : "r")) ==
1274 #endif
1275             (FILE *) NULL) {
1276             int_warn(NO_CARET, "Skipping unreadable file \"%s\"", df_filename);
1277             df_eof = 1;
1278             return DF_EOF;
1279         }
1280     }
1281 /*}}} */
1282
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.
1288      */
1289     if (df_matrix_file)
1290         df_determine_matrix_info(data_fp);
1291
1292     /* General binary, matrix binary and ASCII matrix all use the
1293      * df_readbinary() routine.
1294      */
1295     if (df_binary_file || df_matrix_file) {
1296         df_read_binary = TRUE;
1297         adjust_binary_use_spec();
1298     } else
1299         df_read_binary = FALSE;
1300
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))));
1307
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 */
1313
1314     return df_no_use_specs;
1315 }
1316
1317 /*}}} */
1318
1319 /*{{{  void df_close() */
1320 void
1321 df_close()
1322 {
1323     int i;
1324
1325     /* paranoid - mark $n and column(n) as invalid */
1326     df_no_cols = 0;
1327
1328     if (!data_fp)
1329         return;
1330
1331     if (ydata_func.at) {
1332         free_at(ydata_func.at);
1333         ydata_func.at = NULL;
1334     }
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;
1340         }
1341     /*}}} */
1342
1343     if (!mixed_data_fp) {
1344 #if defined(PIPES)
1345         if (df_pipe_open) {
1346             (void) pclose(data_fp);
1347             df_pipe_open = FALSE;
1348         } else
1349 #endif /* PIPES */
1350             (void) fclose(data_fp);
1351     }
1352     mixed_data_fp = FALSE;
1353     data_fp = NULL;
1354 }
1355
1356 /*}}} */
1357
1358 /*{{{  void df_showdata() */
1359 /* display the current data file line for an error message
1360  */
1361 void
1362 df_showdata()
1363 {
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);
1369   }
1370 }
1371
1372 /*}}} */
1373
1374
1375 static void
1376 plot_option_every()
1377 {
1378     struct value a;
1379
1380     fast_columns = 0;           /* corey@cac */
1381     /* allow empty fields - every a:b:c::e we have already established
1382      * the defaults */
1383
1384     if (!equals(++c_token, ":")) {
1385         everypoint = (int) real(const_express(&a));
1386         if (everypoint < 1)
1387             int_error(c_token, "Expected positive integer");
1388     }
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
1391      * c_token */
1392     if (equals(c_token, ":") && !equals(++c_token, ":")) {
1393         everyline = (int) real(const_express(&a));
1394         if (everyline < 1)
1395             int_error(c_token, "Expected positive integer");
1396     }
1397     if (equals(c_token, ":") && !equals(++c_token, ":")) {
1398         firstpoint = (int) real(const_express(&a));
1399         if (firstpoint < 0)
1400             int_error(c_token, "Expected non-negative integer");
1401     }
1402     if (equals(c_token, ":") && !equals(++c_token, ":")) {
1403         firstline = (int) real(const_express(&a));
1404         if (firstline < 0)
1405             int_error(c_token, "Expected non-negative integer");
1406     }
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");
1411     }
1412     if (equals(c_token, ":")) {
1413         ++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");
1417     }
1418 }
1419
1420
1421 static void
1422 plot_option_index()
1423 {
1424     struct value a;
1425
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");
1429 #else
1430     if (df_binary)
1431         int_error(c_token, "Binary file format does not allow more than one surface per file");
1432 #endif
1433
1434     ++c_token;
1435     df_lower_index = (int) real(const_express(&a));
1436     if (equals(c_token, ":")) {
1437         ++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");
1441
1442         if (equals(c_token, ":")) {
1443             ++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");
1447         }
1448     } else
1449         df_upper_index = df_lower_index;
1450 }
1451
1452
1453 static void
1454 plot_option_thru()
1455 {
1456     c_token++;
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 ?
1463      */
1464     dummy_func = &ydata_func;
1465     strcpy(c_dummy_var[2], "y");
1466     ydata_func.at = perm_at();
1467     dummy_func = NULL;
1468 }
1469
1470
1471 static void
1472 plot_option_using(int max_using)
1473 {
1474
1475     int no_cols = 0;  /* For general binary only. */
1476
1477 #ifdef BINARY_DATA_FILE
1478     /* The filetype function may have set the using specs, so reset
1479      * them before processing tokens. */
1480     if (df_binary_file)
1481         initialize_use_spec();
1482 #endif
1483
1484     if (!END_OF_COMMAND && !isstring(++c_token)) {
1485         struct value a;
1486
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");
1490
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;
1496                 ++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;
1508
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 */
1527             } else {
1528                 int col = (int) real(const_express(&a));
1529                 
1530                 if (col < -2)
1531                     int_error(c_token, "Column must be >= -2");
1532                 use_spec[df_no_use_specs++].column = col;
1533                 if (col > no_cols)
1534                     no_cols = col;
1535             }
1536         } while (equals(c_token, ":") && ++c_token);
1537     }
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.
1543          */
1544         df_extend_binary_columns(no_cols);
1545     }
1546 #endif
1547     if (!END_OF_COMMAND && isstring(c_token)) {
1548 #ifdef BINARY_DATA_FILE
1549         if (df_binary_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");
1552 # else
1553             if (df_matrix_file)
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 */
1558         if (df_binary)
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))
1563             int_error(c_token,
1564                       "Please use between 1 and 7 conversions, of type double (%%lf)");
1565
1566         c_token++;              /* skip format */
1567     } /* if (!EOC) */
1568 }
1569
1570
1571 #ifdef EAM_DATASTRINGS
1572 static
1573 void plot_ticlabel_using(int axis)
1574 {
1575     struct value a;
1576     int col = 0;
1577     
1578     c_token += 2;
1579
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;
1587     } else {
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 */
1591     }
1592 #else
1593     col = (int) real(const_express(&a));
1594 #endif
1595
1596     if (col < 1)
1597         int_error(c_token, "ticlabels must come from a real column");
1598     c_token++;
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;
1601     df_no_tic_specs++;
1602 }
1603 #endif /* EAM_DATASTRINGS */
1604
1605
1606 /*{{{  int df_readline(v, max) */
1607 int
1608 df_readline(double v[], int max)
1609 {
1610     if (!data_fp)
1611         return DF_EOF;
1612
1613 #ifdef BINARY_DATA_FILE
1614     if (df_read_binary)
1615         /* General binary, matrix binary or matrix ascii
1616          * that's been converted to binary.
1617          */
1618         return df_readbinary(v, max);
1619     else
1620 #endif
1621         return df_readascii(v, max);
1622 }
1623 /*}}} */
1624
1625
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
1630  */
1631
1632 int
1633 df_readascii(double v[], int max)
1634 {
1635     char *s;
1636
1637     assert(data_fp != NULL);
1638     assert(max_line_len);       /* alloc-ed in df_open() */
1639     assert(max <= MAXDATACOLS);
1640
1641     /* catch attempt to read past EOF on mixed-input */
1642     if (df_eof)
1643         return DF_EOF;
1644
1645         /*{{{  process line */
1646     while ((s = df_gets()) != NULL) {
1647         int line_okay = 1;
1648         int output = 0;         /* how many numbers written to v[] */
1649
1650         ++df_line_number;
1651         df_no_cols = 0;
1652
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  */
1657         /*}}} */
1658
1659         /*{{{  skip comments */
1660         if (is_comment(*s))
1661             continue;           /* ignore comments */
1662         /*}}} */
1663
1664         /*{{{  check EOF on mixed data */
1665         if (mixed_data_fp && is_EOF(*s)) {
1666             df_eof = 1;         /* trap attempts to read past EOF */
1667             return DF_EOF;
1668         }
1669         /*}}} */
1670
1671         /*{{{  its a blank line - update counters and continue or return */
1672         if (*s == 0) {
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
1677              *
1678              * - I have probably missed some obvious way of doing all this,
1679              * but its getting late
1680              */
1681
1682             point_count = -1;   /* restart counter within line */
1683
1684             if (++blank_count == 1) {
1685                 /* first blank line */
1686                 ++line_count;
1687             }
1688             /* just reached end of a group/surface */
1689             if (blank_count == 2) {
1690                 ++df_current_index;
1691                 line_count = 0;
1692                 df_datum = -1;
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
1698                  */
1699                 if (df_current_index <= df_lower_index)
1700                     continue;   /* dont tell client */
1701
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 */
1705                     if (mixed_data_fp)
1706                         continue;
1707                     else {
1708                         df_eof = 1;
1709                         return DF_EOF;  /* no point continuing */
1710                     }
1711                 }
1712             }
1713             /* dont tell client if we haven't reached first index */
1714             if (df_current_index < df_lower_index)
1715                 continue;
1716
1717             /* ignore blank lines after blank_index */
1718             if (blank_count > 2)
1719                 continue;
1720
1721             return DF_FIRST_BLANK - (blank_count - 1);
1722         }
1723         /*}}} */
1724
1725         /* get here => was not blank */
1726
1727         blank_count = 0;
1728
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
1732          */
1733
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)
1737             continue;
1738         /*}}} */
1739
1740         /*{{{  reject points by every */
1741         /* accept only lines with (line_count%everyline) == 0 */
1742
1743         if (line_count < firstline || line_count > lastline ||
1744             (line_count - firstline) % everyline != 0)
1745             continue;
1746
1747         /* update point_count. ignore point if point_count%everypoint != 0 */
1748
1749         if (++point_count < firstpoint || point_count > lastpoint ||
1750             (point_count - firstpoint) % everypoint != 0)
1751             continue;
1752         /*}}} */
1753         /*}}} */
1754
1755         ++df_datum;
1756
1757         if (*df_format) {
1758             /*{{{  do a sscanf */
1759             int i;
1760
1761             assert(MAXDATACOLS == 7);
1762
1763             /* check we have room for at least 7 columns */
1764             if (df_max_cols < 7) {
1765                 df_max_cols = 7;
1766                 df_column = gp_realloc(df_column,
1767                                        df_max_cols * sizeof(df_column_struct),
1768                                        "datafile columns");
1769             }
1770
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);
1779
1780             if (df_no_cols == EOF) {
1781                 df_eof = 1;
1782                 return DF_EOF;  /* tell client */
1783             }
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 */
1787             }
1788             /*}}} */
1789         } else
1790             df_tokenise(s);
1791
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) {
1796             df_datum--;
1797             if (!(*df_key_title)) {
1798                 FPRINTF((stderr,
1799                          "df_readline: missing column head for key title\n"));
1800                 return(DF_KEY_TITLE_MISSING);
1801             }
1802             df_parse_string_field(df_key_title, df_key_title);
1803             FPRINTF((stderr,
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);
1809         }
1810 #endif
1811
1812         /*{{{  copy column[] to v[] via use[] */
1813         {
1814 #ifdef EAM_DATASTRINGS
1815             int limit = (df_no_use_specs
1816                          ? df_no_use_specs + df_no_tic_specs
1817                          : MAXDATACOLS);
1818             
1819             if (limit > max + df_no_tic_specs)
1820                 limit = max + df_no_tic_specs;
1821 #else
1822             int limit = (df_no_use_specs ? df_no_use_specs : MAXDATACOLS);
1823             if (limit > max)
1824                 limit = max;
1825 #endif
1826
1827             for (output = 0; output < limit; ++output) {
1828                 /* if there was no using spec, column is output+1 and
1829                  * at=NULL */
1830                 int column = use_spec[output].column;
1831
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];
1837                     int axis, axcol;
1838                     float xpos;
1839                     
1840                     switch (use_spec[output].expected_type) {
1841                         default:
1842                         case CT_XTICLABEL:
1843                             axis = FIRST_X_AXIS;
1844                             axcol = 0;
1845                             break;
1846                         case CT_X2TICLABEL:
1847                             axis = SECOND_X_AXIS;
1848                             axcol = 0;
1849                             break;
1850                         case CT_YTICLABEL:
1851                             axis = FIRST_Y_AXIS;
1852                             axcol = 1;
1853                             break;
1854                         case CT_Y2TICLABEL:
1855                             axis = SECOND_Y_AXIS;
1856                             axcol = 1;
1857                             break;
1858                         case CT_ZTICLABEL:
1859                             axis = FIRST_Z_AXIS;
1860                             axcol = 2;
1861                             break;
1862                         case CT_CBTICLABEL:
1863                             /* EAM FIXME - Which column to set for cbtic? */
1864                             axis = COLOR_AXIS;
1865                             axcol = 3;
1866                             break;
1867                     }
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 */
1871                     if (output == 1)
1872                         xpos = (axcol == 0) ? df_datum : v[axcol-1];
1873                     else
1874                         xpos = v[axcol];
1875 #ifdef EAM_HISTOGRAMS
1876                     if (df_current_plot
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;
1881                     }
1882 #endif
1883
1884 #ifdef GP_STRING_VARS
1885                     /* Tic label is generated by a string-valued function */
1886                     if (use_spec[output].at) {
1887                         struct value a;
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);
1893                             gpfree_string(&a);
1894                         } else
1895                             fprintf(stderr,"Tic label does not evaluate as string!\n");
1896                     } else
1897 #endif
1898                     {
1899                         df_parse_string_field(temp_string,df_tokens[output]);
1900                         add_tic_user(axis,temp_string, xpos, -1);
1901                     }
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);
1908 #endif
1909                 } else
1910 #endif
1911                 if (use_spec[output].at) {
1912                     struct value a;
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;
1917                     if (undefined)
1918                         return DF_UNDEFINED;    /* store undefined point in plot */
1919
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");
1926                             *s = '"';
1927                             strcpy(s+1, a.v.string_val);
1928                             strcat(s, "\"");
1929                             free(df_stringexpression[output]);
1930                             df_tokens[output] = df_stringexpression[output] = s;
1931                         }
1932
1933                         /* Check for timefmt string generated by a function */
1934                         if ((df_axis[output] != -1)
1935                            && axis_array[df_axis[output]].is_timedata) {
1936                             struct tm tm;
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? */
1941                                 line_okay = 0;
1942                         }
1943                         gpfree_string(&a);
1944                     } else
1945 #endif
1946                         v[output] = real(&a);
1947
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)) {
1958                     struct tm tm;
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)
1964                         ) {
1965                         /* line bad only if user explicitly asked for this column */
1966                         if (df_no_use_specs)
1967                             line_okay = 0;
1968
1969                         /* return or ignore line depending on line_okay */
1970                         break;
1971                     }
1972                     v[output] = (double) gtimegm(&tm);
1973 #ifdef EAM_DATASTRINGS
1974                 } else if (use_spec[output].expected_type == CT_STRING) {
1975                     /* Do nothing. */
1976                     /* String tokens were loaded into df_tokens already. */
1977 #endif
1978                 } else {
1979                     /* column > 0 */
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))
1991                         return DF_MISSING;
1992                     else {
1993                         /* line bad only if user explicitly asked
1994                          * for this column */
1995                         if (df_no_use_specs)
1996                             line_okay = 0;
1997                         break;      /* return or ignore depending on line_okay */
1998                     }
1999                 }
2000             }
2001         }
2002         /*}}} */
2003
2004         if (!line_okay)
2005             continue;
2006
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;
2015 #endif
2016         assert(df_no_use_specs == 0
2017                || output == df_no_use_specs
2018                || output == max);
2019
2020         return output;
2021
2022     }
2023     /*}}} */
2024
2025     /* get here => fgets failed */
2026
2027     /* no longer needed - mark column(x) as invalid */
2028     df_no_cols = 0;
2029
2030     df_eof = 1;
2031     return DF_EOF;
2032 }
2033 /*}}} */
2034
2035
2036 #ifndef BINARY_DATA_FILE
2037 /*{{{  int df_2dbinary(this_plot) */
2038 int
2039 df_2dbinary(struct curve_points *this_plot)
2040 {
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 */
2044 }
2045 /*}}} */
2046 #endif
2047
2048
2049 #ifndef BINARY_DATA_FILE /* NO LONGER REQUIRED FOR GENERAL BINARY DATA */
2050 /*{{{  int df_3dmatrix(this_plot, ret_this_iso) */
2051 /*
2052  * formerly in gnubin.c
2053  *
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)
2059  *
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
2063  * properly ?
2064  *
2065  * Trouble figuring out file format ! Is it
2066
2067  width  x1  x2  x3  x4  x5 ...
2068  y1   z11 z12 z13 z14 z15 ...
2069  y2   x21 z22 z23 .....
2070  .    .
2071  .        .
2072  .             .
2073
2074  * with perhaps x and y swapped...
2075  *
2076  * - presumably rows continue to end of file, hence no indexing...
2077  *
2078  * Last update: 3/3/92 for Gnuplot 3.24.
2079  * Created from code for written by RKC for gnuplot 2.0b.
2080  *
2081  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
2082  * Added user-specified bases for log scaling.
2083  *
2084  * Copyright (c) 1991,1992 Robert K. Cunningham, MIT Lincoln Laboratory
2085  *
2086  */
2087
2088 /*
2089  * Here we keep putting new plots onto the end of the linked list
2090  *
2091  * We assume the data's x,y values have x1<x2, x2<x3... and
2092  * y1<y2, y2<y3... .
2093  * Actually, I think the assumption is less strong than that--it looks like
2094  * the direction just has to be the same.
2095  *
2096  * This routine expects all the 'axis array' variables (now gathered
2097  * in axis.h) to be properly initialized
2098  *
2099  * does the autoscaling into the array versions (min_array[], max_array[]) */
2100
2101 int
2102 df_3dmatrix(struct surface_points *this_plot, int need_palette)
2103 {
2104     float GPFAR * GPFAR * dmatrix, GPFAR * rt, GPFAR * ct;
2105     int nr, nc;
2106     int width, height;
2107     int row, col;
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 */
2113
2114     assert(df_matrix);
2115
2116     if (df_eof)
2117         return 0;               /* hope caller understands this */
2118
2119     if (df_binary) {
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 */
2123         df_eof = 1;
2124     } else {
2125         if (!(dmatrix = df_read_matrix(&nr, &nc))) {
2126             df_eof = 1;
2127             return 0;
2128         }
2129         /* HBB 20001208: implement 'index' for matrix files: don't return
2130          * the data to caller if index is not among of the selected
2131          * ones */
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
2135             ) {
2136             free_matrix(dmatrix, 0, nr - 1, 0);
2137             df_current_index ++;
2138             return 0;
2139         }
2140
2141         rt = NULL;
2142         ct = NULL;
2143     }
2144
2145     if (nc == 0 || nr == 0)
2146         int_error(NO_CARET, "Read grid of zero height or zero width");
2147
2148     this_plot->plot_type = DATA3D;
2149     this_plot->has_grid_topology = TRUE;
2150
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");
2155
2156     if (need_palette && df_no_use_specs == 4)
2157         this_plot->pm3d_color_from_column = 1;
2158
2159     /* columns are those in the binary data file, not those of `using` spec */
2160     if (df_max_cols < 3) {
2161         df_max_cols = 3;
2162         df_column = gp_realloc(df_column,
2163                                df_max_cols * sizeof(df_column_struct),
2164                                "datafile columns");
2165     }
2166
2167     df_no_cols = 3;
2168     df_column[0].good = df_column[1].good = df_column[2].good = DF_GOOD;
2169
2170     assert(everyline > 0);
2171     assert(everypoint > 0);
2172     width = (nc - firstpoint + everypoint - 1) / everypoint;    /* ? ? ? ? ? */
2173     height = (nr - firstline + everyline - 1) / everyline;      /* ? ? ? ? ? */
2174
2175     for (row = firstline; row < nr; row += everyline) {
2176         df_column[1].datum = rt ? rt[row] : row;
2177
2178         /* Allocate the correct number of entries */
2179         this_iso = iso_alloc(width);
2180
2181         point = this_iso->points;
2182
2183         /* Cycle through data */
2184         for (col = firstpoint; col < nc; col += everypoint, ++point) {
2185             /*{{{  process one point */
2186             int i;
2187
2188             df_column[0].datum = ct ? ct[col] : col;
2189             df_column[2].datum = dmatrix[row][col];
2190
2191             /*{{{  pass through using spec */
2192             for (i = 0; i < use_spec_34; ++i) {
2193                 int column = use_spec[i].column;
2194
2195                 if (df_no_use_specs == 0)
2196                     used[i] = df_column[i].datum;
2197                 else if (use_spec[i].at) {
2198                     struct value a;
2199                     evaluate_inside_using = TRUE;
2200                     evaluate_at(use_spec[i].at, &a);
2201                     evaluate_inside_using = FALSE;
2202                     if (undefined) {
2203                         point->type = UNDEFINED;
2204                         goto skip;      /* continue _outer_ loop */
2205                     }
2206                     used[i] = real(&a);
2207                 } else if (column < 1 || column > df_no_cols) {
2208                     point->type = UNDEFINED;
2209                     goto skip;
2210                 } else
2211                     used[i] = df_column[column - 1].datum;
2212             }
2213             /*}}} */
2214             if (df_no_use_specs != 4)
2215                 used[3] = used[2]; /* 3 parameters of `using` => 4th color-value equals z-value */
2216
2217             point->type = INRANGE;      /* so far */
2218
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);
2222             if (need_palette) {
2223                 COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(point->CRD_COLOR, used[3], point->type, COLOR_AXIS, NOOP, goto skip);
2224             }
2225
2226             /* some of you won't like this, but I say goto is for this */
2227
2228           skip:
2229             ;                   /* ansi requires this */
2230             /*}}} */
2231         }
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++;
2236     }
2237
2238     free_matrix(dmatrix, 0, nr - 1, 0);
2239     if (rt)
2240         free_vector(rt, 0);
2241     if (ct)
2242         free_vector(ct, 0);
2243
2244     /* HBB 20001208: implement 'index' for matrix datafiles */
2245     df_current_index ++;
2246
2247     return (nc);
2248 }
2249
2250 /*}}} */
2251
2252 #else /* REPLACED BY df_readbinary() READING JUST THE FIRST ROW AND SAVING FOR LATER USE. */
2253
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). */
2256
2257 float
2258 df_read_a_float(FILE *fin) {
2259     float fdummy;
2260     if (fread(&fdummy, sizeof(fdummy), 1, fin) != 1) {
2261         if (feof(fin))
2262             int_error(NO_CARET, "Data file is empty");
2263         else
2264             int_error(NO_CARET, read_error_msg);
2265     }
2266     df_swap_bytes_by_endianess((char *)&fdummy, byte_read_order(df_bin_file_endianess), sizeof(fdummy));
2267     return fdummy;
2268 }
2269
2270 void
2271 df_determine_matrix_info(FILE *fin)
2272 {
2273
2274     if (df_binary_file) {
2275
2276         /* Binary matrix format. */
2277         float fdummy;
2278         int nc, nr;
2279         long flength;
2280
2281         /* Read first value for number of columns. */
2282         fdummy = df_read_a_float(fin);
2283         nc = ((size_t) fdummy);
2284         if (nc == 0)
2285             int_error(NO_CARET, "Read grid of zero width");
2286         else if (nc > 1e8)
2287             int_error(NO_CARET, "Read grid width too large"); /* A sanity check on reading absurd numbers. */
2288
2289         /* Read second value for corner_0 x. */
2290         fdummy = df_read_a_float(fin);
2291         df_matrix_corner[0][0] = fdummy;
2292
2293         /* Read nc+1 value for corner_1 x. */
2294         if (nc > 1) {
2295             fseek(fin, (nc-2)*sizeof(float), SEEK_CUR);
2296             fdummy = df_read_a_float(fin);
2297         }
2298         df_matrix_corner[1][0] = fdummy;
2299
2300         /* Read nc+2 value for corner_0 y. */
2301         df_matrix_corner[0][1] = df_read_a_float(fin);
2302
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");
2309
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);
2313
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;
2317
2318         /* Reset counter file pointer. */
2319         fseek(fin, 0L, SEEK_SET);
2320
2321     } else {
2322
2323         /* ASCII matrix format, converted to binary memory format. */
2324         static float *matrix = NULL;
2325         int nr, nc;
2326
2327         /* Insurance against creating a matrix with df_read_matrix()
2328          * and then erroring out through df_add_binary_records().
2329          */
2330         if (matrix)
2331             free(matrix);
2332
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);
2337
2338         /* Keep reading matrices until file is empty. */
2339         while (1) {
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. ***
2344                  */
2345                 df_add_binary_records(1, DF_CURRENT_RECORDS);
2346                 df_bin_record[index].memory_data = (char *) matrix;
2347                 matrix = NULL;
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;
2352             } else
2353                 break;
2354         }
2355
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.
2358          */
2359         df_eof = 0;
2360
2361     }
2362
2363 }
2364 #endif
2365
2366
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
2369  */
2370
2371 /*{{{  void f_dollars(x) */
2372 void
2373 f_dollars(union argument *x)
2374 {
2375     int column = x->v_arg.v.int_val - 1;
2376     /* we checked it was an integer >= 0 at compile time */
2377     struct value a;
2378
2379     if (column == -1) {
2380         push(Gcomplex(&a, (double) df_datum, 0.0));     /* $0 */
2381     } else if (column >= df_no_cols || df_column[column].good != DF_GOOD) {
2382         undefined = TRUE;
2383         push(&(x->v_arg));      /* this okay ? */
2384     } else
2385         push(Gcomplex(&a, df_column[column].datum, 0.0));
2386 }
2387
2388 /*}}} */
2389
2390 /*{{{  void f_column() */
2391 void
2392 f_column(union argument *arg)
2393 {
2394     struct value a;
2395     int column;
2396
2397     (void) arg;                 /* avoid -Wunused warning */
2398     (void) pop(&a);
2399     column = (int) real(&a);
2400
2401     if (!evaluate_inside_using)
2402         int_error(c_token-1, "column() called from invalid context");
2403     
2404     if (column == -2)
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));
2410     else if (column < 1
2411              || column > df_no_cols
2412              || df_column[column - 1].good != DF_GOOD
2413              ) {
2414         undefined = TRUE;
2415         push(&a);               /* any objection to this ? */
2416     } else
2417         push(Gcomplex(&a, df_column[column - 1].datum, 0.0));
2418 }
2419
2420 /* Called from int_error() */
2421 void
2422 df_reset_after_error()
2423 {
2424         evaluate_inside_using = FALSE;
2425 }
2426
2427 #ifdef GP_STRING_VARS
2428 void
2429 f_stringcolumn(union argument *arg)
2430 {
2431     struct value a;
2432     int column;
2433
2434     (void) arg;                 /* avoid -Wunused warning */
2435     (void) pop(&a);
2436     column = (int) real(&a);
2437
2438     if (!evaluate_inside_using)
2439         int_error(c_token-1, "stringcolumn() called from invalid context");
2440
2441     if (column < 1 || column > df_no_cols) {
2442         undefined = TRUE;
2443         push(&a);               /* any objection to this ? */
2444     } else {
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 ));
2448     }
2449 }
2450 #endif
2451
2452 /*{{{  void f_valid() */
2453 void
2454 f_valid(union argument *arg)
2455 {
2456     struct value a;
2457     int column, good;
2458
2459     (void) arg;                 /* avoid -Wunused warning */
2460     (void) pop(&a);
2461     column = (int) magnitude(&a) - 1;
2462     good = column >= 0
2463         && column < df_no_cols
2464         && df_column[column].good == DF_GOOD;
2465     push(Ginteger(&a, good));
2466 }
2467
2468 /*}}} */
2469
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 */
2483 void
2484 f_timecolumn(union argument *arg)
2485 {
2486     struct value a;
2487     int column, spec;
2488     AXIS_INDEX whichaxis;
2489     struct tm tm;
2490     int limit = (df_no_use_specs ? df_no_use_specs : MAXDATACOLS);
2491
2492     (void) arg;                 /* avoid -Wunused warning */
2493     (void) pop(&a);
2494     column = (int) magnitude(&a); /* HBB 20050505: removed - 1*/
2495
2496     if (!evaluate_inside_using)
2497         int_error(c_token-1, "timecolumn() called from invalid context");
2498
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];
2508             break;
2509         }
2510
2511     if (column < 1
2512         || column > df_no_cols
2513         || !df_column[column - 1].position
2514         || !gstrptime(df_column[column - 1].position,
2515                       axis_array[whichaxis].timefmt, &tm)) {
2516         undefined = TRUE;
2517         push(&a);               /* any objection to this ? */
2518     } else
2519         push(Gcomplex(&a, gtimegm(&tm), 0.0));
2520 }
2521
2522 /*}}} */
2523
2524 #if 0                           /* not used */
2525 /*{{{  static int get_time_cols(fmt) */
2526 /* count columns in timefmt */
2527 static int
2528 get_time_cols(char *fmt)
2529 {
2530     int cnt, i;
2531     char *p;
2532
2533     p = fmt;
2534     cnt = 0;
2535     while (isspace((unsigned char) *p))
2536         p++;
2537     if (!strlen(p))
2538         int_error(NO_CARET, "Empty time-data format");
2539     cnt++;
2540     for (i = 0; i < strlen(p) - 1; i++) {
2541         if (isspace((unsigned char) p[i])
2542             && !isspace((unsigned char) p[i + 1]))
2543             cnt++;
2544     }
2545     return (cnt);
2546 }
2547 /*}}} */
2548
2549 /*{{{  static void mod_def_usespec(specno,jump) */
2550 /* modify default use_spec, applies for no user spec and time datacolumns */
2551 static void
2552 mod_def_usespec(
2553     int specno,                 /* which spec in ?:?:? */
2554     int jump)                   /* no of columns in timefmt (time data) */
2555 {
2556     int i;
2557
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;
2561 }
2562
2563 /*}}} */
2564 #endif /* not used */
2565
2566 /*{{{  static int check_missing(s) */
2567 static int
2568 check_missing(char *s)
2569 {
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 */
2575     }
2576     return (0);
2577 }
2578
2579 /*}}} */
2580
2581
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) */
2586 static TBOOLEAN
2587 valid_format(const char *format)
2588 {
2589     int formats_found = 0;
2590
2591     for (;;) {
2592         if (!(format = strchr(format, '%')))    /* look for format spec  */
2593             return (formats_found > 0 && formats_found <= 7);
2594
2595         /* Found a % to check --- scan past option specifiers: */
2596         do {
2597             format++;
2598         } while (strchr("+-#0123456789.", *format));
2599
2600         /* Now at format modifier */
2601         switch (*format) {
2602         case '*':               /* Ignore '*' statements */
2603         case '%':               /* Char   '%' itself     */
2604             format++;
2605             continue;
2606         case 'l':               /* Now we found it !!! */
2607             if (!strchr("fFeEgG", format[1]))   /* looking for a valid format */
2608                 return FALSE;
2609             formats_found++;
2610             format++;
2611             break;
2612         default:
2613             return FALSE;
2614         }
2615     }
2616 }
2617
2618 #ifdef EAM_DATASTRINGS
2619 /*
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
2622  * number.
2623  */
2624 int
2625 expect_string(const char column)
2626 {
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);
2630 }
2631
2632 /*
2633  * Load plot title for key box from the string found earlier by df_readline.
2634  * Called from get_data().
2635  */
2636 void
2637 df_set_key_title(struct curve_points *plot)
2638 {
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';
2648         return;
2649     }
2650 #endif
2651
2652     /* What if there was already a title specified? */
2653     if (plot->title && !plot->title_is_filename)
2654         return;
2655     if (plot->title_is_suppressed)
2656         return;
2657     if (plot->title)
2658         free(plot->title);
2659
2660     plot->title = gp_strdup(df_key_title);
2661     plot->title_no_enhanced = !keyT.enhanced;
2662 }
2663
2664 static void
2665 df_parse_string_field(char *string, char *field)
2666 {
2667     char temp_string[MAX_TOKEN_LENGTH];
2668     temp_string[sizeof(temp_string)-1] = '\0';
2669
2670     if (!field) {
2671         *string = '\0';
2672         return;
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') {
2677         char eor[3];
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';
2681     } else {
2682         strncpy(temp_string,field,sizeof(temp_string)-1);
2683         temp_string[strcspn(temp_string,"\t ")] = '\0';
2684     }
2685     parse_esc(temp_string);
2686     strcpy(string,temp_string);
2687 }
2688
2689 #ifdef EAM_HISTOGRAMS
2690 static void
2691 add_key_entry(char *temp_string, int df_datum)
2692 {
2693     text_label *new_entry = gp_alloc(sizeof(text_label), "key entry");
2694
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;
2701     }
2702
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;
2708 }
2709 #endif
2710
2711 #endif /* EAM_DATASTRINGS */
2712
2713
2714 #ifdef BINARY_DATA_FILE
2715
2716 /* Construct 2D rotation matrix. */
2717 /* R - Matrix to construct. */
2718 /* alpha - Rotation angle. */
2719 /* return - TRUE means a translation is required. */
2720 TBOOLEAN
2721 rotation_matrix_2D(double R[][2], double alpha)
2722 {
2723     static double I[2][2] = {{1, 0},
2724                              {0, 1}};
2725 #define ANGLE_TOLERANCE 0.001
2726     if (fabs(alpha) < ANGLE_TOLERANCE) {
2727         /* Zero angle.  Unity rotation. */
2728         memcpy(R, I, sizeof(I));
2729         return FALSE;
2730     } else {
2731         R[0][0] = cos(alpha);
2732         R[0][1] = -sin(alpha);
2733         R[1][0] = sin(alpha);
2734         R[1][1] = cos(alpha);
2735         return TRUE;
2736     }
2737 }
2738
2739
2740 /* Construct 3D rotation matrix. */
2741 /* P - Matrix to construct. */
2742 /* p - Pointer to perpendicular vector. */
2743 /* return - TRUE means a translation is required. */
2744 TBOOLEAN
2745 rotation_matrix_3D(double P[][3], double *p)
2746 {
2747     static double I[3][3] = {{1, 0, 0},
2748                              {0, 1, 0},
2749                              {0, 0, 1}};
2750     double scale, C1, C2;
2751 #define x p[0]
2752 #define y p[1]
2753 #define z p[2]
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));
2760         return FALSE;
2761     } else {
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;
2770         P[2][1] =      0;
2771         P[2][2] =   z*C2 * scale;
2772         return TRUE;
2773     }
2774 #undef x
2775 #undef y
2776 #undef z
2777 }
2778
2779
2780 df_byte_read_order_type
2781 byte_read_order (df_endianess_type file_endian)
2782 {
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.
2786      */
2787     return df_byte_read_order_map[THIS_COMPILER_ENDIAN][GPMIN(file_endian, DF_ENDIAN_TYPE_LENGTH-1)];
2788 }
2789
2790
2791 void
2792 df_unset_datafile_binary(void)
2793 {
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;
2797 }
2798
2799
2800 void
2801 df_set_datafile_binary()
2802 {
2803     c_token++;
2804     if (END_OF_COMMAND)
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));
2813     } else {
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);
2817     }
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));
2827 }
2828
2829
2830 void
2831 gpbin_filetype_function(void)
2832 {
2833     /* Gnuplot binary. */
2834     df_matrix_file = TRUE;
2835     df_binary_file = TRUE;
2836 }
2837
2838
2839 void
2840 raw_filetype_function(void)
2841 {
2842     /* No information in file, just data. */
2843     df_matrix_file = FALSE;
2844     df_binary_file = TRUE;
2845 }
2846
2847
2848 void
2849 avs_filetype_function(void)
2850 {
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).
2854      */
2855
2856     FILE *fp;
2857     unsigned long M, N;
2858     int read_order = 0;
2859
2860     /* open (header) file */
2861     fp = loadpath_fopen(df_filename, "rb");
2862     if (!fp)
2863         os_error(NO_CARET, "Can't open data file \"%s\"", df_filename);
2864
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);
2868     if (M > 0xFFFF)
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);
2874
2875     fclose(fp);
2876
2877     df_matrix_file = FALSE;
2878     df_binary_file = TRUE;
2879
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;
2883  
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;
2889
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 */
2897
2898     df_no_use_specs = 3;
2899     use_spec[0].column = 1;
2900     use_spec[1].column = 2;
2901     use_spec[2].column = 3;
2902
2903 }
2904
2905 static void
2906 initialize_binary_vars()
2907 {
2908     /* Initialize for the df_readline() routine. */
2909     df_bin_record_count = 0;
2910     df_M_count = df_N_count = df_O_count = 0;
2911
2912     /* Set default binary data widths and skip paratemers. */
2913     df_no_bin_cols = 0;
2914     df_set_skip_before(1, 0);
2915
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.
2919      */
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));
2926     } else {
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);
2930     }
2931 }
2932
2933
2934 static char *too_many_cols_msg = "Too many columns in using specification and implied sampling array";
2935
2936
2937 /* Place a special marker in the using list to derive the x/y/z value
2938  * from the appropriate dimensional counter.
2939  */
2940 void
2941 df_insert_scanned_use_spec(int uspec)
2942 {
2943     /* Place a special marker in the using list to derive the z value
2944      * from the third dimensional counter, which will be zero.
2945      */
2946     if (df_no_use_specs >= MAXDATACOLS)
2947         int_error(NO_CARET, too_many_cols_msg);
2948     else {
2949         int j;
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.
2956          */
2957         use_spec[uspec].at = NULL; /* Not a bad memory pointer overwrite!! */
2958         df_no_use_specs++;
2959     }
2960 }
2961
2962
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.
2965  */
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] = {
2973     {LINES, 1, 1},
2974     {POINTSTYLE, 1, 1},
2975     {IMPULSES, 1, 1},
2976     {LINESPOINTS, 1, 1},
2977     {DOTS, 1, 1},
2978     {XERRORBARS, 2, 1},
2979     {YERRORBARS, 2, 1},
2980     {XYERRORBARS, 3, 1},
2981     {BOXXYERROR, 3, 1},
2982     {BOXES, 1, 1},
2983     {BOXERROR, 3, 1},
2984     {STEPS, 1, 1},
2985     {FSTEPS, 1, 1},
2986     {HISTEPS, 1, 1},
2987     {VECTOR, 2, 2},
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},
2997 #endif
2998 #ifdef EAM_HISTOGRAMS
2999     {HISTOGRAMS, 1, 0},
3000 #endif
3001 #ifdef WITH_IMAGE
3002     {IMAGE, 1, 2},
3003     {RGBIMAGE, 3, 2}
3004 #endif
3005 };
3006
3007
3008 static void
3009 adjust_binary_use_spec()
3010 {
3011
3012     char *nothing_known = "No default columns known for that plot style";
3013     enum PLOT_STYLE plot_style;
3014     unsigned ps_index;
3015     int c_token_copy;
3016
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.
3022      */
3023     df_matrix_binary = (df_matrix_file && df_binary_file);
3024
3025     c_token_copy = c_token;
3026     for (; !END_OF_COMMAND; c_token++)
3027         if (almost_equals(c_token, "w$ith"))
3028             break;
3029     if (!END_OF_COMMAND)
3030         plot_style = get_style();
3031     else
3032         plot_style = LINES;
3033     c_token = c_token_copy;
3034
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)
3038             break;
3039     }
3040     if (ps_index == sizeof(default_style_cols)/sizeof(default_style_cols[0]))
3041         int_error(c_token_copy, nothing_known);
3042
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);
3048     }
3049
3050     /* If nothing has been done to set the using specs, use the default using
3051      * characteristics for the style.
3052      */
3053     if (!df_no_use_specs) {
3054
3055         if (!df_matrix_file) {
3056
3057             int no_cols = default_style_cols[ps_index].excluding_gen_coords;
3058             if (!no_cols)
3059                 int_error(c_token_copy, nothing_known);
3060
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`.
3064              */
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");
3068             } else {
3069                 /* If there aren't generated coordinates, then add the
3070                  * amount of columns that would be generated.
3071                  */
3072                 no_cols += default_style_cols[ps_index].dimen_in_2d;
3073                 if (df_plot_mode == MODE_SPLOT)
3074                     no_cols++;
3075             }
3076
3077             assert(no_cols <= MAXDATACOLS);
3078
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.
3082              */
3083             df_no_use_specs = no_cols;
3084             df_extend_binary_columns(no_cols);
3085
3086         } else {
3087
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
3092              * should go.
3093              */
3094
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;
3102                 else {
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;
3107                 }
3108             } else
3109                 int_error(NO_CARET, "Plot style does not conform to three column data in this graph mode");
3110         }
3111
3112     }
3113
3114     /* Adjust for ASCII matrix format.  The first two "columns" come from indices. */
3115     if (df_matrix_file && !df_binary_file) {
3116     }
3117
3118     if (df_num_bin_records && df_bin_record[0].scan_generate_coord && !df_matrix_file) {
3119
3120         int i;
3121
3122         struct use_spec_s original_use_spec[MAXDATACOLS];
3123         int added_columns = 0;
3124
3125         /* Keep record of the original using specs. */
3126         memcpy(original_use_spec, use_spec, sizeof(use_spec));
3127
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])
3131                 added_columns++;
3132             else
3133                 break;
3134         }
3135         if ((df_no_use_specs + added_columns) >= MAXDATACOLS)
3136             int_error(NO_CARET, too_many_cols_msg);
3137         else {
3138
3139             /* Shift the original columns over by added number of columns, but only
3140              * if not matrix data.
3141              */
3142             memcpy(&use_spec[added_columns], original_use_spec, df_no_use_specs*sizeof(use_spec[0]));
3143
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().
3147              */
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!! */
3151             }
3152
3153             df_no_use_specs += added_columns; /* Do not extend columns for generated coordinates. */
3154         }
3155
3156         if (df_plot_mode == MODE_SPLOT) {
3157
3158             /* For binary data having an implied uniformly sampled grid, treat
3159              * less than three-dimensional data in special ways based upon what
3160              * is being plotted.
3161              */
3162             int k;
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");
3167                     else {
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");
3171                             else {
3172                                 /* Place a special marker in the using list to derive the y value
3173                                  * from the second dimensional counter.
3174                                  */
3175                                 df_insert_scanned_use_spec(1);
3176                             }
3177                         }
3178                         /* Place a special marker in the using list to derive the z value
3179                          * from the third dimensional counter.
3180                          */
3181                         df_insert_scanned_use_spec(2);
3182                     }
3183                 }
3184             }
3185         }
3186     }
3187 }
3188
3189 char *equal_symbol_msg = "Equal ('=') symbol required";
3190
3191
3192 static void
3193 plot_option_binary(TBOOLEAN set_matrix, TBOOLEAN set_default)
3194 {
3195 #define MAX_FILE_EXT_LEN 10
3196     char file_ext[MAX_FILE_EXT_LEN+1];
3197
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;
3208 #endif
3209
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)) {
3212             int i;
3213
3214             /* Above keyword not part of pre-existing binary definition.
3215              * So use general binary. */
3216             if (set_matrix)
3217                 int_error(c_token, matrix_general_binary_conflict_msg);
3218             df_matrix_file = FALSE;
3219
3220             if (almost_equals(c_token, "file$type")) {
3221                 c_token++;
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++;
3226 #else
3227                 /* else equal symbol. */
3228                 if (!equals(c_token, "="))
3229                     int_error(c_token, equal_symbol_msg);
3230                 c_token++;
3231 #endif
3232                 copy_str(file_ext, c_token, MAX_FILE_EXT_LEN);
3233
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;
3237                         break;
3238                     }
3239                 }
3240                 if (i == (sizeof(df_bin_filetype_table)/sizeof(df_bin_filetype_table_struct)))
3241                     int_error(c_token, "Unsupported file type");
3242                 c_token++;
3243
3244             }
3245
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.
3251              *
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.
3261              */
3262             if (!strcasecmp("auto", df_bin_filetype_table[df_bin_filetype].extension) && (df_plot_mode != MODE_QUERY)) {
3263                 int i;
3264                 char *ext_start = strrchr (df_filename, '.');
3265                 if (!ext_start)
3266                     df_bin_filetype = RAW_FILETYPE;
3267                 else {
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;
3272                             break;
3273                         }
3274                     }
3275                     if (i == (sizeof(df_bin_filetype_table)/sizeof(df_bin_filetype_table_struct)))
3276                         int_error(c_token, "Unsupported file type");
3277                 }
3278             }
3279
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();
3283
3284             /* Now, at this point anything that was filled in for "scan" should
3285              * override the "cart" variables.
3286              */
3287             for (i=0; i < df_num_bin_records; i++) {
3288                 int j;
3289                 /* Dimension */
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;
3293                 /* Delta */
3294                 for (j=0; j < 3; j++)
3295                     if (df_bin_record[i].scan_delta[j] != 0.0) {
3296                         int k;
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;
3300                     }
3301                 /* Translation */
3302                 if (df_bin_record[i].scan_trans != DF_TRANSLATE_DEFAULT)
3303                     df_bin_record[i].cart_trans = DF_TRANSLATE_DEFAULT;
3304             }
3305         }
3306
3307
3308     while (!END_OF_COMMAND) {
3309         char origin_and_center_conflict_message[] = "Can specify `origin` or `center`, but not both";
3310
3311         /* look for record */
3312         if (almost_equals(c_token, "rec$ord")) {
3313             if (set_record) { duplication=TRUE; break; }
3314             c_token++;
3315             /* Above keyword not part of pre-existing binary definition.  So use general binary. */
3316             if (set_matrix)
3317                 int_error(c_token, matrix_general_binary_conflict_msg);
3318             df_matrix_file = FALSE;
3319             plot_option_array();
3320             set_record = TRUE;
3321             continue;
3322         }
3323
3324         /* look for array */
3325         if (almost_equals(c_token, "arr$ay")) {
3326             if (set_array) { duplication=TRUE; break; }
3327             c_token++;
3328             /* Above keyword not part of pre-existing binary definition.  So use general binary. */
3329             if (set_matrix)
3330                 int_error(c_token, matrix_general_binary_conflict_msg);
3331             df_matrix_file = FALSE;
3332             plot_option_array();
3333             {int i;
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. */
3336             }
3337             set_array = TRUE;
3338             continue;
3339         }
3340
3341         /* deal with spacing between array points */
3342         if (equals(c_token, "dx") || equals(c_token, "dt")) {
3343             if (set_dx) { duplication=TRUE; break; }
3344             c_token++;
3345             plot_option_multivalued(DF_DELTA, 0);
3346             if (!set_dy) {
3347                 int i;
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];
3350             }
3351             if (!set_dz) {
3352                 int i;
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];
3355             }
3356             set_dx = TRUE;
3357             continue;
3358         }
3359
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");
3364             c_token++;
3365             plot_option_multivalued(DF_DELTA, 1);
3366             if (!set_dz) {
3367                 int i;
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];
3370             }
3371             set_dy = TRUE;
3372             continue;
3373         }
3374
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");
3380             c_token++;
3381             plot_option_multivalued(DF_DELTA, 2);
3382             set_dz = TRUE;
3383             continue;
3384         }
3385
3386         /* deal with direction in which sampling increments */
3387         if (equals(c_token, "flipx")) {
3388             if (set_flipx) { duplication=TRUE; break; }
3389             c_token++;
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)) {
3393 #else
3394             if (!equals(c_token, "=")) {
3395 #endif
3396                 int i;
3397                 for (i = 0; i < df_num_bin_records; i++)
3398                     df_bin_record[i].cart_dir[0] = -1;
3399             } else {
3400                 plot_option_multivalued(DF_FLIP_AXIS, 0);
3401             }
3402             set_flipx = TRUE;
3403             continue;
3404         }
3405
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");
3410             c_token++;
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)) {
3414 #else
3415             if (!equals(c_token, "=")) {
3416 #endif
3417                 int i;
3418                 for (i = 0; i < df_num_bin_records; i++)
3419                     df_bin_record[i].cart_dir[1] = -1;
3420             } else {
3421                 plot_option_multivalued(DF_FLIP_AXIS, 1);
3422             }
3423             set_flipy = TRUE;
3424             continue;
3425         }
3426
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");
3432             c_token++;
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)) {
3436 #else
3437             if (!equals(c_token, "=")) {
3438 #endif
3439                 int i;
3440                 for (i=0; i < df_num_bin_records; i++)
3441                     df_bin_record[i].cart_dir[2] = -1;
3442             } else {
3443                 plot_option_multivalued(DF_FLIP_AXIS, 2);
3444             }
3445             set_flipz = TRUE;
3446             continue;
3447         }
3448
3449         /* Deal with flipping data for individual records. */
3450         if (equals(c_token, "flip")) {
3451             if (set_flip) { duplication=TRUE; break; }
3452             c_token++;
3453             plot_option_multivalued(DF_FLIP, -1);
3454             set_flip = TRUE;
3455             continue;
3456         }
3457
3458         /* Deal with flipping data for individual records. */
3459         if (equals(c_token, "noflip")) {
3460             if (set_noflip) { duplication=TRUE; break; }
3461             c_token++;
3462             plot_option_multivalued(DF_FLIP, 1);
3463             set_noflip = TRUE;
3464             continue;
3465         }
3466
3467         /* Deal with manner in which dimensions are scanned from file. */
3468         if (equals(c_token, "scan")) {
3469             if (set_scan) { duplication=TRUE; break; }
3470             c_token++;
3471             plot_option_multivalued(DF_SCAN, 0);
3472             set_scan = TRUE;
3473             continue;
3474         }
3475
3476         /* Deal with manner in which dimensions are scanned from file. */
3477         if (almost_equals(c_token, "trans$pose")) {
3478             int i;
3479             if (set_scan) { duplication=TRUE; break; }
3480             c_token++;
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));
3483             set_scan = TRUE;
3484             continue;
3485         }
3486
3487         /* deal with origin */
3488         if (almost_equals(c_token, "orig$in")) {
3489             if (set_center)
3490                 int_error(c_token, origin_and_center_conflict_message);
3491             if (set_origin) { duplication=TRUE; break; }
3492             c_token++;
3493             plot_option_multivalued(DF_ORIGIN, df_plot_mode);
3494             set_origin = TRUE;
3495             continue;
3496         }
3497
3498         /* deal with origin */
3499         if (almost_equals(c_token, "cen$ter")) {
3500             if (set_origin)
3501                 int_error(c_token, origin_and_center_conflict_message);
3502             if (set_center) { duplication=TRUE; break; }
3503             c_token++;
3504             plot_option_multivalued(DF_CENTER, df_plot_mode);
3505             set_center = TRUE;
3506             continue;
3507         }
3508
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; }
3512             c_token++;
3513             plot_option_multivalued(DF_ROTATION, 0);
3514             set_rotation = TRUE;
3515             continue;
3516         }
3517
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; }
3523             c_token++;
3524             plot_option_multivalued(DF_PERPENDICULAR, 0);
3525             set_perpendicular = TRUE;
3526             continue;
3527         }
3528
3529         /* deal with number of bytes to skip before record */
3530         if (almost_equals(c_token, "skip")) {
3531             if (set_skip) { duplication=TRUE; break; }
3532             c_token++;
3533             plot_option_multivalued(DF_SKIP, 0);
3534             set_skip = TRUE;
3535             continue;
3536         }
3537
3538         /* deal with byte order */
3539         if (almost_equals(c_token, "end$ian")) {
3540             if (set_endian) { duplication=TRUE; break; }
3541             c_token++;
3542 #if EQUAL_SYMBOL_NOT_REQUIRED
3543             /* Ignore or do not require equal symbol. */
3544             if (equals(c_token, "=")) c_token++;
3545 #else
3546             /* Require equal symbol. */
3547             if (!equals(c_token, "="))
3548                 int_error(c_token, equal_symbol_msg);
3549             c_token++;
3550 #endif
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;
3562             else
3563                 int_error(c_token, "Options are default, swap (swab), little, big, middle (pdp)");
3564 #else
3565             else
3566                 int_error(c_token, "Options are default, swap (swab), little, big");
3567 #endif
3568             c_token++;
3569             set_endian = TRUE;
3570             continue;
3571         }
3572
3573 #if BINARY_HAS_OWN_FORMAT_STRING
3574         /* deal with various types of binary files */
3575         if (almost_equals(c_token, "form$at")) {
3576             if (set_default)
3577                 int_error(c_token, "Sorry - default binary properties not fully implemented");
3578             if (set_format) { duplication=TRUE; break; }
3579             c_token++;
3580             /* Format string not part of pre-existing binary definition.  So use general binary. */
3581             if (set_matrix)
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++;
3587 #else
3588             /* Require equal symbol. */
3589             if (!equals(c_token, "="))
3590                 int_error(c_token, equal_symbol_msg);
3591             c_token++;
3592 #endif
3593             if (isstring(c_token))
3594                 plot_option_binary_format();
3595             else
3596                 int_error(c_token, "Expecting format string");
3597             set_format = TRUE;
3598             continue;
3599         }
3600 #endif
3601
3602         break; /* unknown option */
3603
3604     } /* while (!END_OF_COMMAND) */
3605
3606     if (duplication)
3607         int_error(c_token, "Duplicated or contradicting arguments in datafile options");
3608
3609 }
3610
3611
3612 void
3613 df_add_binary_records(int num_records_to_add, df_records_type records_type)
3614 {
3615     int i;
3616     int new_number;
3617     df_binary_file_record_struct **bin_record;
3618     int *num_bin_records;
3619     int *max_num_bin_records;
3620
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;
3625     } else {
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;
3629     }
3630
3631     new_number = *num_bin_records + num_records_to_add;
3632
3633     if (new_number > *max_num_bin_records) {
3634         *bin_record
3635             = gp_realloc(*bin_record,
3636                          new_number * sizeof(df_binary_file_record_struct),
3637                          "binary file data records");
3638         if (!*bin_record) {
3639             *max_num_bin_records = 0;
3640             int_error(c_token,
3641                       "Error assigning memory for binary file data records");
3642         }
3643         *max_num_bin_records = new_number;
3644     }
3645
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)++;
3651     }
3652 }
3653
3654
3655 static void
3656 clear_binary_records(df_records_type records_type)
3657 {
3658     df_binary_file_record_struct *temp_bin_record;
3659     int *temp_num_bin_records;
3660     int i;
3661
3662     if (records_type == DF_CURRENT_RECORDS) {
3663         temp_bin_record = df_bin_record;
3664         temp_num_bin_records = &df_num_bin_records;
3665     } else {
3666         temp_bin_record = df_bin_record_default;
3667         temp_num_bin_records = &df_num_bin_records_default;
3668     }
3669
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;
3674         }
3675     }
3676     *temp_num_bin_records = 0;
3677 }
3678
3679
3680 #define TUPLE_SEPARATOR_CHAR ":"
3681 #define LEFT_TUPLE_CHAR "("   /* Parser problems with (#,#) considered complex. */
3682 #define RIGHT_TUPLE_CHAR ")"
3683
3684 static void
3685 plot_option_array(void)
3686 {
3687     /* Process command line definition of array. */
3688     if (!END_OF_COMMAND) {
3689         int number_of_records = 0;
3690         char *token_string;
3691         TBOOLEAN expecting_number;
3692         int ival;
3693         int i_dimension = 0;
3694
3695 #if EQUAL_SYMBOL_NOT_REQUIRED
3696         /* Ignore or do not require equal symbol. */
3697         if (equals(c_token, "="))
3698             c_token++;
3699 #else
3700         /* Require equal symbol. */
3701         if (!equals(c_token, "="))
3702             int_error(c_token, equal_symbol_msg);
3703         c_token++;
3704 #endif
3705
3706         /* Set true in case user starts string with a comma. */
3707         expecting_number = TRUE;
3708
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.  */
3713         c_token--;
3714         df_format[0] = '\0';
3715         token_string = df_format;
3716
3717         while (1) {
3718             if (*token_string == '\0') {
3719                 c_token++;
3720                 if (END_OF_COMMAND) break;
3721                 copy_str(df_format, c_token, MAX_LINE_LEN);
3722                 token_string = df_format;
3723             }
3724
3725             if (expecting_number
3726                 && !(isdigit(*token_string)
3727                      || !strncasecmp(token_string, "Inf", 3)))
3728                 break;
3729
3730             if (!strcmp(token_string, TUPLE_SEPARATOR_CHAR)) {
3731                 i_dimension = 0;
3732                 token_string++;
3733                 expecting_number = TRUE;
3734                 continue;
3735             }
3736
3737             if ((*token_string=='x') || (*token_string=='X') ) {
3738                 i_dimension++;
3739                 if (i_dimension >= 2)
3740                     int_error(c_token,
3741                               "Currently do not support sampled array dimensions greater than 2");
3742                 expecting_number = TRUE;
3743                 token_string++;
3744                 continue;
3745             }
3746
3747             if (!expecting_number
3748                 && (isdigit(*token_string)
3749                     || !strncasecmp(token_string, "Inf", 3))) {
3750 #if 0
3751                 /* No dimension symbol required. */
3752                 i_dimension++;
3753                 if (i_dimension >= 2)
3754                     int_error(c_token, "Currently do not support sampled array dimensions greater than 2");
3755 #else
3756                 /* Dimension symbol or comma required. */
3757                 int_error(c_token, "Use '" TUPLE_SEPARATOR_CHAR "' between records or 'x' between dimensions");
3758 #endif
3759             }
3760
3761             if (!isdigit(*token_string) && strncasecmp(token_string, "Inf", 3)) break;
3762
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++;
3767             } else {
3768                 int_error(c_token, "Sorry - Inf keyword not implemented");
3769             }
3770             if (!i_dimension) {
3771                 number_of_records++;
3772                 if (number_of_records > df_num_bin_records)
3773                     df_add_binary_records(1, DF_CURRENT_RECORDS);
3774             }
3775             df_bin_record[df_num_bin_records - 1].cart_dim[i_dimension] = ival;
3776             expecting_number = FALSE;
3777
3778         }
3779
3780         /* Don't allow ending while expecting a number. */
3781         if (expecting_number)
3782             int_error(c_token, "Missing a number");
3783
3784     }
3785
3786 }
3787
3788
3789 /* Evaluate a tuple of up to specified dimension. */
3790 int
3791 token2tuple(double *tuple, int dimension)
3792 {
3793     if (equals(c_token, LEFT_TUPLE_CHAR)) {
3794         TBOOLEAN expecting_number = TRUE;
3795         int N = 0;
3796
3797         c_token++;
3798         while (!END_OF_COMMAND) {
3799             if (expecting_number) {
3800                 struct value a;
3801                 double x;
3802
3803                 x = real(const_express(&a));
3804                 N++;
3805                 if (N <= dimension)
3806                     *tuple++ = x;
3807                 else
3808                     int_error(c_token-1, "More than %d elements", N);
3809                 expecting_number = FALSE;
3810             } else {
3811                 if (equals(c_token, ",")) {
3812                     c_token++;
3813                     expecting_number = TRUE;
3814                 } else if (equals(c_token, RIGHT_TUPLE_CHAR)) {
3815                     c_token++;
3816                     return N;
3817                 } else
3818                     int_error(c_token, "Expecting ',' or '" RIGHT_TUPLE_CHAR "'");
3819             }
3820         }
3821     }
3822
3823     /* Not a tuple */
3824     return 0;
3825 }
3826
3827
3828 /* Determine the 2D rotational matrix from the "rotation" qualifier. */
3829 void
3830 plot_option_multivalued(df_multivalue_type type, int arg)
3831 {
3832     int bin_record_count = 0;
3833     int test_val;
3834 #if EQUAL_SYMBOL_NOT_REQUIRED
3835     /* Ignore or do not require equal symbol. */
3836     if (equals(c_token, "=")) c_token++;
3837 #else
3838     /* Require equal symbol. */
3839     if (!equals(c_token, "="))
3840         int_error(c_token, equal_symbol_msg);
3841     c_token++;
3842 #endif
3843
3844     while (!END_OF_COMMAND) {
3845         double tuple[3];
3846
3847         switch (type) {
3848             case DF_ORIGIN:
3849             case DF_CENTER:
3850             case DF_PERPENDICULAR:
3851                 test_val = token2tuple(tuple, sizeof(tuple)/sizeof(tuple[0]));
3852                 break;
3853             case DF_SCAN:
3854             case DF_FLIP:
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")) );
3858                 break;
3859             default: {
3860                 /* Check if a valid number. */
3861                 struct value a;
3862                 tuple[0] = real(const_express(&a));
3863                 test_val = 1;
3864             }
3865         }
3866
3867         if (test_val) {
3868             char const * cannot_flip_msg
3869                 = "Cannot flip a non-existent dimension";
3870
3871             if (bin_record_count >= df_num_bin_records)
3872                 int_error(c_token, "\
3873 More parameters specified than data records specified");
3874
3875             switch (type) {
3876                 case DF_DELTA:
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");
3883                     break;
3884
3885                 case DF_FLIP_AXIS:
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;
3893                         else
3894                             int_error(c_token-1, "\
3895 Flipping dimension direction must be 1 or 0");
3896                     } else
3897                         int_error(c_token, cannot_flip_msg);
3898                     break;
3899
3900                 case DF_FLIP:
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;
3912                         else
3913                             int_error(c_token, cannot_flip_msg);
3914                     }
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;
3918                         else
3919                             int_error(c_token, cannot_flip_msg);
3920                     }
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;
3924                         else
3925                             int_error(c_token, cannot_flip_msg);
3926                     }
3927                     c_token++;
3928                     break;
3929                 
3930                 case DF_SCAN: {
3931                     /* Set the method in which data is scanned from
3932                      * file.  Compare against a set number of strings.  */
3933                     int i;
3934                 
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]) {
3943                         for (i = 0;
3944                              i < sizeof(df_bin_scan_table_3D)
3945                                  /sizeof(df_bin_scan_table_3D_struct);
3946                              i++)
3947                             if (equals(c_token,
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));
3952                                 break;
3953                             }
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");
3958                     } else {
3959                         for (i = 0;
3960                              i < sizeof(df_bin_scan_table_2D)
3961                                  /sizeof(df_bin_scan_table_2D_struct); i++)
3962                             if (equals(c_token,
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));
3967                                 break;
3968                             }
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");
3973                     }
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));
3978                     c_token++;
3979                     break;
3980                 }
3981
3982                 case DF_SKIP:
3983                     /* Set the number of bytes to skip before reading
3984                      * record. */
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");
3992                     break;
3993
3994                 case DF_ORIGIN:
3995                 case DF_CENTER:
3996                     /* Set the origin or center of the image based upon
3997                      * the plot mode. */
3998                     if (type == DF_ORIGIN)
3999                         df_bin_record[bin_record_count].cart_trans
4000                             = DF_TRANSLATE_VIA_ORIGIN;
4001                     else
4002                         df_bin_record[bin_record_count].cart_trans
4003                             = DF_TRANSLATE_VIA_CENTER;
4004                     if (arg == MODE_PLOT) {
4005                         if (test_val != 2)
4006                             int_error(c_token, "\
4007 Two-dimensional tuple required for 2D plot");
4008                         tuple[2] = 0.0;
4009                     } else if (arg == MODE_SPLOT) {
4010                         if (test_val != 3)
4011                             int_error(c_token, "\
4012 Three-dimensional tuple required for 3D plot");
4013                     } else if (arg == MODE_QUERY) {
4014                         if (test_val != 3)
4015                             int_error(c_token, "\
4016 Three-dimensional tuple required for setting binary parameters");
4017                     } else {
4018                         int_error(c_token, "\
4019 Internal error (datafile.c): Unknown plot mode");
4020                     }
4021                     memcpy(df_bin_record[bin_record_count].cart_cen_or_ori,
4022                            tuple, sizeof(tuple));
4023                     break;
4024                 
4025                 case DF_ROTATION:
4026                     /* Allow user to enter angle in terms of pi or degrees. */
4027                     if (equals(c_token, "pi")) {
4028                         tuple[0] *= M_PI;
4029                         c_token++;
4030                     } else if (almost_equals(c_token, "d$egrees")) {
4031                         tuple[0] *= M_PI/180;
4032                         c_token++;
4033                     }
4034                     /* Construct 2D rotation matrix. */
4035                     df_bin_record[bin_record_count].cart_alpha = tuple[0];
4036                     break;
4037
4038                 case DF_PERPENDICULAR:
4039                     /* Make sure in three dimensional plotting mode before
4040                      * accepting the perpendicular vector for translation. */
4041                     if (test_val != 3)
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]
4046                          + tuple[1]*tuple[1]
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,
4051                            tuple,
4052                            sizeof(tuple));
4053                     break;
4054
4055                 default:
4056                     int_error(NO_CARET, "\
4057 Internal error (datafile.c): Invalid comma separated type");
4058             } /* switch() */
4059         } else {
4060             int_error(c_token, "Invalid numeric or tuple form");
4061         }
4062
4063         if (equals(c_token, TUPLE_SEPARATOR_CHAR)) {
4064             bin_record_count++;
4065             c_token++;
4066         } else
4067             break;
4068
4069     } /* while(!EOC) */
4070
4071     return;
4072 }
4073
4074
4075 /* Set the 'bytes' to skip before column 'col'. */
4076 void
4077 df_set_skip_before(int col, int bytes)
4078 {
4079     assert(col > 0);
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;
4086     }
4087     df_column_bininfo[col-1].skip_bytes = bytes;
4088 }
4089
4090
4091 /* Set the column data type. */
4092 void
4093 df_set_read_type(int col, df_data_type type)
4094 {
4095     assert(col > 0);
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;
4102     }
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;
4106 }
4107
4108
4109 /* Get the column data type. */
4110 df_data_type
4111 df_get_read_type(int col)
4112 {
4113     assert(col > 0);
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);
4117     else
4118         return -1;
4119 }
4120
4121
4122 /* Get the binary column data size. */
4123 int
4124 df_get_read_size(int col)
4125 {
4126     assert(col > 0);
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);
4130     else
4131         return -1;
4132 }
4133
4134
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.  */
4138 void
4139 df_extend_binary_columns(int no_cols)
4140 {
4141     if (no_cols > df_no_bin_cols) {
4142         int i;
4143         df_data_type type;
4144         if (df_no_bin_cols > 0)
4145             type = df_column_bininfo[df_no_bin_cols-1].column.read_type;
4146         else
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);
4151         }
4152         df_no_bin_cols = no_cols;
4153     }
4154 }
4155
4156
4157 /* Determine binary data widths from the `using` (or `binary`) format
4158  * specification. */
4159 void
4160 plot_option_binary_format(void)
4161 {
4162
4163     int prev_read_type = DF_DEFAULT_TYPE; /* Defaults when none specified. */
4164     int i, no_fields = 0;
4165
4166     /* Copy the token for our own analysis. */
4167     copy_str(df_format, c_token, MAX_LINE_LEN);
4168     
4169     for (i=1;
4170          df_format[i] != '\0'
4171              && df_format[i] != '\"'
4172              && df_format[i] != '\''
4173              && i <= MAX_LINE_LEN;
4174          ) {
4175         if (df_format[i] == ' ') {
4176             i++;
4177             continue;
4178         }  /* Ignore spaces. */
4179
4180         if (df_format[i] == '%') {
4181             int ignore, field_repeat, j = 0, k = 0, m = 0, breakout;
4182             
4183             i++;
4184             ignore = (df_format[i] == '*');
4185             if(ignore)
4186                 i++;
4187
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';
4194                 i++;
4195             } else
4196                 field_repeat = 1;
4197
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]));
4202                  j++) {
4203                 for (k = 0, breakout = 0;
4204                      k < df_binary_tables[j].group_length;
4205                      k++) {
4206                     for (m = 0;
4207                          m < df_binary_tables[j].group[k].no_names;
4208                          m++) {
4209                         int strl
4210                             = strlen(df_binary_tables[j].group[k].name[m]);
4211                         
4212                         if (!strncmp(df_format + i,
4213                                      df_binary_tables[j].group[k].name[m],
4214                                      strl)
4215                             && strchr("%\'\" ", df_format[i + strl]) ) {
4216                             i += strl;  /* Advance pointer in array to next text. */
4217                             if (!ignore) {
4218                                 int n;
4219                                 
4220                                 for (n = 0; n < field_repeat; n++) {
4221                                     no_fields++;
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;
4226                                 }
4227                             } else
4228                                 df_column_bininfo[no_fields].skip_bytes
4229                                     += field_repeat
4230                                     * df_binary_tables[j].group[k].type.read_size;
4231                             breakout = 1;
4232                             break;
4233                         }
4234                     }
4235                     if (breakout)
4236                         break;
4237                 }
4238                 if (breakout)
4239                     break;
4240             }
4241
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");
4247             }
4248         } else {
4249             int_error(c_token, "Format specifier must begin with '%'");
4250         }
4251     }
4252
4253     /* Any remaining unspecified fields are assumed to be of the same type
4254      * as the last specified field.
4255      */
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);
4260     }
4261     df_no_bin_cols = no_fields;
4262
4263     c_token++;  /* Advance to next token character. */
4264
4265 }
4266
4267
4268 void
4269 df_show_binary(FILE *fp)
4270 {
4271     int i, num_record;
4272     df_binary_file_record_struct *bin_record;
4273
4274     fprintf(fp, "\
4275 \tDefault binary data file settings (in-file settings may override):\n");
4276
4277     if (!df_num_bin_records_default) {
4278         bin_record = &df_bin_record_reset;
4279         num_record = 1;
4280     } else {
4281         bin_record = df_bin_record_default;
4282         num_record = df_num_bin_records_default;
4283     }
4284
4285     fprintf(fp, "\n\t  File Type: ");
4286     if (df_bin_filetype_default >= 0)
4287         fprintf(fp, "%s",
4288                 df_bin_filetype_table[df_bin_filetype_default].extension);
4289     else
4290         fprintf(fp, "none");
4291     fprintf(fp, "\n\t  File Endianess: %s",
4292             df_endian[df_bin_file_endianess_default]);
4293
4294     for (i = 0; i < num_record; i++) {
4295         int dimension = 1;
4296         
4297         fprintf(fp, "\n\t  Record %d:\n", i);
4298         fprintf(fp, "\t    Dimension: ");
4299         if (bin_record[i].cart_dim[0] < 0)
4300             fprintf(fp, "Inf");
4301         else {
4302             fprintf(fp, "%d", bin_record[i].cart_dim[0]);
4303             if (bin_record[i].cart_dim[1] > 0) {
4304                 dimension = 2;
4305                 fprintf(fp, "x%d", bin_record[i].cart_dim[1]);
4306                 if (bin_record[i].cart_dim[2] > 0) {
4307                     dimension = 3;
4308                     fprintf(fp, "x%d", bin_record[i].cart_dim[2]);
4309                 }
4310             }
4311         }
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) {
4315             int j;
4316             TBOOLEAN no_flip = TRUE;
4317             
4318             fprintf(fp, "\n\t    Direction: ");
4319             if (bin_record[i].cart_dir[0] == -1) {
4320                 fprintf(fp, "flip x");
4321                 no_flip = FALSE;
4322             }
4323             if ((dimension > 1) && (bin_record[i].cart_dir[1] == -1)) {
4324                 fprintf(fp, "%sflip y", (no_flip ? "" : ", "));
4325                 no_flip = FALSE;
4326             }
4327             if ((dimension > 2) && (bin_record[i].cart_dir[2] == -1)) {
4328                 fprintf(fp, "%sflip z", (no_flip ? "" : ", "));
4329                 no_flip = FALSE;
4330             }
4331             if (no_flip)
4332                 fprintf(fp, "all forward");
4333             fprintf(fp, "\n\t    Sample periods: dx=%f",
4334                     bin_record[i].cart_delta[0]);
4335             if (dimension > 1)
4336                 fprintf(fp, ", dy=%f", bin_record[i].cart_delta[1]);
4337             if (dimension > 2)
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]);
4355             for (j = 0;
4356                  j < (sizeof(df_bin_scan_table_3D)
4357                       /sizeof(df_bin_scan_table_3D[0]));
4358                  j++) {
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: ");
4363                     fprintf(fp,
4364                             (bin_record[i].cart_dim[2] ? "%s" : "%2.2s"),
4365                             df_bin_scan_table_3D[j].string);
4366                     break;
4367                 }
4368             }
4369             fprintf(fp, "\n\t    Skip bytes: %d before record",
4370                     bin_record[i].scan_skip[0]);
4371             if (dimension > 1)
4372                 fprintf(fp, ", %d before line", bin_record[i].scan_skip[1]);
4373             if (dimension > 2)
4374                 fprintf(fp, ", %d before plane", bin_record[i].scan_skip[2]);
4375         }
4376         fprintf(fp, "\n");
4377     }
4378 }
4379
4380
4381 void
4382 df_show_datasizes(FILE *fp)
4383 {
4384     int i;
4385
4386     fprintf(fp,"\tThe following binary data sizes are machine dependent:\n\n"
4387             "\t  name (size in bytes)\n\n");
4388     for (i = 0;
4389          i < sizeof(df_binary_details)/sizeof(df_binary_details[0]);
4390          i++) {
4391         int j;
4392         
4393         fprintf(fp,"\t  ");
4394         for (j = 0; j < df_binary_details[i].no_names; j++) {
4395             fprintf(fp,"\"%s\" ",df_binary_details[i].name[j]);
4396         }
4397         fprintf(fp,"(%d)\n",df_binary_details[i].type.read_size);
4398     }
4399
4400     fprintf(fp,"\n\
4401 \tThe following binary data sizes attempt to be machine independent:\n\n\
4402 \t  name (size in bytes)\n\n");
4403     for (i = 0;
4404          i < sizeof(df_binary_details_independent)
4405              /sizeof(df_binary_details_independent[0]);
4406          i++) {
4407         int j;
4408         
4409         fprintf(fp,"\t  ");
4410         for (j = 0; j < df_binary_details_independent[i].no_names; j++) {
4411             fprintf(fp,"\"%s\" ",df_binary_details_independent[i].name[j]);
4412         }
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");
4416         fputc('\n', fp);
4417     }
4418 }
4419
4420
4421 void
4422 df_show_filetypes(FILE *fp)
4423 {
4424     int i;
4425     
4426     fprintf(fp,"\tThe following binary file types are understood by gnuplot:\n\n");
4427     for (i = 0;
4428          i < sizeof(df_bin_filetype_table)
4429              /sizeof(df_bin_filetype_table_struct);
4430          i++) {
4431         fprintf(fp, "\t  %s\n", df_bin_filetype_table[i].extension);
4432     }
4433 }
4434
4435
4436 void
4437 df_swap_bytes_by_endianess(char *data, int read_order, int read_size)
4438 {
4439     if ((read_order == DF_3210) 
4440 #if SUPPORT_MIDDLE_ENDIAN
4441         || (read_order == DF_2301)
4442 #endif
4443         ) {
4444         int j = 0;
4445         int k = read_size - 1;
4446         
4447         for (; j < k; j++, k--) {
4448             char temp = data[j];
4449             
4450             data[j] = data[k];
4451             data[k] = temp;
4452         }
4453     }
4454     
4455 #if SUPPORT_MIDDLE_ENDIAN
4456     if ((read_order == DF_1032) || (read_order == DF_2301)) {
4457         int j= read_size - 1;
4458         
4459         for (; j > 0; j -= 2) {
4460             char temp = data[j-1];
4461             
4462             data[j-1] = data[j];
4463             data[j] = temp;
4464         }
4465     }
4466 #endif
4467 }
4468
4469
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
4475  */
4476
4477 int
4478 df_readbinary(double v[], int max)
4479 {
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;
4493
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;
4499
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);
4504
4505     /* catch attempt to read past EOF on mixed-input */
4506     if (df_eof)
4507         return DF_EOF;
4508
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;
4515     }
4516
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) {
4522         int i;
4523         TBOOLEAN D2, D3;
4524         df_binary_file_record_struct *this_record
4525             = df_bin_record + df_bin_record_count;
4526
4527         scan_size[0] = scan_size[1] = scan_size[2] = 0;
4528
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;
4532
4533         if (df_matrix_file) {
4534             /* Dimensions */
4535             scan_size[0] = this_record->scan_dim[0];
4536             scan_size[1] = this_record->scan_dim[1];
4537
4538             if (scan_size[0] == 0)
4539                 int_error(NO_CARET, "Scan size of matrix is zero");
4540
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++) {
4544                 int j;
4545                 
4546                 for (j = 0; j < 2; j++) {
4547                     R[i][j] *= this_record->cart_dir[i];
4548                 }
4549             }
4550             /* o */
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];
4554                 } else {
4555                     /* Default is translate by center. */
4556                     if (i < 2)
4557                         o[i] = (df_matrix_corner[1][i]
4558                                 + df_matrix_corner[0][i]) / 2;
4559                     else
4560                         o[i] = 0;
4561                 }
4562             }
4563             /* c */
4564             for (i = 0; i < 3; i++) {
4565                 if (this_record->cart_trans == DF_TRANSLATE_VIA_ORIGIN) {
4566                     if (i < 2)
4567                         c[i] = df_matrix_corner[0][i];
4568                     else
4569                         c[i] = 0;
4570                 } else {
4571                     if (i < 2)
4572                         c[i] = (df_matrix_corner[1][i]
4573                                 + df_matrix_corner[0][i]) / 2;
4574                     else
4575                         c[i] = 0;
4576                 }
4577             }
4578
4579             first_matrix_row_col_count = 0;
4580         } else { /* general binary */
4581             for (i = 0; i < 3; i++) {
4582                 int map;
4583                 
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];
4589                     
4590                 }
4591                 /* Dimensions */
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];
4595                 else
4596                     scan_size[map]
4597                         = this_record->scan_dim[map];
4598                 /* Sample periods */
4599                 if (this_record->cart_delta[i])
4600                     delta[map] = this_record->cart_delta[i];
4601                 else
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];
4606                 /* o */
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;
4614                 else
4615                     o[i] = 0;
4616                 /* c */
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)
4620                     ) {
4621                     if ((scan_size[map] > 0) && (delta[map] < 0))
4622                         c[i] = (scan_size[map] - 1)*delta[map];
4623                     else
4624                         c[i] = 0;
4625                 } else {
4626                     if (scan_size[map] > 0)
4627                         c[i] = (scan_size[map] - 1)*(delta[map]/2);
4628                     else
4629                         c[i] = 0;
4630                 }
4631             }
4632         }
4633
4634         /* Check if c and o are the same. */
4635         for (i = 0; i < 3; i++)
4636             translation_required = translation_required
4637                                    || (c[i] != o[i]);
4638
4639         /* Should data come from memory? */
4640         memory_data = this_record->memory_data;
4641
4642         /* byte read order */
4643         read_order = byte_read_order(df_bin_file_endianess);
4644
4645         /* amount to skip before record */
4646         record_skip = this_record->scan_skip[0];
4647
4648         end_of_scan_line = FALSE;
4649         end_of_block = FALSE;
4650         point_count = -1;
4651         line_count = 0;
4652         df_current_index = df_bin_record_count;
4653     }
4654
4655     while (!df_eof) {
4656         /*{{{  process line */
4657         int line_okay = 1;
4658         int output = 0;             /* how many numbers written to v[] */
4659         int i, fread_ret = 0;
4660         int m_value, n_value, o_value;
4661         union io_val {
4662             char ch;
4663             unsigned char uc;
4664             short sh;
4665             unsigned short us;
4666             int in;
4667             unsigned int ui;
4668             long lo;
4669             unsigned long ul;
4670             float fl;
4671             double db;
4672         } io_val;
4673
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.
4677          */
4678
4679         /* Handle end of line or end of block on previous read. */
4680         if (end_of_scan_line) {
4681             end_of_scan_line = FALSE;
4682             point_count = -1;
4683             line_count++;
4684             return DF_FIRST_BLANK;
4685         }
4686         if (end_of_block) {
4687             end_of_block = FALSE;
4688             line_count = 0;
4689             return DF_SECOND_BLANK;
4690         }
4691
4692         /* Possibly skip bytes before starting to read record. */
4693         while (record_skip) {
4694             if (memory_data) {
4695                 memory_data++;
4696             } else if ((fread_ret = fread(&io_val.ch,
4697                                           sizeof(io_val.ch),
4698                                           1, data_fp))
4699                        != 1) {
4700                 if (feof(data_fp)) {
4701                     df_eof = 1;
4702                     return DF_EOF;
4703                 } else
4704                     int_error(NO_CARET, read_error_msg);
4705             }
4706             record_skip--;
4707         } /* while(record_skip) */
4708
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;
4714
4715             if (skip_bytes) {
4716                 if (memory_data) {
4717                     memory_data += skip_bytes;
4718                 } else if ((fread_ret = fread(&io_val.ch, sizeof(io_val.ch),
4719                                               skip_bytes, data_fp))
4720                            != skip_bytes) {
4721                     if (feof(data_fp)) {
4722                         df_eof = 1;
4723                         return DF_EOF;
4724                     } else
4725                         int_error(NO_CARET, read_error_msg);
4726                 }
4727             }
4728
4729             /* Last entry only has skip bytes, no data. */
4730             if (i == df_no_bin_cols)
4731                 break;
4732
4733             /* Read in a "column", i.e., a binary value of various types. */
4734             if (memory_data) {
4735                 for (fread_ret = 0;
4736                      fread_ret < df_column_bininfo[i].column.read_size;
4737                      fread_ret++)
4738                     (&io_val.ch)[fread_ret] = *memory_data++;
4739             } else {
4740                 fread_ret = fread(&io_val.ch,
4741                                   df_column_bininfo[i].column.read_size,
4742                                   1, data_fp);
4743                 if (fread_ret != 1) {
4744                     df_eof = 1;
4745                     return DF_EOF;
4746                 }
4747             }
4748
4749             df_swap_bytes_by_endianess(&io_val.ch, read_order,
4750                                        df_column_bininfo[i].column.read_size);
4751
4752             switch (df_column_bininfo[i].column.read_type) {
4753                 case DF_CHAR:
4754                     df_column[i].datum = io_val.ch;
4755                     break;
4756                 case DF_UCHAR:
4757                     df_column[i].datum = io_val.uc;
4758                     break;
4759                 case DF_SHORT:
4760                     df_column[i].datum = io_val.sh;
4761                     break;
4762                 case DF_USHORT:
4763                     df_column[i].datum = io_val.us;
4764                     break;
4765                 case DF_INT:
4766                     df_column[i].datum = io_val.in;
4767                     break;
4768                 case DF_UINT:
4769                     df_column[i].datum = io_val.ui;
4770                     break;
4771                 case DF_LONG:
4772                     df_column[i].datum = io_val.lo;
4773                     break;
4774                 case DF_ULONG:
4775                     df_column[i].datum = io_val.ul;
4776                     break;
4777                 case DF_FLOAT:
4778                     df_column[i].datum = io_val.fl;
4779                     break;
4780                 case DF_DOUBLE:
4781                     df_column[i].datum = io_val.db;
4782                     break;
4783                 default:
4784                     int_error(NO_CARET, "Binary data type unknown");
4785             }
4786
4787             df_column[i].good = DF_GOOD;
4788             df_column[i].position = NULL;   /* cant get a time */
4789
4790             /* Matrix file data is a special case. After reading
4791              * in just one binary value, stop then decide on what
4792              * to do with it. */
4793             if (df_matrix_file)
4794                 break;
4795
4796         } /* for(i) */
4797
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;
4804                     continue;
4805                 }
4806
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;
4822                     }
4823                     continue;
4824                 }
4825
4826             }
4827
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.  */
4833             {
4834                 int j;
4835
4836                 df_datum = df_column[i].datum;
4837
4838                 /* Fill backward so that current read value is not
4839                  * overwritten. */
4840                 for (j = df_no_bin_cols-1; j >= 0; j--) {
4841                     if (j == 0)
4842                         df_column[j].datum
4843                             = df_matrix_binary
4844                             ? scanned_matrix_row[df_M_count]
4845                             : df_M_count;
4846                     else if (j == 1)
4847                         df_column[j].datum
4848                             = df_matrix_binary
4849                             ? first_matrix_column
4850                             : df_N_count;
4851                     else
4852                         df_column[j].datum = df_column[i].datum;
4853                     df_column[j].good = DF_GOOD;
4854                     df_column[j].position = NULL;
4855                 }
4856             }
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)) {
4861                     if (i != 0) 
4862                         int_error(NO_CARET, "\
4863 Last point in the binary file did not match the specified `using` columns");
4864                     df_eof = 1;
4865                     return DF_EOF;
4866                 } else {
4867                     int_error(NO_CARET, read_error_msg);
4868                 }
4869             }
4870         }
4871
4872         m_value = df_M_count;
4873         n_value = df_N_count;
4874         o_value = df_O_count;
4875         df_M_count++;
4876         if ((scan_size[0] > 0) && (df_M_count >= scan_size[0])) {
4877             /* This is a new "line". */
4878             df_M_count = 0;
4879             df_N_count++;
4880             end_of_scan_line = TRUE;
4881             if ((scan_size[1] >= 0) && (df_N_count >= scan_size[1])) {
4882                 /* This is a "block". */
4883                 df_N_count = 0;
4884                 df_O_count++;
4885                 if ((scan_size[2] >= 0) && (df_O_count >= scan_size[2])) {
4886                     df_O_count = 0;
4887                     end_of_block = TRUE;
4888                     if (++df_bin_record_count >= df_num_bin_records) {
4889                         df_eof = 1;
4890                     }
4891                 }
4892             }
4893         }
4894
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 */
4898
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)
4902             continue;
4903         /*}}} */
4904
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)
4910             continue;
4911
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)
4917             continue;
4918         /*}}} */
4919
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;
4924
4925         /*{{{  copy column[] to v[] via use[] */
4926         {
4927             int limit = (df_no_use_specs ? df_no_use_specs : MAXDATACOLS);
4928                 
4929             if (limit > max)
4930                 limit = max;
4931
4932             for (output = 0; output < limit; ++output) {
4933                 int column = use_spec[output].column;
4934
4935                 /* if there was no using spec, column is output+1 and at=NULL */
4936                 if (use_spec[output].at) {
4937                     struct value a;
4938                         
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;
4943                     if (undefined)
4944                         /* store undefined point in plot */
4945                         return DF_UNDEFINED; 
4946
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)) {
4967                     struct tm tm;
4968                         
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,
4974                                       &tm)) {
4975                         /* line bad only if user explicitly asked
4976                          * for this column */
4977                         if (df_no_use_specs)
4978                             line_okay = 0;
4979                         
4980                         /* return or ignore line depending on line_okay */
4981                         break;
4982                     }
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;
4987                         
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))
4996                     return DF_MISSING;
4997                 else {
4998                     /* line bad only if user explicitly asked
4999                      * for this column */
5000                     if (df_no_use_specs)
5001                         line_okay = 0;
5002                     break;  /* return or ignore depending on line_okay */
5003                 }
5004             }
5005
5006             /* Linear translation. */
5007             if (translation_required) {
5008                 double x, y, z;
5009
5010                 x = v[0] - c[0];
5011                 y = v[1] - c[1];
5012
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) {
5016                     x = v[0];
5017                     y = v[1];
5018                     z = v[2] - c[2];
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;
5022                 }
5023
5024                 v[0] += o[0];
5025                 v[1] += o[1];
5026                 if (df_plot_mode == MODE_SPLOT)
5027                     v[2] += o[2];
5028             }
5029
5030         }
5031         /*}}} */
5032
5033         if (!line_okay)
5034             continue;
5035
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
5040                || output == max);
5041
5042         return output;
5043
5044     }
5045     /*}}} */
5046
5047     df_eof = 1;
5048     return DF_EOF;
5049
5050 }
5051
5052 void
5053 df_set_plot_mode(int mode)
5054 {
5055     df_plot_mode = mode;
5056 }
5057 #endif /* BINARY_DATA_FILE */
5058