9 std::map
<std::string
, command
*>* commands
;
10 std::set
<std::string
> command_stack
;
11 std::map
<std::string
, std::list
<std::string
>> aliases
;
13 function_ptr_command
<arg_filename
> run_script("run-script", "run file as a script",
14 "Syntax: run-script <file>\nRuns file <file> just as it would have been entered in the command line\n",
15 [](arg_filename filename
) throw(std::bad_alloc
, std::runtime_error
) {
16 std::istream
* o
= NULL
;
18 o
= &open_file_relative(filename
, "");
19 messages
<< "Running '" << std::string(filename
) << "'" << std::endl
;
21 while(std::getline(*o
, line
))
22 command::invokeC(line
);
24 } catch(std::exception
& e
) {
31 function_ptr_command
<> show_aliases("show-aliases", "show aliases",
32 "Syntax: show-aliases\nShow expansions of all aliases\n",
33 []() throw(std::bad_alloc
, std::runtime_error
) {
34 for(auto i
= aliases
.begin(); i
!= aliases
.end(); i
++)
35 for(auto j
= i
->second
.begin(); j
!= i
->second
.end(); j
++)
36 messages
<< "alias " << i
->first
<< " " << *j
<< std::endl
;
39 function_ptr_command
<tokensplitter
&> unalias_command("unalias-command", "unalias a command",
40 "Syntax: unalias-command <aliasname>\nClear expansion of alias <aliasname>\n",
41 [](tokensplitter
& t
) throw(std::bad_alloc
, std::runtime_error
) {
42 std::string aliasname
= t
;
44 throw std::runtime_error("This command only takes one argument");
45 if(aliasname
.length() == 0 || aliasname
[0] == '?' || aliasname
[0] == '*')
46 throw std::runtime_error("Illegal alias name");
47 aliases
[aliasname
].clear();
48 messages
<< "Command '" << aliasname
<< "' unaliased" << std::endl
;
51 function_ptr_command
<tokensplitter
&> alias_command("alias-command", "alias a command",
52 "Syntax: alias-command <aliasname> <command>\nAppend <command> to expansion of alias <aliasname>\n"
53 "Valid alias names can't be empty nor start with '*' or '?'\n",
54 [](tokensplitter
& t
) throw(std::bad_alloc
, std::runtime_error
) {
55 std::string aliasname
= t
;
56 std::string command
= t
.tail();
58 throw std::runtime_error("Alias name and command needed");
59 if(aliasname
.length() == 0 || aliasname
[0] == '?' || aliasname
[0] == '*')
60 throw std::runtime_error("Illegal alias name");
61 aliases
[aliasname
].push_back(command
);
62 messages
<< "Command '" << aliasname
<< "' aliased to '" << command
<< "'" << std::endl
;
66 command::command(const std::string
& cmd
) throw(std::bad_alloc
)
69 commands
= new std::map
<std::string
, command
*>();
70 if(commands
->count(cmd
))
71 std::cerr
<< "WARNING: Command collision for " << cmd
<< "!" << std::endl
;
72 (*commands
)[commandname
= cmd
] = this;
75 command::~command() throw()
79 commands
->erase(commandname
);
82 void command::invokeC(const std::string
& cmd
) throw()
85 std::string cmd2
= cmd
;
87 //The special ? command.
89 for(auto i
= commands
->begin(); i
!= commands
->end(); ++i
)
90 messages
<< i
->first
<< ": " << i
->second
->get_short_help() << std::endl
;
94 if(cmd2
.length() > 1 && cmd2
[0] == '?') {
96 size_t split
= cmd2
.find_first_of(" \t");
98 if(split
>= cmd2
.length())
99 rcmd
= cmd2
.substr(1);
101 rcmd
= cmd2
.substr(1, split
- 1);
102 if(rcmd
.length() > 0 && rcmd
[0] != '*') {
103 //This may be an alias.
104 std::string aname
= cmd2
.substr(1);
105 if(aliases
.count(aname
)) {
107 messages
<< aname
<< " is an alias for: " << std::endl
;
109 for(auto i
= aliases
[aname
].begin(); i
!= aliases
[aname
].end(); ++i
, ++j
)
110 messages
<< "#" + (j
+ 1) << ": " << *i
<< std::endl
;
114 if(rcmd
.length() > 0 && rcmd
[0] == '*')
115 rcmd
= rcmd
.substr(1);
116 if(!commands
|| !commands
->count(rcmd
)) {
118 messages
<< "Unknown command '" << rcmd
<< "'" << std::endl
;
121 messages
<< (*commands
)[rcmd
]->get_long_help() << std::endl
;
124 bool may_be_alias_expanded
= true;
125 if(cmd2
.length() > 0 && cmd2
[0] == '*') {
126 may_be_alias_expanded
= false;
127 cmd2
= cmd2
.substr(1);
129 if(may_be_alias_expanded
&& aliases
.count(cmd2
)) {
130 for(auto i
= aliases
[cmd2
].begin(); i
!= aliases
[cmd2
].end(); ++i
)
135 size_t split
= cmd2
.find_first_of(" \t");
137 if(split
>= cmd2
.length())
140 rcmd
= cmd2
.substr(0, split
);
141 split
= cmd2
.find_first_not_of(" \t", split
);
143 if(split
< cmd2
.length())
144 args
= cmd2
.substr(split
);
145 command
* cmdh
= NULL
;
146 if(commands
&& commands
->count(rcmd
))
147 cmdh
= (*commands
)[rcmd
];
149 messages
<< "Unknown command '" << rcmd
<< "'" << std::endl
;
152 if(command_stack
.count(cmd
))
153 throw std::runtime_error("Recursive command invocation");
154 command_stack
.insert(cmd
);
156 command_stack
.erase(cmd
);
158 } catch(std::bad_alloc
& e
) {
160 } catch(std::exception
& e
) {
161 messages
<< "Error: " << e
.what() << std::endl
;
162 command_stack
.erase(cmd
);
165 } catch(std::bad_alloc
& e
) {
170 std::string
command::get_short_help() throw(std::bad_alloc
)
172 return "No description available";
175 std::string
command::get_long_help() throw(std::bad_alloc
)
177 return "No help available on command " + commandname
;
180 tokensplitter::tokensplitter(const std::string
& _line
) throw(std::bad_alloc
)
186 tokensplitter::operator bool() throw()
188 return (position
< line
.length());
191 tokensplitter::operator std::string() throw(std::bad_alloc
)
193 size_t nextp
, oldp
= position
;
194 nextp
= line
.find_first_of(" \t", position
);
195 if(nextp
> line
.length()) {
196 position
= line
.length();
197 return line
.substr(oldp
);
200 while(position
< line
.length() && (line
[position
] == ' ' || line
[position
] == '\t'))
202 return line
.substr(oldp
, nextp
- oldp
);
206 std::string
tokensplitter::tail() throw(std::bad_alloc
)
208 return line
.substr(position
);
212 void invoke_command_fn(void (*fn
)(const std::string
& args
), const std::string
& args
)
218 void invoke_command_fn(void (*fn
)(), const std::string
& args
)
221 throw std::runtime_error("This command does not take arguments");
226 void invoke_command_fn(void (*fn
)(struct arg_filename a
), const std::string
& args
)
229 throw std::runtime_error("Filename required");
236 void invoke_command_fn(void (*fn
)(tokensplitter
& a
), const std::string
& args
)
238 tokensplitter
t(args
);