Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / axis.h
diff --git a/src/axis.h b/src/axis.h
new file mode 100644 (file)
index 0000000..f591f00
--- /dev/null
@@ -0,0 +1,661 @@
+/*
+ * $Id: axis.h,v 1.46.2.3 2008/10/30 22:26:23 sfeam Exp $
+ *
+ */
+
+/*[
+ * Copyright 2000, 2004   Thomas Williams, Colin Kelley
+ *
+ * Permission to use, copy, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.
+ *
+ * Permission to modify the software is granted, but not the right to
+ * distribute the complete modified source code.  Modifications are to
+ * be distributed as patches to the released version.  Permission to
+ * distribute binaries produced by compiling modified sources is granted,
+ * provided you
+ *   1. distribute the corresponding source modifications from the
+ *    released version in the form of a patch file along with the binaries,
+ *   2. add special version identification to distinguish your version
+ *    in addition to the base release version number,
+ *   3. provide your name and address as the primary contact for the
+ *    support of your modified version, and
+ *   4. retain our contact information in regard to use of the base
+ *    software.
+ * Permission to distribute the released version of the source code along
+ * with corresponding source modifications in the form of a patch file is
+ * granted with same provisions 2 through 4 for binary distributions.
+ *
+ * This software is provided "as is" without express or implied warranty
+ * to the extent permitted by applicable law.
+]*/
+
+#ifndef GNUPLOT_AXIS_H
+#define GNUPLOT_AXIS_H
+
+#include "gp_types.h"          /* for TBOOLEAN */
+
+#include "gadgets.h"
+#include "parse.h"             /* for const_express() */
+#include "tables.h"            /* for the axis name parse table */
+#include "term_api.h"          /* for lp_style_type */
+#include "util.h"              /* for int_error() */
+
+/* typedefs / #defines */
+
+/* give some names to some array elements used in command.c and grap*.c
+ * maybe one day the relevant items in setshow will also be stored
+ * in arrays.
+ *
+ * Always keep the following conditions alive:
+ * SECOND_X_AXIS = FIRST_X_AXIS + SECOND_AXES
+ * FIRST_X_AXIS & SECOND_AXES == 0
+ */
+typedef enum AXIS_INDEX {
+#define FIRST_AXES 0
+    FIRST_Z_AXIS,
+    FIRST_Y_AXIS,
+    FIRST_X_AXIS,
+    T_AXIS,                    /* fill gap */
+#define SECOND_AXES 4
+    SECOND_Z_AXIS,             /* not used, yet */
+    SECOND_Y_AXIS,
+    SECOND_X_AXIS,
+    R_AXIS,                    /* never used ? */
+    U_AXIS,                    /* ditto */
+    V_AXIS                     /* ditto */
+    ,COLOR_AXIS
+} AXIS_INDEX;
+
+# define AXIS_ARRAY_SIZE 11
+
+/* What kind of ticmarking is wanted? */
+typedef enum en_ticseries_type {
+    TIC_COMPUTED=1,            /* default; gnuplot figures them */
+    TIC_SERIES,                        /* user-defined series */
+    TIC_USER,                  /* user-defined points */
+    TIC_MONTH,                 /* print out month names ((mo-1)%12)+1 */
+    TIC_DAY                    /* print out day of week */
+} t_ticseries_type;
+
+/* Defines one ticmark for TIC_USER style.
+ * If label==NULL, the value is printed with the usual format string.
+ * else, it is used as the format string (note that it may be a constant
+ * string, like "high" or "low").
+ */
+typedef struct ticmark {
+    double position;           /* where on axis is this */
+    char *label;               /* optional (format) string label */
+    int level;                 /* 0=major tic, 1=minor tic */
+    struct ticmark *next;      /* linked list */
+} ticmark;
+
+/* Tic-mark labelling definition; see set xtics */
+typedef struct ticdef {
+    t_ticseries_type type;
+    char *font;
+    struct t_colorspec textcolor;
+    struct {
+          struct ticmark *user;        /* for TIC_USER */
+          struct {                     /* for TIC_SERIES */
+                 double start, incr;
+                 double end;           /* ymax, if VERYLARGE */
+          } series;
+          TBOOLEAN mix;                /* TRUE to use both the above */
+    } def;
+    struct position offset;
+    TBOOLEAN rangelimited;             /* Limit tics to data range */
+} t_ticdef;
+
+/* we want two auto modes for minitics - default where minitics are
+ * auto for log/time and off for linear, and auto where auto for all
+ * graphs I've done them in this order so that logscale-mode can
+ * simply test bit 0 to see if it must do the minitics automatically.
+ * similarly, conventional plot can test bit 1 to see if minitics are
+ * required */
+enum en_minitics_status {
+    MINI_OFF,
+    MINI_DEFAULT,
+    MINI_USER,
+    MINI_AUTO
+};
+
+/* Function pointer type for callback functions doing operations for a
+ * single ticmark */
+typedef void (*tic_callback) __PROTO((AXIS_INDEX, double, char *, struct lp_style_type ));
+
+/* Values to put in the axis_tics[] variables that decides where the
+ * ticmarks should be drawn: not at all, on one or both plot borders,
+ * or the zeroaxes. These look like a series of values, but TICS_MASK
+ * shows that they're actually bit masks --> don't turn into an enum
+ * */
+#define NO_TICS        0
+#define TICS_ON_BORDER 1
+#define TICS_ON_AXIS   2
+#define TICS_MASK      3
+#define TICS_MIRROR    4
+
+
+#if 0 /* HBB 20010806 --- move GRID flags into axis struct */
+/* Need to allow user to choose grid at first and/or second axes tics.
+ * Also want to let user choose circles at x or y tics for polar grid.
+ * Also want to allow user rectangular grid for polar plot or polar
+ * grid for parametric plot. So just go for full configurability.
+ * These are bitmasks
+ */
+#define GRID_OFF    0
+#define GRID_X      (1<<0)
+#define GRID_Y      (1<<1)
+#define GRID_Z      (1<<2)
+#define GRID_X2     (1<<3)
+#define GRID_Y2     (1<<4)
+#define GRID_MX     (1<<5)
+#define GRID_MY     (1<<6)
+#define GRID_MZ     (1<<7)
+#define GRID_MX2    (1<<8)
+#define GRID_MY2    (1<<9)
+#define GRID_CB     (1<<10)
+#define GRID_MCB    (1<<11)
+#endif /* 0 */
+
+/* HBB 20010610: new type for storing autoscale activity. Effectively
+ * two booleans (bits) in a single variable, so I'm using an enum with
+ * all 4 possible bit masks given readable names. */
+typedef enum e_autoscale {
+    AUTOSCALE_NONE = 0,
+    AUTOSCALE_MIN = 1<<0,
+    AUTOSCALE_MAX = 1<<1,
+    AUTOSCALE_BOTH = (1<<0 | 1 << 1),
+    AUTOSCALE_FIXMIN = 1<<2,
+    AUTOSCALE_FIXMAX = 1<<3
+} t_autoscale;
+
+
+/* FIXME 20000725: collect some of those various TBOOLEAN fields into
+ * a larger int (or -- shudder -- a bitfield?) */
+typedef struct axis {
+/* range of this axis */
+    t_autoscale autoscale;     /* Which end(s) are autoscaled? */
+    t_autoscale set_autoscale; /* what does 'set' think autoscale to be? */
+    int range_flags;           /* flag bits about autoscale/writeback: */
+    /* write auto-ed ranges back to variables for autoscale */
+#define RANGE_WRITEBACK 1
+    /* allow auto and reversed ranges */
+#define RANGE_REVERSE   2
+    TBOOLEAN range_is_reverted;        /* range [high:low] silently reverted? */
+    double min;                        /* 'transient' axis extremal values */
+    double max;
+    double set_min;            /* set/show 'permanent' values */
+    double set_max;
+    double writeback_min;      /* ULIG's writeback implementation */
+    double writeback_max;
+    double data_min;           /* Not necessarily the same as axis min */
+    double data_max;
+
+/* output-related quantities */
+    int term_lower;            /* low and high end of the axis on output, */
+    int term_upper;            /* ... (in terminal coordinates)*/
+    double term_scale;         /* scale factor: plot --> term coords */
+    unsigned int term_zero;    /* position of zero axis */
+
+/* log axis control */
+    TBOOLEAN log;              /* log axis stuff: flag "islog?" */
+    double base;               /* logarithm base value */
+    double log_base;           /* ln(base), for easier computations */
+
+/* time/date axis control */
+    TBOOLEAN is_timedata;      /* is this a time/date axis? */
+    TBOOLEAN format_is_numeric;        /* format string looks like numeric??? */
+    char timefmt[MAX_ID_LEN+1];        /* format string for input */
+    char formatstring[MAX_ID_LEN+1];
+                               /* the format string for output */
+
+/* ticmark control variables */
+    int ticmode;               /* tics on border/axis? mirrored? */
+    struct ticdef ticdef;      /* tic series definition */
+    int tic_rotate;            /* ticmarks rotated by this angle */
+    TBOOLEAN gridmajor;                /* Grid lines wanted on major tics? */
+    TBOOLEAN gridminor;                /* Grid lines for minor tics? */
+    int minitics;              /* minor tic mode (none/auto/user)? */
+    double mtic_freq;          /* minitic stepsize */
+    double ticscale;           /* scale factor for tic marks (was (0..1])*/
+    double miniticscale;       /* and for minitics */
+    TBOOLEAN tic_in;           /* tics to be drawn inward?  */
+
+/* other miscellaneous fields */
+    text_label label;          /* label string and position offsets */
+    lp_style_type zeroaxis;    /* drawing style for zeroaxis, if any */
+} AXIS;
+
+#define DEFAULT_AXIS_TICDEF {TIC_COMPUTED, NULL, {TC_DEFAULT, 0, 0}, {NULL, {0,0}, FALSE},  { character, character, character, 0., 0., 0. }, FALSE }
+# define DEFAULT_AXIS_ZEROAXIS {0, -3, 0, 1.0, 1.0, 0}
+
+#define DEFAULT_AXIS_STRUCT {                                              \
+       AUTOSCALE_BOTH, AUTOSCALE_BOTH, /* auto, set_auto */                \
+       0, FALSE,               /* range_flags, rev_range */                \
+       -10.0, 10.0,            /* 3 pairs of min/max for axis itself */    \
+       -10.0, 10.0,                                                        \
+       -10.0, 10.0,                                                        \
+         0.0,  0.0,            /* and another min/max for the data */      \
+       0, 0, 0, 0,             /* terminal dependents */                   \
+       FALSE, 0.0, 0.0,        /* log, base, log(base) */                  \
+       0, 1,                   /* is_timedata, format_numeric */           \
+       DEF_FORMAT, TIMEFMT,    /* output format, timefmt */                \
+       NO_TICS,                /* tic output positions (border, mirror) */ \
+       DEFAULT_AXIS_TICDEF,    /* tic series definition */                 \
+       0, FALSE, FALSE,        /* tic_rotate, grid{major,minor} */         \
+       MINI_DEFAULT, 10,       /* minitics, mtic_freq */                   \
+        1.0, 0.5, TRUE,                /* ticscale, miniticscale, tic_in */        \
+       EMPTY_LABELSTRUCT,      /* axis label */                            \
+       DEFAULT_AXIS_ZEROAXIS   /* zeroaxis line style */                   \
+}
+
+/* Table of default behaviours --- a subset of the struct above. Only
+ * those fields are present that differ from axis to axis. */
+typedef struct axis_defaults {
+    double min;                        /* default axis endpoints */
+    double max;
+    char name[4];              /* axis name, like in "x2" or "t" */
+    int ticmode;               /* tics on border/axis? mirrored? */
+} AXIS_DEFAULTS;
+
+
+
+/* global variables in axis.c */
+
+extern AXIS axis_array[AXIS_ARRAY_SIZE];
+extern const AXIS_DEFAULTS axis_defaults[AXIS_ARRAY_SIZE];
+
+/* A parsing table for mapping axis names into axis indices. For use
+ * by the set/show machinery, mainly */
+extern const struct gen_table axisname_tbl[AXIS_ARRAY_SIZE+1];
+
+
+extern const struct ticdef default_axis_ticdef;
+
+/* default format for tic mark labels */
+#define DEF_FORMAT "% g"
+
+/* default parse timedata string */
+#define TIMEFMT "%d/%m/%y,%H:%M"
+
+/* axis labels */
+extern const text_label default_axis_label;
+
+/* zeroaxis linetype (flag type==-3 if none wanted) */
+extern const lp_style_type default_axis_zeroaxis;
+
+/* default grid linetype, to be used by 'unset grid' and 'reset' */
+extern const struct lp_style_type default_grid_lp;
+
+/* grid layer: -1 default, 0 back, 1 front */
+extern int grid_layer;
+
+/* global variables for communication with the tic callback functions */
+/* FIXME HBB 20010806: had better be collected into a struct that's
+ * passed to the callback */
+extern int tic_start, tic_direction, tic_mirror;
+/* These are for passing on to write_multiline(): */
+extern int tic_text, rotate_tics, tic_hjust, tic_vjust;
+/* The remaining ones are for grid drawing; controlled by 'set grid': */
+/* extern int grid_selection; --- comm'ed out, HBB 20010806 */
+extern struct lp_style_type grid_lp; /* linestyle for major grid lines */
+extern struct lp_style_type mgrid_lp; /* linestyle for minor grid lines */
+extern double polar_grid_angle; /* angle step in polar grid in radians */
+
+/* Length of the longest tics label, set by widest_tic_callback(): */
+extern int widest_tic_strlen;
+
+/* axes being used by the current plot */
+extern AXIS_INDEX x_axis, y_axis, z_axis;
+/* macros to reduce code clutter caused by the array notation, mainly
+ * in graphics.c and fit.c */
+#define X_AXIS axis_array[x_axis]
+#define Y_AXIS axis_array[y_axis]
+#define Z_AXIS axis_array[z_axis]
+#define CB_AXIS axis_array[COLOR_AXIS]
+
+/* -------- macros using these variables: */
+
+/* Macros to map from user to terminal coordinates and back */
+#define AXIS_MAP(axis, variable)               \
+  (int) ((axis_array[axis].term_lower)         \
+        + ((variable) - axis_array[axis].min)  \
+        * axis_array[axis].term_scale + 0.5)
+#define AXIS_MAPBACK(axis, pos)                                                   \
+  (((double)(pos)-axis_array[axis].term_lower)/axis_array[axis].term_scale \
+   + axis_array[axis].min)
+
+/* these are the old names for these: */
+#define map_x(x) AXIS_MAP(x_axis, x)
+#define map_y(y) AXIS_MAP(y_axis, y)
+
+#define AXIS_SETSCALE(axis, out_low, out_high)                 \
+    axis_array[axis].term_scale = ((out_high) - (out_low))     \
+        / (axis_array[axis].max - axis_array[axis].min)
+
+/* write current min/max_array contents into the set/show status
+ * variables */
+#define AXIS_WRITEBACK(axis)                   \
+do {                                           \
+    AXIS *this = axis_array + axis;            \
+                                               \
+    if (this->range_flags & RANGE_WRITEBACK) { \
+       if (this->autoscale & AUTOSCALE_MIN)    \
+           this->set_min = this->min;          \
+       if (this->autoscale & AUTOSCALE_MAX)    \
+           this->set_max = this->max;          \
+    }                                          \
+} while(0)
+
+/* HBB 20000430: New macros, logarithmize a value into a stored
+ * coordinate*/
+#define AXIS_DO_LOG(axis,value) (log(value) / axis_array[axis].log_base)
+#define AXIS_UNDO_LOG(axis,value) exp((value) * axis_array[axis].log_base)
+
+/* HBB 20000430: same, but these test if the axis is log, first: */
+#define AXIS_LOG_VALUE(axis,value)                             \
+    (axis_array[axis].log ? AXIS_DO_LOG(axis,value) : (value))
+#define AXIS_DE_LOG_VALUE(axis,coordinate)                               \
+    (axis_array[axis].log ? AXIS_UNDO_LOG(axis,coordinate): (coordinate))
+
+
+/* copy scalar data to arrays. The difference between 3D and 2D
+ * versions is: dont know we have to support ranges [10:-10] - lets
+ * reverse it for now, then fix it at the end.  */
+/* FIXME HBB 20000426: unknown if this distinction makes any sense... */
+#define AXIS_INIT3D(axis, islog_override, infinite)                    \
+do {                                                                   \
+    AXIS *this = axis_array + axis;                                    \
+                                                                       \
+    this->autoscale = this->set_autoscale;                             \
+    if ((this->autoscale & AUTOSCALE_BOTH) == AUTOSCALE_NONE           \
+       && this->set_max < this->set_min) {                             \
+       this->min = this->set_max;                                      \
+       this->max = this->set_min;                                      \
+        /* we will fix later */                                                \
+    } else {                                                           \
+       this->min = (infinite && (this->set_autoscale & AUTOSCALE_MIN)) \
+           ? VERYLARGE : this->set_min;                                \
+       this->max = (infinite && (this->set_autoscale & AUTOSCALE_MAX)) \
+           ? -VERYLARGE : this->set_max;                               \
+    }                                                                  \
+    if (islog_override) {                                              \
+       this->log = 0;                                                  \
+       this->base = 1;                                                 \
+       this->log_base = 0;                                             \
+    } else {                                                           \
+       this->log_base = this->log ? log(this->base) : 0;               \
+    }                                                                  \
+    this->data_min = VERYLARGE;                                                \
+    this->data_max = -VERYLARGE;                                       \
+} while(0)
+
+#define AXIS_INIT2D(axis, infinite)                                    \
+do {                                                                   \
+    AXIS *this = axis_array + axis;                                    \
+                                                                       \
+    this->autoscale = this->set_autoscale;                             \
+    this->min = (infinite && (this->set_autoscale & AUTOSCALE_MIN))    \
+       ? VERYLARGE : this->set_min;                                    \
+    this->max = (infinite && (this->set_autoscale & AUTOSCALE_MAX))    \
+       ? -VERYLARGE : this->set_max;                                   \
+    this->log_base = this->log ? log(this->base) : 0;                  \
+    this->data_min = VERYLARGE;                                                \
+    this->data_max = -VERYLARGE;                                       \
+} while(0)
+
+/* handle reversed ranges */
+#define CHECK_REVERSE(axis) do {                                       \
+    AXIS *this = axis_array + axis;                                    \
+                                                                       \
+    if (((this->autoscale & AUTOSCALE_BOTH) == AUTOSCALE_NONE)         \
+       && (this->max < this->min)) {                                   \
+       double temp = this->min;                                        \
+                                                                       \
+       this->min = this->max;                                          \
+       this->max = temp;                                               \
+       this->range_is_reverted = 1;                                    \
+    } else                                                             \
+       this->range_is_reverted = (this->range_flags & RANGE_REVERSE);  \
+} while(0)
+
+/* HBB NEW 20050316: macros to always access the actual minimum, even
+ * if 'set view map' or something else flipped things around behind
+ * our back */
+#define AXIS_ACTUAL_MIN(axis)                          \
+    (axis_array[axis].range_flags & RANGE_REVERSE      \
+     ? axis_array[axis].max : axis_array[axis].min)
+
+#define AXIS_ACTUAL_MAX(axis)                          \
+    (axis_array[axis].range_flags & RANGE_REVERSE      \
+     ? axis_array[axis].min : axis_array[axis].max)
+
+/* HBB 20000725: new macro, built upon ULIG's SAVE_WRITEBACK(axis),
+ * but easier to use. Code like this occured twice, in plot2d and
+ * plot3d: */
+#define SAVE_WRITEBACK_ALL_AXES                                        \
+do {                                                           \
+    AXIS_INDEX axis;                                           \
+                                                               \
+    for (axis = 0; axis < AXIS_ARRAY_SIZE; axis++)             \
+       if(axis_array[axis].range_flags & RANGE_WRITEBACK) {    \
+           set_writeback_min(axis);                            \
+           set_writeback_max(axis);                            \
+       }                                                       \
+} while(0)
+
+/* get optional [min:max] */
+#define PARSE_RANGE(axis)                                                 \
+do {                                                                      \
+    if (equals(c_token, "[")) {                                                   \
+       c_token++;                                                         \
+       axis_array[axis].autoscale =                                       \
+           load_range(axis, &axis_array[axis].min, &axis_array[axis].max, \
+                      axis_array[axis].autoscale);                        \
+       if (!equals(c_token, "]"))                                         \
+           int_error(c_token, "']' expected");                            \
+       c_token++;                                                         \
+    }                                                                     \
+} while (0)
+
+/* HBB 20000430: new macro, like PARSE_RANGE, but for named ranges as
+ * in 'plot [phi=3.5:7] sin(phi)' */
+#define PARSE_NAMED_RANGE(axis, dummy_token)                                \
+do {                                                                        \
+    if (equals(c_token, "[")) {                                                     \
+       c_token++;                                                           \
+       if (isletter(c_token)) {                                             \
+           if (equals(c_token + 1, "=")) {                                  \
+               dummy_token = c_token;                                       \
+               c_token += 2;                                                \
+           }                                                                \
+               /* oops; probably an expression with a variable: act         \
+                * as if no variable name had been seen, by                  \
+                * fallthrough */                                            \
+       }                                                                    \
+       axis_array[axis].autoscale = load_range(axis, &axis_array[axis].min, \
+                                     &axis_array[axis].max,                 \
+                                     axis_array[axis].autoscale);           \
+       if (!equals(c_token, "]"))                                           \
+           int_error(c_token, "']' expected");                              \
+       c_token++;                                                           \
+    }                          /* first '[' */                              \
+} while (0)
+
+/* parse a position of the form
+ *    [coords] x, [coords] y {,[coords] z}
+ * where coords is one of first,second.graph,screen,character
+ * if first or second, we need to take axis_is_timedata into account
+ */
+#define GET_NUMBER_OR_TIME(store,axes,axis)                            \
+do {                                                                   \
+    if (((axes) >= 0) && (axis_array[(axes)+(axis)].is_timedata)       \
+       && isstringvalue(c_token)) {                                    \
+       struct tm tm;                                                   \
+       char *ss = try_to_get_string();                                 \
+       if (gstrptime(ss,axis_array[axis].timefmt,&tm))                 \
+           (store) = (double) gtimegm(&tm);                            \
+       free(ss);                                                       \
+    } else {                                                           \
+       struct value value;                                             \
+       (store) = real(const_express(&value));                          \
+    }                                                                  \
+} while(0)
+
+/* This is one is very similar to GET_NUMBER_OR_TIME, but has slightly
+ * different usage: it writes out '0' in case of inparsable time data,
+ * and it's used when the target axis is fixed without a 'first' or
+ * 'second' keyword in front of it. */
+#define GET_NUM_OR_TIME(store,axis)                    \
+do {                                                   \
+    (store) = 0;                                       \
+    GET_NUMBER_OR_TIME(store, FIRST_AXES, axis);       \
+} while (0);
+
+/* store VALUE or log(VALUE) in STORE, set TYPE as appropriate
+ * Do OUT_ACTION or UNDEF_ACTION as appropriate
+ * adjust range provided type is INRANGE (ie dont adjust y if x is outrange
+ * VALUE must not be same as STORE
+ * Note: see the particular implementation for COLOR AXIS below.
+ */
+
+#define STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, TYPE, AXIS,        \
+                                      OUT_ACTION, UNDEF_ACTION)          \
+do {                                                                     \
+    /* HBB 20000726: new check, to avoid crashes with axis index -1 */   \
+    if (AXIS==-1)                                                        \
+       break;                                                            \
+    /* HBB 20040304: new check to avoid storing infinities and NaNs */   \
+    if (! (VALUE > -VERYLARGE && VALUE < VERYLARGE)) {                   \
+       TYPE = UNDEFINED;                                                 \
+       UNDEF_ACTION;                                                     \
+       break;                                                            \
+    }                                                                    \
+    if (axis_array[AXIS].log) {                                                  \
+       if (VALUE<0.0) {                                                  \
+           TYPE = UNDEFINED;                                             \
+           UNDEF_ACTION;                                                 \
+           break;                                                        \
+       } else if (VALUE == 0.0) {                                        \
+           STORE = -VERYLARGE;                                           \
+           TYPE = OUTRANGE;                                              \
+           OUT_ACTION;                                                   \
+           break;                                                        \
+       } else {                                                          \
+           STORE = AXIS_DO_LOG(AXIS,VALUE);                              \
+       }                                                                 \
+    } else                                                               \
+       STORE = VALUE;                                                    \
+    if (TYPE != INRANGE)                                                 \
+       break;  /* don't set y range if x is outrange, for example */     \
+    if ((int)AXIS < 0)                                                   \
+       break;  /* HBB 20000507: don't check range if not a coordinate */ \
+    if ( VALUE<axis_array[AXIS].data_min )                               \
+       axis_array[AXIS].data_min = VALUE;                                \
+    if ( VALUE<axis_array[AXIS].min ) {                                          \
+       if (axis_array[AXIS].autoscale & AUTOSCALE_MIN)                   \
+           axis_array[AXIS].min = VALUE;                                 \
+       else {                                                            \
+           TYPE = OUTRANGE;                                              \
+           OUT_ACTION;                                                   \
+           break;                                                        \
+       }                                                                 \
+    }                                                                    \
+    if ( VALUE>axis_array[AXIS].data_max )                               \
+       axis_array[AXIS].data_max = VALUE;                                \
+    if ( VALUE>axis_array[AXIS].max ) {                                          \
+       if (axis_array[AXIS].autoscale & AUTOSCALE_MAX)                   \
+           axis_array[AXIS].max = VALUE;                                 \
+       else {                                                            \
+           TYPE = OUTRANGE;                                              \
+           OUT_ACTION;                                                   \
+       }                                                                 \
+    }                                                                    \
+} while(0)
+
+/* Implementation of the above for the color axis. It should not change
+ * the type of the point (out-of-range color is plotted with the color
+ * of the min or max color value).
+ */
+#define COLOR_STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, TYPE, AXIS,          \
+                                      OUT_ACTION, UNDEF_ACTION)          \
+{                                                                        \
+    int c_type_tmp = TYPE;                                               \
+    STORE_WITH_LOG_AND_UPDATE_RANGE(STORE, VALUE, c_type_tmp, AXIS,      \
+                                      OUT_ACTION, UNDEF_ACTION);         \
+}
+
+/* Empty macro arguments triggered NeXT cpp bug       */
+/* #define NOOP (0) caused many warnings from gcc 3.2 */
+/* Now trying ((void)0) */
+#define NOOP ((void)0)
+
+/* HBB 20000506: new macro, initializes one variable to the same
+ * value, for all axes. */
+#define INIT_AXIS_ARRAY(field, value)          \
+do {                                           \
+    int tmp;                                   \
+    for (tmp=0; tmp<AXIS_ARRAY_SIZE; tmp++)    \
+       axis_array[tmp].field=(value);          \
+} while(0)
+
+/* HBB 20000506: new macro to automatically build intializer lists
+ * for arrays of AXIS_ARRAY_SIZE equal elements */
+#define AXIS_ARRAY_INITIALIZER(value) {                        \
+    value, value, value, value, value,                 \
+       value, value, value, value, value, value }
+
+/* used by set.c */
+#define SET_DEFFORMAT(axis, flag_array)                                \
+       if (flag_array[axis]) {                                 \
+           (void) strcpy(axis_array[axis].formatstring,DEF_FORMAT);    \
+           axis_array[axis].format_is_numeric = 1;             \
+       }
+
+
+/* 'roundoff' check tolerance: less than one hundredth of a tic mark */
+#define SIGNIF (0.01)
+/* (DFK) Watch for cancellation error near zero on axes labels */
+/* FIXME HBB 20000521: these seem not to be used much, anywhere... */
+#define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
+
+
+/* ------------ functions exported by axis.c */
+t_autoscale load_range __PROTO((AXIS_INDEX, double *, double *, t_autoscale));
+void axis_unlog_interval __PROTO((AXIS_INDEX, double *, double *, TBOOLEAN));
+void axis_revert_and_unlog_range __PROTO((AXIS_INDEX));
+double axis_log_value_checked __PROTO((AXIS_INDEX, double, const char *));
+void axis_checked_extend_empty_range __PROTO((AXIS_INDEX, const char *mesg));
+char * copy_or_invent_formatstring __PROTO((AXIS_INDEX));
+double quantize_normal_tics __PROTO((double, int));
+void setup_tics __PROTO((AXIS_INDEX, int));
+void gen_tics __PROTO((AXIS_INDEX, /* int, */ tic_callback));
+void axis_output_tics __PROTO((AXIS_INDEX, int *, AXIS_INDEX, tic_callback));
+void axis_set_graphical_range __PROTO((AXIS_INDEX, unsigned int lower, unsigned int upper));
+void axis_draw_2d_zeroaxis __PROTO((AXIS_INDEX, AXIS_INDEX));
+TBOOLEAN some_grid_selected __PROTO((void));
+void add_tic_user __PROTO((AXIS_INDEX, char *, double, int));
+
+double get_writeback_min __PROTO((AXIS_INDEX));
+double get_writeback_max __PROTO((AXIS_INDEX));
+void set_writeback_min __PROTO((AXIS_INDEX));
+void set_writeback_max __PROTO((AXIS_INDEX));
+
+/* set widest_tic_label: length of the longest tics label */
+void widest_tic_callback __PROTO((AXIS_INDEX, double place, char *text, struct lp_style_type grid));
+
+void get_position __PROTO((struct position *pos));
+void get_position_default __PROTO((struct position *pos, enum position_type default_type));
+
+/* ------------ autoscaling of the color axis */
+#define NEED_PALETTE(plot) \
+   (PM3DSURFACE == (plot)->plot_style \
+    || PM3D_IMPLICIT == pm3d.implicit \
+    || 1 == (plot)->lp_properties.use_palette)
+int set_cbminmax __PROTO((void));
+
+#endif /* GNUPLOT_AXIS_H */