diff --git a/framework-dotnet/src/lib/MBS.Core/Application.cs b/framework-dotnet/src/lib/MBS.Core/Application.cs
index 024c65c..9c1bcb3 100644
--- a/framework-dotnet/src/lib/MBS.Core/Application.cs
+++ b/framework-dotnet/src/lib/MBS.Core/Application.cs
@@ -1,4 +1,6 @@
-namespace MBS.Core;
+using System.ComponentModel;
+
+namespace MBS.Core;
public class Application
{
@@ -8,12 +10,224 @@ public class Application
protected virtual void OnStartup(EventArgs e)
{
}
+ public event ApplicationActivatedEventHandler BeforeActivated;
+ protected virtual void OnBeforeActivated(ApplicationActivatedEventArgs e)
+ {
+ BeforeActivated?.Invoke(this, e);
+ }
+
+ public event ApplicationActivatedEventHandler Activated;
protected virtual void OnActivated(ApplicationActivatedEventArgs e)
+ {
+ Activated?.Invoke(this, e);
+ }
+
+
+ public event ApplicationActivatedEventHandler AfterActivated;
+ protected virtual void OnAfterActivated(ApplicationActivatedEventArgs e)
+ {
+ AfterActivated?.Invoke(this, e);
+ }
+
+ ///
+ /// Parses the option.
+ ///
+ /// true, if option was parsed, false otherwise.
+ /// Arguments.
+ /// Index.
+ /// The list into which to add the option if it has been specified.
+ /// The set of available options.
+ private bool ParseOption(string[] args, ref int index, IList list, CommandLineOption.CommandLineOptionCollection optionSet)
+ {
+ string longOptionPrefix = "--", shortOptionPrefix = "-";
+
+ bool breakout = false;
+ if (args[index].StartsWith(shortOptionPrefix) && args[index].Length == (shortOptionPrefix.Length + 1))
+ {
+ char shortOptionChar = args[index][args[index].Length - 1];
+ CommandLineOption option = optionSet[shortOptionChar];
+ if (option != null)
+ {
+ if (option.Abbreviation == shortOptionChar)
+ {
+ if (option.Type != CommandLineOptionValueType.None)
+ {
+ index++;
+ option.Value = args[index];
+ }
+ else
+ {
+ option.Value = true;
+ }
+
+ if (list != null)
+ list.Add(option);
+ }
+ }
+ else
+ {
+ list.Add(new CommandLineOption() { Abbreviation = shortOptionChar });
+ }
+ }
+ else if (args[index].StartsWith(longOptionPrefix))
+ {
+ // long option format is --name[=value]
+ string name = args[index].Substring(longOptionPrefix.Length);
+ string value = null;
+ if (name.Contains("="))
+ {
+ int idx = name.IndexOf('=');
+ value = name.Substring(idx + 1);
+ name = name.Substring(0, idx);
+ }
+ CommandLineOption option = optionSet[name];
+ if (option != null)
+ {
+ if (option.Type != CommandLineOptionValueType.None)
+ {
+ // index++;
+ // option.Value = args[index];
+ if (!name.Contains("="))
+ {
+ // already taken care of the true case above
+ if (index + 1 < args.Length)
+ {
+ index++;
+ value = args[index];
+ }
+ }
+ option.Value = value;
+ }
+ else
+ {
+ option.Value = true;
+ }
+ list.Add(option);
+ }
+ else
+ {
+ list.Add(new CommandLineOption() { Name = name });
+ }
+ }
+ else
+ {
+ // we have reached a non-option
+ return true;
+ }
+ return false;
+ }
+
+ protected virtual void OnBeforeStartInternal(CancelEventArgs e)
{
}
protected virtual int StartInternal()
{
+ CancelEventArgs ce = new CancelEventArgs();
+ OnBeforeStartInternal(ce);
+ if (ce.Cancel)
+ return 2;
+
+ CommandLine cline = new CommandLine();
+ string[] args = CommandLine.Arguments;
+
+ if (args.Length > 0)
+ {
+ int i = 0;
+ for (i = 0; i < args.Length; i++)
+ {
+ if (ParseOption(args, ref i, cline.Options, CommandLine.Options))
+ break;
+ }
+
+ // we have finished parsing the first set of options ("global" options)
+ // now we see if we have commands
+ if (CommandLine.Commands.Count > 0 && i < args.Length)
+ {
+ // we support commands like git and apt, "appname --app-global-options --command-options"
+ CommandLineCommand cmd = CommandLine.Commands[args[i]];
+ if (cmd != null)
+ {
+ for (i++; i < args.Length; i++)
+ {
+ if (ParseOption(args, ref i, cline.Options, cmd.Options))
+ break;
+ }
+
+ cline.Command = cmd;
+ }
+ else
+ {
+ // assume filename
+ }
+ }
+
+ for (/* intentionally left blank */; i < args.Length; i++)
+ {
+ cline.FileNames.Add(args[i]);
+ }
+ }
+
+ ApplicationActivatedEventArgs e = new ApplicationActivatedEventArgs(true, ApplicationActivationType.CommandLineLaunch, cline);
+
+ if (CommandLine.Options["help"]?.Value is bool && ((bool)CommandLine.Options["help"]?.Value) == true)
+ {
+ if (ShowCommandLineHelp(out int resultCode))
+ {
+ return resultCode;
+ }
+ }
+
+ OnStartup(EventArgs.Empty);
+ if (cline.Command != null && cline.Command.ActivationDelegate != null)
+ {
+ OnBeforeActivated(e);
+ if (!e.Success)
+ {
+ Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
+ return e.ExitCode;
+ }
+
+ // use the activation delegate instead of calling OnActivated
+ cline.Command.ActivationDelegate(e);
+ if (!e.Success)
+ {
+ Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
+ return e.ExitCode;
+ }
+
+ OnAfterActivated(e);
+ if (!e.Success)
+ {
+ Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
+ return e.ExitCode;
+ }
+ }
+ else
+ {
+ OnBeforeActivated(e);
+ if (!e.Success)
+ {
+ Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
+ return e.ExitCode;
+ }
+
+ OnActivated(e);
+ if (!e.Success)
+ {
+ Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
+ return e.ExitCode;
+ }
+
+ OnAfterActivated(e);
+ if (!e.Success)
+ {
+ Console.WriteLine(String.Format("Try '{0} --help' for more information.", ShortName));
+ return e.ExitCode;
+ }
+ }
+ return e.ExitCode;
+ /*
OnStartup(EventArgs.Empty);
CommandLine cline = new CommandLine();
@@ -23,6 +237,7 @@ public class Application
OnActivated(e);
return e.ExitCode;
+ */
}
public int Start()
@@ -43,4 +258,235 @@ public class Application
StopInternal(exitCode);
}
+ private string _UniqueName = null;
+ public string UniqueName
+ {
+ get
+ {
+ if (_UniqueName == null)
+ {
+ return ShortName;
+ }
+ return _UniqueName;
+ }
+ set
+ {
+ _UniqueName = value;
+ }
+ }
+
+ private string mvarBasePath = null;
+ public string BasePath
+ {
+ get
+ {
+ if (mvarBasePath == null)
+ {
+ // Set up the base path for the current application. Should this be able to be
+ // overridden with a switch (/basepath:...) ?
+ mvarBasePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
+ }
+ return mvarBasePath;
+ }
+ }
+
+ protected virtual string DataDirectoryName => ShortName;
+ public string[] EnumerateDataPaths() => EnumerateDataPaths(FindFileOptions.All);
+ public string[] EnumerateDataPaths(FindFileOptions options)
+ {
+ List list = new List();
+
+ string[] dataDirectoryNames = null;
+ if (AdditionalShortNames != null)
+ {
+ dataDirectoryNames = new string[AdditionalShortNames.Length + 1];
+ dataDirectoryNames[0] = DataDirectoryName;
+ for (int i = 0; i < AdditionalShortNames.Length; i++)
+ {
+ dataDirectoryNames[i + 1] = AdditionalShortNames[i];
+ }
+ }
+ else
+ {
+ dataDirectoryNames = new string[] { DataDirectoryName };
+ }
+
+ if ((options & FindFileOptions.All) == FindFileOptions.All)
+ {
+ // first look in the application root directory since this will override everything else
+ list.Add(BasePath);
+
+ foreach (string dataDirName in dataDirectoryNames)
+ {
+ if (Environment.OSVersion.Platform == PlatformID.Unix)
+ {
+ // if we are on Unix or Mac OS X, look in /etc/...
+ list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[]
+ {
+ String.Empty, // *nix root directory
+ "etc",
+ dataDirName
+ }));
+ }
+
+ // then look in /usr/share/universal-editor or C:\ProgramData\Mike Becker's Software\Universal Editor
+ list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[]
+ {
+ System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData),
+ dataDirName
+ }));
+
+ // then look in ~/.local/share/universal-editor or C:\Users\USERNAME\AppData\Local\Mike Becker's Software\Universal Editor
+ list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[]
+ {
+ System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData),
+ dataDirName
+ }));
+ }
+ }
+
+
+
+ //fixme: addd finddfileoption.userconfig, localdata, etc.
+ // now for the user-writable locations...
+
+ foreach (string dataDirName in dataDirectoryNames)
+ {
+ // then look in ~/.universal-editor or C:\Users\USERNAME\AppData\Roaming\Mike Becker's Software\Universal Editor
+ list.Add(String.Join(System.IO.Path.DirectorySeparatorChar.ToString(), new string[]
+ {
+ System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData),
+ dataDirName
+ }));
+ }
+ return list.ToArray();
+ }
+
+ public string ShortName { get; set; }
+ public virtual string[] AdditionalShortNames => null;
+
+ protected void PrintUsageStatement(CommandLineCommand command = null)
+ {
+ string shortOptionPrefix = CommandLine.ShortOptionPrefix ?? "-";
+ string longOptionPrefix = CommandLine.LongOptionPrefix ?? "--";
+
+ Console.Write("usage: {0} ", ShortName);
+ foreach (CommandLineOption option in CommandLine.Options)
+ {
+ PrintUsageStatementOption(option);
+ }
+
+ if (CommandLine.HelpTextPrefix != null)
+ {
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine(CommandLine.HelpTextPrefix);
+ }
+
+ Console.WriteLine();
+
+ bool printDescriptions = true;
+ if (printDescriptions)
+ {
+ foreach (CommandLineOption option in CommandLine.Options)
+ {
+ Console.WriteLine(" {0}{1}", option.Abbreviation != '\0' ? String.Format("{0}{1}, {2}{3}", shortOptionPrefix, option.Abbreviation, longOptionPrefix, option.Name) : String.Format("{0}{1}", longOptionPrefix, option.Name), option.Description == null ? null : String.Format(" - {0}", option.Description));
+ }
+ }
+ // Console.Write("[]");
+
+ if (command != null)
+ {
+ Console.WriteLine(" {0}{1}", command.Name, command.Description == null ? null : String.Format(" - {0}", command.Description));
+ foreach (CommandLineOption option in command.Options)
+ {
+ PrintUsageStatementOption(option);
+ }
+ }
+ else
+ {
+ if (CommandLine.Commands.Count > 0)
+ {
+ Console.WriteLine(" []");
+ Console.WriteLine();
+
+ List commands = new List(CommandLine.Commands);
+ commands.Sort((x, y) =>
+ {
+ return x.Name.CompareTo(y.Name);
+ });
+ foreach (CommandLineCommand command1 in commands)
+ {
+ Console.WriteLine(" {0}{1}", command1.Name, command1.Description == null ? null : String.Format(" - {0}", command1.Description));
+ }
+ }
+ }
+
+ if (CommandLine.HelpTextSuffix != null)
+ {
+ Console.WriteLine();
+ Console.WriteLine(CommandLine.HelpTextSuffix);
+ }
+ }
+
+ private void PrintUsageStatementOption(CommandLineOption option)
+ {
+ Console.Write(" ");
+ if (option.Optional)
+ {
+ Console.Write('[');
+ }
+
+ string shortOptionPrefix = CommandLine.ShortOptionPrefix ?? "-";
+ string longOptionPrefix = CommandLine.LongOptionPrefix ?? "--";
+
+ if (option.Abbreviation != '\0')
+ {
+ Console.Write("{0}{1}", shortOptionPrefix, option.Abbreviation);
+ if (option.Type == CommandLineOptionValueType.Single)
+ {
+ Console.Write(" ");
+ }
+ else if (option.Type == CommandLineOptionValueType.Multiple)
+ {
+ Console.Write(" [,,...]");
+ }
+
+ Console.Write(" | {0}{1}", longOptionPrefix, option.Name);
+ if (option.Type == CommandLineOptionValueType.Single)
+ {
+ Console.Write("=");
+ }
+ else if (option.Type == CommandLineOptionValueType.Multiple)
+ {
+ Console.Write("=[,,...]");
+ }
+ }
+ else
+ {
+ Console.Write(longOptionPrefix ?? "--");
+ Console.Write("{0}", option.Name);
+ if (option.Type == CommandLineOptionValueType.Single)
+ {
+ Console.Write("=");
+ }
+ else if (option.Type == CommandLineOptionValueType.Multiple)
+ {
+ Console.Write("=[,,...]");
+ }
+ }
+ if (option.Optional)
+ {
+ Console.Write(']');
+ }
+ // Console.WriteLine();
+ }
+ protected virtual bool ShowCommandLineHelp(out int resultCode)
+ {
+ // bash: cd returns 2 if --help is specified OR invalid option selected, 1 if file not found
+ PrintUsageStatement();
+ resultCode = 2;
+ return true;
+ }
+
}
diff --git a/framework-dotnet/src/lib/MBS.Core/Collections/Generic/ExtensionMethods.cs b/framework-dotnet/src/lib/MBS.Core/Collections/Generic/ExtensionMethods.cs
index db03cbf..0b58403 100755
--- a/framework-dotnet/src/lib/MBS.Core/Collections/Generic/ExtensionMethods.cs
+++ b/framework-dotnet/src/lib/MBS.Core/Collections/Generic/ExtensionMethods.cs
@@ -55,7 +55,7 @@ namespace MBS.Core.Collections.Generic
return ((List)(cacheOfT[obj][typeof(T)])).ToArray();
}
- public static void AddRange(this IList list, IEnumerable items)
+ public static void AddRange(this ICollection list, IEnumerable items)
{
foreach (T item in items)
{
diff --git a/framework-dotnet/src/lib/MBS.Core/FindFileOptions.cs b/framework-dotnet/src/lib/MBS.Core/FindFileOptions.cs
new file mode 100644
index 0000000..473678d
--- /dev/null
+++ b/framework-dotnet/src/lib/MBS.Core/FindFileOptions.cs
@@ -0,0 +1,45 @@
+//
+// FindFileOptions.cs
+//
+// Author:
+// Michael Becker
+//
+// Copyright (c) 2022 Mike Becker's Software
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+using System;
+namespace MBS.Core;
+
+///
+/// Controls the behavior of relative file resolution.
+///
+[Flags()]
+public enum FindFileOptions
+{
+ ///
+ /// Returns all matching fully-qualified file paths across all global,
+ /// application, and user directories.
+ ///
+ All = 1,
+ ///
+ /// Returns only file paths that are writable by the user (i.e., in the
+ /// user's local or roaming data directory).
+ ///
+ UserWritable = 2,
+ ///
+ /// Allows the user to create a file if it does not exist (i.e., returns
+ /// a file name even if it does not exist)
+ ///
+ Create = 4
+}
diff --git a/framework-dotnet/src/lib/MBS.Core/NanoId.cs b/framework-dotnet/src/lib/MBS.Core/NanoId.cs
index 6259def..8349238 100755
--- a/framework-dotnet/src/lib/MBS.Core/NanoId.cs
+++ b/framework-dotnet/src/lib/MBS.Core/NanoId.cs
@@ -163,6 +163,8 @@ namespace MBS.Core
public const string DefaultAlphabet = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public const string DefaultAlphabetNoSpecialChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ public const string CapitalAlphabetNoSpecialChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ public const string CapitalAlphanumericNoSpecialChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static readonly CryptoRandom Random = new CryptoRandom();
///
diff --git a/framework-dotnet/src/lib/MBS.Core/Reflection/TypeLoader.cs b/framework-dotnet/src/lib/MBS.Core/Reflection/TypeLoader.cs
index 29e999e..eeab03f 100644
--- a/framework-dotnet/src/lib/MBS.Core/Reflection/TypeLoader.cs
+++ b/framework-dotnet/src/lib/MBS.Core/Reflection/TypeLoader.cs
@@ -197,16 +197,29 @@ public class TypeLoader
}
}
mvarAvailableTypes = types.ToArray();
+ /*
+ foreach (Type t in mvarAvailableTypes)
+ {
+ Console.WriteLine("Type load: {0}", t.FullName);
+ }
+ */
}
if (inheritsFrom != null)
{
List retval = new List();
- for (int iTyp = 0; iTyp < mvarAvailableTypes.Length; iTyp++)
+ foreach (Type t in mvarAvailableTypes)
{
- for (int jInh = 0; jInh < inheritsFrom.Length; jInh++)
+ foreach (Type inheritsFromType in inheritsFrom)
{
- if (mvarAvailableTypes[iTyp].IsSubclassOf(inheritsFrom[jInh])) retval.Add(mvarAvailableTypes[iTyp]);
+ if (t.FullName.Contains("Mini."))
+ {
+ Console.WriteLine(inheritsFromType.FullName + " ? inherits ? " + t.FullName);
+ }
+ if (t.IsSubclassOf(inheritsFromType))
+ {
+ retval.Add(t);
+ }
}
}
return retval.ToArray();
diff --git a/framework-dotnet/src/lib/MBS.Core/StreamExtensions.cs b/framework-dotnet/src/lib/MBS.Core/StreamExtensions.cs
index b1a5d14..9568243 100644
--- a/framework-dotnet/src/lib/MBS.Core/StreamExtensions.cs
+++ b/framework-dotnet/src/lib/MBS.Core/StreamExtensions.cs
@@ -19,6 +19,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+using System.Net.Http.Headers;
+
namespace MBS.Core;
public static class StreamExtensions
@@ -96,4 +98,27 @@ public static class StreamExtensions
}
_streamPositions[st].Push(st.Position);
}
+
+ public static byte[] ReadToEnd(this Stream st)
+ {
+ byte[] retval = new byte[0];
+ byte[] buffer = new byte[4096];
+
+ long j = 0;
+ bool remaining = true;
+ while (remaining)
+ {
+ int count = st.Read(buffer, 0, buffer.Length);
+ if (count < buffer.Length)
+ {
+ Array.Resize(ref buffer, count);
+ remaining = false;
+ }
+
+ Array.Resize(ref retval, retval.Length + buffer.Length);
+ Array.Copy(buffer, 0, retval, j, buffer.Length);
+ j += buffer.Length;
+ }
+ return retval;
+ }
}
\ No newline at end of file