/// <summary> /// Browse a directory for file and subdirectory entries. /// </summary> /// <param name="path">path to directory, "" is root, separator is "/"</param> /// <param name="option">(optional) operation specific option; capability constraint, a session, security token or credential. Used for authenticating, authorizing or restricting the operation.</param> /// <returns>a snapshot of file and directory entries</returns> /// <exception cref="IOException">On unexpected IO error</exception> /// <exception cref="SecurityException">If caller did not have permission</exception> /// <exception cref="ArgumentNullException"><paramref name="path"/> is null</exception> /// <exception cref="ArgumentException"><paramref name="path"/> contains only white space, or contains one or more invalid characters</exception> /// <exception cref="NotSupportedException">The <see cref="IFileSystem"/> doesn't support browse</exception> /// <exception cref="UnauthorizedAccessException">The access requested is not permitted by the operating system for the specified path, such as when access is Write or ReadWrite and the file or directory is set for read-only access.</exception> /// <exception cref="PathTooLongException">The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters.</exception> /// <exception cref="InvalidOperationException">If <paramref name="path"/> refers to a non-file device, such as "con:", "com1:", "lpt1:", etc.</exception> /// <exception cref="ObjectDisposedException"/> public IDirectoryContent Browse(string path, IOption option = null) { // Assert supported if (!CanBrowse || !option.CanBrowse(true)) { throw new NotSupportedException(nameof(Browse)); } // Make path if (isPhysicalFileProvider && path.Contains(@"\")) { path = path.Replace(@"\", "/"); } // Is disposed? IFileProvider fp = fileProvider; if (fp == null) { throw new ObjectDisposedException(nameof(FileProviderSystem)); } // Browse IDirectoryContents contents = fp.GetDirectoryContents(path); // Not found if (!contents.Exists) { return(new DirectoryNotFound(this, path)); } // Convert result StructList24 <IEntry> list = new StructList24 <IEntry>(); foreach (IFileInfo info in contents) { if (info.IsDirectory) { IEntry e = new DirectoryEntry(this, String.IsNullOrEmpty(path) ? info.Name + "/" : (path.EndsWith("/") ?path + info.Name + "/":path + "/" + info.Name + "/"), info.Name, info.LastModified, DateTimeOffset.MinValue, info.PhysicalPath); list.Add(e); } else { IEntry e = new FileEntry(this, String.IsNullOrEmpty(path) ? info.Name : (path.EndsWith("/") ? path + info.Name : path + "/" + info.Name), info.Name, info.LastModified, DateTimeOffset.MinValue, info.Length, info.PhysicalPath); list.Add(e); } } // Return contents return(new DirectoryContent(this, path, list.ToArray())); }
/// <summary> /// Create intersections of <paramref name="leftPattern"/> and <paramref name="rightPattern"/>. /// </summary> /// <param name="leftPattern"></param> /// <param name="rightPattern"></param> /// <returns>intersections</returns> public static IEnumerable <String> Intersections(string leftPattern, string rightPattern) { // Read in the tokens StructList24 <Token> leftTokens = new StructList24 <Token>(), rightTokens = new StructList24 <Token>(); Token.Enumerator leftEnumerator = new Token.Enumerator(leftPattern), rightEnumerator = new Token.Enumerator(rightPattern); while (leftEnumerator.MoveNext()) { leftTokens.Add(leftEnumerator.Current); } while (rightEnumerator.MoveNext()) { rightTokens.Add(rightEnumerator.Current); } // Queue of scenarios as index pairs and result so far. List <Line> queue = new List <Line>(); // List of already yielded strings HashSet <Line> visited = new HashSet <Line>(); // Queue the starting position Queue(queue, visited, 0, 0, null); // Process queue while (queue.Count > 0) { // Take indices from queue Line line = queue[queue.Count - 1]; int li = line.li, ri = line.ri; List <Token> result = line.tokens; queue.RemoveAt(queue.Count - 1); // Has more tokens bool leftHasMore = li < leftTokens.Count, rightHasMore = ri < rightTokens.Count; // End of tokens on both streams if (!leftHasMore && !rightHasMore) { // Print to string string pattern = Print(result); // yield result yield return(pattern); } // left still has tokens, right is at end else if (leftHasMore && !rightHasMore) { // Take token Token l = leftTokens[li]; // "*" and "**" matches against "" if (l == Token.Type.Star || l == Token.Type.StarStar) { Queue(queue, visited, li + 1, ri, result); } } // left is at end, right still has tokens else if (!leftHasMore && rightHasMore) { // Take token and type Token r = rightTokens[ri]; // "" matches against "*" and "**" if (r == Token.Type.Star || r == Token.Type.StarStar) { Queue(queue, visited, li, ri + 1, result); } } // left and right have tokens if (leftHasMore && rightHasMore) { // Take tokens Token l = leftTokens[li], r = rightTokens[ri]; // l == ** if (l == Token.Type.StarStar) { // Match one and more later CloneAndAppend(queue, visited, li, ri + 1, result, r); // r = *, r = ** if (r == Token.Type.Star || r == Token.Type.StarStar) { // Append(queue, visited, li + 1, ri, result, r); } else // r = x { // Match to nothing Queue(queue, visited, li + 1, ri, result); } // Next scenario continue; } // r == ** if (r == Token.Type.StarStar) { // Match one and more later CloneAndAppend(queue, visited, li + 1, ri, result, l); // l = *, l = ** if (l == Token.Type.Star || l == Token.Type.StarStar) { // Append(queue, visited, li, ri + 1, result, l); } else { // Match to nothing Queue(queue, visited, li, ri + 1, result); } // Next scenario continue; } // l == * if (l == Token.Type.Star) { // * & / if (r == Token.Type.Slash) { // Match / to nothing Queue(queue, visited, li + 1, ri, result); continue; } // Match to one and more later CloneAndAppend(queue, visited, li, ri + 1, result, r); // Match to r = * if (r == Token.Type.Star) { Append(queue, visited, li + 1, ri, result, r); } else { // Match to nothing Queue(queue, visited, li + 1, ri, result); } // Next scenario continue; } // r == * if (r == Token.Type.Star) { // / & * if (l == Token.Type.Slash) { // Match / to nothing Queue(queue, visited, li, ri + 1, result); continue; } // Match one, and more later CloneAndAppend(queue, visited, li + 1, ri, result, l); if (l == Token.Type.Star) { Append(queue, visited, li, ri + 1, result, l); } else { // Match to nothing Queue(queue, visited, li, ri + 1, result); } // Next scenario continue; } // l == ? if (l == Token.Type.QuestionMark) { // ? & / if (r == Token.Type.Slash) { continue; } // Downgrade '*' and '**' to '?' if (r.Kind == Token.Type.Star || r.Kind == Token.Type.StarStar) { r = Token.Type.QuestionMark; } // Append what ever is in right token Append(queue, visited, li + 1, ri + 1, result, r); // Next scenario continue; } // r == ? if (r == Token.Type.QuestionMark) { // / & ? if (l == Token.Type.Slash) { continue; } // Downgrade '*' and '**' to '?' if (l.Kind == Token.Type.Star || l.Kind == Token.Type.StarStar) { l = Token.Type.QuestionMark; } // Append what ever is in left token Append(queue, visited, li + 1, ri + 1, result, l); // Next scenario continue; } // l == r if (l == r) { // Append, move indices and queue. Append(queue, visited, li + 1, ri + 1, result, l); // Next scenario continue; } } } //Console.Write($" (visited={visited.Count}) "); }
/// <summary> /// Create union of <paramref name="leftPattern"/> and <paramref name="rightPattern"/>. /// </summary> /// <param name="leftPattern"></param> /// <param name="rightPattern"></param> /// <returns>union that contains <paramref name="leftPattern"/> and <paramref name="rightPattern"/>. May return broader union that minimal due to lack of expression capability to hold in a single pattern string.</returns> public static string Union(string leftPattern, string rightPattern) { // Same pattern if (leftPattern == rightPattern) { return(leftPattern); } // Read in the tokens StructList24 <Token> leftTokens = new StructList24 <Token>(), rightTokens = new StructList24 <Token>(); Token.Enumerator leftEnumerator = new Token.Enumerator(leftPattern), rightEnumerator = new Token.Enumerator(rightPattern); while (leftEnumerator.MoveNext()) { leftTokens.Add(leftEnumerator.Current); } while (rightEnumerator.MoveNext()) { rightTokens.Add(rightEnumerator.Current); } // Queue of scenarios as index pairs and result so far. List <Line> queue = new List <Line>(); // List of already yielded strings HashSet <Line> visited = new HashSet <Line>(); // Queue the starting position Queue(queue, visited, 0, 0, null); // Final result List <Token> finalresult = null; int finalscore = int.MinValue; // Process queue while (queue.Count > 0) { // Take indices from queue Line line = queue[queue.Count - 1]; int li = line.li, ri = line.ri; List <Token> result = line.tokens; queue.RemoveAt(queue.Count - 1); // Has more tokens bool leftHasMore = li < leftTokens.Count, rightHasMore = ri < rightTokens.Count; // l = Left input, r = right input, _ = last in result Token l = leftHasMore ? leftTokens[li] : (Token)Token.Type.None, r = rightHasMore ? rightTokens[ri] : (Token)Token.Type.None, _ = result == null || result.Count == 0 ? (Token)Token.Type.None : result[result.Count - 1]; // End of tokens on both streams if (!leftHasMore && !rightHasMore) { int score = Score(result); if (score > finalscore) { finalresult = result; finalscore = score; } continue; } // left or right have tokens if (leftHasMore || rightHasMore) { // l == ** if (l == Token.Type.StarStar) { if (_ == Token.Type.StarStar) { Queue(queue, visited, li + 1, ri, result); } else { Append(queue, visited, li + 1, ri, result, l); } continue; } // r == ** if (r == Token.Type.StarStar) { if (_ == Token.Type.StarStar) { Queue(queue, visited, li, ri + 1, result); } else { Append(queue, visited, li, ri + 1, result, r); } continue; } // l == * if (l == Token.Type.Star) { if (_ == Token.Type.Star || _ == Token.Type.StarStar) { Queue(queue, visited, li + 1, ri, result); } else { Append(queue, visited, li + 1, ri, result, l); } continue; } // r == * if (r == Token.Type.Star) { if (_ == Token.Type.Star || _ == Token.Type.StarStar) { Queue(queue, visited, li, ri + 1, result); } else { Append(queue, visited, li, ri + 1, result, r); } continue; } // l == r if (l == r) { Append(queue, visited, li + 1, ri + 1, result, l); continue; } // l == ? && r == c if (l == Token.Type.QuestionMark && r.Kind == Token.Type.Char) { Append(queue, visited, li + 1, ri + 1, result, l); continue; } // l == c && r == ? if (l.Kind == Token.Type.Char && r == Token.Type.QuestionMark) { Append(queue, visited, li + 1, ri + 1, result, l); continue; } // l == c || r == c if (l.Kind == Token.Type.Char || r.Kind == Token.Type.Char) { // Add ? if (l.Kind == Token.Type.Char && r.Kind == Token.Type.Char) { CloneAndAppend(queue, visited, li + 1, ri + 1, result, Token.Type.QuestionMark); } // Add * if (_ != Token.Type.Star && _ != Token.Type.StarStar) { if (l.Kind == Token.Type.Char) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.Star); } if (r.Kind == Token.Type.Char) { Append(queue, visited, li, ri + 1, result, Token.Type.Star); } } else // Use previous * { if (l.Kind == Token.Type.Char) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.None); } if (r.Kind == Token.Type.Char) { Queue(queue, visited, li, ri + 1, result); } } continue; } { // Replace * with ** if (_ == Token.Type.Star) { result[result.Count - 1] = Token.Type.StarStar; if (l != Token.Type.None) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.None); } if (r != Token.Type.None) { Queue(queue, visited, li, ri + 1, result); } } // Add ** else if (_ != Token.Type.StarStar) { if (l != Token.Type.None) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.StarStar); } if (r != Token.Type.None) { Append(queue, visited, li, ri + 1, result, Token.Type.StarStar); } } else // Use previous ** { if (l != Token.Type.None) { CloneAndAppend(queue, visited, li + 1, ri, result, Token.Type.None); } if (r != Token.Type.None) { Queue(queue, visited, li, ri + 1, result); } } } } } //Console.Write($" (visited={visited.Count}) "); return(Print(finalresult)); // Heuristic score int Score(List <Token> result) { if (result == null) { return(int.MinValue); } int x = 0; foreach (Token t in result) { if (t.Kind == Token.Type.Char) { x += 256; } else if (t.Kind == Token.Type.QuestionMark) { x += 16; } else if (t.Kind == Token.Type.Slash) { x += 1024; } else if (t.Kind == Token.Type.Star) { x -= 4; } else if (t.Kind == Token.Type.StarStar) { x -= 16; } } return(x); } }