1 #include "commands.hpp"
2 #include "globalwrap.hpp"
4 #include "register-queue.hpp"
12 struct run_script
: public command
14 run_script(command_group
& group
, std::ostream
*& _output
)
15 : command(group
, "run-script"), in_group(group
), output(_output
)
23 void invoke(const std::string
& filename
) throw(std::bad_alloc
, std::runtime_error
)
26 (*output
) << "Syntax: run-script <scriptfile>" << std::endl
;
29 std::istream
* o
= NULL
;
31 o
= &open_file_relative(filename
, "");
32 (*output
) << "Running '" << std::string(filename
) << "'" << std::endl
;
34 while(std::getline(*o
, line
))
35 in_group
.invoke(line
);
37 } catch(std::exception
& e
) {
43 std::string
get_short_help() throw(std::bad_alloc
)
45 return "Run file as a script";
48 std::string
get_long_help() throw(std::bad_alloc
)
50 return "Syntax: run-script <file>\nRuns file <file> just as it would have been entered in "
54 command_group
& in_group
;
55 std::ostream
*& output
;
58 void default_oom_panic()
60 std::cerr
<< "PANIC: Fatal error, can't continue: Out of memory." << std::endl
;
64 typedef register_queue
<command_group
, command
> regqueue_t
;
67 command::command(command_group
& group
, const std::string
& cmd
) throw(std::bad_alloc
)
70 regqueue_t::do_register(in_group
, commandname
= cmd
, *this);
73 command::~command() throw()
75 regqueue_t::do_unregister(in_group
, commandname
);
79 std::string
command::get_short_help() throw(std::bad_alloc
)
81 return "No description available";
84 std::string
command::get_long_help() throw(std::bad_alloc
)
86 return "No help available on command " + commandname
;
89 command_group::command_group() throw(std::bad_alloc
)
91 oom_panic_routine
= default_oom_panic
;
93 regqueue_t::do_ready(*this, true);
94 //The builtin commands.
95 builtin
[0] = new run_script(*this, output
);
98 command_group::~command_group() throw()
100 for(size_t i
= 0; i
< sizeof(builtin
)/sizeof(builtin
[0]); i
++)
102 regqueue_t::do_ready(*this, false);
105 void command_group::invoke(const std::string
& cmd
) throw()
108 std::string cmd2
= strip_CR(cmd
);
110 //The special ? command.
111 umutex_class
lock(int_mutex
);
112 for(auto i
: commands
)
113 (*output
) << i
.first
<< ": " << i
.second
->get_short_help() << std::endl
;
116 if(firstchar(cmd2
) == '?') {
118 umutex_class
lock(int_mutex
);
119 std::string rcmd
= cmd2
.substr(1, min(cmd2
.find_first_of(" \t"), cmd2
.length()));
120 if(firstchar(rcmd
) != '*') {
121 //This may be an alias.
122 if(aliases
.count(rcmd
)) {
124 (*output
) << rcmd
<< " is an alias for: " << std::endl
;
126 for(auto i
: aliases
[rcmd
])
127 (*output
) << "#" << (++j
) << ": " << i
<< std::endl
;
131 rcmd
= rcmd
.substr(1);
132 if(!commands
.count(rcmd
))
133 (*output
) << "Unknown command '" << rcmd
<< "'" << std::endl
;
135 (*output
) << commands
[rcmd
]->get_long_help() << std::endl
;
138 bool may_be_alias_expanded
= true;
139 if(firstchar(cmd2
) == '*') {
140 may_be_alias_expanded
= false;
141 cmd2
= cmd2
.substr(1);
143 //Now this gets painful as command handlers must not be invoked with lock held.
144 if(may_be_alias_expanded
) {
145 std::list
<std::string
> aexp
;
147 umutex_class
lock(int_mutex
);
148 if(!aliases
.count(cmd
))
150 aexp
= aliases
[cmd2
];
158 size_t split
= cmd2
.find_first_of(" \t");
159 std::string rcmd
= cmd2
.substr(0, min(split
, cmd2
.length()));
160 std::string args
= cmd2
.substr(min(cmd2
.find_first_not_of(" \t", split
), cmd2
.length()));
161 command
* cmdh
= NULL
;
163 umutex_class
lock(int_mutex
);
164 if(!commands
.count(rcmd
)) {
165 (*output
) << "Unknown command '" << rcmd
<< "'" << std::endl
;
168 cmdh
= commands
[rcmd
];
170 if(command_stack
.count(cmd2
))
171 throw std::runtime_error("Recursive command invocation");
172 command_stack
.insert(cmd2
);
174 command_stack
.erase(cmd2
);
176 } catch(std::bad_alloc
& e
) {
178 } catch(std::exception
& e
) {
179 (*output
) << "Error: " << e
.what() << std::endl
;
180 command_stack
.erase(cmd2
);
183 } catch(std::bad_alloc
& e
) {
188 std::set
<std::string
> command_group::get_aliases() throw(std::bad_alloc
)
190 umutex_class
lock(int_mutex
);
191 std::set
<std::string
> r
;
192 for(auto i
: aliases
)
197 std::string
command_group::get_alias_for(const std::string
& aname
) throw(std::bad_alloc
)
199 umutex_class
lock(int_mutex
);
200 if(!valid_alias_name(aname
))
202 if(aliases
.count(aname
)) {
204 for(auto i
: aliases
[aname
])
211 void command_group::set_alias_for(const std::string
& aname
, const std::string
& avalue
) throw(std::bad_alloc
)
213 umutex_class
lock(int_mutex
);
214 if(!valid_alias_name(aname
))
216 std::list
<std::string
> newlist
;
218 while(avitr
< avalue
.length()) {
219 size_t nextsplit
= min(avalue
.find_first_of("\n", avitr
), avalue
.length());
220 std::string x
= strip_CR(avalue
.substr(avitr
, nextsplit
- avitr
));
222 newlist
.push_back(x
);
223 avitr
= nextsplit
+ 1;
226 aliases
.erase(aname
);
228 aliases
[aname
] = newlist
;
231 bool command_group::valid_alias_name(const std::string
& aliasname
) throw(std::bad_alloc
)
233 if(aliasname
.length() == 0 || aliasname
[0] == '?' || aliasname
[0] == '*')
235 if(aliasname
.find_first_of(" \t") < aliasname
.length())
240 void command_group::do_register(const std::string
& name
, command
& cmd
) throw(std::bad_alloc
)
242 umutex_class
lock(int_mutex
);
243 if(commands
.count(name
))
244 std::cerr
<< "WARNING: Command collision for " << name
<< "!" << std::endl
;
245 commands
[name
] = &cmd
;
248 void command_group::do_unregister(const std::string
& name
) throw(std::bad_alloc
)
250 umutex_class
lock(int_mutex
);
251 commands
.erase(name
);
254 void command_group::set_output(std::ostream
& s
)
259 void command_group::set_oom_panic(void (*fn
)())
262 oom_panic_routine
= fn
;
264 oom_panic_routine
= default_oom_panic
;
268 void invoke_command_fn(void (*fn
)(const std::string
& args
), const std::string
& args
)
274 void invoke_command_fn(void (*fn
)(), const std::string
& args
)
277 throw std::runtime_error("This command does not take arguments");
282 void invoke_command_fn(void (*fn
)(struct arg_filename a
), const std::string
& args
)
285 throw std::runtime_error("Filename required");