/* $Id: Gnuplot.h,v 1.7 2002/06/09 18:49:11 karim Exp $

Copyright (C) 2000  The PARI group.

This file is part of the PARI/GP package.

PARI/GP is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation. It is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY WHATSOEVER.

Check the License for details. You should have received a copy of it, along
with the package; see the file 'COPYING'. If not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */

/* This header should be included in one C file only! */

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

#ifdef __cplusplus
  extern "C" {
#endif

/* CAT2:
 *      This macro catenates 2 tokens together.
 */
/* STRINGIFY:
 *      This macro surrounds its token with double quotes.
 */
#ifndef CAT2
# if 42 == 1
#  define CAT2(a,b)a/**/b
#  define CAT3(a,b,c)a/**/b/**/c
#  define CAT4(a,b,c,d)a/**/b/**/c/**/d
#  define CAT5(a,b,c,d,e)a/**/b/**/c/**/d/**/e
#  define STRINGIFY(a)"a"
                /* If you can get stringification with catify, tell me how! */
# endif
# if 42 == 42
#  define CAT2(a,b)a ## b
#  define CAT3(a,b,c)a ## b ## c
#  define CAT4(a,b,c,d)a ## b ## c ## d
#  define CAT5(a,b,c,d,e)a ## b ## c ## d ## e
#  define StGiFy(a)# a
#  define STRINGIFY(a)StGiFy(a)
#  define SCAT2(a,b)StGiFy(a) StGiFy(b)
#  define SCAT3(a,b,c)StGiFy(a) StGiFy(b) StGiFy(c)
#  define SCAT4(a,b,c,d)StGiFy(a) StGiFy(b) StGiFy(c) StGiFy(d)
#  define SCAT5(a,b,c,d,e)StGiFy(a) StGiFy(b) StGiFy(c) StGiFy(d) StGiFy(e)
# endif
# ifndef CAT2
#   include "Bletch: How does this C preprocessor catenate tokens?"
# endif
#endif /* CAT2 */


#define TERM_CAN_MULTIPLOT    1  /* tested if stdout not redirected */
#define TERM_CANNOT_MULTIPLOT 2  /* tested if stdout is redirected  */
#define TERM_BINARY           4  /* open output file with "b"       */

#ifndef NO_JUNK_SMALL

/* Compatibility with the old gnuplot: */
extern  FILE *outfile;
FILE *outfile = NULL;

extern  FILE *gpoutfile;
FILE *gpoutfile = NULL;

static outfile_set;
static void
set_gpoutfile(void)
{
  outfile = stdout;
  gpoutfile = stdout;
}

#define SET_OUTFILE (outfile_set++ ? 1 : (set_gpoutfile(), 1))

extern int encoding;
int        encoding = 0;
extern float                   xoffset;  /* x origin */
extern float                   yoffset;  /* y origin */
float                   xoffset = 0.0;  /* x origin */
float                   yoffset = 0.0;  /* y origin */
extern int		multiplot;
int		multiplot		= 0;

extern char *outstr;
#define MAX_ID_LEN 50
/* char        outstr[MAX_ID_LEN+1] = "STDOUT"; */
char        *outstr = NULL;
extern double ticscale; /* scale factor for tic marks (was (0..1])*/
double        ticscale = 1.0; /* scale factor for tic mark */

char *input_line = NULL;
int inline_num;          /* from command.c */

float xsize=1.0, ysize=1.0;
double pointsize=1.0;		/* During test! */

int interactive;    /* from plot.c */
char *infile_name;       /* from plot.c */
extern char     default_font[];
char            default_font[MAX_ID_LEN+1] = "\0"; /* Entry added by DJL */

typedef int TBOOLEAN;

enum DATA_TYPES {
	INTGR, CMPLX
};

#if !(defined(ATARI)&&defined(__GNUC__)&&defined(_MATH_H)) &&  !(defined(MTOS)&&defined(__GNUC__)&&defined(_MATH_H)) /* FF's math.h has the type already */
struct cmplx {
	double real, imag;
};
#endif

struct value {
	enum DATA_TYPES type;
	union {
		int int_val;
		struct cmplx cmplx_val;
	} v;
};

struct lexical_unit {	/* produced by scanner */
	TBOOLEAN is_token;	/* true if token, false if a value */
	struct value l_val;
	int start_index;	/* index of first char in token */
	int length;			/* length of token in chars */
};

/* char *token; */
#define MAX_TOKENS 20
extern struct lexical_unit *token;
struct lexical_unit tokens[MAX_TOKENS];	/* We only process options,
					   there should not be many */
struct lexical_unit *token = tokens;
long c_token = 0, num_tokens = 0;
char term_options[200] = "";

/* New with 3.7.1: */

#define FIRST_Z_AXIS 0
#define FIRST_Y_AXIS 1
#define FIRST_X_AXIS 2
#define SECOND_Z_AXIS 4 /* for future expansion ;-) */
#define SECOND_Y_AXIS 5
#define SECOND_X_AXIS 6
/* extend list for datatype[] for t,u,v,r though IMHO
 * they are not relevant to time data [being parametric dummies]
 */
#define T_AXIS 3  /* fill gap */
#define R_AXIS 7  /* never used ? */
#define U_AXIS 8
#define V_AXIS 9

#define AXIS_ARRAY_SIZE 10
#define DATATYPE_ARRAY_SIZE 10

extern double base_array[], log_base_array[];
extern TBOOLEAN log_array[];
/* graphics.c */
extern TBOOLEAN is_3d_plot;

double min_array[AXIS_ARRAY_SIZE], max_array[AXIS_ARRAY_SIZE], base_array[AXIS_ARRAY_SIZE], log_base_array[AXIS_ARRAY_SIZE];
TBOOLEAN log_array[AXIS_ARRAY_SIZE];
int xleft, xright, ybot, ytop;
TBOOLEAN is_3d_plot;

/* End of 3.7.1 additions */

/* 3.7.0-devel additions */

extern float surface_rot_z;
extern TBOOLEAN polar;
extern double			base_log_x, base_log_y, base_log_z;
extern TBOOLEAN			is_log_x, is_log_y, is_log_z;
extern double			log_base_log_x2, log_base_log_y2;
extern double base_z;
extern TBOOLEAN screen_ok;

float surface_rot_z = 30.0;
TBOOLEAN polar = 0;
TBOOLEAN is_log_x = 0;
TBOOLEAN is_log_y = 0;
TBOOLEAN is_log_z = 0;
double base_log_x = 0.0;
double base_log_y = 0.0;
double base_log_z = 0.0;
double log_base_log_x = 0.0;
double log_base_log_y = 0.0;
double log_base_log_z = 0.0;
double base_z = 0.0;
TBOOLEAN screen_ok;

void map3d_xy (double x, double y, double z, unsigned int *xt, unsigned int *yt)
{
    croak("Unsupported function map3d_xy called");
}

/* End of 3.7.0-devel additions */

/* Here are the only missing functions: */

struct value*
const_express(struct value*v)
{
    if (token[c_token].is_token)
	croak("Expect a number, got a string");
    *v = token[c_token++].l_val;
    return v;
}

void*
gp_alloc(unsigned long size, char *usage)
{
  (void)usage;
  return malloc(size);
}

void*
gp_realloc(void *old, unsigned long size, char *usage)
{
  (void)usage;
  return realloc(old,size);
}

void
bail_to_command_line()
{
  croak("panic: gnuplot");
}

#endif	/* NO_JUNK_SMALL */ 

/* Cannot pull the whole plot.h, too many contradictions. */

#ifdef __ZTC__
typedef int (*FUNC_PTR)(...);
#else
typedef int (*FUNC_PTR)();
#endif

struct TERMENTRY {
        char *name;
#if defined(_Windows) && !defined(WIN32)
        char GPFAR description[80];     /* to make text go in FAR segment */
#else
        char *description;
#endif
        unsigned int xmax,ymax,v_char,h_char,v_tic,h_tic;
        FUNC_PTR options,init,reset,text,scale,graphics,move,vector,linetype,
                put_text,text_angle,justify_text,point,arrow,set_font,
		pointsize;
	int flags;
        FUNC_PTR suspend,resume,fillbox,linewidth;
};

#ifdef _Windows
#  define termentry TERMENTRY far
#else
#  define termentry TERMENTRY
#endif

extern struct termentry *term;
struct termentry *term;

#define RETVOID
#define RETINT , 1

#define F_0 void(*)()
#define F_1 void(*)(int)
#define F_1I int(*)(int)
#define F_1D void(*)(double)
#define F_1IP int(*)(char*)
#define F_2 void(*)(unsigned int,unsigned int)
#define F_2D int(*)(double,double)
#define F_3 void(*)(unsigned int,unsigned int,int)
#define F_3T void(*)(int,int,char*)
#define F_4 void(*)(int,int,int,int)
#define F_5 void(*)(int,int,int,int,int)

#define CALL_G_METH0(method) CALL_G_METH(method,0,(),RETVOID)
#define CALL_G_METH1(method,arg1) CALL_G_METH(method,1,(arg1),RETVOID)
#define CALL_G_METH1I(method,arg1) CALL_G_METH(method,1I,(arg1),RETINT)
#define CALL_G_METH1D(method,arg1) CALL_G_METH(method,1D,(arg1),RETVOID)
#define CALL_G_METH1IP(method,arg1) CALL_G_METH(method,1IP,(arg1),RETINT)
#define CALL_G_METH2(method,arg1,arg2) \
		CALL_G_METH(method,2,((arg1),(arg2)),RETVOID)
#define CALL_G_METH2D(method,arg1,arg2) \
		CALL_G_METH(method,2D,((arg1),(arg2)),RETINT)
#define CALL_G_METH3(method,arg1,arg2,arg3) \
		CALL_G_METH(method,3,((arg1),(arg2),(arg3)),RETVOID)
#define CALL_G_METH3T(method,arg1,arg2,arg3) \
		CALL_G_METH(method,3T,((arg1),(arg2),(arg3)),RETVOID)
#define CALL_G_METH4(method,arg1,arg2,arg3,arg4) \
		CALL_G_METH(method,4,((arg1),(arg2),(arg3),(arg4)),RETVOID)
#define CALL_G_METH5(method,arg1,arg2,arg3,arg4,arg5) \
		CALL_G_METH(method,5,((arg1),(arg2),(arg3),(arg4),(arg5)),RETVOID)

#define CALL_G_METH(method,mult,args,returnval)    (		\
       (term==0) ? (						\
	 croak("No terminal specified") returnval		\
       ) :							\
       (*(CAT2(F_,mult))term->method)args		\
     )

#define GET_G_FLAG(mask)    (		\
       (term==0) ? (						\
	 croak("No terminal specified") RETINT		\
       ) :							\
       (term->flags & (mask)))

#ifdef DONT_POLLUTE_INIT
#  define gptable_init()	CALL_G_METH0(init)
#else
#  define init()		CALL_G_METH0(init)
#  define gptable_init		init
#endif
#define reset()		CALL_G_METH0(reset)
#define text()		CALL_G_METH0(text)
#define options()	CALL_G_METH0(options)
#define graphics()	CALL_G_METH0(graphics)
#define linetype(lt)	CALL_G_METH1(linetype,lt)
#define justify_text(mode)	CALL_G_METH1I(justify_text,mode)
#define text_angle(ang)	CALL_G_METH1I(text_angle,ang)
#define scale(xs,ys)	CALL_G_METH2D(scale,xs,ys)
#define move(x,y)	CALL_G_METH2(move,x,y)
#define vector(x,y)	CALL_G_METH2(vector,x,y)
#define put_text(x,y,str)	CALL_G_METH3T(put_text,x,y,str)
#define point(x,y,p)	CALL_G_METH3(point,x,y,p)
#define arrow(sx,sy,ex,ey,head)	CALL_G_METH5(arrow,sx,sy,ex,ey,head)
#define set_font(font)	CALL_G_METH1IP(set_font,font)
#define setpointsize(size)	CALL_G_METH1D(pointsize,size)
#define suspend()	CALL_G_METH0(suspend)
#define resume()	CALL_G_METH0(resume)
#define fillbox(sx,sy,ex,ey,head)	CALL_G_METH5(fillbox,sx,sy,ex,ey,head)
#define linewidth(size)	CALL_G_METH1D(linewidth,size)
#define can_multiplot()	GET_G_FLAG(TERM_CAN_MULTIPLOT)
#define cannot_multiplot()	GET_G_FLAG(TERM_CANNOT_MULTIPLOT)
#define is_binary()	GET_G_FLAG(TERM_BINARY)

#define termprop(prop) (term->prop)
#define termset(term) my_change_term(term,strlen(term))

struct termentry * change_term(char*,int);

#define TTABLE_STARTPLOT	0
#define TTABLE_ENDPLOT		1
#define TTABLE_STARTMPLOT	2
#define TTABLE_ENDMPLOT		3
#define TTABLE_INIT		4
#define TTABLE_LIST		5
#define TTABLE_COUNT		6

typedef void (*TSET_FP)(char *s);
typedef void (*TST_END_FP)(void);
typedef void (*SET_SIZES_t)(double x, double y);
typedef double (*GET_SIZES_t)(int flag);
typedef void (*SET_MOUSE_FEEDBACK_RECTAGLE_t)(int term_xmin, int term_xmax, 
			     int term_ymin, int term_ymax,
			     double plot_xmin, double plot_xmax,
			     double plot_ymin, double plot_ymax);

struct t_ftable {
  int loaded;
  FUNC_PTR change_term_p;
  TSET_FP term_set_outputp;
  SET_SIZES_t set_sizesp;
  GET_SIZES_t get_sizesp;
  TST_END_FP term_funcs[TTABLE_COUNT];
  SET_MOUSE_FEEDBACK_RECTAGLE_t mouse_feedback_func;
};

#ifdef DYNAMIC_PLOTTING			/* Can load plotting DLL later */

int
UNKNOWN_null()
{
    croak("gnuplot-like plotting environment not loaded yet");
    return 0;
}

static void myterm_table_not_loaded_v(void);
static void myterm_table_not_loaded(char*);
static int myterm_table_not_loaded_u();
static void myterm_table_not_loaded_vdd(double x, double y);
static double myterm_table_not_loaded_di(int flag);
static void myterm_table_not_loaded_v4i4d(int term_xmin, int term_xmax, 
			     int term_ymin, int term_ymax,
			     double plot_xmin, double plot_xmax,
			     double plot_ymin, double plot_ymax);
#if 0
static int ftable_warned;
static void
tmp_my_term_init
{
  if (!warned++)
     warn("This runtime link with gnuplot-shim does not implement midlevel start/end functions");
  shim_myinit();
}
#endif

static struct t_ftable my_term_ftable = 
{
	0, &myterm_table_not_loaded_u, &myterm_table_not_loaded,
	&myterm_table_not_loaded_vdd,
	&myterm_table_not_loaded_di,
	{&myterm_table_not_loaded_v, &myterm_table_not_loaded_v, 
	 &myterm_table_not_loaded_v, &myterm_table_not_loaded_v,
	 &myterm_table_not_loaded_v, &myterm_table_not_loaded_v},
	myterm_table_not_loaded_v4i4d
};

static struct t_ftable *my_term_ftablep = &my_term_ftable;

static void
myterm_table_not_loaded_v(void)
{
    if (!my_term_ftablep->loaded) {
        UNKNOWN_null();
	return;
    }
    croak("This runtime link with gnuplot-shim does not implement midlevel start/end functions");
}

static void
myterm_table_not_loaded(char *s)
{
  myterm_table_not_loaded_v();
}

static void
myterm_table_not_loaded_vdd(double x, double y)
{
  myterm_table_not_loaded_v();
}

static double
myterm_table_not_loaded_di(int flag)
{
  myterm_table_not_loaded_v();
  return 0;			/* NOT REACHED */
}

static int
myterm_table_not_loaded_u()
{
  myterm_table_not_loaded_v();
  return 0;
}

void myterm_table_not_loaded_v4i4d(int term_xmin, int term_xmax, 
			     int term_ymin, int term_ymax,
			     double plot_xmin, double plot_xmax,
			     double plot_ymin, double plot_ymax)
{
  myterm_table_not_loaded_v();
}

#  define change_term		(*my_term_ftablep->change_term_p)
#  define term_set_output	(*my_term_ftablep->term_set_outputp)
#  define term_start_plot	(*my_term_ftablep->term_funcs[TTABLE_STARTPLOT])
#  define term_end_plot	(*my_term_ftablep->term_funcs[TTABLE_ENDPLOT])
#  define term_start_multiplot	(*my_term_ftablep->term_funcs[TTABLE_STARTMPLOT])
#  define term_end_multiplot	(*my_term_ftablep->term_funcs[TTABLE_ENDMPLOT])
#  define term_init		(*my_term_ftablep->term_funcs[TTABLE_INIT])
#  define list_terms		(*my_term_ftablep->term_funcs[TTABLE_LIST])
#  define plotsizes_scale	(*my_term_ftablep->set_sizesp)
#  define plotsizes_scale_get	(*my_term_ftablep->get_sizesp)

#ifdef USE_SET_FEEDBACK_RECTANGLE
/* If DLL has it, but was compiled with older Gnuplot.h */
#  define set_mouse_feedback_rectangle	(*my_term_ftablep->mouse_feedback_func)
#else
#  define set_mouse_feedback_rectangle(term_xmin, term_xmax, term_ymin, term_ymax, plot_xmin, plot_xmax, plot_ymin, plot_ymax)	\
	((my_term_ftablep->loaded & 2) ?	\
	 ((*my_term_ftablep->mouse_feedback_func)(term_xmin, term_xmax, term_ymin, term_ymax, plot_xmin, plot_xmax, plot_ymin, plot_ymax), 0) : 0)
#endif	/* defined USE_SET_FEEDBACK_RECTANGLE */

#  define scaled_xmax()	((int)termprop(xmax)*plotsizes_scale_get(0))
#  define scaled_ymax()	((int)termprop(ymax)*plotsizes_scale_get(1))

#define USE_FUNCTION_FROM_TABLE

static struct termentry *
my_change_term(char*s,int l)
{
    SET_OUTFILE;
    if (!my_term_ftablep->change_term_p)
	UNKNOWN_null();
    return term = (struct termentry *)(*my_term_ftablep->change_term_p)(s,l);
}

#if 0
static struct termentry dummy_term_tbl[] = {
    {"unknown", "Unknown terminal type - not a plotting device",
	  100, 100, 1, 1,
	  1, 1, UNKNOWN_null, UNKNOWN_null, UNKNOWN_null,
	  UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, UNKNOWN_null,
	  UNKNOWN_null, UNKNOWN_null, UNKNOWN_null,
     UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, 0,
	  UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, UNKNOWN_null},
};
#endif

#define set_term_funcp(change_p, term_p) set_term_funcp2((change_p), 0)
/* #define set_term_funcp3(change_p, term_p, tchange) \
			set_term_funcp2((change_p), (tchange)) */

/* This function should be called before any graphic code can be used... */
void
set_term_funcp2(FUNC_PTR change_p, TSET_FP tchange)
{
    SET_OUTFILE;
    my_term_ftable.change_term_p = change_p;
    my_term_ftable.loaded = 1;
    if (tchange) {
	my_term_ftable.term_set_outputp = tchange;
    }
}

/* Used from Math::Pari */
void
set_term_funcp3(FUNC_PTR change_p, void *term_p, TSET_FP tchange)
{
  set_term_funcp2(change_p, tchange);
}

void
set_term_ftable(struct t_ftable *p)
{
  SET_OUTFILE;
  my_term_ftablep = p;
}

extern struct t_ftable *get_term_ftable();

#else /* !DYNAMIC_PLOTTING */
#define set_mouse_feedback_rectangle  mys_mouse_feedback_rectangle

extern struct termentry term_tbl[];
extern double min_array[], max_array[];
extern int xleft, xright, ybot, ytop;

void
mys_mouse_feedback_rectangle(int term_xmin, int term_xmax, 
			     int term_ymin, int term_ymax,
			     double plot_xmin, double plot_xmax,
			     double plot_ymin, double plot_ymax)
{
  xleft = term_xmin, xright = term_xmax;
  ybot = term_ymin, ytop = term_ymax;
  min_array[FIRST_X_AXIS] = min_array[SECOND_X_AXIS] = plot_xmin;
  max_array[FIRST_X_AXIS] = max_array[SECOND_X_AXIS] = plot_xmax;
  min_array[FIRST_Y_AXIS] = min_array[SECOND_Y_AXIS] = plot_ymin;
  max_array[FIRST_Y_AXIS] = max_array[SECOND_Y_AXIS] = plot_ymax;
}

#  define my_change_term	change_term
#  define my_term_tbl		term_tbl

extern void term_set_output(char *s);
extern void term_start_plot(void);
extern void term_end_plot(void);
extern void term_start_multiplot(void);
extern void term_end_multiplot(void);
extern void term_init(void);
extern void list_terms(void);

static void
plotsizes_scale(double x, double y)	{ xsize=x; ysize=y; }

static double
plotsizes_get(int flag)	{ return (flag ? ysize : xsize); }

struct t_ftable my_term_ftable =
{
	2,		/* bit 2 means it has mys_mouse_feedback_rectangle */
	(FUNC_PTR)&change_term, &term_set_output,
	&plotsizes_scale, &plotsizes_get,
	{&term_start_plot, &term_end_plot, 
	 &term_start_multiplot, &term_end_multiplot, &term_init, &list_terms},
	&mys_mouse_feedback_rectangle
};

struct t_ftable *get_term_ftable()	{ SET_OUTFILE; return &my_term_ftable; }
void set_term_ftable()	{ SET_OUTFILE; }

void
set_term_funcp3(FUNC_PTR change_p, void *term_p, TSET_FP tchange)
{
    SET_OUTFILE;
    (void)term_p;
    my_term_ftable.change_term_p = change_p;
    my_term_ftable.loaded = 1;
    if (tchange) {
	my_term_ftable.term_set_outputp = tchange;
    }
}

#define scaled_xmax()	((int)termprop(xmax)*xsize)
#define scaled_ymax()	((int)termprop(ymax)*ysize)

#endif /* !DYNAMIC_PLOTTING */

#define int_get_term_ftable()	((IV)get_term_ftable())
#define int_set_term_ftable(a) (v_set_term_ftable((void*)a))

void
v_set_term_ftable(void *a) { set_term_ftable((struct t_ftable*)a); }

typedef void (*set_term_ftable_t)(struct t_ftable *p);
typedef struct t_ftable *(get_term_ftable_t)(void);

extern get_term_ftable_t *get_term_ftable_get(void);

static int shim_set;

void
setup_gpshim(void) {
#if 0
  if (shim_set++)
    return;
#endif

  if (!shim_set++) {
#ifdef DYNAMIC_PLOTTING_RUNTIME_LINK
    get_term_ftable_t *f = get_term_ftable_get(); /* Resolve the getter */

    if (f)
	v_set_term_ftable(f());			/* Get the external table */
#endif

#ifdef DYNAMIC_PLOTTING_STATIC_LINK
    void *a = get_term_ftable();		/* Get the external one */
    v_set_term_ftable(get_term_ftable());
#endif
  }
  SET_OUTFILE;
}

#ifdef SET_OPTIONS_FROM_STRING
/* This sets the tokens for the options */
void
set_tokens_string(char *start)
{
    char *s = start;
    char *tstart;
    int is_real, is_integer, has_exp;
    
    num_tokens = 0;
    while (num_tokens < MAX_TOKENS) {
	while (*s == ' ' || *s == '\t' || *s == '\n')
	    s++;
	if (!*s)
	    return;
	tstart = s;
	if (*s == ',') {
	    s++;
	    is_integer = is_real = 0;
	    goto process;
	}
	is_integer = is_real = ((*s) != 0);
	if (*s == '+' || *s == '-')
	    s++;
	has_exp = 0;
	while (*s && !(*s == ' ' || *s == '\t' || *s == '\n')) {
	    if (!(*s <= '9' && *s >= '0')) {
		if (*s == '.') {		
		    if (!is_integer)
			is_real = 0;
		    else if (is_integer == 1 && !(s[1] <= '9' && s[1] >= '0'))
			is_real = 0;
		} else if (*s == 'e' || *s == 'E') {
		    if (has_exp)
			is_real = 0;
		    has_exp = 1;
		    if (s[1] == '+' || s[1] == '-')
			s++;
		} else if (*s == ',' && (is_integer || is_real))
		    break;
		else
		    is_real = 0;
		is_integer = 0;
	    } else if (is_integer)
		is_integer++;
	    s++;	    
	}
      process:
	token[num_tokens].start_index = tstart - input_line;
	token[num_tokens].length = s - tstart;
	if (is_integer) {
	    token[num_tokens].is_token = 0;
	    token[num_tokens].l_val.type = INTGR;
	    token[num_tokens].l_val.v.int_val = atoi(tstart);
	} else if (is_real) {
	    token[num_tokens].is_token = 0;
	    token[num_tokens].l_val.type = CMPLX;
	    token[num_tokens].l_val.v.cmplx_val.real = atof(tstart);
	    token[num_tokens].l_val.v.cmplx_val.imag = 0;
	} else {
	    token[num_tokens].is_token = 1;
	}
	num_tokens++;
    }
    if (num_tokens >= MAX_TOKENS) {
	char buf[80];
	sprintf(buf, "panic: more than %d tokens for options", MAX_TOKENS);
	croak(buf);    
    }
}

void
set_options_from(char *s)
{
    char *o = input_line;

    input_line = s;		/* for error reports */
    set_tokens_string(s);
    options();
    input_line = o;
    c_token = num_tokens = 0;
}
#endif

#ifdef GNUPLOT_OUTLINE_STDOUT
int
StartOutput() { return 0; }

int
EndOutput() { return 0; }

int
OutLine(char *s)
{
   return fprintf(stdout, "%s", s);
}
#endif

#ifdef __cplusplus
  }
#endif
