[BACK]Return to datafile.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot

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>