PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Rusty/Core/Loop.cs

http://github.com/polyethene/IronAHK
C# | 306 lines | 276 code | 11 blank | 19 comment | 6 complexity | 12c7ed1ba431c47f8860e9ee03d4c2ba MD5 | raw file
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Text;
  6. namespace IronAHK.Rusty
  7. {
  8. partial class Core
  9. {
  10. // TODO: organise Loops.cs
  11. static Stack<LoopInfo> loops = new Stack<LoopInfo>();
  12. enum LoopType
  13. {
  14. Normal,
  15. Registry,
  16. Directory,
  17. Parse,
  18. File,
  19. Each,
  20. }
  21. class LoopInfo
  22. {
  23. public int index = -1;
  24. public LoopType type = LoopType.Normal;
  25. public object result;
  26. }
  27. /// <summary>
  28. /// Perform a series of commands repeatedly: either the specified number of times or until break is encountered.
  29. /// </summary>
  30. /// <param name="n">How many times (iterations) to perform the loop.</param>
  31. /// <returns></returns>
  32. public static IEnumerable Loop(int n)
  33. {
  34. var info = new LoopInfo { type = LoopType.Normal };
  35. loops.Push(info);
  36. for (int i = 0; i < n;)
  37. {
  38. info.index = i;
  39. yield return ++i;
  40. }
  41. loops.Pop();
  42. }
  43. /// <summary>
  44. /// Retrieves substrings (fields) from a string, one at a time.
  45. /// </summary>
  46. /// <param name="input">The string to parse.</param>
  47. /// <param name="delimiters">One of the following:
  48. /// <list>
  49. /// <item>the word <code>CSV</code> to parse in comma seperated value format;</item>
  50. /// <item>a sequence of characters to treat as delimiters;</item>
  51. /// <item>blank to parse each character of the string.</item>
  52. /// </list>
  53. /// </param>
  54. /// <param name="omit">An optional list of characters (case sensitive) to exclude from the beginning and end of each substring.</param>
  55. /// <returns></returns>
  56. public static IEnumerable LoopParse(string input, string delimiters, string omit)
  57. {
  58. var info = new LoopInfo { type = LoopType.Parse };
  59. loops.Push(info);
  60. if (delimiters.ToLowerInvariant() == Keyword_CSV)
  61. {
  62. var reader = new StringReader(input);
  63. var part = new StringBuilder();
  64. bool str = false, next = false;
  65. while (true)
  66. {
  67. int current = reader.Read();
  68. if (current == -1)
  69. goto collect;
  70. const char tokenStr = '"', tokenDelim = ',';
  71. var sym = (char)current;
  72. switch (sym)
  73. {
  74. case tokenStr:
  75. if (str)
  76. {
  77. if ((char)reader.Peek() == tokenStr)
  78. {
  79. part.Append(tokenStr);
  80. reader.Read();
  81. }
  82. else
  83. str = false;
  84. }
  85. else
  86. {
  87. if (next)
  88. part.Append(tokenStr);
  89. else
  90. str = true;
  91. }
  92. break;
  93. case tokenDelim:
  94. if (str)
  95. goto default;
  96. goto collect; // sorry
  97. default:
  98. next = true;
  99. part.Append(sym);
  100. break;
  101. }
  102. continue;
  103. collect:
  104. next = false;
  105. string result = part.ToString();
  106. part.Length = 0;
  107. info.result = result;
  108. info.index++;
  109. yield return result;
  110. if (current == -1)
  111. break;
  112. }
  113. } else {
  114. string[] parts;
  115. var remove = omit.ToCharArray();
  116. if(string.IsNullOrEmpty(delimiters)) {
  117. var chars = input.ToCharArray();
  118. parts = new string[chars.Length];
  119. for(int i=0; i < chars.Length; i++)
  120. parts[i] = chars[i].ToString();
  121. }else
  122. parts = input.Split(delimiters.ToCharArray(), StringSplitOptions.None);
  123. foreach (var part in parts)
  124. {
  125. var result = part.Trim(remove);
  126. if(string.IsNullOrEmpty(result))
  127. continue;
  128. info.result = result;
  129. info.index++;
  130. yield return result;
  131. }
  132. }
  133. loops.Pop();
  134. }
  135. /// <summary>
  136. /// Retrieves the lines in a text file, one at a time.
  137. /// </summary>
  138. /// <param name="input">The name of the text file whose contents will be read by the loop.</param>
  139. /// <param name="output">The optional name of the file to be kept open for the duration of the loop.</param>
  140. /// <returns></returns>
  141. public static IEnumerable LoopRead(string input, string output)
  142. {
  143. if (!File.Exists(input))
  144. yield break;
  145. StreamWriter writer = null;
  146. if (output == "*")
  147. {
  148. writer = new StreamWriter(Console.OpenStandardOutput());
  149. }
  150. else if (!string.IsNullOrEmpty(output))
  151. {
  152. bool binary = output[0] == '*';
  153. if (binary)
  154. output = output.Substring(1);
  155. if (output.Length == 0 || !File.Exists(output))
  156. yield break;
  157. writer = new StreamWriter(File.OpenWrite(output));
  158. if (binary)
  159. writer.NewLine = "\n";
  160. }
  161. var info = new LoopInfo { type = LoopType.File };
  162. loops.Push(info);
  163. var reader = File.OpenText(input);
  164. string line;
  165. while ((line = reader.ReadLine()) != null)
  166. {
  167. if (writer != null)
  168. writer.WriteLine(line);
  169. info.result = line;
  170. info.index++;
  171. yield return line;
  172. }
  173. loops.Pop();
  174. }
  175. /// <summary>
  176. /// Retrieves the specified files or folders, one at a time.
  177. /// </summary>
  178. /// <param name="pattern">The name of a single file or folder, or a wildcard pattern.</param>
  179. /// <param name="folders">One of the following digits, or blank to use the default:
  180. /// <list>
  181. /// <item><code>1</code> (default) folders are not retrieved (only files);</item>
  182. /// <item><code>1</code> all files and folders that match the wildcard pattern are retrieved;</item>
  183. /// <item><code>2</code> only folders are retrieved (no files).</item>
  184. /// </list>
  185. /// </param>
  186. /// <param name="recurse"><code>1</code> to recurse into subfolders, <code>0</code> otherwise.</param>
  187. /// <returns></returns>
  188. public static IEnumerable LoopFile(string pattern, int folders, bool recurse)
  189. {
  190. var info = new LoopInfo { type = LoopType.Directory };
  191. loops.Push(info);
  192. string[] list = Directory.GetFiles(pattern, string.Empty, recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
  193. foreach (var file in list)
  194. {
  195. info.result = file;
  196. info.index++;
  197. yield return file;
  198. }
  199. loops.Pop();
  200. }
  201. /// <summary>
  202. /// Retrieves the contents of the specified registry subkey, one item at a time.
  203. /// </summary>
  204. /// <param name="root">Must be either HKEY_LOCAL_MACHINE (or HKLM), HKEY_USERS (or HKU), HKEY_CURRENT_USER (or HKCU), HKEY_CLASSES_ROOT (or HKCR), or HKEY_CURRENT_CONFIG (or HKCC).</param>
  205. /// <param name="key">The name of the key (e.g. Software\SomeApplication). If blank or omitted, the contents of RootKey will be retrieved.</param>
  206. /// <param name="subkeys">
  207. /// <list>
  208. /// <item><code>1</code> subkeys contained within Key are not retrieved (only the values);</item>
  209. /// <item><code>1</code> all values and subkeys are retrieved;</item>
  210. /// <item><code>2</code> only the subkeys are retrieved (not the values).</item>
  211. /// </list>
  212. /// </param>
  213. /// <param name="recurse"><code>1</code> to recurse into subkeys, <code>0</code> otherwise.</param>
  214. /// <returns></returns>
  215. public static IEnumerable LoopRegistry(string root, string key, int subkeys, bool recurse)
  216. {
  217. var info = new LoopInfo { type = LoopType.Registry };
  218. loops.Push(info);
  219. loops.Pop();
  220. yield break;
  221. // TODO: registry loop
  222. }
  223. /// <summary>
  224. /// Retrieves each element of an array with its key if any.
  225. /// </summary>
  226. /// <param name="array">An array or object.</param>
  227. /// <returns>The current element.</returns>
  228. public static IEnumerable LoopEach(object array)
  229. {
  230. if (array == null)
  231. yield break;
  232. var info = new LoopInfo { type = LoopType.Each };
  233. loops.Push(info);
  234. var type = array.GetType();
  235. if (typeof(IDictionary).IsAssignableFrom(type))
  236. {
  237. var dictionary = (IDictionary)array;
  238. foreach (var key in dictionary.Keys)
  239. {
  240. info.result = new[] { key, dictionary[key] };
  241. info.index++;
  242. yield return info.result;
  243. }
  244. }
  245. else if (typeof(IEnumerable).IsAssignableFrom(type))
  246. {
  247. var enumerator = ((IEnumerable)array).GetEnumerator();
  248. while (enumerator.MoveNext())
  249. {
  250. info.result = new[] { null, enumerator.Current };
  251. info.index++;
  252. yield return info.result;
  253. }
  254. }
  255. loops.Pop();
  256. }
  257. }
  258. }