File: [local] / OpenXM_contrib / gnuplot / Attic / command.c (download)
Revision 1.1.1.2 (vendor branch), Sat Jan 22 14:15:56 2000 UTC (24 years, 8 months ago) by maekawa
Branch: GNUPLOT
CVS Tags: maekawa-ipv6, VERSION_3_7_1, RELEASE_20000124, RELEASE_1_2_2, RELEASE_1_2_1, RELEASE_1_1_3, RELEASE_1_1_2 Changes since 1.1.1.1: +12 -12
lines
Import gnuplot 3.7.1
|
#ifndef lint
static char *RCSid = "$Id: command.c,v 1.20.2.1 1999/08/19 14:42:21 lhecking Exp $";
#endif
/* GNUPLOT - command.c */
/*[
* Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the complete modified source code. Modifications are to
* be distributed as patches to the released version. Permission to
* distribute binaries produced by compiling modified sources is granted,
* provided you
* 1. distribute the corresponding source modifications from the
* released version in the form of a patch file along with the binaries,
* 2. add special version identification to distinguish your version
* in addition to the base release version number,
* 3. provide your name and address as the primary contact for the
* support of your modified version, and
* 4. retain our contact information in regard to use of the base
* software.
* Permission to distribute the released version of the source code along
* with corresponding source modifications in the form of a patch file is
* granted with same provisions 2 through 4 for binary distributions.
*
* This software is provided "as is" without express or implied warranty
* to the extent permitted by applicable law.
]*/
/*
* Changes:
*
* Feb 5, 1992 Jack Veenstra (veenstra@cs.rochester.edu) Added support to
* filter data values read from a file through a user-defined function before
* plotting. The keyword "thru" was added to the "plot" command. Example
* syntax: f(x) = x / 100 plot "test.data" thru f(x) This example divides all
* the y values by 100 before plotting. The filter function processes the
* data before any log-scaling occurs. This capability should be generalized
* to filter x values as well and a similar feature should be added to the
* "splot" command.
*
* 19 September 1992 Lawrence Crowl (crowl@cs.orst.edu)
* Added user-specified bases for log scaling.
*/
#include "plot.h"
#include "setshow.h"
#include "fit.h"
#include "binary.h"
#if defined(MSDOS) || defined(DOS386)
# ifdef DJGPP
extern char HelpFile[]; /* patch for do_help - AP */
# endif /* DJGPP */
# ifdef __TURBOC__
# ifndef _Windows
extern unsigned _stklen = 16394; /* increase stack size */
extern char HelpFile[]; /* patch for do_help - DJL */
# endif /* _Windows */
# endif /* TURBOC */
#endif /* MSDOS */
#ifndef _Windows
# include "help.h"
#else
static int winsystem __PROTO((char *));
#endif /* _Windows */
#ifndef STDOUT
# define STDOUT 1
#endif
#ifdef _Windows
# include <windows.h>
# ifdef __MSC__
# include <malloc.h>
# else
# include <alloc.h>
# include <dir.h> /* setdisk() */
# endif /* !MSC */
# include "win/wgnuplib.h"
extern TW textwin;
extern LPSTR winhelpname;
extern void screen_dump(void); /* in term/win.trm */
extern int Pause(LPSTR mess); /* in winmain.c */
#endif /* _Windows */
#ifdef _Windows
# define SET_CURSOR_WAIT SetCursor(LoadCursor((HINSTANCE) NULL, IDC_WAIT))
# define SET_CURSOR_ARROW SetCursor(LoadCursor((HINSTANCE) NULL, IDC_ARROW))
#else
# define SET_CURSOR_WAIT /* nought, zilch */
# define SET_CURSOR_ARROW /* nought, zilch */
#endif
#ifdef OS2
/* emx has getcwd, chdir that can handle drive names */
# define chdir _chdir2
extern int PM_pause(char *); /* term/pm.trm */
extern int ExecuteMacro(char *, int); /* plot.c */
#endif /* OS2 */
#ifdef VMS
int vms_vkid; /* Virtual keyboard id */
int vms_ktid; /* key table id, for translating keystrokes */
#endif /* VMS */
/* Used by vws.trm */
void replotrequest __PROTO((void));
/* static prototypes */
static int command __PROTO((void));
static int read_line __PROTO((char *prompt));
static void do_shell __PROTO((void));
static void do_help __PROTO((int toplevel));
static void do_system __PROTO((void));
static int changedir __PROTO((char *path));
/* input data, parsing variables */
#ifdef AMIGA_SC_6_1
__far int num_tokens, c_token;
#else
int num_tokens, c_token;
#endif
struct lexical_unit *token;
int token_table_size;
char *input_line;
int input_line_len;
int inline_num; /* input line number */
struct udft_entry *dummy_func; /* NULL means no dummy vars active */
char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1]; /* current dummy vars */
/* support for replot command */
char *replot_line;
int plot_token; /* start of 'plot' command */
/* If last plot was a 3d one. */
TBOOLEAN is_3d_plot = FALSE;
#define Inc_c_token if (++c_token >= num_tokens) \
int_error ("Syntax error", c_token);
/* support for dynamic size of input line */
void extend_input_line()
{
if (input_line_len == 0) {
/* first time */
input_line = gp_alloc(MAX_LINE_LEN, "input_line");
input_line_len = MAX_LINE_LEN;
input_line[0] = NUL;
} else {
input_line = gp_realloc(input_line, input_line_len + MAX_LINE_LEN, "extend input line");
input_line_len += MAX_LINE_LEN;
FPRINTF((stderr, "extending input line to %d chars\n", input_line_len));
}
}
void extend_token_table()
{
if (token_table_size == 0) {
/* first time */
token = (struct lexical_unit *) gp_alloc(MAX_TOKENS * sizeof(struct lexical_unit), "token table");
token_table_size = MAX_TOKENS;
} else {
token = gp_realloc(token, (token_table_size + MAX_TOKENS) * sizeof(struct lexical_unit), "extend token table");
token_table_size += MAX_TOKENS;
FPRINTF((stderr, "extending token table to %d elements\n", token_table_size));
}
}
void init_memory()
{
extend_input_line();
extend_token_table();
replot_line = gp_alloc(1, "string");
*replot_line = NUL;
}
int com_line()
{
if (multiplot) {
/* calls int_error() if it is not happy */
term_check_multiplot_okay(interactive);
if (read_line("multiplot> "))
return (1);
} else {
if (read_line(PROMPT))
return (1);
}
/* So we can flag any new output: if false at time of error,
* we reprint the command line before printing caret.
* TRUE for interactive terminals, since the command line is typed.
* FALSE for non-terminal stdin, so command line is printed anyway.
* (DFK 11/89)
*/
screen_ok = interactive;
if (do_line())
return (1);
else
return (0);
}
int do_line()
{
/* Line continuation has already been handled
* by read_line() */
char *inlptr = input_line;
/* Skip leading whitespace */
while (isspace((int)*inlptr))
inlptr++;
if (inlptr != input_line) {
/* If there was leading whitespace, copy the actual
* command string to the front. use memmove() because
* source and target overlap */
memmove(input_line,inlptr,strlen(inlptr));
/* Terminate resulting string */
input_line[strlen(inlptr)] = NUL;
}
FPRINTF((stderr, "Input line: \"%s\"\n",input_line));
/* also used in load_file */
if (is_system(input_line[0])) {
do_system();
if (interactive) /* 3.5 did it unconditionally */
(void) fputs("!\n", stderr); /* why do we need this ? */
return (0);
}
num_tokens = scanner(input_line);
c_token = 0;
while (c_token < num_tokens) {
if (command())
return (1);
if (c_token < num_tokens) { /* something after command */
if (equals(c_token, ";"))
c_token++;
else
int_error("';' expected", c_token);
}
}
return (0);
}
void define()
{
register int start_token; /* the 1st token in the function definition */
register struct udvt_entry *udv;
register struct udft_entry *udf;
if (equals(c_token + 1, "(")) {
/* function ! */
int dummy_num = 0;
struct at_type *at_tmp;
char save_dummy[MAX_NUM_VAR][MAX_ID_LEN + 1];
memcpy(save_dummy, c_dummy_var, sizeof(save_dummy));
start_token = c_token;
do {
c_token += 2; /* skip to the next dummy */
copy_str(c_dummy_var[dummy_num++], c_token, MAX_ID_LEN);
} while (equals(c_token + 1, ",") && (dummy_num < MAX_NUM_VAR));
if (equals(c_token + 1, ","))
int_error("function contains too many parameters", c_token + 2);
c_token += 3; /* skip (, dummy, ) and = */
if (END_OF_COMMAND)
int_error("function definition expected", c_token);
udf = dummy_func = add_udf(start_token);
if ((at_tmp = perm_at()) == (struct at_type *) NULL)
int_error("not enough memory for function", start_token);
if (udf->at) /* already a dynamic a.t. there */
free((char *) udf->at); /* so free it first */
udf->at = at_tmp; /* before re-assigning it. */
memcpy(c_dummy_var, save_dummy, sizeof(save_dummy));
m_capture(&(udf->definition), start_token, c_token - 1);
dummy_func = NULL; /* dont let anyone else use our workspace */
} else {
/* variable ! */
start_token = c_token;
c_token += 2;
udv = add_udv(start_token);
(void) const_express(&(udv->udv_value));
udv->udv_undef = FALSE;
}
}
static int command()
{
FILE *fp;
int i;
/* string holding name of save or load file */
char sv_file[MAX_LINE_LEN + 1];
for (i = 0; i < MAX_NUM_VAR; i++)
c_dummy_var[i][0] = NUL; /* no dummy variables */
if (is_definition(c_token))
define();
else if (almost_equals(c_token, "h$elp") || equals(c_token, "?")) {
c_token++;
do_help(1);
} else if (equals(c_token, "testtime")) {
/* given a format and a time string, exercise the time code */
char format[160], string[160];
struct tm tm;
double secs;
if (isstring(++c_token)) {
quote_str(format, c_token, 159);
if (isstring(++c_token)) {
quote_str(string, c_token++, 159);
memset(&tm, 0, sizeof(tm));
gstrptime(string, format, &tm);
secs = gtimegm(&tm);
fprintf(stderr, "internal = %f - %d/%d/%d::%d:%d:%d , wday=%d, yday=%d\n",
secs, tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday, tm.tm_yday);
memset(&tm, 0, sizeof(tm));
ggmtime(&tm, secs);
gstrftime(string, 159, format, secs);
fprintf(stderr, "convert back \"%s\" - %d/%d/%d::%d:%d:%d , wday=%d, yday=%d\n",
string, tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday, tm.tm_yday);
}
}
} else if (almost_equals(c_token, "test")) {
c_token++;
test_term();
} else if (almost_equals(c_token, "scr$eendump")) {
c_token++;
#ifdef _Windows
screen_dump();
#else
fputs("screendump not implemented\n", stderr);
#endif
} else if (almost_equals(c_token, "pa$use")) {
struct value a;
int sleep_time, text = 0;
char buf[MAX_LINE_LEN + 1];
c_token++;
sleep_time = (int) real(const_express(&a));
buf[0] = NUL;
if (!(END_OF_COMMAND)) {
if (!isstring(c_token))
int_error("expecting string", c_token);
else {
quote_str(buf, c_token, MAX_LINE_LEN);
++c_token;
#ifdef _Windows
if (sleep_time >= 0)
#else
# ifdef OS2
if (strcmp(term->name, "pm") != 0 || sleep_time >= 0)
# else
# ifdef MTOS
if (strcmp(term->name, "mtos") != 0 || sleep_time >= 0)
# endif /* MTOS */
# endif /* OS2 */
#endif /* _Windows */
fputs(buf, stderr);
text = 1;
}
}
if (sleep_time < 0) {
#ifdef _Windows
if (!Pause(buf))
bail_to_command_line();
#else
# ifdef OS2
if (strcmp(term->name, "pm") == 0 && sleep_time < 0) {
int rc;
if ((rc = PM_pause(buf)) == 0)
bail_to_command_line();
else if (rc == 2) {
fputs(buf, stderr);
text = 1;
(void) fgets(buf, MAX_LINE_LEN, stdin);
}
}
# else /* !OS2 */
# ifdef _Macintosh
if (strcmp(term->name, "macintosh") == 0 && sleep_time < 0)
Pause(sleep_time);
# else /* !_Macintosh */
# ifdef MTOS
if (strcmp(term->name, "mtos") == 0) {
int MTOS_pause(char *buf);
int rc;
if ((rc = MTOS_pause(buf)) == 0)
bail_to_command_line();
else if (rc == 2) {
fputs(buf, stderr);
text = 1;
(void) fgets(buf, MAX_LINE_LEN, stdin);
}
} else if (strcmp(term->name, "atari") == 0) {
char *readline(char *);
char *line = readline("");
if (line)
free(line);
} else
(void) fgets(buf, MAX_LINE_LEN, stdin);
# else /* !MTOS */
# ifdef ATARI
if (strcmp(term->name, "atari") == 0) {
char *readline(char *);
char *line = readline("");
if (line)
free(line);
} else
(void) fgets(buf, MAX_LINE_LEN, stdin);
# else /* !ATARI */
(void) fgets(buf, MAX_LINE_LEN, stdin);
/* Hold until CR hit. */
# endif /* !ATARI */
# endif /* !MTOS */
# endif /* !_Macintosh */
# endif /* !OS2 */
#endif
}
if (sleep_time > 0)
GP_SLEEP(sleep_time);
if (text != 0 && sleep_time >= 0)
fputc('\n', stderr);
screen_ok = FALSE;
} else if (almost_equals(c_token, "pr$int")) {
int need_space = 0; /* space printed between two expressions only */
screen_ok = FALSE;
do {
++c_token;
if (isstring(c_token)) {
char s[MAX_LINE_LEN];
quote_str(s, c_token, MAX_LINE_LEN);
fputs(s, stderr);
need_space = 0;
++c_token;
} else {
struct value a;
(void) const_express(&a);
if (need_space)
putc(' ', stderr);
need_space = 1;
disp_value(stderr, &a);
}
} while (!END_OF_COMMAND && equals(c_token, ","));
(void) putc('\n', stderr);
} else if (almost_equals(c_token, "fit")) {
++c_token;
do_fit();
} else if (almost_equals(c_token, "up$date")) {
char tmps[80];
char tmps2[80];
/* Have to initialise tmps2, otherwise
* update() cannot decide whether a valid
* filename was given. lh
*/
tmps2[0] = NUL;
if (!isstring(++c_token))
int_error("Parameter filename expected", c_token);
quote_str(tmps, c_token++, 80);
if (!(END_OF_COMMAND)) {
if (!isstring(c_token))
int_error("New parameter filename expected", c_token);
else
quote_str(tmps2, c_token++, 80);
}
update(tmps, tmps2);
} else if (almost_equals(c_token, "p$lot")) {
plot_token = c_token++;
SET_CURSOR_WAIT;
plotrequest();
SET_CURSOR_ARROW;
} else if (almost_equals(c_token, "sp$lot")) {
plot_token = c_token++;
SET_CURSOR_WAIT;
plot3drequest();
SET_CURSOR_ARROW;
} else if (almost_equals(c_token, "rep$lot")) {
if (replot_line[0] == NUL)
int_error("no previous plot", c_token);
c_token++;
SET_CURSOR_WAIT;
replotrequest();
SET_CURSOR_ARROW;
} else if (almost_equals(c_token, "se$t"))
set_command();
else if (almost_equals(c_token, "res$et"))
reset_command();
else if (almost_equals(c_token, "sh$ow"))
show_command();
else if (almost_equals(c_token, "cl$ear")) {
term_start_plot();
if (multiplot && term->fillbox) {
unsigned int x1 = (unsigned int) (xoffset * term->xmax);
unsigned int y1 = (unsigned int) (yoffset * term->ymax);
unsigned int width = (unsigned int) (xsize * term->xmax);
unsigned int height = (unsigned int) (ysize * term->ymax);
(*term->fillbox) (0, x1, y1, width, height);
}
term_end_plot();
screen_ok = FALSE;
c_token++;
} else if (almost_equals(c_token, "she$ll")) {
do_shell();
screen_ok = FALSE;
c_token++;
} else if (almost_equals(c_token, "sa$ve")) {
if (almost_equals(++c_token, "f$unctions")) {
if (!isstring(++c_token))
int_error("expecting filename", c_token);
else {
quote_str(sv_file, c_token, MAX_LINE_LEN);
save_functions(fopen(sv_file, "w"));
}
} else if (almost_equals(c_token, "v$ariables")) {
if (!isstring(++c_token))
int_error("expecting filename", c_token);
else {
quote_str(sv_file, c_token, MAX_LINE_LEN);
save_variables(fopen(sv_file, "w"));
}
} else if (almost_equals(c_token, "s$et")) {
if (!isstring(++c_token))
int_error("expecting filename", c_token);
else {
quote_str(sv_file, c_token, MAX_LINE_LEN);
save_set(fopen(sv_file, "w"));
}
} else if (isstring(c_token)) {
quote_str(sv_file, c_token, MAX_LINE_LEN);
save_all(fopen(sv_file, "w"));
} else {
int_error("filename or keyword 'functions', 'variables', or 'set' expected", c_token);
}
c_token++;
} else if (almost_equals(c_token, "l$oad")) {
if (!isstring(++c_token))
int_error("expecting filename", c_token);
else {
quote_str(sv_file, c_token, MAX_LINE_LEN);
/* load_file(fp=fopen(sv_file, "r"), sv_file, FALSE); OLD
* DBT 10/6/98 handle stdin as special case
* passes it on to load_file() so that it gets
* pushed on the stack and recusion will work, etc
*/
fp = strcmp(sv_file, "-") ? fopen(sv_file, "r") : stdin;
load_file(fp, sv_file, FALSE);
/* input_line[] and token[] now destroyed! */
c_token = num_tokens = 0;
}
} else if (almost_equals(c_token, "ca$ll")) {
if (!isstring(++c_token))
int_error("expecting filename", c_token);
else {
quote_str(sv_file, c_token, MAX_LINE_LEN);
load_file(fopen(sv_file, "r"), sv_file, TRUE); /* Argument list follows filename */
/* input_line[] and token[] now destroyed! */
c_token = num_tokens = 0;
}
} else if (almost_equals(c_token, "if")) {
double exprval;
struct value t;
if (!equals(++c_token, "(")) /* no expression */
int_error("expecting (expression)", c_token);
exprval = real(const_express(&t));
if (exprval != 0.0) {
/* fake the condition of a ';' between commands */
int eolpos = token[num_tokens - 1].start_index + token[num_tokens - 1].length;
--c_token;
token[c_token].length = 1;
token[c_token].start_index = eolpos + 2;
input_line[eolpos + 2] = ';';
input_line[eolpos + 3] = NUL;
} else
c_token = num_tokens = 0;
} else if (almost_equals(c_token, "rer$ead")) {
fp = lf_top();
if (fp != (FILE *) NULL)
rewind(fp);
c_token++;
} else if (almost_equals(c_token, "cd")) {
if (!isstring(++c_token))
int_error("expecting directory name", c_token);
else {
quote_str(sv_file, c_token, MAX_LINE_LEN);
if (changedir(sv_file)) {
int_error("Can't change to this directory", c_token);
}
c_token++;
}
} else if (almost_equals(c_token, "pwd")) {
GP_GETCWD(sv_file, sizeof(sv_file));
fprintf(stderr, "%s\n", sv_file);
c_token++;
} else if (almost_equals(c_token, "ex$it") ||
almost_equals(c_token, "q$uit")) {
/* graphics will be tidied up in main */
return (1);
} else if (!equals(c_token, ";")) { /* null statement */
#ifdef OS2
if (_osmode == OS2_MODE) {
if (token[c_token].is_token) {
int rc;
rc = ExecuteMacro(input_line + token[c_token].start_index,
token[c_token].length);
if (rc == 0) {
c_token = num_tokens = 0;
return (0);
}
}
}
#endif
int_error("invalid command", c_token);
}
return (0);
}
void done(status)
int status;
{
term_reset();
exit(status);
}
static int changedir(path)
char *path;
{
#if defined(MSDOS) || defined(WIN16) || defined(ATARI) || defined(DOS386)
# if defined(__ZTC__)
unsigned dummy; /* it's a parameter needed for dos_setdrive */
# endif
/* first deal with drive letter */
if (isalpha(path[0]) && (path[1] == ':')) {
int driveno = toupper(path[0]) - 'A'; /* 0=A, 1=B, ... */
# if defined(ATARI)
(void) Dsetdrv(driveno);
# endif
# if defined(__ZTC__)
(void) dos_setdrive(driveno + 1, &dummy);
# endif
# if (defined(MSDOS) && defined(__EMX__)) || defined(__MSC__)
(void) _chdrive(driveno + 1);
# endif
/* HBB: recent versions of DJGPP also have setdisk():,
* so I del'ed the special code */
# if ((defined(MSDOS) || defined(_Windows)) && defined(__TURBOC__)) || defined(DJGPP)
(void) setdisk(driveno);
# endif
path += 2; /* move past drive letter */
}
/* then change to actual directory */
if (*path)
if (chdir(path))
return 1;
return 0; /* should report error with setdrive also */
#elif defined(WIN32)
return !(SetCurrentDirectory(path));
#else
return chdir(path);
#endif /* MSDOS, ATARI etc. */
}
void replotrequest()
{
if (equals(c_token, "["))
int_error("cannot set range with replot", c_token);
/* do not store directly into the replot_line string, until the
* new plot line has been successfully plotted. This way,
* if user makes a typo in a replot line, they do not have
* to start from scratch. The replot_line will be committed
* after do_plot has returned, whence we know all is well
*/
if (END_OF_COMMAND) {
/* it must already be long enough, but lets make sure */
int len = strlen(replot_line) + 1;
while (input_line_len < len)
extend_input_line();
strcpy(input_line, replot_line);
} else {
char *replot_args = NULL; /* else m_capture will free it */
int last_token = num_tokens - 1;
/* length = length of old part + length of new part + ',' + \0 */
int newlen = strlen(replot_line) + token[last_token].start_index + token[last_token].length - token[c_token].start_index + 2;
m_capture(&replot_args, c_token, last_token); /* might be empty */
while (input_line_len < newlen)
extend_input_line();
strcpy(input_line, replot_line);
strcat(input_line, ",");
strcat(input_line, replot_args);
free(replot_args);
}
plot_token = 0; /* whole line to be saved as replot line */
screen_ok = FALSE;
num_tokens = scanner(input_line);
c_token = 1; /* skip the 'plot' part */
if (is_3d_plot)
plot3drequest();
else
plotrequest();
}
/* Support for input, shell, and help for various systems */
#ifdef VMS
# include <descrip.h>
# include <rmsdef.h>
# include <smgdef.h>
# include <smgmsg.h>
extern lib$get_input(), lib$put_output();
extern smg$read_composed_line();
extern sys$putmsg();
extern lbr$output_help();
extern lib$spawn();
int vms_len;
unsigned int status[2] = {1, 0};
static char Help[MAX_LINE_LEN+1] = "gnuplot";
$DESCRIPTOR(prompt_desc, PROMPT);
/* temporary fix until change to variable length */
struct dsc$descriptor_s line_desc =
{0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
$DESCRIPTOR(help_desc, Help);
$DESCRIPTOR(helpfile_desc, "GNUPLOT$HELP");
/* please note that the vms version of read_line doesn't support variable line
length (yet) */
static int read_line(prompt)
char *prompt;
{
int more, start = 0;
char expand_prompt[40];
prompt_desc.dsc$w_length = strlen(prompt);
prompt_desc.dsc$a_pointer = prompt;
(void) strcpy(expand_prompt, "_");
(void) strncat(expand_prompt, prompt, 38);
do {
line_desc.dsc$w_length = MAX_LINE_LEN - start;
line_desc.dsc$a_pointer = &input_line[start];
switch (status[1] = smg$read_composed_line(&vms_vkid, &vms_ktid, &line_desc, &prompt_desc, &vms_len)) {
case SMG$_EOF:
done(IO_SUCCESS); /* ^Z isn't really an error */
break;
case RMS$_TNS: /* didn't press return in time */
vms_len--; /* skip the last character */
break; /* and parse anyway */
case RMS$_BES: /* Bad Escape Sequence */
case RMS$_PES: /* Partial Escape Sequence */
sys$putmsg(status);
vms_len = 0; /* ignore the line */
break;
case SS$_NORMAL:
break; /* everything's fine */
default:
done(status[1]); /* give the error message */
}
start += vms_len;
input_line[start] = NUL;
inline_num++;
if (input_line[start - 1] == '\\') {
/* Allow for a continuation line. */
prompt_desc.dsc$w_length = strlen(expand_prompt);
prompt_desc.dsc$a_pointer = expand_prompt;
more = 1;
--start;
} else {
line_desc.dsc$w_length = strlen(input_line);
line_desc.dsc$a_pointer = input_line;
more = 0;
}
} while (more);
return 0;
}
# ifdef NO_GIH
static void do_help(toplevel)
int toplevel; /* not used for VMS version */
{
int first = c_token;
while (!END_OF_COMMAND)
++c_token;
strcpy(Help, "GNUPLOT ");
capture(Help + 8, first, c_token - 1, sizeof(Help) - 9);
help_desc.dsc$w_length = strlen(Help);
if ((vaxc$errno = lbr$output_help(lib$put_output, 0, &help_desc,
&helpfile_desc, 0, lib$get_input)) != SS$_NORMAL)
os_error("can't open GNUPLOT$HELP", NO_CARET);
}
# endif /* NO_GIH */
static void do_shell()
{
if ((vaxc$errno = lib$spawn()) != SS$_NORMAL) {
os_error("spawn error", NO_CARET);
}
}
static void do_system()
{
/* input_line[0] = ' '; an embarrassment, but... */
/* input_line is filled by read_line or load_file, but
* line_desc length is set only by read_line; adjust now
*/
line_desc.dsc$w_length = strlen(input_line) - 1;
line_desc.dsc$a_pointer = &input_line[1];
if ((vaxc$errno = lib$spawn(&line_desc)) != SS$_NORMAL)
os_error("spawn error", NO_CARET);
(void) putc('\n', stderr);
}
#endif /* VMS */
#ifdef _Windows
# ifdef NO_GIH
static void do_help(toplevel)
int toplevel; /* not used for windows */
{
if (END_OF_COMMAND)
WinHelp(textwin.hWndParent, (LPSTR) winhelpname, HELP_INDEX, (DWORD) NULL);
else {
char buf[128];
int start = c_token++;
while (!(END_OF_COMMAND))
c_token++;
capture(buf, start, c_token - 1, 128);
WinHelp(textwin.hWndParent, (LPSTR) winhelpname, HELP_PARTIALKEY, (DWORD) buf);
}
}
# endif /* NO_GIH */
#endif /* _Windows */
/*
* do_help: (not VMS, although it would work) Give help to the user. It
* parses the command line into helpbuf and supplies help for that string.
* Then, if there are subtopics available for that key, it prompts the user
* with this string. If more input is given, do_help is called recursively,
* with argument 0. Thus a more specific help can be supplied. This can be
* done repeatedly. If null input is given, the function returns, effecting
* a backward climb up the tree.
* David Kotz (David.Kotz@Dartmouth.edu) 10/89
* drd - The help buffer is first cleared when called with toplevel=1.
* This is to fix a bug where help is broken if ^C is pressed whilst in the
* help.
*/
#ifndef NO_GIH
static void do_help(toplevel)
int toplevel;
{
static char *helpbuf = NULL;
static char *prompt = NULL;
int base; /* index of first char AFTER help string */
int len; /* length of current help string */
TBOOLEAN more_help;
TBOOLEAN only; /* TRUE if only printing subtopics */
int subtopics; /* 0 if no subtopics for this topic */
int start; /* starting token of help string */
char *help_ptr; /* name of help file */
# if defined(SHELFIND)
static char help_fname[256] = ""; /* keep helpfilename across calls */
# endif
# if defined(MTOS) || defined(ATARI)
char const *const ext[] = {NULL};
# endif
if ((help_ptr = getenv("GNUHELP")) == (char *) NULL)
# ifndef SHELFIND
/* if can't find environment variable then just use HELPFILE */
/* patch by David J. Liu for getting GNUHELP from home directory */
# if (defined(__TURBOC__) && (defined(MSDOS) || defined(DOS386))) || defined(__DJGPP__)
help_ptr = HelpFile;
# else
# if defined(MTOS) || defined(ATARI)
{
if ((help_ptr = findfile(HELPFILE, getenv("GNUPLOTPATH"), ext)) == NULL)
help_ptr = findfile(HELPFILE, getenv("PATH"), ext);
if (!help_ptr)
help_ptr = HELPFILE;
}
# else
help_ptr = HELPFILE;
# endif /* MTOS || ATARI */
# endif /* __TURBOC__ */
/* end of patch - DJL */
# else /* !SHELFIND */
/* try whether we can find the helpfile via shell_find. If not, just
use the default. (tnx Andreas) */
if (!strchr(HELPFILE, ':') && !strchr(HELPFILE, '/') &&
!strchr(HELPFILE, '\\')) {
if (strlen(help_fname) == 0) {
strcpy(help_fname, HELPFILE);
if (shel_find(help_fname) == 0) {
strcpy(help_fname, HELPFILE);
}
}
help_ptr = help_fname;
} else {
help_ptr = HELPFILE;
}
# endif /* !SHELFIND */
/* Since MSDOS DGROUP segment is being overflowed we can not allow such */
/* huge static variables (1k each). Instead we dynamically allocate them */
/* on the first call to this function... */
if (helpbuf == NULL) {
helpbuf = gp_alloc((unsigned long) MAX_LINE_LEN, "help buffer");
prompt = gp_alloc((unsigned long) MAX_LINE_LEN, "help prompt");
helpbuf[0] = prompt[0] = 0;
}
if (toplevel)
helpbuf[0] = prompt[0] = 0; /* in case user hit ^c last time */
len = base = strlen(helpbuf);
/* find the end of the help command */
for (start = c_token; !(END_OF_COMMAND); c_token++);
/* copy new help input into helpbuf */
if (len > 0)
helpbuf[len++] = ' '; /* add a space */
capture(helpbuf + len, start, c_token - 1, MAX_LINE_LEN - len);
squash_spaces(helpbuf + base); /* only bother with new stuff */
lower_case(helpbuf + base); /* only bother with new stuff */
len = strlen(helpbuf);
/* now, a lone ? will print subtopics only */
if (strcmp(helpbuf + (base ? base + 1 : 0), "?") == 0) {
/* subtopics only */
subtopics = 1;
only = TRUE;
helpbuf[base] = NUL; /* cut off question mark */
} else {
/* normal help request */
subtopics = 0;
only = FALSE;
}
switch (help(helpbuf, help_ptr, &subtopics)) {
case H_FOUND:{
/* already printed the help info */
/* subtopics now is true if there were any subtopics */
screen_ok = FALSE;
do {
if (subtopics && !only) {
/* prompt for subtopic with current help string */
if (len > 0)
(void) sprintf(prompt, "Subtopic of %s: ", helpbuf);
else
(void) strcpy(prompt, "Help topic: ");
read_line(prompt);
num_tokens = scanner(input_line);
c_token = 0;
more_help = !(END_OF_COMMAND);
if (more_help)
/* base for next level is all of current helpbuf */
do_help(0);
} else
more_help = FALSE;
} while (more_help);
break;
}
case H_NOTFOUND:{
printf("Sorry, no help for '%s'\n", helpbuf);
break;
}
case H_ERROR:{
perror(help_ptr);
break;
}
default:{ /* defensive programming */
int_error("Impossible case in switch", NO_CARET);
/* NOTREACHED */
}
}
helpbuf[base] = NUL; /* cut it off where we started */
}
#endif /* !NO_GIH */
#ifndef VMS
# ifdef AMIGA_AC_5
static char *parms[80];
static char strg0[256];
static void getparms __PROTO((char *, char**));
# endif
static void do_system()
{
# ifdef AMIGA_AC_5
getparms(input_line + 1, parms);
fexecv(parms[0], parms);
# elif (defined(ATARI) && defined(__GNUC__))
/* || (defined(MTOS) && defined(__GNUC__)) */
/* use preloaded shell, if available */
short (*shell_p) (char *command);
void *ssp;
ssp = (void *) Super(NULL);
shell_p = *(short (**)(char *)) 0x4f6;
Super(ssp);
/* this is a bit strange, but we have to have a single if */
if (shell_p)
(*shell_p) (input_line + 1);
else
system(input_line + 1);
# elif defined(_Windows)
winsystem(input_line + 1);
# else /* !(AMIGA_AC_5 || ATARI && __GNUC__ || _Windows) */
/* (am, 19980929)
* OS/2 related note: cmd.exe returns 255 if called w/o argument.
* i.e. calling a shell by "!" will always end with an error message.
* A workaround has to include checking for EMX,OS/2, two environment
* variables,...
*/
system(input_line + 1);
# endif /* !(AMIGA_AC_5 || ATARI&&__GNUC__ || _Windows) */
}
# ifdef AMIGA_AC_5
/******************************************************************************
* Parses the command string (for fexecv use) and converts the first token
* to lower case
*****************************************************************************/
static void getparms(command, parms)
char *command;
char **parms;
{
register int i = 0; /* A bunch of indices */
register int j = 0;
register int k = 0;
while (*(command + j) != NUL) { /* Loop on string characters */
parms[k++] = strg0 + i;
while (*(command + j) == ' ')
++j;
while (*(command + j) != ' ' && *(command + j) != NUL) {
if (*(command + j) == '"') /* Get quoted string */
for (*(strg0 + (i++)) = *(command + (j++));
*(command + j) != '"';
*(strg0 + (i++)) = *(command + (j++)));
*(strg0 + (i++)) = *(command + (j++));
}
*(strg0 + (i++)) = NUL; /* NUL terminate every token */
}
parms[k] = NUL;
for (k = strlen(strg0) - 1; k >= 0; --k) /* Convert to lower case */
*(strg0 + k) >= 'A' && *(strg0 + k) <= 'Z' ? *(strg0 + k) |= 32 : *(strg0 + k);
}
# endif /* AMIGA_AC_5 */
# if defined(READLINE) || defined(HAVE_LIBREADLINE)
/* keep some compilers happy */
static char *rlgets __PROTO((char *s, int n, char *prompt));
static char * rlgets(s, n, prompt)
char *s;
int n;
char *prompt;
{
static char *line = (char *) NULL;
static int leftover = -1; /* index of 1st char leftover from last call */
if (leftover == -1) {
/* If we already have a line, first free it */
if (line != (char *) NULL) {
free(line);
line = NULL;
/* so that ^C or int_error during readline() does
* not result in line being free-ed twice */
}
line = readline((interactive) ? prompt : "");
leftover = 0;
/* If it's not an EOF */
if (line && *line)
add_history(line);
}
if (line) {
safe_strncpy(s, line + leftover, n);
leftover += strlen(s);
if (line[leftover] == NUL)
leftover = -1;
return s;
}
return NULL;
}
# endif /* READLINE || HAVE_LIBREADLINE */
# if defined(MSDOS) || defined(_Windows) || defined(DOS386)
static void do_shell()
{
register char *comspec;
if ((comspec = getenv("COMSPEC")) == (char *) NULL)
comspec = "\\command.com";
# ifdef _Windows
if (WinExec(comspec, SW_SHOWNORMAL) <= 32)
# else
# ifdef DJGPP
if (system(comspec) == -1)
# else
if (spawnl(P_WAIT, comspec, NULL) == -1)
# endif /* !DJGPP */
# endif /* !_Windows */
os_error("unable to spawn shell", NO_CARET);
}
# else /* !MSDOS */
/* plain old Unix */
# ifdef AMIGA_SC_6_1
static void do_shell()
{
register char *shell;
if (!(shell = getenv("SHELL")))
shell = SHELL;
if (system(shell))
os_error("system() failed", NO_CARET);
(void) putc('\n', stderr);
}
# else /* !AMIGA_SC_6_1 */
# ifdef OS2
static void do_shell()
{
register char *shell;
if (!(shell = getenv("SHELL")) && !(shell = getenv("COMSPEC")))
shell = SHELL;
if (system(shell) == -1)
os_error("system() failed", NO_CARET);
(void) putc('\n', stderr);
}
# else /* !OS2 */
#define EXEC "exec "
static void do_shell()
{
static char exec[100] = EXEC;
register char *shell;
if (!(shell = getenv("SHELL")))
shell = SHELL;
if (system(safe_strncpy(&exec[sizeof(EXEC) - 1], shell,
sizeof(exec) - sizeof(EXEC) - 1)))
os_error("system() failed", NO_CARET);
(void) putc('\n', stderr);
}
# endif /* !OS2 */
# endif /* !AMIGA_SC_6_1 */
# endif /* !MSDOS */
/* read from stdin, everything except VMS */
# if !defined(READLINE) && !defined(HAVE_LIBREADLINE)
# if (defined(MSDOS) || defined(DOS386)) && !defined(_Windows) && !defined(__EMX__) && !defined(DJGPP)
/* if interactive use console IO so CED will work */
#define PUT_STRING(s) cputs(s)
#define GET_STRING(s,l) ((interactive) ? cgets_emu(s,l) : fgets(s,l,stdin))
# ifdef __TURBOC__
/* cgets implemented using dos functions */
/* Maurice Castro 22/5/91 */
static char *doscgets __PROTO((char *));
static char *doscgets(s)
char *s;
{
long datseg;
/* protect and preserve segments - call dos to do the dirty work */
datseg = _DS;
_DX = FP_OFF(s);
_DS = FP_SEG(s);
_AH = 0x0A;
geninterrupt(33);
_DS = datseg;
/* check for a carriage return and then clobber it with a null */
if (s[s[1] + 2] == '\r')
s[s[1] + 2] = 0;
/* return the input string */
return (&(s[2]));
}
# endif /* __TURBOC__ */
# ifdef __ZTC__
void cputs(char *s)
{
register int i = 0;
while (s[i] != NUL)
bdos(0x02, s[i++], NULL);
}
char *cgets(char *s)
{
bdosx(0x0A, s, NULL);
if (s[s[1] + 2] == '\r')
s[s[1] + 2] = 0;
/* return the input string */
return (&(s[2]));
}
# endif /* __ZTC__ */
/* emulate a fgets like input function with DOS cgets */
char *cgets_emu(str, len)
char *str;
int len;
{
static char buffer[128] = "";
static int leftover = 0;
if (buffer[leftover] == NUL) {
buffer[0] = 126;
# ifdef __TURBOC__
doscgets(buffer);
# else
cgets(buffer);
# endif
fputc('\n', stderr);
if (buffer[2] == 26)
return NULL;
leftover = 2;
}
safe_strncpy(str, buffer + leftover, len);
leftover += strlen(str);
return str;
}
# else /* !plain DOS */
# define PUT_STRING(s) fputs(s, stderr)
# define GET_STRING(s,l) fgets(s, l, stdin)
# endif /* !plain DOS */
# endif /* !READLINE && !HAVE_LIBREADLINE) */
/* Non-VMS version */
static int read_line(prompt)
char *prompt;
{
int start = 0;
TBOOLEAN more = FALSE;
int last = 0;
# if !defined(READLINE) && !defined(HAVE_LIBREADLINE)
if (interactive)
PUT_STRING(prompt);
# endif /* READLINE */
do {
/* grab some input */
# if defined(READLINE) || defined(HAVE_LIBREADLINE)
if (((interactive)
? rlgets(&(input_line[start]), input_line_len - start,
((more) ? "> " : prompt))
: fgets(&(input_line[start]), input_line_len - start, stdin))
== (char *) NULL) {
# else /* !(READLINE || HAVE_LIBREADLINE) */
if (GET_STRING(&(input_line[start]), input_line_len - start)
== (char *) NULL) {
# endif /* !(READLINE || HAVE_LIBREADLINE) */
/* end-of-file */
if (interactive)
(void) putc('\n', stderr);
input_line[start] = NUL;
inline_num++;
if (start > 0) /* don't quit yet - process what we have */
more = FALSE;
else
return (1); /* exit gnuplot */
} else {
/* normal line input */
last = strlen(input_line) - 1;
if (last >= 0) {
if (input_line[last] == '\n') { /* remove any newline */
input_line[last] = NUL;
/* Watch out that we don't backup beyond 0 (1-1-1) */
if (last > 0)
--last;
} else if (last + 2 >= input_line_len) {
extend_input_line();
start = last + 1;
more = TRUE;
continue; /* read rest of line, don't print "> " */
}
if (input_line[last] == '\\') { /* line continuation */
start = last;
more = TRUE;
} else
more = FALSE;
} else
more = FALSE;
}
# if !defined(READLINE) && !defined(HAVE_LIBREADLINE)
if (more && interactive)
PUT_STRING("> ");
# endif
} while (more);
return (0);
}
#endif /* !VMS */
#ifdef _Windows
/* there is a system like call on MS Windows but it is a bit difficult to
use, so we will invoke the command interpreter and use it to execute the
commands */
static int winsystem(char *s)
{
LPSTR comspec;
LPSTR execstr;
LPSTR p;
/* get COMSPEC environment variable */
# ifdef WIN32
char envbuf[81];
GetEnvironmentVariable("COMSPEC", envbuf, 80);
if (*envbuf == NUL)
comspec = "\\command.com";
else
comspec = envbuf;
# else
p = GetDOSEnvironment();
comspec = "\\command.com";
while (*p) {
if (!strncmp(p, "COMSPEC=", 8)) {
comspec = p + 8;
break;
}
p += strlen(p) + 1;
}
# endif
/* if the command is blank we must use command.com */
p = s;
while ((*p == ' ') || (*p == '\n') || (*p == '\r'))
p++;
if (*p == NUL) {
WinExec(comspec, SW_SHOWNORMAL);
} else {
/* attempt to run the windows/dos program via windows */
if (WinExec(s, SW_SHOWNORMAL) <= 32) {
/* attempt to run it as a dos program from command line */
execstr = (char *) malloc(strlen(s) + strlen(comspec) + 6);
strcpy(execstr, comspec);
strcat(execstr, " /c ");
strcat(execstr, s);
WinExec(execstr, SW_SHOWNORMAL);
free(execstr);
}
}
/* regardless of the reality return OK - the consequences of */
/* failure include shutting down Windows */
return (0); /* success */
}
#endif /* _Windows */