10 std::map
<std::string
, command
*>* commands
;
11 std::set
<std::string
> command_stack
;
12 std::map
<std::string
, std::list
<std::string
>> aliases
;
14 class run_command
: public command
17 run_command() throw(std::bad_alloc
) : command("run-script") {}
18 void invoke(const std::string
& args
, window
* win
) throw(std::bad_alloc
, std::runtime_error
)
21 throw std::runtime_error("Filename needed");
22 std::istream
* o
= NULL
;
24 o
= &open_file_relative(args
, "");
25 out(win
) << "Running '" << args
<< "'" << std::endl
;
27 while(std::getline(*o
, line
))
28 command::invokeC(line
, win
);
30 } catch(std::exception
& e
) {
36 std::string
get_short_help() throw(std::bad_alloc
) { return "run a file as a script"; }
37 std::string
get_long_help() throw(std::bad_alloc
)
39 return "Syntax: run-script <file>\n"
40 "Runs file <file> just as it would have been entered in the command line\n";
44 class aliases_command
: public command
47 aliases_command() throw(std::bad_alloc
) : command("show-aliases") {}
48 void invoke(const std::string
& args
, window
* win
) throw(std::bad_alloc
, std::runtime_error
)
51 throw std::runtime_error("This command does not take parameters");
52 for(auto i
= aliases
.begin(); i
!= aliases
.end(); i
++)
53 for(auto j
= i
->second
.begin(); j
!= i
->second
.end(); j
++)
54 out(win
) << "alias " << i
->first
<< " " << *j
<< std::endl
;
56 std::string
get_short_help() throw(std::bad_alloc
) { return "show aliases"; }
57 std::string
get_long_help() throw(std::bad_alloc
)
59 return "Syntax: show-aliases\n"
60 "Show expansions of all aliases\n";
64 class unalias_command
: public command
67 unalias_command() throw(std::bad_alloc
) : command("unalias-command") {}
68 void invoke(const std::string
& args
, window
* win
) throw(std::bad_alloc
, std::runtime_error
)
70 tokensplitter
t(args
);
71 std::string aliasname
= t
;
73 throw std::runtime_error("This command only takes one argument");
74 if(aliasname
.length() == 0 || aliasname
[0] == '?' || aliasname
[0] == '*')
75 throw std::runtime_error("Illegal alias name");
76 aliases
[aliasname
].clear();
77 out(win
) << "Command '" << aliasname
<< "' unaliased" << std::endl
;
79 std::string
get_short_help() throw(std::bad_alloc
) { return "unalias a command"; }
80 std::string
get_long_help() throw(std::bad_alloc
)
82 return "Syntax: unalias-command <aliasname>\n"
83 "Clear expansion of alias <aliasname>\n";
87 class alias_command
: public command
90 alias_command() throw(std::bad_alloc
) : command("alias-command") {}
91 void invoke(const std::string
& args
, window
* win
) throw(std::bad_alloc
, std::runtime_error
)
93 tokensplitter
t(args
);
94 std::string aliasname
= t
;
95 std::string command
= t
.tail();
97 throw std::runtime_error("Alias name and command needed");
98 if(aliasname
.length() == 0 || aliasname
[0] == '?' || aliasname
[0] == '*')
99 throw std::runtime_error("Illegal alias name");
100 aliases
[aliasname
].push_back(command
);
101 out(win
) << "Command '" << aliasname
<< "' aliased to '" << command
<< "'" << std::endl
;
103 std::string
get_short_help() throw(std::bad_alloc
) { return "alias a command"; }
104 std::string
get_long_help() throw(std::bad_alloc
)
106 return "Syntax: alias-command <aliasname> <command>\n"
107 "Append <command> to expansion of alias <aliasname>\n"
108 "Valid alias names can't be empty nor start with '*' or '?'\n";
113 command::command(const std::string
& cmd
) throw(std::bad_alloc
)
116 commands
= new std::map
<std::string
, command
*>();
117 if(commands
->count(cmd
))
118 std::cerr
<< "WARNING: Command collision for " << cmd
<< "!" << std::endl
;
119 (*commands
)[commandname
= cmd
] = this;
122 command::~command() throw()
126 commands
->erase(commandname
);
129 void command::invokeC(const std::string
& cmd
, window
* win
) throw()
132 if(command_stack
.count(cmd
)) {
133 out(win
) << "Can not invoke recursively: " << cmd
<< std::endl
;
136 command_stack
.insert(cmd
);
137 std::string cmd2
= cmd
;
139 //The special ? command.
141 for(auto i
= commands
->begin(); i
!= commands
->end(); ++i
)
142 out(win
) << i
->first
<< ": " << i
->second
->get_short_help() << std::endl
;
144 command_stack
.erase(cmd
);
147 if(cmd2
.length() > 1 && cmd2
[0] == '?') {
149 size_t split
= cmd2
.find_first_of(" \t");
151 if(split
>= cmd2
.length())
152 rcmd
= cmd2
.substr(1);
154 rcmd
= cmd2
.substr(1, split
- 1);
155 if(rcmd
.length() > 0 && rcmd
[0] != '*') {
156 //This may be an alias.
157 std::string aname
= cmd2
.substr(1);
158 if(aliases
.count(aname
)) {
160 out(win
) << aname
<< " is an alias for: " << std::endl
;
162 for(auto i
= aliases
[aname
].begin(); i
!= aliases
[aname
].end(); ++i
, ++j
)
163 out(win
) << "#" + (j
+ 1) << ": " << *i
<< std::endl
;
164 command_stack
.erase(cmd
);
168 if(rcmd
.length() > 0 && rcmd
[0] == '*')
169 rcmd
= rcmd
.substr(1);
170 if(!commands
|| !commands
->count(rcmd
)) {
172 out(win
) << "Unknown command '" << rcmd
<< "'" << std::endl
;
173 command_stack
.erase(cmd
);
176 out(win
) << (*commands
)[rcmd
]->get_long_help() << std::endl
;
177 command_stack
.erase(cmd
);
180 bool may_be_alias_expanded
= true;
181 if(cmd2
.length() > 0 && cmd2
[0] == '*') {
182 may_be_alias_expanded
= false;
183 cmd2
= cmd2
.substr(1);
185 if(may_be_alias_expanded
&& aliases
.count(cmd2
)) {
186 for(auto i
= aliases
[cmd2
].begin(); i
!= aliases
[cmd2
].end(); ++i
)
188 command_stack
.erase(cmd
);
192 size_t split
= cmd2
.find_first_of(" \t");
194 if(split
>= cmd2
.length())
197 rcmd
= cmd2
.substr(0, split
);
198 split
= cmd2
.find_first_not_of(" \t", split
);
200 if(split
< cmd2
.length())
201 args
= cmd2
.substr(split
);
202 command
* cmdh
= NULL
;
203 if(commands
&& commands
->count(rcmd
))
204 cmdh
= (*commands
)[rcmd
];
206 out(win
) << "Unknown command '" << rcmd
<< "'" << std::endl
;
207 command_stack
.erase(cmd
);
210 cmdh
->invoke(args
, win
);
211 command_stack
.erase(cmd
);
213 } catch(std::bad_alloc
& e
) {
215 } catch(std::exception
& e
) {
216 out(win
) << "Error: " << e
.what() << std::endl
;
217 command_stack
.erase(cmd
);
220 } catch(std::bad_alloc
& e
) {
225 std::string
command::get_short_help() throw(std::bad_alloc
)
227 return "No description available";
230 std::string
command::get_long_help() throw(std::bad_alloc
)
232 return "No help available on command " + commandname
;
235 tokensplitter::tokensplitter(const std::string
& _line
) throw(std::bad_alloc
)
241 tokensplitter::operator bool() throw()
243 return (position
< line
.length());
246 tokensplitter::operator std::string() throw(std::bad_alloc
)
248 size_t nextp
, oldp
= position
;
249 nextp
= line
.find_first_of(" \t", position
);
250 if(nextp
> line
.length()) {
251 position
= line
.length();
252 return line
.substr(oldp
);
255 while(position
< line
.length() && (line
[position
] == ' ' || line
[position
] == '\t'))
257 return line
.substr(oldp
, nextp
- oldp
);
261 std::string
tokensplitter::tail() throw(std::bad_alloc
)
263 return line
.substr(position
);