/*
* lftp - file transfer program
*
* Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net)
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CMDEXEC_H
#define CMDEXEC_H
#include <stdarg.h>
#include "Job.h"
#include "ArgV.h"
#include "Filter.h"
#include "alias.h"
#include "History.h"
#include "bookmark.h"
#include "FileGlob.h"
class QueueFeeder;
class LocalDirectory;
extern History cwd_history;
#define CMD(name) Job *cmd_##name(CmdExec *parent)
typedef Job * (*cmd_creator_t)(class CmdExec *parent);
class CmdFeeder
{
public:
xstring_c saved_buf;
CmdFeeder *prev;
virtual const char *NextCmd(class CmdExec *exec,const char *prompt) = 0;
virtual ~CmdFeeder() {}
virtual void clear() {}
virtual bool RealEOF() { return true; }
virtual void Fg() {}
virtual void Bg() {}
virtual bool IsInteractive() const { return false; }
};
extern CmdFeeder *lftp_feeder; // feeder to use after 'lftp' command
class CmdExec : public SessionJob, public ResClient
{
public:
// current command data
Ref<ArgV> args;
Ref<FDStream> output;
bool background;
int exit_code;
int prev_exit_code;
private:
CmdExec *parent_exec;
Buffer cmd_buf;
bool partial_cmd;
int alias_field; // length of expanded alias (and ttl for used_aliases)
int failed_exit_code;
TouchedAlias *used_aliases;
void free_used_aliases();
void skip_cmd(int len);
enum
{
COND_ANY,
COND_AND,
COND_OR
}
condition;
struct cmd_rec
{
const char *name;
cmd_creator_t creator;
const char *short_desc;
const char *long_desc;
static int cmp(const CmdExec::cmd_rec *a,const CmdExec::cmd_rec *b);
};
static const cmd_rec static_cmd_table[];
static const int static_cmd_table_length;
static xarray<cmd_rec> dyn_cmd_table;
static int find_cmd(const char *cmd_name,const cmd_rec **ret);
void exec_parsed_command();
enum parse_result
{
PARSE_OK,
PARSE_ERR,
PARSE_AGAIN
};
parse_result parse_one_cmd();
CmdFeeder *feeder;
bool feeder_called;
bool fed_at_finish;
void AtFinish();
enum builtins
{
BUILTIN_NONE=0,
BUILTIN_OPEN,
BUILTIN_CD,
BUILTIN_EXEC_RESTART,
BUILTIN_GLOB
}
builtin;
FileAccess::Path old_cwd;
xstring_c old_lcwd;
xstring_c slot;
Ref<GlobURL> glob;
Ref<ArgV> args_glob;
int redirections;
static CmdExec *chain;
CmdExec *next;
QueueFeeder *queue_feeder;
CmdExec *GetQueue(bool create = true);
bool SameQueueParameters(CmdExec *,const char *);
int max_waiting;
FileAccessRef saved_session;
void ReuseSavedSession();
void RevertToSavedSession();
void init(LocalDirectory *c);
public:
void FeedCmd(const char *c);
void FeedArgV(const ArgV *,int start=0);
void PrependCmd(const char *c);
void ExecParsed(ArgV *a,FDStream *o=0,bool b=false);
static bool needs_quotation(const char *buf,int len);
static bool needs_quotation(const char *buf) { return needs_quotation(buf,strlen(buf)); }
static bool quotable(char c,char in_quotes);
static bool is_space(char c) { return c==' ' || c=='\t'; }
static bool is_quote(char c) { return c=='"' || c=='\''; }
void FeedQuoted(const char *c);
void Exit(int);
void AtExit();
void AtExitBg();
void AtExitFg();
void AtBackground();
void AtTerminate();
void EmptyCmds();
bool WriteCmds(int fd) const;
bool ReadCmds(int fd); // does not clear queue before reading (appends)
void AddNewJob(Job *new_job);
void SuspendJob(Job *j);
CmdExec(FileAccess *s,LocalDirectory *c);
CmdExec(CmdExec *parent);
~CmdExec();
bool Idle(); // when we have no command running and command buffer is empty
int Done();
int ExitCode() { return failed_exit_code ? failed_exit_code : exit_code; }
int Do();
xstring& FormatStatus(xstring&,int,const char *prefix="\t");
void ShowRunStatus(const SMTaskRef<StatusLine>& s);
int AcceptSig(int sig);
const char *FormatPrompt(const char *scan);
const char *MakePrompt();
bool interactive;
bool show_status;
bool top_level;
bool verbose;
bool auto_terminate_in_bg;
SMTaskRef<StatusLine> status_line;
void SetCmdFeeder(CmdFeeder *new_feeder);
void RemoveFeeder();
friend char *command_generator(char *,int); // readline completor
static const char *GetFullCommandName(const char *);
bool remote_completion;
int long_running;
bool csh_history;
bool verify_host;
bool verify_path;
bool verify_path_cached;
void Reconfig(const char *name=0);
void beep_if_long();
time_t start_time;
static CmdExec *cwd_owner;
Ref<LocalDirectory> cwd;
void SaveCWD();
int RestoreCWD();
FDStream *default_output;
void top_vfprintf(FILE *file,const char *f,va_list v);
void SetInteractive(bool i);
void SetInteractive();
void SetTopLevel()
{
top_level=true;
Reconfig(0);
SetInteractive();
}
void SetStatusLine(StatusLine *s) { status_line=s; }
void SetAutoTerminateInBackground(bool b) { auto_terminate_in_bg=b; }
static void RegisterCommand(const char *name,cmd_creator_t creator,
const char *short_name=0,const char *long_name=0);
Job *builtin_lcd();
Job *builtin_cd();
Job *builtin_open();
Job *builtin_exit();
Job *builtin_lftp();
Job *builtin_restart();
Job *builtin_glob();
Job *builtin_queue();
Job *builtin_queue_edit();
Job *builtin_local();
bool load_cmd_module(const char *op);
Job *default_cmd();
void ChangeSession(FileAccess *new_session);
bool print_cmd_help(const char *cmd);
void print_cmd_index();
static const char *CmdByIndex(int i);
void enable_debug(const char *opt=0);
int last_bg;
bool wait_all;
void pre_stdout();
void ChangeSlot(const char *n);
static JobRef<CmdExec> top;
};
extern const char * const bookmark_subcmd[];
extern const char * const cache_subcmd[];
#endif//CMDEXEC_H