/*
* gretl -- Gnu Regression, Econometrics and Time-series Library
* Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
/* command-line client program for libgretl */
#include "libgretl.h"
#include "version.h"
#include "monte_carlo.h"
#include "var.h"
#include "system.h"
#include "gretl_restrict.h"
#include "gretl_func.h"
#include "gretl_help.h"
#include "libset.h"
#include "cmd_private.h"
#include "flow_control.h"
#include "objstack.h"
#include "gretl_xml.h"
#include "gretl_string_table.h"
#include "dbread.h"
#include "uservar.h"
#include "csvdata.h"
#ifdef USE_CURL
# include "gretl_www.h"
#endif
#include
#ifdef WIN32
# include "gretl_win32.h"
#else
# include
# include
# include
# include
#endif
#ifdef HAVE_READLINE
# include
/* readline functions from complete.c */
extern char *rl_gets (char **line_read, const char *prompt);
extern void initialize_readline (void);
#endif /* HAVE_READLINE */
#define ENDRUN (NC + 1)
#define RUNLOOP (NC + 2)
char datafile[MAXLEN];
char cmdfile[MAXLEN];
FILE *fb;
int batch;
int runit;
int indent0;
int batch_stdin;
int data_status;
char linebak[MAXLINE]; /* for storing comments */
char *line_read;
static int cli_exec_line (ExecState *s, DATASET *dset, PRN *cmdprn);
static int push_input_file (FILE *fp);
static FILE *pop_input_file (void);
static int cli_saved_object_action (const char *line,
DATASET *dset,
PRN *prn);
static int parse_options (int *pargc, char ***pargv, gretlopt *popt,
double *scriptval, char *fname)
{
char **argv;
int argc, gotfile = 0;
gretlopt opt = OPT_NONE;
int err = 0;
*fname = '\0';
if (pargv == NULL) {
return 0;
}
argc = *pargc;
argv = *pargv;
while (*++argv) {
const char *s = *argv;
if (!strcmp(s, "-e") || !strncmp(s, "--english", 9)) {
opt |= OPT_ENGLISH;
} else if (!strcmp(s, "-b") || !strncmp(s, "--batch", 7)) {
opt |= OPT_BATCH;
} else if (!strcmp(s, "-h") || !strcmp(s, "--help")) {
opt |= OPT_HELP;
} else if (!strcmp(s, "-v") || !strcmp(s, "--version")) {
opt |= OPT_VERSION;
} else if (!strcmp(s, "-r") || !strncmp(s, "--run", 5)) {
opt |= OPT_RUNIT;
} else if (!strcmp(s, "-c") || !strncmp(s, "--dump", 6)) {
opt |= OPT_DUMP;
} else if (!strcmp(s, "-q") || !strcmp(s, "--quiet")) {
opt |= OPT_QUIET;
} else if (!strcmp(s, "-m") || !strcmp(s, "--makepkg")) {
opt |= OPT_MAKEPKG;
} else if (!strcmp(s, "-i") || !strcmp(s, "--instpkg")) {
opt |= OPT_INSTPKG;
} else if (!strcmp(s, "-t") || !strcmp(s, "--tool")) {
opt |= (OPT_TOOL | OPT_BATCH);
} else if (!strncmp(s, "--scriptopt=", 12)) {
*scriptval = atof(s + 12);
} else if (*s == '-' && *(s+1) != '\0') {
/* spurious option? */
fprintf(stderr, "Bad option: %s\n", s);
err = E_DATA;
break;
} else if (!gotfile) {
strncat(fname, s, MAXLEN - 1);
gotfile = 1;
}
argc--;
}
if (!err) {
err = incompatible_options(opt, OPT_BATCH | OPT_RUNIT |
OPT_DBOPEN | OPT_WEBDB | OPT_MAKEPKG);
if (!err) {
err = incompatible_options(opt, OPT_ENGLISH | OPT_BASQUE);
}
if (!err) {
err = incompatible_options(opt, OPT_MAKEPKG | OPT_INSTPKG);
}
}
*pargc = argc;
*pargv = argv;
*popt = opt;
return err;
}
static void usage (int err)
{
logo(0);
printf(_("\nYou may supply the name of a data file on the command line.\n"
"Options:\n"
" -b or --batch Process a command script and exit.\n"
" -r or --run Run a script then hand control to command line.\n"
" -m or --makepkg Run a script and create a package from it.\n"
" -i or --instpkg Install a specified function package.\n"
" -h or --help Print this info and exit.\n"
" -v or --version Print version info and exit.\n"
" -e or --english Force use of English rather than translation.\n"
" -q or --quiet Print less verbose program information.\n"
" -t or --tool Operate silently.\n"
"Example of batch mode usage:\n"
" gretlcli -b myfile.inp > myfile.out\n"
"Example of run mode usage:\n"
" gretlcli -r myfile.inp\n"));
printf(_("\nSpecial batch-mode option:\n"
" --scriptopt= sets a scalar value, accessible to a script\n"
" under the name \"scriptopt\"\n\n"));
if (err) {
exit(EXIT_FAILURE);
} else {
exit(EXIT_SUCCESS);
}
}
#if defined(OPENMP_BUILD) && !defined(WIN32) && !defined(OS_OSX)
static void check_blas_threading (int tool, int quiet)
{
char *s1, *s2;
if (get_openblas_details(&s1, &s2) && !strcmp(s2, "pthreads")) {
if (tool || quiet) {
fprintf(stderr, "Disabling OpenBLAS multi-threading "
"(OpenMP/pthreads collision)\n");
} else {
puts("\n*** Warning ***\n*\n"
"* gretl is built using OpenMP, but is linked against\n"
"* OpenBLAS parallelized via pthreads. This combination\n"
"* of threading mechanisms is not recommended. Ideally,\n"
"* OpenBLAS should also use OpenMP.");
}
/* do we really need this? */
gretl_setenv("OPENBLAS_NUM_THREADS", "1");
}
}
#endif
static void gretl_abort (char *line)
{
const char *tokline = get_parser_errline();
fprintf(stderr, _("\ngretlcli: error executing script: halting\n"));
if (tokline != NULL && *tokline != '\0' && strcmp(tokline, line)) {
fprintf(stderr, "> %s\n", tokline);
}
if (*line != '\0') {
fprintf(stderr, "> %s\n", line);
}
exit(EXIT_FAILURE);
}
static void noalloc (void)
{
fputs(_("Out of memory!\n"), stderr);
exit(EXIT_FAILURE);
}
static int file_get_line (ExecState *s)
{
char *line = s->line;
int len = 0;
memset(line, 0, MAXLINE);
if (fgets(line, MAXLINE, fb) == NULL) {
/* no more input from current source */
gretl_exec_state_uncomment(s);
} else {
len = strlen(line);
}
if (*line == '\0') {
strcpy(line, "quit");
s->cmd->ci = QUIT;
} else if (len == MAXLINE - 1 && line[len-1] != '\n') {
return E_TOOLONG;
} else {
*linebak = '\0';
strncat(linebak, line, MAXLINE-1);
tailstrip(linebak);
}
if (gretl_echo_on() && s->cmd->ci == RUN && batch && *line == '(') {
printf("%s", line);
*linebak = '\0';
}
return 0;
}
#ifdef ENABLE_NLS
static void nls_init (void)
{
# if defined(WIN32) && defined(PKGBUILD)
char localedir[MAXLEN];
gretl_build_path(localedir, gretl_home(), "locale", NULL);
# else
const char *localedir = LOCALEDIR;
# endif /* WIN32 package or not */
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, localedir);
textdomain(PACKAGE);
bind_textdomain_codeset(PACKAGE, "UTF-8");
gretl_setenv("LC_NUMERIC", "");
setlocale(LC_NUMERIC, "");
reset_local_decpoint();
# ifdef WIN32
if (getenv("CLI_DEBUG")) {
set_windebug(2);
}
if (try_for_CP_65001() != 0) {
/* FIXME issue a warning */
;
}
# endif
}
#endif /* ENABLE_NLS */
static int cli_clear_data (ExecState *s, DATASET *dset)
{
CMD *cmd = s->cmd;
gretlopt clearopt = 0;
int err = 0;
if (cmd->ci == CLEAR) {
clearopt = cmd->opt;
} else if (cmd->opt & OPT_P) {
/* --preserve: clear dataset only */
clearopt = OPT_D;
} else if (csv_open_needs_matrix(cmd->opt)) {
clearopt = OPT_D;
}
if (dset->Z != NULL) {
err = restore_full_sample(dset, NULL);
free_Z(dset);
}
clear_datainfo(dset, CLEAR_FULL);
data_status = 0;
*datafile = '\0';
clear_model(s->model);
if (clearopt & OPT_D) {
libgretl_session_cleanup(SESSION_CLEAR_DATASET);
} else {
libgretl_session_cleanup(SESSION_CLEAR_ALL);
}
set_model_count(0);
gretl_cmd_destroy_context(cmd);
return err;
}
static const char *get_prompt (ExecState *s)
{
if (s->flags & DEBUG_EXEC) {
return "$ ";
} else if (gretl_compiling_function() ||
gretl_compiling_loop()) {
return "> ";
} else {
return "? ";
}
}
/* this function is set up as it is to make it available for debugging
purposes */
static int get_interactive_line (void *p)
{
ExecState *s = (ExecState *) p;
const char *prompt = get_prompt(s);
int err = 0;
#ifdef HAVE_READLINE
rl_gets(&line_read, prompt);
if (line_read == NULL) {
strcpy(s->line, "quit");
} else if (strlen(line_read) > MAXLINE - 2) {
err = E_TOOLONG;
} else {
*s->line = '\0';
strncat(s->line, line_read, MAXLINE - 2);
strcat(s->line, "\n");
}
#else
printf("%s", prompt);
fflush(stdout);
file_get_line(s); /* note: "file" = stdin here */
#endif
return err;
}
static int cli_get_input_line (ExecState *s)
{
int err = 0;
if (s->more != NULL) {
/* pick up next concatented statement */
memmove(s->line, s->more, strlen(s->more) + 1);
} else if (runit || batch) {
/* reading from script file */
err = file_get_line(s);
} else {
/* interactive use */
err = get_interactive_line(s);
}
return err;
}
/* allow for continuation of lines */
static int maybe_get_input_line_continuation (char *line)
{
char tmp[MAXLINE];
int contd, err = 0;
if (!strncmp(line, "quit", 4)) {
return 0;
}
contd = top_n_tail(line, MAXLINE, &err);
while (contd && !err) {
*tmp = '\0';
if (batch || runit) {
char *test = fgets(tmp, MAXLINE, fb);
if (test == NULL) {
break;
}
} else {
#ifdef HAVE_READLINE
rl_gets(&line_read, "> ");
strcpy(tmp, line_read);
#else
fgets(tmp, MAXLINE, stdin);
#endif
}
if (*tmp != '\0') {
if (strlen(line) + strlen(tmp) > MAXLINE - 1) {
err = E_TOOLONG;
break;
} else {
strcat(line, tmp);
compress_spaces(line);
}
}
contd = top_n_tail(line, MAXLINE, &err);
}
return err;
}
#ifdef G_OS_WIN32
/* We're looking at an input line here, either in interactive
mode or from file, with line-continuation already applied
if required.
*/
static int line_ensure_utf8 (char *s)
{
int err = 0;
if (!g_utf8_validate(s, -1, NULL)) {
gsize bytes;
gchar *tmp = g_locale_to_utf8(s, -1, NULL, &bytes, NULL);
if (tmp == NULL) {
gretl_errmsg_set("Couldn't convert input to UTF-8");
err = E_DATA;
} else {
*s = '\0';
if (strlen(tmp) > MAXLINE - 1) {
err = E_TOOLONG;
} else {
strcpy(s, tmp);
}
g_free(tmp);
}
}
return err;
}
static int win32_get_args (int *pargc, char ***pargv)
{
int argc_w = 0;
LPWSTR *argv_w;
int err = 0;
/* get command-line arguments as UTF-16 */
argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
if (argv_w == NULL) {
err = 1;
} else {
/* convert args to UTF-8 */
char **argv_u8 = calloc((argc_w + 1), sizeof *argv_u8);
int i;
for (i=0; ici = RUNLOOP;
err = cli_exec_line(&state, dset, cmdprn);
state.cmd->ci = 0;
} else {
err = cli_get_input_line(&state);
if (err) {
errmsg(err, prn);
break;
} else if (cmd.ci == QUIT) {
/* no more input available */
cli_exec_line(&state, dset, cmdprn);
if (runit == 0) {
err = gretl_if_state_check(0);
if (err) {
errmsg(err, prn);
}
}
continue;
}
}
if (xout) {
/* readline Ctrl-X: get out without saving
input or output */
gretl_print_destroy(cmdprn);
gretl_remove(cmdfile);
break;
}
if (!state.in_comment) {
if (cmd.context == FOREIGN || cmd.context == MPI ||
gretl_compiling_python(line)) {
tailstrip(line);
} else {
err = maybe_get_input_line_continuation(line);
if (err) {
errmsg(err, prn);
break;
}
}
}
#ifdef G_OS_WIN32
line_ensure_utf8(line);
#endif
strcpy(linecopy, line);
tailstrip(linecopy);
err = cli_exec_line(&state, dset, cmdprn);
}
/* finished main command loop */
if (!err) {
err = gretl_if_state_check(0);
if (err) {
errmsg(err, prn);
}
}
if (!err && pkgmode) {
if (pkgmode == OPT_MAKEPKG) {
switch_ext(filearg, runfile, "gfn");
sprintf(line, "makepkg %s\n", filearg);
} else {
if (!isalpha(filearg[0]) || filearg[1] == ':') {
/* some sort of path: install local file */
sprintf(line, "pkg install %s --local\n", filearg);
} else {
/* plain filename or http: install from server */
sprintf(line, "pkg install %s\n", filearg);
}
}
cli_exec_line(&state, dset, cmdprn);
}
/* leak check -- try explicitly freeing all memory allocated */
destroy_working_model(model);
destroy_dataset(dset);
if (fb != stdin && fb != NULL) {
fclose(fb);
}
free(line);
gretl_print_destroy(prn);
gretl_cmd_free(&cmd);
libgretl_cleanup();
exit(err ? EXIT_FAILURE : EXIT_SUCCESS);
}
static void printline (const char *s)
{
if (*s != '\0') {
if (gretl_compiling_loop()) {
printf("> %s\n", s);
} else {
printf("%s\n", s);
}
}
}
static int maybe_abort_open (ExecState *s)
{
if (data_status && !batch) {
char response[3];
fprintf(stderr, _("Opening a new data file closes the "
"present one. Proceed? (y/n) "));
if (fgets(response, sizeof response, stdin) != NULL &&
*response != 'y' && *response != 'Y') {
pprintf(s->prn, _("OK, staying with current data set\n"));
return 1;
}
}
return 0;
}
static int cli_exec_callback (ExecState *s, void *ptr,
GretlObjType type)
{
if (s->cmd->ci == MODELTAB || s->cmd->ci == GRAPHPG) {
pprintf(s->prn, _("%s: command not available\n"),
gretl_command_word(s->cmd->ci));
} else if (s->cmd->ci == OPEN) {
if (type == GRETL_OBJ_DSET) {
/* check that "open" is really OK */
if (maybe_abort_open(s)) {
return 1;
} else {
if (gretl_looping()) {
s->cmd->opt |= OPT_P;
}
cli_clear_data(s, (DATASET *) ptr);
}
} else if (type == GRETL_OBJ_ANY) {
/* handle successful "open" */
OpenOp *op = (OpenOp *) ptr;
if (op->fname[0] != '\0') {
strncpy(datafile, op->fname, MAXLEN - 1);
}
data_status = 1;
}
}
return 0;
}
static int cli_renumber_series (const int *list,
const char *parm,
DATASET *dset,
PRN *prn)
{
int err, fixmax = highest_numbered_var_in_saved_object(dset);
err = renumber_series_with_checks(list, parm, fixmax, dset, prn);
if (err) {
errmsg(err, prn);
}
return err;
}
static void maybe_save_session_output (const char *cmdfile)
{
char outfile[FILENAME_MAX];
printf(_("type a filename to store output (enter to quit): "));
*outfile = '\0';
if (fgets(outfile, sizeof outfile, stdin) != NULL) {
top_n_tail(outfile, 0, NULL);
}
if (*outfile != '\0' && *outfile != '\n' && *outfile != '\r'
&& strcmp(outfile, "q")) {
const char *udir = gretl_workdir();
char *syscmd;
int err;
printf(_("writing session output to %s%s\n"), udir, outfile);
#ifdef WIN32
syscmd = gretl_strdup_printf("\"%sgretlcli\" -b \"%s\" > \"%s%s\"",
gretl_home(), cmdfile, udir, outfile);
err = system(syscmd);
#else
syscmd = gretl_strdup_printf("gretlcli -b \"%s\" > \"%s%s\"",
cmdfile, udir, outfile);
err = system(syscmd);
#endif
if (!err) {
printf("%s\n", syscmd);
}
free(syscmd);
}
}
static int run_include_error (ExecState *s, const char *param,
int err, PRN *prn)
{
const char *msg = gretl_errmsg_get();
pprintf(prn, _("Error reading %s\n"), param);
if (*msg != '\0') {
pprintf(prn, "%s\n", msg);
}
return process_command_error(s, err);
}
static void do_quit_message (ExecState *s, int err)
{
if (gretl_messages_on() && s != NULL && s->prn != NULL) {
if (err) {
pputs(s->prn, _("Terminated on error\n"));
} else {
pputs(s->prn, _("Done\n"));
}
}
}
static void cli_quit (ExecState *s, PRN *cmdprn, int err)
{
if (runit || batch_stdin) {
*s->runfile = '\0';
runit--;
fclose(fb);
fb = pop_input_file();
if (fb == NULL) {
do_quit_message(s, err);
} else {
gretl_if_state_reset(indent0);
s->cmd->ci = ENDRUN;
}
} else if (batch && fb == NULL) {
do_quit_message(s, err);
} else {
gretl_print_destroy(cmdprn);
if (s->cmd->opt & OPT_X) {
gretl_remove(cmdfile);
} else {
printf(_("commands saved as %s\n"), cmdfile);
maybe_save_session_output(cmdfile);
}
}
}
/* cli_exec_line: this is called to execute both interactive and
script commands. Note that most commands get passed on to the
libgretl function gretl_cmd_exec(), but some commands that require
special action are dealt with here.
see also gui_exec_line() in gui2/library.c
*/
static int cli_exec_line (ExecState *s, DATASET *dset, PRN *cmdprn)
{
char *line = s->line;
CMD *cmd = s->cmd;
PRN *prn = s->prn;
int old_runit = runit;
char runfile[MAXLEN];
int renumber = 0;
int err = 0;
if (cmd->ci == RUNLOOP) {
goto cmd_proceed;
}
#if 0
fprintf(stderr, "cli_exec_line: '%s'\n", line);
#endif
if (gretl_compiling_function()) {
err = gretl_function_append_line(s);
if (err) {
errmsg(err, prn);
goto cmd_finish;
} else {
pprintf(cmdprn, "%s\n", line);
return 0;
}
}
if (string_is_blank(line)) {
return 0;
}
if (!gretl_compiling_loop() && !s->in_comment &&
!cmd->context && !gretl_if_state_false()) {
/* catch requests relating to saved objects, which are not
really "commands" as such */
int action = cli_saved_object_action(line, dset, prn);
if (action == OBJ_ACTION_INVALID) {
/* action was faulty */
err = 1;
goto cmd_finish;
} else if (action != OBJ_ACTION_NONE) {
return 0; /* action was OK (and handled), or ignored */
}
}
/* tell libgretl if we're in batch mode */
gretl_set_batch_mode(batch);
if (gretl_compiling_loop()) {
/* if we're stacking commands for a loop, parse "lightly" */
err = get_command_index(s, LOOP);
} else {
err = parse_command_line(s, dset, NULL);
}
if (err) {
int catch = 0;
gretl_exec_state_uncomment(s);
if (err != E_ALLOC && (cmd->flags & CMD_CATCH)) {
set_gretl_errno(err);
catch = 1;
}
gretl_echo_command(cmd, line, prn);
errmsg(err, prn);
err = catch ? 0 : err;
goto cmd_finish;
}
gretl_exec_state_transcribe_flags(s, cmd);
/* if in batch mode, echo comments from input */
if (batch && runit < 2 && cmd->ci == CMD_COMMENT &&
!gretl_if_state_false()) {
if (gretl_echo_on() || gretl_comments_on()) {
printline(linebak);
}
}
if (cmd->ci < 0) {
/* nothing there, comment, or masked by "if" */
return 0;
}
if (s->sys != NULL && cmd->ci != END && cmd->ci != EQUATION &&
cmd->ci != SYSTEM) {
printf(_("Command '%s' ignored; not valid within equation system\n"),
line);
equation_system_destroy(s->sys);
s->sys = NULL;
err = 1;
goto cmd_finish;
}
if (cmd->ci == LOOP && !batch && !runit) {
pputs(prn, _("Enter commands for loop. "
"Type 'endloop' to get out\n"));
}
if (cmd->ci == LOOP || gretl_compiling_loop()) {
/* accumulating loop commands */
if (gretl_echo_on() && (!gretl_compiling_loop() || batch || runit)) {
/* straight visual echo */
gretl_echo_command(cmd, line, prn);
}
err = gretl_loop_append_line(s, dset);
if (err) {
errmsg(err, prn);
} else if (!batch && !runit) {
gretl_record_command(cmd, line, cmdprn);
}
goto cmd_finish;
}
if (gretl_echo_on()) {
/* visual feedback, not recording */
if (cmd->ci == FUNC && runit > 1) {
; /* don't echo */
} else if (batch || runit) {
gretl_echo_command(cmd, line, prn);
}
}
check_for_loop_only_options(cmd->ci, cmd->opt, prn);
cmd_proceed:
gretl_exec_state_set_callback(s, cli_exec_callback, OPT_NONE);
switch (cmd->ci) {
case DELEET:
err = gretl_delete_variables(cmd->list, cmd->param,
cmd->opt, dset, &renumber,
prn);
if (err) {
errmsg(err, prn);
} else if (renumber && !batch) {
pputs(prn, _("Take note: variables have been renumbered"));
pputc(prn, '\n');
maybe_list_series(dset, prn);
}
if (err && cmd->flags & CMD_CATCH) {
cmd->flags ^= CMD_CATCH;
err = 0;
}
break;
case HELP:
cli_help(cmd->param, cmd->parm2, cmd->opt, NULL, prn);
break;
case NULLDATA:
if (cmd->order < 1) {
err = 1;
pputs(prn, _("Data series length count missing or invalid\n"));
} else {
cli_clear_data(s, dset);
err = open_nulldata(dset, data_status, cmd->order,
cmd->opt, prn);
if (err) {
errmsg(err, prn);
} else {
data_status = 1;
}
}
break;
case RUNLOOP:
err = gretl_loop_exec(s, dset, NULL);
break;
case QUIT:
gretl_if_state_clear();
cli_quit(s, cmdprn, err);
break;
case RUN:
case INCLUDE:
if (cmd->ci == INCLUDE) {
err = get_full_filename(cmd->param, runfile, OPT_I);
} else {
err = get_full_filename(cmd->param, runfile, OPT_S);
}
if (err) {
err = run_include_error(s, cmd->param, err, prn);
break;
}
if (gretl_messages_on()) {
pprintf(prn, " %s\n", runfile);
}
if (cmd->ci == INCLUDE && gretl_is_xml_file(runfile)) {
err = load_XML_functions_file(runfile, cmd->opt, prn);
if (err) {
err = run_include_error(s, runfile, err, prn);
} else {
pprintf(cmdprn, "include \"%s\"\n", runfile);
}
break;
} else if (cmd->ci == INCLUDE && gfn_is_loaded(runfile)) {
break;
}
if (!strcmp(runfile, s->runfile)) {
pprintf(prn, _("Infinite loop detected in script\n"));
err = 1;
break;
}
if (fb != NULL) {
push_input_file(fb);
}
if ((fb = gretl_fopen(runfile, "r")) == NULL) {
pprintf(prn, _("Error reading %s\n"), runfile);
err = process_command_error(s, E_FOPEN);
fb = pop_input_file();
} else {
strcpy(s->runfile, runfile);
gretl_set_script_dir(runfile);
if (cmd->ci == INCLUDE) {
pprintf(cmdprn, "include \"%s\"\n", runfile);
} else {
pprintf(cmdprn, "run \"%s\"\n", runfile);
}
runit++;
indent0 = gretl_if_state_record();
}
break;
case CLEAR:
err = incompatible_options(cmd->opt, OPT_D | OPT_F);
if (!err) {
if (cmd->opt & OPT_F) {
gretl_functions_cleanup();
} else {
err = cli_clear_data(s, dset);
}
}
break;
case DATAMOD:
if (cmd->auxint == DS_CLEAR) {
err = cli_clear_data(s, dset);
pputs(prn, _("Dataset cleared\n"));
break;
} else if (cmd->auxint == DS_RENUMBER) {
err = cli_renumber_series(cmd->list, cmd->parm2, dset, prn);
break;
} else {
err = gretl_cmd_exec(s, dset);
}
break;
default:
err = gretl_cmd_exec(s, dset);
break;
}
if (!err && cmd->ci != QUIT && gretl_echo_on() && !batch && !old_runit) {
/* record a successful interactive command */
gretl_record_command(cmd, line, cmdprn);
}
cmd_finish:
if (err) {
gretl_exec_state_uncomment(s);
if ((runit || batch) && cmd->ci != QUIT) {
cli_quit(s, cmdprn, err);
}
}
return err;
}
/* apparatus for keeping track of input stream */
#define N_STACKED_FILES 8
static int nfiles;
static FILE *fstack[N_STACKED_FILES];
static int push_input_file (FILE *fp)
{
int err = 0;
if (nfiles >= N_STACKED_FILES) {
err = 1;
} else {
fstack[nfiles++] = fp;
}
return err;
}
static FILE *pop_input_file (void)
{
FILE *ret = NULL;
if (nfiles > 0) {
ret = fstack[--nfiles];
}
return ret;
}
#include "cli_object.c"