diff options
author | Melanie Thielker | 2009-02-07 12:25:39 +0000 |
---|---|---|
committer | Melanie Thielker | 2009-02-07 12:25:39 +0000 |
commit | 54c6a920baa0ef02a9ea09e08cc1effcef3b0a3a (patch) | |
tree | f606cbdbc383ec21fee28f0a1454140a1c714278 /OpenSim/Framework | |
parent | Thank you dslake for a patch that: (diff) | |
download | opensim-SC-54c6a920baa0ef02a9ea09e08cc1effcef3b0a3a.zip opensim-SC-54c6a920baa0ef02a9ea09e08cc1effcef3b0a3a.tar.gz opensim-SC-54c6a920baa0ef02a9ea09e08cc1effcef3b0a3a.tar.bz2 opensim-SC-54c6a920baa0ef02a9ea09e08cc1effcef3b0a3a.tar.xz |
Replace the console for all OpenSim apps with a new console featuring command
line editing, context sensitive help (press ? at any time), command line
history, a new plugin command system and new appender features thet let you
type while the console is scrolling. Seamlessly integrates the ICommander
interfaces.
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/Console/ConsoleBase.cs | 661 | ||||
-rw-r--r-- | OpenSim/Framework/Console/ConsoleCallbacksBase.cs | 35 | ||||
-rw-r--r-- | OpenSim/Framework/Console/OpenSimAppender.cs | 16 | ||||
-rw-r--r-- | OpenSim/Framework/IScene.cs | 3 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/BaseOpenSimServer.cs | 119 |
5 files changed, 588 insertions, 246 deletions
diff --git a/OpenSim/Framework/Console/ConsoleBase.cs b/OpenSim/Framework/Console/ConsoleBase.cs index 30af23a..f990748 100644 --- a/OpenSim/Framework/Console/ConsoleBase.cs +++ b/OpenSim/Framework/Console/ConsoleBase.cs | |||
@@ -26,22 +26,250 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Text; |
30 | using System.Diagnostics; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | 30 | using System.Reflection; |
33 | using System.Text.RegularExpressions; | 31 | using System.Diagnostics; |
32 | using System.Collections.Generic; | ||
34 | using log4net; | 33 | using log4net; |
35 | 34 | ||
36 | namespace OpenSim.Framework.Console | 35 | namespace OpenSim.Framework.Console |
37 | { | 36 | { |
37 | public delegate void CommandDelegate(string module, string[] cmd); | ||
38 | |||
39 | public class Commands | ||
40 | { | ||
41 | private class CommandInfo | ||
42 | { | ||
43 | public string module; | ||
44 | public string help_text; | ||
45 | public string long_help; | ||
46 | public CommandDelegate fn; | ||
47 | } | ||
48 | |||
49 | private Dictionary<string, Object> tree = | ||
50 | new Dictionary<string, Object>(); | ||
51 | |||
52 | public List<string> GetHelp() | ||
53 | { | ||
54 | List<string> help = new List<string>(); | ||
55 | |||
56 | help.AddRange(CollectHelp(tree)); | ||
57 | |||
58 | help.Sort(); | ||
59 | |||
60 | return help; | ||
61 | } | ||
62 | |||
63 | private List<string> CollectHelp(Dictionary<string, Object> dict) | ||
64 | { | ||
65 | List<string> result = new List<string>(); | ||
66 | |||
67 | foreach (KeyValuePair<string, object> kvp in dict) | ||
68 | { | ||
69 | if (kvp.Value is Dictionary<string, Object>) | ||
70 | { | ||
71 | result.AddRange(CollectHelp((Dictionary<string, Object>)kvp.Value)); | ||
72 | } | ||
73 | else | ||
74 | { | ||
75 | if (((CommandInfo)kvp.Value).long_help != String.Empty) | ||
76 | result.Add(((CommandInfo)kvp.Value).help_text+" - "+ | ||
77 | ((CommandInfo)kvp.Value).long_help); | ||
78 | } | ||
79 | } | ||
80 | return result; | ||
81 | } | ||
82 | |||
83 | public void AddCommand(string module, string command, string help, string longhelp, CommandDelegate fn) | ||
84 | { | ||
85 | string[] parts = Parser.Parse(command); | ||
86 | |||
87 | Dictionary<string, Object> current = tree; | ||
88 | foreach (string s in parts) | ||
89 | { | ||
90 | if (current.ContainsKey(s)) | ||
91 | { | ||
92 | if (current[s] is Dictionary<string, Object>) | ||
93 | { | ||
94 | current = (Dictionary<string, Object>)current[s]; | ||
95 | } | ||
96 | else | ||
97 | return; | ||
98 | } | ||
99 | else | ||
100 | { | ||
101 | current[s] = new Dictionary<string, Object>(); | ||
102 | current = (Dictionary<string, Object>)current[s]; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | if (current.ContainsKey(String.Empty)) | ||
107 | return; | ||
108 | CommandInfo info = new CommandInfo(); | ||
109 | info.module = module; | ||
110 | info.help_text = help; | ||
111 | info.long_help = longhelp; | ||
112 | info.fn = fn; | ||
113 | current[String.Empty] = info; | ||
114 | } | ||
115 | |||
116 | public string[] FindNextOption(string[] cmd, bool term) | ||
117 | { | ||
118 | Dictionary<string, object> current = tree; | ||
119 | |||
120 | int remaining = cmd.Length; | ||
121 | |||
122 | foreach (string s in cmd) | ||
123 | { | ||
124 | remaining--; | ||
125 | |||
126 | List<string> found = new List<string>(); | ||
127 | |||
128 | foreach (string opt in current.Keys) | ||
129 | { | ||
130 | if (opt.StartsWith(s)) | ||
131 | { | ||
132 | found.Add(opt); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | if (found.Count == 1 && (remaining != 0 || term)) | ||
137 | { | ||
138 | current = (Dictionary<string, object>)current[found[0]]; | ||
139 | } | ||
140 | else if (found.Count > 0) | ||
141 | { | ||
142 | return found.ToArray(); | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | break; | ||
147 | // return new string[] {"<cr>"}; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | if (current.Count > 1) | ||
152 | { | ||
153 | List<string> choices = new List<string>(); | ||
154 | |||
155 | bool addcr = false; | ||
156 | foreach (string s in current.Keys) | ||
157 | { | ||
158 | if (s == String.Empty) | ||
159 | { | ||
160 | CommandInfo ci = (CommandInfo)current[String.Empty]; | ||
161 | if (ci.fn != null) | ||
162 | addcr = true; | ||
163 | } | ||
164 | else | ||
165 | choices.Add(s); | ||
166 | } | ||
167 | if (addcr) | ||
168 | choices.Add("<cr>"); | ||
169 | return choices.ToArray(); | ||
170 | } | ||
171 | |||
172 | if (current.ContainsKey(String.Empty)) | ||
173 | return new string[] { "Command help: "+((CommandInfo)current[String.Empty]).help_text}; | ||
174 | |||
175 | return new string[] { new List<string>(current.Keys)[0] }; | ||
176 | } | ||
177 | |||
178 | public string[] Resolve(string[] cmd) | ||
179 | { | ||
180 | string[] result = cmd; | ||
181 | int index = -1; | ||
182 | |||
183 | Dictionary<string, object> current = tree; | ||
184 | |||
185 | foreach (string s in cmd) | ||
186 | { | ||
187 | index++; | ||
188 | |||
189 | List<string> found = new List<string>(); | ||
190 | |||
191 | foreach (string opt in current.Keys) | ||
192 | { | ||
193 | if (opt.StartsWith(s)) | ||
194 | { | ||
195 | found.Add(opt); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | if (found.Count == 1) | ||
200 | { | ||
201 | result[index] = found[0]; | ||
202 | current = (Dictionary<string, object>)current[found[0]]; | ||
203 | } | ||
204 | else if (found.Count > 0) | ||
205 | { | ||
206 | return new string[0]; | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | break; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | if (current.ContainsKey(String.Empty)) | ||
215 | { | ||
216 | CommandInfo ci = (CommandInfo)current[String.Empty]; | ||
217 | if (ci.fn == null) | ||
218 | return new string[0]; | ||
219 | ci.fn(ci.module, result); | ||
220 | return result; | ||
221 | } | ||
222 | return new string[0]; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | public class Parser | ||
227 | { | ||
228 | public static string[] Parse(string text) | ||
229 | { | ||
230 | List<string> result = new List<string>(); | ||
231 | |||
232 | int index; | ||
233 | |||
234 | string[] unquoted = text.Split(new char[] {'"'}); | ||
235 | |||
236 | for (index = 0 ; index < unquoted.Length ; index++) | ||
237 | { | ||
238 | if (index % 2 == 0) | ||
239 | { | ||
240 | string[] words = unquoted[index].Split(new char[] {' '}); | ||
241 | foreach (string w in words) | ||
242 | { | ||
243 | if (w != String.Empty) | ||
244 | result.Add(w); | ||
245 | } | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | result.Add(unquoted[index]); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | return result.ToArray(); | ||
254 | } | ||
255 | } | ||
256 | |||
38 | public class ConsoleBase | 257 | public class ConsoleBase |
39 | { | 258 | { |
40 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 259 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
41 | 260 | ||
42 | private readonly object m_syncRoot = new object(); | 261 | private readonly object m_syncRoot = new object(); |
43 | 262 | ||
44 | public conscmd_callback m_cmdParser; | 263 | private int y = -1; |
264 | private int cp = 0; | ||
265 | private int h = 1; | ||
266 | private string prompt = "# "; | ||
267 | private StringBuilder cmdline = new StringBuilder(); | ||
268 | public Commands Commands = new Commands(); | ||
269 | private bool echo = true; | ||
270 | private List<string> history = new List<string>(); | ||
271 | |||
272 | public object ConsoleScene = null; | ||
45 | 273 | ||
46 | /// <summary> | 274 | /// <summary> |
47 | /// The default prompt text. | 275 | /// The default prompt text. |
@@ -53,15 +281,19 @@ namespace OpenSim.Framework.Console | |||
53 | } | 281 | } |
54 | protected string m_defaultPrompt; | 282 | protected string m_defaultPrompt; |
55 | 283 | ||
56 | /// <summary> | 284 | public ConsoleBase(string defaultPrompt) |
57 | /// Constructor. | ||
58 | /// </summary> | ||
59 | /// <param name="defaultPrompt"></param> | ||
60 | /// <param name="cmdparser"></param> | ||
61 | public ConsoleBase(string defaultPrompt, conscmd_callback cmdparser) | ||
62 | { | 285 | { |
63 | DefaultPrompt = defaultPrompt; | 286 | DefaultPrompt = defaultPrompt; |
64 | m_cmdParser = cmdparser; | 287 | |
288 | Commands.AddCommand("console", "help", "help", "Get command list", Help); | ||
289 | } | ||
290 | |||
291 | private void AddToHistory(string text) | ||
292 | { | ||
293 | while (history.Count >= 100) | ||
294 | history.RemoveAt(0); | ||
295 | |||
296 | history.Add(text); | ||
65 | } | 297 | } |
66 | 298 | ||
67 | /// <summary> | 299 | /// <summary> |
@@ -95,8 +327,7 @@ namespace OpenSim.Framework.Console | |||
95 | /// <param name="args">WriteLine-style message arguments</param> | 327 | /// <param name="args">WriteLine-style message arguments</param> |
96 | public void Warn(string sender, string format, params object[] args) | 328 | public void Warn(string sender, string format, params object[] args) |
97 | { | 329 | { |
98 | WritePrefixLine(DeriveColor(sender), sender); | 330 | WriteNewLine(DeriveColor(sender), sender, ConsoleColor.Yellow, format, args); |
99 | WriteNewLine(ConsoleColor.Yellow, format, args); | ||
100 | } | 331 | } |
101 | 332 | ||
102 | /// <summary> | 333 | /// <summary> |
@@ -117,10 +348,8 @@ namespace OpenSim.Framework.Console | |||
117 | /// <param name="args">WriteLine-style message arguments</param> | 348 | /// <param name="args">WriteLine-style message arguments</param> |
118 | public void Notice(string sender, string format, params object[] args) | 349 | public void Notice(string sender, string format, params object[] args) |
119 | { | 350 | { |
120 | WritePrefixLine(DeriveColor(sender), sender); | 351 | WriteNewLine(DeriveColor(sender), sender, ConsoleColor.White, format, args); |
121 | WriteNewLine(ConsoleColor.White, format, args); | ||
122 | } | 352 | } |
123 | |||
124 | /// <summary> | 353 | /// <summary> |
125 | /// Sends an error to the current console output | 354 | /// Sends an error to the current console output |
126 | /// </summary> | 355 | /// </summary> |
@@ -139,8 +368,7 @@ namespace OpenSim.Framework.Console | |||
139 | /// <param name="args">WriteLine-style message arguments</param> | 368 | /// <param name="args">WriteLine-style message arguments</param> |
140 | public void Error(string sender, string format, params object[] args) | 369 | public void Error(string sender, string format, params object[] args) |
141 | { | 370 | { |
142 | WritePrefixLine(DeriveColor(sender), sender); | 371 | WriteNewLine(DeriveColor(sender), sender, ConsoleColor.Red, format, args); |
143 | Error(format, args); | ||
144 | } | 372 | } |
145 | 373 | ||
146 | /// <summary> | 374 | /// <summary> |
@@ -161,8 +389,7 @@ namespace OpenSim.Framework.Console | |||
161 | /// <param name="args">WriteLine-style message arguments</param> | 389 | /// <param name="args">WriteLine-style message arguments</param> |
162 | public void Status(string sender, string format, params object[] args) | 390 | public void Status(string sender, string format, params object[] args) |
163 | { | 391 | { |
164 | WritePrefixLine(DeriveColor(sender), sender); | 392 | WriteNewLine(DeriveColor(sender), sender, ConsoleColor.Blue, format, args); |
165 | WriteNewLine(ConsoleColor.Blue, format, args); | ||
166 | } | 393 | } |
167 | 394 | ||
168 | [Conditional("DEBUG")] | 395 | [Conditional("DEBUG")] |
@@ -174,12 +401,60 @@ namespace OpenSim.Framework.Console | |||
174 | [Conditional("DEBUG")] | 401 | [Conditional("DEBUG")] |
175 | public void Debug(string sender, string format, params object[] args) | 402 | public void Debug(string sender, string format, params object[] args) |
176 | { | 403 | { |
177 | WritePrefixLine(DeriveColor(sender), sender); | 404 | WriteNewLine(DeriveColor(sender), sender, ConsoleColor.Gray, format, args); |
178 | WriteNewLine(ConsoleColor.Gray, format, args); | 405 | } |
406 | |||
407 | private void WriteNewLine(ConsoleColor senderColor, string sender, ConsoleColor color, string format, params object[] args) | ||
408 | { | ||
409 | lock (cmdline) | ||
410 | { | ||
411 | if (y != -1) | ||
412 | { | ||
413 | System.Console.CursorTop = y; | ||
414 | System.Console.CursorLeft = 0; | ||
415 | |||
416 | int count = cmdline.Length; | ||
417 | |||
418 | System.Console.Write(" "); | ||
419 | while (count-- > 0) | ||
420 | System.Console.Write(" "); | ||
421 | |||
422 | System.Console.CursorTop = y; | ||
423 | System.Console.CursorLeft = 0; | ||
424 | } | ||
425 | WritePrefixLine(senderColor, sender); | ||
426 | WriteConsoleLine(color, format, args); | ||
427 | if (y != -1) | ||
428 | y = System.Console.CursorTop; | ||
429 | } | ||
179 | } | 430 | } |
180 | 431 | ||
181 | private void WriteNewLine(ConsoleColor color, string format, params object[] args) | 432 | private void WriteNewLine(ConsoleColor color, string format, params object[] args) |
182 | { | 433 | { |
434 | lock (cmdline) | ||
435 | { | ||
436 | if (y != -1) | ||
437 | { | ||
438 | System.Console.CursorTop = y; | ||
439 | System.Console.CursorLeft = 0; | ||
440 | |||
441 | int count = cmdline.Length; | ||
442 | |||
443 | System.Console.Write(" "); | ||
444 | while (count-- > 0) | ||
445 | System.Console.Write(" "); | ||
446 | |||
447 | System.Console.CursorTop = y; | ||
448 | System.Console.CursorLeft = 0; | ||
449 | } | ||
450 | WriteConsoleLine(color, format, args); | ||
451 | if (y != -1) | ||
452 | y = System.Console.CursorTop; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | private void WriteConsoleLine(ConsoleColor color, string format, params object[] args) | ||
457 | { | ||
183 | try | 458 | try |
184 | { | 459 | { |
185 | lock (m_syncRoot) | 460 | lock (m_syncRoot) |
@@ -240,108 +515,150 @@ namespace OpenSim.Framework.Console | |||
240 | } | 515 | } |
241 | } | 516 | } |
242 | 517 | ||
243 | public string ReadLine() | 518 | private void Help(string module, string[] cmd) |
244 | { | 519 | { |
245 | try | 520 | List<string> help = Commands.GetHelp(); |
246 | { | 521 | |
247 | string line = System.Console.ReadLine(); | 522 | foreach (string s in help) |
523 | Output(s); | ||
524 | } | ||
248 | 525 | ||
249 | while (line == null) | 526 | private void Show() |
527 | { | ||
528 | lock (cmdline) | ||
529 | { | ||
530 | if (y == -1 || System.Console.BufferWidth == 0) | ||
531 | return; | ||
532 | |||
533 | int xc = prompt.Length + cp; | ||
534 | int new_x = xc % System.Console.BufferWidth; | ||
535 | int new_y = y + xc / System.Console.BufferWidth; | ||
536 | int end_y = y + (cmdline.Length + prompt.Length) / System.Console.BufferWidth; | ||
537 | if (end_y / System.Console.BufferWidth >= h) | ||
538 | h++; | ||
539 | if (end_y >= System.Console.BufferHeight) // wrap | ||
250 | { | 540 | { |
251 | line = System.Console.ReadLine(); | 541 | y--; |
542 | new_y--; | ||
543 | System.Console.CursorLeft = 0; | ||
544 | System.Console.CursorTop = System.Console.BufferHeight-1; | ||
545 | System.Console.WriteLine(" "); | ||
252 | } | 546 | } |
253 | 547 | ||
254 | return line; | 548 | System.Console.CursorTop = y; |
255 | } | 549 | System.Console.CursorLeft = 0; |
256 | catch (Exception e) | ||
257 | { | ||
258 | m_log.Error("[Console]: System.Console.ReadLine exception " + e.ToString()); | ||
259 | return String.Empty; | ||
260 | } | ||
261 | } | ||
262 | 550 | ||
263 | public int Read() | 551 | if (echo) |
264 | { | 552 | System.Console.Write("{0}{1}", prompt, cmdline); |
265 | return System.Console.Read(); | 553 | else |
554 | System.Console.Write("{0}", prompt); | ||
555 | |||
556 | System.Console.CursorLeft = new_x; | ||
557 | System.Console.CursorTop = new_y; | ||
558 | } | ||
266 | } | 559 | } |
267 | 560 | ||
268 | public IPAddress CmdPromptIPAddress(string prompt, string defaultvalue) | 561 | public void LockOutput() |
269 | { | 562 | { |
270 | IPAddress address; | 563 | System.Threading.Monitor.Enter(cmdline); |
271 | string addressStr; | 564 | try |
272 | |||
273 | while (true) | ||
274 | { | 565 | { |
275 | addressStr = CmdPrompt(prompt, defaultvalue); | 566 | if (y != -1) |
276 | if (IPAddress.TryParse(addressStr, out address)) | ||
277 | { | 567 | { |
278 | break; | 568 | System.Console.CursorTop = y; |
279 | } | 569 | System.Console.CursorLeft = 0; |
280 | else | 570 | |
281 | { | 571 | int count = cmdline.Length + prompt.Length; |
282 | m_log.Error("Illegal address. Please re-enter."); | 572 | |
573 | while (count-- > 0) | ||
574 | System.Console.Write(" "); | ||
575 | |||
576 | System.Console.CursorTop = y; | ||
577 | System.Console.CursorLeft = 0; | ||
578 | |||
283 | } | 579 | } |
284 | } | 580 | } |
285 | 581 | catch (Exception) | |
286 | return address; | 582 | { |
583 | } | ||
287 | } | 584 | } |
288 | 585 | ||
289 | public uint CmdPromptIPPort(string prompt, string defaultvalue) | 586 | public void UnlockOutput() |
290 | { | 587 | { |
291 | uint port; | 588 | if (y != -1) |
292 | string portStr; | 589 | { |
590 | y = System.Console.CursorTop; | ||
591 | Show(); | ||
592 | } | ||
593 | System.Threading.Monitor.Exit(cmdline); | ||
594 | } | ||
293 | 595 | ||
294 | while (true) | 596 | public void Output(string text) |
597 | { | ||
598 | lock (cmdline) | ||
295 | { | 599 | { |
296 | portStr = CmdPrompt(prompt, defaultvalue); | 600 | if (y == -1) |
297 | if (uint.TryParse(portStr, out port)) | ||
298 | { | 601 | { |
299 | if (port >= IPEndPoint.MinPort && port <= IPEndPoint.MaxPort) | 602 | System.Console.WriteLine(text); |
300 | { | 603 | |
301 | break; | 604 | return; |
302 | } | ||
303 | } | 605 | } |
304 | 606 | ||
305 | m_log.Error("Illegal address. Please re-enter."); | 607 | System.Console.CursorTop = y; |
306 | } | 608 | System.Console.CursorLeft = 0; |
307 | 609 | ||
308 | return port; | 610 | int count = cmdline.Length + prompt.Length; |
309 | } | ||
310 | 611 | ||
311 | // Displays a prompt and waits for the user to enter a string, then returns that string | 612 | while (count-- > 0) |
312 | // (Done with no echo and suitable for passwords - currently disabled) | 613 | System.Console.Write(" "); |
313 | public string PasswdPrompt(string prompt) | 614 | |
314 | { | 615 | System.Console.CursorTop = y; |
315 | // FIXME: Needs to be better abstracted | 616 | System.Console.CursorLeft = 0; |
316 | System.Console.WriteLine(String.Format("{0}: ", prompt)); | 617 | |
317 | //ConsoleColor oldfg = System.Console.ForegroundColor; | 618 | System.Console.WriteLine(text); |
318 | //System.Console.ForegroundColor = System.Console.BackgroundColor; | 619 | |
319 | string temp = System.Console.ReadLine(); | 620 | y = System.Console.CursorTop; |
320 | //System.Console.ForegroundColor = oldfg; | 621 | |
321 | return temp; | 622 | Show(); |
623 | } | ||
322 | } | 624 | } |
323 | 625 | ||
324 | // Displays a command prompt and waits for the user to enter a string, then returns that string | 626 | private void ContextHelp() |
325 | public string CmdPrompt(string prompt) | ||
326 | { | 627 | { |
327 | System.Console.WriteLine(String.Format("{0}: ", prompt)); | 628 | string[] words = Parser.Parse(cmdline.ToString()); |
328 | return ReadLine(); | 629 | |
630 | string[] opts = Commands.FindNextOption(words, cmdline.ToString().EndsWith(" ")); | ||
631 | |||
632 | if (opts[0].StartsWith("Command help:")) | ||
633 | Output(opts[0]); | ||
634 | else | ||
635 | Output(String.Format("Options: {0}", String.Join(" ", opts))); | ||
329 | } | 636 | } |
330 | 637 | ||
331 | // Displays a command prompt and returns a default value if the user simply presses enter | 638 | public void Prompt() |
332 | public string CmdPrompt(string prompt, string defaultresponse) | ||
333 | { | 639 | { |
334 | string temp = CmdPrompt(String.Format("{0} [{1}]", prompt, defaultresponse)); | 640 | string line = ReadLine(m_defaultPrompt, true, true); |
335 | if (temp == String.Empty) | 641 | |
336 | { | 642 | if (line != String.Empty) |
337 | return defaultresponse; | ||
338 | } | ||
339 | else | ||
340 | { | 643 | { |
341 | return temp; | 644 | m_log.Info("Invalid command"); |
342 | } | 645 | } |
343 | } | 646 | } |
344 | 647 | ||
648 | public string CmdPrompt(string p) | ||
649 | { | ||
650 | return ReadLine(String.Format("{0}: ", p), false, true); | ||
651 | } | ||
652 | |||
653 | public string CmdPrompt(string p, string def) | ||
654 | { | ||
655 | string ret = ReadLine(String.Format("{0} [{1}]: ", p, def), false, true); | ||
656 | if (ret == String.Empty) | ||
657 | ret = def; | ||
658 | |||
659 | return ret; | ||
660 | } | ||
661 | |||
345 | // Displays a command prompt and returns a default value, user may only enter 1 of 2 options | 662 | // Displays a command prompt and returns a default value, user may only enter 1 of 2 options |
346 | public string CmdPrompt(string prompt, string defaultresponse, string OptionA, string OptionB) | 663 | public string CmdPrompt(string prompt, string defaultresponse, string OptionA, string OptionB) |
347 | { | 664 | { |
@@ -362,85 +679,137 @@ namespace OpenSim.Framework.Console | |||
362 | return temp; | 679 | return temp; |
363 | } | 680 | } |
364 | 681 | ||
365 | // Runs a command with a number of parameters | 682 | // Displays a prompt and waits for the user to enter a string, then returns that string |
366 | public Object RunCmd(string Cmd, string[] cmdparams) | 683 | // (Done with no echo and suitable for passwords) |
367 | { | 684 | public string PasswdPrompt(string p) |
368 | m_cmdParser.RunCmd(Cmd, cmdparams); | ||
369 | return null; | ||
370 | } | ||
371 | |||
372 | // Shows data about something | ||
373 | public void ShowCommands(string ShowWhat) | ||
374 | { | 685 | { |
375 | m_cmdParser.Show(new string[] { ShowWhat }); | 686 | return ReadLine(p, false, false); |
376 | } | 687 | } |
377 | 688 | ||
378 | public void Prompt() | 689 | public void RunCommand(string cmd) |
379 | { | 690 | { |
380 | string tempstr = CmdPrompt(m_defaultPrompt); | 691 | string[] parts = Parser.Parse(cmd); |
381 | RunCommand(tempstr); | 692 | Commands.Resolve(parts); |
382 | } | 693 | } |
383 | 694 | ||
384 | public void RunCommand(string cmdline) | 695 | public string ReadLine(string p, bool isCommand, bool e) |
385 | { | 696 | { |
386 | Regex Extractor = new Regex(@"(['""][^""]+['""])\s*|([^\s]+)\s*", RegexOptions.Compiled); | 697 | h = 1; |
387 | char[] delims = {' ', '"'}; | 698 | cp = 0; |
388 | MatchCollection matches = Extractor.Matches(cmdline); | 699 | prompt = p; |
389 | // Get matches | 700 | echo = e; |
701 | int historyLine = history.Count; | ||
390 | 702 | ||
391 | if (matches.Count == 0) | 703 | System.Console.CursorLeft = 0; // Needed for mono |
392 | return; | 704 | System.Console.Write(" "); // Needed for mono |
393 | 705 | ||
394 | string cmd = matches[0].Value.Trim(delims); | 706 | y = System.Console.CursorTop; |
395 | string[] cmdparams = new string[matches.Count - 1]; | 707 | cmdline = new StringBuilder(); |
396 | 708 | ||
397 | for (int i = 1; i < matches.Count; i++) | 709 | while(true) |
398 | { | 710 | { |
399 | cmdparams[i-1] = matches[i].Value.Trim(delims); | 711 | Show(); |
400 | } | ||
401 | 712 | ||
402 | try | 713 | ConsoleKeyInfo key = System.Console.ReadKey(true); |
403 | { | 714 | char c = key.KeyChar; |
404 | RunCmd(cmd, cmdparams); | ||
405 | } | ||
406 | catch (Exception e) | ||
407 | { | ||
408 | m_log.ErrorFormat("[Console]: Command [{0}] failed with exception {1}", cmdline, e.ToString()); | ||
409 | m_log.Error(e.StackTrace); | ||
410 | } | ||
411 | } | ||
412 | 715 | ||
413 | public string LineInfo | 716 | if (!Char.IsControl(c)) |
414 | { | 717 | { |
415 | get | 718 | if (cp >= 318) |
416 | { | 719 | continue; |
417 | string result = String.Empty; | ||
418 | 720 | ||
419 | string stacktrace = Environment.StackTrace; | 721 | if (c == '?' && isCommand) |
420 | List<string> lines = new List<string>(stacktrace.Split(new string[] {"at "}, StringSplitOptions.None)); | 722 | { |
723 | ContextHelp(); | ||
724 | continue; | ||
725 | } | ||
421 | 726 | ||
422 | if (lines.Count > 4) | 727 | cmdline.Insert(cp, c); |
728 | cp++; | ||
729 | } | ||
730 | else | ||
423 | { | 731 | { |
424 | lines.RemoveRange(0, 4); | 732 | switch (key.Key) |
733 | { | ||
734 | case ConsoleKey.Backspace: | ||
735 | if (cp == 0) | ||
736 | break; | ||
737 | cmdline.Remove(cp-1, 1); | ||
738 | cp--; | ||
425 | 739 | ||
426 | string tmpLine = lines[0]; | 740 | System.Console.CursorLeft = 0; |
741 | System.Console.CursorTop = y; | ||
427 | 742 | ||
428 | int inIndex = tmpLine.IndexOf(" in "); | 743 | System.Console.Write("{0}{1} ", prompt, cmdline); |
429 | 744 | ||
430 | if (inIndex > -1) | 745 | break; |
431 | { | 746 | case ConsoleKey.End: |
432 | result = tmpLine.Substring(0, inIndex); | 747 | cp = cmdline.Length; |
748 | break; | ||
749 | case ConsoleKey.Home: | ||
750 | cp = 0; | ||
751 | break; | ||
752 | case ConsoleKey.UpArrow: | ||
753 | if (historyLine < 1) | ||
754 | break; | ||
755 | historyLine--; | ||
756 | LockOutput(); | ||
757 | cmdline = new StringBuilder(history[historyLine]); | ||
758 | cp = cmdline.Length; | ||
759 | UnlockOutput(); | ||
760 | break; | ||
761 | case ConsoleKey.DownArrow: | ||
762 | if (historyLine >= history.Count) | ||
763 | break; | ||
764 | historyLine++; | ||
765 | LockOutput(); | ||
766 | if (historyLine == history.Count) | ||
767 | cmdline = new StringBuilder(); | ||
768 | else | ||
769 | cmdline = new StringBuilder(history[historyLine]); | ||
770 | cp = cmdline.Length; | ||
771 | UnlockOutput(); | ||
772 | break; | ||
773 | case ConsoleKey.LeftArrow: | ||
774 | if (cp > 0) | ||
775 | cp--; | ||
776 | break; | ||
777 | case ConsoleKey.RightArrow: | ||
778 | if (cp < cmdline.Length) | ||
779 | cp++; | ||
780 | break; | ||
781 | case ConsoleKey.Enter: | ||
782 | System.Console.CursorLeft = 0; | ||
783 | System.Console.CursorTop = y; | ||
784 | |||
785 | System.Console.WriteLine("{0}{1}", prompt, cmdline); | ||
433 | 786 | ||
434 | int lineIndex = tmpLine.IndexOf(":line "); | 787 | y = -1; |
435 | 788 | ||
436 | if (lineIndex > -1) | 789 | if (isCommand) |
437 | { | 790 | { |
438 | lineIndex += 6; | 791 | string[] cmd = Commands.Resolve(Parser.Parse(cmdline.ToString())); |
439 | result += ", line " + tmpLine.Substring(lineIndex, (tmpLine.Length - lineIndex) - 5); | 792 | |
793 | if (cmd.Length != 0) | ||
794 | { | ||
795 | int i; | ||
796 | |||
797 | for (i=0 ; i < cmd.Length ; i++) | ||
798 | { | ||
799 | if (cmd[i].Contains(" ")) | ||
800 | cmd[i] = "\"" + cmd[i] + "\""; | ||
801 | } | ||
802 | AddToHistory(String.Join(" ", cmd)); | ||
803 | return String.Empty; | ||
804 | } | ||
440 | } | 805 | } |
806 | |||
807 | AddToHistory(cmdline.ToString()); | ||
808 | return cmdline.ToString(); | ||
809 | default: | ||
810 | break; | ||
441 | } | 811 | } |
442 | } | 812 | } |
443 | return result; | ||
444 | } | 813 | } |
445 | } | 814 | } |
446 | } | 815 | } |
diff --git a/OpenSim/Framework/Console/ConsoleCallbacksBase.cs b/OpenSim/Framework/Console/ConsoleCallbacksBase.cs deleted file mode 100644 index d37c47a..0000000 --- a/OpenSim/Framework/Console/ConsoleCallbacksBase.cs +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
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 | namespace OpenSim.Framework.Console | ||
29 | { | ||
30 | public interface conscmd_callback | ||
31 | { | ||
32 | void RunCmd(string cmd, string[] cmdparams); | ||
33 | void Show(string[] showParams); | ||
34 | } | ||
35 | } | ||
diff --git a/OpenSim/Framework/Console/OpenSimAppender.cs b/OpenSim/Framework/Console/OpenSimAppender.cs index b07617f..6193bac 100644 --- a/OpenSim/Framework/Console/OpenSimAppender.cs +++ b/OpenSim/Framework/Console/OpenSimAppender.cs | |||
@@ -37,6 +37,14 @@ namespace OpenSim.Framework.Console | |||
37 | /// </summary> | 37 | /// </summary> |
38 | public class OpenSimAppender : AnsiColorTerminalAppender | 38 | public class OpenSimAppender : AnsiColorTerminalAppender |
39 | { | 39 | { |
40 | private ConsoleBase m_console = null; | ||
41 | |||
42 | public ConsoleBase Console | ||
43 | { | ||
44 | get { return m_console; } | ||
45 | set { m_console = value; } | ||
46 | } | ||
47 | |||
40 | private static readonly ConsoleColor[] Colors = { | 48 | private static readonly ConsoleColor[] Colors = { |
41 | // the dark colors don't seem to be visible on some black background terminals like putty :( | 49 | // the dark colors don't seem to be visible on some black background terminals like putty :( |
42 | //ConsoleColor.DarkBlue, | 50 | //ConsoleColor.DarkBlue, |
@@ -55,6 +63,9 @@ namespace OpenSim.Framework.Console | |||
55 | 63 | ||
56 | override protected void Append(LoggingEvent le) | 64 | override protected void Append(LoggingEvent le) |
57 | { | 65 | { |
66 | if (m_console != null) | ||
67 | m_console.LockOutput(); | ||
68 | |||
58 | try | 69 | try |
59 | { | 70 | { |
60 | string loggingMessage = RenderLoggingEvent(le); | 71 | string loggingMessage = RenderLoggingEvent(le); |
@@ -96,6 +107,11 @@ namespace OpenSim.Framework.Console | |||
96 | { | 107 | { |
97 | System.Console.WriteLine("Couldn't write out log message: {0}", e.ToString()); | 108 | System.Console.WriteLine("Couldn't write out log message: {0}", e.ToString()); |
98 | } | 109 | } |
110 | finally | ||
111 | { | ||
112 | if (m_console != null) | ||
113 | m_console.UnlockOutput(); | ||
114 | } | ||
99 | } | 115 | } |
100 | 116 | ||
101 | private void WriteColorText(ConsoleColor color, string sender) | 117 | private void WriteColorText(ConsoleColor color, string sender) |
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index ce74b46..493c626 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using OpenMetaverse; | 29 | using OpenMetaverse; |
30 | using OpenSim.Framework.Console; | ||
30 | 31 | ||
31 | namespace OpenSim.Framework | 32 | namespace OpenSim.Framework |
32 | { | 33 | { |
@@ -88,5 +89,7 @@ namespace OpenSim.Framework | |||
88 | 89 | ||
89 | T RequestModuleInterface<T>(); | 90 | T RequestModuleInterface<T>(); |
90 | T[] RequestModuleInterfaces<T>(); | 91 | T[] RequestModuleInterfaces<T>(); |
92 | |||
93 | void AddCommand(string module, string command, string shorthelp, string longhelp, CommandDelegate callback); | ||
91 | } | 94 | } |
92 | } | 95 | } |
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 473991a..cc75df4 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs | |||
@@ -98,7 +98,45 @@ namespace OpenSim.Framework.Servers | |||
98 | /// <summary> | 98 | /// <summary> |
99 | /// Must be overriden by child classes for their own server specific startup behaviour. | 99 | /// Must be overriden by child classes for their own server specific startup behaviour. |
100 | /// </summary> | 100 | /// </summary> |
101 | protected abstract void StartupSpecific(); | 101 | protected virtual void StartupSpecific() |
102 | { | ||
103 | if (m_console != null) | ||
104 | { | ||
105 | SetConsoleLogLevel(new string[] { "ALL" }); | ||
106 | |||
107 | m_console.Commands.AddCommand("base", "quit", | ||
108 | "quit", | ||
109 | "Quit the application", HandleQuit); | ||
110 | |||
111 | m_console.Commands.AddCommand("base", "shutdown", | ||
112 | "shutdown", | ||
113 | "Quit the application", HandleQuit); | ||
114 | |||
115 | m_console.Commands.AddCommand("base", "set log level", | ||
116 | "set log level <level>", | ||
117 | "Set the console logging level", HandleLogLevel); | ||
118 | |||
119 | m_console.Commands.AddCommand("base", "show info", | ||
120 | "show info", | ||
121 | "Show general information", HandleShow); | ||
122 | |||
123 | m_console.Commands.AddCommand("base", "show stats", | ||
124 | "show stats", | ||
125 | "Show statistics", HandleShow); | ||
126 | |||
127 | m_console.Commands.AddCommand("base", "show threads", | ||
128 | "show threads", | ||
129 | "Show thread status", HandleShow); | ||
130 | |||
131 | m_console.Commands.AddCommand("base", "show uptime", | ||
132 | "show uptime", | ||
133 | "Show server uptime", HandleShow); | ||
134 | |||
135 | m_console.Commands.AddCommand("base", "show version", | ||
136 | "show version", | ||
137 | "Show server version", HandleShow); | ||
138 | } | ||
139 | } | ||
102 | 140 | ||
103 | /// <summary> | 141 | /// <summary> |
104 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing | 142 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing |
@@ -212,6 +250,8 @@ namespace OpenSim.Framework.Servers | |||
212 | return; | 250 | return; |
213 | } | 251 | } |
214 | 252 | ||
253 | consoleAppender.Console = m_console; | ||
254 | |||
215 | if (setParams.Length > 0) | 255 | if (setParams.Length > 0) |
216 | { | 256 | { |
217 | Level consoleLevel = repository.LevelMap[setParams[0]]; | 257 | Level consoleLevel = repository.LevelMap[setParams[0]]; |
@@ -261,56 +301,18 @@ namespace OpenSim.Framework.Servers | |||
261 | Environment.Exit(0); | 301 | Environment.Exit(0); |
262 | } | 302 | } |
263 | 303 | ||
264 | /// <summary> | 304 | private void HandleQuit(string module, string[] args) |
265 | /// Runs commands issued by the server console from the operator | ||
266 | /// </summary> | ||
267 | /// <param name="command">The first argument of the parameter (the command)</param> | ||
268 | /// <param name="cmdparams">Additional arguments passed to the command</param> | ||
269 | public virtual void RunCmd(string command, string[] cmdparams) | ||
270 | { | 305 | { |
271 | switch (command) | 306 | Shutdown(); |
272 | { | ||
273 | case "help": | ||
274 | ShowHelp(cmdparams); | ||
275 | Notice(""); | ||
276 | break; | ||
277 | |||
278 | case "set": | ||
279 | Set(cmdparams); | ||
280 | break; | ||
281 | |||
282 | case "show": | ||
283 | if (cmdparams.Length > 0) | ||
284 | { | ||
285 | Show(cmdparams); | ||
286 | } | ||
287 | break; | ||
288 | |||
289 | case "quit": | ||
290 | case "shutdown": | ||
291 | Shutdown(); | ||
292 | break; | ||
293 | } | ||
294 | } | 307 | } |
295 | 308 | ||
296 | /// <summary> | 309 | private void HandleLogLevel(string module, string[] cmd) |
297 | /// Set an OpenSim parameter | ||
298 | /// </summary> | ||
299 | /// <param name="setArgs"> | ||
300 | /// The arguments given to the set command. | ||
301 | /// </param> | ||
302 | public virtual void Set(string[] setArgs) | ||
303 | { | 310 | { |
304 | // Temporary while we only have one command which takes at least two parameters | 311 | if (cmd.Length > 3) |
305 | if (setArgs.Length < 2) | ||
306 | return; | ||
307 | |||
308 | if (setArgs[0] == "log" && setArgs[1] == "level") | ||
309 | { | 312 | { |
310 | string[] setParams = new string[setArgs.Length - 2]; | 313 | string level = cmd[3]; |
311 | Array.Copy(setArgs, 2, setParams, 0, setArgs.Length - 2); | ||
312 | 314 | ||
313 | SetConsoleLogLevel(setParams); | 315 | SetConsoleLogLevel(new string[] { level }); |
314 | } | 316 | } |
315 | } | 317 | } |
316 | 318 | ||
@@ -324,18 +326,6 @@ namespace OpenSim.Framework.Servers | |||
324 | 326 | ||
325 | if (helpArgs.Length == 0) | 327 | if (helpArgs.Length == 0) |
326 | { | 328 | { |
327 | List<string> helpTopics = GetHelpTopics(); | ||
328 | |||
329 | if (helpTopics.Count > 0) | ||
330 | { | ||
331 | Notice( | ||
332 | "As well as the help information below, you can also type help <topic> to get more information on the following areas:"); | ||
333 | Notice(string.Format(" {0}", string.Join(", ", helpTopics.ToArray()))); | ||
334 | Notice(""); | ||
335 | } | ||
336 | |||
337 | Notice("quit - equivalent to shutdown."); | ||
338 | |||
339 | Notice("set log level [level] - change the console logging level only. For example, off or debug."); | 329 | Notice("set log level [level] - change the console logging level only. For example, off or debug."); |
340 | Notice("show info - show server information (e.g. startup path)."); | 330 | Notice("show info - show server information (e.g. startup path)."); |
341 | 331 | ||
@@ -345,21 +335,20 @@ namespace OpenSim.Framework.Servers | |||
345 | Notice("show threads - list tracked threads"); | 335 | Notice("show threads - list tracked threads"); |
346 | Notice("show uptime - show server startup time and uptime."); | 336 | Notice("show uptime - show server startup time and uptime."); |
347 | Notice("show version - show server version."); | 337 | Notice("show version - show server version."); |
348 | Notice("shutdown - shutdown the server."); | ||
349 | Notice(""); | 338 | Notice(""); |
350 | 339 | ||
351 | return; | 340 | return; |
352 | } | 341 | } |
353 | } | 342 | } |
354 | 343 | ||
355 | /// <summary> | 344 | public virtual void HandleShow(string module, string[] cmd) |
356 | /// Outputs to the console information about the region | ||
357 | /// </summary> | ||
358 | /// <param name="showParams"> | ||
359 | /// What information to display (valid arguments are "uptime", "users", ...) | ||
360 | /// </param> | ||
361 | public virtual void Show(string[] showParams) | ||
362 | { | 345 | { |
346 | List<string> args = new List<string>(cmd); | ||
347 | |||
348 | args.RemoveAt(0); | ||
349 | |||
350 | string[] showParams = args.ToArray(); | ||
351 | |||
363 | switch (showParams[0]) | 352 | switch (showParams[0]) |
364 | { | 353 | { |
365 | case "info": | 354 | case "info": |