From c5198ccb8083d2002a651104f5febbfc87ac6baf Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sat, 4 Jul 2015 18:43:32 +0200 Subject: [PATCH 01/16] File.Exists works (at least for root files) --- Users/Sentinel/SentinelKernel/Kernel.cs | 41 +++++---- .../FileSystem/FAT/FatFileSystem.cs | 5 ++ .../SentinelSystem/FileSystem/FileSystem.cs | 2 + .../FileSystem/VFS/VFSManager.cs | 29 +++--- .../SentinelSystem/SentinelSystem.csproj | 1 - Users/Sentinel/SentinelSystem/SentinelVFS.cs | 88 +++++++++++-------- .../SentinelSystem/System/IO/PathImpl.cs | 7 +- 7 files changed, 107 insertions(+), 66 deletions(-) diff --git a/Users/Sentinel/SentinelKernel/Kernel.cs b/Users/Sentinel/SentinelKernel/Kernel.cs index 9ad5faec5..7e8f84b46 100644 --- a/Users/Sentinel/SentinelKernel/Kernel.cs +++ b/Users/Sentinel/SentinelKernel/Kernel.cs @@ -26,32 +26,41 @@ namespace SentinelKernel var xRoot = Path.GetPathRoot(@"0:\test"); bool xTest = Directory.Exists("0:\\test"); Console.WriteLine("After test"); - if (xTest) - { - Console.WriteLine("Folder exists!"); - xTest = Directory.Exists("0:\\test\\DirInTest"); - if (xTest) - { - Console.WriteLine("Subfolder exists as well!"); - } - else - { - Console.WriteLine("Subfolder doesn't exist!"); - } - } - else + if (!xTest) { Console.WriteLine("Folder does not exist!"); + return; } + Console.WriteLine("Folder exists!"); + xTest = Directory.Exists("0:\\test\\DirInTest"); + if (!xTest) + { + Console.WriteLine("Subfolder doesn't exist!"); + return; + } + Console.WriteLine("Subfolder exists as well!"); + + xTest = File.Exists(@"0:\Kudzu.txt"); + if (!xTest) + { + Console.WriteLine(@"\Kudzu.txt not found!"); + return; + } + + Console.WriteLine("Kudzu.txt found!"); + } catch (Exception e) { Console.WriteLine("Exception occurred:"); Console.WriteLine(e.Message); } - - Stop(); + finally + { + while (true) + ; + } } } } diff --git a/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs b/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs index a237c4f33..65f1c5817 100644 --- a/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs +++ b/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs @@ -394,5 +394,10 @@ namespace SentinelKernel.System.FileSystem.FAT return GetDirectoryContents((FatDirectory)baseDirectory); } } + + public override Directory GetRootDirectory(string name) + { + return new FatDirectory(this, name, RootCluster); + } } } diff --git a/Users/Sentinel/SentinelSystem/FileSystem/FileSystem.cs b/Users/Sentinel/SentinelSystem/FileSystem/FileSystem.cs index 6a63bf5c5..833d1a6aa 100644 --- a/Users/Sentinel/SentinelSystem/FileSystem/FileSystem.cs +++ b/Users/Sentinel/SentinelSystem/FileSystem/FileSystem.cs @@ -41,5 +41,7 @@ namespace SentinelKernel.System.FileSystem } public abstract List GetDirectoryListing(Directory baseDirectory); + + public abstract Directory GetRootDirectory(string name); } } diff --git a/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs b/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs index 66086361e..ff3766125 100644 --- a/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs +++ b/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs @@ -141,29 +141,34 @@ namespace SentinelKernel.System.FileSystem.VFS throw new ArgumentNullException("aPath"); } - return null; - - /* string xFileName = Path.GetFileName(aPath); - string xDirectory = Path.GetDirectoryName(aPath) + Path.DirectorySeparatorChar; - - foreach (var xEntry in GetDirectoryListing(xDirectory)) + string xDirectory = Path.GetDirectoryName(aPath); + var xLastChar = xDirectory[xDirectory.Length - 1]; + if (xLastChar != Path.DirectorySeparatorChar) { - if ((xEntry is FileSystem.Listing.File) && (xEntry.Name == xFileName)) + xDirectory = xDirectory + Path.DirectorySeparatorChar; + } + + + var xList = GetDirectoryListing(xDirectory); + for (int i = 0; i < xList.Count; i++) + { + var xEntry = xList[i]; + var xFile = xEntry as Listing.File; + if (xFile != null && String.Equals(xEntry.Name, xFileName, StringComparison.OrdinalIgnoreCase)) { - return (xEntry as FileSystem.Listing.File); + return xFile; } } return null; - */ } public static List GetFiles(string aPath) { if (string.IsNullOrEmpty(aPath)) { - throw new ArgumentNullException("sPath"); + throw new ArgumentNullException("aPath"); } return null; @@ -274,8 +279,10 @@ namespace SentinelKernel.System.FileSystem.VFS { return (VFSManager.GetFile(aPath) != null); } - catch (Exception) + catch (Exception E) { + Console.Write("Exception occurred: "); + Console.WriteLine(E.Message); return false; } } diff --git a/Users/Sentinel/SentinelSystem/SentinelSystem.csproj b/Users/Sentinel/SentinelSystem/SentinelSystem.csproj index df7d45ba1..480378ba4 100644 --- a/Users/Sentinel/SentinelSystem/SentinelSystem.csproj +++ b/Users/Sentinel/SentinelSystem/SentinelSystem.csproj @@ -59,7 +59,6 @@ - diff --git a/Users/Sentinel/SentinelSystem/SentinelVFS.cs b/Users/Sentinel/SentinelSystem/SentinelVFS.cs index 5e2fad0b6..a2cd8d8d8 100644 --- a/Users/Sentinel/SentinelSystem/SentinelVFS.cs +++ b/Users/Sentinel/SentinelSystem/SentinelVFS.cs @@ -8,6 +8,7 @@ using System.IO; using SentinelKernel.System.FileSystem.FAT; using SentinelKernel.System.FileSystem.Listing; using Console = global::System.Console; +using Directory = SentinelKernel.System.FileSystem.Listing.Directory; namespace SentinelKernel.System.FileSystem.VFS { @@ -199,12 +200,12 @@ namespace SentinelKernel.System.FileSystem.VFS for (int i = 0; i < mFileSystems.Count; i++) { string xTest = mFileSystems[i].Key; - if (xTest == xPath) + if (String.Equals(xTest, xPath)) { return mFileSystems[i].Value; } } - return null; + throw new Exception("Unable to determine filesystem for path: " + aPath); } public override void Initialize() @@ -221,55 +222,63 @@ namespace SentinelKernel.System.FileSystem.VFS public override Listing.Directory GetDirectory(string aPath) { - string[] xPathParts = VFSManager.SplitPath(aPath); var xFS = GetFileSystemFromPath(aPath); - if (xFS != null) + return DoGetDirectory(aPath, xFS); + } + + private Directory DoGetDirectory(string aPath, FileSystem aFS) + { + if (aFS == null) { - if (xPathParts.Length == 1) + throw new ArgumentNullException("aFS"); + } + string[] xPathParts = VFSManager.SplitPath(aPath); + + if (xPathParts.Length == 1) + { + return GetVolume(aFS, aPath); + } + + Listing.Directory xBaseDirectory = null; + + // start at index 1, because 0 is the volume + for (int i = 1; i < xPathParts.Length; i++) + { + var xPathPart = xPathParts[i]; + var xPartFound = false; + var xListing = aFS.GetDirectoryListing(xBaseDirectory); + + for (int j = 0; j < xListing.Count; j++) { - return GetVolume(xPathParts[0]); - } - - Listing.Directory xBaseDirectory = null; - - // start at index 1, because 0 is the volume - for (int i = 1; i < xPathParts.Length; i++) - { - var xPathPart = xPathParts[i]; - var xPartFound = false; - var xListing = xFS.GetDirectoryListing(xBaseDirectory); - - for (int j = 0; j < xListing.Count; j++) + var xListingItem = xListing[j]; + if (String.Equals(xListingItem.Name, xPathPart, StringComparison.OrdinalIgnoreCase)) { - var xListingItem = xListing[j]; - if (String.Equals(xListingItem.Name, xPathPart, StringComparison.OrdinalIgnoreCase)) + if (xListingItem is Listing.Directory) { - if (xListingItem is Listing.Directory) - { - xBaseDirectory = (Listing.Directory)xListingItem; - xPartFound = true; - } - else - { - throw new Exception("Path part '" + xPathPart + "' found, but not a directory!"); - } + xBaseDirectory = (Listing.Directory)xListingItem; + xPartFound = true; + } + else + { + throw new Exception("Path part '" + xPathPart + "' found, but not a directory!"); } } - - if (!xPartFound) - { - throw new Exception("Path part '" + xPathPart + "' not found!"); - } } - return xBaseDirectory; + + if (!xPartFound) + { + throw new Exception("Path part '" + xPathPart + "' not found!"); + } } - return null; + return xBaseDirectory; } public override List GetDirectoryListing(string aPath) { - throw new NotImplementedException(); + var xFS = GetFileSystemFromPath(aPath); + var xDirectory = DoGetDirectory(aPath, xFS); + return xFS.GetDirectoryListing(xDirectory); } public override List GetDirectoryListing(Listing.Directory aParentDirectory) @@ -287,6 +296,11 @@ namespace SentinelKernel.System.FileSystem.VFS throw new NotImplementedException(); } + public Listing.Directory GetVolume(FileSystem filesystem, string name) + { + return filesystem.GetRootDirectory(name); + } + /* public override SentinelKernel.System.FileSystem.Listing.Directory GetVolume(string aVolume) { diff --git a/Users/Sentinel/SentinelSystem/System/IO/PathImpl.cs b/Users/Sentinel/SentinelSystem/System/IO/PathImpl.cs index 89e0c7d49..2db8b757e 100644 --- a/Users/Sentinel/SentinelSystem/System/IO/PathImpl.cs +++ b/Users/Sentinel/SentinelSystem/System/IO/PathImpl.cs @@ -245,7 +245,12 @@ namespace SentinelKernel.System.Plugs.System.IO return null; } aPath = NormalizePath(aPath, false); - return aPath.Substring(0, GetRootLength(aPath)); + var xResult = aPath.Substring(0, GetRootLength(aPath)); + if (xResult[xResult.Length - 1] != Path.DirectorySeparatorChar) + { + xResult = xResult + Path.DirectorySeparatorChar; + } + return xResult; } public static string GetRandomFileName() From 65fdc07baddd0dfd832daff127af99428abeaf1b Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 11:14:16 +0200 Subject: [PATCH 02/16] File.Exists works for files in subdirectories as well. --- Users/Sentinel/SentinelKernel/Kernel.cs | 11 +- .../FileSystem/FAT/FatFileSystem.cs | 113 ++++++++++-------- .../SentinelSystem/FileSystem/FatHelpers.cs | 2 +- .../FileSystem/VFS/VFSManager.cs | 1 - 4 files changed, 73 insertions(+), 54 deletions(-) diff --git a/Users/Sentinel/SentinelKernel/Kernel.cs b/Users/Sentinel/SentinelKernel/Kernel.cs index 7e8f84b46..beab38e10 100644 --- a/Users/Sentinel/SentinelKernel/Kernel.cs +++ b/Users/Sentinel/SentinelKernel/Kernel.cs @@ -41,7 +41,7 @@ namespace SentinelKernel } Console.WriteLine("Subfolder exists as well!"); - xTest = File.Exists(@"0:\Kudzu.txt"); + xTest = File.Exists(@"0:\KudzU.txt"); if (!xTest) { Console.WriteLine(@"\Kudzu.txt not found!"); @@ -50,6 +50,15 @@ namespace SentinelKernel Console.WriteLine("Kudzu.txt found!"); + xTest = File.Exists(@"0:\Test\DirInTest\Readme.txt"); + if (!xTest) + { + Console.WriteLine(@"\Test\DirInTest\Readme.txt not found!"); + return; + } + + Console.WriteLine(@"Test\DirInTest\Readme.txt found!"); + } catch (Exception e) { diff --git a/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs b/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs index 65f1c5817..c8cc165ec 100644 --- a/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs +++ b/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs @@ -241,17 +241,20 @@ namespace SentinelKernel.System.FileSystem.FAT { var xResult = new List(); //TODO: Change xLongName to StringBuilder + string xLongName = ""; + string xName = ""; for (UInt32 i = 0; i < xData.Length; i = i + 32) { FatHelpers.Debug("-------------------------------------------------"); - string xLongName = ""; byte xAttrib = xData[i + 11]; - FatHelpers.Debug("Attrib = " + xAttrib.ToString()); + byte xStatus = xData[i]; + + FatHelpers.Debug("Attrib = " + xAttrib.ToString() + ", Status = " + xStatus); if (xAttrib == DirectoryEntryAttributeConsts.LongName) { byte xType = xData[i + 12]; byte xOrd = xData[i]; - FatHelpers.Debug("Reading LFN with Seqnr " + xOrd.ToString()); + FatHelpers.Debug("Reading LFN with Seqnr " + xOrd.ToString() + ", Type = " + xType); if (xOrd == 0xE5) { FatHelpers.Debug("Skipping deleted entry"); @@ -280,65 +283,74 @@ namespace SentinelKernel.System.FileSystem.FAT } } xLongName = xLongPart + xLongName; + xLongPart = null; //TODO: LDIR_Chksum } } - string xName = xLongName; - byte xStatus = xData[i]; - if (xStatus == 0x00) + else { - // Empty slot, and no more entries after this - break; - } - else if (xStatus == 0x05) - { - // Japanese characters - We dont handle these - } - else if (xStatus == 0xE5) - { - // Empty slot, skip it - } - else if (xStatus >= 0x20) - { - if (xLongName.Length > 0) + xName = xLongName; + if (xStatus == 0x00) { - // Leading and trailing spaces are to be ignored according to spec. - // Many programs (including Windows) pad trailing spaces although it - // it is not required for long names. - // As per spec, ignore trailing periods - xName = xLongName.Trim(); - - //If there are trailing periods - int nameIndex = xName.Length - 1; - if (xName[nameIndex] == '.') - { - //Search backwards till we find the first non-period character - for (; nameIndex > 0; nameIndex--) - { - if (xName[nameIndex] != '.') - { - break; - } - } - //Substring to remove the periods - xName = xName.Substring(0, nameIndex + 1); - } + // Empty slot, and no more entries after this + break; } - else + else if (xStatus == 0x05) { - string xEntry = xData.GetAsciiString(i, 11); - xName = xEntry.Substring(0, 8).TrimEnd(); - string xExt = xEntry.Substring(8, 3).TrimEnd(); - if (xExt.Length > 0) + // Japanese characters - We dont handle these + } + else if (xStatus == 0xE5) + { + // Empty slot, skip it + } + else if (xStatus >= 0x20) + { + if (xLongName.Length > 0) { - xName = xName + "." + xExt; + // Leading and trailing spaces are to be ignored according to spec. + // Many programs (including Windows) pad trailing spaces although it + // it is not required for long names. + // As per spec, ignore trailing periods + xName = xLongName.Trim(); + + //If there are trailing periods + int nameIndex = xName.Length - 1; + if (xName[nameIndex] == '.') + { + //Search backwards till we find the first non-period character + for (; nameIndex > 0; nameIndex--) + { + if (xName[nameIndex] != '.') + { + break; + } + } + //Substring to remove the periods + xName = xName.Substring(0, nameIndex + 1); + } + xLongName = ""; + } + else + { + string xEntry = xData.GetAsciiString(i, 11); + xName = xEntry.Substring(0, 8).TrimEnd(); + string xExt = xEntry.Substring(8, 3).TrimEnd(); + if (xExt.Length > 0) + { + xName = xName + "." + xExt; + } } } } UInt32 xFirstCluster = (UInt32)(xData.ToUInt16(i + 20) << 16 | xData.ToUInt16(i + 26)); var xTest = xAttrib & (DirectoryEntryAttributeConsts.Directory | DirectoryEntryAttributeConsts.VolumeID); - if (xTest == 0) + if (xAttrib == DirectoryEntryAttributeConsts.LongName) + { + // skip adding, as it's a LongFileName entry, meaning the next normal entry is the item with the name. + FatHelpers.Debug("Entry was an Long FileName entry. Current LongName = '" + xLongName + "'"); + } + else if (xTest == 0) { UInt32 xSize = xData.ToUInt32(i + 28); if (xSize == 0 && xName.Length == 0) @@ -348,11 +360,11 @@ namespace SentinelKernel.System.FileSystem.FAT xResult.Add(new FatFile(this, xName, xSize, xFirstCluster)); FatHelpers.Debug("Returning file '" + xName + "'"); } - else if (xTest == DirectoryEntryAttributeConsts.Directory || xAttrib == DirectoryEntryAttributeConsts.LongName) + else if (xTest == DirectoryEntryAttributeConsts.Directory) { UInt32 xSize = xData.ToUInt32(i + 28); var xFatDirectory = new FatDirectory(this, xName, xFirstCluster); - FatHelpers.Debug("Returning directory '" + xFatDirectory.Name + "'"); + FatHelpers.Debug("Returning directory '" + xFatDirectory.Name + "', FirstCluster = " + xFirstCluster); xResult.Add(xFatDirectory); } else if (xTest == DirectoryEntryAttributeConsts.VolumeID) @@ -364,7 +376,6 @@ namespace SentinelKernel.System.FileSystem.FAT { FatHelpers.Debug("Not sure what to do!"); } - xLongName = ""; } return xResult; diff --git a/Users/Sentinel/SentinelSystem/FileSystem/FatHelpers.cs b/Users/Sentinel/SentinelSystem/FileSystem/FatHelpers.cs index 5e197996b..043221718 100644 --- a/Users/Sentinel/SentinelSystem/FileSystem/FatHelpers.cs +++ b/Users/Sentinel/SentinelSystem/FileSystem/FatHelpers.cs @@ -8,7 +8,7 @@ namespace SentinelKernel.System.FileSystem private static Debugger mDebugger = new Debugger("FAT", "Debug"); public static void Debug(string message) { - mDebugger.Send("FAT Debug: " + message); + //mDebugger.Send("FAT Debug: " + message); } } } diff --git a/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs b/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs index ff3766125..fea00ecd4 100644 --- a/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs +++ b/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs @@ -149,7 +149,6 @@ namespace SentinelKernel.System.FileSystem.VFS xDirectory = xDirectory + Path.DirectorySeparatorChar; } - var xList = GetDirectoryListing(xDirectory); for (int i = 0; i < xList.Count; i++) { From 2fd9977c205d9e93f7c2c84d44e2408b9627e3e9 Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 11:42:31 +0200 Subject: [PATCH 03/16] File.ReadAllText works! --- Users/Sentinel/SentinelKernel/Kernel.cs | 3 + .../FileSystem/FAT/FatFileSystem.cs | 8 ++ .../SentinelSystem/FileSystem/FileSystem.cs | 5 +- .../FileSystem/VFS/VFSManager.cs | 15 +++- .../SentinelSystem/SentinelSystem.csproj | 1 + .../SentinelSystem/System/IO/FileImpl.cs | 23 +++++- .../System/IO/FileStreamImpl.cs | 75 +++++++++++-------- .../Cosmos.Common/Extensions/ByteConverter.cs | 15 ++++ 8 files changed, 107 insertions(+), 38 deletions(-) diff --git a/Users/Sentinel/SentinelKernel/Kernel.cs b/Users/Sentinel/SentinelKernel/Kernel.cs index beab38e10..62015a168 100644 --- a/Users/Sentinel/SentinelKernel/Kernel.cs +++ b/Users/Sentinel/SentinelKernel/Kernel.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Text; using System.IO; using SentinelKernel.System.FileSystem.VFS; +using Cosmos.Common.Extensions; using Sys = Cosmos.System; namespace SentinelKernel @@ -59,6 +60,8 @@ namespace SentinelKernel Console.WriteLine(@"Test\DirInTest\Readme.txt found!"); + Console.Write("File contents of Kudzu.txt: "); + Console.WriteLine(File.ReadAllText(@"0:\Kudzu.txt")); } catch (Exception e) { diff --git a/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs b/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs index c8cc165ec..561c3bc8e 100644 --- a/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs +++ b/Users/Sentinel/SentinelSystem/FileSystem/FAT/FatFileSystem.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using Cosmos.Common.Extensions; using Cosmos.HAL.BlockDevice; using SentinelKernel.System.FileSystem.FAT.Listing; using SentinelKernel.System.FileSystem.Listing; +using Directory = SentinelKernel.System.FileSystem.Listing.Directory; +using File = SentinelKernel.System.FileSystem.Listing.File; namespace SentinelKernel.System.FileSystem.FAT { @@ -410,5 +413,10 @@ namespace SentinelKernel.System.FileSystem.FAT { return new FatDirectory(this, name, RootCluster); } + + public override Stream GetFileStream(File fileInfo) + { + return new FatStream((FatFile)fileInfo); + } } } diff --git a/Users/Sentinel/SentinelSystem/FileSystem/FileSystem.cs b/Users/Sentinel/SentinelSystem/FileSystem/FileSystem.cs index 833d1a6aa..368c3b444 100644 --- a/Users/Sentinel/SentinelSystem/FileSystem/FileSystem.cs +++ b/Users/Sentinel/SentinelSystem/FileSystem/FileSystem.cs @@ -1,9 +1,11 @@ using Cosmos.HAL.BlockDevice; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; -using SentinelKernel.System.FileSystem.Listing; +using Directory = SentinelKernel.System.FileSystem.Listing.Directory; +using File = SentinelKernel.System.FileSystem.Listing.File; namespace SentinelKernel.System.FileSystem { @@ -43,5 +45,6 @@ namespace SentinelKernel.System.FileSystem public abstract List GetDirectoryListing(Directory baseDirectory); public abstract Directory GetRootDirectory(string name); + public abstract Stream GetFileStream(File fileInfo); } } diff --git a/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs b/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs index fea00ecd4..f08cb5c0d 100644 --- a/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs +++ b/Users/Sentinel/SentinelSystem/FileSystem/VFS/VFSManager.cs @@ -134,7 +134,7 @@ namespace SentinelKernel.System.FileSystem.VFS #endregion - public static Listing.File GetFile(string aPath) + public static Listing.File TryGetFile(string aPath) { if (string.IsNullOrEmpty(aPath)) { @@ -276,7 +276,7 @@ namespace SentinelKernel.System.FileSystem.VFS { try { - return (VFSManager.GetFile(aPath) != null); + return (VFSManager.TryGetFile(aPath) != null); } catch (Exception E) { @@ -303,5 +303,16 @@ namespace SentinelKernel.System.FileSystem.VFS } } + + public static Stream GetFileStream(string aPathname) + { + var xFileInfo = TryGetFile(aPathname); + if (xFileInfo == null) + { + throw new Exception("File not found: " + aPathname); + } + + return xFileInfo.FileSystem.GetFileStream(xFileInfo); + } } } diff --git a/Users/Sentinel/SentinelSystem/SentinelSystem.csproj b/Users/Sentinel/SentinelSystem/SentinelSystem.csproj index 480378ba4..df7d45ba1 100644 --- a/Users/Sentinel/SentinelSystem/SentinelSystem.csproj +++ b/Users/Sentinel/SentinelSystem/SentinelSystem.csproj @@ -59,6 +59,7 @@ + diff --git a/Users/Sentinel/SentinelSystem/System/IO/FileImpl.cs b/Users/Sentinel/SentinelSystem/System/IO/FileImpl.cs index 3a104f9a9..10fd2535e 100644 --- a/Users/Sentinel/SentinelSystem/System/IO/FileImpl.cs +++ b/Users/Sentinel/SentinelSystem/System/IO/FileImpl.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using Cosmos.Common.Extensions; using Cosmos.IL2CPU.Plugs; using SentinelKernel.System.FileSystem.VFS; @@ -16,9 +17,23 @@ namespace SentinelKernel.System.Plugs.System.IO return FileSystem.VFS.VFSManager.FileExists(aFile); } - //public static string ReadAllText(string aFile) - //{ - // //Find file + + + public static string ReadAllText(string aFile) + { + using (var xFS = new FileStream(aFile, FileMode.Open)) + { + var xBuff = new byte[(int)xFS.Length]; + var xResult = xFS.Read(xBuff, 0, xBuff.Length); + if (xResult != xBuff.Length) + { + throw new Exception("Couldn't read complete file!"); + } + + return xBuff.GetUtf8String(0, (uint)xBuff.Length); + } + } + // if (!File.Exists(aFile)) // return "Could not find file " + aFile; // //throw new FileNotFoundException("Could not find file " + aFile); @@ -26,4 +41,4 @@ namespace SentinelKernel.System.Plugs.System.IO // return VFSManager.ReadFileAsString(aFile); //} } -} \ No newline at end of file +} diff --git a/Users/Sentinel/SentinelSystem/System/IO/FileStreamImpl.cs b/Users/Sentinel/SentinelSystem/System/IO/FileStreamImpl.cs index 55881c578..b8194cc7a 100644 --- a/Users/Sentinel/SentinelSystem/System/IO/FileStreamImpl.cs +++ b/Users/Sentinel/SentinelSystem/System/IO/FileStreamImpl.cs @@ -8,38 +8,51 @@ using SentinelKernel.System.FileSystem.VFS; namespace SentinelKernel.System.Plugs.System.IO { - [Plug(Target = typeof(IO::FileStream))] - public class FileStreamImpl { + [Plug(Target = typeof(IO::FileStream))] + [PlugField(FieldId = "$$InnerStream$$", FieldType = typeof(IO::Stream))] + public class FileStreamImpl + { + // This plug basically forwards all calls to the $$InnerStream$$ stream, which is supplied by the file system. + + + + + // public static unsafe void Ctor(String aThis, [FieldAccess(Name = "$$Storage$$")]ref Char[] aStorage, Char[] aChars, int aStartIndex, int aLength, + + public static void Ctor(IO::FileStream aThis, string aPathname, IO::FileMode aMode, [FieldAccess(Name = "$$InnerStream$$")] ref IO::Stream innerStream) + { + Console.WriteLine("In FileStreamImpl.Ctor"); + innerStream = VFSManager.GetFileStream(aPathname); + } + + public static void CCtor() + { + // plug cctor as it (indirectly) uses Thread.MemoryBarrier() + } + + public static int Read(IO::FileStream aThis, byte[] aBuffer, int aOffset, int aCount, [FieldAccess(Name = "$$InnerStream$$")] ref IO::Stream innerStream) + { + return innerStream.Read(aBuffer, aOffset, aCount); + } + + public static long get_Length(IO::FileStream aThis, [FieldAccess(Name = "$$InnerStream$$")] ref IO::Stream innerStream) + { + return innerStream.Length; + } + + public static void SetLength(IO::FileStream aThis, long value) + { + throw new NotImplementedException(); + } + + public static void Dispose(IO::FileStream aThis, bool disposing) + { + throw new NotImplementedException(); + } + + //static void Init(IO::FileStream aThis, string path, IO::FileMode mode, IO::FileAccess access, int rights, bool useRights, IO::FileShare share, int bufferSize + // , IO::FileOptions options, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES secAttrs, string msgPath, bool bFromProxy) { } - //[PlugField(FieldId = "$$Storage$$", FieldType = typeof(char[]))] - //[PlugField(FieldId = "System.Char System.String.m_firstChar", IsExternalValue = true)] - //public static class StringImpl { - // //[PlugMethod(Signature = "System_Void__System_String__ctor_System_Char____System_Int32__System_Int32_")] - // public static unsafe void Ctor(String aThis, [FieldAccess(Name = "$$Storage$$")]ref Char[] aStorage, Char[] aChars, int aStartIndex, int aLength, - // [FieldAccess(Name = "System.Int32 System.String.m_stringLength")] ref int aStringLength, - // [FieldAccess(Name = "System.Char System.String.m_firstChar")] ref char* aFirstChar) { - // Char[] newChars = new Char[aLength]; - // Array.Copy(aChars, aStartIndex, newChars, 0, aLength); - // aStorage = newChars; - // aStringLength = newChars.Length; - // fixed (char* xFirstChar = &aStorage[0]) { - // aFirstChar = xFirstChar; - // } - // } - static public void Ctor(IO::FileStream aThis, string aPathname, IO::FileMode aMode) { } - - static public void CCtor() { - // plug cctor as it (indirectly) uses Thread.MemoryBarrier() - } - - static public int Read(IO::FileStream aThis, byte[] aBuffer, int aOffset, int aCount) { - return 0; - } - - //static void Init(IO::FileStream aThis, string path, IO::FileMode mode, IO::FileAccess access, int rights, bool useRights, IO::FileShare share, int bufferSize - // , IO::FileOptions options, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES secAttrs, string msgPath, bool bFromProxy) { } - - } } diff --git a/source/Cosmos.Common/Extensions/ByteConverter.cs b/source/Cosmos.Common/Extensions/ByteConverter.cs index 7f09acec6..2df70e49e 100644 --- a/source/Cosmos.Common/Extensions/ByteConverter.cs +++ b/source/Cosmos.Common/Extensions/ByteConverter.cs @@ -35,6 +35,21 @@ namespace Cosmos.Common.Extensions { return new string(xChars); } + static public string GetUtf8String(this byte[] n, UInt32 aStart, UInt32 aCharCount) + { + // TODO: This method handles ASCII only currently, no unicode. + var xChars = new char[aCharCount]; + for (int i = 0; i < aCharCount; i++) + { + xChars[i] = (char)n[(aStart) + i]; + if (xChars[i] == 0) + { + return new string(xChars, 0, i); + } + } + return new string(xChars); + } + static public string GetUtf16String(this byte[] n, UInt32 aStart, UInt32 aCharCount) { //TODO: This routine only handles ASCII. It does not handle unicode yet. var xChars = new char[aCharCount]; From 24b60285ad6f3588e04293de99f8178b18c1bcf5 Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 11:44:56 +0200 Subject: [PATCH 04/16] Further testing and codecleanup. --- Users/Sentinel/SentinelKernel/Kernel.cs | 3 +++ Users/Sentinel/SentinelSystem/System/IO/FileStreamImpl.cs | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Users/Sentinel/SentinelKernel/Kernel.cs b/Users/Sentinel/SentinelKernel/Kernel.cs index 62015a168..1cc66bd20 100644 --- a/Users/Sentinel/SentinelKernel/Kernel.cs +++ b/Users/Sentinel/SentinelKernel/Kernel.cs @@ -62,6 +62,9 @@ namespace SentinelKernel Console.Write("File contents of Kudzu.txt: "); Console.WriteLine(File.ReadAllText(@"0:\Kudzu.txt")); + + Console.WriteLine(@"File contents of Test\DirInTest\Readme.txt: "); + Console.WriteLine(File.ReadAllText(@"0:\Test\DirInTest\Readme.txt")); } catch (Exception e) { diff --git a/Users/Sentinel/SentinelSystem/System/IO/FileStreamImpl.cs b/Users/Sentinel/SentinelSystem/System/IO/FileStreamImpl.cs index b8194cc7a..a9c11e87c 100644 --- a/Users/Sentinel/SentinelSystem/System/IO/FileStreamImpl.cs +++ b/Users/Sentinel/SentinelSystem/System/IO/FileStreamImpl.cs @@ -21,7 +21,6 @@ namespace SentinelKernel.System.Plugs.System.IO public static void Ctor(IO::FileStream aThis, string aPathname, IO::FileMode aMode, [FieldAccess(Name = "$$InnerStream$$")] ref IO::Stream innerStream) { - Console.WriteLine("In FileStreamImpl.Ctor"); innerStream = VFSManager.GetFileStream(aPathname); } From eef80473fb89e97d9f6068d216e8f9bb2527a581 Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 12:28:09 +0200 Subject: [PATCH 05/16] Sort the Locals window contents. Fixes #152 --- .../Cosmos.Debug.VSDebugEngine/.editorconfig | 3 ++ .../AD7.Impl/AD7StackFrame.cs | 29 +++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/source/Cosmos.Debug.VSDebugEngine/.editorconfig b/source/Cosmos.Debug.VSDebugEngine/.editorconfig index 4ebeb28a1..ce3678be2 100644 --- a/source/Cosmos.Debug.VSDebugEngine/.editorconfig +++ b/source/Cosmos.Debug.VSDebugEngine/.editorconfig @@ -4,3 +4,6 @@ indent_style=space [Host/*.cs] indent_size=2 + +[AD7.Impl/AD7StackFrame.cs] +indent_size=2 diff --git a/source/Cosmos.Debug.VSDebugEngine/AD7.Impl/AD7StackFrame.cs b/source/Cosmos.Debug.VSDebugEngine/AD7.Impl/AD7StackFrame.cs index c486d7dc1..01cebdaf2 100644 --- a/source/Cosmos.Debug.VSDebugEngine/AD7.Impl/AD7StackFrame.cs +++ b/source/Cosmos.Debug.VSDebugEngine/AD7.Impl/AD7StackFrame.cs @@ -13,7 +13,7 @@ using SQLinq; using SQLinq.Dapper; namespace Cosmos.Debug.VSDebugEngine { - // Represents a logical stack frame on the thread stack. + // Represents a logical stack frame on the thread stack. // Also implements the IDebugExpressionContext interface, which allows expression evaluation and watch windows. public class AD7StackFrame : IDebugStackFrame2, IDebugExpressionContext2 { readonly AD7Engine mEngine; @@ -24,7 +24,7 @@ namespace Cosmos.Debug.VSDebugEngine { private string mFunctionName; private uint mLineNum; private bool mHasSource; - + // Must have empty holders, some code looks at length and can run // before we set them. internal LOCAL_ARGUMENT_INFO[] mLocalInfos = new LOCAL_ARGUMENT_INFO[] {}; @@ -36,7 +36,7 @@ namespace Cosmos.Debug.VSDebugEngine { // An array of this frame's locals private DebugLocalInfo[] mLocals; private AD7Process mProcess; - + public AD7StackFrame(AD7Engine aEngine, AD7Thread aThread, AD7Process aProcess) { mEngine = aEngine; @@ -49,7 +49,7 @@ namespace Cosmos.Debug.VSDebugEngine { var xSourceInfos = xProcess.mDebugInfoDb.GetSourceInfos(xAddress); if (!xSourceInfos.ContainsKey(xAddress)) { - //Attempt to find the ASM address of the first ASM line of the C# line that contains + //Attempt to find the ASM address of the first ASM line of the C# line that contains //the current ASM address line // Because of Asm breakpoints the address we have might be in the middle of a C# line. @@ -83,7 +83,7 @@ namespace Cosmos.Debug.VSDebugEngine { xSymbolInfo = aProcess.mDebugInfoDb.Connection.Query(new SQLinq().Where(q => q.LabelName == xLabel)).FirstOrDefault(); if (xSymbolInfo != null) { - var xMethod = mProcess.mDebugInfoDb.Connection.Get(xSymbolInfo.MethodID); + var xMethod = mProcess.mDebugInfoDb.Connection.Get(xSymbolInfo.MethodID); var xAllInfos = aProcess.mDebugInfoDb.Connection.Query(new SQLinq().Where(q => q.METHODLABELNAME == xMethod.LabelCall)); mLocalInfos = xAllInfos.Where(q => !q.IsArgument).ToArray(); mArgumentInfos = xAllInfos.Where(q => q.IsArgument).ToArray(); @@ -99,6 +99,7 @@ namespace Cosmos.Debug.VSDebugEngine { IsLocal = false }; } + mParams = mParams.OrderBy(i => i.Name, StringComparer.OrdinalIgnoreCase).ToArray(); } if (mLocalInfos.Length > 0) @@ -113,6 +114,7 @@ namespace Cosmos.Debug.VSDebugEngine { IsLocal = true }; } + mLocals = mLocals.OrderBy(i => i.Name, StringComparer.OrdinalIgnoreCase).ToArray(); } } } @@ -278,6 +280,7 @@ namespace Cosmos.Debug.VSDebugEngine { } } + propInfo = propInfo.OrderBy(i => i.bstrName).ToArray(); enumObject = new AD7PropertyInfoEnum(propInfo); } @@ -291,6 +294,7 @@ namespace Cosmos.Debug.VSDebugEngine { propInfo[i] = property.ConstructDebugPropertyInfo(enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_STANDARD); } + propInfo = propInfo.OrderBy(i => i.bstrName).ToArray(); enumObject = new AD7PropertyInfoEnum(propInfo); } @@ -304,6 +308,7 @@ namespace Cosmos.Debug.VSDebugEngine { propInfo[i] = property.ConstructDebugPropertyInfo(enum_DEBUGPROP_INFO_FLAGS.DEBUGPROP_INFO_STANDARD); } + propInfo = propInfo.OrderBy(i => i.bstrName).ToArray(); enumObject = new AD7PropertyInfoEnum(propInfo); } @@ -364,7 +369,7 @@ namespace Cosmos.Debug.VSDebugEngine { } // Gets a description of the properties of a stack frame. - // Calling the IDebugProperty2::EnumChildren method with appropriate filters can retrieve the local variables, method parameters, registers, and "this" + // Calling the IDebugProperty2::EnumChildren method with appropriate filters can retrieve the local variables, method parameters, registers, and "this" // pointer associated with the stack frame. The debugger calls EnumProperties to obtain these values in the sample. int IDebugStackFrame2.GetDebugProperty(out IDebugProperty2 property) { throw new NotImplementedException(); @@ -400,8 +405,8 @@ namespace Cosmos.Debug.VSDebugEngine { } // Gets an evaluation context for expression evaluation within the current context of a stack frame and thread. - // Generally, an expression evaluation context can be thought of as a scope for performing expression evaluation. - // Call the IDebugExpressionContext2::ParseText method to parse an expression and then call the resulting IDebugExpression2::EvaluateSync + // Generally, an expression evaluation context can be thought of as a scope for performing expression evaluation. + // Call the IDebugExpressionContext2::ParseText method to parse an expression and then call the resulting IDebugExpression2::EvaluateSync // or IDebugExpression2::EvaluateAsync methods to evaluate the parsed expression. int IDebugStackFrame2.GetExpressionContext(out IDebugExpressionContext2 ppExprCxt) { ppExprCxt = (IDebugExpressionContext2)this; @@ -424,7 +429,7 @@ namespace Cosmos.Debug.VSDebugEngine { } } - // Gets the language associated with this stack frame. + // Gets the language associated with this stack frame. // In this sample, all the supported stack frames are C++ int IDebugStackFrame2.GetLanguageInfo(ref string pbstrLanguage, ref Guid pguidLanguage) { pbstrLanguage = "CSharp"; @@ -466,9 +471,9 @@ namespace Cosmos.Debug.VSDebugEngine { #endregion - // Retrieves the name of the evaluation context. - // The name is the description of this evaluation context. It is typically something that can be parsed by an expression evaluator - // that refers to this exact evaluation context. For example, in C++ the name is as follows: + // Retrieves the name of the evaluation context. + // The name is the description of this evaluation context. It is typically something that can be parsed by an expression evaluator + // that refers to this exact evaluation context. For example, in C++ the name is as follows: // "{ function-name, source-file-name, module-file-name }" int IDebugExpressionContext2.GetName(out string pbstrName) { throw new NotImplementedException(); From 9b13be0d02c4496cfbac02ba84c30c888758dda1 Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 13:26:37 +0200 Subject: [PATCH 06/16] Change xml output of kernel tester slightly, so that messages are more readable. --- Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs b/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs index 6daa4db15..b7cee74a6 100644 --- a/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs +++ b/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs @@ -46,7 +46,7 @@ namespace Cosmos.TestRunner.Core { var xParent = mCurrentNode.Peek(); var xItem = mDocument.CreateElement("Message"); - xItem.AppendChild(mDocument.CreateCDataSection(message)); + xItem.InnerText = message; xParent.AppendChild(xItem); } From 5fca0ecbb7c86b0ca89da1d28d063eefb3c4cf87 Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 13:28:16 +0200 Subject: [PATCH 07/16] Fix ata detection bug. CD drives were recognized as ATAPI devices, but still handled as ATA ones. Currently we don't have an ATAPI driver, so the CD drives are ignored. Fixes #129 --- .../Host/Bochs.Configuration.cs | 11 +-- source/Cosmos.HAL/.editorconfig | 6 ++ source/Cosmos.HAL/BlockDevice/Ata.cs | 8 +- source/Cosmos.HAL/BlockDevice/AtaPio.cs | 38 +++++---- source/Cosmos.HAL/Global.cs | 80 +++++++++++-------- 5 files changed, 85 insertions(+), 58 deletions(-) diff --git a/source/Cosmos.Debug.VSDebugEngine/Host/Bochs.Configuration.cs b/source/Cosmos.Debug.VSDebugEngine/Host/Bochs.Configuration.cs index afb7361e6..d572126c9 100644 --- a/source/Cosmos.Debug.VSDebugEngine/Host/Bochs.Configuration.cs +++ b/source/Cosmos.Debug.VSDebugEngine/Host/Bochs.Configuration.cs @@ -32,11 +32,11 @@ namespace Cosmos.Debug.VSDebugEngine.Host "floppy_bootsig_check: disabled=0\n" + "# no floppya\n" + "# no floppyb\n" + + "ata0-master: type=cdrom, path=\"%CDROMBOOTPATH%\", status=inserted, model=\"Generic 1234\", biosdetect=auto\n" + "ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14\n" + - "ata0-master: type=disk, path=\"%HARDDISKPATH%\", mode=vmware4, cylinders=0, heads=0, spt=0, model=\"Generic 1234\", biosdetect=auto, translation=auto\n" + "ata0-slave: type=none\n" + "ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15\n" + - "ata1-master: type=cdrom, path=\"%CDROMBOOTPATH%\", status=inserted, model=\"Generic 1234\", biosdetect=auto\n" + + "ata1-master: type=disk, path=\"%HARDDISKPATH%\", mode=vmware4, cylinders=0, heads=0, spt=0, model=\"Generic 1234\", biosdetect=auto, translation=auto\n" + "ata2: enabled=0\n" + "ata3: enabled=0\n" + "pci: enabled=1, chipset=i440fx\n" + @@ -85,11 +85,8 @@ namespace Cosmos.Debug.VSDebugEngine.Host defaultConfigs.Set("com1", defaultConfigs.Get("com1").Replace("%PIPESERVERNAME%", xParts[1].ToLower())); var xHarddiskFile = Path.Combine(CosmosPaths.Build, @"VMWare\Workstation\Filesystem.vmdk"); - defaultConfigs.Set("ata0-master", defaultConfigs.Get("ata0-master").Replace("%HARDDISKPATH%", xHarddiskFile)); - - defaultConfigs.Set("ata1-master", defaultConfigs.Get("ata1-master").Replace("%CDROMBOOTPATH%", mParams["ISOFile"])); - - + defaultConfigs.Set("ata0-master", defaultConfigs.Get("ata0-master").Replace("%CDROMBOOTPATH%", mParams["ISOFile"])); + defaultConfigs.Set("ata1-master", defaultConfigs.Get("ata1-master").Replace("%HARDDISKPATH%", xHarddiskFile)); } private void GenerateConfiguration(string filePath) diff --git a/source/Cosmos.HAL/.editorconfig b/source/Cosmos.HAL/.editorconfig index 2788264c4..3e188034f 100644 --- a/source/Cosmos.HAL/.editorconfig +++ b/source/Cosmos.HAL/.editorconfig @@ -1,2 +1,8 @@ [*.cs] indent_size=4 + +[Global.cs] +indent_size = 2 + +[BlockDevice/Ata.cs] +indent_size = 2 diff --git a/source/Cosmos.HAL/BlockDevice/Ata.cs b/source/Cosmos.HAL/BlockDevice/Ata.cs index 60e4446cf..ef28ce530 100644 --- a/source/Cosmos.HAL/BlockDevice/Ata.cs +++ b/source/Cosmos.HAL/BlockDevice/Ata.cs @@ -2,15 +2,19 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Cosmos.Debug.Kernel; namespace Cosmos.HAL.BlockDevice { - public abstract class Ata : BlockDevice { + public abstract class Ata : BlockDevice + { + + internal static Debugger AtaDebugger = new Debugger("HAL", "Ata"); protected Ata() { mBlockSize = 512; } - // In future may need to add a None for PCI ATA controllers. + // In future may need to add a None for PCI ATA controllers. // Or maybe they all have Primary and Secondary on them as well. public enum ControllerIdEnum { Primary, Secondary } protected ControllerIdEnum mControllerID; diff --git a/source/Cosmos.HAL/BlockDevice/AtaPio.cs b/source/Cosmos.HAL/BlockDevice/AtaPio.cs index 48140151e..ef28033bb 100644 --- a/source/Cosmos.HAL/BlockDevice/AtaPio.cs +++ b/source/Cosmos.HAL/BlockDevice/AtaPio.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Text; using System.Threading; using Cosmos.Common; +using Cosmos.Debug.Kernel; namespace Cosmos.HAL.BlockDevice { @@ -80,7 +81,7 @@ namespace Cosmos.HAL.BlockDevice //* Bit 6: LBA (0: CHS, 1: LBA). LBA = 0x40, //* Bit 5: Obsolete and isn't used, but should be set. - //* Bit 7: Obsolete and isn't used, but should be set. + //* Bit 7: Obsolete and isn't used, but should be set. Default = 0xA0 }; @@ -127,6 +128,13 @@ namespace Cosmos.HAL.BlockDevice } #endregion + internal static Debugger mDebugger = new Debugger("HAL", "AtaPio"); + + private static void Debug(string message) + { + mDebugger.Send("AtaPio debug: " + message); + } + public AtaPio(Core.IOGroup.ATA aIO, Ata.ControllerIdEnum aControllerId, Ata.BusPositionEnum aBusPosition) { IO = aIO; @@ -180,10 +188,10 @@ namespace Cosmos.HAL.BlockDevice } // ATA requires a wait of 400 nanoseconds. - // Read the Status register FIVE TIMES, and only pay attention to the value - // returned by the last one -- after selecting a new master or slave device. The point being that - // you can assume an IO port read takes approximately 100ns, so doing the first four creates a 400ns - // delay -- which allows the drive time to push the correct voltages onto the bus. + // Read the Status register FIVE TIMES, and only pay attention to the value + // returned by the last one -- after selecting a new master or slave device. The point being that + // you can assume an IO port read takes approximately 100ns, so doing the first four creates a 400ns + // delay -- which allows the drive time to push the correct voltages onto the bus. // Since we read status again later, we wait by reading it 4 times. protected void Wait() { @@ -206,7 +214,6 @@ namespace Cosmos.HAL.BlockDevice return SendCmd(aCmd, true); } - public Status SendCmd(Cmd aCmd, bool aThrowOnError) { IO.Command.Byte = (byte)aCmd; @@ -221,6 +228,7 @@ namespace Cosmos.HAL.BlockDevice if (aThrowOnError && (xStatus & Status.Error) != 0) { // TODO: Read error port + Debug("ATA Error in SendCmd. Cmd = " + (byte)aCmd + ", Status = " + (byte)xStatus); throw new Exception("ATA Error"); } return xStatus; @@ -228,7 +236,7 @@ namespace Cosmos.HAL.BlockDevice protected string GetString(UInt16[] aBuffer, int aIndexStart, int aStringLength) { - // Would be nice to convert to byte[] and use + // Would be nice to convert to byte[] and use // new string(ASCIIEncoding.ASCII.GetChars(xBytes)); // But it requires some code Cosmos doesnt support yet var xChars = new char[aStringLength]; @@ -256,13 +264,13 @@ namespace Cosmos.HAL.BlockDevice // Not sure if all this is needed, its different than documented elsewhere but might not be bad // to add code to do all listed here: // - //To use the IDENTIFY command, select a target drive by sending 0xA0 for the master drive, or 0xB0 for the slave, to the "drive select" IO port. On the Primary bus, this would be port 0x1F6. - // Then set the Sectorcount, LBAlo, LBAmid, and LBAhi IO ports to 0 (port 0x1F2 to 0x1F5). - // Then send the IDENTIFY command (0xEC) to the Command IO port (0x1F7). - // Then read the Status port (0x1F7) again. If the value read is 0, the drive does not exist. For any other value: poll the Status port (0x1F7) until bit 7 (BSY, value = 0x80) clears. - // Because of some ATAPI drives that do not follow spec, at this point you need to check the LBAmid and LBAhi ports (0x1F4 and 0x1F5) to see if they are non-zero. + //To use the IDENTIFY command, select a target drive by sending 0xA0 for the master drive, or 0xB0 for the slave, to the "drive select" IO port. On the Primary bus, this would be port 0x1F6. + // Then set the Sectorcount, LBAlo, LBAmid, and LBAhi IO ports to 0 (port 0x1F2 to 0x1F5). + // Then send the IDENTIFY command (0xEC) to the Command IO port (0x1F7). + // Then read the Status port (0x1F7) again. If the value read is 0, the drive does not exist. For any other value: poll the Status port (0x1F7) until bit 7 (BSY, value = 0x80) clears. + // Because of some ATAPI drives that do not follow spec, at this point you need to check the LBAmid and LBAhi ports (0x1F4 and 0x1F5) to see if they are non-zero. // If so, the drive is not ATA, and you should stop polling. Otherwise, continue polling one of the Status ports until bit 3 (DRQ, value = 8) sets, or until bit 0 (ERR, value = 1) sets. - // At that point, if ERR is clear, the data is ready to read from the Data port (0x1F0). Read 256 words, and store them. + // At that point, if ERR is clear, the data is ready to read from the Data port (0x1F0). Read 256 words, and store them. // Read Identification Space of the Device var xBuff = new UInt16[256]; @@ -310,7 +318,7 @@ namespace Cosmos.HAL.BlockDevice IO.SectorCount.Byte = (byte)aSectorCount; IO.LBA0.Byte = (byte)(aSectorNo); IO.LBA1.Byte = (byte)(aSectorNo >> 8); - IO.LBA2.Byte = (byte)(aSectorNo >> 16); + IO.LBA2.Byte = (byte)(aSectorNo >> 16); //IO.LBA0.Byte = (byte)(aSectorNo & 0xFF); //IO.LBA1.Byte = (byte)((aSectorNo & 0xFF00) >> 8); //IO.LBA2.Byte = (byte)((aSectorNo & 0xFF0000) >> 16); @@ -347,4 +355,4 @@ namespace Cosmos.HAL.BlockDevice } } -} \ No newline at end of file +} diff --git a/source/Cosmos.HAL/Global.cs b/source/Cosmos.HAL/Global.cs index a282de306..8ba2857bc 100644 --- a/source/Cosmos.HAL/Global.cs +++ b/source/Cosmos.HAL/Global.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Cosmos.HAL.BlockDevice; namespace Cosmos.HAL { static public class Global { @@ -14,46 +15,57 @@ namespace Cosmos.HAL { public static PCI Pci; - static void InitAta(BlockDevice.Ata.ControllerIdEnum aControllerID, BlockDevice.Ata.BusPositionEnum aBusPosition) { + private static void InitAta(BlockDevice.Ata.ControllerIdEnum aControllerID, BlockDevice.Ata.BusPositionEnum aBusPosition) + { var xIO = aControllerID == BlockDevice.Ata.ControllerIdEnum.Primary ? Cosmos.Core.Global.BaseIOGroups.ATA1 : Cosmos.Core.Global.BaseIOGroups.ATA2; var xATA = new BlockDevice.AtaPio(xIO, aControllerID, aBusPosition); - if (xATA.DriveType != BlockDevice.AtaPio.SpecLevel.Null) { + if (xATA.DriveType == BlockDevice.AtaPio.SpecLevel.Null) + { + return; + } + if (xATA.DriveType == BlockDevice.AtaPio.SpecLevel.ATA) + { BlockDevice.BlockDevice.Devices.Add(xATA); - var xMbrData = new byte[512]; - xATA.ReadBlock(0UL, 1U, xMbrData); - var xMBR = new BlockDevice.MBR(xMbrData); + } + else + { + Ata.AtaDebugger.Send("ATA device with spec level " + (int)xATA.DriveType + " found, which is not supported!"); + return; + } + var xMbrData = new byte[512]; + xATA.ReadBlock(0UL, 1U, xMbrData); + var xMBR = new BlockDevice.MBR(xMbrData); - if (xMBR.EBRLocation != 0) - { - //EBR Detected - var xEbrData = new byte[512]; - xATA.ReadBlock(xMBR.EBRLocation, 1U, xEbrData); - var xEBR = new BlockDevice.EBR(xEbrData); + if (xMBR.EBRLocation != 0) + { + //EBR Detected + var xEbrData = new byte[512]; + xATA.ReadBlock(xMBR.EBRLocation, 1U, xEbrData); + var xEBR = new BlockDevice.EBR(xEbrData); - for (int i = 0; i < xEBR.Partitions.Count; i++) - { - //var xPart = xEBR.Partitions[i]; - //var xPartDevice = new BlockDevice.Partition(xATA, xPart.StartSector, xPart.SectorCount); - //BlockDevice.BlockDevice.Devices.Add(xPartDevice); - } - } + for (int i = 0; i < xEBR.Partitions.Count; i++) + { + //var xPart = xEBR.Partitions[i]; + //var xPartDevice = new BlockDevice.Partition(xATA, xPart.StartSector, xPart.SectorCount); + //BlockDevice.BlockDevice.Devices.Add(xPartDevice); + } + } - // TODO Change this to foreach when foreach is supported - Console.WriteLine("Number of MBR partitions found: " + xMBR.Partitions.Count); - for (int i = 0; i < xMBR.Partitions.Count; i++) - { - var xPart = xMBR.Partitions[i]; - if (xPart == null) - { - Console.WriteLine("Null partition found at idx " + i); - } - else - { - var xPartDevice = new BlockDevice.Partition(xATA, xPart.StartSector, xPart.SectorCount); - BlockDevice.BlockDevice.Devices.Add(xPartDevice); - Console.WriteLine("Found partition at idx " + i); - } - } + // TODO Change this to foreach when foreach is supported + Console.WriteLine("Number of MBR partitions found: " + xMBR.Partitions.Count); + for (int i = 0; i < xMBR.Partitions.Count; i++) + { + var xPart = xMBR.Partitions[i]; + if (xPart == null) + { + Console.WriteLine("Null partition found at idx " + i); + } + else + { + var xPartDevice = new BlockDevice.Partition(xATA, xPart.StartSector, xPart.SectorCount); + BlockDevice.BlockDevice.Devices.Add(xPartDevice); + Console.WriteLine("Found partition at idx " + i); + } } } From 8e2a89ac6edd04eed4017de4a7d734cf4838c475 Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 14:07:51 +0200 Subject: [PATCH 08/16] Restore guess demo. --- Demos/Guess/Guess.Cosmos | 28 ++++++++++---------- Demos/Guess/GuessOS.cs | 55 ++++++++++++++++------------------------ 2 files changed, 36 insertions(+), 47 deletions(-) diff --git a/Demos/Guess/Guess.Cosmos b/Demos/Guess/Guess.Cosmos index 961971150..c8b818936 100644 --- a/Demos/Guess/Guess.Cosmos +++ b/Demos/Guess/Guess.Cosmos @@ -20,12 +20,12 @@ bin\Debug\ MicrosoftNET False - False - IL + True + Source User PXE Player - False + True Workstation ISO False @@ -60,15 +60,15 @@ ISO VMware True - IL + Source False Workstation bin\Debug\ MicrosoftNET False All - False - False + True + True ISO None False @@ -138,7 +138,7 @@ False True True - Source + IL False Pipe: Cosmos\Serial 192.168.43.1 @@ -186,12 +186,12 @@ bin\Debug\ MicrosoftNET False - False - IL + True + Source User PXE Player - False + True Workstation ISO False @@ -226,15 +226,15 @@ ISO VMware True - IL + Source False Workstation bin\Debug\ MicrosoftNET False All - False - False + True + True ISO None False @@ -310,7 +310,7 @@ False True True - Source + IL False Pipe: Cosmos\Serial 192.168.43.1 diff --git a/Demos/Guess/GuessOS.cs b/Demos/Guess/GuessOS.cs index 9b8f36582..d4b9ca359 100644 --- a/Demos/Guess/GuessOS.cs +++ b/Demos/Guess/GuessOS.cs @@ -45,39 +45,28 @@ namespace GuessKernel { mCount++; - var xListClasses = new List(); - var xListStructs = new List(); - - xListClasses.Add(new KVPClass { Key = 1, Value = 2 }); - xListClasses.Add(new KVPClass { Key = 2, Value = 5 }); - - var xListItem= xListClasses[0]; - Console.Write("Classes0. Key = "); - Console.Write(xListItem.Key); - Console.Write("Value = "); - Console.WriteLine(xListItem.Value); - xListItem = xListClasses[1]; - Console.Write("Classes1. Key = "); - Console.Write(xListItem.Key); - Console.Write("Value = "); - Console.WriteLine(xListItem.Value); - - xListStructs.Add(new KVPStruct { Key = 1, Value = 2 }); - xListStructs.Add(new KVPStruct { Key = 2, Value = 5 }); - - var xStructItem = xListStructs[0]; - Console.Write("Item0. Key = "); - Console.Write(xStructItem.Key); - Console.Write("Value = "); - Console.WriteLine(xStructItem.Value); - xStructItem = xListStructs[1]; - Console.Write("Item1. Key = "); - Console.Write(xStructItem.Key); - Console.Write("Value = "); - Console.WriteLine(xStructItem.Value); - - - Stop(); + mDebugger.SendMessage("Kernel", "New iteration"); + Console.WriteLine(); + Console.WriteLine("Guess #" + mCount); + Console.Write("Please enter a guess: "); + string xInputStr = Console.ReadLine(); + Console.Write("Input length: "); + Console.WriteLine(xInputStr.Length.ToString()); + int xGuess = int.Parse(xInputStr); + Console.WriteLine("Your guess was " + xGuess); + if (xGuess < mMagicNo) + { + Console.WriteLine("Too low."); + } + else if (xGuess > mMagicNo) + { + Console.WriteLine("Too high."); + } + else + { + Console.WriteLine("You guessed it!"); + Stop(); + } } } } From 76308133fd3fcd8c6f56d24ad2a02a66e5dc9d6d Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 14:22:01 +0200 Subject: [PATCH 09/16] In tester, redirect bochs output to output handler as well. In xml, it's redirected to a new subelement of the task. (For separating it from kernel output). Part of #143 --- .../DefaultEngineConfiguration.cs | 4 +-- Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs | 3 +++ .../OutputHandlerBase.cs | 1 + .../OutputHandlerConsole.cs | 5 ++++ .../OutputHandlerXml.cs | 14 ++++++++++ .../Cosmos.Debug.VSDebugEngine/Host/Bochs.cs | 26 ++++++++++++++++++- 6 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Tests/Cosmos.TestRunner.Core/DefaultEngineConfiguration.cs b/Tests/Cosmos.TestRunner.Core/DefaultEngineConfiguration.cs index 335ed190e..ed689f088 100644 --- a/Tests/Cosmos.TestRunner.Core/DefaultEngineConfiguration.cs +++ b/Tests/Cosmos.TestRunner.Core/DefaultEngineConfiguration.cs @@ -12,8 +12,8 @@ namespace Cosmos.TestRunner.Core } engine.AddKernel(typeof(Cosmos.Compiler.Tests.SimpleWriteLine.Kernel.Kernel).Assembly.Location); - engine.AddKernel(typeof(SimpleStructsAndArraysTest.Kernel).Assembly.Location); - engine.AddKernel(typeof(VGACompilerCrash.Kernel).Assembly.Location); + //engine.AddKernel(typeof(SimpleStructsAndArraysTest.Kernel).Assembly.Location); + //engine.AddKernel(typeof(VGACompilerCrash.Kernel).Assembly.Location); // known bugs, therefor disabled for now: } diff --git a/Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs b/Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs index f768cb556..997e3646d 100644 --- a/Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs +++ b/Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs @@ -70,6 +70,9 @@ namespace Cosmos.TestRunner.Core xBochs.OnShutDown = (a, b) => { }; + xBochs.RedirectOutput = true; + xBochs.LogError = s => OutputHandler.LogDebugMessage(s); + xBochs.LogOutput = s => OutputHandler.LogDebugMessage(s); mBochsRunning = true; xBochs.Start(); diff --git a/Tests/Cosmos.TestRunner.Core/OutputHandlerBase.cs b/Tests/Cosmos.TestRunner.Core/OutputHandlerBase.cs index 2efd4aecb..460af4ac3 100644 --- a/Tests/Cosmos.TestRunner.Core/OutputHandlerBase.cs +++ b/Tests/Cosmos.TestRunner.Core/OutputHandlerBase.cs @@ -8,6 +8,7 @@ namespace Cosmos.TestRunner.Core { public abstract void ExecuteKernelStart(string assemblyName); public abstract void ExecuteKernelEnd(string assemblyName); + public abstract void LogDebugMessage(string message); public abstract void LogMessage(string message); public abstract void LogError(string message); public abstract void ExecutionStart(); diff --git a/Tests/Cosmos.TestRunner.Core/OutputHandlerConsole.cs b/Tests/Cosmos.TestRunner.Core/OutputHandlerConsole.cs index 95f70cd9c..b13eb0079 100644 --- a/Tests/Cosmos.TestRunner.Core/OutputHandlerConsole.cs +++ b/Tests/Cosmos.TestRunner.Core/OutputHandlerConsole.cs @@ -46,6 +46,11 @@ namespace Cosmos.TestRunner.Core mLogLevel = 1; } + public override void LogDebugMessage(string message) + { + + } + public override void RunConfigurationStart(RunConfiguration configuration) { } diff --git a/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs b/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs index b7cee74a6..5df3d437c 100644 --- a/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs +++ b/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs @@ -42,6 +42,20 @@ namespace Cosmos.TestRunner.Core xItem.Attributes.Append(NewXmlAttribute("Duration", mKernelStopwatch.Elapsed.ToString("c"))); } + public override void LogDebugMessage(string message) + { + var xParent = mCurrentNode.Peek(); + var xNode = xParent.SelectSingleNode("./DebugMessages"); + if (xNode == null) + { + xNode = mDocument.CreateElement("DebugMessages"); + xParent.PrependChild(xNode); + } + var xItem = mDocument.CreateElement("Message"); + xItem.InnerText = message; + xNode.AppendChild(xItem); + } + public override void LogMessage(string message) { var xParent = mCurrentNode.Peek(); diff --git a/source/Cosmos.Debug.VSDebugEngine/Host/Bochs.cs b/source/Cosmos.Debug.VSDebugEngine/Host/Bochs.cs index b5497a829..5491ff9f8 100644 --- a/source/Cosmos.Debug.VSDebugEngine/Host/Bochs.cs +++ b/source/Cosmos.Debug.VSDebugEngine/Host/Bochs.cs @@ -72,6 +72,11 @@ namespace Cosmos.Debug.VSDebugEngine.Host } } + public bool RedirectOutput = false; + + public Action LogOutput; + public Action LogError; + /// Initialize and start the Bochs process. public override void Start() { @@ -86,12 +91,31 @@ namespace Cosmos.Debug.VSDebugEngine.Host _bochsStartInfo.Arguments = string.Format("-q -f \"{0}\"", _bochsConfigurationFile.FullName); _bochsStartInfo.WorkingDirectory = _bochsConfigurationFile.Directory.FullName; _bochsStartInfo.UseShellExecute = false; - + if (RedirectOutput) + { + if (LogOutput == null) + { + throw new Exception("No LogOutput handler specified!"); + } + if (LogError == null) + { + throw new Exception("No LogError handler specified!"); + } + _bochsStartInfo.RedirectStandardOutput = true; + _bochsStartInfo.RedirectStandardError = true; + _bochsProcess.OutputDataReceived += (sender, args) => LogOutput(args.Data); + _bochsProcess.ErrorDataReceived += (sender, args) => LogError(args.Data); + } // Register for process completion event so that we can funnel it to any code that // subscribed to this event in our base class. _bochsProcess.EnableRaisingEvents = true; _bochsProcess.Exited += ExitCallback; _bochsProcess.Start(); + if (RedirectOutput) + { + _bochsProcess.BeginErrorReadLine(); + _bochsProcess.BeginOutputReadLine(); + } return; } From 1156f38c13dfb141b5038de4c1e95d3d110c5af8 Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 15:46:15 +0200 Subject: [PATCH 10/16] Continuing improvements to test runner. (#143) --- .../DefaultEngineConfiguration.cs | 4 +- Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs | 2 - .../OutputHandlerConsole.cs | 24 ++++++++++-- Tests/Cosmos.TestRunner/Program.cs | 4 +- Tests/SimpleStructsAndArraysTest/Kernel.cs | 39 ++++++++++++++++--- 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/Tests/Cosmos.TestRunner.Core/DefaultEngineConfiguration.cs b/Tests/Cosmos.TestRunner.Core/DefaultEngineConfiguration.cs index ed689f088..335ed190e 100644 --- a/Tests/Cosmos.TestRunner.Core/DefaultEngineConfiguration.cs +++ b/Tests/Cosmos.TestRunner.Core/DefaultEngineConfiguration.cs @@ -12,8 +12,8 @@ namespace Cosmos.TestRunner.Core } engine.AddKernel(typeof(Cosmos.Compiler.Tests.SimpleWriteLine.Kernel.Kernel).Assembly.Location); - //engine.AddKernel(typeof(SimpleStructsAndArraysTest.Kernel).Assembly.Location); - //engine.AddKernel(typeof(VGACompilerCrash.Kernel).Assembly.Location); + engine.AddKernel(typeof(SimpleStructsAndArraysTest.Kernel).Assembly.Location); + engine.AddKernel(typeof(VGACompilerCrash.Kernel).Assembly.Location); // known bugs, therefor disabled for now: } diff --git a/Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs b/Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs index 997e3646d..fe92c8c89 100644 --- a/Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs +++ b/Tests/Cosmos.TestRunner.Core/Engine.Bochs.cs @@ -82,7 +82,6 @@ namespace Cosmos.TestRunner.Core mKernelResultSet = false; Interlocked.Exchange(ref mSucceededAssertions, 0); - Console.WriteLine("Bochs started"); while (mBochsRunning) { Thread.Sleep(50); @@ -99,7 +98,6 @@ namespace Cosmos.TestRunner.Core OutputHandler.SetKernelTestResult(true, null); } OutputHandler.SetKernelSucceededAssertionsCount(mSucceededAssertions); - Console.WriteLine("Stopping bochs now"); } finally { diff --git a/Tests/Cosmos.TestRunner.Core/OutputHandlerConsole.cs b/Tests/Cosmos.TestRunner.Core/OutputHandlerConsole.cs index b13eb0079..4ecb4d2a5 100644 --- a/Tests/Cosmos.TestRunner.Core/OutputHandlerConsole.cs +++ b/Tests/Cosmos.TestRunner.Core/OutputHandlerConsole.cs @@ -15,13 +15,13 @@ namespace Cosmos.TestRunner.Core Log("Running task '" + taskName + "'"); mCurrentTaskStopwatch.Reset(); mCurrentTaskStopwatch.Start(); - mLogLevel = 3; + mLogLevel ++; } public override void TaskEnd(string taskName) { mCurrentTaskStopwatch.Stop(); - mLogLevel = 2; + mLogLevel --; Log("Done running task '" + taskName + "'. Took " + mCurrentTaskStopwatch.Elapsed); } @@ -35,6 +35,9 @@ namespace Cosmos.TestRunner.Core mLogLevel = 0; Log("Done executing"); Log("Took " + mExecutionStopwatch.Elapsed); + + Log(String.Format("{0} kernels succeeded their tests", mNumberOfSuccesses)); + Log(String.Format("{0} kernels failed their tests", mNumberOfFailures)); } public override void ExecutionStart() @@ -53,10 +56,13 @@ namespace Cosmos.TestRunner.Core public override void RunConfigurationStart(RunConfiguration configuration) { + Log(string.Format("Start configuration. IsELF = {0}", configuration.IsELF)); + mLogLevel++; } public override void RunConfigurationEnd(RunConfiguration configuration) { + mLogLevel --; } public override void LogError(string message) @@ -66,13 +72,13 @@ namespace Cosmos.TestRunner.Core public override void LogMessage(string message) { - Log(message); } public override void ExecuteKernelEnd(string assemblyName) { mCurrentKernelStopwatch.Stop(); Log("Done running kernel. Took " + mCurrentKernelStopwatch.Elapsed); + mLogLevel--; } public override void ExecuteKernelStart(string assemblyName) @@ -80,6 +86,7 @@ namespace Cosmos.TestRunner.Core Log("Starting kernel '" + assemblyName + "'"); mCurrentKernelStopwatch.Reset(); mCurrentKernelStopwatch.Start(); + mLogLevel++; } private int mLogLevel; @@ -93,8 +100,19 @@ namespace Cosmos.TestRunner.Core public override void SetKernelTestResult(bool succeeded, string message) { Log(string.Format("Success = {0}, Message = '{1}'", succeeded, message)); + if (succeeded) + { + mNumberOfSuccesses++; + } + else + { + mNumberOfFailures++; + } } + private int mNumberOfSuccesses = 0; + private int mNumberOfFailures = 0; + public override void SetKernelSucceededAssertionsCount(int succeededAssertions) { } diff --git a/Tests/Cosmos.TestRunner/Program.cs b/Tests/Cosmos.TestRunner/Program.cs index e47328c42..1efd70de1 100644 --- a/Tests/Cosmos.TestRunner/Program.cs +++ b/Tests/Cosmos.TestRunner/Program.cs @@ -15,8 +15,8 @@ namespace Cosmos.TestRunner.Console DefaultEngineConfiguration.Apply(xEngine); - xEngine.OutputHandler = new OutputHandlerXml(@"c:\data\CosmosTests.xml"); - //xEngine.OutputHandler = new OutputHandlerConsole(); + //xEngine.OutputHandler = new OutputHandlerXml(@"c:\data\CosmosTests.xml"); + xEngine.OutputHandler = new OutputHandlerConsole(); xEngine.Execute(); } } diff --git a/Tests/SimpleStructsAndArraysTest/Kernel.cs b/Tests/SimpleStructsAndArraysTest/Kernel.cs index 7e4052644..81572fcd6 100644 --- a/Tests/SimpleStructsAndArraysTest/Kernel.cs +++ b/Tests/SimpleStructsAndArraysTest/Kernel.cs @@ -108,8 +108,6 @@ namespace SimpleStructsAndArraysTest Assert.IsTrue(xItem2.E == 5, "xItem2.E == 5"); Console.Write("E: "); Console.WriteLine(xItem2.E); - - TestController.Completed(); } private class KVPClass @@ -199,7 +197,7 @@ namespace SimpleStructsAndArraysTest { get { - Assert.IsTrue(index == ExpectedIndex, "index = " + ExpectedIndex); + Assert.IsTrue(index == ExpectedIndex, "index == " + ExpectedIndex); if (index >= this._size) { throw new Exception("Out of range!"); @@ -212,7 +210,7 @@ namespace SimpleStructsAndArraysTest } - protected static void TestSimpleItemsInArray() + protected static void TestOurList() { Assert.IsTrue(true, "Start of test"); var xListClasses = new OurList(); @@ -243,11 +241,40 @@ namespace SimpleStructsAndArraysTest Assert.AreEqual(5, xStructItem.Value, "xListStructs[1].Value == 5"); } + protected static void TestStandardList() + { + Assert.IsTrue(true, "Start of test"); + var xListClasses = new List(); + var xListStructs = new List(); + + xListClasses.Add(new KVPClass { Key = 1, Value = 2 }); + xListClasses.Add(new KVPClass { Key = 2, Value = 5 }); + + var xListItem = xListClasses[0]; + Assert.AreEqual(1, xListItem.Key, "xListClasses[0].Key == 1"); + Assert.AreEqual(2, xListItem.Value, "xListClasses[0].Value == 2"); + xListItem = xListClasses[1]; + Assert.AreEqual(2, xListItem.Key, "xListClasses[1].Key == 2"); + Assert.AreEqual(5, xListItem.Value, "xListClasses[1].Value == 5"); + + xListStructs.Add(new KVPStruct { Key = 1, Value = 2 }); + xListStructs.Add(new KVPStruct { Key = 2, Value = 5 }); + + var xStructItem = xListStructs[0]; + Assert.AreEqual(1, xStructItem.Key, "xListStructs[0].Key == 1"); + Assert.AreEqual(2, xStructItem.Value, "xListStructs[0].Value == 2"); + xStructItem = xListStructs[1]; + Assert.AreEqual(2, xStructItem.Key, "xListStructs[1].Key == 2"); + Assert.AreEqual(5, xStructItem.Value, "xListStructs[1].Value == 5"); + } + protected override void Run() { TestStep1(); - TestSimpleItemsInArray(); - Assert.IsTrue(true, "After TestSimpleItemsInArray"); + TestOurList(); + Assert.IsTrue(true, "After TestOurList"); + TestStandardList(); + Assert.IsTrue(true, "After TestStandardList"); TestController.Completed(); } } From faad7cf9c59b2131b959d33e4ee0473748e9e653 Mon Sep 17 00:00:00 2001 From: Matthijs ter Woord Date: Sun, 5 Jul 2015 16:05:35 +0200 Subject: [PATCH 11/16] Fix the test runner, so it can save the details of a run. This is all that's the current high priority part of #143 --- .../Cosmos.TestRunner.Core.csproj | 1 + .../MultiplexingOutputHandler.cs | 92 +++++++++++++++++++ .../OutputHandlerXml.cs | 10 +- .../Cosmos.TestRunner.csproj | 1 + Tests/Cosmos.TestRunner/Program.cs | 25 ++++- 5 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 Tests/Cosmos.TestRunner.Core/MultiplexingOutputHandler.cs diff --git a/Tests/Cosmos.TestRunner.Core/Cosmos.TestRunner.Core.csproj b/Tests/Cosmos.TestRunner.Core/Cosmos.TestRunner.Core.csproj index 04a501127..3a3f48991 100644 --- a/Tests/Cosmos.TestRunner.Core/Cosmos.TestRunner.Core.csproj +++ b/Tests/Cosmos.TestRunner.Core/Cosmos.TestRunner.Core.csproj @@ -52,6 +52,7 @@ Engine.cs + diff --git a/Tests/Cosmos.TestRunner.Core/MultiplexingOutputHandler.cs b/Tests/Cosmos.TestRunner.Core/MultiplexingOutputHandler.cs new file mode 100644 index 000000000..d6b88f663 --- /dev/null +++ b/Tests/Cosmos.TestRunner.Core/MultiplexingOutputHandler.cs @@ -0,0 +1,92 @@ +using System; + +namespace Cosmos.TestRunner.Core +{ + public class MultiplexingOutputHandler: OutputHandlerBase + { + private readonly OutputHandlerBase[] mTargets; + + public MultiplexingOutputHandler(params OutputHandlerBase[] targets) + { + mTargets = targets; + } + + private void RunOnTargets(Action action) + { + foreach (var xTarget in mTargets) + { + action(xTarget); + } + } + + public override void ExecuteKernelStart(string assemblyName) + { + RunOnTargets(t => t.ExecuteKernelStart(assemblyName)); + } + + public override void ExecuteKernelEnd(string assemblyName) + { + RunOnTargets(t => t.ExecuteKernelEnd(assemblyName)); + } + + public override void LogDebugMessage(string message) + { + RunOnTargets(t => t.LogDebugMessage(message)); + } + + public override void LogMessage(string message) + { + RunOnTargets(t => t.LogMessage(message)); + } + + public override void LogError(string message) + { + RunOnTargets(t => t.LogError(message)); + } + + public override void ExecutionStart() + { + RunOnTargets(t => t.ExecutionStart()); + } + + public override void ExecutionEnd() + { + RunOnTargets(t => t.ExecutionEnd()); + } + + public override void UnhandledException(Exception exception) + { + RunOnTargets(t => t.UnhandledException(exception)); + } + + public override void TaskStart(string taskName) + { + RunOnTargets(t => t.TaskStart(taskName)); + } + + public override void TaskEnd(string taskName) + { + RunOnTargets(t => t.TaskEnd(taskName)); + } + + public override void SetKernelTestResult(bool succeeded, string message) + { + RunOnTargets(t => t.SetKernelTestResult(succeeded, message)); + } + + public override void RunConfigurationStart(RunConfiguration configuration) + { + RunOnTargets(t => t.RunConfigurationStart(configuration)); + } + + public override void RunConfigurationEnd(RunConfiguration configuration) + { + RunOnTargets(t => t.RunConfigurationEnd(configuration)); + } + + public override void SetKernelSucceededAssertionsCount(int succeededAssertions) + { + RunOnTargets(t => t.SetKernelSucceededAssertionsCount(succeededAssertions)); + } + } +} diff --git a/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs b/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs index 5df3d437c..3039d204a 100644 --- a/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs +++ b/Tests/Cosmos.TestRunner.Core/OutputHandlerXml.cs @@ -10,15 +10,13 @@ namespace Cosmos.TestRunner.Core { public partial class OutputHandlerXml: OutputHandlerBase { - private readonly string mFilename; private XmlDocument mDocument; private bool mConfigurationSucceeded = false; private bool mExecutionSucceeded = false; - public OutputHandlerXml(string filename) + public OutputHandlerXml() { - mFilename = filename; } public override void ExecuteKernelStart(string assemblyName) @@ -89,10 +87,14 @@ namespace Cosmos.TestRunner.Core mExecutionStopwatch.Stop(); mDocument.DocumentElement.Attributes.Append(NewXmlAttribute("Duration", mExecutionStopwatch.Elapsed.ToString("c"))); mDocument.DocumentElement.Attributes.Append(NewXmlAttribute("Succeeded", mExecutionSucceeded.ToString())); - mDocument.Save(mFilename); mCurrentNode.Pop(); } + public void SaveToFile(string filename) + { + mDocument.Save(filename); + } + private Stack mCurrentNode = new Stack(); private Stopwatch mTaskStopwatch; private Stopwatch mConfigurationStopwatch; diff --git a/Tests/Cosmos.TestRunner/Cosmos.TestRunner.csproj b/Tests/Cosmos.TestRunner/Cosmos.TestRunner.csproj index 5532f01fc..a515dcc2a 100644 --- a/Tests/Cosmos.TestRunner/Cosmos.TestRunner.csproj +++ b/Tests/Cosmos.TestRunner/Cosmos.TestRunner.csproj @@ -34,6 +34,7 @@ + diff --git a/Tests/Cosmos.TestRunner/Program.cs b/Tests/Cosmos.TestRunner/Program.cs index 1efd70de1..6e6a901f8 100644 --- a/Tests/Cosmos.TestRunner/Program.cs +++ b/Tests/Cosmos.TestRunner/Program.cs @@ -3,21 +3,42 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows.Forms; using Cosmos.TestRunner.Core; +using Microsoft.Win32; namespace Cosmos.TestRunner.Console { class Program { + [STAThread] static void Main(string[] args) { var xEngine = new Engine(); DefaultEngineConfiguration.Apply(xEngine); - //xEngine.OutputHandler = new OutputHandlerXml(@"c:\data\CosmosTests.xml"); - xEngine.OutputHandler = new OutputHandlerConsole(); + var xOutputXml = new OutputHandlerXml(); + xEngine.OutputHandler = new MultiplexingOutputHandler( + xOutputXml, + new OutputHandlerConsole()); + xEngine.Execute(); + + global::System.Console.WriteLine("Do you want to save test run details?"); + global::System.Console.Write("Type yes, or nothing to just exit: "); + var xResult = global::System.Console.ReadLine(); + if (xResult != null && xResult.Equals("yes", StringComparison.OrdinalIgnoreCase)) + { + var xSaveDialog = new SaveFileDialog(); + xSaveDialog.Filter = "XML documents|*.xml"; + if (xSaveDialog.ShowDialog() != DialogResult.OK) + { + return; + } + + xOutputXml.SaveToFile(xSaveDialog.FileName); + } } } } From 39281a65b5a73873ec5983ebd1c0d456710bb993 Mon Sep 17 00:00:00 2001 From: Joshua Zenn Date: Tue, 7 Jul 2015 09:05:57 -0400 Subject: [PATCH 12/16] Create CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..fdca26b26 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1 @@ +CosmosOS is a volunteer effort. We encourage you to pitch in. Join the team! From eec563b84f88a8ab042e09286109a4ffd2d0285c Mon Sep 17 00:00:00 2001 From: Joshua Zenn Date: Tue, 7 Jul 2015 09:09:38 -0400 Subject: [PATCH 13/16] Update CONTRIBUTING.md --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fdca26b26..1a1b4d18e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1,6 @@ CosmosOS is a volunteer effort. We encourage you to pitch in. Join the team! + + +Thanks! + +Cosmos Team From 08e5112c80a16453467e9ab2c1ecaca3ae3d1b16 Mon Sep 17 00:00:00 2001 From: Joshua Zenn Date: Tue, 7 Jul 2015 09:23:32 -0400 Subject: [PATCH 14/16] Update CONTRIBUTING.md --- CONTRIBUTING.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1a1b4d18e..684ccdebd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,13 @@ CosmosOS is a volunteer effort. We encourage you to pitch in. Join the team! +- Before you begin work, make sure to clear it with the project owners. It will save a lot of time down the road. +- Fork the project over to your account, do not request repostory access. +- Please don't "bump" your issue(s). If it has been filed, we have seen it and are working on it. + +Want to get started contributing to Cosmos? Check out the open issues page: +- [Medium priority](https://github.com/CosmosOS/Cosmos/labels/priority_medium) +- [High priority](https://github.com/CosmosOS/Cosmos/issues?q=is%3Aopen+is%3Aissue+label%3Apriority_high) + Thanks! From 268385fbb4c100655ff9afb123899108ecbd21f1 Mon Sep 17 00:00:00 2001 From: Joshua Zenn Date: Tue, 7 Jul 2015 09:27:08 -0400 Subject: [PATCH 15/16] Update CONTRIBUTING.md --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 684ccdebd..2904b43a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,11 +2,11 @@ CosmosOS is a volunteer effort. We encourage you to pitch in. Join the team! - Before you begin work, make sure to clear it with the project owners. It will save a lot of time down the road. - Fork the project over to your account, do not request repostory access. -- Please don't "bump" your issue(s). If it has been filed, we have seen it and are working on it. +- Please don't "bump" your issue(s). Want to get started contributing to Cosmos? Check out the open issues page: -- [Medium priority](https://github.com/CosmosOS/Cosmos/labels/priority_medium) - [High priority](https://github.com/CosmosOS/Cosmos/issues?q=is%3Aopen+is%3Aissue+label%3Apriority_high) +- [Medium priority](https://github.com/CosmosOS/Cosmos/labels/priority_medium) Thanks! From 3073f3ae00d481640746dc84569ead8a1ad09a45 Mon Sep 17 00:00:00 2001 From: Joshua Zenn Date: Tue, 7 Jul 2015 09:29:56 -0400 Subject: [PATCH 16/16] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2904b43a0..41d68cfcc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ CosmosOS is a volunteer effort. We encourage you to pitch in. Join the team! - Before you begin work, make sure to clear it with the project owners. It will save a lot of time down the road. - Fork the project over to your account, do not request repostory access. -- Please don't "bump" your issue(s). +- Please don't "bump" your issue(s). If you've filed it, we have seen it. Want to get started contributing to Cosmos? Check out the open issues page: - [High priority](https://github.com/CosmosOS/Cosmos/issues?q=is%3Aopen+is%3Aissue+label%3Apriority_high)