-
Notifications
You must be signed in to change notification settings - Fork 50
/
interface.hh
301 lines (265 loc) · 12.3 KB
/
interface.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file interface.hh
/// \brief Classes and utilities for a \e generic command-line interface
#ifndef __INTERFACE_HH__
#define __INTERFACE_HH__
#include "capability.hh"
#include <map>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <cstdio>
namespace ghidra {
using std::map;
using std::istream;
using std::ostream;
using std::ifstream;
using std::ofstream;
using std::istringstream;
using std::endl;
using std::ws;
using std::ios_base;
#ifdef __REMOTE_SOCKET__
/// \brief A wrapper around a UNIX domain socket
///
/// The open() command attempts to connect to given socket name,
/// which must have been previously established by an external process.
/// The socket is bound to a C++ istream and ostream.
class RemoteSocket {
int fileDescriptor; ///< Descriptor for the socket
basic_filebuf<char> *inbuf; ///< Input buffer associated with the socket
basic_filebuf<char> *outbuf; ///< Output buffer for the socket
istream *inStream; ///< The C++ input stream
ostream *outStream; ///< The C++ output stream
bool isOpen; ///< Has the socket been opened
public:
RemoteSocket(void); ///< Constructor
~RemoteSocket(void) { close(); } ///< Destructor
bool open(const string &filename); ///< Connect to the given socket
bool isSocketOpen(void); ///< Return \b true if the socket is ready to transfer data
istream *getInputStream(void) { return inStream; } ///< Get the input stream
ostream *getOutputStream(void) { return outStream; } ///< Get the output stream
void close(void); ///< Close the streams and socket
};
#endif
/// \brief An exception specific to the command line interface
struct IfaceError {
string explain; ///< Explanatory string
IfaceError(const string &s) { explain = s; } ///< Constructor
};
/// \brief An exception describing a parsing error in a command line
///
/// Thrown when attempting to parse a command line. Options are missing or are in
/// the wrong form etc.
struct IfaceParseError : public IfaceError {
IfaceParseError(const string &s) : IfaceError(s) {} ///< Constructor
};
/// \brief An exception throw during the execution of a command
///
/// Processing of a specific command has started but has reached an error state
struct IfaceExecutionError : public IfaceError {
IfaceExecutionError(const string &s) : IfaceError(s) {} ///< Constructor
};
class IfaceStatus; // Forward declaration
/// \brief Data specialized for a particular command module
///
/// IfaceCommands can have specialized data that is shared with other commands in
/// the same module. This is the root object for all such data.
class IfaceData {
public:
virtual ~IfaceData(void) {} ///< Destructor
};
/// \brief A command that can be executed from the command line
///
/// The command has data associated with it (via setData()) and is executed
/// via the execute() method. The command can get additional parameters from
/// the command line by reading the input stream passed to it.
/// The command is associated with a specific sequence of words (tokens)
/// that should appear at the start of the command line.
class IfaceCommand {
vector<string> com; ///< The token sequence associated with the command
public:
virtual ~IfaceCommand(void) {} ///< Destructor
/// \brief Associate a specific data object with this command.
///
/// \param root is the interface object this command is registered with
/// \param data is the data object the command should use
virtual void setData(IfaceStatus *root,IfaceData *data)=0;
/// Execute this command. Additional state can be read from the given command line stream.
/// Otherwise, the command gets its data from its registered IfaceData object
/// \param s is the input stream from the command line
virtual void execute(istream &s)=0;
/// \brief Get the formal module name to which this command belongs
///
/// Commands in the same module share data through their registered IfaceData object
/// \return the formal module name
virtual string getModule(void) const=0;
/// \brief Create a specialized data object for \b this command (and its module)
///
/// This method is only called once per module
/// \return the newly created data object for the module
virtual IfaceData *createData(void)=0;
/// \brief Add a token to the command line string associated with this command
///
/// \param temp is the new token to add
void addWord(const string &temp) { com.push_back(temp); }
void removeWord(void) { com.pop_back(); } ///< Remove the last token from the associated command line string
const string &getCommandWord(int4 i) const { return com[i]; } ///< Get the i-th command token
void addWords(const vector<string> &wordlist); ///< Add words to the associated command line string
int4 numWords(void) const { return com.size(); } ///< Return the number of tokens in the command line string
void commandString(string &res) const; ///< Get the complete command line string
int4 compare(const IfaceCommand &op2) const; ///< Order two commands by their command line strings
};
/// \brief A dummy command used during parsing
class IfaceCommandDummy : public IfaceCommand {
public:
virtual void setData(IfaceStatus *root,IfaceData *data) {}
virtual void execute(istream &s) {}
virtual string getModule(void) const { return "dummy"; }
virtual IfaceData *createData(void) { return (IfaceData *)0; }
};
/// \brief Compare to commands as pointers
///
/// \param a is a pointer to the first command
/// \param b is a pointer to the second command
/// \return \b true if the first pointer is ordered before the second
inline bool compare_ifacecommand(const IfaceCommand *a,const IfaceCommand *b) {
return (0>a->compare(*b));
}
/// \brief Groups of console commands that are \e discovered by the loader
///
/// Any IfaceCommand that is registered with a grouping derived from this class
/// is automatically made available to any IfaceStatus object just by calling
/// the static registerAllCommands()
class IfaceCapability : public CapabilityPoint {
static vector<IfaceCapability *> thelist; ///< The global list of discovered command groupings
protected:
string name; ///< Identifying name for the capability
public:
const string &getName(void) const { return name; } ///< Get the name of the capability
virtual void initialize(void);
virtual void registerCommands(IfaceStatus *status)=0; ///< Register commands for \b this grouping
static void registerAllCommands(IfaceStatus *status); ///< Register all discovered commands with the interface
};
/// \brief A generic console mode interface and command executor
///
/// Input is provided one command line at a time by providing calling readLine().
/// Output goes to a provided ostream, \e optr. Output to a separate bulk stream
/// can be enabled by setting \e fileoptr.
///
/// A derived IfaceCommand is attached to a command string via registerCom()
/// i.e.
/// stat.registerCom(new IfcQuit(),"quit");
/// stat.registerCom(new IfcOpenfileAppend(),"openfile","append");
/// stat.mainloop();
/// Command line processing is started with mainloop(), which prints a command prompt,
/// allows command line editing, including command completion and history, and executes
/// the corresponding IfaceComman::execute() callback.
/// Command words only have to match enough to disambiguate it from other commands.
/// A Custom history size and command prompt can be passed to the constructor.
/// Applications should inherit from base class IfaceStatus in order to
/// - Override the readLine() method
/// - Override pushScript() and popScript() to allow command scripts
/// - Get custom data into IfaceCommand callbacks
class IfaceStatus {
vector<string> promptstack; ///< Stack of command prompts corresponding to script nesting level
vector<uint4> flagstack; ///< Stack of flag state corresponding to script nesting level
string prompt; ///< The current command prompt
int4 maxhistory; ///< Maximum number of command lines to store in history
int4 curhistory; ///< Most recent history
vector<string> history; ///< History of commands executed through this interface
bool sorted; ///< Set to \b true if commands are sorted
bool errorisdone; ///< Set to \b true if any error terminates the process
void restrictCom(vector<IfaceCommand *>::const_iterator &first,
vector<IfaceCommand *>::const_iterator &last,vector<string> &input);
/// \brief Read the next command line
///
/// \param line is filled in with the next command to execute
virtual void readLine(string &line)=0;
void saveHistory(const string &line); ///< Store the given command line into \e history
protected:
bool inerror; ///< Set to \b true if last command did not succeed
vector<IfaceCommand *> comlist; ///< List of registered commands
map<string,IfaceData *> datamap; ///< Data associated with particular modules
int4 expandCom(vector<string> &expand,istream &s,
vector<IfaceCommand *>::const_iterator &first,
vector<IfaceCommand *>::const_iterator &last);
public:
bool done; ///< Set to \b true (by a command) to indicate processing is finished
ostream *optr; ///< Where to put command line output
ostream *fileoptr; ///< Where to put bulk output
IfaceStatus(const string &prmpt,ostream &os,int4 mxhist=10); ///< Constructor
virtual ~IfaceStatus(void); ///< Destructor
void setErrorIsDone(bool val) { errorisdone = val; } ///< Set if processing should terminate on an error
void pushScript(const string &filename,const string &newprompt);
virtual void pushScript(istream *iptr,const string &newprompt);
virtual void popScript(void);
virtual void reset(void); ///< Pop any existing script streams and return to processing from the base stream
int4 getNumInputStreamSize(void) const { return promptstack.size(); } ///< Get depth of script nesting
void writePrompt(void) { *optr << prompt; } ///< Write the current command prompt to the current output stream
void registerCom(IfaceCommand *fptr, const char *nm1,
const char *nm2 = (const char *)0,
const char *nm3 = (const char *)0,
const char *nm4 = (const char *)0,
const char *nm5 = (const char *)0);
IfaceData *getData(const string &nm) const; ///< Get data associated with a IfaceCommand module
bool runCommand(void); ///< Run the next command
void getHistory(string &line,int4 i) const; ///< Get the i-th command line from history
int4 getHistorySize(void) const { return history.size(); } ///< Get the number of command lines in history
virtual bool isStreamFinished(void) const=0; ///< Return \b true if the current stream is finished
bool isInError(void) const { return inerror; } ///< Return \b true if the last command failed
void evaluateError(void); ///< Adjust which stream to process based on last error
static void wordsToString(string &res,const vector<string> &list); ///< Concatenate tokens
};
/// \brief A root class for a basic set of commands
///
/// Commands derived from this class are in the "base" module.
/// They are useful as part of any interface
class IfaceBaseCommand : public IfaceCommand {
protected:
IfaceStatus *status; ///< The interface owning this command instance
public:
virtual void setData(IfaceStatus *root,IfaceData *data) { status = root; }
virtual string getModule(void) const { return "base"; }
virtual IfaceData *createData(void) { return (IfaceData *)0; }
};
class IfcQuit : public IfaceBaseCommand {
public:
virtual void execute(istream &s);
};
class IfcHistory : public IfaceBaseCommand {
public:
virtual void execute(istream &s);
};
class IfcOpenfile : public IfaceBaseCommand {
public:
virtual void execute(istream &s);
};
class IfcOpenfileAppend : public IfaceBaseCommand {
public:
virtual void execute(istream &s);
};
class IfcClosefile : public IfaceBaseCommand {
public:
virtual void execute(istream &s);
};
class IfcEcho : public IfaceBaseCommand {
public:
virtual void execute(istream &s);
};
} // End namespace ghidra
#endif