Browse Source

Moved glob code into the corlib.

svn path=/trunk/mcs/; revision=3128
Dan Lewis 24 years ago
parent
commit
73010d4dcd

+ 5 - 0
mcs/class/corlib/System.IO/ChangeLog

@@ -1,3 +1,8 @@
+2002-03-15  Dan Lewis <[email protected]>
+
+	* SearchPattern.cs: New class. Glob matching code for Directory.
+	* Directory.cs: Changed to use SearchPattern instead of mono_glob_*()
+
 2002/03/15 Nick Drochak <[email protected]>
 
 	* DirectoryInfo.cs: Fixed the overloaded GetDirectories and GetFiles.

+ 5 - 7
mcs/class/corlib/System.IO/Directory.cs

@@ -162,7 +162,7 @@ namespace System.IO
 		internal static ArrayList GetListing (string path, string pattern)
 		{
 			IntPtr dir_handle;
-			IntPtr glob_handle = (IntPtr) 0;
+			SearchPattern search_pattern;
 			ArrayList list;
 			string name, subdir = "";
 			int slashpos;
@@ -177,7 +177,7 @@ namespace System.IO
 				path = "";
 
 			if (pattern == "*")
-				pattern = null;
+				search_pattern = null;
 			else {
 				// do we need to handle globbing in directory names, too?
 				if ((slashpos = pattern.LastIndexOf (Path.DirectorySeparatorStr)) >= 0) {
@@ -185,7 +185,7 @@ namespace System.IO
 					path += subdir;
 					pattern = pattern.Substring (slashpos + 1);
 				}
-				glob_handle = Wrapper.mono_glob_compile (pattern);
+				search_pattern = new SearchPattern (pattern);
 			}
 			
 			dir_handle = Wrapper.opendir (path);
@@ -193,16 +193,14 @@ namespace System.IO
 				return null;
 			list = new ArrayList ();
 			while ((name = Wrapper.readdir (dir_handle)) != null){
-				if (pattern == null){
+				if (search_pattern == null){
 					list.Add (name);
 					continue;
 				}
 
-				if (Wrapper.mono_glob_match (glob_handle, name) != 0)
+				if (search_pattern.IsMatch (name))
 					list.Add (subdir + name);
 			}
-			if (pattern != null)
-				Wrapper.mono_glob_dispose (glob_handle);
 			Wrapper.closedir (dir_handle);
 
 			return list;

+ 169 - 0
mcs/class/corlib/System.IO/SearchPattern.cs

@@ -0,0 +1,169 @@
+//
+// System.IO.SearchPattern.cs: Filename glob support.
+//
+// Author:
+//   Dan Lewis ([email protected])
+//
+// (C) 2002
+//
+
+using System;
+
+namespace System.IO {
+
+	// FIXME: there's a complication with this algorithm under windows.
+	// the pattern '*.*' matches all files (i think . matches the extension),
+	// whereas under UNIX it should only match files containing the '.' character.
+
+	class SearchPattern {
+		public SearchPattern (string pattern) : this (pattern, false) { }
+
+		public SearchPattern (string pattern, bool ignore)
+		{
+			this.ignore = ignore;
+			Compile (pattern);
+		}
+
+		public bool IsMatch (string text)
+		{
+			return Match (ops, text, 0);
+		}
+
+		// private
+
+		private Op ops;		// the compiled pattern
+		private bool ignore;	// ignore case
+
+		private void Compile (string pattern)
+		{
+			if (pattern == null || pattern.IndexOfAny (InvalidChars) >= 0)
+				throw new ArgumentException ("Invalid search pattern.");
+
+			if (pattern == "*") {	// common case
+				ops = new Op (OpCode.True);
+				return;
+			}
+
+			ops = null;
+
+			int ptr = 0;
+			Op last_op = null;
+			while (ptr < pattern.Length) {
+				Op op;
+			
+				switch (pattern [ptr]) {
+				case '?':
+					op = new Op (OpCode.AnyChar);
+					++ ptr;
+					break;
+
+				case '*':
+					op = new Op (OpCode.AnyString);
+					++ ptr;
+					break;
+					
+				default:
+					op = new Op (OpCode.ExactString);
+					int end = pattern.IndexOfAny (WildcardChars, ptr);
+					if (end < 0)
+						end = pattern.Length;
+
+					op.Argument = pattern.Substring (ptr, end - ptr);
+					if (ignore)
+						op.Argument = op.Argument.ToLower ();
+
+					ptr = end;
+					break;
+				}
+
+				if (last_op == null)
+					ops = op;
+				else
+					last_op.Next = op;
+
+				last_op = op;
+			}
+
+			if (last_op == null)
+				ops = new Op (OpCode.End);
+			else
+				last_op.Next = new Op (OpCode.End);
+		}
+
+		private bool Match (Op op, string text, int ptr)
+		{
+			while (op != null) {
+				switch (op.Code) {
+				case OpCode.True:
+					return true;
+
+				case OpCode.End:
+					if (ptr == text.Length)
+						return true;
+
+					return false;
+				
+				case OpCode.ExactString:
+					int length = op.Argument.Length;
+					if (ptr + length > text.Length)
+						return false;
+
+					string str = text.Substring (ptr, length);
+					if (ignore)
+						str = str.ToLower ();
+
+					if (str != op.Argument)
+						return false;
+
+					ptr += length;
+					break;
+
+				case OpCode.AnyChar:
+					if (++ ptr > text.Length)
+						return false;
+					break;
+
+				case OpCode.AnyString:
+					while (ptr <= text.Length) {
+						if (Match (op.Next, text, ptr))
+							return true;
+
+						++ ptr;
+					}
+
+					return false;
+				}
+
+				op = op.Next;
+			}
+
+			return true;
+		}
+
+		// private static
+
+		private static readonly char [] WildcardChars = { '*', '?' };
+		private static readonly char [] InvalidChars = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
+
+		private class Op {
+			public Op (OpCode code)
+			{
+				this.Code = code;
+				this.Argument = null;
+				this.Next = null;
+			}
+		
+			public OpCode Code;
+			public string Argument;
+			public Op Next;
+		}
+
+		private enum OpCode {
+			ExactString,		// literal
+			AnyChar,		// ?
+			AnyString,		// *
+			End,			// end of pattern
+			True			// always succeeds
+		};
+	}
+}

+ 0 - 10
mcs/class/corlib/Unix/Wrapper.cs

@@ -233,15 +233,5 @@ public class Wrapper {
 
 	[DllImport("monowrapper", EntryPoint="mono_wrapper_utime", CharSet=CharSet.Ansi)]
 	public unsafe static extern int utime (string path, int atime, int mtime);
-
-	[DllImport("monowrapper", EntryPoint="mono_glob_compile", CharSet=CharSet.Ansi)]
-	public unsafe static extern IntPtr mono_glob_compile (string glob);
-
-	[DllImport("monowrapper", EntryPoint="mono_glob_match", CharSet=CharSet.Ansi)]
-	public unsafe static extern int mono_glob_match (IntPtr handle, string str);
-
-	[DllImport("monowrapper", EntryPoint="mono_glob_dispose", CharSet=CharSet.Ansi)]
-	public unsafe static extern void mono_glob_dispose (IntPtr handle);
-
 }
 }