[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.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>