From ec1a0196e2a3cb15f430d23ea3c0f36fd7102dc9 Mon Sep 17 00:00:00 2001 From: "J. Ritchie Carroll" Date: Tue, 16 Jun 2026 10:48:50 -0500 Subject: [PATCH 1/4] Updates for Linux compile --- src/Gemstone/Common.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Gemstone/Common.cs b/src/Gemstone/Common.cs index 14d3e14980..3d6b848411 100644 --- a/src/Gemstone/Common.cs +++ b/src/Gemstone/Common.cs @@ -616,7 +616,10 @@ public static ulong GetTotalPhysicalMemory() { if (IsPosixEnvironment) { - string output = Command.Execute("awk", "'/MemTotal/ {print $2}' /proc/meminfo").StandardOutput; + // Pass the awk program as a single argument using double quotes (which the .NET argument tokenizer + // groups and strips); single quotes are shell-only syntax and, since the command is executed without + // a shell, would be passed to awk literally - causing "awk: unexpected character '''". + string output = Command.Execute("awk", "\"/MemTotal/ {print $2}\" /proc/meminfo").StandardOutput; return ulong.Parse(output) * SI2.Kilo; } @@ -632,7 +635,9 @@ public static ulong GetAvailablePhysicalMemory() { if (IsPosixEnvironment) { - string output = Command.Execute("awk", "'/MemAvailable/ {print $2}' /proc/meminfo").StandardOutput; + // Double-quote the awk program so it is passed as a single argument; single quotes are shell-only + // syntax and would reach awk literally when executed without a shell (see GetTotalPhysicalMemory). + string output = Command.Execute("awk", "\"/MemAvailable/ {print $2}\" /proc/meminfo").StandardOutput; return ulong.Parse(output) * SI2.Kilo; } From a336d3680164c20aa348f4e3332355f710605139 Mon Sep 17 00:00:00 2001 From: "J. Ritchie Carroll" Date: Fri, 29 May 2026 08:22:47 -0500 Subject: [PATCH 2/4] Improved legacy serialization binder --- src/Gemstone/Serialization.cs | 74 ++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/src/Gemstone/Serialization.cs b/src/Gemstone/Serialization.cs index 9b6a14adbe..1fd5978bed 100644 --- a/src/Gemstone/Serialization.cs +++ b/src/Gemstone/Serialization.cs @@ -73,29 +73,28 @@ private class LegacySerializationBinder : SerializationBinder // Perform namespace transformations that occurred when migrating to the Grid Solutions Framework // from various older versions of code with different namespaces string newTypeName = typeName - .Replace("TVA.", "Gemstone.") - .Replace("GSF.TimeSeries.", "Gemstone.Timeseries.") - .Replace("GSF.", "Gemstone.") - .Replace("TimeSeriesFramework.", "Gemstone.Timeseries.") + .Replace(".TimeSeries.", ".Timeseries.") // Updated Gemstone casing for timeseries namespace + .Replace("GSF.Units.EE", "Gemstone.Numeric.EE") // Gemstone assembly relocation of EE namespace + .Replace("TVA.Units.EE", "Gemstone.Numeric.EE") // Gemstone assembly relocation of EE namespace + .Replace("TimeSeriesFramework.", "Gemstone.Timeseries.") // 2007 TVA Code Library "TimeSeriesFramework" namespace .Replace("ConnectionTester.", "Gemstone.PhasorProtocols.") // PMU Connection Tester namespace - .Replace("TVA.Phasors.", "Gemstone.PhasorProtocols.") // 2007 TVA Code Library namespace - .Replace("Tva.Phasors.", "Gemstone.PhasorProtocols.") // 2008 TVA Code Library namespace - .Replace("BpaPdcStream", "BPAPDCstream") // 2013 GSF uppercase phasor protocol namespace - .Replace("FNet", "FNET") // 2013 GSF uppercase phasor protocol namespace - .Replace("Iec61850_90_5", "IEC61850_90_5") // 2013 GSF uppercase phasor protocol namespace - .Replace("Ieee1344", "IEEE1344") // 2013 GSF uppercase phasor protocol namespace - .Replace("IeeeC37_118", "IEEEC37_118"); // 2013 GSF uppercase phasor protocol namespace + .Replace("TVA.Phasors.", "Gemstone.PhasorProtocols.") // 2007 TVA Code Library "Phasors" namespace + .Replace("Tva.Phasors.", "Gemstone.PhasorProtocols.") // 2008 TVA Code Library "Phasors" namespace + .Replace("GSF.", "Gemstone.") // 2013+ GSF root namespace + .Replace("TVA.", "Gemstone.") // 2007 TVA Code Library root namespace + .Replace("Tva.", "Gemstone.") // 2008 TVA Code Library root namespace + .Replace("BpaPdcStream", "BPAPDCstream") // 2013 updated GSF casing for phasor protocol namespace + .Replace("FNet", "FNET") // 2013 updated GSF casing for phasor protocol namespace + .Replace("Iec61850_90_5", "IEC61850_90_5") // 2013 updated GSF casing for phasor protocol namespace + .Replace("Ieee1344", "IEEE1344") // 2013 updated GSF casing for phasor protocol namespace + .Replace("IeeeC37_118", "IEEEC37_118"); // 2013 updated GSF casing for phasor protocol namespace - // Check for 2009 TVA Code Library namespace + // Check for 2009 TVA Code Library "PhasorProtocols" namespace if (newTypeName.StartsWith("PhasorProtocols", StringComparison.Ordinal)) newTypeName = "Gemstone." + newTypeName; - // Check for 2014 LineFrequency type - if (newTypeName.Equals("GSF.PhasorProtocols.LineFrequency", StringComparison.Ordinal)) - newTypeName = "Gemstone.Numeric.EE.LineFrequency"; - - // Check for GSF LineFrequency type - if (newTypeName.Equals("GSF.Units.EE.LineFrequency", StringComparison.Ordinal)) + // Check for 2014 LineFrequency type (note: already replaced GSF with Gemstone here) + if (newTypeName.Equals("Gemstone.PhasorProtocols.LineFrequency", StringComparison.Ordinal)) newTypeName = "Gemstone.Numeric.EE.LineFrequency"; try @@ -128,8 +127,45 @@ private class LegacySerializationBinder : SerializationBinder // No type found; return null return null; } + + /// + /// Controls the binding of a serialized object to a type name and assembly name during serialization. + /// + /// + /// Maps current Gemstone types back to their legacy GSF names so that XML written by Gemstone code + /// remains readable by .NET Framework consumers (PMU Connection Tester, older openPDC builds, etc.) + /// that only know the GSF-era types. The Gemstone-side reader translates these names back via + /// , so round-trip identity is preserved. + /// + /// The runtime type being serialized. + /// On return, the legacy assembly name to emit. + /// On return, the legacy fully-qualified type name to emit. + public override void BindToName(Type serializedType, out string? assemblyName, out string? typeName) + { + string fullName = serializedType.FullName ?? serializedType.Name; + string typeNamespace = serializedType.Namespace ?? string.Empty; + string runtimeAssembly = serializedType.Assembly.GetName().Name ?? string.Empty; + + // Special case: Gemstone.Numeric.EE.* types (LineFrequency, PhasorType, etc.) historically + // lived in the GSF.Units.EE namespace inside the GSF.Core assembly. + if (typeNamespace == "Gemstone.Numeric.EE" || typeNamespace.StartsWith("Gemstone.Numeric.EE.", StringComparison.Ordinal)) + { + typeName = fullName.Replace("Gemstone.Numeric.EE", "GSF.Units.EE", StringComparison.Ordinal); + assemblyName = "GSF.Core"; + return; + } + + // General case: Gemstone.* → GSF.* (and Timeseries → TimeSeries casing flip). + typeName = fullName + .Replace("Gemstone.Timeseries.", "GSF.TimeSeries.", StringComparison.Ordinal) + .Replace("Gemstone.", "GSF.", StringComparison.Ordinal); + + assemblyName = runtimeAssembly + .Replace("Gemstone.Timeseries", "GSF.TimeSeries", StringComparison.Ordinal) + .Replace("Gemstone.", "GSF.", StringComparison.Ordinal); + } } - + /// /// Gets value for specified ; otherwise . /// From 35ccbd3f2229253a6913653847f096de98976036 Mon Sep 17 00:00:00 2001 From: "J. Ritchie Carroll" Date: Tue, 23 Jun 2026 15:32:28 -0500 Subject: [PATCH 3/4] Removed unused using directives --- src/Gemstone/Common.cs | 1 - src/Gemstone/Identity/UserInfoUnix.cs | 5 ----- src/Gemstone/Identity/UserInfoWindows.cs | 1 - .../StringExtensions/FuzzyStrings/LongestCommonSubstring.cs | 1 - 4 files changed, 8 deletions(-) diff --git a/src/Gemstone/Common.cs b/src/Gemstone/Common.cs index 3d6b848411..c080d0df9a 100644 --- a/src/Gemstone/Common.cs +++ b/src/Gemstone/Common.cs @@ -46,7 +46,6 @@ using System; using System.Collections; -using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; diff --git a/src/Gemstone/Identity/UserInfoUnix.cs b/src/Gemstone/Identity/UserInfoUnix.cs index 573e3bef6f..32807f207d 100644 --- a/src/Gemstone/Identity/UserInfoUnix.cs +++ b/src/Gemstone/Identity/UserInfoUnix.cs @@ -23,13 +23,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; using System.Linq; using System.Runtime.InteropServices; -using System.Security; -using System.Security.Principal; using System.Text; using Gemstone.Collections.CollectionExtensions; using Gemstone.Console; diff --git a/src/Gemstone/Identity/UserInfoWindows.cs b/src/Gemstone/Identity/UserInfoWindows.cs index d105f31553..3660b3caea 100644 --- a/src/Gemstone/Identity/UserInfoWindows.cs +++ b/src/Gemstone/Identity/UserInfoWindows.cs @@ -25,7 +25,6 @@ using System.Collections; using System.Collections.Generic; using System.DirectoryServices; -using System.Linq; using System.Management; using System.Reflection; using System.Runtime.InteropServices; diff --git a/src/Gemstone/StringExtensions/FuzzyStrings/LongestCommonSubstring.cs b/src/Gemstone/StringExtensions/FuzzyStrings/LongestCommonSubstring.cs index dd5bfc9c6e..dc16af2734 100644 --- a/src/Gemstone/StringExtensions/FuzzyStrings/LongestCommonSubstring.cs +++ b/src/Gemstone/StringExtensions/FuzzyStrings/LongestCommonSubstring.cs @@ -21,7 +21,6 @@ // //****************************************************************************************************** -using System; using System.Diagnostics.CodeAnalysis; using System.Text; From acedfc9e04310dbb3ca81ecd894d41831eda5064 Mon Sep 17 00:00:00 2001 From: StephenCWills Date: Wed, 15 Jul 2026 11:55:26 -0400 Subject: [PATCH 4/4] Do not convert empty string to null in StringExtensions.ConvertToType() --- src/Gemstone/StringExtensions/StringExtensions.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Gemstone/StringExtensions/StringExtensions.cs b/src/Gemstone/StringExtensions/StringExtensions.cs index 3a4c2e1693..fb9fc8eb5d 100644 --- a/src/Gemstone/StringExtensions/StringExtensions.cs +++ b/src/Gemstone/StringExtensions/StringExtensions.cs @@ -250,15 +250,19 @@ public static T ConvertToType(this string? value, CultureInfo? culture) /// public static object? ConvertToType(this string? value, Type type, CultureInfo? culture, bool suppressException = true) { - // Don't proceed further if string is empty. + // Handle the trivial string-to-string conversion + if (type == typeof(string)) + return value; + + // Don't proceed further if string is empty if (string.IsNullOrEmpty(value)) return null; - // Initialize return type if not specified. + // There is no way to guess what type the user intended to convert to if (type is null) throw new ArgumentNullException(nameof(type)); - // Initialize culture info if not specified. + // Initialize culture info if not specified culture ??= CultureInfo.InvariantCulture; // Handle array types as a special case