ConsoleUtil.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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 OpenSimulator 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. using System;
  28. using System.Collections.Generic;
  29. using System.IO;
  30. using System.Linq;
  31. using System.Reflection;
  32. using log4net;
  33. using OpenMetaverse;
  34. namespace OpenSim.Framework.Console
  35. {
  36. public class ConsoleUtil
  37. {
  38. // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  39. public const int LocalIdNotFound = 0;
  40. /// <summary>
  41. /// Used by modules to display stock co-ordinate help, though possibly this should be under some general section
  42. /// rather than in each help summary.
  43. /// </summary>
  44. public const string CoordHelp
  45. = @"Each component of the coord is comma separated. There must be no spaces between the commas.
  46. If you don't care about the z component you can simply omit it.
  47. If you don't care about the x or y components then you can leave them blank (though a comma is still required)
  48. If you want to specify the maximum value of a component then you can use ~ instead of a number
  49. If you want to specify the minimum value of a component then you can use -~ instead of a number
  50. e.g.
  51. show object pos 20,20,20 to 40,40,40
  52. delete object pos 20,20 to 40,40
  53. show object pos ,20,20 to ,40,40
  54. delete object pos ,,30 to ,,~
  55. show object pos ,,-~ to ,,30";
  56. public const string MinRawConsoleVectorValue = "-~";
  57. public const string MaxRawConsoleVectorValue = "~";
  58. public const string VectorSeparator = ",";
  59. public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray();
  60. /// <summary>
  61. /// Check if the given file path exists.
  62. /// </summary>
  63. /// <remarks>If not, warning is printed to the given console.</remarks>
  64. /// <returns>true if the file does not exist, false otherwise.</returns>
  65. /// <param name='console'></param>
  66. /// <param name='path'></param>
  67. public static bool CheckFileDoesNotExist(ICommandConsole console, string path)
  68. {
  69. if (File.Exists(path))
  70. {
  71. console.Output("File {0} already exists. Please move or remove it.", path);
  72. return false;
  73. }
  74. return true;
  75. }
  76. /// <summary>
  77. /// Try to parse a console UUID from the console.
  78. /// </summary>
  79. /// <remarks>
  80. /// Will complain to the console if parsing fails.
  81. /// </remarks>
  82. /// <returns></returns>
  83. /// <param name='console'>If null then no complaint is printed.</param>
  84. /// <param name='rawUuid'></param>
  85. /// <param name='uuid'></param>
  86. public static bool TryParseConsoleUuid(ICommandConsole console, string rawUuid, out UUID uuid)
  87. {
  88. if (!UUID.TryParse(rawUuid, out uuid))
  89. {
  90. if (console != null)
  91. console.Output("ERROR: {0} is not a valid uuid", rawUuid);
  92. return false;
  93. }
  94. return true;
  95. }
  96. public static bool TryParseConsoleLocalId(ICommandConsole console, string rawLocalId, out uint localId)
  97. {
  98. if (!uint.TryParse(rawLocalId, out localId))
  99. {
  100. if (console != null)
  101. console.Output("ERROR: {0} is not a valid local id", localId);
  102. return false;
  103. }
  104. if (localId == 0)
  105. {
  106. if (console != null)
  107. console.Output("ERROR: {0} is not a valid local id - it must be greater than 0", localId);
  108. return false;
  109. }
  110. return true;
  111. }
  112. /// <summary>
  113. /// Tries to parse the input as either a UUID or a local ID.
  114. /// </summary>
  115. /// <returns>true if parsing succeeded, false otherwise.</returns>
  116. /// <param name='console'></param>
  117. /// <param name='rawId'></param>
  118. /// <param name='uuid'></param>
  119. /// <param name='localId'>
  120. /// Will be set to ConsoleUtil.LocalIdNotFound if parsing result was a UUID or no parse succeeded.
  121. /// </param>
  122. public static bool TryParseConsoleId(ICommandConsole console, string rawId, out UUID uuid, out uint localId)
  123. {
  124. if (TryParseConsoleUuid(null, rawId, out uuid))
  125. {
  126. localId = LocalIdNotFound;
  127. return true;
  128. }
  129. if (TryParseConsoleLocalId(null, rawId, out localId))
  130. {
  131. return true;
  132. }
  133. if (console != null)
  134. console.Output("ERROR: {0} is not a valid UUID or local id", rawId);
  135. return false;
  136. }
  137. /// <summary>
  138. /// Convert a console input to a bool, automatically complaining if a console is given.
  139. /// </summary>
  140. /// <param name='console'>Can be null if no console is available.</param>
  141. /// <param name='rawConsoleVector'>/param>
  142. /// <param name='vector'></param>
  143. /// <returns></returns>
  144. public static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b)
  145. {
  146. if (!bool.TryParse(rawConsoleString, out b))
  147. {
  148. if (console != null)
  149. console.Output("ERROR: {0} is not a true or false value", rawConsoleString);
  150. return false;
  151. }
  152. return true;
  153. }
  154. /// <summary>
  155. /// Convert a console input to an int, automatically complaining if a console is given.
  156. /// </summary>
  157. /// <param name='console'>Can be null if no console is available.</param>
  158. /// <param name='rawConsoleInt'>/param>
  159. /// <param name='i'></param>
  160. /// <returns></returns>
  161. public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
  162. {
  163. if (!int.TryParse(rawConsoleInt, out i))
  164. {
  165. if (console != null)
  166. console.Output("ERROR: {0} is not a valid integer", rawConsoleInt);
  167. return false;
  168. }
  169. return true;
  170. }
  171. /// <summary>
  172. /// Convert a console input to a float, automatically complaining if a console is given.
  173. /// </summary>
  174. /// <param name='console'>Can be null if no console is available.</param>
  175. /// <param name='rawConsoleInput'>/param>
  176. /// <param name='i'></param>
  177. /// <returns></returns>
  178. public static bool TryParseConsoleFloat(ICommandConsole console, string rawConsoleInput, out float i)
  179. {
  180. if (!float.TryParse(rawConsoleInput, out i))
  181. {
  182. if (console != null)
  183. console.Output("ERROR: {0} is not a valid float", rawConsoleInput);
  184. return false;
  185. }
  186. return true;
  187. }
  188. /// <summary>
  189. /// Convert a console input to a double, automatically complaining if a console is given.
  190. /// </summary>
  191. /// <param name='console'>Can be null if no console is available.</param>
  192. /// <param name='rawConsoleInput'>/param>
  193. /// <param name='i'></param>
  194. /// <returns></returns>
  195. public static bool TryParseConsoleDouble(ICommandConsole console, string rawConsoleInput, out double i)
  196. {
  197. if (!double.TryParse(rawConsoleInput, out i))
  198. {
  199. if (console != null)
  200. console.Output("ERROR: {0} is not a valid double", rawConsoleInput);
  201. return false;
  202. }
  203. return true;
  204. }
  205. /// <summary>
  206. /// Convert a console integer to a natural int, automatically complaining if a console is given.
  207. /// </summary>
  208. /// <param name='console'>Can be null if no console is available.</param>
  209. /// <param name='rawConsoleInt'>/param>
  210. /// <param name='i'></param>
  211. /// <returns></returns>
  212. public static bool TryParseConsoleNaturalInt(ICommandConsole console, string rawConsoleInt, out int i)
  213. {
  214. if (TryParseConsoleInt(console, rawConsoleInt, out i))
  215. {
  216. if (i < 0)
  217. {
  218. if (console != null)
  219. console.Output("ERROR: {0} is not a positive integer", rawConsoleInt);
  220. return false;
  221. }
  222. return true;
  223. }
  224. return false;
  225. }
  226. /// <summary>
  227. /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
  228. /// </summary>
  229. /// <param name='rawConsoleVector'>/param>
  230. /// <param name='vector'></param>
  231. /// <returns></returns>
  232. public static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
  233. {
  234. return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector);
  235. }
  236. /// <summary>
  237. /// Convert a maximum vector input from the console to an OpenMetaverse.Vector3
  238. /// </summary>
  239. /// <param name='rawConsoleVector'>/param>
  240. /// <param name='vector'></param>
  241. /// <returns></returns>
  242. public static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
  243. {
  244. return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector);
  245. }
  246. /// <summary>
  247. /// Convert a vector input from the console to an OpenMetaverse.Vector3
  248. /// </summary>
  249. /// <param name='rawConsoleVector'>
  250. /// A string in the form <x>,<y>,<z> where there is no space between values.
  251. /// Any component can be missing (e.g. ,,40). blankComponentFunc is invoked to replace the blank with a suitable value
  252. /// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40,30 or 40)
  253. /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
  254. /// Other than that, component values must be numeric.
  255. /// </param>
  256. /// <param name='blankComponentFunc'>
  257. /// Behaviour if component is blank. If null then conversion fails on a blank component.
  258. /// </param>
  259. /// <param name='vector'></param>
  260. /// <returns></returns>
  261. public static bool TryParseConsoleVector(
  262. string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector)
  263. {
  264. return Vector3.TryParse(CookVector(rawConsoleVector, 3, blankComponentFunc), out vector);
  265. }
  266. /// <summary>
  267. /// Convert a vector input from the console to an OpenMetaverse.Vector2
  268. /// </summary>
  269. /// <param name='rawConsoleVector'>
  270. /// A string in the form <x>,<y> where there is no space between values.
  271. /// Any component can be missing (e.g. ,40). blankComponentFunc is invoked to replace the blank with a suitable value
  272. /// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40)
  273. /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
  274. /// Other than that, component values must be numeric.
  275. /// </param>
  276. /// <param name='blankComponentFunc'>
  277. /// Behaviour if component is blank. If null then conversion fails on a blank component.
  278. /// </param>
  279. /// <param name='vector'></param>
  280. /// <returns></returns>
  281. public static bool TryParseConsole2DVector(
  282. string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector2 vector)
  283. {
  284. // We don't use Vector2.TryParse() for now because for some reason it expects an input with 3 components
  285. // rather than 2.
  286. string cookedVector = CookVector(rawConsoleVector, 2, blankComponentFunc);
  287. if (cookedVector == null)
  288. {
  289. vector = Vector2.Zero;
  290. return false;
  291. }
  292. else
  293. {
  294. string[] cookedComponents = cookedVector.Split(VectorSeparatorChars);
  295. vector = new Vector2(float.Parse(cookedComponents[0]), float.Parse(cookedComponents[1]));
  296. return true;
  297. }
  298. //return Vector2.TryParse(CookVector(rawConsoleVector, 2, blankComponentFunc), out vector);
  299. }
  300. /// <summary>
  301. /// Convert a raw console vector into a vector that can be be parsed by the relevant OpenMetaverse.TryParse()
  302. /// </summary>
  303. /// <param name='rawConsoleVector'></param>
  304. /// <param name='dimensions'></param>
  305. /// <param name='blankComponentFunc'></param>
  306. /// <returns>null if conversion was not possible</returns>
  307. private static string CookVector(
  308. string rawConsoleVector, int dimensions, Func<string, string> blankComponentFunc)
  309. {
  310. List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
  311. if (components.Count < 1 || components.Count > dimensions)
  312. return null;
  313. if (components.Count < dimensions)
  314. {
  315. if (blankComponentFunc == null)
  316. return null;
  317. else
  318. for (int i = components.Count; i < dimensions; i++)
  319. components.Add("");
  320. }
  321. List<string> cookedComponents
  322. = components.ConvertAll<string>(
  323. c =>
  324. {
  325. if (c == "")
  326. return blankComponentFunc.Invoke(c);
  327. else if (c == MaxRawConsoleVectorValue)
  328. return float.MaxValue.ToString();
  329. else if (c == MinRawConsoleVectorValue)
  330. return float.MinValue.ToString();
  331. else
  332. return c;
  333. });
  334. return string.Join(VectorSeparator, cookedComponents.ToArray());
  335. }
  336. }
  337. }