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

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

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