Annotation of OpenXM_contrib/gnuplot/datafile.c, Revision 1.1
1.1 ! maekawa 1: #ifndef lint
! 2: static char *RCSid = "$Id: datafile.c,v 1.42 1998/04/14 00:15:17 drd Exp $";
! 3: #endif
! 4:
! 5: /* GNUPLOT - datafile.c */
! 6:
! 7: /*[
! 8: * Copyright 1986 - 1993, 1998 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: * use a global array df_timecol[] - cleared by df_open, then
! 70: * columns needing time set by client.
! 71: *
! 72: * Now that df_2dbinary() and df_3dbinary() are here, I am seriously
! 73: * tempted to move get_data() and get_3ddata() in here too
! 74: *
! 75: * public variables declared in this file.
! 76: * int df_no_use_specs - number of columns specified with 'using'
! 77: * int df_line_number - for error reporting
! 78: * int df_datum - increases with each data point
! 79: * TBOOLEAN df_binary - it's a binary file
! 80: * [ might change this to return value from df_open() ]
! 81: * int df_eof - end of file
! 82: * int df_timecol[] - client controls which cols read as time
! 83: *
! 84: * functions
! 85: * int df_open(int max_using)
! 86: * parses thru / index / using on command line
! 87: * max_using is max no of 'using' columns allowed
! 88: * returns number of 'using' cols specified, or -1 on error (?)
! 89: *
! 90: * int df_readline(double vector[], int max)
! 91: * reads a line, does all the 'index' and 'using' manipulation
! 92: * deposits values into vector[]
! 93: * returns
! 94: * number of columns parsed [0=not blank line, but no valid data],
! 95: * DF_EOF for EOF
! 96: * DF_UNDEFINED - undefined result during eval of extended using spec
! 97: * DF_FIRST_BLANK for first consecutive blank line
! 98: * DF_SECOND_BLANK for second consecutive blank line
! 99: * will return FIRST before SECOND
! 100: *
! 101: * if a using spec was given, lines not fulfilling spec are ignored.
! 102: * we will always return exactly the number of items specified
! 103: *
! 104: * if no spec given, we return number of consecutive columns we parsed.
! 105: *
! 106: * if we are processing indexes, seperated by 'n' blank lines,
! 107: * we will return n-1 blank lines before noticing the index change
! 108: *
! 109: * void df_close()
! 110: * closes a currently open file.
! 111: *
! 112: * void f_dollars(x)
! 113: * void f_column() actions for expressions using $i, column(j), etc
! 114: * void f_valid()
! 115: *
! 116: *
! 117: * line parsing slightly differently from previous versions of gnuplot...
! 118: * given a line containing fewer columns than asked for, gnuplot used to make
! 119: * up values... I say that if I have explicitly said 'using 1:2:3', then if
! 120: * column 3 doesn't exist, I dont want this point...
! 121: *
! 122: * a column number of 0 means generate a value... as before, this value
! 123: * is useful in 2d as an x value, and is reset at blank lines.
! 124: * a column number of -1 means the (data) line number (not the file line
! 125: * number). splot 'file' using 1 is equivalent to
! 126: * splot 'file' using 0:-1:1
! 127: * column number -2 is the index. It was put in to kludge multi-branch
! 128: * fitting.
! 129: *
! 130: * 20/5/95 : accept 1.23d4 in place of e (but not in scanf string)
! 131: * : autoextend data line buffer and MAX_COLS
! 132: *
! 133: * 11/8/96 : add 'columns' -1 for suggested y value, and -2 for
! 134: * current index.
! 135: * using 1:-1:-2 and column(-1) are supported.
! 136: * $-1 and $-2 are not yet supported, because of the
! 137: * way the parser works
! 138: *
! 139: */
! 140: /*}}} */
! 141:
! 142: #include "plot.h"
! 143: #include "fnproto.h" /* check prototypes against our defns */
! 144: #include "binary.h"
! 145: #include "setshow.h"
! 146:
! 147: /* if you change this, change the scanf in readline */
! 148: #define NCOL 7 /* max using specs */
! 149:
! 150: /*{{{ static fns */
! 151: #if 0 /* not used */
! 152: static int get_time_cols __PROTO((char *fmt));
! 153: static void mod_def_usespec __PROTO((int specno, int jump));
! 154: #endif
! 155: static int check_missing __PROTO((char *s));
! 156: static char *df_gets __PROTO((void));
! 157: static int df_tokenise __PROTO((char *s));
! 158: static float **df_read_matrix __PROTO((int *rows, int *columns));
! 159: /*}}} */
! 160:
! 161: /*{{{ variables */
! 162: struct use_spec_s {
! 163: int column;
! 164: struct at_type *at;
! 165: };
! 166:
! 167: /* public variables client might access */
! 168:
! 169: int df_no_use_specs; /* how many using columns were specified */
! 170: int df_line_number;
! 171: int df_datum; /* suggested x value if none given */
! 172: TBOOLEAN df_matrix = FALSE; /* is this a matrix splot */
! 173: int df_eof = 0;
! 174: int df_timecol[NCOL];
! 175: TBOOLEAN df_binary = FALSE; /* this is a binary file */
! 176:
! 177: /* private variables */
! 178:
! 179: /* in order to allow arbitrary data line length, we need to use the heap
! 180: * might consider free-ing it in df_close, especially for small systems
! 181: */
! 182: static char *line = NULL;
! 183: static int max_line_len = 0;
! 184:
! 185: static FILE *data_fp = NULL;
! 186: static TBOOLEAN pipe_open = FALSE;
! 187: static TBOOLEAN mixed_data_fp = FALSE;
! 188:
! 189: #ifndef MAXINT /* should there be one already defined ? */
! 190: # ifdef INT_MAX /* in limits.h ? */
! 191: # define MAXINT INT_MAX
! 192: # else
! 193: # define MAXINT ((~0)>>1)
! 194: # endif
! 195: #endif
! 196:
! 197: /* stuff for implementing index */
! 198: static int blank_count = 0; /* how many blank lines recently */
! 199: static int df_lower_index = 0; /* first mesh required */
! 200: static int df_upper_index = MAXINT;
! 201: static int df_index_step = 1; /* 'every' for indices */
! 202: static int df_current_index; /* current mesh */
! 203:
! 204: /* stuff for every point:line */
! 205: static int everypoint = 1;
! 206: static int firstpoint = 0;
! 207: static int lastpoint = MAXINT;
! 208: static int everyline = 1;
! 209: static int firstline = 0;
! 210: static int lastline = MAXINT;
! 211: static int point_count = -1; /* point counter - preincrement and test 0 */
! 212: static int line_count = 0; /* line counter */
! 213:
! 214: /* parsing stuff */
! 215: static struct use_spec_s use_spec[NCOL];
! 216: static char df_format[MAX_LINE_LEN + 1];
! 217:
! 218: /* rather than three arrays which all grow dynamically, make one
! 219: * dynamic array of this structure
! 220: */
! 221:
! 222: typedef struct df_column_struct {
! 223: double datum;
! 224: enum {
! 225: DF_MISSING, DF_BAD, DF_GOOD
! 226: } good;
! 227: char *position;
! 228: } df_column_struct;
! 229:
! 230: static df_column_struct *df_column = NULL; /* we'll allocate space as needed */
! 231: static int df_max_cols = 0; /* space allocated */
! 232: static int df_no_cols; /* cols read */
! 233: static int fast_columns; /* corey@cac optimization */
! 234:
! 235: /* external variables we need */
! 236:
! 237: extern int c_token, num_tokens;
! 238: extern char timefmt[]; /* I would rather not need this, but ... */
! 239: /* columns needing timefmt are passed in df_timecol[] after df_open */
! 240:
! 241: /* jev -- for passing data thru user-defined function */
! 242: extern struct udft_entry ydata_func;
! 243: extern struct udft_entry *dummy_func;
! 244: extern char dummy_var[MAX_NUM_VAR][MAX_ID_LEN + 1];
! 245: extern char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN + 1];
! 246:
! 247: extern double min_array[], max_array[];
! 248: /*}}} */
! 249:
! 250:
! 251: /*{{{ static char *df_gets() */
! 252: static char *df_gets()
! 253: {
! 254: int len = 0;
! 255:
! 256: if (!fgets(line, max_line_len, data_fp))
! 257: return NULL;
! 258:
! 259: if (mixed_data_fp)
! 260: ++inline_num;
! 261:
! 262: for (;;) {
! 263: len += strlen(line + len);
! 264:
! 265: if (len > 0 && line[len - 1] == '\n') {
! 266: /* we have read an entire text-file line.
! 267: * Strip the trailing linefeed and return
! 268: */
! 269: line[len - 1] = 0;
! 270: return line;
! 271: }
! 272: /* buffer we provided may not be full - dont grab extra
! 273: * memory un-necessarily. This may trap a problem with last
! 274: * line in file not being properly terminated - each time
! 275: * through a replot loop, it was doubling buffer size
! 276: */
! 277:
! 278: if ((max_line_len - len) < 32)
! 279: line = gp_realloc(line, max_line_len *= 2, "datafile line buffer");
! 280:
! 281: if (!fgets(line + len, max_line_len - len, data_fp))
! 282: return line; /* unexpected end of file, but we have something to do */
! 283: }
! 284:
! 285: /* NOTREACHED */
! 286: return NULL;
! 287: }
! 288: /*}}} */
! 289:
! 290: /*{{{ static int df_tokenise(s) */
! 291: static int df_tokenise(s)
! 292: char *s;
! 293: {
! 294: /* implement our own sscanf that takes 'missing' into account,
! 295: * and can understand fortran quad format
! 296: */
! 297:
! 298: df_no_cols = 0;
! 299:
! 300: while (*s) {
! 301:
! 302: /* check store - double max cols or add 20, whichever is greater */
! 303: if (df_max_cols <= df_no_cols)
! 304: df_column = (df_column_struct *) gp_realloc(df_column, (df_max_cols += (df_max_cols < 20 ? 20 : df_max_cols)) * sizeof(df_column_struct), "datafile column");
! 305:
! 306: /* have always skipped spaces at this point */
! 307: df_column[df_no_cols].position = s;
! 308:
! 309: if (check_missing(s))
! 310: df_column[df_no_cols].good = DF_MISSING;
! 311: else {
! 312: #ifdef OSK
! 313: /* apparently %n does not work. This implementation
! 314: * is just as good as the non-OSK one, but close
! 315: * to a release (at last) we make it os-9 specific
! 316: */
! 317: int count;
! 318: char *p = strpbrk(s, "dqDQ");
! 319: if (p != NULL)
! 320: *p = 'e';
! 321:
! 322: count = sscanf(s, "%lf", &df_column[df_no_cols].datum);
! 323: #else
! 324: /* cannot trust strtod - eg strtod("-",&p) */
! 325: int used;
! 326: int count;
! 327: int dfncp1 = df_no_cols + 1;
! 328:
! 329: /*
! 330: * optimizations by Corey Satten, corey@cac.washington.edu
! 331: */
! 332: if (fast_columns == 0 ||
! 333: df_no_use_specs > 0 && (use_spec[0].column == dfncp1 ||
! 334: df_no_use_specs > 1 && (use_spec[1].column == dfncp1 ||
! 335: df_no_use_specs > 2 && (use_spec[2].column == dfncp1 ||
! 336: df_no_use_specs > 3 && (use_spec[3].column == dfncp1 ||
! 337: df_no_use_specs > 4 && (use_spec[4].column == dfncp1 ||
! 338: df_no_use_specs > 5))))) ||
! 339: df_no_use_specs == 0) {
! 340:
! 341: #ifndef NO_FORTRAN_NUMS
! 342: count = sscanf(s, "%lf%n", &df_column[df_no_cols].datum, &used);
! 343: #else
! 344: while (isspace(*s))
! 345: ++s;
! 346: count = *s ? 1 : 0;
! 347: df_column[df_no_cols].datum = atof(s);
! 348: #endif /* NO_FORTRAN_NUMS */
! 349: } else {
! 350: /* skip any space at start of column */
! 351: while (isspace((int)*s))
! 352: ++s;
! 353: count = *s ? 1 : 0;
! 354: /* skip chars to end of column */
! 355: for (used = 0; !isspace((int)*s) && (*s != NUL); ++used, ++s)
! 356: ;
! 357: }
! 358:
! 359: /* it might be a fortran double or quad precision.
! 360: * 'used' is only safe if count is 1
! 361: */
! 362:
! 363: #ifndef NO_FORTRAN_NUMS
! 364: if (count == 1 &&
! 365: (s[used] == 'd' || s[used] == 'D' ||
! 366: s[used] == 'q' || s[used] == 'Q')) {
! 367: /* might be fortran double */
! 368: s[used] = 'e';
! 369: /* and try again */
! 370: count = sscanf(s, "%lf", &df_column[df_no_cols].datum);
! 371: }
! 372: #endif /* NO_FORTRAN_NUMS */
! 373: #endif /* OSK */
! 374: df_column[df_no_cols].good = count == 1 ? DF_GOOD : DF_BAD;
! 375: }
! 376:
! 377: ++df_no_cols;
! 378: /*{{{ skip chars to end of column */
! 379: while ((!isspace((int)*s)) && (*s != '\0'))
! 380: ++s;
! 381: /*}}} */
! 382: /*{{{ skip spaces to start of next column */
! 383: while (isspace((int)*s))
! 384: ++s;
! 385: /*}}} */
! 386: }
! 387:
! 388: return df_no_cols;
! 389: }
! 390: /*}}} */
! 391:
! 392: /*{{{ static float **df_read_matrix() */
! 393: /* reads a matrix from a text file
! 394: * stores in same storage format as fread_matrix
! 395: */
! 396:
! 397: static float **df_read_matrix(rows, cols)
! 398: int *rows, *cols;
! 399: {
! 400: int max_rows = 0;
! 401: int c;
! 402: float **rmatrix = NULL;
! 403:
! 404: char *s;
! 405:
! 406: *rows = 0;
! 407: *cols = 0;
! 408:
! 409: for (;;) {
! 410: if (!(s = df_gets())) {
! 411: df_eof = 1;
! 412: return rmatrix; /* NULL if we have not read anything yet */
! 413: }
! 414: while (isspace((int)*s))
! 415: ++s;
! 416:
! 417: if (!*s || is_comment(*s)) {
! 418: if (rmatrix)
! 419: return rmatrix;
! 420: else
! 421: continue;
! 422: }
! 423: if (mixed_data_fp && is_EOF(*s)) {
! 424: df_eof = 1;
! 425: return rmatrix;
! 426: }
! 427: c = df_tokenise(s);
! 428:
! 429: if (!c)
! 430: return rmatrix;
! 431:
! 432: if (*cols && c != *cols) {
! 433: /* its not regular */
! 434: int_error("Matrix does not represent a grid", NO_CARET);
! 435: }
! 436: *cols = c;
! 437:
! 438: if (*rows >= max_rows) {
! 439: rmatrix = gp_realloc(rmatrix, (max_rows += 10) * sizeof(float *), "df_matrix");
! 440: }
! 441: /* allocate a row and store data */
! 442: {
! 443: int i;
! 444: float *row = rmatrix[*rows] = (float *) gp_alloc(c * sizeof(float), "df_matrix row");
! 445:
! 446: for (i = 0; i < c; ++i) {
! 447: if (df_column[i].good != DF_GOOD)
! 448: int_error("Bad number in matrix", NO_CARET);
! 449:
! 450: row[i] = (float) df_column[i].datum;
! 451: }
! 452:
! 453: ++*rows;
! 454: }
! 455: }
! 456: }
! 457:
! 458: /*}}} */
! 459:
! 460:
! 461: /*{{{ int df_open(max_using) */
! 462: int df_open(max_using)
! 463: int max_using;
! 464:
! 465: /* open file, parsing using/thru/index stuff
! 466: * return number of using specs [well, we have to return something !]
! 467: */
! 468:
! 469: {
! 470: static char filename[MAX_LINE_LEN + 1] = "";
! 471: int i;
! 472: int name_token;
! 473:
! 474: fast_columns = 1; /* corey@cac */
! 475:
! 476: /*{{{ close file if necessary */
! 477: if (data_fp)
! 478: df_close();
! 479: /*}}} */
! 480:
! 481: /*{{{ initialise static variables */
! 482: df_format[0] = NUL; /* no format string */
! 483:
! 484: df_no_use_specs = 0;
! 485:
! 486: for (i = 0; i < NCOL; ++i) {
! 487: use_spec[i].column = i + 1; /* default column */
! 488: use_spec[i].at = NULL; /* no expression */
! 489: }
! 490:
! 491: if (max_using > NCOL)
! 492: max_using = NCOL;
! 493:
! 494: df_datum = -1; /* it will be preincremented before use */
! 495: df_line_number = 0; /* ditto */
! 496:
! 497: df_lower_index = 0;
! 498: df_index_step = 1;
! 499: df_upper_index = MAXINT;
! 500:
! 501: df_current_index = 0;
! 502: blank_count = 2;
! 503: /* by initialising blank_count, leading blanks will be ignored */
! 504:
! 505: everypoint = everyline = 1; /* unless there is an every spec */
! 506: firstpoint = firstline = 0;
! 507: lastpoint = lastline = MAXINT;
! 508:
! 509: df_eof = 0;
! 510:
! 511: memset(df_timecol, 0, sizeof(df_timecol));
! 512:
! 513: df_binary = 1;
! 514: /*}}} */
! 515:
! 516: assert(max_using <= NCOL);
! 517:
! 518: /* empty name means re-use last one */
! 519:
! 520: {
! 521: char name[MAX_LINE_LEN + 1];
! 522: quote_str(name, c_token, MAX_LINE_LEN);
! 523: if (name[0])
! 524: strcpy(filename, name);
! 525: else if (!filename[0])
! 526: int_error("No previous filename", c_token);
! 527: }
! 528: name_token = c_token++;
! 529:
! 530: /* defer opening until we have parsed the modifiers... */
! 531:
! 532: /*{{{ look for binary / matrix */
! 533: df_binary = df_matrix = FALSE;
! 534:
! 535: if (almost_equals(c_token, "bin$ary")) {
! 536: ++c_token;
! 537: df_binary = TRUE;
! 538: df_matrix = TRUE;
! 539: } else if (almost_equals(c_token, "mat$rix")) {
! 540: ++c_token;
! 541: df_matrix = TRUE;
! 542: }
! 543: /*}}} */
! 544:
! 545: /*{{{ deal with index */
! 546: if (almost_equals(c_token, "i$ndex")) {
! 547: struct value a;
! 548:
! 549: if (df_binary)
! 550: int_error("Binary file format does not allow more than one surface per file", c_token);
! 551:
! 552: ++c_token;
! 553: df_lower_index = (int) real(const_express(&a));
! 554: if (equals(c_token, ":")) {
! 555: ++c_token;
! 556: df_upper_index = (int) magnitude(const_express(&a));
! 557: if (df_upper_index < df_lower_index)
! 558: int_error("Upper index should be bigger than lower index", c_token);
! 559:
! 560: if (equals(c_token, ":")) {
! 561: ++c_token;
! 562: df_index_step = (int) magnitude(const_express(&a));
! 563: if (df_index_step < 1)
! 564: int_error("Index step must be positive", c_token);
! 565: }
! 566: } else
! 567: df_upper_index = df_lower_index;
! 568: }
! 569: /*}}} */
! 570:
! 571: /*{{{ deal with every */
! 572: if (almost_equals(c_token, "ev$ery")) {
! 573: struct value a;
! 574:
! 575: fast_columns = 0; /* corey@cac */
! 576: /* allow empty fields - every a:b:c::e
! 577: * we have already established the defaults
! 578: */
! 579:
! 580: if (!equals(++c_token, ":")) {
! 581: everypoint = (int) real(const_express(&a));
! 582: if (everypoint < 1)
! 583: int_error("Expected positive integer", c_token);
! 584: }
! 585: /* if it fails on first test, no more tests will succeed. If it
! 586: * fails on second test, next test will succeed with correct c_token
! 587: */
! 588: if (equals(c_token, ":") && !equals(++c_token, ":")) {
! 589: everyline = (int) real(const_express(&a));
! 590: if (everyline < 1)
! 591: int_error("Expected positive integer", c_token);
! 592: }
! 593: if (equals(c_token, ":") && !equals(++c_token, ":")) {
! 594: firstpoint = (int) real(const_express(&a));
! 595: if (firstpoint < 0)
! 596: int_error("Expected non-negative integer", c_token);
! 597: }
! 598: if (equals(c_token, ":") && !equals(++c_token, ":")) {
! 599: firstline = (int) real(const_express(&a));
! 600: if (firstline < 0)
! 601: int_error("Expected non-negative integer", c_token);
! 602: }
! 603: if (equals(c_token, ":") && !equals(++c_token, ":")) {
! 604: lastpoint = (int) real(const_express(&a));
! 605: if (lastpoint < firstpoint)
! 606: int_error("Last point must not be before first point", c_token);
! 607: }
! 608: if (equals(c_token, ":")) {
! 609: ++c_token;
! 610: lastline = (int) real(const_express(&a));
! 611: if (lastline < firstline)
! 612: int_error("Last line must not be before first line", c_token);
! 613: }
! 614: }
! 615: /*}}} */
! 616:
! 617: /*{{{ deal with thru */
! 618: /* jev -- support for passing data from file thru user function */
! 619:
! 620: if (almost_equals(c_token, "thru$")) {
! 621: c_token++;
! 622: if (ydata_func.at)
! 623: free(ydata_func.at);
! 624: strcpy(c_dummy_var[0], dummy_var[0]);
! 625: /* allow y also as a dummy variable.
! 626: * during plot, c_dummy_var[0] and [1] are 'sacred'
! 627: * ie may be set by splot [u=1:2] [v=1:2], and these
! 628: * names are stored only in c_dummy_var[]
! 629: * so choose dummy var 2 - can anything vital be here ?
! 630: */
! 631: dummy_func = &ydata_func;
! 632: strcpy(c_dummy_var[2], "y");
! 633: ydata_func.at = perm_at();
! 634: dummy_func = NULL;
! 635: } else {
! 636: if (ydata_func.at)
! 637: free(ydata_func.at);
! 638: ydata_func.at = NULL;
! 639: }
! 640: /*}}} */
! 641:
! 642: /*{{{ deal with using */
! 643: if (almost_equals(c_token, "u$sing")) {
! 644: if (!END_OF_COMMAND && !isstring(++c_token)) {
! 645: struct value a;
! 646:
! 647: do { /* must be at least one */
! 648: if (df_no_use_specs >= max_using)
! 649: int_error("Too many columns in using specification", c_token);
! 650:
! 651: if (equals(c_token, ":")) {
! 652: /* empty specification - use default */
! 653: use_spec[df_no_use_specs].column = df_no_use_specs;
! 654: ++df_no_use_specs;
! 655: /* do not increment c+token ; let while() find the : */
! 656: } else if (equals(c_token, "(")) {
! 657: fast_columns = 0; /* corey@cac */
! 658: dummy_func = NULL; /* no dummy variables active */
! 659: use_spec[df_no_use_specs++].at = perm_at(); /* it will match ()'s */
! 660: } else {
! 661: int col = (int) real(const_express(&a));
! 662: if (col < -2)
! 663: int_error("Column must be >= -2", c_token);
! 664: use_spec[df_no_use_specs++].column = col;
! 665: }
! 666: } while (equals(c_token, ":") && ++c_token);
! 667: }
! 668: if (!END_OF_COMMAND && isstring(c_token)) {
! 669: if (df_binary)
! 670: int_error("Format string meaningless with binary data", NO_CARET);
! 671:
! 672: quote_str(df_format, c_token, MAX_LINE_LEN);
! 673: if (!valid_format(df_format))
! 674: int_error("Please use a double conversion %lf", c_token);
! 675:
! 676: c_token++; /* skip format */
! 677: }
! 678: }
! 679: /*}}} */
! 680:
! 681: /*{{{ more variable inits */
! 682: point_count = -1; /* we preincrement */
! 683: line_count = 0;
! 684:
! 685: /* here so it's not done for every line in df_readline */
! 686: if (max_line_len < 160)
! 687: line = (char *) gp_alloc(max_line_len = 160, "datafile line buffer");
! 688:
! 689:
! 690: /*}}} */
! 691:
! 692:
! 693: /*{{{ open file */
! 694: #if defined(PIPES)
! 695: if (*filename == '<') {
! 696: if ((data_fp = popen(filename + 1, "r")) == (FILE *) NULL)
! 697: os_error("cannot create pipe for data", name_token);
! 698: else
! 699: pipe_open = TRUE;
! 700: } else
! 701: #endif /* PIPES */
! 702: if (*filename == '-') {
! 703: data_fp = lf_top();
! 704: if (!data_fp)
! 705: data_fp = stdin;
! 706: mixed_data_fp = TRUE; /* don't close command file */
! 707: } else {
! 708: char msg[MAX_LINE_LEN+1];
! 709: #ifdef HAVE_SYS_STAT_H
! 710: struct stat statbuf;
! 711:
! 712: if ((stat(filename, &statbuf) > -1) &&
! 713: !S_ISREG(statbuf.st_mode) && !S_ISFIFO(statbuf.st_mode)) {
! 714: sprintf(msg, "\"%s\" is not a regular file or pipe", filename);
! 715: os_error(msg, name_token);
! 716: }
! 717: #endif /* HAVE_SYS_STAT_H */
! 718: if ((data_fp = fopen(filename, df_binary ? "rb" : "r")) == (FILE *) NULL) {
! 719: /* one day we will have proper printf-style error reporting fns */
! 720: sprintf(msg, "can't read data file \"%s\"", filename);
! 721: os_error(msg, name_token);
! 722: }
! 723: }
! 724: /*}}} */
! 725:
! 726: return df_no_use_specs;
! 727: }
! 728: /*}}} */
! 729:
! 730: /*{{{ void df_close() */
! 731: void df_close()
! 732: {
! 733: int i;
! 734: /* paranoid - mark $n and column(n) as invalid */
! 735: df_no_cols = 0;
! 736:
! 737: if (!data_fp)
! 738: return;
! 739:
! 740: if (ydata_func.at) {
! 741: free(ydata_func.at);
! 742: ydata_func.at = NULL;
! 743: }
! 744: /*{{{ free any use expression storage */
! 745: for (i = 0; i < df_no_use_specs; ++i)
! 746: if (use_spec[i].at) {
! 747: free(use_spec[i].at);
! 748: use_spec[i].at = NULL;
! 749: }
! 750: /*}}} */
! 751:
! 752: if (!mixed_data_fp) {
! 753: #if defined(PIPES)
! 754: if (pipe_open) {
! 755: (void) pclose(data_fp);
! 756: pipe_open = FALSE;
! 757: } else
! 758: #endif /* PIPES */
! 759: (void) fclose(data_fp);
! 760: }
! 761: mixed_data_fp = FALSE;
! 762: data_fp = NULL;
! 763: }
! 764:
! 765: /*}}} */
! 766:
! 767: /*{{{ int df_readline(v, max) */
! 768: /* do the hard work... read lines from file,
! 769: * - use blanks to get index number
! 770: * - ignore lines outside range of indices required
! 771: * - fill v[] based on using spec if given
! 772: */
! 773:
! 774: int df_readline(v, max)
! 775: double v[];
! 776: int max;
! 777: {
! 778: char *s;
! 779:
! 780: assert(data_fp != NULL);
! 781: assert(!df_binary);
! 782: assert(max_line_len); /* alloc-ed in df_open() */
! 783: assert(max <= NCOL);
! 784:
! 785: /* catch attempt to read past EOF on mixed-input */
! 786: if (df_eof)
! 787: return DF_EOF;
! 788:
! 789: while ((s = df_gets()) != NULL)
! 790: /*{{{ process line */
! 791: {
! 792: int line_okay = 1;
! 793: int output = 0; /* how many numbers written to v[] */
! 794:
! 795: ++df_line_number;
! 796: df_no_cols = 0;
! 797:
! 798: /*{{{ check for blank lines, and reject by index/every */
! 799: /*{{{ skip leading spaces */
! 800: while (isspace((int)*s))
! 801: ++s; /* will skip the \n too, to point at \0 */
! 802: /*}}} */
! 803:
! 804: /*{{{ skip comments */
! 805: if (is_comment(*s))
! 806: continue; /* ignore comments */
! 807: /*}}} */
! 808:
! 809: /*{{{ check EOF on mixed data */
! 810: if (mixed_data_fp && is_EOF(*s)) {
! 811: df_eof = 1; /* trap attempts to read past EOF */
! 812: return DF_EOF;
! 813: }
! 814: /*}}} */
! 815:
! 816: /*{{{ its a blank line - update counters and continue or return */
! 817: if (*s == 0) {
! 818: /* argh - this is complicated ! we need to
! 819: * ignore it if we haven't reached first index
! 820: * report EOF if passed last index
! 821: * report blank line unless we've already done 2 blank lines
! 822: *
! 823: * - I have probably missed some obvious way of doing all this,
! 824: * but its getting late
! 825: */
! 826:
! 827: point_count = -1; /* restart counter within line */
! 828:
! 829: if (++blank_count == 1) {
! 830: /* first blank line */
! 831: ++line_count;
! 832: }
! 833:
! 834: /* just reached end of a group/surface */
! 835: if (blank_count == 2) {
! 836: ++df_current_index;
! 837: line_count = 0;
! 838: df_datum = -1;
! 839: /* ignore line if current_index has just become
! 840: * first required one - client doesn't want this
! 841: * blank line. While we're here, check for <=
! 842: * - we need to do it outside this conditional, but
! 843: * probably no extra cost at assembler level
! 844: */
! 845: if (df_current_index <= df_lower_index)
! 846: continue; /* dont tell client */
! 847:
! 848: /* df_upper_index is MAXINT-1 if we are not doing index */
! 849: if (df_current_index > df_upper_index) {
! 850: /* oops - need to gobble rest of input if mixed */
! 851: if (mixed_data_fp)
! 852: continue;
! 853: else {
! 854: df_eof = 1;
! 855: return DF_EOF; /* no point continuing */
! 856: }
! 857: }
! 858: }
! 859: /* dont tell client if we haven't reached first index */
! 860: if (df_current_index < df_lower_index)
! 861: continue;
! 862:
! 863: /* ignore blank lines after blank_index */
! 864: if (blank_count > 2)
! 865: continue;
! 866:
! 867: return DF_FIRST_BLANK - (blank_count - 1);
! 868: }
! 869: /*}}} */
! 870:
! 871: /* get here => was not blank */
! 872:
! 873: blank_count = 0;
! 874:
! 875: /*{{{ ignore points outside range of index */
! 876: /* we try to return end-of-file as soon as we pass upper index,
! 877: * but for mixed input stream, we must skip garbage
! 878: */
! 879:
! 880: if (df_current_index < df_lower_index ||
! 881: df_current_index > df_upper_index ||
! 882: ((df_current_index - df_lower_index) % df_index_step) != 0)
! 883: continue;
! 884: /*}}} */
! 885:
! 886: /*{{{ reject points by every */
! 887: /* accept only lines with (line_count%everyline) == 0 */
! 888:
! 889: if (line_count < firstline || line_count > lastline ||
! 890: (line_count - firstline) % everyline != 0
! 891: )
! 892: continue;
! 893:
! 894: /* update point_count. ignore point if point_count%everypoint != 0 */
! 895:
! 896: if (++point_count < firstpoint || point_count > lastpoint ||
! 897: (point_count - firstpoint) % everypoint != 0
! 898: )
! 899: continue;
! 900: /*}}} */
! 901: /*}}} */
! 902:
! 903: ++df_datum;
! 904:
! 905: /*{{{ do a sscanf */
! 906: if (*df_format) {
! 907: int i;
! 908:
! 909: assert(NCOL == 7);
! 910:
! 911: /* check we have room for at least 7 columns */
! 912: if (df_max_cols < 7)
! 913: df_column = (df_column_struct *) gp_realloc(df_column, (df_max_cols = 7) * sizeof(df_column_struct), "datafile columns");
! 914:
! 915: df_no_cols = sscanf(line, df_format,
! 916: &df_column[0].datum,
! 917: &df_column[1].datum,
! 918: &df_column[2].datum,
! 919: &df_column[3].datum,
! 920: &df_column[4].datum,
! 921: &df_column[5].datum,
! 922: &df_column[6].datum);
! 923:
! 924: if (df_no_cols == EOF) {
! 925: df_eof = 1;
! 926: return DF_EOF; /* tell client */
! 927: }
! 928: for (i = 0; i < df_no_cols; ++i) { /* may be zero */
! 929: df_column[i].good = DF_GOOD;
! 930: df_column[i].position = NULL; /* cant get a time */
! 931: }
! 932: }
! 933: /*}}} */
! 934: else
! 935: df_tokenise(s);
! 936:
! 937: /*{{{ copy column[] to v[] via use[] */
! 938: {
! 939: int limit = (df_no_use_specs ? df_no_use_specs : NCOL);
! 940: if (limit > max)
! 941: limit = max;
! 942:
! 943: for (output = 0; output < limit; ++output) {
! 944: /* if there was no using spec, column is output+1 and at=NULL */
! 945: int column = use_spec[output].column;
! 946:
! 947: if (use_spec[output].at) {
! 948: struct value a;
! 949: /* no dummy values to set up prior to... */
! 950: evaluate_at(use_spec[output].at, &a);
! 951: if (undefined)
! 952: return DF_UNDEFINED; /* store undefined point in plot */
! 953:
! 954: v[output] = real(&a);
! 955: } else if (column == -2) {
! 956: v[output] = df_current_index;
! 957: } else if (column == -1) {
! 958: v[output] = line_count;
! 959: } else if (column == 0) {
! 960: v[output] = df_datum; /* using 0 */
! 961: } else if (column <= 0) /* really < -2, but */
! 962: int_error("internal error: column <= 0 in datafile.c", NO_CARET);
! 963: else if (df_timecol[output]) {
! 964: struct tm tm;
! 965: if (column > df_no_cols ||
! 966: df_column[column - 1].good == DF_MISSING ||
! 967: !df_column[column - 1].position ||
! 968: !gstrptime(df_column[column - 1].position, timefmt, &tm)
! 969: ) {
! 970: /* line bad only if user explicitly asked for this column */
! 971: if (df_no_use_specs)
! 972: line_okay = 0;
! 973:
! 974: /* return or ignore line depending on line_okay */
! 975: break;
! 976: }
! 977: v[output] = (double) gtimegm(&tm);
! 978: } else { /* column > 0 */
! 979: if ((column <= df_no_cols) && df_column[column - 1].good == DF_GOOD)
! 980: v[output] = df_column[column - 1].datum;
! 981: else {
! 982: /* line bad only if user explicitly asked for this column */
! 983: if (df_no_use_specs)
! 984: line_okay = 0;
! 985: break; /* return or ignore depending on line_okay */
! 986: }
! 987: }
! 988: }
! 989: }
! 990: /*}}} */
! 991:
! 992: if (!line_okay)
! 993: continue;
! 994:
! 995: /* output == df_no_use_specs if using was specified
! 996: * - actually, smaller of df_no_use_specs and max
! 997: */
! 998: assert(df_no_use_specs == 0 || output == df_no_use_specs || output == max);
! 999:
! 1000: return output;
! 1001:
! 1002: }
! 1003: /*}}} */
! 1004:
! 1005: /* get here => fgets failed */
! 1006:
! 1007: /* no longer needed - mark column(x) as invalid */
! 1008: df_no_cols = 0;
! 1009:
! 1010: df_eof = 1;
! 1011: return DF_EOF;
! 1012: }
! 1013: /*}}} */
! 1014:
! 1015: /*{{{ int df_2dbinary(this_plot) */
! 1016: int df_2dbinary(this_plot)
! 1017: struct curve_points *this_plot;
! 1018: {
! 1019: int_error("Binary file format for 2d data not yet defined", NO_CARET);
! 1020: return 0; /* keep compiler happy */
! 1021: }
! 1022: /*}}} */
! 1023:
! 1024: /*{{{ int df_3dmatrix(this_plot, ret_this_iso) */
! 1025: /*
! 1026: * formerly in gnubin.c
! 1027: *
! 1028: * modified by div for 3.6
! 1029: * obey the 'every' field from df_open
! 1030: * outrange points are marked as such, not omitted
! 1031: * obey using - treat x as column 1, y as col 2 and z as col 3
! 1032: * ( ie $1 gets x, $2 gets y, $3 gets z)
! 1033: *
! 1034: * we are less optimal for case of log plot and no using spec,
! 1035: * (call log too often) but that is price for flexibility
! 1036: * I suspect it didn't do autoscaling of x and y for log scale
! 1037: * properly ?
! 1038: *
! 1039: * Trouble figuring out file format ! Is it
! 1040:
! 1041: width x1 x2 x3 x4 x5 ...
! 1042: y1 z11 z12 z13 z14 z15 ...
! 1043: y2 x21 z22 z23 .....
! 1044: . .
! 1045: . .
! 1046: . .
! 1047:
! 1048: * with perhaps x and y swapped...
! 1049: *
! 1050: * - presumably rows continue to end of file, hence no indexing...
! 1051: *
! 1052: * Last update: 3/3/92 for Gnuplot 3.24.
! 1053: * Created from code for written by RKC for gnuplot 2.0b.
! 1054: *
! 1055: * 19 September 1992 Lawrence Crowl (crowl@cs.orst.edu)
! 1056: * Added user-specified bases for log scaling.
! 1057: *
! 1058: * Copyright (c) 1991,1992 Robert K. Cunningham, MIT Lincoln Laboratory
! 1059: *
! 1060: */
! 1061:
! 1062: /*
! 1063: Here we keep putting new plots onto the end of the linked list
! 1064:
! 1065: We assume the data's x,y values have x1<x2, x2<x3... and
! 1066: y1<y2, y2<y3... .
! 1067: Actually, I think the assumption is less strong than that--it looks like
! 1068: the direction just has to be the same.
! 1069: This routine expects the following to be properly initialized:
! 1070: is_log_x, is_log_y, and is_log_z
! 1071: base_log_x, base_log_y, and base_log_z
! 1072: log_base_log_x, log_base_log_y, and log_base_log_z
! 1073: xmin,ymin, and zmin
! 1074: xmax,ymax, and zmax
! 1075: autoscale_lx, autoscale_ly, and autoscale_lz
! 1076:
! 1077: does the autoscaling into the array versions (min_array[], max_array[])
! 1078: */
! 1079:
! 1080: int df_3dmatrix(this_plot)
! 1081: struct surface_points *this_plot;
! 1082: {
! 1083: float GPFAR *GPFAR * dmatrix, GPFAR * rt, GPFAR * ct;
! 1084: int nr, nc;
! 1085: int width, height;
! 1086: int row, col;
! 1087: struct iso_curve *this_iso;
! 1088: double used[3]; /* output from using manip */
! 1089: struct coordinate GPHUGE *point; /* HBB 980308: added 'GPHUGE' flag */
! 1090:
! 1091: assert(df_matrix);
! 1092:
! 1093: if (df_eof)
! 1094: return 0; /* hope caller understands this */
! 1095:
! 1096: if (df_binary) {
! 1097: if (!fread_matrix(data_fp, &dmatrix, &nr, &nc, &rt, &ct))
! 1098: int_error("Binary file read error: format unknown!", NO_CARET);
! 1099: /* fread_matrix() drains the file */
! 1100: df_eof = 1;
! 1101: } else {
! 1102: if (!(dmatrix = df_read_matrix(&nr, &nc))) {
! 1103: df_eof = 1;
! 1104: return 0;
! 1105: }
! 1106: rt = NULL;
! 1107: ct = NULL;
! 1108: }
! 1109:
! 1110: if (nc == 0 || nr == 0)
! 1111: int_error("Read grid of zero height or zero width", NO_CARET);
! 1112:
! 1113: this_plot->plot_type = DATA3D;
! 1114: this_plot->has_grid_topology = TRUE;
! 1115:
! 1116: if (df_no_use_specs != 0 && df_no_use_specs != 3)
! 1117: int_error("Current implementation requires full using spec", NO_CARET);
! 1118:
! 1119: if (df_max_cols < 3 &&
! 1120: !(df_column = (df_column_struct *) gp_realloc(df_column, (df_max_cols = 3) * sizeof(df_column_struct), "datafile columns"))
! 1121: )
! 1122: int_error("Out of store in binary read", c_token);
! 1123:
! 1124: df_no_cols = 3;
! 1125: df_column[0].good = df_column[1].good = df_column[2].good = DF_GOOD;
! 1126:
! 1127: assert(everyline > 0);
! 1128: assert(everypoint > 0);
! 1129: width = (nc - firstpoint + everypoint - 1) / everypoint; /* ? ? ? ? ? */
! 1130: height = (nr - firstline + everyline - 1) / everyline; /* ? ? ? ? ? */
! 1131:
! 1132: for (row = firstline; row < nr; row += everyline) {
! 1133: df_column[1].datum = rt ? rt[row] : row;
! 1134:
! 1135: /*Allocate the correct number of entries */
! 1136: this_iso = iso_alloc(width);
! 1137:
! 1138: point = this_iso->points;
! 1139:
! 1140: /* Cycle through data */
! 1141: for (col = firstpoint; col < nc; col += everypoint, ++point) {
! 1142: /*{{{ process one point */
! 1143: int i;
! 1144:
! 1145: df_column[0].datum = ct ? ct[col] : col;
! 1146: df_column[2].datum = dmatrix[row][col];
! 1147:
! 1148: /*{{{ pass through using spec */
! 1149: for (i = 0; i < 3; ++i) {
! 1150: int column = use_spec[i].column;
! 1151:
! 1152: if (df_no_use_specs == 0)
! 1153: used[i] = df_column[i].datum;
! 1154: else if (use_spec[i].at) {
! 1155: struct value a;
! 1156: evaluate_at(use_spec[i].at, &a);
! 1157: if (undefined) {
! 1158: point->type = UNDEFINED;
! 1159: goto skip; /* continue _outer_ loop */
! 1160: }
! 1161: used[i] = real(&a);
! 1162: } else if (column < 1 || column > df_no_cols) {
! 1163: point->type = UNDEFINED;
! 1164: goto skip;
! 1165: } else
! 1166: used[i] = df_column[column - 1].datum;
! 1167: }
! 1168: /*}}} */
! 1169:
! 1170: point->type = INRANGE; /* so far */
! 1171:
! 1172: /*{{{ autoscaling/clipping */
! 1173: /*{{{ autoscale/range-check x */
! 1174: if (used[0] > 0 || !is_log_x) {
! 1175: if (used[0] < min_array[FIRST_X_AXIS]) {
! 1176: if (autoscale_lx & 1)
! 1177: min_array[FIRST_X_AXIS] = used[0];
! 1178: else
! 1179: point->type = OUTRANGE;
! 1180: }
! 1181: if (used[0] > max_array[FIRST_X_AXIS]) {
! 1182: if (autoscale_lx & 2)
! 1183: max_array[FIRST_X_AXIS] = used[0];
! 1184: else
! 1185: point->type = OUTRANGE;
! 1186: }
! 1187: }
! 1188: /*}}} */
! 1189:
! 1190: /*{{{ autoscale/range-check y */
! 1191: if (used[1] > 0 || !is_log_y) {
! 1192: if (used[1] < min_array[FIRST_Y_AXIS]) {
! 1193: if (autoscale_ly & 1)
! 1194: min_array[FIRST_Y_AXIS] = used[1];
! 1195: else
! 1196: point->type = OUTRANGE;
! 1197: }
! 1198: if (used[1] > max_array[FIRST_Y_AXIS]) {
! 1199: if (autoscale_ly & 2)
! 1200: max_array[FIRST_Y_AXIS] = used[1];
! 1201: else
! 1202: point->type = OUTRANGE;
! 1203: }
! 1204: }
! 1205: /*}}} */
! 1206:
! 1207: /*{{{ autoscale/range-check z */
! 1208: if (used[2] > 0 || !is_log_z) {
! 1209: if (used[2] < min_array[FIRST_Z_AXIS]) {
! 1210: if (autoscale_lz & 1)
! 1211: min_array[FIRST_Z_AXIS] = used[2];
! 1212: else
! 1213: point->type = OUTRANGE;
! 1214: }
! 1215: if (used[2] > max_array[FIRST_Z_AXIS]) {
! 1216: if (autoscale_lz & 2)
! 1217: max_array[FIRST_Z_AXIS] = used[2];
! 1218: else
! 1219: point->type = OUTRANGE;
! 1220: }
! 1221: }
! 1222: /*}}} */
! 1223: /*}}} */
! 1224:
! 1225: /*{{{ log x */
! 1226: if (is_log_x) {
! 1227: if (used[0] < 0.0) {
! 1228: point->type = UNDEFINED;
! 1229: goto skip;
! 1230: } else if (used[0] == 0.0) {
! 1231: point->type = OUTRANGE;
! 1232: used[0] = -VERYLARGE;
! 1233: } else
! 1234: used[0] = log(used[0]) / log_base_log_x;
! 1235: }
! 1236: /*}}} */
! 1237:
! 1238: /*{{{ log y */
! 1239: if (is_log_y) {
! 1240: if (used[1] < 0.0) {
! 1241: point->type = UNDEFINED;
! 1242: goto skip;
! 1243: } else if (used[1] == 0.0) {
! 1244: point->type = OUTRANGE;
! 1245: used[1] = -VERYLARGE;
! 1246: } else
! 1247: used[1] = log(used[1]) / log_base_log_y;
! 1248: }
! 1249: /*}}} */
! 1250:
! 1251: /*{{{ log z */
! 1252: if (is_log_z) {
! 1253: if (used[2] < 0.0) {
! 1254: point->type = UNDEFINED;
! 1255: goto skip;
! 1256: } else if (used[2] == 0.0) {
! 1257: point->type = OUTRANGE;
! 1258: used[2] = -VERYLARGE;
! 1259: } else
! 1260: used[2] = log(used[2]) / log_base_log_z;
! 1261: }
! 1262: /*}}} */
! 1263:
! 1264: point->x = used[0];
! 1265: point->y = used[1];
! 1266: point->z = used[2];
! 1267:
! 1268:
! 1269: /* some of you wont like this, but I say goto is for this */
! 1270:
! 1271: skip:
! 1272: ; /* ansi requires this */
! 1273: /*}}} */
! 1274: }
! 1275: this_iso->p_count = width;
! 1276: this_iso->next = this_plot->iso_crvs;
! 1277: this_plot->iso_crvs = this_iso;
! 1278: this_plot->num_iso_read++;
! 1279: }
! 1280:
! 1281: free_matrix(dmatrix, 0, nr - 1, 0, nc - 1);
! 1282: if (rt)
! 1283: free_vector(rt, 0, nr - 1);
! 1284: if (ct)
! 1285: free_vector(ct, 0, nc - 1);
! 1286: return (nc);
! 1287: }
! 1288: /*}}} */
! 1289:
! 1290: /* stuff for implementing the call-backs for picking up data values
! 1291: * do it here so we can make the variables private to this file
! 1292: */
! 1293:
! 1294: /*{{{ void f_dollars(x) */
! 1295: void f_dollars(x)
! 1296: union argument *x;
! 1297: {
! 1298: int column = x->v_arg.v.int_val - 1;
! 1299: /* we checked it was an integer >= 0 at compile time */
! 1300: struct value a;
! 1301:
! 1302: if (column == -1) {
! 1303: push(Gcomplex(&a, (double) df_datum, 0.0)); /* $0 */
! 1304: } else if (column >= df_no_cols || df_column[column].good != DF_GOOD) {
! 1305: undefined = TRUE;
! 1306: push(&(x->v_arg)); /* this okay ? */
! 1307: } else
! 1308: push(Gcomplex(&a, df_column[column].datum, 0.0));
! 1309: }
! 1310: /*}}} */
! 1311:
! 1312: /*{{{ void f_column() */
! 1313: void f_column()
! 1314: {
! 1315: struct value a;
! 1316: int column;
! 1317: (void) pop(&a);
! 1318: column = (int) real(&a) - 1;
! 1319: if (column == -2)
! 1320: push(Ginteger(&a, line_count));
! 1321: else if (column == -1) /* $0 = df_datum */
! 1322: push(Gcomplex(&a, (double) df_datum, 0.0));
! 1323: else if (column < 0 || column >= df_no_cols || df_column[column].good != DF_GOOD) {
! 1324: undefined = TRUE;
! 1325: push(&a); /* any objection to this ? */
! 1326: } else
! 1327: push(Gcomplex(&a, df_column[column].datum, 0.0));
! 1328: }
! 1329: /*}}} */
! 1330:
! 1331: /*{{{ void f_valid() */
! 1332: void f_valid()
! 1333: {
! 1334: struct value a;
! 1335: int column, good;
! 1336: (void) pop(&a);
! 1337: column = (int) magnitude(&a) - 1;
! 1338: good = column >= 0 && column < df_no_cols && df_column[column].good == DF_GOOD;
! 1339: push(Ginteger(&a, good));
! 1340: }
! 1341:
! 1342: /*}}} */
! 1343:
! 1344: /*{{{ void f_timecolumn() */
! 1345: void f_timecolumn()
! 1346: {
! 1347: struct value a;
! 1348: int column;
! 1349: struct tm tm;
! 1350: (void) pop(&a);
! 1351: column = (int) magnitude(&a) - 1;
! 1352: if (column < 0 || column >= df_no_cols ||
! 1353: !df_column[column].position ||
! 1354: !gstrptime(df_column[column].position, timefmt, &tm)
! 1355: ) {
! 1356: undefined = TRUE;
! 1357: push(&a); /* any objection to this ? */
! 1358: } else
! 1359: push(Gcomplex(&a, gtimegm(&tm), 0.0));
! 1360: }
! 1361: /*}}} */
! 1362:
! 1363: #if 0 /* not used */
! 1364: /* count columns in timefmt */
! 1365: /*{{{ static int get_time_cols(fmt) */
! 1366: static int get_time_cols(fmt)
! 1367: char *fmt; /* format string */
! 1368: {
! 1369: int cnt, i;
! 1370: char *p;
! 1371:
! 1372: p = fmt;
! 1373: cnt = 0;
! 1374: while (isspace(*p))
! 1375: p++;
! 1376: if (!strlen(p))
! 1377: int_error("Empty time-data format", NO_CARET);
! 1378: cnt++;
! 1379: for (i = 0; i < strlen(p) - 1; i++) {
! 1380: if (isspace(p[i]) && !isspace(p[i + 1]))
! 1381: cnt++;
! 1382: }
! 1383: return (cnt);
! 1384: }
! 1385: /*}}} */
! 1386:
! 1387: /* modify default use_spec, applies for no user spec and time datacolumns */
! 1388: /*{{{ static void mod_def_usespec(specno,jump) */
! 1389: static void mod_def_usespec(specno, jump)
! 1390: int specno; /* which spec in ?:?:? */
! 1391: int jump; /* no of columns in timefmt (time data) */
! 1392: {
! 1393: int i;
! 1394:
! 1395: for (i = specno + 1; i < NCOL; ++i)
! 1396: use_spec[i].column += jump; /* add no of columns in time to the rest */
! 1397: df_no_use_specs = 0;
! 1398: }
! 1399: /*}}} */
! 1400: #endif /* not used */
! 1401:
! 1402: /*{{{ static int check_missing(s) */
! 1403: static int check_missing(s)
! 1404: char *s;
! 1405: {
! 1406: if (missing_val != NULL) {
! 1407: int len = strlen(missing_val);
! 1408: if (strncmp(s, missing_val, len) == 0 &&
! 1409: (isspace((int)s[len]) || !s[len])) {
! 1410: return (1);; /* store undefined point in plot */
! 1411: }
! 1412: }
! 1413: return (0);
! 1414: }
! 1415: /*}}} */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>