[alt.sources] Fchart part 02/04

fs@uwasa.fi (Filip Sawicki LAKE) (06/04/90)

Submitted-by: fs@chyde
Archive-name: Fchart/part02

#!/bin/sh
# This is part 02 of Fchart
if touch 2>&1 | fgrep '[-amc]' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= fcmd.c ==============
echo "x - extracting fcmd.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > fcmd.c &&
X/* Fchart - fcmd.c */
X/*
X * Gnuplot code
X * Copyright (C) 1986, 1987, 1990   Thomas Williams, Colin Kelley
X *
X * Permission to use, copy, and distribute this software and its
X * documentation for any purpose with or without fee is hereby granted,
X * provided that the above copyright notice appear in all copies and
X * that both that copyright notice and this permission notice appear
X * in supporting documentation.
X *
X * Permission to modify the software is granted, but not the right to
X * distribute the modified code.  Modifications are to be distributed
X * as patches to released version.
X *
X * This software  is provided "as is" without express or implied warranty.
X *
X *
X * AUTHORS
X *
X *   Original Software:
X *     Thomas Williams,  Colin Kelley.
X *
X *   Gnuplot 2.0 additions:
X *       Russell Lang, Dave Kotz, John Campbell.
X *
X *   Fchart changes and additions:
X *       Piotr Filip Sawicki
X *
X * send your comments or suggestions to fs@uwasa.fi
X *
X */
X#include <stdio.h>
X#include <math.h>
X#include <ctype.h>
X
X#ifdef MSDOS
X#include <process.h>
X
X#ifdef __ZTC__
X#define P_WAIT 0
X#include <time.h>       /* usleep() */
X#else
X
X#ifdef __TURBOC__
X#include <dos.h>        /* sleep() */
X
X#else   /* must be MSC */
X#include <time.h>       /* kludge to provide sleep() */
Xvoid sleep();           /* defined later */
X#endif /* TURBOC */
X#endif /* ZTC */
X
X#endif /* MSDOS */
X
X#include "plot.h"
X#include "fchart.h"
X#include "help.h"
X
X#ifndef STDOUT
X#define STDOUT 1
X#endif
X
X#ifndef HELPFILE
X#define HELPFILE "fchart.gih" /* changed by makefile */
X#endif
X
X/* global defs for default values */
X#define DEF_T_FORMAT "%g"	/* make it as narrow as possible */
X#define EXPL_RAD 0.3		/* ratio of explosion of a slice */
X#define MAXBARWIDTH 0.2		/* default maximal allowable width of bar */
X#define INTERBAR 0.2		/* interbar space in terms of real bar width */
X#define INTERGROUP 0.5		/* space between groups of bars */
X#define OTHER "other"		/* name for combined slice */
X
X/*
X * global variables to hold status of 'set' options
X *
X */
X
XBOOLEAN			autoscale	= TRUE,
X				auto_label	= FALSE,
X				p_clockwise	= TRUE,
X				b_clockwise = TRUE,
X				draw_border = TRUE;
X
Xenum DRAW_STYLE data_style	= ABARS;
Xenum GRAV_DIR	gravity		= SOUTH,
X				explode		= DEFAULT;
Xenum INP_STYLE	inp_style	= PRIVATE;
Xenum FONT_STYLE	vect_font	= F_WHENN;
XBOOLEAN			log_y		= FALSE;
XFILE*			outfile;
Xchar			outstr[MAX_LINE_LEN+1] = "STDOUT";
Xint				samples		= SAMPLES;
Xint				term		= 0;			/* unknown term is 0 */
Xint				xmin		= -1,
X				xmax		= -1;
Xdouble			base		= 0.0;
Xdouble			loff		= 0.0,
X				roff		= 0.0,
X				toff		= 0.0,
X				boff		= 0.0;
Xdouble			b_wid		= MAXBARWIDTH,
X				b_int		= INTERBAR,
X				b_spc		= INTERGROUP;
Xdouble			radexp		= EXPL_RAD;		/* explosion power */
Xdouble			zero		= ZERO;			/* zero threshold, not 0! */
Xint				HLitem		= HL_NON;		/* no highliting by default */
Xstruct pair		data_place	= { -1, -1 },	/* not defined yet */
X				label_plac	= { -1, -1 };	/* not defined yet */
Xfloat			xsize		= 1.0,
X				ysize		= 1.0;
Xdouble			treshold	= 0.0;
Xchar			thrname[MAX_LINE_LEN+1] = OTHER;
Xchar 			tic_form[MAX_LINE_LEN+1]	= DEF_T_FORMAT;
Xint				strunc		= -1;
X
Xstruct dfile data_head = { NULL, 0.0, 0.0, 0, 0, HL_NON, FALSE, NULL, NULL } ;
X
XBOOLEAN screen_ok;
XBOOLEAN term_init;
X/* BOOLEAN undefined; */  /* probably not even used */
X
X/*
X * instead of <strings.h>
X */
X
Xchar *gets(),*getenv(),*sprintf();	/* for lint only */
Xchar *strcpy(),*strncpy(),*strcat();
X
Xextern double real();
Xextern void set_label(), set_nolabel(), set_arrow(), set_noarrow();
Xextern void show_labels(), show_arrow();
X
Xextern struct termentry term_tbl[];
X
Xstruct lexical_unit token[MAX_TOKENS];
Xchar input_line[MAX_LINE_LEN+1] = "";
Xint num_tokens, c_token;
X
Xstatic char replot_line[MAX_LINE_LEN+1];
Xstatic int plot_token;					/* start of 'plot' command */
X
Xextern void squash_spaces(), lower_case();
X
Xcom_line()
X{
X	read_line(PROMPT);
X
X	screen_ok = interactive;		/* see 'Gnuplot' why */
X
X	do_line();
X}
X
X
Xdo_line()	  /* also used in load_file */
X{
X	if (is_system(input_line[0])) {
X		do_system();
X		fputs("!\n",stderr);
X		return;
X	}
X	num_tokens = scanner(input_line);
X	c_token = 0;
X	while(c_token < num_tokens) {
X		command();
X		if (c_token < num_tokens)	/* something after command */
X			if (equals(c_token,";"))
X				c_token++;
X			else
X					int_error("';' expected",c_token);
X	}
X}
X
Xcommand()
X{
X	static char sv_file[MAX_LINE_LEN+1];
X			/* string holding name of save or load file */
X
X	if (equals(c_token,"help") || equals(c_token,"?")) {
X		c_token++;
X		do_help();
X	}
X	else if (almost_equals(c_token,"test")) {
X		c_token++;
X		term_test();
X	}
X	else if (almost_equals(c_token,"pa$use")) {
X		int stime=1, text=0;
X		char buf[MAX_LINE_LEN+1];
X
X		c_token++;
X		if (equals(c_token,"-")) stime=-1, c_token++;
X		stime *= (int)real(c_token);
X		c_token++;
X		if (!(END_OF_COMMAND)) {
X			if (!isstring(c_token))
X				int_error("expecting string",c_token);
X			else {
X				quote_str(buf,c_token);
X				fprintf (stderr, "%s",buf);
X				text = 1;
X			}
X		}
X		if (stime < 0) fgets (buf,MAX_LINE_LEN,stdin);  /* Hold until CR hit */
X#ifdef __ZTC__
X		if (stime > 0) usleep((unsigned long) stime);
X#else		
X		if (stime > 0) sleep((unsigned) stime);
X#endif
X		if (text != 0 && stime >= 0) fprintf (stderr,"\n");
X		c_token++;
X		screen_ok = FALSE;
X	}
X	else if (almost_equals(c_token,"p$lot") ||
X			 almost_equals(c_token,"d$raw")) {
X		plot_token = c_token++;
X		plotrequest(FALSE);
X	}
X	else if (almost_equals(c_token,"tp$lot") ||
X			 almost_equals(c_token,"td$raw") ||
X			 almost_equals(c_token,"xp$lot") ||		/* for backward compatibility */
X			 almost_equals(c_token,"xd$raw") ||		/* for backward compatibility */
X			 almost_equals(c_token,"trans_plot") ||
X			 almost_equals(c_token,"trans_draw")) {
X		plot_token = c_token++;
X		plotrequest(TRUE);
X	}
X	else if (almost_equals(c_token,"rep$lot") ||
X			 almost_equals(c_token,"red$raw")) {
X		c_token++;
X		if (replot_line[0] == '\0') 
X			int_error("no previous plot",c_token);
X		if (!END_OF_COMMAND) {
X			char str[MAX_LINE_LEN+1];
X			capture(str,c_token,num_tokens-1);
X			if ((strlen(str)+strlen(input_line)) <= MAX_LINE_LEN-1) {
X				(void) strcat(replot_line,",");
X				(void) strcat(replot_line,str);
X			}
X			else
X				int_error("plot line too long with replot arguments",c_token);
X		}
X		(void) strcpy(input_line,replot_line);
X		screen_ok = FALSE;
X		num_tokens = scanner(input_line);
X		c_token = 1;					/* skip the 'plot' part */
X		plotrequest(almost_equals(0,"td$raw") ||
X					almost_equals(0,"tp$lot") ||
X					almost_equals(0,"xd$raw") ||
X					almost_equals(0,"xp$lot") ||
X					almost_equals(0,"tr$ans_plot") ||
X					almost_equals(0,"tr$ans_draw"));  /* fetch plot type */
X	}
X	else if (almost_equals(c_token,"se$t"))
X		set_stuff();
X	else if (almost_equals(c_token,"sh$ow"))
X		show_stuff();
X	else if (almost_equals(c_token,"sa$ve")) {
X		c_token++;
X		if (END_OF_COMMAND || !isstring(c_token))
X			int_error("name of file expected", c_token);
X		quote_str(sv_file,c_token);
X		save_sets(fopen(sv_file,"w"));
X		/* c_token updated in save_sets */
X	}
X	else if (almost_equals(c_token,"cl$ear")) {
X		if (!term_init) {
X			(*term_tbl[term].init)();
X			term_init = TRUE;
X		}
X		(*term_tbl[term].graphics)();
X		(*term_tbl[term].text)();
X		(void) fflush(outfile);
X		screen_ok = FALSE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"she$ll")) {
X		do_shell();
X		screen_ok = FALSE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"l$oad") ||
X			 almost_equals(c_token,"r$ead")) {
X		if (!isstring(++c_token))
X			int_error("expecting filename",c_token);
X		else {
X			quote_str(sv_file,c_token);
X			load_file(fopen(sv_file,"r"));	
X		/* input_line[] and token[] now destroyed! */
X			c_token = num_tokens = 0;
X		}
X	}
X	else if (almost_equals(c_token,"ex$it") ||
X			almost_equals(c_token,"q$uit")) {
X		done(IO_SUCCESS);
X	}
X	else if (!equals(c_token,";")) {		/* null statement */
X		int_error("Invalid command. Try:\n\
X'?/help', 'test', 'pause', '[t]draw/[t]plot',\n\
X'replot/redraw', 'set', 'show', 'save', 'shell',\n\
X'load/read', 'exit/quit'",c_token);
X	}
X}
X
X
Xenum DRAW_STYLE
Xget_style()
X{
Xregister enum DRAW_STYLE ps;
X
X	c_token++;
X	if (almost_equals(c_token,"a$djacent_bars"))
X		ps = ABARS;
X	else if (almost_equals(c_token,"l$ayer_bars"))
X		ps = LAYB;
X	else if (almost_equals(c_token,"s$tacked_bars"))
X		ps = SBAR;
X	else if (almost_equals(c_token,"p$iechart"))
X		ps = PIECHART;
X	else
X		int_error("expecting 'adjacent_bars', 'stacked_bars', 'layer_bars' or 'piechart'",c_token);
X	c_token++;
X	return(ps);
X}
X
Xenum GRAV_DIR
Xget_gravity()
X{
X	c_token++;
X	if (END_OF_COMMAND) return(DEFAULT);
X	else if (almost_equals(c_token,"b$ottom") || almost_equals(c_token,"s$outh")) {
X		c_token++;
X		return(SOUTH);
X	}
X	else if (almost_equals(c_token,"t$op") || almost_equals(c_token,"n$orth")) {
X		c_token++;
X		return(NORTH);
X	}
X	else if (almost_equals(c_token,"l$eft") || almost_equals(c_token,"w$est")) {
X		c_token++;
X		return(WEST);
X	}
X	else if (almost_equals(c_token,"r$ight") || almost_equals(c_token,"e$ast")) {
X		c_token++;
X		return(EAST);
X	}
X	else
X		int_error("expecting direction: 'left/west', 'right/east',\n'bottom/south' or 'top/north'",c_token);
X	/*NOTREACHED*/
X}
X
Xenum INP_STYLE
Xget_input()
X{
X	if (END_OF_COMMAND) return(PRIVATE);
X	else if (almost_equals(c_token,"g$nuplot")) {
X		c_token++;
X		return(GNUPLOT);
X	}
X	else if (almost_equals(c_token,"p$rivate")) {
X		c_token++;
X		return(PRIVATE);
X	}
X	else if (almost_equals(c_token,"c$ustomized")) {
X		c_token++;
X		return(CUSTOMD);
X	}
X	else
X		int_error("expected 'gnuplot', 'private' or 'customized'",c_token);
X	/*NOTREACHED*/
X}
X
Xset_stuff()
X{
X	static char testfile[MAX_LINE_LEN+1];
X
X	if (almost_equals(++c_token,"b$ar")) {
X		set_bar_stuff();
X	}
X	else if (almost_equals(c_token,"fr$ame")) {
X		draw_border = TRUE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"nof$rame")) {
X		draw_border = FALSE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"for$mat")) {
X		c_token++;
X		if (END_OF_COMMAND)
X			(void) strcpy(tic_form, DEF_T_FORMAT);
X		else if (!isstring(c_token))
X			int_error("enquoted format expected", c_token);
X		else 
X			quote_str(tic_form, c_token++);
X	}
X	else if (almost_equals(c_token,"fon$t")) {
X		c_token++;
X		if (END_OF_COMMAND)
X			vect_font = F_ALWYS;
X		else {
X			if (almost_equals(c_token,"n$ever")) 
X				vect_font = F_NEVER;
X			else if (almost_equals(c_token,"w$hen_needed"))
X				vect_font = F_WHENN;
X			else if (almost_equals(c_token,"r$otated"))
X				vect_font = F_ROTAT;
X			else if (almost_equals(c_token,"a$lways"))
X				vect_font = F_ALWYS;
X			else
X				int_error("'never', 'when_needed', 'rotated', or 'always' expected",c_token);
X			c_token++;
X		}
X	}	
X	else if (almost_equals(c_token,"au$tolabeling")) {
X		auto_label = TRUE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"noau$tolabeling")) {
X		auto_label = FALSE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"ar$row")) {
X		c_token++;
X		set_arrow(TRUE);
X	}
X	else if (almost_equals(c_token,"noar$row")) {
X		c_token++;
X		set_noarrow();
X	}
X	else if (almost_equals(c_token,"c$ustomized")) {
X		c_token++;
X		if (END_OF_COMMAND) {
X			data_place.from = -1;	/* not defined */
X			label_plac.from = -1;	/* thus no label */
X		}
X		else {
X			if (!equals(c_token,"["))
X				int_error("expecting '['",c_token);
X			c_token++;
X			load_range(&data_place.from,&data_place.upto);
X			if (!equals(c_token,"]"))
X				int_error("expecting ']'",c_token);
X			c_token++;
X			if (END_OF_COMMAND)
X				label_plac.from = -1;	/* no label */
X			else {
X				if (equals(c_token,",")) c_token++;		/* optional ',' */
X				if (!equals(c_token,"["))
X					int_error("expecting '['",c_token);
X				c_token++;
X				load_range(&label_plac.from,&label_plac.upto);
X				if (!equals(c_token,"]"))
X					int_error("expected ']'",c_token);
X				c_token++;
X			}
X			if (!check_ranges(&data_place,&label_plac)) {	/* overlapping ranges ? */
X				data_place.from = label_plac.from = -1;
X				int_error("value and label places are overlapping or are empty",NO_CARET);
X			}
X		}
X	}
X	else if (almost_equals(c_token,"h$ighlight")) {
X		c_token++;
X		HLitem = get_HL();
X	}
X	else if (almost_equals(c_token,"i$nput")) {
X		c_token++;
X		inp_style = get_input();
X	}
X	else if (almost_equals(c_token,"lo$gscale")) {
X		c_token++;
X		log_y = TRUE;
X	}
X	else if (almost_equals(c_token,"nolo$gscale")) {
X		log_y = FALSE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"la$bel")) {
X		c_token++;
X		set_label();
X	}
X	else if (almost_equals(c_token,"nola$bel")) {
X		c_token++;
X		set_nolabel();
X	}
X	else if (almost_equals(c_token,"li$ne")) {
X		c_token++;
X		set_arrow(FALSE);
X	}
X	else if (almost_equals(c_token,"noli$ne")) {
X		c_token++;
X		set_noarrow();
X	}	
X	else if (almost_equals(c_token,"of$fsets")) {
X		c_token++;
X		if (END_OF_COMMAND) {
X			loff = roff = toff = boff = 0.0;  /* Reset offsets */
X		}
X		else {
X			load_offsets (&loff,&roff,&toff,&boff);
X			if ((loff>1.0 ? loff/100.0 : loff) + (roff>1.0 ? roff/100.0 : roff) >= 1.0 ||
X				(boff>1.0 ? boff/100.0 : boff) + (toff>1.0 ? toff/100.0 : toff) >= 1.0) {
X				loff = roff = toff = boff = 0.0;  /* Reset offsets for the future */
X				int_error("null picture size within given offsets",NO_CARET);
X			}
X		}
X	}
X	else if (almost_equals(c_token,"o$utput")) {
X		register FILE *f;
X
X		c_token++;
X		if (END_OF_COMMAND) {	/* no file specified */
X 			UP_redirect (4);
X			if (outfile != stdout) /* Never close stdout */
X				(void) fclose(outfile);
X			outfile = stdout; /* Avoid the dup... */
X			term_init = FALSE;
X			(void) strcpy(outstr,"STDOUT");
X		} else if (!isstring(c_token))
X			int_error("expecting filename",c_token);
X		else {
X			quote_str(testfile,c_token);
X			if (!(f = fopen(testfile,"w"))) {
X			  os_error("cannot open file; output not changed",c_token);
X			}
X			if (outfile != stdout) /* Never close stdout */
X				(void) fclose(outfile);
X			outfile = f;
X			term_init = FALSE;
X			outstr[0] = '\'';
X			(void) strcat(strcpy(outstr+1,testfile),"'");
X 			UP_redirect (1);
X		}
X		c_token++;
X	}
X	else if (almost_equals(c_token,"p$ie")) {
X		set_pie_stuff();
X	}
X	else if (almost_equals(c_token,"si$ze")) {
X        c_token++;
X        if (END_OF_COMMAND) {
X            xsize = 1.0;
X            ysize = 1.0;
X        }
X        else {
X			xsize = (float)real(c_token);
X			c_token++;
X			if (!equals(c_token,","))
X				int_error("',' expected",c_token);
X			c_token++;
X			if (END_OF_COMMAND)
X				int_error("value for ysize expected",c_token);
X			ysize = (float)real(c_token);
X			c_token++;
X        }
X    }		
X	else if (almost_equals(c_token,"st$yle")) {
X		data_style = get_style();
X	}
X	else if (almost_equals(c_token,"te$rminal")) {
X		c_token++;
X		if (END_OF_COMMAND) {
X			list_terms();
X			screen_ok = FALSE;
X		}
X		else {
X            if (term && term_init) {
X                (*term_tbl[term].reset)();
X                (void) fflush(outfile);
X            }			
X			term = set_term(c_token);
X			c_token++;
X		}
X	}
X	else if (almost_equals(c_token,"ti$tle")) {
X		c_token++;
X		if (END_OF_COMMAND) {
X			if (data_head.fname)
X				free(data_head.fname);
X			data_head.fname = NULL;
X		}
X		else if (isstring(c_token)) {
X			m_quote_capture(&(data_head.fname), c_token, c_token);
X			c_token++;
X		}
X		else
X			int_error("title within quotes expected", c_token);
X	}
X	else if (almost_equals(c_token,"tr$uncate")) {
X		c_token++;
X		if (END_OF_COMMAND)
X			strunc = 0;
X		else {
X			strunc = real(c_token);
X			c_token++;
X		}
X	}
X	else if (almost_equals(c_token,"not$runcate")) {
X		c_token++;
X		strunc = -1;
X	}
X	else if (almost_equals(c_token,"r$ange")) {
X		c_token++;
X		if (END_OF_COMMAND) xmin=-1;
X		else {
X			if (!equals(c_token,"["))
X				int_error("expecting '['",c_token);
X			c_token++;
X			load_range(&xmin,&xmax);
X			if (!equals(c_token,"]"))
X				int_error("expecting ']'",c_token);
X			c_token++;
X			if (xmax != -1 && xmax < xmin) {
X				xmin = -1;  /* whole */
X				int_error("given range is empty",NO_CARET);
X			}
X		}
X	}
X	else if (almost_equals(c_token,"z$ero") ||
X			 almost_equals(c_token,"eps$ilon")) {
X		int sign=1;
X		c_token++;
X		if (equals(c_token,"-")) sign=-1, c_token++;
X		zero = sign*real(c_token);
X		c_token++;
X	}
X	else
X		int_error(
X	"valid set options:  'bar', '[no]logscale',\n\
X'customized', 'format', 'highlight', 'offsets'\n\
X'output', 'pie', 'style', '[no]autolabeling',\n\
X'terminal', 'title', 'range', 'zero/epsilon',\n\
X'[no]frame', 'font', '[no]truncate', '[no]label',\n\
X'[no]arrow', '[no]line'",
X	c_token);
X}
X
Xset_bar_stuff()
X{
X	if (almost_equals(++c_token,"a$utoscale")) {
X		autoscale = TRUE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"noa$utoscale")) {
X		autoscale = FALSE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"b$ase")) {
X		int sign = 1;
X		c_token++;
X		if (END_OF_COMMAND) base = 0.0;
X		else {
X			if (equals(c_token,"-")) c_token++, sign=-1;
X			base = sign*real(c_token);
X			c_token++;
X		}
X	}
X	else if (almost_equals(c_token,"cl$ockwise")) {
X		b_clockwise = TRUE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"co$unter_clockwise")) {
X		b_clockwise = FALSE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"g$ravitation")) {
X		gravity = get_gravity();
X		if (gravity==DEFAULT) gravity = SOUTH;
X	}
X	else if (almost_equals(c_token,"w$idth")) {
X		c_token++;
X		if (END_OF_COMMAND) {
X			b_wid = MAXBARWIDTH;
X			b_int = INTERBAR;
X			b_spc = INTERGROUP;
X		}
X		else
X			load_offsets(&b_wid, &b_int, &b_spc, (double *) NULL);
X	}
X	else
X		int_error("valid options:  '[no]autoscale', 'base',\n\
X'[counter_]clockwise', 'gravitation', 'width'",c_token);
X}
X
Xset_pie_stuff()
X{
X	if (almost_equals(++c_token,"ex$plode")) {
X		explode = get_gravity();
X	}
X	else if (almost_equals(c_token,"cl$ockwise")) {
X		p_clockwise = TRUE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"co$unter_clockwise")) {
X		p_clockwise = FALSE;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"r$adius")) {
X		c_token++;
X		if (END_OF_COMMAND)
X			radexp = EXPL_RAD;
X		else {
X			radexp = real(c_token);
X			c_token++;
X		}
X	}
X	else if (almost_equals(c_token,"s$amples")) {
X		register int tsamp;
X
X		c_token++;
X		tsamp = (int)real(c_token);
X		if (tsamp < 1)
X			int_error("sampling rate must be > 0; sampling unchanged",
X				c_token);
X		else samples = tsamp;
X		c_token++;
X	}
X	else if (almost_equals(c_token,"t$hreshold")) {
X		c_token++;
X		if (END_OF_COMMAND) {
X			treshold = 0.0;
X			strcpy(thrname, OTHER);
X		}
X		else {
X			treshold = real(c_token);
X			c_token++;
X			if (END_OF_COMMAND)
X				strcpy(thrname, OTHER);
X			else if (!isstring(c_token))
X				int_error("name in quotes expected", c_token);
X			else {
X				quote_str(thrname, c_token);
X				c_token++;
X			}
X		}
X	}
X	else
X		int_error("valid options: '[counter_]clockwise',\n\
X'explode', 'radius', 'samples', 'threshold'",c_token);
X}
X
Xget_HL()
X{
X	if (END_OF_COMMAND) return(HL_NON);
X	else if (almost_equals(c_token,"n$one")) {
X		c_token++;
X		return(HL_NON);
X	}
X	else if (almost_equals(c_token,"mi$nim")) {
X		c_token++;
X		return(HL_MIN);
X	}
X	else if (almost_equals(c_token,"ma$xim")) {
X		c_token++;
X		return(HL_MAX);
X	}
X	else if (isnumber(c_token)) {
X		return((int) real(c_token++));
X	}
X	else
X		int_error("'maximum', 'minimum', 'none' or number expected",c_token);
X	/*NOTREACHED*/
X}
X
Xshow_stuff()
X{
X	if (almost_equals(++c_token,"sc$ale")) {
X		(void) putc('\n',stderr);
X		show_autoscale();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"au$tolabeling")) {
X		(void) putc('\n',stderr);
X		show_label();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"lo$gscale")) {
X		(void) putc('\n',stderr);
X		show_logscale();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"la$bel")) {
X		(void) putc('\n',stderr);
X		c_token++;
X		if (END_OF_COMMAND)
X			show_labels(0, stderr, FALSE);
X		else {
X			show_labels((int)real(c_token), stderr, FALSE);
X			c_token++;
X		}
X	}
X	else if (almost_equals(c_token,"li$ne") || almost_equals(c_token,"ar$row")) {
X		(void) putc('\n',stderr);
X		c_token++;
X		if (END_OF_COMMAND)
X			show_arrow(0, stderr, FALSE);
X		else {
X			show_arrow((int)real(c_token), stderr, FALSE);
X			c_token++;
X		}
X	}	
X	else if (almost_equals(c_token,"bas$e")) {
X		(void) putc('\n',stderr);
X		show_base();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"fr$ame")) {
X		(void) putc('\n',stderr);
X		show_border();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"for$mat")) {
X		(void) putc('\n',stderr);
X		show_format();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"fon$t")) {
X		(void) putc('\n',stderr);
X		show_font();
X		c_token++;
X	}	
X	else if (almost_equals(c_token,"cl$ockwise")) {
X		(void) putc('\n',stderr);
X		show_clock(TRUE);
X		show_clock(FALSE);
X		c_token++;
X	}
X	else if (almost_equals(c_token,"cu$stomized")) {
X		(void) putc('\n',stderr);
X		show_custom();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"ex$plode")) {
X		(void) putc('\n',stderr);
X		show_explode();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"gr$avitation")) {
X		(void) putc('\n',stderr);
X		show_gravity();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"h$ighlight")) {
X		(void) putc('\n',stderr);
X		show_HLset();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"i$nput")) {
X		(void) putc('\n',stderr);
X		show_input();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"of$fsets")) {
X		(void) putc('\n',stderr);
X		show_offsets();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"o$utput")) {
X		(void) putc('\n',stderr);
X		show_output();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"sa$mples")) {
X		(void) putc('\n',stderr);
X		show_samples();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"st$yle")) {
X		(void) putc('\n',stderr);
X		c_token++;
X		show_style();
X	}
X	else if (almost_equals(c_token,"si$ze")) {
X		(void) putc('\n',stderr);
X		c_token++;
X		show_size();
X	}
X	else if (almost_equals(c_token,"te$rminal")) {
X		(void) putc('\n',stderr);
X		show_term();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"ti$tle")) {
X		(void) putc('\n',stderr);
X		show_title();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"th$reshold")) {
X		(void) putc('\n',stderr);
X		show_tresh();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"tr$uncate")) {
X		(void) putc('\n',stderr);
X		show_trunc();
X		c_token++;
X	}	
X	else if (almost_equals(c_token,"w$idth")) {
X		(void) putc('\n',stderr);
X		show_width();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"ve$rsion")) {
X		show_version();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"rad$ius")) {
X		(void) putc('\n',stderr);
X		show_radius();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"r$ange")) {
X		(void) putc('\n',stderr);
X		show_range();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"z$ero") ||
X			 almost_equals(c_token,"eps$ilon")) {
X		(void) putc('\n',stderr);
X		show_zero();
X		c_token++;
X	}
X	else if (almost_equals(c_token,"g$eneral")) {	/* no more !!! */
X		c_token++;
X		show_version();
X		show_input();
X		show_custom();
X		show_range();
X		show_label();
X		show_trunc();
X		show_output();
X		show_term();
X		show_size();
X		show_offsets();
X		show_border();
X		show_font();
X		show_title();
X		show_labels(0, stderr, FALSE);
X		show_arrow(0, stderr, FALSE);
X		show_logscale();
X		show_format();
X		show_zero();
X		show_HLset();
X		show_style();
X	}
X	else if (almost_equals(c_token,"bar$charts")) {
X		c_token++;
X		show_version();
X		show_style();
X		fprintf(stderr,"\n\tsettings for barcharts (any bar style):\n\n");
X		show_base();
X		show_width();
X		show_autoscale();
X		show_gravity();
X		show_clock(FALSE);
X	}
X	else if (almost_equals(c_token,"pie$charts")) {
X		c_token++;
X		show_version();
X		show_style();
X		fprintf(stderr,"\n\tsettings for piecharts:\n\n");
X		show_clock(TRUE);
X		show_explode();
X		show_radius();
X		show_tresh();
X		show_samples();
X	}		
X	else if (almost_equals(c_token,"a$ll")) {
X		c_token++;
X		show_version();
X		show_input();
X		show_custom();
X		show_range();
X		show_label();
X		show_trunc();
X		show_output();
X		show_term();
X		show_size();
X		show_offsets();
X		show_border();
X		show_font();
X		show_title();
X		show_labels(0, stderr, FALSE);
X		show_arrow(0, stderr, FALSE);
X		show_logscale();
X		show_format();
X		show_zero();
X		show_HLset();
X		show_style();
X		show_base();
X		show_width();
X		show_autoscale();
X		show_gravity();
X		show_clock(FALSE);	/* bars */
X		show_clock(TRUE);	/* pies */
X		show_explode();
X		show_radius();
X		show_tresh();
X		show_samples();
X	}
X	else
X		int_error(
X	"valid show options:  'all', 'scale', 'base', 'font'\n\
X'customized', 'explode', 'gravitation', 'highlight',\n\
X'input', 'logscale', 'offsets', 'output', 'label',\n\
X'samples', 'style', 'terminal', 'version', 'range',\n\
X'radius', 'clockwise', 'width', 'zero/epsilon', 'frame',\n\
X'size', 'general', 'barcharts', 'piecharts', 'format',\n\
X'threshold', 'truncate', 'line', 'arrow', 'autolabeling'",
Xc_token);
X	screen_ok = FALSE;
X	(void) putc('\n',stderr);
X}
X
X
Xload_offsets (a, b, c, d)
Xdouble *a, *b, *c, *d;
X{
X	*a = real (c_token);  /* loff value */
X	if (*a >= 100.0 && d)
X		int_error("value <0,100) expected",c_token);
X	c_token++;
X	if (equals(c_token,","))
X		c_token++;
X	if (END_OF_COMMAND) 
X	    return;
X
X	*b = real (c_token);  /* roff value */
X	if (*b >= 100.0 && d)
X		int_error("value <0,100) expected",c_token);		
X	c_token++;
X	if (equals(c_token,","))
X		c_token++;
X	if (END_OF_COMMAND) 
X	    return;
X
X	*c = real (c_token);  /* toff value */
X	if (*c >= 100.0 && d)
X		int_error("value <0,100) expected",c_token);
X	c_token++;
X
X	if (!d) return;
X	if (equals(c_token,","))
X		c_token++;
X	if (END_OF_COMMAND) 
X	    return;
X
X	*d = real (c_token);  /* boff value */
X	if (*d >= 100.0)
X		int_error("value <0,100) expected",c_token);
X	c_token++;
X}
X
X
Xload_range(a,b)
Xint *a, *b;
X{
X	if (equals(c_token,"]"))
X		return;  /* no change */
X	if (END_OF_COMMAND) {
X	    int_error("starting range value or ':' expected",c_token);
X	} else if (!equals(c_token,"to") && !equals(c_token,":"))  {
X		*a = (int)real(c_token);
X		c_token++;
X	}
X	else *a = 0;	/* from the very begining */
X	if (!equals(c_token,"to") && !equals(c_token,":"))
X		int_error("':' expected",c_token);
X	c_token++;
X	if (!equals(c_token,"]")) {
X		*b = (int)real(c_token);
X		c_token++;
X	}
X	else *b = -1;	/* to infinity */
X}
X
X
Xplotrequest(xplot)
XBOOLEAN xplot;
X{
X	
X	if (!term)					/* unknown */
X		int_error("use 'set term' to set terminal type first",c_token);
X
X	if (log_y && base<1.0 && data_style != PIECHART)
X		int_error("base for bars out of range for logscale",NO_CARET);
X
X	if (equals(c_token,"[")) {
X		c_token++;
X		load_range(&xmin,&xmax);
X		if (!equals(c_token,"]"))
X			int_error("']' expected",c_token);
X		c_token++;
X		if (xmax != -1 && xmax < xmin)
X			int_error("given range is empty",NO_CARET);
X	}
X
X	eval_plots(xplot);
X}
X
Xint missing(s)
Xchar *s;
X/* check if s represents a missing value (spaces and dot) */
X{
X	char *p = s + strlen(s) - 1;
X	if (!s || !*s)
X		return(1);
X	while (isspace(*s)) s++;
X	if (s == p && *s == '.')
X		return(1);
X	else
X		return(0);
X}
X
Xget_data(this_plot,this_style)
Xstruct dfile *this_plot;
Xenum INP_STYLE this_style;
X{
X	static char data_file[MAX_LINE_LEN+1], line[MAX_LINE_LEN+1];
X	register int i, l_num, ob_num, scanval;
X	register FILE *fp;
X	double x;
X	struct chunk *chn;
X	char *labpt;
X	int chsiz = CH_INIT_SIZE;
X	int lablen, aux;
X
X	quote_str(data_file, c_token);
X	m_quote_capture(&(this_plot->fname), c_token, c_token);
X
X	chn = (struct chunk *) alloc((unsigned)sizeof(struct chunk), data_file);
X	chn->next = NULL;	/* in case of further errors */
X	chn->dval = NULL;
X	chn->vlbl = (char **) NULL;
X	this_plot->data = chn;
X	this_plot->chunks = 1;
X	if (xmin != -1 && xmax != -1) 		/* known number of data */
X		chsiz = xmax - xmin + 1;
X	chn->dval = (vreal *) alloc((unsigned)chsiz*sizeof(vreal), data_file);
X	chn->used = 0;
X	if (this_style != CUSTOMD || label_plac.from != -1) {	/* labels expected */
X		chn->vlbl = (char **) alloc((unsigned)chsiz*sizeof(char *), data_file);
X		for (i=0; i<chsiz; i++)
X			chn->vlbl[i] = (char *) NULL;
X	}
X	this_plot->d_min =  VERYLARGE;
X	this_plot->d_max = -VERYLARGE;
X	this_plot->points = 0;
X	this_plot->makeHL = HL_NON;
X	this_plot->labels = TRUE;		/* label autogenerating may be possible */
X
X	if (!(fp = fopen(data_file, "r")))
X		os_error("can't open data file", c_token);
X		
X	l_num = 0;
X	ob_num = -1;		/* will be incremented before any operation */
X	i = -1;
X
X	while (fgets(line, MAX_LINE_LEN, fp)) {							/* REWRITE ALL !!! */
X		l_num++;
X		if (is_comment(line[0]) && this_style != CUSTOMD)	/* label can be on any position, incl. 1st column */
X			continue;		/* ignore comments */
X
X		i++;
X		if (i<xmin) continue;	/* still out of range */
X		if (xmax != -1 && i>xmax) break;	/* don't even read the rest of file */
X
X		line[strlen(line)-1] = '\0';	/* get rid of '\n' */
X		ob_num++;
X		if (ob_num==chsiz) {	/* open new chunk */
X			chn->next = (struct chunk *) alloc((unsigned)sizeof(struct chunk), data_file);
X			chn = chn->next;
X			chn->next = NULL;	/* in case of further errors */
X			chn->dval = NULL;
X			chn->vlbl = (char **) NULL;
X			this_plot->chunks++;
X			this_plot->points += chsiz;		/* chunkful of points */
X			chsiz *= 2;			/* probably the optimal allocation step */
X			chn->dval = (vreal *) alloc((unsigned)chsiz*sizeof(vreal), (char *)NULL);
X			if (!chn->dval)
X				(void) fclose(fp),
X				int_error("out of memory",c_token);
X			chn->used = 0;		/* this one */
X			if (this_style != CUSTOMD || label_plac.from != -1) {	/* labels expected */
X				chn->vlbl = (char **) alloc((unsigned)chsiz*sizeof(char *), (char *)NULL);
X				if (!chn->vlbl)
X					(void) fclose(fp),
X					int_error("out of memory",c_token++);
X				else {
X					int ii;
X					for (ii=0; ii<chsiz; ii++)
X						chn->vlbl[ii] = (char *) NULL;
X				}
X			}
X			ob_num = 0;
X		}
X
X		if (!*line && this_style != CUSTOMD) { 	/* empty data == missing value. not in SAS */
X			chn->dval[ob_num] = VERYLARGE;	
X			if (chn->vlbl)
X				chn->vlbl[ob_num] = (char *) NULL;
X			chn->used++;
X			continue;
X		}
X
X		/* so here we go. now consider input format */
X		switch (this_style) {
X			case PRIVATE:
X				scanval = sscanf(line,"%lf",&x);
X				if (scanval == 1) {
X					for (labpt = line; *labpt && isspace(*labpt); labpt++) ;
X					while (*labpt && !isspace(*labpt)) labpt++;
X					lablen = strlen(labpt);		/* initialy */
X				}
X				break;
X			case GNUPLOT:
X				scanval = sscanf(line,"%*lf %lf",&x);
X				if (scanval == 1) {
X					for (aux=0; isspace(line[aux]); aux++);
X					labpt = line + aux;
X					for (lablen=0; !isspace(line[aux++]); lablen++) ;
X				}
X				else labpt=NULL, scanval = sscanf(line,"%lf",&x);
X				break;
X			case CUSTOMD:
X				if (strlen(line) < data_place.from) {
X					scanval = 0;		/* generate error */
X					break;
X				}
X				labpt = line + data_place.from;
X				if (data_place.upto == -1 || data_place.upto >= strlen(line))
X					if (missing(labpt))
X						x = VERYLARGE;
X					else
X						scanval = sscanf(labpt,"%lf",&x);
X				else {
X					aux = line[data_place.upto];
X					line[data_place.upto] = '\0';
X					if (missing(labpt))
X						x = VERYLARGE;
X					else
X						scanval = sscanf(labpt,"%lf",&x);
X					line[data_place.upto] = aux;
X				}
X				if (x == VERYLARGE) { 		/* missing value detected, or unplottable anyway */
X					chn->dval[ob_num] = VERYLARGE;
X					if (chn->vlbl)
X						chn->vlbl[ob_num] = (char *) NULL;
X					chn->used++;
X					continue;
X				}
X				if (label_plac.from >= strlen(line) || label_plac.from == -1) 
X					labpt = NULL;
X				else {
X					labpt = line + label_plac.from;
X					if (label_plac.upto == -1 || label_plac.upto >= strlen(line))
X						lablen = strlen(labpt);
X					else
X						lablen = label_plac.upto - label_plac.from - 1;
X				}
X				break;
X			}
X
X		if (scanval != 1) {		/* can be also EOF for empty line */
X			(void) sprintf(line, "bad data on line %d", l_num);
X			(void) fclose(fp);
X			int_error(line,c_token);
X		}
X
X		if (x<0.0 && data_style == PIECHART ||
X			x<1.0 && data_style != PIECHART && log_y) {
X			(void) fclose(fp);
X			(void) sprintf(line,"unplotable data on line %d",l_num);
X			int_error(line,c_token);
X		}
X
X		if (log_y) x = log10(x);
X		
X		chn->dval[ob_num] = (vreal) x;
X		if (x<this_plot->d_min) this_plot->d_min = (vreal) x;
X		if (x>this_plot->d_max) this_plot->d_max = (vreal) x;  /* without 'else', I know */
X		
X		if (labpt && *labpt && lablen && strunc!=0) {	/* copy existing label -- ignore if empty */
X			char *q;
X			/* remove meaningless spaces */
X			while (isspace(*labpt)) labpt++, lablen--;
X			while (isspace(labpt[lablen])) lablen--;
X			if (strunc>0 && strunc<lablen)
X				lablen = strunc;
X			if (!lablen)	/* truncated to zero */
X				chn->vlbl[ob_num] = (char *) NULL;
X			else {
X				if (!(q = alloc((unsigned) lablen+1, (char *)NULL))) {
X					(void) fclose(fp);
X					int_error("out of memory",c_token);
X				}
X				(void) strncpy(q,labpt,lablen);
X				q[lablen] = '\0';
X				chn->vlbl[ob_num] = q;
X				this_plot->labels = FALSE;	/* cannot autogenerate labels if some exist */
X			}
X		}
X		else
X			chn->vlbl[ob_num] = (char *) NULL;
X
X		chn->used++;
X	} /* while */
X
X	(void) fclose(fp);
X	if (i<xmin)
X		int_error("too few data",c_token);
X
X	this_plot->points += chn->used;
X
X}
X
Xeval_plots(xplot)
XBOOLEAN xplot;
X{
X	struct dfile *dp = &data_head, *tail;
X	enum INP_STYLE in_st;
X
X	data_head.d_min = VERYLARGE; data_head.d_max = -VERYLARGE;
X	data_head.points = data_head.chunks = 0;
X	if (data_head.data) free((char *)data_head.data);
X	data_head.data = NULL;
X	destroy(data_head.dnxt);
X	data_head.dnxt = (struct dfile *) NULL;
X	data_head.makeHL = HLitem;
X	data_head.labels = auto_label;
X
X	while (TRUE) {
X		if (END_OF_COMMAND)
X			int_error("data file to plot expected",c_token);
X		if (equals(c_token,"(")) {
X			c_token++;
X			in_st = get_input();
X			if (END_OF_COMMAND || !equals(c_token,")"))
X				int_error("expected ')'",c_token);
X			c_token++;
X		}
X		else
X			in_st = inp_style;
X		if (in_st == CUSTOMD && data_place.from == -1)
X			int_error("Customized input format not defined. Use 'set customized'",NO_CARET);
X		
X		if (END_OF_COMMAND || !isstring(c_token)) 
X			int_error("data file to plot expected",c_token);
X		tail = (struct dfile *) alloc((unsigned int) sizeof(struct dfile), "data");
X		tail->fname = NULL;
X		tail->data  = NULL;
X		tail->dnxt  = NULL;
X		dp->dnxt    = tail;	/* to free all memory on error */
X
X		get_data(tail,in_st);
X
X		c_token++;
X		dp		 	= tail;
X		data_head.chunks++;  /* here we count overall number of files */
X		if (data_style != ABARS && data_style != PIECHART || xplot)	/* if (ABARS || PIECHART => xplot) */
X			data_head.labels = data_head.labels && dp->labels;	/* is making labels sensible or not ? */
X		/* else this serves different purpose */
X		if (data_head.points < dp->points)
X			data_head.points = dp->points;  /* ... and maximal number of points */
X		if (data_head.d_min > dp->d_min)
X			data_head.d_min = dp->d_min;	/* minimum ... */
X		if (data_head.d_max < dp->d_max)
X			data_head.d_max = dp->d_max;	/* and maximum */
X
X		if (almost_equals(c_token,"a$s")) {
X			c_token++;
X			if (END_OF_COMMAND || !isstring(c_token))
X				int_error("name in quotes expected", c_token);
X			else {
X				m_quote_capture(&(dp->fname), c_token, c_token);
X				c_token++;
X			}
X		}
X		
X		if (almost_equals(c_token,"h$ighlighting")) {
X			c_token++;
X			dp->makeHL = get_HL();
X		}
X
X		if (END_OF_COMMAND)
X			break;
X		else if (equals(c_token,","))
X			c_token++;
X		else
X			int_error("expected ','",c_token);
X	}
X
X	if (data_head.d_min == VERYLARGE || data_head.d_max == -VERYLARGE)
X		int_error("all points undefined, nothing to draw",NO_CARET);
X
X	if (data_head.chunks > 1) {		/* reserve space for xpointers structure */
X		/* do it here, to avoid memory management in graphics.c */
X		data_head.data = (struct chunk *) alloc((unsigned)data_head.chunks*sizeof(struct xptr), "data");
X	}
X
X	capture(replot_line,plot_token,c_token);
X	do_plot(xplot,data_style,xmin<=0?0:xmin);
X}
X
Xdone(status)
Xint status;
X{
X	if (term && term_init)
X		(*term_tbl[term].reset)();
X#ifdef VMS
X	vms_reset();
X#endif
X	exit(status);
X}
X
X#ifdef MSDOS
X#ifndef __TURBOC__  /* Turbo C already has sleep() */
X#ifndef __ZTC__     /* ZTC already has usleep() */
X/* kludge to provide sleep() for msc 5.1 */
Xvoid sleep(delay)
Xunsigned int delay;
X{
Xunsigned long time_is_up;
X    time_is_up = time(NULL) + (unsigned long) delay;
X    while (time(NULL)<time_is_up)
X        /* wait */ ;
X}
X#endif /* not ZTC */
X#endif /* not TURBOC */
X#endif /* MSDOS */
X
X
X/* Support for input, shell, and help for various systems */
X
X#ifdef vms
X
X#include <descrip.h>
X#include <rmsdef.h>
X#include <errno.h>
X
Xextern lib$get_input(), lib$put_output();
X
Xint vms_len;
X
Xunsigned int status[2] = {1, 0};
X
Xstatic char help[MAX_LINE_LEN+1] = "fchart";
X
X$DESCRIPTOR(prompt_desc,PROMPT);
X$DESCRIPTOR(line_desc,input_line);
X
X$DESCRIPTOR(help_desc,help);
X$DESCRIPTOR(helpfile_desc,"FCHART$HELP");
X
Xread_line(prompt)
Xchar *prompt;
X{
X	int more, start=0;
X	char exp_prompt = EXP_PROMPT;
X    prompt_desc.dsc$w_length = strlen (prompt);
X    prompt_desc.dsc$a_pointer = prompt;
X	do {
X		line_desc.dsc$w_length = MAX_LINE_LEN - start;
X        line_desc.dsc$a_pointer = &input_line[start];
X		switch(status[1] = lib$get_input(&line_desc, &prompt_desc, &vms_len)){
X			case RMS$_EOF:
X				done(IO_SUCCESS);	/* ^Z isn't really an error */
X				break;
X			case RMS$_TNS:			/* didn't press return in time */
X				vms_len--;		/* skip the last character */
X				break;			/* and parse anyway */
X			case RMS$_BES:			/* Bad Escape Sequence */
X			case RMS$_PES:			/* Partial Escape Sequence */
X				sys$putmsg(status);
X				vms_len = 0;		/* ignore the line */
X				break;
X			case SS$_NORMAL:
X				break;			/* everything's fine */
X			default:
X				done(status[1]);	/* give the error message */
X		}
X		start += vms_len;
X		input_line[start] = '\0';
X        if (input_line[start-1] == '\\') {
X          /* Allow for a continuation line. */
X          prompt_desc.dsc$w_length = strlen (exp_prompt);
X          prompt_desc.dsc$a_pointer = exp_prompt;
X          more = 1;
X          --start;
X        }
X        else {
X          line_desc.dsc$w_length = strlen(input_line);
X          line_desc.dsc$a_pointer = input_line;
X          more = 0;
X        }
X    } while (more);		
X}
X
X
Xdo_help()
X{
X	help_desc.dsc$w_length = strlen(help);
X	if ((vaxc$errno = lbr$output_help(lib$put_output,0,&help_desc,
X		&helpfile_desc,0,lib$get_input)) != SS$_NORMAL)
X			os_error("can't open FCHART$HELP");
X}
X
X
Xdo_shell()
X{
X	if ((vaxc$errno = lib$spawn()) != SS$_NORMAL) {
X		os_error("spawn error",NO_CARET);
X	}
X}
X
X
Xdo_system()
X{
X	input_line[0] = ' ';	/* an embarrassment, but... */
X
X	if ((vaxc$errno = lib$spawn(&line_desc)) != SS$_NORMAL)
X		os_error("spawn error",NO_CARET);
X
X	(void) putc('\n',stderr);
X}
X
X#else /* vms */
X
X/* do_help: (not VMS, although it would work)
X * Give help to the user.
X * It parses the command line into helpbuf and supplies help for that
X * string. Then, if there are subtopics available for that key,
X * it prompts the user with this string. If more input is
X * given, do_help is called recursively, with the argument the index of
X * null character in the string. Thus a more specific help can be
X * supplied. This can be done repeatedly.
X * If null input is given, the function returns, effecting a
X * backward climb up the tree.
X * David Kotz (dfk@cs.duke.edu) 10/89
X */
Xdo_help()
X{
X    static char helpbuf[MAX_LINE_LEN] = "";
X    static char prompt[MAX_LINE_LEN] = "";
X    int base;               /* index of first char AFTER help string */
X    int len;                /* length of current help string */
X    BOOLEAN more_help;
X    BOOLEAN only;           /* TRUE if only printing subtopics */
X    int subtopics;          /* 0 if no subtopics for this topic */
X    int start;              /* starting token of help string */
X    char *help_ptr;         /* name of help file */
X	
X    if ( (help_ptr = getenv("FCHARTHELP")) == (char *)NULL )
X        /* if can't find environment variable then just use HELPFILE */
X        help_ptr = HELPFILE;
X	
X    len = base = strlen(helpbuf);
X	
X    /* find the end of the help command */
X    for (start = c_token; !(END_OF_COMMAND); c_token++) ;
X    /* copy new help input into helpbuf */
X    if (len > 0)
X		helpbuf[len++] = ' ';  /* add a space */
X    capture(helpbuf+len, start, c_token-1);
X    squash_spaces(helpbuf+base); /* only bother with new stuff */
X    lower_case(helpbuf+base); /* only bother with new stuff */
X    len = strlen(helpbuf);
X	
X    /* now, a lone ? will print subtopics only */
X    if (strcmp(helpbuf + (base ? base+1 : 0), "?") == 0) {
X		/* subtopics only */
X		subtopics = 1;
X		only = TRUE;
X		helpbuf[base] = '\0';    /* cut off question mark */
X    } else {
X		/* normal help request */
X		subtopics = 0;
X		only = FALSE;
X    }
X	
X    switch ( help(helpbuf, help_ptr, &subtopics)) {
X		case H_FOUND: {
X			/* already printed the help info */
X			/* subtopics now is true if there were any subtopics */
X			screen_ok = FALSE;
X			
X			do {
X				if (subtopics && !only) {
X					/* prompt for subtopic with current help string */
X					if (len > 0)
X						(void) sprintf(prompt, "Subtopic of %s: ", helpbuf);
X					else
X						(void) strcpy(prompt, "Help topic: ");
X					read_line(prompt);
X					num_tokens = scanner(input_line);
X					c_token = 0;
X					more_help = !(END_OF_COMMAND);
X					if (more_help)
X						/* base for next level is all of current helpbuf */
X						do_help();
X				} else
X					more_help = FALSE;
X			} while(more_help);
X			
X			break;
X		}
X		case H_NOTFOUND: {
X			printf("Sorry, no help for '%s'\n", helpbuf);
X			break;
X		}
X		case H_ERROR: {
X			perror(help_ptr);
X			break;
X		}
X		default: {       /* defensive programming */
X			int_error("Impossible case in switch\n", NO_CARET);
X			/* NOTREACHED */
X		}
X    }
X	
X    helpbuf[base] = '\0';   /* cut it off where we started */
X}
X
Xdo_system()
X{
X	if (system(input_line + 1))
X		os_error("system() failed",NO_CARET);
X}
X
X#ifdef MSDOS
X
Xread_line(prompt)
Xchar *prompt;
X{
X	int last, start = 0;
X	BOOLEAN more;
X
X#ifndef __ZTC__
X    if (interactive) { /* if interactive use console IO so CED will work */
X        cputs(prompt);
X        do {
X			input_line[start] = MAX_LINE_LEN - start - 1;
X			cgets(&(input_line[start]));
X			(void) putc('\n',stderr);
X			if (input_line[start+2] == 26) {
X				/* end-of-file */
X				(void) putc('\n',stderr);
X				input_line[start] = '\0';
X				if (start > 0)    /* don't quit yet - process what we have */
X					more = FALSE;
X				else {
X					(void) putc('\n',stderr);
X					done(IO_SUCCESS);
X					/* NOTREACHED */
X				}
X			} else {
X				/* normal line input */
X				register i = start;
X				while ( (input_line[i] = input_line[i+2]) != (char)NULL )
X					i++;        /* yuck!  move everything down two characters */
X				
X				last = strlen(input_line) - 1;
X				if (last + 1 >= MAX_LINE_LEN)
X					int_error("Input line too long",NO_CARET);
X				
X				if (input_line[last] == '\\') { /* line continuation */
X					start = last;
X					more = TRUE;
X				} else
X					more = FALSE;
X			}
X			if (more && isatty(fileno(stdin)))
X				cputs(EXP_PROMPT);
X        } while(more);
X    }
X    else { /* not interactive */
X#endif /* not ZTC */
X        if (interactive) 
X			fputs(prompt,stderr);
X        do {
X			/* grab some input */
X			if ( fgets(&(input_line[start]), MAX_LINE_LEN - start, stdin)
X				== (char *)NULL ) {
X				/* end-of-file */
X				if (interactive)
X					(void) putc('\n',stderr);
X				input_line[start] = '\0';
X				if (start > 0)    /* don't quit yet - process what we have */
X					more = FALSE;
X				else
X					done(IO_SUCCESS); /* no return */
X			} else {
X				/* normal line input */
X				last = strlen(input_line) - 1;
X				if (input_line[last] == '\n') { /* remove any newline */
X					input_line[last] = '\0';
X					/* Watch out that we don't backup beyond 0 (1-1-1) */
X					if (last > 0) --last;
X				} else if (last+1 >= MAX_LINE_LEN)
X					int_error("Input line too long",NO_CARET);
X				
X				if (input_line[last] == '\\') { /* line continuation */
X					start = last;
X					more = TRUE;
X				} else
X					more = FALSE;
X			}
X            if (more && interactive)
X				fputs(EXP_PROMPT, stderr);
X        } while(more);
X#ifndef __ZTC
X    }
X#endif
X	
X#ifdef FILIP
X	input_line[0] = MAX_LINE_LEN - 1;
X	cputs(PROMPT);
X	cgets(input_line);			/* console input so CED will work */
X	(void) putc('\n',stderr);
X	if (input_line[2] == 26) {
X		(void) putc('\n',stderr);		/* end-of-file */
X		done(IO_SUCCESS);
X	}
X	
X	i = 0;
X	while (input_line[i] = input_line[i+2])
X		i++;		/* yuck!  move everything down two characters */
X#endif
X}
X
X
Xdo_shell()
X{
X	register char *comspec;
X	if (!(comspec = getenv("COMSPEC")))
X		comspec = "\command.com";
X	if (spawnl(P_WAIT,comspec,NULL) == -1)
X		os_error("unable to spawn shell",NO_CARET);
X}
X
X#else /* MSDOS */
X/* plain old Unix */
X
Xread_line(prompt)
Xchar *prompt;
X{
X	int start=0, last=0;
X	BOOLEAN more;
X	
X	if (interactive) fputs(prompt,stderr);
X	do {
X		if (!fgets(&input_line[start], MAX_LINE_LEN-start, stdin)) {
X			if (interactive)
X				(void) putc('\n',stderr);		/* end-of-file */
X			input_line[start] = '\0';
X			if (start > 0)    /* don't quit yet - process what we have */
X				more = FALSE;
X			else
X				done(IO_SUCCESS); /* no return */
X		}
X		else {	/* normal line input */
X			last = strlen(input_line)-1;
X			if (input_line[last] == '\n') { /* remove any newline */
X				input_line[last] = '\0';
X                /* Watch out that we don't backup beyond 0 (1-1-1) */
X				if (last > 0) --last;
X			}
X			else if (last+1 >= MAX_LINE_LEN)
X				int_error("Input line too long",NO_CARET);
X			
X			if (input_line[last] == '\\') { /* line continuation */
X				start = last;
X				more = TRUE;
X			} else
X				more = FALSE;
X		}
X		if (more && interactive) fputs(EXP_PROMPT,stderr);
X	} while (more);
X}
X
X#ifdef VFORK
X
Xdo_shell()
X{
Xregister char *shell;
Xregister int p;
Xstatic int execstat;
X	if (!(shell = getenv("SHELL")))
X		shell = SHELL;
X	if ((p = vfork()) == 0) {
X		execstat = execl(shell,shell,NULL);
X		_exit(1);
X	} else if (p == -1)
X		os_error("vfork failed",c_token);
X	else
X		while (wait(NULL) != p)
X			;
X	if (execstat == -1)
X		os_error("shell exec failed",c_token);
X	(void) putc('\n',stderr);
X}
X#else /* VFORK */
X
X#define EXEC "exec "
Xdo_shell()
X{
Xstatic char exec[100] = EXEC;
Xregister char *shell;
X	if (!(shell = getenv("SHELL")))
X		shell = SHELL;
X
X	if (system(strncpy(&exec[sizeof(EXEC)-1],shell,
X		sizeof(exec)-sizeof(EXEC)-1)))
X		os_error("system() failed",NO_CARET);
X
X	(void) putc('\n',stderr);
X}
X#endif /* VFORK */
X#endif /* MSDOS */
X#endif /* vms */
SHAR_EOF
$TOUCH -am 0604152590 fcmd.c &&
chmod 0666 fcmd.c ||
echo "restore of fcmd.c failed"
set `wc -c fcmd.c`;Wc_c=$1
if test "$Wc_c" != "45623"; then
	echo original size 45623, current size $Wc_c
fi
# ============= fgraf.c ==============
echo "x - extracting fgraf.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > fgraf.c &&
X/*
X *
X *  Fchart  --  fgraf.c
X *
X *  Copyright (C) 1990 Piotr Filip Sawicki
X *
X *  WARNING:
X *    Included "fstyles.i" is an older version of already rewritten graphics
X *    module. Please, don't change anything, rather mail me suggestions.
X *    It emerged like a ball of mud -- don't be shocked with this code.
X *    Writing program I jjust have been adding here new styles, parameters,
X *    bells and whistles -- so it looks like it looks.
X *
X *  Rest of the code can be freely modified and used, as long as this message
X *  is retained and modified code is not redistributed.
X *
X *  Please e-mail any useful additions to fs@uwasa.fi so they may be
X *  included in later releases.
X *
X *  This file should be edited with 4-column tabs!  (:set ts=4 sw=4 in vi)
X */
X
X#include <stdio.h>
X#include <math.h>
X#include "plot.h"
X#include "fchart.h"
X
X/***********************************************************************/
X
X#define MARGIN 0.95			/* margin within frame */
X
X/***********************************************************************/
X  
X
Xchar *strcpy(),*strncpy(),*strcat(),*sprintf();	/* for lint only */
X
Xchar *make_labl();
X
Xextern BOOLEAN autoscale;
Xextern FILE *outfile;
Xextern BOOLEAN log_y;
Xextern int term;
Xextern BOOLEAN draw_border;
X
Xextern BOOLEAN screen_ok;
Xextern BOOLEAN term_init;
X
Xextern double loff,roff,toff,boff;
Xextern double zero;
X
Xextern enum GRAV_DIR   gravity, explode;
Xextern int             samples;
Xextern double          base;
Xextern BOOLEAN         p_clockwise, b_clockwise;
Xextern double          radexp, treshold;
Xextern double          b_wid, b_spc, b_int;
Xextern char            thrname[];
X
Xextern float           xsize, ysize;
X
Xextern char tic_form[];
X
Xextern enum FONT_STYLE vect_font;
X	
Xextern struct termentry term_tbl[];
Xextern struct dfile data_head;	/* static head of data list */
X
Xextern struct label_def *first_label;	/* defined in flblarr.c */
Xextern struct linearrow_def *first_arrow;	/* defined in flblarr.c */
X
X#ifndef toascii
X#define toascii(A) (((int)(A)) & 0x7F)
X#endif
X
X#define SIGN(A) (A>=0 ? 1 : -1)
X
Xextern struct Char trt[];	/* font translation table */
X
Xstatic struct termentry *t;				/* faster */
Xstatic int xbase, ybase, xmaxp, ymaxp;	/* viewport */
Xstatic struct xptr *across;				/* used for xplot */
Xstatic int first_element;				/* first element for autolabeling */
Xstatic BOOLEAN trotate;					/* whether terminal can rotate text or not */
Xstatic int tstate;						/* state of terminal text rotation */
Xstatic int howmuch;						/* how much space takes as text the longest used value */
X
Xdo_plot(xplot,style,fel)
XBOOLEAN xplot;
Xenum DRAW_STYLE style;
Xint fel;
X{
X	/**This bloody part of code initializes graphic *
X	 * environment, draws borders, outputs trailer, *
X	 * etc. Before calling drawing fuctions it cal- *
X	 * culates  viewport  (see toff,boff,roff,loff) *
X	 * and some other variables used in any style.  *
X	 *   Ough,  how I long to Pascal's nested local *
X	 * procedures !!!                               */
X
X	BOOLEAN dolabel = (data_head.fname != (char *)NULL);
X	int effect, x, y, x0, dx, y0, dy;
X	struct label_def *lb;
X	struct linearrow_def *ar;
X	
X	t = &term_tbl[term];
X	if (!(*t->scale)(xsize, ysize)) {
X		x = t->xmax * xsize;
X		y = t->ymax * ysize;
X	}
X	else {
X		x = t->xmax;
X		y = t->ymax;
X	}
X	
X	y0 = ybase = (int) ((boff>1.0 ? boff/100.0 : boff)*y) + 1;
X	dy = ymaxp = (int) ((1.0-(toff>1.0 ? toff/100.0 : toff))*(y-2)) - (dolabel ? 3*t->v_char : 0);
X	if (ymaxp <= ybase)
X		int_error("no space to put title, change offsets", NO_CARET);
X	x0 = xbase = (int) ((loff>1.0 ? loff/100.0 : loff)*x) + 1;
X	dx = xmaxp = (int) ((1.0-(roff>1.0 ? roff/100.0 : roff))*(x-2));
X
X	across = (struct xptr *) data_head.data;
X	first_element = fel;
X	
X	if (!term_init) {
X		(*t->init)();
X		term_init = TRUE;
X	}
X	screen_ok = FALSE;
X	(*t->graphics)();
X	trotate = (*t->text_angle)(0);		/* mostly harmless */
X	tstate  = 0;
X
X	switch (style) {
X		case ABARS    : effect = dr_abar(xplot);
X			break;
X		case SBAR     : effect = dr_sbar(xplot);
X			break;
X		case LAYB     : effect = dr_lbar(xplot);
X			break;
X		case PIECHART : effect = dr_pies(xplot);
X			break;
X		default :
X			(*t->text)();
X			(void) fflush(outfile);
X			int_error("style not yet implemented",NO_CARET);
X	}
X
X	if (!effect) {
X		(*t->text)();
X		(void) fflush(outfile);
X		int_error("too many data to make sensible picture", NO_CARET);
X	}
X	
X	(*t->linetype)(-2); /* border linetype */
X	if (draw_border) {	/* draw plot border */
X		(*t->move)(0,0);	
X		(*t->vector)(x-1,0);	
X		(*t->vector)(x-1,y-1);	
X		(*t->vector)(0,y-1);	
X		(*t->vector)(0,0);
X	}
X
X	(*t->linetype)(0);	/* only one guaranted to be solid */
X	if (dolabel)		/* put title */
X		put_txt((x0+dx)/2, (int)(dy+3*t->v_char/2), data_head.fname, CENTRE, 0);
X
X	for (lb=first_label; lb; lb=lb->next) {		/* process and put labels */
X		double c_x = lb->x <= 1.0 ? lb->x : lb->x/RESOLUTION;
X		double c_y = lb->y <= 1.0 ? lb->y : lb->y/RESOLUTION;
X		double c_h = lb->h <= 1.0 ? lb->h : lb->h/RESOLUTION;
X		double c_w = lb->w <= 1.0 ? lb->w : lb->w/RESOLUTION;
X		int lx, ly, r_x, r_y, r0x, r0y;
X		if (!*lb->text)
X			continue;
X
X		if (lb->paged) {
X			r0x =  r0y   = 0;
X			r_x = x; r_y = y;
X		}
X		else {
X			r0x = x0;    r0y = y0;
X			r_x = dx-x0; r_y = dy-y0;
X		}
X		lx = r0x + c_x*r_x;
X		ly = r0y + c_y*r_y;
X
X		if ((lb->rot == L_NORMAL || lb->rot == L_BOTTOM) &&
X			!lb->h && !lb->w)					/* try to put it as a normal text */
X			put_txt(lx, ly, lb->text, lb->pos, lb->rot==L_NORMAL ? 0 : 1);
X		else {
X			double an = (int)lb->rot * Pi/2;
X			if (!lb->h && !lb->w)				/* use standard size */
X				(void) draw_text(lx, ly, lb->text, (int)t->v_char, 0, -1, lb->pos, lb->rot==L_RANDOM ? lb->a : an);
X			else								/* draw_text will worry */
X				(void) draw_text(lx, ly, lb->text, (int)(c_h*r_y), (int)(c_w*r_x),
X						  -1, lb->pos, lb->rot==L_RANDOM ? lb->a : an);
X		}
X	}
X
X	for (ar=first_arrow; ar; ar=ar->next) {		/* process and put arrows/lines */
X		double c_sx = ar->sx <= 1.0 ? ar->sx : ar->sx/RESOLUTION;
X		double c_sy = ar->sy <= 1.0 ? ar->sy : ar->sy/RESOLUTION;
X		double c_ex = ar->ex <= 1.0 ? ar->ex : ar->ex/RESOLUTION;
X		double c_ey = ar->ey <= 1.0 ? ar->ey : ar->ey/RESOLUTION;
X		int sx,sy,ex,ey;
X		if (ar->startp) {
X			sx = x*c_sx;
X			sy = y*c_sy;
X		}
X		else {
X			sx = x0 + (dx-x0)*c_sx;
X			sy = y0 + (dy-y0)*c_sy;
X		}
X		if (ar->endp) {
X			ex = x*c_ex;
X			ey = y*c_ey;
X		}
X		else {
X			ex = x0 + (dx-x0)*c_ex;
X			ey = y0 + (dy-y0)*c_ey;
X		}
X
X		if (ar->arrow)
X			(*t->arrow)(sx, sy, ex, ey);
X		else {
X			(*t->move)(sx, sy);
X			(*t->vector)(ex, ey);
X		}
X	}
X			
X	(*t->text)();
X	(void) fflush(outfile);
X}
X
X#define MCx(PT,R,AN) nint((PT)+(R)*cos(AN))
X#define MCy(PT,R,AN) nint((PT)+(R)*sin(AN))
X
Xput_arc(x,y,r,a0,da)
Xint x,y,r;
Xdouble a0,da;
X/* draw arc from a0, da long */
X{
X	double step, drto;
X	int iter;
X
X	(*t->move)(MCx(x,r,a0),MCy(y,r,a0)); 
X	step = 2*Pi/samples * (da>0.0 ? 1 : -1);	/* angle step */
X	iter = nint(floor(da/step));				/* number of iterations - makes loop faster */
X	drto = a0 + step;							/* next place to draw */
X	while (iter--) {
X		(*t->vector)(MCx(x,r,drto),MCy(y,r,drto));
X		drto += step;
X	}
X	(*t->vector)(MCx(x,r,a0+da),MCy(y,r,a0+da));	/* last part - prob. shorter */
X}
X			  
Xput_bar(x0,y0,dx,dy,turn)
Xint x0,y0,dx,dy,turn;
X/* put single bar (opened rectangle) */
X{
X	if (turn) (*t->move)(x0,y0+dy);
X	else {
X		(*t->move)(x0,y0);
X		(*t->vector)(x0,y0+dy);
X	}
X	(*t->vector)(x0+dx,y0+dy);
X	(*t->vector)(x0+dx,y0);
X	if (turn) 
X		(*t->vector)(x0,y0);
X}
X
XBOOLEAN find_ran(min, max, sum, lab)
Xdouble *min, *max, *sum;
Xchar **lab;		/* NULL if all labels undefined; "" if labels different; else pointer to the good label */
X/**find function used for stacked bars: find min, max and total sum across all data. *
X * Check also possibility of labelling across etc. */
X{
X	int i;
X	vreal w;
X	static char nothing[] = "";
X	int labfound = 1;
X	char *good = NULL, *aux;
X	
X	*min = VERYLARGE;
X	*max = -VERYLARGE;
X	*sum = 0.0;
X	for (i=0; i<data_head.chunks; i++) {
X		if (!across[i].chnp || (w=across[i].chnp->dval[across[i].vindex]) == VERYLARGE) continue;
X		if (*min > w) *min = w;
X		if (*max < w) *max = w;
X		*sum += w;
X		if (labfound && across[i].chnp->vlbl && (aux = across[i].chnp->vlbl[across[i].vindex]))
X			if (!good)	/* first found */
X				good = aux;
X			else
X				labfound = !strcmp(good,aux);
X	}
X
X	if (!good)			/* no label found, all undefined */
X		*lab = NULL;
X	else if (labfound)	/* all labels are the same -- return any */
X		*lab = good;
X	else 				/* different -- return fake label (will be processed in function, but rejected later) */
X		*lab = nothing;
X	
X	if (*min == VERYLARGE || *max == -VERYLARGE)		/* all points undefined */
X		return(FALSE);
X	else
X		return(TRUE);
X}
X
Xchar *comm_lget()
X/* check labels (like find_ran above), but also advance pointers */
X{
X	int i, j;
X	static char nothing[] = "";
X	int labfound = 1;
X	char *good = NULL, *aux;
X
X	for (i=0; i<data_head.chunks; i++) {
X		if (!across[i].chnp) continue;
X		j = across[i].vindex;
X		if (across[i].chnp->dval[j] != VERYLARGE && across[i].chnp->vlbl && (aux = across[i].chnp->vlbl[j]))
X			if (!good)	/* first found */
X				good = aux;
X			else
X				labfound = !strcmp(good,aux);
X		if (++across[i].vindex == across[i].chnp->used) {
X			across[i].chnp = across[i].chnp->next;
X			across[i].vindex = 0;
X		}
X	}
X
X	if (!good)		/* no label found, all undefined */
X		return (NULL);
X	else if (labfound)		/* all labels are the same -- return any */
X		return (good);
X	else
X		return (nothing);
X}
X	
Xdo_axis(a1,a2,xb,xm,yb,ym,reserved)
Xdouble *a1, *a2;
Xint xb, xm, yb, ym;
XBOOLEAN reserved;		/* should we shrink drawing area, or there's enough space ? */
X/* draws axis for bars, reserve space for values, put tickmarks with labels */
X{
X	double minv = *a1, maxv = *a2, tick, minpl, maxpl, unit;
X	int dirNS = !((int)gravity&1);
X	int i, j, space;
X
X	space = dirNS ? (ym-yb)/t->v_char : (xm-xb)/t->h_char;
X	if (minv == maxv)
X		tick=0;
X	else if (log_y) {
X		minpl = minv = floor(minv)+log10(2.0)<minv ? floor(minv)+log10(2.0) : floor(minv);
X		maxpl = maxv = ceil(maxv)-log10(2.0)>maxv ? ceil(maxv)-log10(2.0) : ceil(maxv);
X		tick = floor(log10(maxv-minv))+1;
X	}
X	else {
X		double aux = fabs(minv)>fabs(maxv) ? fabs(minv) : fabs(maxv);
X		tick = exp10(floor(log10(aux)));
X		aux  = exp10(floor(log10(aux)-1));
X		minpl = tick * ceil(minv/tick);
X		maxpl = tick * floor(maxv/tick);
X		minv = aux * floor(minv/aux);
X		maxv = aux * ceil(maxv/aux);
X		if ((maxv-minv)/tick <= 3.0) {
X			int flip = 1;
X			do {
X				tick /= flip ? 2.0 : 5.0;
X				flip = 1-flip;
X				minpl = tick * ceil(minv/tick);
X				maxpl = tick * floor(maxv/tick);
X			} while ((maxv-minv)/tick <= 3.0);
X		}
X		if ((maxpl-minpl)/tick >= (double)space) {
X			int flip = 1;
X			do {
X				tick *= flip ? 5.0 : 2.0;
X				flip = 1-flip;
X				minpl = tick * ceil(minv/tick);
X				maxpl = tick * floor(maxv/tick);
X			} while ((maxpl-minpl)/tick >= (double)space);
X		}
X	}
X
X	if (!tick) return(0);
X
X	unit = (dirNS ? ym-yb : xm-xb)/(maxv-minv);
X	(*t->linetype)(0);		/* solid linetype */
X	switch (gravity) {
X		case SOUTH:
X			if (!reserved)
X				xb += t->h_char*howmuch + 2*t->h_tic;
X			j = xb - 2*t->h_tic;
X			(*t->move)(xb,yb);
X			(*t->vector)(xb,ym);
X			(*t->linetype)(0);		/* the only type solid for sure */
X			while (minpl<=maxpl) {
X				(*t->move)(xb,i=yb+nint((minpl-minv)*unit));
X				(*t->vector)(xb-t->h_tic,i);
X				put_txt(j, i, make_labl((double) (log_y ? exp10(minpl) : minpl)), RIGHT, 0);
X				minpl += tick;
X			}
X			break;
X		case NORTH:
X			if (!reserved)
X				xm -= t->h_char*howmuch + 2*t->h_tic;
X			j = xm + 2*t->h_tic;
X			(*t->move)(xm,yb);
X			(*t->vector)(xm,ym);
X			(*t->linetype)(0);		/* the only type solid for sure */
X			while (minpl<=maxpl) {
X				(*t->move)(xm,i=ym-nint((minpl-minv)*unit));
X				(*t->vector)(xm+t->h_tic,i);
X				put_txt(j, i, make_labl((double) (log_y ? exp10(minpl) : minpl)), LEFT, 0);
X				minpl += tick;
X			}
X			break;
X		case WEST:
X			if (!reserved)
X				ym -= t->v_char*howmuch + 2*t->v_tic;
X			j = ym + 2*t->v_tic;
X			(*t->move)(xb,ym);
X			(*t->vector)(xm,ym);
X			(*t->linetype)(0);		/* the only type solid for sure */
X			while (minpl<=maxpl) {
X				(*t->move)(i=xb+nint((minpl-minv)*unit),ym);
X				(*t->vector)(i,ym+t->v_tic);
X				put_txt(i, j, make_labl((double) (log_y ? exp10(minpl) : minpl)), LEFT, 1);
X				minpl += tick;
X			}
X			break;
X		case EAST:
X			if (!reserved)
X				yb += t->v_char*howmuch + 2*t->v_tic;
X			j = yb - 2*t->v_tic;
X			(*t->move)(xm,yb);
X			(*t->vector)(xb,yb);
X			(*t->linetype)(0);		/* the only type solid for sure */
X			while (minpl<=maxpl) {
X				(*t->move)(i=xm-nint((minpl-minv)*unit),yb);
X				(*t->vector)(i,yb-t->v_tic);
X				put_txt(i, j, make_labl((double) (log_y ? exp10(minpl) : minpl)), RIGHT, 1); 
X				minpl += tick;
X			}
X			break;
X	}
X
X	*a1 = minv; *a2 = maxv;
X	return ( (int) (2*(dirNS ? t->h_tic : t->v_tic) + howmuch*(dirNS ? t->h_char : t->v_char)) );
X		/* if (reserved), return value is rejected, so it doesn't matter */
X}
X
X/* from hereon go different labeling functions. The basic one is the first */
X
Xint draw_text(x, y, s, h, w, tc, just, an)
Xint x, y, h, w, tc;
Xchar *s;
Xenum JUSTIFY just;
Xdouble an;
X/* draw text in vector font and return useful info - complementary of h parameter */
X{
X	int wid, k, retv, rwid;
X	char *p;
X	double sc;
X	int *d;
X	MATRIX R, S, A;
X
X	if (!s || !*s || !tc || !h && !w)
X		return(0);		/* nothing useful can be done */
X	if (tc>0 && tc < strlen(s))
X		s[tc] = '\0';	/* truncate */
X	
X	for (p=s, wid=0; *p; p++)
X		if (!trt[*p=toascii(*p)].wid)
X			wid += trt[0].wid + CHAR_OFF;
X		else
X			wid += trt[*p].wid + CHAR_OFF;
X	rwid = wid;
X	
X	rotat(-an, R);							/* rotate object system (!) */
X	
X	if (h) {
X		sc = (double)(h) / (double)CHAR_GRD;
X		wid *= sc;
X		retv = wid;
X	}
X	else
X		wid = 0;
X	if (!wid || w && wid > w) {				/* can't with with desired height -- try to schrink */
X		sc = (double)(w)/(double)(rwid);
X		wid = w;
X		retv = CHAR_GRD*sc;					/* return text height */
X	}
X	scale(sc, sc, S);
X	multi(S, R, A);
X	
X	switch (just) {
X		case LEFT: break;
X		case CENTRE: {
X			wid /= 2;	/* and no break */
X		}
X		case RIGHT: {
X			x -= (double)wid*cos(an);		/* rotate within coordinate system */
X			y -= (double)wid*sin(an);
X		}
X	}	
X	if (x<0 || y<0) 
X		return(0);	/* nothing useful - failed */
X
X#ifdef NO_ROMAN_FONT
X
X	x += (CHAR_OFF/2)*A[0][0]+A[0][2];
X	y += (CHAR_OFF/2)*A[1][0]+A[1][2]; 
X
X#define MX(v) nint( (*(v))*A[0][0] + (*(v+1))*A[0][1] + A[0][2] )
X#define MY(v) nint( (*(v))*A[1][0] + (*(v+1))*A[1][1] + A[1][2] )
X
X	{
X		unsigned char *u;
X		int i,j;
X		for ( ; *s; wid=trt[*s].wid, x+=(wid+CHAR_OFF)*A[0][0]+A[0][2], y+=(wid+CHAR_OFF)*A[1][0]+A[1][2], s++) {
X			if (!trt[c=*s].wid) c='\0';
X			for (i=0; i<3 && (u=trt[c].def[i]); i++) {
X				(*t->move) (x+MX(u), y+MY(u));
X				while (*(u+=2))
X					(*t->vector) (x+MX(u), y+MY(u));
X			}
X		}
X	}
X
X#undef MX
X#undef MY
X
X#else		/* another algorithm: for roman font */
X
X	x -= (CHAR_OFF/2)*A[0][0]+A[0][2];
X	y -= (CHAR_OFF/2)*A[1][0]+A[1][2]; 
X
X#define MX(v) nint( ((v)/100)*A[0][0] + ((v)%100)*A[0][1] + A[0][2] )
X#define MY(v) nint( ((v)/100)*A[1][0] + ((v)%100)*A[1][1] + A[1][2] )
X
X	for ( ; *s; wid=trt[*s].wid, x+=(wid+CHAR_OFF)*A[0][0]+A[0][2], y+=(wid+CHAR_OFF)*A[1][0]+A[1][2], s++)
X		for (d=trt[*s].def; *d; d++)
X			if ((k=*d)<0) {
X				k = abs(k);
X				(*t->move)(x+MX(k), y+MY(k));
X			}
X			else
X				(*t->vector)(x+MX(k), y+MY(k));
X	
X#undef MX
X#undef MY
X	
X#endif	
X
X	return(retv);
X}
X
Xmake_just(x, y, j, l, d)
Xint *x, *y;
Xint l, d;				/* l != 0 */
Xenum JUSTIFY j;
X/* set terminal justification */
X{
X	if (!d) { 
X		if (j == LEFT) 
X			(void) (*t->justify_text)(LEFT);
X		else if ((*t->justify_text)(j)) ;
X		else if (j == CENTRE)
X			*x -= t->h_char * l/2;
X		else if (j == RIGHT)
X			*x -= t->h_char * l;
X		else /* impossible */ return;
X	}
X	else {
X		if (j == LEFT) 
X			(void) (*t->justify_text)(LEFT);
X		else if ((*t->justify_text)(j)) ;
X		else if (j == CENTRE)
X			*y -= t->h_char * l/2;
X		else if (j == RIGHT)
X			*y -= t->h_char * l;
X		else /* impossible */ return;
X	}
X}
X
Xput_txt(x,y,s,j,d)
Xint x, y, d;
Xchar *s;
Xenum JUSTIFY j;
X/* put any text on given position, with standard size, sideways or rotated +Pi/2 */
X{
X	if (!s || !*s) return;
X	if ((trotate || !d) && vect_font == F_WHENN ||		/* terminal can or need not rotate */
X		vect_font == F_NEVER) {							/* never use vector font, regardles of anything */
X		if (tstate != d)
X			(*t->text_angle)(tstate = d);
X		make_just(&x, &y, j, strlen(s), d);
X		(*t->put_text)(x, y, s);
X	}			
X	else {		/* use vector font */
X		int i = t->v_char;
X		if (d)
X			x += t->h_char/2;	/* draw_text takes lower-left corner */
X		else
X			y -= t->h_char/2;
X		(void) draw_text(x, y, s, i, 0, -1, j, d*Pi/2);
X	}
X}
X
Xput_lab(x,y,s,d,size)
Xint x, y, d, size;
Xchar *s;
X/* put label centered around (x,y), fitting it within given size, use vector font if only allowed */
X{
X	int i, j, l;
X
X	if (!s || !*s || size<=0)
X		return;		/* nothing useful */
X
X	j = size / t->h_char;							/* number of standard chars that can fit */
X	i = (l=strlen(s)) < howmuch ? howmuch : l;		/* how many chars should we fit ? */
X
X	if (vect_font == F_NEVER || 					/* never use vector font */
X		!d && i <= j && vect_font != F_ALWYS) {		/* horizontal, fits within req. size, no need for font */
X		if (tstate != d)
X			(*t->text_angle)(tstate = d);
X		make_just(&x, &y, CENTRE, strlen(s), d);
X		(*t->put_text)(x, y, s);
X	}
X	else {											/* pain in the ass */
X		if (d)
X			x += t->h_char/2;						/* draw_text takes lower-left corner */
X		else
X			y -= t->v_char/2;
X		i = t->v_char;
X		(void) draw_text(x, y, s, i, size, -1, CENTRE, d*Pi/2);
X	}
X}
X
Xchar *make_labl(d)
Xdouble d;
X{
X	static char buf[200];
X	if (d == VERYLARGE || d== -VERYLARGE)
X		return(NULL);	/* will be rejected later */
X	sprintf(buf, tic_form, (float) d);	/* it's float from user point of view, and compatibility with Gnuplot */
X	return(buf);
X}
X
Xset_hm(min, max)
Xdouble min, max;
X/* find space needed for ticks */
X{
X	char buf[200];
X	int i;
X	sprintf(buf, tic_form, (float) min);
X	howmuch = strlen(buf);
X	sprintf(buf, tic_form, (float) max);
X	if (howmuch < (i=strlen(buf)))
X		howmuch = i;
X}
X
Xinit_acrs()
X/* init across pointer structure */
X{
X	struct dfile *f = &data_head;
X	int i = 0;
X
X	while (f = f->dnxt) {
X		across[i].chnp = f->data;
X		across[i++].vindex = 0;
X	}
X}
X
X/* test terminal by drawing border and text */
X/* called from command test */
Xterm_test()
X/* don't use original test_term() from term.c */
X{
X	char *str;
X	int x,y, xl,yl, i;
X	char label[MAX_LINE_LEN];
X
X	t = &term_tbl[term];
X	if (!term_init) {
X	   (*t->init)();
X	   term_init = TRUE;
X	}
X	screen_ok = FALSE;
X	(*t->graphics)();
X	/* border linetype */
X	(*t->linetype)(-2);
X	(*t->move)(0,0);
X	(*t->vector)(t->xmax-1,0);
X	(*t->vector)(t->xmax-1,t->ymax-1);
X	(*t->vector)(0,t->ymax-1);
X	(*t->vector)(0,0);
X	(void) (*t->justify_text)(LEFT);
X	(*t->put_text)(t->h_char*5,t->ymax-t->v_char*3,"Terminal Test");
X	(*t->linetype)(0);
X	(*t->arrow)(t->h_char*5, t->ymax-t->v_char*5, t->h_char*5, t->ymax/2+t->v_char);
X	/* axis linetype */
X	(*t->linetype)(-1);
X	(*t->move)(t->xmax/2,0);
X	(*t->vector)(t->xmax/2,t->ymax-1);
X	(*t->move)(0,t->ymax/2);
X	(*t->vector)(t->xmax-1,t->ymax/2);
X	/* test width and height of characters */
X	(*t->linetype)(-2);
X	(*t->move)(  t->xmax/2-t->h_char*10,t->ymax/2+t->v_char/2);
X	(*t->vector)(t->xmax/2+t->h_char*10,t->ymax/2+t->v_char/2);
X	(*t->vector)(t->xmax/2+t->h_char*10,t->ymax/2-t->v_char/2);
X	(*t->vector)(t->xmax/2-t->h_char*10,t->ymax/2-t->v_char/2);
X	(*t->vector)(t->xmax/2-t->h_char*10,t->ymax/2+t->v_char/2);
X	(*t->put_text)(t->xmax/2-t->h_char*10,t->ymax/2,
X		"12345678901234567890");
X	/* test justification */
X	(void) (*t->justify_text)(LEFT);
X	(*t->put_text)(t->xmax/2,t->ymax/2+t->v_char*5,"left justified");
X	str = "centre+d text";
X	if ((*t->justify_text)(CENTRE))
X		(*t->put_text)(t->xmax/2,
X				t->ymax/2+t->v_char*4,str);
X	else
X		(*t->put_text)(t->xmax/2-strlen(str)*t->h_char/2,
X				t->ymax/2+t->v_char*4,str);
X	str = "right justified";
X	if ((*t->justify_text)(RIGHT))
X		(*t->put_text)(t->xmax/2,
X				t->ymax/2+t->v_char*3,str);
X	else
X		(*t->put_text)(t->xmax/2-strlen(str)*t->h_char,
X				t->ymax/2+t->v_char*3,str);
X	/* test text angle */
X	str = "rotated ce+ntred text";
X	if ((*t->text_angle)(1)) {
X		if ((*t->justify_text)(CENTRE))
X			(*t->put_text)(t->v_char,
X				t->ymax/2,str);
X		else
X			(*t->put_text)(t->v_char,
X				t->ymax/2-strlen(str)*t->h_char/2,str);
X	}
X	else {
X	    (void) (*t->justify_text)(LEFT);
X	    (*t->put_text)(t->h_char*2,t->ymax/2-t->v_char*2,"Can't rotate text");
X	}
X	(void) (*t->justify_text)(LEFT);
X	(void) (*t->text_angle)(0);
X	/* test tic size */
X	(*t->move)(t->xmax/2+t->h_tic*2,0);
X	(*t->vector)(t->xmax/2+t->h_tic*2,t->v_tic);
X	(*t->move)(t->xmax/2,t->v_tic*2);
X	(*t->vector)(t->xmax/2+t->h_tic,t->v_tic*2);
X	(*t->put_text)(t->xmax/2+t->h_tic*2,t->v_tic*2+t->v_char/2,"test tics");
X	/* test line and point types */
X	x = t->xmax - t->h_char*4 - t->h_tic*4;
X	y = t->ymax - t->v_char;
X	for ( i = -2; y > t->v_char; i++ ) {
X		(*t->linetype)(i);
X		(void) sprintf(label,"%d",i);
X		if ((*t->justify_text)(RIGHT))
X			(*t->put_text)(x,y,label);
X		else
X			(*t->put_text)(x-strlen(label)*t->h_char,y,label);
X		(*t->move)(x+t->h_char,y);
X		(*t->vector)(x+t->h_char*4,y);
X		y -= t->v_char;
X	}
X	/* test bars */
X	(*t->linetype)(-1);
X	x = t->xmax/2 + t->xmax/12;
X	y = t->ymax/6;
X	xl = t->xmax/32;
X	yl = t->ymax/32;
X	(*t->move)(x,y);
X	(*t->vector)(x+xl*6,y);
X	x += xl/4;
X	for (i=1; i<=4; i++, x+=xl*3/2) {
X		(*t->linetype)(i-1);
X		put_bar(x,y,xl,i*yl,FALSE);
X	}
X	/* test pies */
X	(*t->linetype)(0);
X	x = t->xmax/4;
X	y = t->ymax/4;
X	i = 3*(t->xmax < t->ymax ? t->xmax : t->ymax)/32;
X	xl = MCx(0,i,Pi/4);
X	yl = MCy(0,i,Pi/4);
X	(*t->move)(x+xl,y+yl);
X	(*t->vector)(x-xl,y-yl);
X	(*t->move)(x-xl,y+yl);
X	(*t->vector)(x+xl,y-yl);
X	put_arc(x,y,i,Pi/4,3*Pi/2);
X	sprintf(label,"(pie sampling is %d)",samples);
X	put_txt(x,y-yl-2*(int)(t->v_char),label,CENTRE,0);
X	x += t->xmax/32;
X	(*t->move)(x+xl,y-yl);
X	(*t->vector)(x,y);
X	(*t->vector)(x+xl,y+yl);
X	put_arc(x,y,i,Pi/4,-Pi/2);
X
X	/* experimental code */
X	(*t->linetype)(0);
X	x = t->xmax/2 + t->xmax/32;
X	y = t->ymax*9/10;
X	i = t->v_char;
X	x += draw_text(x, y, "experimental", i, 0, -1, LEFT, 0.0);
X	i = draw_text(x, y, "scalable", i*2, 0, -1, LEFT, -Pi/4);
X	x += i*cos(-Pi/4); y += i*sin(-Pi/4);
X	(void) draw_text(x, y, "vector font", 0, (int)(t->xmax/16), -1, LEFT, -Pi/2);
X	y -= (int)(t->xmax/16);
X	(void) draw_text(x, y, "0123456789", 0, (int)(t->xmax/8), -1, LEFT, -Pi); 
X	
X	/* and back into text mode */
X	(*t->text)();
X	(void) fflush(outfile);
X}
X
X
X
X
X
X
X
X
X
X
X/* included file contains an old version of graphics routines */
X
X#include "fstyles.i"
X
X
X
X
X
SHAR_EOF
$TOUCH -am 0604152590 fgraf.c &&
chmod 0666 fgraf.c ||
echo "restore of fgraf.c failed"
set `wc -c fgraf.c`;Wc_c=$1
if test "$Wc_c" != "22428"; then
	echo original size 22428, current size $Wc_c
fi
echo "End of part 2, continue with part 3"
exit 0