diff options
author | Melanie Thielker | 2009-05-04 12:15:55 +0000 |
---|---|---|
committer | Melanie Thielker | 2009-05-04 12:15:55 +0000 |
commit | 1b877234dada9f14cebc486cc426db892beae152 (patch) | |
tree | 762ee7172c66a78b643f4cef0eed946314816403 /OpenSim/Framework/Console | |
parent | Thanks BlueWall for Mantis #3578 - adding Hypergrid connection to JSON Stats (diff) | |
download | opensim-SC-1b877234dada9f14cebc486cc426db892beae152.zip opensim-SC-1b877234dada9f14cebc486cc426db892beae152.tar.gz opensim-SC-1b877234dada9f14cebc486cc426db892beae152.tar.bz2 opensim-SC-1b877234dada9f14cebc486cc426db892beae152.tar.xz |
Refactor. Make ConsoleBase a true base class. Create CommandConsole as a simple
console capable of processing commands. Create LocalConsole as a console
that uses cursor control and context help. Precursor to a distributed
console system for the new grid services. No functional change intended :)
Diffstat (limited to 'OpenSim/Framework/Console')
-rw-r--r-- | OpenSim/Framework/Console/CommandConsole.cs | 467 | ||||
-rw-r--r-- | OpenSim/Framework/Console/ConsoleBase.cs | 829 | ||||
-rw-r--r-- | OpenSim/Framework/Console/LocalConsole.cs | 470 | ||||
-rw-r--r-- | OpenSim/Framework/Console/MainConsole.cs | 4 |
4 files changed, 970 insertions, 800 deletions
diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs new file mode 100644 index 0000000..0c314b9 --- /dev/null +++ b/OpenSim/Framework/Console/CommandConsole.cs | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using System.Threading; | ||
34 | using log4net; | ||
35 | |||
36 | namespace OpenSim.Framework.Console | ||
37 | { | ||
38 | public delegate void CommandDelegate(string module, string[] cmd); | ||
39 | |||
40 | public class Commands | ||
41 | { | ||
42 | /// <summary> | ||
43 | /// Encapsulates a command that can be invoked from the console | ||
44 | /// </summary> | ||
45 | private class CommandInfo | ||
46 | { | ||
47 | /// <value> | ||
48 | /// The module from which this command comes | ||
49 | /// </value> | ||
50 | public string module; | ||
51 | |||
52 | /// <value> | ||
53 | /// Whether the module is shared | ||
54 | /// </value> | ||
55 | public bool shared; | ||
56 | |||
57 | /// <value> | ||
58 | /// Very short BNF description | ||
59 | /// </value> | ||
60 | public string help_text; | ||
61 | |||
62 | /// <value> | ||
63 | /// Longer one line help text | ||
64 | /// </value> | ||
65 | public string long_help; | ||
66 | |||
67 | /// <value> | ||
68 | /// Full descriptive help for this command | ||
69 | /// </value> | ||
70 | public string descriptive_help; | ||
71 | |||
72 | /// <value> | ||
73 | /// The method to invoke for this command | ||
74 | /// </value> | ||
75 | public List<CommandDelegate> fn; | ||
76 | } | ||
77 | |||
78 | /// <value> | ||
79 | /// Commands organized by keyword in a tree | ||
80 | /// </value> | ||
81 | private Dictionary<string, object> tree = | ||
82 | new Dictionary<string, object>(); | ||
83 | |||
84 | /// <summary> | ||
85 | /// Get help for the given help string | ||
86 | /// </summary> | ||
87 | /// <param name="helpParts">Parsed parts of the help string. If empty then general help is returned.</param> | ||
88 | /// <returns></returns> | ||
89 | public List<string> GetHelp(string[] cmd) | ||
90 | { | ||
91 | List<string> help = new List<string>(); | ||
92 | List<string> helpParts = new List<string>(cmd); | ||
93 | |||
94 | // Remove initial help keyword | ||
95 | helpParts.RemoveAt(0); | ||
96 | |||
97 | // General help | ||
98 | if (helpParts.Count == 0) | ||
99 | { | ||
100 | help.AddRange(CollectHelp(tree)); | ||
101 | help.Sort(); | ||
102 | } | ||
103 | else | ||
104 | { | ||
105 | help.AddRange(CollectHelp(helpParts)); | ||
106 | } | ||
107 | |||
108 | return help; | ||
109 | } | ||
110 | |||
111 | /// <summary> | ||
112 | /// See if we can find the requested command in order to display longer help | ||
113 | /// </summary> | ||
114 | /// <param name="helpParts"></param> | ||
115 | /// <returns></returns> | ||
116 | private List<string> CollectHelp(List<string> helpParts) | ||
117 | { | ||
118 | string originalHelpRequest = string.Join(" ", helpParts.ToArray()); | ||
119 | List<string> help = new List<string>(); | ||
120 | |||
121 | Dictionary<string, object> dict = tree; | ||
122 | while (helpParts.Count > 0) | ||
123 | { | ||
124 | string helpPart = helpParts[0]; | ||
125 | |||
126 | if (!dict.ContainsKey(helpPart)) | ||
127 | break; | ||
128 | |||
129 | //m_log.Debug("Found {0}", helpParts[0]); | ||
130 | |||
131 | if (dict[helpPart] is Dictionary<string, Object>) | ||
132 | dict = (Dictionary<string, object>)dict[helpPart]; | ||
133 | |||
134 | helpParts.RemoveAt(0); | ||
135 | } | ||
136 | |||
137 | // There was a command for the given help string | ||
138 | if (dict.ContainsKey(String.Empty)) | ||
139 | { | ||
140 | CommandInfo commandInfo = (CommandInfo)dict[String.Empty]; | ||
141 | help.Add(commandInfo.help_text); | ||
142 | help.Add(commandInfo.long_help); | ||
143 | help.Add(commandInfo.descriptive_help); | ||
144 | } | ||
145 | else | ||
146 | { | ||
147 | help.Add(string.Format("No help is available for {0}", originalHelpRequest)); | ||
148 | } | ||
149 | |||
150 | return help; | ||
151 | } | ||
152 | |||
153 | private List<string> CollectHelp(Dictionary<string, object> dict) | ||
154 | { | ||
155 | List<string> result = new List<string>(); | ||
156 | |||
157 | foreach (KeyValuePair<string, object> kvp in dict) | ||
158 | { | ||
159 | if (kvp.Value is Dictionary<string, Object>) | ||
160 | { | ||
161 | result.AddRange(CollectHelp((Dictionary<string, Object>)kvp.Value)); | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | if (((CommandInfo)kvp.Value).long_help != String.Empty) | ||
166 | result.Add(((CommandInfo)kvp.Value).help_text+" - "+ | ||
167 | ((CommandInfo)kvp.Value).long_help); | ||
168 | } | ||
169 | } | ||
170 | return result; | ||
171 | } | ||
172 | |||
173 | /// <summary> | ||
174 | /// Add a command to those which can be invoked from the console. | ||
175 | /// </summary> | ||
176 | /// <param name="module"></param> | ||
177 | /// <param name="command"></param> | ||
178 | /// <param name="help"></param> | ||
179 | /// <param name="longhelp"></param> | ||
180 | /// <param name="fn"></param> | ||
181 | public void AddCommand(string module, bool shared, string command, | ||
182 | string help, string longhelp, CommandDelegate fn) | ||
183 | { | ||
184 | AddCommand(module, shared, command, help, longhelp, | ||
185 | String.Empty, fn); | ||
186 | } | ||
187 | |||
188 | /// <summary> | ||
189 | /// Add a command to those which can be invoked from the console. | ||
190 | /// </summary> | ||
191 | /// <param name="module"></param> | ||
192 | /// <param name="command"></param> | ||
193 | /// <param name="help"></param> | ||
194 | /// <param name="longhelp"></param> | ||
195 | /// <param name="descriptivehelp"></param> | ||
196 | /// <param name="fn"></param> | ||
197 | public void AddCommand(string module, bool shared, string command, | ||
198 | string help, string longhelp, string descriptivehelp, | ||
199 | CommandDelegate fn) | ||
200 | { | ||
201 | string[] parts = Parser.Parse(command); | ||
202 | |||
203 | Dictionary<string, Object> current = tree; | ||
204 | |||
205 | foreach (string s in parts) | ||
206 | { | ||
207 | if (current.ContainsKey(s)) | ||
208 | { | ||
209 | if (current[s] is Dictionary<string, Object>) | ||
210 | { | ||
211 | current = (Dictionary<string, Object>)current[s]; | ||
212 | } | ||
213 | else | ||
214 | return; | ||
215 | } | ||
216 | else | ||
217 | { | ||
218 | current[s] = new Dictionary<string, Object>(); | ||
219 | current = (Dictionary<string, Object>)current[s]; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | CommandInfo info; | ||
224 | |||
225 | if (current.ContainsKey(String.Empty)) | ||
226 | { | ||
227 | info = (CommandInfo)current[String.Empty]; | ||
228 | if (!info.shared && !info.fn.Contains(fn)) | ||
229 | info.fn.Add(fn); | ||
230 | |||
231 | return; | ||
232 | } | ||
233 | |||
234 | info = new CommandInfo(); | ||
235 | info.module = module; | ||
236 | info.shared = shared; | ||
237 | info.help_text = help; | ||
238 | info.long_help = longhelp; | ||
239 | info.descriptive_help = descriptivehelp; | ||
240 | info.fn = new List<CommandDelegate>(); | ||
241 | info.fn.Add(fn); | ||
242 | current[String.Empty] = info; | ||
243 | } | ||
244 | |||
245 | public string[] FindNextOption(string[] cmd, bool term) | ||
246 | { | ||
247 | Dictionary<string, object> current = tree; | ||
248 | |||
249 | int remaining = cmd.Length; | ||
250 | |||
251 | foreach (string s in cmd) | ||
252 | { | ||
253 | remaining--; | ||
254 | |||
255 | List<string> found = new List<string>(); | ||
256 | |||
257 | foreach (string opt in current.Keys) | ||
258 | { | ||
259 | if (remaining > 0 && opt == s) | ||
260 | { | ||
261 | found.Clear(); | ||
262 | found.Add(opt); | ||
263 | break; | ||
264 | } | ||
265 | if (opt.StartsWith(s)) | ||
266 | { | ||
267 | found.Add(opt); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | if (found.Count == 1 && (remaining != 0 || term)) | ||
272 | { | ||
273 | current = (Dictionary<string, object>)current[found[0]]; | ||
274 | } | ||
275 | else if (found.Count > 0) | ||
276 | { | ||
277 | return found.ToArray(); | ||
278 | } | ||
279 | else | ||
280 | { | ||
281 | break; | ||
282 | // return new string[] {"<cr>"}; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | if (current.Count > 1) | ||
287 | { | ||
288 | List<string> choices = new List<string>(); | ||
289 | |||
290 | bool addcr = false; | ||
291 | foreach (string s in current.Keys) | ||
292 | { | ||
293 | if (s == String.Empty) | ||
294 | { | ||
295 | CommandInfo ci = (CommandInfo)current[String.Empty]; | ||
296 | if (ci.fn.Count != 0) | ||
297 | addcr = true; | ||
298 | } | ||
299 | else | ||
300 | choices.Add(s); | ||
301 | } | ||
302 | if (addcr) | ||
303 | choices.Add("<cr>"); | ||
304 | return choices.ToArray(); | ||
305 | } | ||
306 | |||
307 | if (current.ContainsKey(String.Empty)) | ||
308 | return new string[] { "Command help: "+((CommandInfo)current[String.Empty]).help_text}; | ||
309 | |||
310 | return new string[] { new List<string>(current.Keys)[0] }; | ||
311 | } | ||
312 | |||
313 | public string[] Resolve(string[] cmd) | ||
314 | { | ||
315 | string[] result = cmd; | ||
316 | int index = -1; | ||
317 | |||
318 | Dictionary<string, object> current = tree; | ||
319 | |||
320 | foreach (string s in cmd) | ||
321 | { | ||
322 | index++; | ||
323 | |||
324 | List<string> found = new List<string>(); | ||
325 | |||
326 | foreach (string opt in current.Keys) | ||
327 | { | ||
328 | if (opt == s) | ||
329 | { | ||
330 | found.Clear(); | ||
331 | found.Add(opt); | ||
332 | break; | ||
333 | } | ||
334 | if (opt.StartsWith(s)) | ||
335 | { | ||
336 | found.Add(opt); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | if (found.Count == 1) | ||
341 | { | ||
342 | result[index] = found[0]; | ||
343 | current = (Dictionary<string, object>)current[found[0]]; | ||
344 | } | ||
345 | else if (found.Count > 0) | ||
346 | { | ||
347 | return new string[0]; | ||
348 | } | ||
349 | else | ||
350 | { | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | if (current.ContainsKey(String.Empty)) | ||
356 | { | ||
357 | CommandInfo ci = (CommandInfo)current[String.Empty]; | ||
358 | if (ci.fn.Count == 0) | ||
359 | return new string[0]; | ||
360 | foreach (CommandDelegate fn in ci.fn) | ||
361 | { | ||
362 | if (fn != null) | ||
363 | fn(ci.module, result); | ||
364 | else | ||
365 | return new string[0]; | ||
366 | } | ||
367 | return result; | ||
368 | } | ||
369 | |||
370 | return new string[0]; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | public class Parser | ||
375 | { | ||
376 | public static string[] Parse(string text) | ||
377 | { | ||
378 | List<string> result = new List<string>(); | ||
379 | |||
380 | int index; | ||
381 | |||
382 | string[] unquoted = text.Split(new char[] {'"'}); | ||
383 | |||
384 | for (index = 0 ; index < unquoted.Length ; index++) | ||
385 | { | ||
386 | if (index % 2 == 0) | ||
387 | { | ||
388 | string[] words = unquoted[index].Split(new char[] {' '}); | ||
389 | foreach (string w in words) | ||
390 | { | ||
391 | if (w != String.Empty) | ||
392 | result.Add(w); | ||
393 | } | ||
394 | } | ||
395 | else | ||
396 | { | ||
397 | result.Add(unquoted[index]); | ||
398 | } | ||
399 | } | ||
400 | |||
401 | return result.ToArray(); | ||
402 | } | ||
403 | } | ||
404 | |||
405 | // A console that processes commands internally | ||
406 | // | ||
407 | public class CommandConsole : ConsoleBase | ||
408 | { | ||
409 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
410 | |||
411 | public Commands Commands = new Commands(); | ||
412 | |||
413 | public CommandConsole(string defaultPrompt) : base(defaultPrompt) | ||
414 | { | ||
415 | Commands.AddCommand("console", false, "help", "help [<command>]", | ||
416 | "Get general command list or more detailed help on a specific command", Help); | ||
417 | } | ||
418 | |||
419 | private void Help(string module, string[] cmd) | ||
420 | { | ||
421 | List<string> help = Commands.GetHelp(cmd); | ||
422 | |||
423 | foreach (string s in help) | ||
424 | Output(s); | ||
425 | } | ||
426 | |||
427 | public void Prompt() | ||
428 | { | ||
429 | string line = ReadLine(m_defaultPrompt, true, true); | ||
430 | |||
431 | if (line != String.Empty) | ||
432 | { | ||
433 | m_log.Info("Invalid command"); | ||
434 | } | ||
435 | } | ||
436 | |||
437 | public void RunCommand(string cmd) | ||
438 | { | ||
439 | string[] parts = Parser.Parse(cmd); | ||
440 | Commands.Resolve(parts); | ||
441 | } | ||
442 | |||
443 | public override string ReadLine(string p, bool isCommand, bool e) | ||
444 | { | ||
445 | System.Console.Write("{0}", prompt); | ||
446 | string cmdinput = System.Console.ReadLine(); | ||
447 | |||
448 | if (isCommand) | ||
449 | { | ||
450 | string[] cmd = Commands.Resolve(Parser.Parse(cmdinput)); | ||
451 | |||
452 | if (cmd.Length != 0) | ||
453 | { | ||
454 | int i; | ||
455 | |||
456 | for (i=0 ; i < cmd.Length ; i++) | ||
457 | { | ||
458 | if (cmd[i].Contains(" ")) | ||
459 | cmd[i] = "\"" + cmd[i] + "\""; | ||
460 | } | ||
461 | return String.Empty; | ||
462 | } | ||
463 | } | ||
464 | return cmdinput; | ||
465 | } | ||
466 | } | ||
467 | } | ||
diff --git a/OpenSim/Framework/Console/ConsoleBase.cs b/OpenSim/Framework/Console/ConsoleBase.cs index fda2037..30493fc 100644 --- a/OpenSim/Framework/Console/ConsoleBase.cs +++ b/OpenSim/Framework/Console/ConsoleBase.cs | |||
@@ -35,388 +35,11 @@ using log4net; | |||
35 | 35 | ||
36 | namespace OpenSim.Framework.Console | 36 | namespace OpenSim.Framework.Console |
37 | { | 37 | { |
38 | public delegate void CommandDelegate(string module, string[] cmd); | ||
39 | |||
40 | public class Commands | ||
41 | { | ||
42 | /// <summary> | ||
43 | /// Encapsulates a command that can be invoked from the console | ||
44 | /// </summary> | ||
45 | private class CommandInfo | ||
46 | { | ||
47 | /// <value> | ||
48 | /// The module from which this command comes | ||
49 | /// </value> | ||
50 | public string module; | ||
51 | |||
52 | /// <value> | ||
53 | /// Whether the module is shared | ||
54 | /// </value> | ||
55 | public bool shared; | ||
56 | |||
57 | /// <value> | ||
58 | /// Very short BNF description | ||
59 | /// </value> | ||
60 | public string help_text; | ||
61 | |||
62 | /// <value> | ||
63 | /// Longer one line help text | ||
64 | /// </value> | ||
65 | public string long_help; | ||
66 | |||
67 | /// <value> | ||
68 | /// Full descriptive help for this command | ||
69 | /// </value> | ||
70 | public string descriptive_help; | ||
71 | |||
72 | /// <value> | ||
73 | /// The method to invoke for this command | ||
74 | /// </value> | ||
75 | public List<CommandDelegate> fn; | ||
76 | } | ||
77 | |||
78 | /// <value> | ||
79 | /// Commands organized by keyword in a tree | ||
80 | /// </value> | ||
81 | private Dictionary<string, object> tree = | ||
82 | new Dictionary<string, object>(); | ||
83 | |||
84 | /// <summary> | ||
85 | /// Get help for the given help string | ||
86 | /// </summary> | ||
87 | /// <param name="helpParts">Parsed parts of the help string. If empty then general help is returned.</param> | ||
88 | /// <returns></returns> | ||
89 | public List<string> GetHelp(string[] cmd) | ||
90 | { | ||
91 | List<string> help = new List<string>(); | ||
92 | List<string> helpParts = new List<string>(cmd); | ||
93 | |||
94 | // Remove initial help keyword | ||
95 | helpParts.RemoveAt(0); | ||
96 | |||
97 | // General help | ||
98 | if (helpParts.Count == 0) | ||
99 | { | ||
100 | help.AddRange(CollectHelp(tree)); | ||
101 | help.Sort(); | ||
102 | } | ||
103 | else | ||
104 | { | ||
105 | help.AddRange(CollectHelp(helpParts)); | ||
106 | } | ||
107 | |||
108 | return help; | ||
109 | } | ||
110 | |||
111 | /// <summary> | ||
112 | /// See if we can find the requested command in order to display longer help | ||
113 | /// </summary> | ||
114 | /// <param name="helpParts"></param> | ||
115 | /// <returns></returns> | ||
116 | private List<string> CollectHelp(List<string> helpParts) | ||
117 | { | ||
118 | string originalHelpRequest = string.Join(" ", helpParts.ToArray()); | ||
119 | List<string> help = new List<string>(); | ||
120 | |||
121 | Dictionary<string, object> dict = tree; | ||
122 | while (helpParts.Count > 0) | ||
123 | { | ||
124 | string helpPart = helpParts[0]; | ||
125 | |||
126 | if (!dict.ContainsKey(helpPart)) | ||
127 | break; | ||
128 | |||
129 | //m_log.Debug("Found {0}", helpParts[0]); | ||
130 | |||
131 | if (dict[helpPart] is Dictionary<string, Object>) | ||
132 | dict = (Dictionary<string, object>)dict[helpPart]; | ||
133 | |||
134 | helpParts.RemoveAt(0); | ||
135 | } | ||
136 | |||
137 | // There was a command for the given help string | ||
138 | if (dict.ContainsKey(String.Empty)) | ||
139 | { | ||
140 | CommandInfo commandInfo = (CommandInfo)dict[String.Empty]; | ||
141 | help.Add(commandInfo.help_text); | ||
142 | help.Add(commandInfo.long_help); | ||
143 | help.Add(commandInfo.descriptive_help); | ||
144 | } | ||
145 | else | ||
146 | { | ||
147 | help.Add(string.Format("No help is available for {0}", originalHelpRequest)); | ||
148 | } | ||
149 | |||
150 | return help; | ||
151 | } | ||
152 | |||
153 | private List<string> CollectHelp(Dictionary<string, object> dict) | ||
154 | { | ||
155 | List<string> result = new List<string>(); | ||
156 | |||
157 | foreach (KeyValuePair<string, object> kvp in dict) | ||
158 | { | ||
159 | if (kvp.Value is Dictionary<string, Object>) | ||
160 | { | ||
161 | result.AddRange(CollectHelp((Dictionary<string, Object>)kvp.Value)); | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | if (((CommandInfo)kvp.Value).long_help != String.Empty) | ||
166 | result.Add(((CommandInfo)kvp.Value).help_text+" - "+ | ||
167 | ((CommandInfo)kvp.Value).long_help); | ||
168 | } | ||
169 | } | ||
170 | return result; | ||
171 | } | ||
172 | |||
173 | /// <summary> | ||
174 | /// Add a command to those which can be invoked from the console. | ||
175 | /// </summary> | ||
176 | /// <param name="module"></param> | ||
177 | /// <param name="command"></param> | ||
178 | /// <param name="help"></param> | ||
179 | /// <param name="longhelp"></param> | ||
180 | /// <param name="fn"></param> | ||
181 | public void AddCommand(string module, bool shared, string command, | ||
182 | string help, string longhelp, CommandDelegate fn) | ||
183 | { | ||
184 | AddCommand(module, shared, command, help, longhelp, | ||
185 | String.Empty, fn); | ||
186 | } | ||
187 | |||
188 | /// <summary> | ||
189 | /// Add a command to those which can be invoked from the console. | ||
190 | /// </summary> | ||
191 | /// <param name="module"></param> | ||
192 | /// <param name="command"></param> | ||
193 | /// <param name="help"></param> | ||
194 | /// <param name="longhelp"></param> | ||
195 | /// <param name="descriptivehelp"></param> | ||
196 | /// <param name="fn"></param> | ||
197 | public void AddCommand(string module, bool shared, string command, | ||
198 | string help, string longhelp, string descriptivehelp, | ||
199 | CommandDelegate fn) | ||
200 | { | ||
201 | string[] parts = Parser.Parse(command); | ||
202 | |||
203 | Dictionary<string, Object> current = tree; | ||
204 | |||
205 | foreach (string s in parts) | ||
206 | { | ||
207 | if (current.ContainsKey(s)) | ||
208 | { | ||
209 | if (current[s] is Dictionary<string, Object>) | ||
210 | { | ||
211 | current = (Dictionary<string, Object>)current[s]; | ||
212 | } | ||
213 | else | ||
214 | return; | ||
215 | } | ||
216 | else | ||
217 | { | ||
218 | current[s] = new Dictionary<string, Object>(); | ||
219 | current = (Dictionary<string, Object>)current[s]; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | CommandInfo info; | ||
224 | |||
225 | if (current.ContainsKey(String.Empty)) | ||
226 | { | ||
227 | info = (CommandInfo)current[String.Empty]; | ||
228 | if (!info.shared && !info.fn.Contains(fn)) | ||
229 | info.fn.Add(fn); | ||
230 | |||
231 | return; | ||
232 | } | ||
233 | |||
234 | info = new CommandInfo(); | ||
235 | info.module = module; | ||
236 | info.shared = shared; | ||
237 | info.help_text = help; | ||
238 | info.long_help = longhelp; | ||
239 | info.descriptive_help = descriptivehelp; | ||
240 | info.fn = new List<CommandDelegate>(); | ||
241 | info.fn.Add(fn); | ||
242 | current[String.Empty] = info; | ||
243 | } | ||
244 | |||
245 | public string[] FindNextOption(string[] cmd, bool term) | ||
246 | { | ||
247 | Dictionary<string, object> current = tree; | ||
248 | |||
249 | int remaining = cmd.Length; | ||
250 | |||
251 | foreach (string s in cmd) | ||
252 | { | ||
253 | remaining--; | ||
254 | |||
255 | List<string> found = new List<string>(); | ||
256 | |||
257 | foreach (string opt in current.Keys) | ||
258 | { | ||
259 | if (remaining > 0 && opt == s) | ||
260 | { | ||
261 | found.Clear(); | ||
262 | found.Add(opt); | ||
263 | break; | ||
264 | } | ||
265 | if (opt.StartsWith(s)) | ||
266 | { | ||
267 | found.Add(opt); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | if (found.Count == 1 && (remaining != 0 || term)) | ||
272 | { | ||
273 | current = (Dictionary<string, object>)current[found[0]]; | ||
274 | } | ||
275 | else if (found.Count > 0) | ||
276 | { | ||
277 | return found.ToArray(); | ||
278 | } | ||
279 | else | ||
280 | { | ||
281 | break; | ||
282 | // return new string[] {"<cr>"}; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | if (current.Count > 1) | ||
287 | { | ||
288 | List<string> choices = new List<string>(); | ||
289 | |||
290 | bool addcr = false; | ||
291 | foreach (string s in current.Keys) | ||
292 | { | ||
293 | if (s == String.Empty) | ||
294 | { | ||
295 | CommandInfo ci = (CommandInfo)current[String.Empty]; | ||
296 | if (ci.fn.Count != 0) | ||
297 | addcr = true; | ||
298 | } | ||
299 | else | ||
300 | choices.Add(s); | ||
301 | } | ||
302 | if (addcr) | ||
303 | choices.Add("<cr>"); | ||
304 | return choices.ToArray(); | ||
305 | } | ||
306 | |||
307 | if (current.ContainsKey(String.Empty)) | ||
308 | return new string[] { "Command help: "+((CommandInfo)current[String.Empty]).help_text}; | ||
309 | |||
310 | return new string[] { new List<string>(current.Keys)[0] }; | ||
311 | } | ||
312 | |||
313 | public string[] Resolve(string[] cmd) | ||
314 | { | ||
315 | string[] result = cmd; | ||
316 | int index = -1; | ||
317 | |||
318 | Dictionary<string, object> current = tree; | ||
319 | |||
320 | foreach (string s in cmd) | ||
321 | { | ||
322 | index++; | ||
323 | |||
324 | List<string> found = new List<string>(); | ||
325 | |||
326 | foreach (string opt in current.Keys) | ||
327 | { | ||
328 | if (opt == s) | ||
329 | { | ||
330 | found.Clear(); | ||
331 | found.Add(opt); | ||
332 | break; | ||
333 | } | ||
334 | if (opt.StartsWith(s)) | ||
335 | { | ||
336 | found.Add(opt); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | if (found.Count == 1) | ||
341 | { | ||
342 | result[index] = found[0]; | ||
343 | current = (Dictionary<string, object>)current[found[0]]; | ||
344 | } | ||
345 | else if (found.Count > 0) | ||
346 | { | ||
347 | return new string[0]; | ||
348 | } | ||
349 | else | ||
350 | { | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | if (current.ContainsKey(String.Empty)) | ||
356 | { | ||
357 | CommandInfo ci = (CommandInfo)current[String.Empty]; | ||
358 | if (ci.fn.Count == 0) | ||
359 | return new string[0]; | ||
360 | foreach (CommandDelegate fn in ci.fn) | ||
361 | { | ||
362 | if (fn != null) | ||
363 | fn(ci.module, result); | ||
364 | else | ||
365 | return new string[0]; | ||
366 | } | ||
367 | return result; | ||
368 | } | ||
369 | |||
370 | return new string[0]; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | public class Parser | ||
375 | { | ||
376 | public static string[] Parse(string text) | ||
377 | { | ||
378 | List<string> result = new List<string>(); | ||
379 | |||
380 | int index; | ||
381 | |||
382 | string[] unquoted = text.Split(new char[] {'"'}); | ||
383 | |||
384 | for (index = 0 ; index < unquoted.Length ; index++) | ||
385 | { | ||
386 | if (index % 2 == 0) | ||
387 | { | ||
388 | string[] words = unquoted[index].Split(new char[] {' '}); | ||
389 | foreach (string w in words) | ||
390 | { | ||
391 | if (w != String.Empty) | ||
392 | result.Add(w); | ||
393 | } | ||
394 | } | ||
395 | else | ||
396 | { | ||
397 | result.Add(unquoted[index]); | ||
398 | } | ||
399 | } | ||
400 | |||
401 | return result.ToArray(); | ||
402 | } | ||
403 | } | ||
404 | |||
405 | public class ConsoleBase | 38 | public class ConsoleBase |
406 | { | 39 | { |
407 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 40 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
408 | 41 | ||
409 | private readonly object m_syncRoot = new object(); | 42 | protected string prompt = "# "; |
410 | |||
411 | private int y = -1; | ||
412 | private int cp = 0; | ||
413 | private int h = 1; | ||
414 | private string prompt = "# "; | ||
415 | private StringBuilder cmdline = new StringBuilder(); | ||
416 | public Commands Commands = new Commands(); | ||
417 | private bool echo = true; | ||
418 | private List<string> history = new List<string>(); | ||
419 | private bool gui = false; | ||
420 | 43 | ||
421 | public object ConsoleScene = null; | 44 | public object ConsoleScene = null; |
422 | 45 | ||
@@ -433,22 +56,6 @@ namespace OpenSim.Framework.Console | |||
433 | public ConsoleBase(string defaultPrompt) | 56 | public ConsoleBase(string defaultPrompt) |
434 | { | 57 | { |
435 | DefaultPrompt = defaultPrompt; | 58 | DefaultPrompt = defaultPrompt; |
436 | |||
437 | Commands.AddCommand("console", false, "help", "help [<command>]", | ||
438 | "Get general command list or more detailed help on a specific command", Help); | ||
439 | } | ||
440 | |||
441 | public void SetGuiMode(bool mode) | ||
442 | { | ||
443 | gui = mode; | ||
444 | } | ||
445 | |||
446 | private void AddToHistory(string text) | ||
447 | { | ||
448 | while (history.Count >= 100) | ||
449 | history.RemoveAt(0); | ||
450 | |||
451 | history.Add(text); | ||
452 | } | 59 | } |
453 | 60 | ||
454 | /// <summary> | 61 | /// <summary> |
@@ -458,10 +65,9 @@ namespace OpenSim.Framework.Console | |||
458 | /// </summary> | 65 | /// </summary> |
459 | /// <param name="input">arbitrary string for input</param> | 66 | /// <param name="input">arbitrary string for input</param> |
460 | /// <returns>an ansii color</returns> | 67 | /// <returns>an ansii color</returns> |
461 | private static ConsoleColor DeriveColor(string input) | 68 | protected virtual ConsoleColor DeriveColor(string input) |
462 | { | 69 | { |
463 | int colIdx = (input.ToUpper().GetHashCode() % 6) + 9; | 70 | return ConsoleColor.White; |
464 | return (ConsoleColor) colIdx; | ||
465 | } | 71 | } |
466 | 72 | ||
467 | /// <summary> | 73 | /// <summary> |
@@ -559,280 +165,58 @@ namespace OpenSim.Framework.Console | |||
559 | WriteNewLine(DeriveColor(sender), sender, ConsoleColor.Gray, format, args); | 165 | WriteNewLine(DeriveColor(sender), sender, ConsoleColor.Gray, format, args); |
560 | } | 166 | } |
561 | 167 | ||
562 | private int SetCursorTop(int top) | 168 | protected virtual void WriteNewLine(ConsoleColor senderColor, string sender, ConsoleColor color, string format, params object[] args) |
563 | { | 169 | { |
564 | if (top >= 0 && top < System.Console.BufferHeight) | 170 | WritePrefixLine(senderColor, sender); |
565 | { | 171 | WriteConsoleLine(color, format, args); |
566 | System.Console.CursorTop = top; | ||
567 | return top; | ||
568 | } | ||
569 | else | ||
570 | { | ||
571 | return System.Console.CursorTop; | ||
572 | } | ||
573 | } | 172 | } |
574 | 173 | ||
575 | private int SetCursorLeft(int left) | 174 | protected virtual void WriteNewLine(ConsoleColor color, string format, params object[] args) |
576 | { | 175 | { |
577 | if (left >= 0 && left < System.Console.BufferWidth) | 176 | WriteConsoleLine(color, format, args); |
578 | { | ||
579 | System.Console.CursorLeft = left; | ||
580 | return left; | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | return System.Console.CursorLeft; | ||
585 | } | ||
586 | } | 177 | } |
587 | 178 | ||
588 | private void WriteNewLine(ConsoleColor senderColor, string sender, ConsoleColor color, string format, params object[] args) | 179 | protected virtual void WriteConsoleLine(ConsoleColor color, string format, params object[] args) |
589 | { | ||
590 | lock (cmdline) | ||
591 | { | ||
592 | if (y != -1) | ||
593 | { | ||
594 | y=SetCursorTop(y); | ||
595 | System.Console.CursorLeft = 0; | ||
596 | |||
597 | int count = cmdline.Length; | ||
598 | |||
599 | System.Console.Write(" "); | ||
600 | while (count-- > 0) | ||
601 | System.Console.Write(" "); | ||
602 | |||
603 | y=SetCursorTop(y); | ||
604 | System.Console.CursorLeft = 0; | ||
605 | } | ||
606 | WritePrefixLine(senderColor, sender); | ||
607 | WriteConsoleLine(color, format, args); | ||
608 | if (y != -1) | ||
609 | y = System.Console.CursorTop; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | private void WriteNewLine(ConsoleColor color, string format, params object[] args) | ||
614 | { | ||
615 | lock (cmdline) | ||
616 | { | ||
617 | if (y != -1) | ||
618 | { | ||
619 | y=SetCursorTop(y); | ||
620 | System.Console.CursorLeft = 0; | ||
621 | |||
622 | int count = cmdline.Length; | ||
623 | |||
624 | System.Console.Write(" "); | ||
625 | while (count-- > 0) | ||
626 | System.Console.Write(" "); | ||
627 | |||
628 | y=SetCursorTop(y); | ||
629 | System.Console.CursorLeft = 0; | ||
630 | } | ||
631 | WriteConsoleLine(color, format, args); | ||
632 | if (y != -1) | ||
633 | y = System.Console.CursorTop; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | private void WriteConsoleLine(ConsoleColor color, string format, params object[] args) | ||
638 | { | 180 | { |
639 | try | 181 | try |
640 | { | 182 | { |
641 | lock (m_syncRoot) | 183 | System.Console.WriteLine(format, args); |
642 | { | ||
643 | try | ||
644 | { | ||
645 | if (color != ConsoleColor.White) | ||
646 | System.Console.ForegroundColor = color; | ||
647 | |||
648 | System.Console.WriteLine(format, args); | ||
649 | System.Console.ResetColor(); | ||
650 | } | ||
651 | catch (ArgumentNullException) | ||
652 | { | ||
653 | // Some older systems dont support coloured text. | ||
654 | System.Console.WriteLine(format, args); | ||
655 | } | ||
656 | catch (FormatException) | ||
657 | { | ||
658 | System.Console.WriteLine(args); | ||
659 | } | ||
660 | } | ||
661 | } | 184 | } |
662 | catch (ObjectDisposedException) | 185 | catch (ObjectDisposedException) |
663 | { | 186 | { |
664 | } | 187 | } |
665 | } | 188 | } |
666 | 189 | ||
667 | private void WritePrefixLine(ConsoleColor color, string sender) | 190 | protected virtual void WritePrefixLine(ConsoleColor color, string sender) |
668 | { | 191 | { |
669 | try | 192 | try |
670 | { | 193 | { |
671 | lock (m_syncRoot) | 194 | sender = sender.ToUpper(); |
672 | { | ||
673 | sender = sender.ToUpper(); | ||
674 | 195 | ||
675 | System.Console.WriteLine("[" + sender + "] "); | 196 | System.Console.WriteLine("[" + sender + "] "); |
676 | 197 | ||
677 | System.Console.Write("["); | 198 | System.Console.Write("["); |
678 | 199 | ||
679 | try | 200 | System.Console.Write(sender); |
680 | { | ||
681 | System.Console.ForegroundColor = color; | ||
682 | System.Console.Write(sender); | ||
683 | System.Console.ResetColor(); | ||
684 | } | ||
685 | catch (ArgumentNullException) | ||
686 | { | ||
687 | // Some older systems dont support coloured text. | ||
688 | System.Console.WriteLine(sender); | ||
689 | } | ||
690 | 201 | ||
691 | System.Console.Write("] \t"); | 202 | System.Console.Write("] \t"); |
692 | } | ||
693 | } | 203 | } |
694 | catch (ObjectDisposedException) | 204 | catch (ObjectDisposedException) |
695 | { | 205 | { |
696 | } | 206 | } |
697 | } | 207 | } |
698 | 208 | ||
699 | private void Help(string module, string[] cmd) | 209 | public virtual void LockOutput() |
700 | { | ||
701 | List<string> help = Commands.GetHelp(cmd); | ||
702 | |||
703 | foreach (string s in help) | ||
704 | Output(s); | ||
705 | } | ||
706 | |||
707 | private void Show() | ||
708 | { | ||
709 | lock (cmdline) | ||
710 | { | ||
711 | if (y == -1 || System.Console.BufferWidth == 0) | ||
712 | return; | ||
713 | |||
714 | int xc = prompt.Length + cp; | ||
715 | int new_x = xc % System.Console.BufferWidth; | ||
716 | int new_y = y + xc / System.Console.BufferWidth; | ||
717 | int end_y = y + (cmdline.Length + prompt.Length) / System.Console.BufferWidth; | ||
718 | if (end_y / System.Console.BufferWidth >= h) | ||
719 | h++; | ||
720 | if (end_y >= System.Console.BufferHeight) // wrap | ||
721 | { | ||
722 | y--; | ||
723 | new_y--; | ||
724 | System.Console.CursorLeft = 0; | ||
725 | System.Console.CursorTop = System.Console.BufferHeight-1; | ||
726 | System.Console.WriteLine(" "); | ||
727 | } | ||
728 | |||
729 | y=SetCursorTop(y); | ||
730 | System.Console.CursorLeft = 0; | ||
731 | |||
732 | if (echo) | ||
733 | System.Console.Write("{0}{1}", prompt, cmdline); | ||
734 | else | ||
735 | System.Console.Write("{0}", prompt); | ||
736 | |||
737 | SetCursorLeft(new_x); | ||
738 | SetCursorTop(new_y); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | public void LockOutput() | ||
743 | { | ||
744 | Monitor.Enter(cmdline); | ||
745 | try | ||
746 | { | ||
747 | if (y != -1) | ||
748 | { | ||
749 | y = SetCursorTop(y); | ||
750 | System.Console.CursorLeft = 0; | ||
751 | |||
752 | int count = cmdline.Length + prompt.Length; | ||
753 | |||
754 | while (count-- > 0) | ||
755 | System.Console.Write(" "); | ||
756 | |||
757 | y = SetCursorTop(y); | ||
758 | System.Console.CursorLeft = 0; | ||
759 | |||
760 | } | ||
761 | } | ||
762 | catch (Exception) | ||
763 | { | ||
764 | } | ||
765 | } | ||
766 | |||
767 | public void UnlockOutput() | ||
768 | { | 210 | { |
769 | if (y != -1) | ||
770 | { | ||
771 | y = System.Console.CursorTop; | ||
772 | Show(); | ||
773 | } | ||
774 | Monitor.Exit(cmdline); | ||
775 | } | 211 | } |
776 | 212 | ||
777 | public void Output(string text) | 213 | public virtual void UnlockOutput() |
778 | { | 214 | { |
779 | lock (cmdline) | ||
780 | { | ||
781 | if (y == -1) | ||
782 | { | ||
783 | System.Console.WriteLine(text); | ||
784 | |||
785 | return; | ||
786 | } | ||
787 | |||
788 | y = SetCursorTop(y); | ||
789 | System.Console.CursorLeft = 0; | ||
790 | |||
791 | int count = cmdline.Length + prompt.Length; | ||
792 | |||
793 | while (count-- > 0) | ||
794 | System.Console.Write(" "); | ||
795 | |||
796 | y = SetCursorTop(y); | ||
797 | System.Console.CursorLeft = 0; | ||
798 | |||
799 | System.Console.WriteLine(text); | ||
800 | |||
801 | y = System.Console.CursorTop; | ||
802 | |||
803 | Show(); | ||
804 | } | ||
805 | } | ||
806 | |||
807 | private bool ContextHelp() | ||
808 | { | ||
809 | string[] words = Parser.Parse(cmdline.ToString()); | ||
810 | |||
811 | bool trailingSpace = cmdline.ToString().EndsWith(" "); | ||
812 | |||
813 | // Allow ? through while typing a URI | ||
814 | // | ||
815 | if (words.Length > 0 && words[words.Length-1].StartsWith("http") && !trailingSpace) | ||
816 | return false; | ||
817 | |||
818 | string[] opts = Commands.FindNextOption(words, trailingSpace); | ||
819 | |||
820 | if (opts[0].StartsWith("Command help:")) | ||
821 | Output(opts[0]); | ||
822 | else | ||
823 | Output(String.Format("Options: {0}", String.Join(" ", opts))); | ||
824 | |||
825 | return true; | ||
826 | } | 215 | } |
827 | 216 | ||
828 | public void Prompt() | 217 | public virtual void Output(string text) |
829 | { | 218 | { |
830 | string line = ReadLine(m_defaultPrompt, true, true); | 219 | System.Console.WriteLine(text); |
831 | |||
832 | if (line != String.Empty) | ||
833 | { | ||
834 | m_log.Info("Invalid command"); | ||
835 | } | ||
836 | } | 220 | } |
837 | 221 | ||
838 | public string CmdPrompt(string p) | 222 | public string CmdPrompt(string p) |
@@ -850,19 +234,23 @@ namespace OpenSim.Framework.Console | |||
850 | } | 234 | } |
851 | 235 | ||
852 | // Displays a command prompt and returns a default value, user may only enter 1 of 2 options | 236 | // Displays a command prompt and returns a default value, user may only enter 1 of 2 options |
853 | public string CmdPrompt(string prompt, string defaultresponse, string OptionA, string OptionB) | 237 | public string CmdPrompt(string prompt, string defaultresponse, List<string> options) |
854 | { | 238 | { |
855 | bool itisdone = false; | 239 | bool itisdone = false; |
240 | string optstr = String.Empty; | ||
241 | foreach (string s in options) | ||
242 | optstr += " " + s; | ||
243 | |||
856 | string temp = CmdPrompt(prompt, defaultresponse); | 244 | string temp = CmdPrompt(prompt, defaultresponse); |
857 | while (itisdone == false) | 245 | while (itisdone == false) |
858 | { | 246 | { |
859 | if ((temp == OptionA) || (temp == OptionB)) | 247 | if (options.Contains(temp)) |
860 | { | 248 | { |
861 | itisdone = true; | 249 | itisdone = true; |
862 | } | 250 | } |
863 | else | 251 | else |
864 | { | 252 | { |
865 | System.Console.WriteLine("Valid options are " + OptionA + " or " + OptionB); | 253 | System.Console.WriteLine("Valid options are" + optstr); |
866 | temp = CmdPrompt(prompt, defaultresponse); | 254 | temp = CmdPrompt(prompt, defaultresponse); |
867 | } | 255 | } |
868 | } | 256 | } |
@@ -876,167 +264,12 @@ namespace OpenSim.Framework.Console | |||
876 | return ReadLine(p, false, false); | 264 | return ReadLine(p, false, false); |
877 | } | 265 | } |
878 | 266 | ||
879 | public void RunCommand(string cmd) | 267 | public virtual string ReadLine(string p, bool isCommand, bool e) |
880 | { | ||
881 | string[] parts = Parser.Parse(cmd); | ||
882 | Commands.Resolve(parts); | ||
883 | } | ||
884 | |||
885 | public string ReadLine(string p, bool isCommand, bool e) | ||
886 | { | 268 | { |
887 | h = 1; | 269 | System.Console.Write("{0}", prompt); |
888 | cp = 0; | 270 | string cmdinput = System.Console.ReadLine(); |
889 | prompt = p; | ||
890 | echo = e; | ||
891 | int historyLine = history.Count; | ||
892 | 271 | ||
893 | if (gui) | 272 | return cmdinput; |
894 | { | ||
895 | System.Console.Write("{0}", prompt); | ||
896 | string cmdinput = System.Console.ReadLine(); | ||
897 | |||
898 | if (isCommand) | ||
899 | { | ||
900 | string[] cmd = Commands.Resolve(Parser.Parse(cmdinput)); | ||
901 | |||
902 | if (cmd.Length != 0) | ||
903 | { | ||
904 | int i; | ||
905 | |||
906 | for (i=0 ; i < cmd.Length ; i++) | ||
907 | { | ||
908 | if (cmd[i].Contains(" ")) | ||
909 | cmd[i] = "\"" + cmd[i] + "\""; | ||
910 | } | ||
911 | return String.Empty; | ||
912 | } | ||
913 | } | ||
914 | return cmdinput; | ||
915 | } | ||
916 | |||
917 | System.Console.CursorLeft = 0; // Needed for mono | ||
918 | System.Console.Write(" "); // Needed for mono | ||
919 | |||
920 | lock (cmdline) | ||
921 | { | ||
922 | y = System.Console.CursorTop; | ||
923 | cmdline.Remove(0, cmdline.Length); | ||
924 | } | ||
925 | |||
926 | while (true) | ||
927 | { | ||
928 | Show(); | ||
929 | |||
930 | ConsoleKeyInfo key = System.Console.ReadKey(true); | ||
931 | char c = key.KeyChar; | ||
932 | |||
933 | if (!Char.IsControl(c)) | ||
934 | { | ||
935 | if (cp >= 318) | ||
936 | continue; | ||
937 | |||
938 | if (c == '?' && isCommand) | ||
939 | { | ||
940 | if (ContextHelp()) | ||
941 | continue; | ||
942 | } | ||
943 | |||
944 | cmdline.Insert(cp, c); | ||
945 | cp++; | ||
946 | } | ||
947 | else | ||
948 | { | ||
949 | switch (key.Key) | ||
950 | { | ||
951 | case ConsoleKey.Backspace: | ||
952 | if (cp == 0) | ||
953 | break; | ||
954 | cmdline.Remove(cp-1, 1); | ||
955 | cp--; | ||
956 | |||
957 | System.Console.CursorLeft = 0; | ||
958 | y = SetCursorTop(y); | ||
959 | |||
960 | System.Console.Write("{0}{1} ", prompt, cmdline); | ||
961 | |||
962 | break; | ||
963 | case ConsoleKey.End: | ||
964 | cp = cmdline.Length; | ||
965 | break; | ||
966 | case ConsoleKey.Home: | ||
967 | cp = 0; | ||
968 | break; | ||
969 | case ConsoleKey.UpArrow: | ||
970 | if (historyLine < 1) | ||
971 | break; | ||
972 | historyLine--; | ||
973 | LockOutput(); | ||
974 | cmdline.Remove(0, cmdline.Length); | ||
975 | cmdline.Append(history[historyLine]); | ||
976 | cp = cmdline.Length; | ||
977 | UnlockOutput(); | ||
978 | break; | ||
979 | case ConsoleKey.DownArrow: | ||
980 | if (historyLine >= history.Count) | ||
981 | break; | ||
982 | historyLine++; | ||
983 | LockOutput(); | ||
984 | if (historyLine == history.Count) | ||
985 | { | ||
986 | cmdline.Remove(0, cmdline.Length); | ||
987 | } | ||
988 | else | ||
989 | { | ||
990 | cmdline.Remove(0, cmdline.Length); | ||
991 | cmdline.Append(history[historyLine]); | ||
992 | } | ||
993 | cp = cmdline.Length; | ||
994 | UnlockOutput(); | ||
995 | break; | ||
996 | case ConsoleKey.LeftArrow: | ||
997 | if (cp > 0) | ||
998 | cp--; | ||
999 | break; | ||
1000 | case ConsoleKey.RightArrow: | ||
1001 | if (cp < cmdline.Length) | ||
1002 | cp++; | ||
1003 | break; | ||
1004 | case ConsoleKey.Enter: | ||
1005 | System.Console.CursorLeft = 0; | ||
1006 | y = SetCursorTop(y); | ||
1007 | |||
1008 | System.Console.WriteLine("{0}{1}", prompt, cmdline); | ||
1009 | |||
1010 | lock (cmdline) | ||
1011 | { | ||
1012 | y = -1; | ||
1013 | } | ||
1014 | |||
1015 | if (isCommand) | ||
1016 | { | ||
1017 | string[] cmd = Commands.Resolve(Parser.Parse(cmdline.ToString())); | ||
1018 | |||
1019 | if (cmd.Length != 0) | ||
1020 | { | ||
1021 | int i; | ||
1022 | |||
1023 | for (i=0 ; i < cmd.Length ; i++) | ||
1024 | { | ||
1025 | if (cmd[i].Contains(" ")) | ||
1026 | cmd[i] = "\"" + cmd[i] + "\""; | ||
1027 | } | ||
1028 | AddToHistory(String.Join(" ", cmd)); | ||
1029 | return String.Empty; | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | AddToHistory(cmdline.ToString()); | ||
1034 | return cmdline.ToString(); | ||
1035 | default: | ||
1036 | break; | ||
1037 | } | ||
1038 | } | ||
1039 | } | ||
1040 | } | 273 | } |
1041 | } | 274 | } |
1042 | } | 275 | } |
diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs new file mode 100644 index 0000000..9dde969 --- /dev/null +++ b/OpenSim/Framework/Console/LocalConsole.cs | |||
@@ -0,0 +1,470 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using System.Threading; | ||
34 | using log4net; | ||
35 | |||
36 | namespace OpenSim.Framework.Console | ||
37 | { | ||
38 | // A console that uses cursor control and color | ||
39 | // | ||
40 | public class LocalConsole : CommandConsole | ||
41 | { | ||
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
43 | |||
44 | private readonly object m_syncRoot = new object(); | ||
45 | |||
46 | private int y = -1; | ||
47 | private int cp = 0; | ||
48 | private int h = 1; | ||
49 | private string prompt = "# "; | ||
50 | private StringBuilder cmdline = new StringBuilder(); | ||
51 | private bool echo = true; | ||
52 | private List<string> history = new List<string>(); | ||
53 | |||
54 | public LocalConsole(string defaultPrompt) : base(defaultPrompt) | ||
55 | { | ||
56 | } | ||
57 | |||
58 | private void AddToHistory(string text) | ||
59 | { | ||
60 | while (history.Count >= 100) | ||
61 | history.RemoveAt(0); | ||
62 | |||
63 | history.Add(text); | ||
64 | } | ||
65 | |||
66 | /// <summary> | ||
67 | /// derive an ansi color from a string, ignoring the darker colors. | ||
68 | /// This is used to help automatically bin component tags with colors | ||
69 | /// in various print functions. | ||
70 | /// </summary> | ||
71 | /// <param name="input">arbitrary string for input</param> | ||
72 | /// <returns>an ansii color</returns> | ||
73 | protected override ConsoleColor DeriveColor(string input) | ||
74 | { | ||
75 | int colIdx = (input.ToUpper().GetHashCode() % 6) + 9; | ||
76 | return (ConsoleColor) colIdx; | ||
77 | } | ||
78 | |||
79 | private int SetCursorTop(int top) | ||
80 | { | ||
81 | if (top >= 0 && top < System.Console.BufferHeight) | ||
82 | { | ||
83 | System.Console.CursorTop = top; | ||
84 | return top; | ||
85 | } | ||
86 | else | ||
87 | { | ||
88 | return System.Console.CursorTop; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | private int SetCursorLeft(int left) | ||
93 | { | ||
94 | if (left >= 0 && left < System.Console.BufferWidth) | ||
95 | { | ||
96 | System.Console.CursorLeft = left; | ||
97 | return left; | ||
98 | } | ||
99 | else | ||
100 | { | ||
101 | return System.Console.CursorLeft; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | protected override void WriteNewLine(ConsoleColor senderColor, string sender, ConsoleColor color, string format, params object[] args) | ||
106 | { | ||
107 | lock (cmdline) | ||
108 | { | ||
109 | if (y != -1) | ||
110 | { | ||
111 | y=SetCursorTop(y); | ||
112 | System.Console.CursorLeft = 0; | ||
113 | |||
114 | int count = cmdline.Length; | ||
115 | |||
116 | System.Console.Write(" "); | ||
117 | while (count-- > 0) | ||
118 | System.Console.Write(" "); | ||
119 | |||
120 | y=SetCursorTop(y); | ||
121 | System.Console.CursorLeft = 0; | ||
122 | } | ||
123 | WritePrefixLine(senderColor, sender); | ||
124 | WriteConsoleLine(color, format, args); | ||
125 | if (y != -1) | ||
126 | y = System.Console.CursorTop; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | protected override void WriteNewLine(ConsoleColor color, string format, params object[] args) | ||
131 | { | ||
132 | lock (cmdline) | ||
133 | { | ||
134 | if (y != -1) | ||
135 | { | ||
136 | y=SetCursorTop(y); | ||
137 | System.Console.CursorLeft = 0; | ||
138 | |||
139 | int count = cmdline.Length; | ||
140 | |||
141 | System.Console.Write(" "); | ||
142 | while (count-- > 0) | ||
143 | System.Console.Write(" "); | ||
144 | |||
145 | y=SetCursorTop(y); | ||
146 | System.Console.CursorLeft = 0; | ||
147 | } | ||
148 | WriteConsoleLine(color, format, args); | ||
149 | if (y != -1) | ||
150 | y = System.Console.CursorTop; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | protected override void WriteConsoleLine(ConsoleColor color, string format, params object[] args) | ||
155 | { | ||
156 | try | ||
157 | { | ||
158 | lock (m_syncRoot) | ||
159 | { | ||
160 | try | ||
161 | { | ||
162 | if (color != ConsoleColor.White) | ||
163 | System.Console.ForegroundColor = color; | ||
164 | |||
165 | System.Console.WriteLine(format, args); | ||
166 | System.Console.ResetColor(); | ||
167 | } | ||
168 | catch (ArgumentNullException) | ||
169 | { | ||
170 | // Some older systems dont support coloured text. | ||
171 | System.Console.WriteLine(format, args); | ||
172 | } | ||
173 | catch (FormatException) | ||
174 | { | ||
175 | System.Console.WriteLine(args); | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | catch (ObjectDisposedException) | ||
180 | { | ||
181 | } | ||
182 | } | ||
183 | |||
184 | protected override void WritePrefixLine(ConsoleColor color, string sender) | ||
185 | { | ||
186 | try | ||
187 | { | ||
188 | lock (m_syncRoot) | ||
189 | { | ||
190 | sender = sender.ToUpper(); | ||
191 | |||
192 | System.Console.WriteLine("[" + sender + "] "); | ||
193 | |||
194 | System.Console.Write("["); | ||
195 | |||
196 | try | ||
197 | { | ||
198 | System.Console.ForegroundColor = color; | ||
199 | System.Console.Write(sender); | ||
200 | System.Console.ResetColor(); | ||
201 | } | ||
202 | catch (ArgumentNullException) | ||
203 | { | ||
204 | // Some older systems dont support coloured text. | ||
205 | System.Console.WriteLine(sender); | ||
206 | } | ||
207 | |||
208 | System.Console.Write("] \t"); | ||
209 | } | ||
210 | } | ||
211 | catch (ObjectDisposedException) | ||
212 | { | ||
213 | } | ||
214 | } | ||
215 | |||
216 | private void Show() | ||
217 | { | ||
218 | lock (cmdline) | ||
219 | { | ||
220 | if (y == -1 || System.Console.BufferWidth == 0) | ||
221 | return; | ||
222 | |||
223 | int xc = prompt.Length + cp; | ||
224 | int new_x = xc % System.Console.BufferWidth; | ||
225 | int new_y = y + xc / System.Console.BufferWidth; | ||
226 | int end_y = y + (cmdline.Length + prompt.Length) / System.Console.BufferWidth; | ||
227 | if (end_y / System.Console.BufferWidth >= h) | ||
228 | h++; | ||
229 | if (end_y >= System.Console.BufferHeight) // wrap | ||
230 | { | ||
231 | y--; | ||
232 | new_y--; | ||
233 | System.Console.CursorLeft = 0; | ||
234 | System.Console.CursorTop = System.Console.BufferHeight-1; | ||
235 | System.Console.WriteLine(" "); | ||
236 | } | ||
237 | |||
238 | y=SetCursorTop(y); | ||
239 | System.Console.CursorLeft = 0; | ||
240 | |||
241 | if (echo) | ||
242 | System.Console.Write("{0}{1}", prompt, cmdline); | ||
243 | else | ||
244 | System.Console.Write("{0}", prompt); | ||
245 | |||
246 | SetCursorLeft(new_x); | ||
247 | SetCursorTop(new_y); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | public override void LockOutput() | ||
252 | { | ||
253 | Monitor.Enter(cmdline); | ||
254 | try | ||
255 | { | ||
256 | if (y != -1) | ||
257 | { | ||
258 | y = SetCursorTop(y); | ||
259 | System.Console.CursorLeft = 0; | ||
260 | |||
261 | int count = cmdline.Length + prompt.Length; | ||
262 | |||
263 | while (count-- > 0) | ||
264 | System.Console.Write(" "); | ||
265 | |||
266 | y = SetCursorTop(y); | ||
267 | System.Console.CursorLeft = 0; | ||
268 | |||
269 | } | ||
270 | } | ||
271 | catch (Exception) | ||
272 | { | ||
273 | } | ||
274 | } | ||
275 | |||
276 | public override void UnlockOutput() | ||
277 | { | ||
278 | if (y != -1) | ||
279 | { | ||
280 | y = System.Console.CursorTop; | ||
281 | Show(); | ||
282 | } | ||
283 | Monitor.Exit(cmdline); | ||
284 | } | ||
285 | |||
286 | public override void Output(string text) | ||
287 | { | ||
288 | lock (cmdline) | ||
289 | { | ||
290 | if (y == -1) | ||
291 | { | ||
292 | System.Console.WriteLine(text); | ||
293 | |||
294 | return; | ||
295 | } | ||
296 | |||
297 | y = SetCursorTop(y); | ||
298 | System.Console.CursorLeft = 0; | ||
299 | |||
300 | int count = cmdline.Length + prompt.Length; | ||
301 | |||
302 | while (count-- > 0) | ||
303 | System.Console.Write(" "); | ||
304 | |||
305 | y = SetCursorTop(y); | ||
306 | System.Console.CursorLeft = 0; | ||
307 | |||
308 | System.Console.WriteLine(text); | ||
309 | |||
310 | y = System.Console.CursorTop; | ||
311 | |||
312 | Show(); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | private bool ContextHelp() | ||
317 | { | ||
318 | string[] words = Parser.Parse(cmdline.ToString()); | ||
319 | |||
320 | bool trailingSpace = cmdline.ToString().EndsWith(" "); | ||
321 | |||
322 | // Allow ? through while typing a URI | ||
323 | // | ||
324 | if (words.Length > 0 && words[words.Length-1].StartsWith("http") && !trailingSpace) | ||
325 | return false; | ||
326 | |||
327 | string[] opts = Commands.FindNextOption(words, trailingSpace); | ||
328 | |||
329 | if (opts[0].StartsWith("Command help:")) | ||
330 | Output(opts[0]); | ||
331 | else | ||
332 | Output(String.Format("Options: {0}", String.Join(" ", opts))); | ||
333 | |||
334 | return true; | ||
335 | } | ||
336 | |||
337 | public override string ReadLine(string p, bool isCommand, bool e) | ||
338 | { | ||
339 | h = 1; | ||
340 | cp = 0; | ||
341 | prompt = p; | ||
342 | echo = e; | ||
343 | int historyLine = history.Count; | ||
344 | |||
345 | System.Console.CursorLeft = 0; // Needed for mono | ||
346 | System.Console.Write(" "); // Needed for mono | ||
347 | |||
348 | lock (cmdline) | ||
349 | { | ||
350 | y = System.Console.CursorTop; | ||
351 | cmdline.Remove(0, cmdline.Length); | ||
352 | } | ||
353 | |||
354 | while (true) | ||
355 | { | ||
356 | Show(); | ||
357 | |||
358 | ConsoleKeyInfo key = System.Console.ReadKey(true); | ||
359 | char c = key.KeyChar; | ||
360 | |||
361 | if (!Char.IsControl(c)) | ||
362 | { | ||
363 | if (cp >= 318) | ||
364 | continue; | ||
365 | |||
366 | if (c == '?' && isCommand) | ||
367 | { | ||
368 | if (ContextHelp()) | ||
369 | continue; | ||
370 | } | ||
371 | |||
372 | cmdline.Insert(cp, c); | ||
373 | cp++; | ||
374 | } | ||
375 | else | ||
376 | { | ||
377 | switch (key.Key) | ||
378 | { | ||
379 | case ConsoleKey.Backspace: | ||
380 | if (cp == 0) | ||
381 | break; | ||
382 | cmdline.Remove(cp-1, 1); | ||
383 | cp--; | ||
384 | |||
385 | System.Console.CursorLeft = 0; | ||
386 | y = SetCursorTop(y); | ||
387 | |||
388 | System.Console.Write("{0}{1} ", prompt, cmdline); | ||
389 | |||
390 | break; | ||
391 | case ConsoleKey.End: | ||
392 | cp = cmdline.Length; | ||
393 | break; | ||
394 | case ConsoleKey.Home: | ||
395 | cp = 0; | ||
396 | break; | ||
397 | case ConsoleKey.UpArrow: | ||
398 | if (historyLine < 1) | ||
399 | break; | ||
400 | historyLine--; | ||
401 | LockOutput(); | ||
402 | cmdline.Remove(0, cmdline.Length); | ||
403 | cmdline.Append(history[historyLine]); | ||
404 | cp = cmdline.Length; | ||
405 | UnlockOutput(); | ||
406 | break; | ||
407 | case ConsoleKey.DownArrow: | ||
408 | if (historyLine >= history.Count) | ||
409 | break; | ||
410 | historyLine++; | ||
411 | LockOutput(); | ||
412 | if (historyLine == history.Count) | ||
413 | { | ||
414 | cmdline.Remove(0, cmdline.Length); | ||
415 | } | ||
416 | else | ||
417 | { | ||
418 | cmdline.Remove(0, cmdline.Length); | ||
419 | cmdline.Append(history[historyLine]); | ||
420 | } | ||
421 | cp = cmdline.Length; | ||
422 | UnlockOutput(); | ||
423 | break; | ||
424 | case ConsoleKey.LeftArrow: | ||
425 | if (cp > 0) | ||
426 | cp--; | ||
427 | break; | ||
428 | case ConsoleKey.RightArrow: | ||
429 | if (cp < cmdline.Length) | ||
430 | cp++; | ||
431 | break; | ||
432 | case ConsoleKey.Enter: | ||
433 | System.Console.CursorLeft = 0; | ||
434 | y = SetCursorTop(y); | ||
435 | |||
436 | System.Console.WriteLine("{0}{1}", prompt, cmdline); | ||
437 | |||
438 | lock (cmdline) | ||
439 | { | ||
440 | y = -1; | ||
441 | } | ||
442 | |||
443 | if (isCommand) | ||
444 | { | ||
445 | string[] cmd = Commands.Resolve(Parser.Parse(cmdline.ToString())); | ||
446 | |||
447 | if (cmd.Length != 0) | ||
448 | { | ||
449 | int i; | ||
450 | |||
451 | for (i=0 ; i < cmd.Length ; i++) | ||
452 | { | ||
453 | if (cmd[i].Contains(" ")) | ||
454 | cmd[i] = "\"" + cmd[i] + "\""; | ||
455 | } | ||
456 | AddToHistory(String.Join(" ", cmd)); | ||
457 | return String.Empty; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | AddToHistory(cmdline.ToString()); | ||
462 | return cmdline.ToString(); | ||
463 | default: | ||
464 | break; | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | } | ||
469 | } | ||
470 | } | ||
diff --git a/OpenSim/Framework/Console/MainConsole.cs b/OpenSim/Framework/Console/MainConsole.cs index 15df699..b438089 100644 --- a/OpenSim/Framework/Console/MainConsole.cs +++ b/OpenSim/Framework/Console/MainConsole.cs | |||
@@ -29,9 +29,9 @@ namespace OpenSim.Framework.Console | |||
29 | { | 29 | { |
30 | public class MainConsole | 30 | public class MainConsole |
31 | { | 31 | { |
32 | private static ConsoleBase instance; | 32 | private static CommandConsole instance; |
33 | 33 | ||
34 | public static ConsoleBase Instance | 34 | public static CommandConsole Instance |
35 | { | 35 | { |
36 | get { return instance; } | 36 | get { return instance; } |
37 | set { instance = value; } | 37 | set { instance = value; } |