2 #include "globalwrap.hpp"
4 #include "register-queue.hpp"
14 struct run_script
: public base
16 run_script(group
& group
, std::ostream
*& _output
)
17 : base(group
, "run-script"), in_group(group
), output(_output
)
25 void invoke(const std::string
& filename
) throw(std::bad_alloc
, std::runtime_error
)
28 (*output
) << "Syntax: run-script <scriptfile>" << std::endl
;
31 std::istream
* o
= NULL
;
33 o
= &zip::openrel(filename
, "");
34 (*output
) << "Running '" << std::string(filename
) << "'" << std::endl
;
36 while(std::getline(*o
, line
))
37 in_group
.invoke(line
);
39 } catch(std::exception
& e
) {
45 std::string
get_short_help() throw(std::bad_alloc
)
47 return "Run file as a script";
50 std::string
get_long_help() throw(std::bad_alloc
)
52 return "Syntax: run-script <file>\nRuns file <file> just as it would have been entered in "
57 std::ostream
*& output
;
60 void default_oom_panic()
62 std::cerr
<< "PANIC: Fatal error, can't continue: Out of memory." << std::endl
;
66 typedef register_queue
<group
, base
> regqueue_t
;
69 base::base(group
& group
, const std::string
& cmd
) throw(std::bad_alloc
)
72 regqueue_t::do_register(in_group
, commandname
= cmd
, *this);
77 regqueue_t::do_unregister(in_group
, commandname
);
81 std::string
base::get_short_help() throw(std::bad_alloc
)
83 return "No description available";
86 std::string
base::get_long_help() throw(std::bad_alloc
)
88 return "No help available on command " + commandname
;
91 group::group() throw(std::bad_alloc
)
93 oom_panic_routine
= default_oom_panic
;
95 regqueue_t::do_ready(*this, true);
96 //The builtin commands.
97 builtin
[0] = new run_script(*this, output
);
100 group::~group() throw()
102 for(size_t i
= 0; i
< sizeof(builtin
)/sizeof(builtin
[0]); i
++)
104 regqueue_t::do_ready(*this, false);
107 void group::invoke(const std::string
& cmd
) throw()
110 std::string cmd2
= strip_CR(cmd
);
112 //The special ? command.
113 umutex_class
lock(int_mutex
);
114 for(auto i
: commands
)
115 (*output
) << i
.first
<< ": " << i
.second
->get_short_help() << std::endl
;
118 if(firstchar(cmd2
) == '?') {
120 umutex_class
lock(int_mutex
);
121 std::string rcmd
= cmd2
.substr(1, min(cmd2
.find_first_of(" \t"), cmd2
.length()));
122 if(firstchar(rcmd
) != '*') {
123 //This may be an alias.
124 if(aliases
.count(rcmd
)) {
126 (*output
) << rcmd
<< " is an alias for: " << std::endl
;
128 for(auto i
: aliases
[rcmd
])
129 (*output
) << "#" << (++j
) << ": " << i
<< std::endl
;
133 rcmd
= rcmd
.substr(1);
134 if(!commands
.count(rcmd
))
135 (*output
) << "Unknown command '" << rcmd
<< "'" << std::endl
;
137 (*output
) << commands
[rcmd
]->get_long_help() << std::endl
;
140 bool may_be_alias_expanded
= true;
141 if(firstchar(cmd2
) == '*') {
142 may_be_alias_expanded
= false;
143 cmd2
= cmd2
.substr(1);
145 //Now this gets painful as command handlers must not be invoked with lock held.
146 if(may_be_alias_expanded
) {
147 std::list
<std::string
> aexp
;
149 umutex_class
lock(int_mutex
);
150 if(!aliases
.count(cmd
))
152 aexp
= aliases
[cmd2
];
160 size_t split
= cmd2
.find_first_of(" \t");
161 std::string rcmd
= cmd2
.substr(0, min(split
, cmd2
.length()));
162 std::string args
= cmd2
.substr(min(cmd2
.find_first_not_of(" \t", split
), cmd2
.length()));
165 umutex_class
lock(int_mutex
);
166 if(!commands
.count(rcmd
)) {
167 (*output
) << "Unknown command '" << rcmd
<< "'" << std::endl
;
170 cmdh
= commands
[rcmd
];
172 if(command_stack
.count(cmd2
))
173 throw std::runtime_error("Recursive command invocation");
174 command_stack
.insert(cmd2
);
176 command_stack
.erase(cmd2
);
178 } catch(std::bad_alloc
& e
) {
180 } catch(std::exception
& e
) {
181 (*output
) << "Error: " << e
.what() << std::endl
;
182 command_stack
.erase(cmd2
);
185 } catch(std::bad_alloc
& e
) {
190 std::set
<std::string
> group::get_aliases() throw(std::bad_alloc
)
192 umutex_class
lock(int_mutex
);
193 std::set
<std::string
> r
;
194 for(auto i
: aliases
)
199 std::string
group::get_alias_for(const std::string
& aname
) throw(std::bad_alloc
)
201 umutex_class
lock(int_mutex
);
202 if(!valid_alias_name(aname
))
204 if(aliases
.count(aname
)) {
206 for(auto i
: aliases
[aname
])
213 void group::set_alias_for(const std::string
& aname
, const std::string
& avalue
) throw(std::bad_alloc
)
215 umutex_class
lock(int_mutex
);
216 if(!valid_alias_name(aname
))
218 std::list
<std::string
> newlist
;
220 while(avitr
< avalue
.length()) {
221 size_t nextsplit
= min(avalue
.find_first_of("\n", avitr
), avalue
.length());
222 std::string x
= strip_CR(avalue
.substr(avitr
, nextsplit
- avitr
));
224 newlist
.push_back(x
);
225 avitr
= nextsplit
+ 1;
228 aliases
.erase(aname
);
230 aliases
[aname
] = newlist
;
233 bool group::valid_alias_name(const std::string
& aliasname
) throw(std::bad_alloc
)
235 if(aliasname
.length() == 0 || aliasname
[0] == '?' || aliasname
[0] == '*')
237 if(aliasname
.find_first_of(" \t") < aliasname
.length())
242 void group::do_register(const std::string
& name
, base
& cmd
) throw(std::bad_alloc
)
244 umutex_class
lock(int_mutex
);
245 if(commands
.count(name
))
246 std::cerr
<< "WARNING: Command collision for " << name
<< "!" << std::endl
;
247 commands
[name
] = &cmd
;
250 void group::do_unregister(const std::string
& name
) throw(std::bad_alloc
)
252 umutex_class
lock(int_mutex
);
253 commands
.erase(name
);
256 void group::set_output(std::ostream
& s
)
261 void group::set_oom_panic(void (*fn
)())
264 oom_panic_routine
= fn
;
266 oom_panic_routine
= default_oom_panic
;
270 void invoke_fn(void (*fn
)(const std::string
& args
), const std::string
& args
)
276 void invoke_fn(void (*fn
)(), const std::string
& args
)
279 throw std::runtime_error("This command does not take arguments");
284 void invoke_fn(void (*fn
)(struct arg_filename a
), const std::string
& args
)
287 throw std::runtime_error("Filename required");