/* GNUPLOT - plot.c */
/*[
* Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the complete modified source code. Modifications are to
* be distributed as patches to the released version. Permission to
* distribute binaries produced by compiling modified sources is granted,
* provided you
* 1. distribute the corresponding source modifications from the
* released version in the form of a patch file along with the binaries,
* 2. add special version identification to distinguish your version
* in addition to the base release version number,
* 3. provide your name and address as the primary contact for the
* support of your modified version, and
* 4. retain our contact information in regard to use of the base
* software.
* Permission to distribute the released version of the source code along
* with corresponding source modifications in the form of a patch file is
* granted with same provisions 2 through 4 for binary distributions.
*
* This software is provided "as is" without express or implied warranty
* to the extent permitted by applicable law.
]*/
#include "syscfg.h"
#include "plot.h"
#include "alloc.h"
#include "command.h"
#include "eval.h"
#include "fit.h"
#include "gp_hist.h"
#include "misc.h"
#include "readline.h"
#include "setshow.h"
#include "term_api.h"
#include "util.h"
#include "variable.h"
#include "version.h"
#include "voxelgrid.h"
#include "encoding.h"
#include "xdg.h"
#include
#include
#ifdef OS2
# define INCL_REXXSAA
# include
#endif /* OS2 */
#if defined(MSDOS) || defined(__EMX__) || (defined(WGP_CONSOLE) && defined(MSVC))
# include
#endif
#ifdef VMS
# include "vms.h"
# ifndef __GNUC__
# include
# endif
# include
# include
extern smg$create_virtual_keyboard();
extern smg$create_key_table();
#endif /* VMS */
#ifdef _WIN32
# include
# include "win/winmain.h"
# include "win/wcommon.h"
# include // for isatty
#endif /* _WIN32 */
/* GNU readline
* Only required by two files directly,
* so I don't put this into a header file. -lh
*/
#if defined(HAVE_LIBREADLINE) && !defined(MISSING_RL_TILDE_EXPANSION)
# include
extern int rl_complete_with_tilde_expansion;
#endif
/* BSD editline
*/
#ifdef HAVE_LIBEDITLINE
# include
#endif
/* enable gnuplot history with readline */
#ifdef GNUPLOT_HISTORY
# ifndef GNUPLOT_HISTORY_FILE
# define GNUPLOT_HISTORY_FILE "~/.gnuplot_history"
# endif
/*
* expanded_history_filename points to the value from 'tilde_expand()',
* which expands '~' to the user's home directory, or $HOME.
* Depending on your OS you have to make sure that the "$HOME" environment
* variable exists. You are responsible for valid values.
*/
static char *expanded_history_filename;
static void wrapper_for_write_history(void);
#endif /* GNUPLOT_HISTORY */
TBOOLEAN interactive = TRUE; /* FALSE if stdin not a terminal */
TBOOLEAN noinputfiles = TRUE; /* FALSE if there are script files */
TBOOLEAN reading_from_dash=FALSE; /* True if processing "-" as an input file */
TBOOLEAN skip_gnuplotrc = FALSE; /* skip system gnuplotrc and ~/.gnuplot */
TBOOLEAN persist_cl = FALSE; /* --persist command line option */
TBOOLEAN slow_font_startup = FALSE; /* --slow command line option */
/* user home directory */
static const char *user_homedir = NULL;
/* user shell */
const char *user_shell = NULL;
/* not static because unset.c refers to it when in debugging mode */
TBOOLEAN successful_initialization = FALSE;
#ifdef X11
extern int X11_args(int, char **); /* FIXME: defined in term/x11.trm */
#endif
/* patch to get home dir, see command.c */
#if defined(MSDOS) || defined(OS2)
char HelpFile[PATH_MAX];
static char progpath[PATH_MAX] = "";
#endif
/* a longjmp buffer to get back to the command line */
static JMP_BUF command_line_env;
static void load_rcfile(int where);
static RETSIGTYPE inter(int anint);
static void init_memory(void);
static int exit_status = EXIT_SUCCESS;
/* Flag for asynchronous handling of Ctrl-C. Used by fit.c and Windows */
TBOOLEAN ctrlc_flag = FALSE;
/* Flag for (asynchronous) term signal on Windows. */
TBOOLEAN terminate_flag = FALSE;
#ifdef OS2
# include
static ULONG RexxInterface(PRXSTRING, PUSHORT, PRXSTRING);
TBOOLEAN CallFromRexx = FALSE;
#endif /* OS2 */
static RETSIGTYPE
inter(int anint)
{
(void) anint; /* avoid -Wunused warning */
(void) signal(SIGINT, (sigfunc) inter);
(void) signal(SIGFPE, SIG_DFL); /* turn off FPE trapping */
#ifdef OS2
if (!strcmp(term->name,"pm")) {
PM_intc_cleanup();
/* ??
putc('\n', stderr);
LONGJMP(command_line_env, TRUE);
*/
} else
#endif
#if defined(WGP_CONSOLE)
/* The Windows console Ctrl-C handler runs in another thread. So a
longjmp() would result in crash. Instead, we handle these
events asynchronously.
*/
ctrlc_flag = TRUE;
/* Interrupt ConsoleGetch. */
SendMessage(graphwin->hWndGraph, WM_NULL, 0, 0);
SendMessage(GetConsoleWindow(), WM_CHAR, 0x20, 0);
#else
{
term_reset();
(void) putc('\n', stderr);
bail_to_command_line(); /* return to prompt */
}
#endif
}
/* Normally we return to the command line at a point equivalent
* to program entry, so most context is lost. All loops and
* loaded command files are exited; open files are closed, etc.
*
* The exception to this is when an error is encountered during a
* "fit" command. In this case the program returns to the same
* point it would have reached if the fit command had succeeded,
* possibly inside a loop or a loaded command file.
*/
void
bail_to_command_line()
{
#ifdef _WIN32
kill_pending_Pause_dialog();
ctrlc_flag = FALSE;
#endif
if (fit_env)
LONGJMP(*fit_env, TRUE);
else
LONGJMP(command_line_env, TRUE);
}
#if defined(_WIN32)
int
gnu_main(int argc_orig, char **argv)
#else
int
main(int argc_orig, char **argv)
#endif
{
int i;
/* We want the current value of argc to persist across a LONGJMP from int_error().
* Without this the compiler may put it on the stack, which LONGJMP clobbers.
* Here we try make it a volatile variable that optimization will not affect.
* Why do we not have to do the same for argv? I don't know.
* But the test cases that broke with generic argc seem fine with generic argv.
*/
static volatile int argc;
argc = argc_orig;
/* make sure that we really have revoked root access, this might happen if
gnuplot is compiled without vga support but is installed suid by mistake */
#ifdef __linux__
if (setuid(getuid()) != 0) {
fprintf(stderr,"gnuplot: refusing to run at elevated privilege\n");
exit(EXIT_FAILURE);
}
#endif
/* HBB: Seems this isn't needed any more for DJGPP V2? */
/* HBB: disable all floating point exceptions, just keep running... */
#if defined(DJGPP) && (DJGPP!=2)
_control87(MCW_EM, MCW_EM);
#endif
#ifdef OS2
{
int rc = RexxRegisterSubcomExe("GNUPLOT", (PFN) RexxInterface, NULL);
(void) rc;
# ifdef OS2_IPC
os2_ipc_setup();
# endif
}
#endif
/* malloc large blocks, otherwise problems with fragmented mem */
#ifdef MALLOCDEBUG
malloc_debug(7);
#endif
/* init progpath and get helpfile from executable directory */
#if defined(MSDOS) || defined(OS2)
{
char *s;
#ifdef __EMX__
_execname(progpath, sizeof(progpath));
#else
safe_strncpy(progpath, argv[0], sizeof(progpath));
#endif
/* convert '/' to '\\' */
for (s = progpath; *s != NUL; s++)
if (*s == DIRSEP2)
*s = DIRSEP1;
/* cut program name */
s = strrchr(progpath, DIRSEP1);
if (s != NULL)
s++;
else
s = progpath;
*s = NUL;
/* init HelpFile */
strcpy(HelpFile, progpath);
strcat(HelpFile, "gnuplot.gih");
/* remove trailing "bin/" from progpath */
if ((s != NULL) && (s - progpath >= 4)) {
s -= 4;
if (strncasecmp(s, "bin", 3) == 0)
*s = NUL;
}
}
#endif /* MSDOS || OS2 */
#if (defined(PIPE_IPC) || defined(_WIN32)) && (defined(HAVE_LIBREADLINE) || (defined(HAVE_LIBEDITLINE) && defined(X11)))
/* Editline needs this to be set before the very first call to readline(). */
/* Support for rl_getc_function is broken for utf-8 in editline. Since it is only
really required for X11, disable this section when building without X11. */
rl_getc_function = getc_wrapper;
#endif
#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
/* T.Walter 1999-06-24: 'rl_readline_name' must be this fix name.
* It is used to parse a 'gnuplot' specific section in '~/.inputrc'
* or gnuplot specific commands in '.editrc' (when using editline
* instead of readline) */
rl_readline_name = "Gnuplot";
rl_terminal_name = getenv("TERM");
#if defined(HAVE_LIBREADLINE)
using_history();
#else
history_init();
#endif
#endif
#if defined(HAVE_LIBREADLINE) && defined(RL_VERSION_MAJOR)
/* Starting with readline v8.1 bracketed paste mode is on by default.
* This breaks multi-line pasted input to gnuplot because it looks like
* one long run-on line.
*/
if (RL_VERSION_MAJOR >= 8)
rl_variable_bind ("enable-bracketed-paste", "off");
#endif
#if defined(HAVE_LIBREADLINE) && !defined(MISSING_RL_TILDE_EXPANSION)
rl_complete_with_tilde_expansion = 1;
#endif
for (i = 1; i < argc; i++) {
if (!argv[i])
continue;
if (!strcmp(argv[i], "-c")) {
/* The rest of the command line is a scriptfile and its arguments.
* Do not try to interpret them here (ignore -V, --help, etc).
*/
break;
}
if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) {
printf("gnuplot %s patchlevel %s\n",
gnuplot_version, gnuplot_patchlevel);
return 0;
} else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
printf( "Usage: gnuplot [OPTION] ... [FILE]\n"
" -V, --version\n"
" -h, --help\n"
" -p --persist\n"
" -s --slow\n"
" -d --default-settings\n"
" -c scriptfile ARG1 ARG2 ... \n"
" -e \"command1; command2; ...\"\n"
"gnuplot %s patchlevel %s\n",
gnuplot_version, gnuplot_patchlevel);
#ifdef DEVELOPMENT_VERSION
printf(
#ifdef DIST_CONTACT
"Report bugs to "DIST_CONTACT"\n"
" or %s\n",
#else
"Report bugs to %s\n",
#endif
bug_email);
#endif
return 0;
} else if (!strncmp(argv[i], "-persist", 2) || !strcmp(argv[i], "--persist")
#ifdef _WIN32
|| !stricmp(argv[i], "-noend") || !stricmp(argv[i], "/noend")
#endif
) {
persist_cl = TRUE;
} else if (!strncmp(argv[i], "-slow", 2) || !strcmp(argv[i], "--slow")) {
slow_font_startup = TRUE;
} else if (!strncmp(argv[i], "-d", 2) || !strcmp(argv[i], "--default-settings")) {
/* Skip local customization read from ~/.gnuplot */
skip_gnuplotrc = TRUE;
}
}
#ifdef X11
/* the X11 terminal removes tokens that it recognizes from argv. */
{
int n = X11_args(argc, argv);
argv += n;
argc -= n;
}
#endif
setbuf(stderr, (char *) NULL);
#ifdef HAVE_SETVBUF
/* This was once setlinebuf(). Docs say this is
* identical to setvbuf(,NULL,_IOLBF,0), but MS C
* faults this (size out of range), so we try with
* size of 1024 instead. [SAS/C does that, too. -lh]
*/
if (setvbuf(stdout, (char *) NULL, _IOLBF, (size_t) 1024) != 0)
(void) fputs("Could not linebuffer stdout\n", stderr);
/* Switching to unbuffered mode causes all characters in the input
* buffer to be lost. So the only safe time to do it is on program entry.
* Do any non-X platforms suffer from this problem?
* EAM - Jan 2013 YES.
*/
setvbuf(stdin, (char *) NULL, _IONBF, 0);
#endif
gpoutfile = stdout;
/* Initialize pre-loaded user variables */
/* "pi" is hard-wired as the first variable */
(void) add_udv_by_name("GNUTERM");
(void) add_udv_by_name("I");
(void) add_udv_by_name("NaN");
init_constants();
udv_user_head = &(udv_NaN->next_udv);
init_memory();
interactive = FALSE;
/* April 2017: We used to call init_terminal() here, but now */
/* We defer initialization until error handling has been set up. */
# if defined(_WIN32) && !defined(WGP_CONSOLE)
interactive = TRUE;
# else
interactive = isatty(fileno(stdin));
# endif
/* Note: we want to know whether this is an interactive session so that we can
* decide whether or not to write status information to stderr. The old test
* for this was to see if (argc > 1) but the addition of optional command line
* switches broke this. What we really wanted to know was whether any of the
* command line arguments are file names or an explicit in-line "-e command".
*/
for (i = 1; i < argc; i++) {
# ifdef _WIN32
if (!stricmp(argv[i], "/noend"))
continue;
# endif
if ((argv[i][0] != '-') || (argv[i][1] == 'e') || (argv[i][1] == 'c') ) {
interactive = FALSE;
break;
}
}
/* Need this before show_version is called for the first time */
if (interactive)
show_version(stderr);
else
show_version(NULL); /* Only load GPVAL_COMPILE_OPTIONS */
update_gpval_variables(3); /* update GPVAL_ variables available to user */
#ifdef VMS
/* initialise screen management routines for command recall */
{
unsigned int ierror;
if (ierror = smg$create_virtual_keyboard(&vms_vkid) != SS$_NORMAL)
done(ierror);
if (ierror = smg$create_key_table(&vms_ktid) != SS$_NORMAL)
done(ierror);
}
#endif /* VMS */
if (!SETJMP(command_line_env, 1)) {
/* first time */
interrupt_setup();
get_user_env();
init_loadpath();
init_locale();
memset(&sm_palette, 0, sizeof(sm_palette));
init_fit(); /* Initialization of fitting module */
#ifdef READLINE
/* When using the built-in readline, we set the initial
encoding according to the locale as this is required
to properly handle keyboard input. */
init_encoding();
#endif
init_gadgets();
/* April 2017: Now that error handling is in place, it is safe parse
* GNUTERM during terminal initialization.
* atexit processing is done in reverse order. We want
* the generic terminal shutdown in term_reset to be executed before
* any terminal specific cleanup requested by individual terminals.
*/
init_terminal();
push_terminal(0); /* remember the initial terminal */
gp_atexit(term_reset);
/* Execute commands in ~/.gnuplot */
init_session();
if (interactive && term != 0) { /* not unknown */
#ifdef GNUPLOT_HISTORY
#if (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)) && !defined(_WIN32)
expanded_history_filename = tilde_expand(GNUPLOT_HISTORY_FILE);
#else
expanded_history_filename = gp_strdup(GNUPLOT_HISTORY_FILE);
gp_expand_tilde(&expanded_history_filename);
#endif
if (read_history(expanded_history_filename)) {
#ifdef USE_XDG_BASEDIR
/* use $XDG_STATE_DIR/gnuplot_history only if
* $XDG_STATE_DIR exists or can be created */
char *xdgpath = xdg_get_path(kXDGStateHome, "gnuplot_history",
FALSE /* no subdir */, TRUE /* create */);
if (xdgpath) {
free(expanded_history_filename);
expanded_history_filename = xdgpath;
read_history(expanded_history_filename);
}
#endif /* USE_XDG_BASEDIR */
}
/*
* It is safe to ignore the return values of 'atexit()' and
* 'on_exit()'. In the worst case, there is no history of your
* current session and you have to type all again in your next
* session.
*/
gp_atexit(wrapper_for_write_history);
#endif /* GNUPLOT_HISTORY */
#if defined(READLINE) && defined(WGP_CONSOLE)
fprintf(stderr, "Encoding set to '%s'.\n", encoding_names[encoding]);
#endif
} /* if (interactive && term != 0) */
} else {
/* come back here from int_error() */
if (!successful_initialization) {
/* Only print the warning once */
successful_initialization = TRUE;
fprintf(stderr,"WARNING: Error during initialization\n\n");
}
if (interactive == FALSE)
exit_status = EXIT_FAILURE;
#ifdef HAVE_READLINE_RESET
else {
/* reset properly readline after a SIGINT+longjmp */
rl_reset_after_signal ();
}
#endif
/* If we were in a "load", "call", or nested bracketed clause
* clean up the lf_push/pop stack and restore shadowed variables.
*/
clause_reset_after_error();
lf_reset_after_error();
SET_CURSOR_ARROW;
#ifdef VMS
/* after catching interrupt */
/* VAX stuffs up stdout on SIGINT while writing to stdout,
so reopen stdout. */
if (gpoutfile == stdout) {
if ((stdout = freopen("SYS$OUTPUT", "w", stdout)) == NULL) {
/* couldn't reopen it so try opening it instead */
if ((stdout = fopen("SYS$OUTPUT", "w")) == NULL) {
/* don't use int_error here - causes infinite loop! */
fputs("Error opening SYS$OUTPUT as stdout\n", stderr);
}
}
gpoutfile = stdout;
}
#endif /* VMS */
/* Why a goto? Because we exited the loop below via int_error */
/* using LONGJMP. The compiler was not expecting this, and */
/* "optimized" the handling of argc and argv such that simply */
/* entering the loop again from the top finds them messed up. */
/* If we reenter the loop via a goto then there is some hope */
/* that code reordering does not hurt us. */
if (reading_from_dash && interactive)
goto RECOVER_FROM_ERROR_IN_DASH;
reading_from_dash = FALSE;
if (!interactive && !noinputfiles) {
term_reset();
gp_exit(EXIT_FAILURE); /* exit on non-interactive error */
}
}
/* load filenames given as arguments */
while (--argc > 0) {
++argv;
c_token = 0;
if (!strncmp(*argv, "-persist", 2) || !strcmp(*argv, "--persist")
#ifdef _WIN32
|| !stricmp(*argv, "-noend") || !stricmp(*argv, "/noend")
#endif
) {
FPRINTF((stderr,"'persist' command line option recognized\n"));
} else if (strcmp(*argv, "-") == 0) {
#if defined(_WIN32) && !defined(WGP_CONSOLE)
TextShow(&textwin);
interactive = TRUE;
#else
interactive = isatty(fileno(stdin));
#endif
RECOVER_FROM_ERROR_IN_DASH:
reading_from_dash = TRUE;
while (!com_line());
reading_from_dash = FALSE;
interactive = FALSE;
noinputfiles = FALSE;
} else if (strcmp(*argv, "-e") == 0) {
int save_state = interactive;
--argc; ++argv;
if (argc udv_value), 0.0, 1.0);
}
/*
* Initialize graphics context, color palette, local preferences.
* Called both at program startup and by "reset session".
*/
void
init_session()
{
/* Disable pipes and system commands during initialization */
successful_initialization = FALSE;
/* Undefine any previously-used variables */
del_udv_by_name("",TRUE);
/* Restore default colors before loading local preferences */
set_colorsequence(1);
/* Reset program variables not handled by 'reset' */
overflow_handling = INT64_OVERFLOW_TO_FLOAT;
suppress_warnings = FALSE;
/* Reset voxel data structures if supported */
init_voxelsupport();
/* Make sure all variables start in the same state 'reset'
* would set them to.
*/
reset_command(); /* FIXME: this does c_token++ */
load_rcfile(0); /* System-wide gnuplotrc if configured */
load_rcfile(1); /* ./.gnuplot if configured */
/* After this point we allow pipes and system commands */
successful_initialization = TRUE;
load_rcfile(2); /* ~/.gnuplot */
load_rcfile(3); /* ~/.config/gnuplot/gnuplotrc */
}
/*
* Read commands from an initialization file.
* where = 0: look for gnuplotrc in system shared directory
* where = 1: look for .gnuplot in current directory
* where = 2: look for .gnuplot in home directory
*/
static void
load_rcfile(int where)
{
FILE *plotrc = NULL;
char *rcfile = NULL;
if (skip_gnuplotrc)
return;
if (where == 0) {
#ifdef GNUPLOT_SHARE_DIR
# if defined(_WIN32) || defined(MSDOS) || defined(OS2)
rcfile = RelativePathToGnuplot(GNUPLOT_SHARE_DIR "\\gnuplotrc");
# else
rcfile = (char *) gp_alloc(strlen(GNUPLOT_SHARE_DIR) + 1 + strlen("gnuplotrc") + 1, "rcfile");
strcpy(rcfile, GNUPLOT_SHARE_DIR);
PATH_CONCAT(rcfile, "gnuplotrc");
# endif
plotrc = fopen(rcfile, "r");
#endif
} else if (where == 1) {
#ifdef USE_CWDRC
/* Allow check for a .gnuplot init file in the current directory */
/* This is a security risk, as someone might leave a malicious */
/* init file in a shared directory. */
plotrc = fopen(PLOTRC, "r");
#endif /* !USE_CWDRC */
} else if (where == 2 && user_homedir) {
/* length of homedir + directory separator + length of file name + \0 */
int len = (user_homedir ? strlen(user_homedir) : 0) + 1 + strlen(PLOTRC) + 1;
rcfile = gp_alloc(len, "rcfile");
strcpy(rcfile, user_homedir);
PATH_CONCAT(rcfile, PLOTRC);
plotrc = fopen(rcfile, "r");
} else if (where == 3) {
#ifdef USE_XDG_BASEDIR
rcfile = xdg_get_path(kXDGConfigHome, "gnuplotrc",
TRUE /* use subdir */, FALSE /* not create */);
if (rcfile)
plotrc = fopen(rcfile, "r");
#endif
}
if (plotrc) {
char *rc = gp_strdup(rcfile ? rcfile : PLOTRC);
load_file(plotrc, rc, 3);
push_terminal(0); /* needed if terminal or its options were changed */
}
free(rcfile);
}
void
get_user_env()
{
if (user_homedir == NULL) {
const char *env_home;
if ((env_home = getenv(HOME))
#ifdef _WIN32
|| (env_home = appdata_directory())
|| (env_home = getenv("USERPROFILE"))
#endif
|| (env_home = getenv("HOME"))
)
user_homedir = (const char *) gp_strdup(env_home);
else if (interactive)
int_warn(NO_CARET, "no HOME found");
}
if (user_shell == NULL) {
const char *env_shell;
if ((env_shell = getenv("SHELL")) == NULL)
#if defined(MSDOS) || defined(_WIN32) || defined(OS2)
if ((env_shell = getenv("COMSPEC")) == NULL)
#endif
env_shell = SHELL;
user_shell = (const char *) gp_strdup(env_shell);
}
}
/* expand tilde in path
* path cannot be a static array!
* tilde must be the first character in *pathp;
* we may change that later
*/
void
gp_expand_tilde(char **pathp)
{
if (!*pathp)
int_error(NO_CARET, "Cannot expand empty path");
if ((*pathp)[0] == '~' && (*pathp)[1] == DIRSEP1) {
if (user_homedir) {
size_t n = strlen(*pathp);
*pathp = gp_realloc(*pathp, n + strlen(user_homedir), "tilde expansion");
/* include null at the end ... */
memmove(*pathp + strlen(user_homedir) - 1, *pathp, n + 1);
memcpy(*pathp, user_homedir, strlen(user_homedir));
} else
int_warn(NO_CARET, "HOME not set - cannot expand tilde");
}
}
static void
init_memory()
{
extend_input_line();
extend_token_table();
replot_line = gp_strdup("");
}
#ifdef OS2
int
ExecuteMacro(char *argv, int namelength)
{
RXSTRING rxRc;
RXSTRING rxArg[2];
int rxArgCount = 0;
char pszName[CCHMAXPATH];
char *rxArgStr;
short sRc;
long rc;
if (namelength >= sizeof(pszName))
return 1;
safe_strncpy(pszName, argv, sizeof(pszName));
rxArgStr = &argv[namelength];
RXSTRPTR(rxRc) = NULL;
/*
REXX standard calling (gnuplot 3.7pl1 and above):
The program name is not supplied and so all actual arguments
are in a single string:
Parse Arg param
We even handle blanks like cmd.exe when calling REXX programs.
*/
if (*rxArgStr) {
MAKERXSTRING(rxArg[0], rxArgStr, strlen(rxArgStr));
rxArgCount++;
}
CallFromRexx = TRUE;
rc = RexxStart(
rxArgCount,
rxArg,
pszName,
NULL,
"GNUPLOT",
RXCOMMAND,
NULL,
&sRc,
&rxRc);
CallFromRexx = FALSE;
/* am: a word WRT errors codes:
the negative ones don't seem to have symbolic names, you can get
them from the OREXX reference, they're not in REXX Programming Guide -
no idea where to retrieve them from a Warp 3 reference ??
The positive ones are somehow referenced in REXXPG
*/
if (rc < 0) {
/* REXX error */
} else if (rc > 0) {
/* Interpreter couldn't be started */
if (rc == -4)
/* run was cancelled, but don't give error message */
rc = 0;
} else if (rc==0) {
/* all was fine */
}
/* We don't we try to use rxRc ?
BTW, don't use free() instead since it's allocated inside RexxStart()
and not in our executable using the EMX libraries */
if (RXSTRPTR(rxRc))
/* I guess it's NULL if something major went wrong,
NULL strings are usually not part of the REXX language ... */
DosFreeMem(rxRc.strptr);
return rc;
}
/* Rexx command line interface */
ULONG
RexxInterface(PRXSTRING rxCmd, PUSHORT pusErr, PRXSTRING rxRc)
{
int rc;
static JMP_BUF keepenv;
int cmdlen;
memcpy(keepenv, command_line_env, sizeof(JMP_BUF));
if (!SETJMP(command_line_env, 1)) {
/* Set variable gp_input_line.
Watch out for line length of NOT_ZERO_TERMINATED strings ! */
cmdlen = rxCmd->strlength + 1;
safe_strncpy(gp_input_line, rxCmd->strptr, gp_input_line_len);
gp_input_line[cmdlen] = NUL;
rc = do_line();
*pusErr = RXSUBCOM_OK;
rxRc->strptr[0] = rc + '0';
rxRc->strptr[1] = NUL;
rxRc->strlength = strlen(rxRc->strptr);
} else {
/*
We end up here when bail_to_command_line() is called.
Therefore sometimes this call should be avoided when
executing a REXX program (e.g. 'Cancel' from
PM GUI after a 'pause -1' command)
*/
*pusErr = RXSUBCOM_ERROR;
RexxSetHalt(getpid(), 1);
}
memcpy(command_line_env, keepenv, sizeof(JMP_BUF));
return 0;
}
#endif /* OS2 */
#ifdef GNUPLOT_HISTORY
/* cancel_history() can be called by terminals that fork a helper process
* to make sure that the helper doesn't trash the history file on exit.
*/
void
cancel_history()
{
expanded_history_filename = NULL;
}
# if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
static void
wrapper_for_write_history()
{
if (!expanded_history_filename)
return;
if (history_is_stifled())
unstifle_history();
if (gnuplot_history_size >= 0)
stifle_history (gnuplot_history_size);
/* returns 0 on success */
if (write_history(expanded_history_filename))
fprintf (stderr, "Warning: Could not write history file!!!\n");
unstifle_history();
}
# else /* HAVE_LIBREADLINE || HAVE_LIBEDITLINE */
/* version for gnuplot's own write_history */
static void
wrapper_for_write_history()
{
/* What we really want to do is truncate(expanded_history_filename),
but this is only available on BSD compatible systems */
if (!expanded_history_filename)
return;
remove(expanded_history_filename);
if (gnuplot_history_size < 0)
write_history(expanded_history_filename);
else
write_history_n(gnuplot_history_size, expanded_history_filename, "w");
}
# endif /* HAVE_LIBREADLINE || HAVE_LIBEDITLINE */
#endif /* GNUPLOT_HISTORY */
void
restrict_popen()
{
if (!successful_initialization)
int_error(NO_CARET,"Pipes and shell commands not permitted during initialization");
}
#if defined(MSDOS) || defined(OS2)
/* retrieve path relative to gnuplot executable */
char *
RelativePathToGnuplot(const char * path)
{
char * rel_path, *s;
rel_path = (char * ) gp_alloc(strlen(progpath) + strlen(path) + 1, "RelativePathToGnuplot");
strcpy(rel_path, progpath);
/* progpath is guaranteed to have a trailing slash */
strcat(rel_path, path);
/* convert slashes to backslashes */
for (s = rel_path;*s != NUL; s++)
if (*s == DIRSEP2)
*s = DIRSEP1;
return rel_path;
}
#endif