From cb6acf229da551283285cde23de1343ca2dca91f Mon Sep 17 00:00:00 2001 From: Stefano Moioli Date: Sat, 30 Dec 2017 01:37:17 +0100 Subject: [PATCH] Added Unix support for GLibPorts --- CLanguage/CCodeWriter.cs | 3 +- GLibPorts/CharExtensions.cs | 33 ++++ GLibPorts/File.cs | 31 ++++ GLibPorts/FileStream.cs | 62 +++---- GLibPorts/FileUtils.cs | 44 ++++- GLibPorts/GLib.cs | 4 + GLibPorts/GLib.csproj | 25 ++- GLibPorts/Module.cs | 14 +- GLibPorts/Native/IFileStream.cs | 15 ++ GLibPorts/Native/IModuleLoader.cs | 15 ++ GLibPorts/Native/IStrings.cs | 12 ++ GLibPorts/Native/Platform.cs | 30 ++++ GLibPorts/Native/Unix/FileStream.cs | 50 ++++++ GLibPorts/Native/Unix/NativeImports.cs | 93 ++++++++++ GLibPorts/Native/Unix/UnixFile.cs | 49 ++++++ GLibPorts/Native/Unix/UnixModuleLoader.cs | 29 ++++ GLibPorts/Native/Unix/UnixStrings.cs | 24 +++ GLibPorts/Native/Varargs.cs | 160 ------------------ GLibPorts/Native/Varargs/IVariableCombiner.cs | 12 ++ .../Native/Varargs/UnixVariableCombiner.cs | 55 ++++++ GLibPorts/Native/Varargs/VariableArgument.cs | 40 +++++ .../Native/Varargs/VariableDoubleArgument.cs | 25 +++ .../Native/Varargs/VariableIntegerArgument.cs | 21 +++ .../Native/Varargs/VariableStringArgument.cs | 43 +++++ .../Native/Varargs/Win32VariableCombiner.cs | 58 +++++++ GLibPorts/Native/Win32/FileStream.cs | 55 ++++++ .../{Win32.cs => Win32/NativeImports.cs} | 4 +- .../Native/{File.cs => Win32/Win32File.cs} | 39 ++--- GLibPorts/Native/Win32/Win32ModuleLoader.cs | 25 +++ GLibPorts/Native/Win32/Win32Strings.cs | 17 ++ GLibPorts/StringExtensions.cs | 7 +- GLibPorts/Utils.cs | 10 +- Lang/Code/CodeWriter.cs | 3 +- Lang/Parser/Parser.cs | 1 + 34 files changed, 859 insertions(+), 249 deletions(-) create mode 100644 GLibPorts/CharExtensions.cs create mode 100644 GLibPorts/File.cs create mode 100644 GLibPorts/Native/IFileStream.cs create mode 100644 GLibPorts/Native/IModuleLoader.cs create mode 100644 GLibPorts/Native/IStrings.cs create mode 100644 GLibPorts/Native/Platform.cs create mode 100644 GLibPorts/Native/Unix/FileStream.cs create mode 100644 GLibPorts/Native/Unix/NativeImports.cs create mode 100644 GLibPorts/Native/Unix/UnixFile.cs create mode 100644 GLibPorts/Native/Unix/UnixModuleLoader.cs create mode 100644 GLibPorts/Native/Unix/UnixStrings.cs delete mode 100644 GLibPorts/Native/Varargs.cs create mode 100644 GLibPorts/Native/Varargs/IVariableCombiner.cs create mode 100644 GLibPorts/Native/Varargs/UnixVariableCombiner.cs create mode 100644 GLibPorts/Native/Varargs/VariableArgument.cs create mode 100644 GLibPorts/Native/Varargs/VariableDoubleArgument.cs create mode 100644 GLibPorts/Native/Varargs/VariableIntegerArgument.cs create mode 100644 GLibPorts/Native/Varargs/VariableStringArgument.cs create mode 100644 GLibPorts/Native/Varargs/Win32VariableCombiner.cs create mode 100644 GLibPorts/Native/Win32/FileStream.cs rename GLibPorts/Native/{Win32.cs => Win32/NativeImports.cs} (98%) rename GLibPorts/Native/{File.cs => Win32/Win32File.cs} (55%) create mode 100644 GLibPorts/Native/Win32/Win32ModuleLoader.cs create mode 100644 GLibPorts/Native/Win32/Win32Strings.cs diff --git a/CLanguage/CCodeWriter.cs b/CLanguage/CCodeWriter.cs index 04d36ae..88628d8 100644 --- a/CLanguage/CCodeWriter.cs +++ b/CLanguage/CCodeWriter.cs @@ -1,4 +1,5 @@ using GLibPorts; +using GLibPorts.Native; using System; using System.Collections.Generic; using System.Diagnostics; @@ -44,7 +45,7 @@ public bool bol { private string temp_filename; private bool file_exists; - private GLib.FileStream stream; + private IFileStream stream; private int indent; private int current_line_number = 1; diff --git a/GLibPorts/CharExtensions.cs b/GLibPorts/CharExtensions.cs new file mode 100644 index 0000000..9fa1a69 --- /dev/null +++ b/GLibPorts/CharExtensions.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts { + public static class CharExtensions { + public static bool IsXDigit(this char @this) { + return GChar.isxdigit(@this); + } + + public static bool IsDigit(this char @this) { + return Char.IsDigit(@this); + } + + public static char ToLower(this char @this) { + return Char.ToLower(@this); + } + + public static char ToUpper(this char @this) { + return Char.ToUpper(@this); + } + + public static bool IsLetter(this char @this) { + return Char.IsLetter(@this); + } + + public static bool IsLetterOrDigit(this char @this) { + return Char.IsLetterOrDigit(@this); + } + } +} diff --git a/GLibPorts/File.cs b/GLibPorts/File.cs new file mode 100644 index 0000000..d5b4e03 --- /dev/null +++ b/GLibPorts/File.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts { + public partial class GLib { + internal class File { + public static IntPtr stdin { get; internal set; } + public static IntPtr stderr { get; internal set; } + public static IntPtr stdout { get; internal set; } + + public static void InitializeStatic() { + if (Utils.IsUnix()) { + Native.Unix.UnixFile.InitializeStatic(); + } else { + Native.Win32.Win32File.InitializeStatic(); + } + } + + public static void DisposeStatic() { + if (Utils.IsUnix()) { + Native.Unix.UnixFile.DisposeStatic(); + } else { + Native.Win32.Win32File.DisposeStatic(); + } + } + } + } +} diff --git a/GLibPorts/FileStream.cs b/GLibPorts/FileStream.cs index 54c77b5..9efdba5 100644 --- a/GLibPorts/FileStream.cs +++ b/GLibPorts/FileStream.cs @@ -1,30 +1,30 @@ -using System; +using GLibPorts.Native; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using GLibPorts.Native; namespace GLibPorts { public partial class GLib { - public static FileStream stdin; - public static FileStream stderr; - public static FileStream stdout; - - public class FileStream : IDisposable { - public static void InitializeStatic() { - DisposeStatic(); - stdin = new FileStream(File.stdin); - stderr = new FileStream(File.stderr); - stdout = new FileStream(File.stdout); - } + public class FileStream { + public static IFileStream stdin { get; internal set; } + public static IFileStream stderr { get; internal set; } + public static IFileStream stdout { get; internal set; } private IntPtr stream; internal FileStream(IntPtr streamHandle) { stream = streamHandle; + } - Win32.setvbuf(stream, null, Win32._IONBF, 0); + public static void InitializeStatic() { + DisposeStatic(); + if (Utils.IsUnix()) { + Native.Unix.UnixFileStream.InitilizeStatic(); + } else { + Native.Win32.Win32FileStream.InitializeStatic(); + } } public static void DisposeStatic() { @@ -33,35 +33,11 @@ public static void DisposeStatic() { stdout?.Dispose(); } - public void Dispose() { - if (stream != IntPtr.Zero) { - Win32.fclose(stream); - stream = IntPtr.Zero; - } - } - - public int fileno() { - return Win32._fileno(stream); - } - - public int printf(string format, params VariableArgument[] args) { - return File.fprintf(stream, format, args); - } - - public int puts(string str) { - return Win32.fputs(str, stream); - } - - public int putc(int c) { - return Win32.putc(c, stream); - } - - public static FileStream fdopen(int fd, string mode) { - return new FileStream(Win32._fdopen(fd, mode)); - } - - public static FileStream open(string filename, string mode) { - return new FileStream(Win32.fopen(filename, mode)); + public static IFileStream open(string filePath, string mode) { + if (Utils.IsUnix()) + return Native.Unix.UnixFileStream.open(filePath, mode); + else + return Native.Win32.Win32FileStream.open(filePath, mode); } } } diff --git a/GLibPorts/FileUtils.cs b/GLibPorts/FileUtils.cs index 68ed8af..1cd8579 100644 --- a/GLibPorts/FileUtils.cs +++ b/GLibPorts/FileUtils.cs @@ -23,16 +23,50 @@ public static bool get_contents(string filename, out string contents, out ulong length = (ulong)contents.Length; return true; } + + //TODO(Smx) make an interface for the calls below + private static void close_unix(int outputfd) { + Native.Unix.NativeImports.close(outputfd); + } - public static void close(int outputfd) { - Win32._close(outputfd); + private static void close_win32(int outputfd) { + Native.Win32.NativeImports._close(outputfd); } - public static int mkstemp(string template, out string filename) { - filename = Win32.mktemp(template); + private static int mkstemp_unix(string template, out string filename) { + filename = Native.Unix.NativeImports.mktemp(template); + if (filename == null) + return -1; + return Native.Unix.NativeImports.open( + filename, + Native.Unix.NativeImports.O_RDWR | Native.Unix.NativeImports.O_CREAT, + 0700 + ); + } + + private static int mkstemp_win32(string template, out string filename) { + filename = Native.Win32.NativeImports.mktemp(template); if (filename == null) return -1; - return Win32._open(filename, Win32._O_RDWR | Win32._O_CREAT, 0700); + return Native.Win32.NativeImports._open( + filename, + Native.Win32.NativeImports._O_RDWR | Native.Win32.NativeImports._O_CREAT, + 0700 + ); + } + + public static void close(int outputfd) { + if (Utils.IsUnix()) + close_unix(outputfd); + else + close_win32(outputfd); + } + + public static int mkstemp(string template, out string filename) { + if (Utils.IsUnix()) + return mkstemp_unix(template, out filename); + else + return mkstemp_win32(template, out filename); } } } diff --git a/GLibPorts/GLib.cs b/GLibPorts/GLib.cs index c48468d..123f3ea 100644 --- a/GLibPorts/GLib.cs +++ b/GLibPorts/GLib.cs @@ -19,5 +19,9 @@ public static void GLibInitialize() { File.InitializeStatic(); FileStream.InitializeStatic(); } + + public static IFileStream stdin => FileStream.stdin; + public static IFileStream stderr => FileStream.stderr; + public static IFileStream stdout => FileStream.stdout; } } diff --git a/GLibPorts/GLib.csproj b/GLibPorts/GLib.csproj index 1d991d6..90ad9d1 100644 --- a/GLibPorts/GLib.csproj +++ b/GLibPorts/GLib.csproj @@ -49,6 +49,21 @@ + + + + + + + + + + + + + + + @@ -58,10 +73,14 @@ - - - + + + + + + + diff --git a/GLibPorts/Module.cs b/GLibPorts/Module.cs index 15d3eec..5f139d9 100644 --- a/GLibPorts/Module.cs +++ b/GLibPorts/Module.cs @@ -16,12 +16,18 @@ private Module(IntPtr handle) { this.handle = handle; } + private static IModuleLoader loader { + get { + return Platform.ModuleLoader; + } + } + public static Module open(string file_name, ModuleFlags flags) { IntPtr handle = IntPtr.Zero; if (file_name == null) { - handle = Win32.GetModuleHandle(null); + handle = loader.GetModuleHandle(null); } else { - handle = Win32.LoadLibrary(file_name); + handle = loader.LoadLibrary(file_name); } if (handle == IntPtr.Zero) @@ -31,12 +37,12 @@ public static Module open(string file_name, ModuleFlags flags) { } public void symbol(string symbol_name, out IntPtr symbol) { - symbol = Win32.GetProcAddress(handle, symbol_name); + symbol = loader.GetProcAddress(handle, symbol_name); } public void Dispose() { if (handle != IntPtr.Zero) { - Win32.FreeLibrary(handle); + loader.FreeLibrary(handle); handle = IntPtr.Zero; } } diff --git a/GLibPorts/Native/IFileStream.cs b/GLibPorts/Native/IFileStream.cs new file mode 100644 index 0000000..ff2b6b8 --- /dev/null +++ b/GLibPorts/Native/IFileStream.cs @@ -0,0 +1,15 @@ +using GLibPorts.Native.Varargs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native { + public interface IFileStream : IDisposable { + int fileno(); + int printf(string format, params VariableArgument[] args); + int puts(string str); + int putc(int c); + } +} diff --git a/GLibPorts/Native/IModuleLoader.cs b/GLibPorts/Native/IModuleLoader.cs new file mode 100644 index 0000000..6a4b0cd --- /dev/null +++ b/GLibPorts/Native/IModuleLoader.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native { + public interface IModuleLoader { + IntPtr GetProcAddress(IntPtr handle, string symbol_name); + IntPtr LoadLibrary(string library_path); + void FreeLibrary(IntPtr handle); + + IntPtr GetModuleHandle(string moduleName); + } +} diff --git a/GLibPorts/Native/IStrings.cs b/GLibPorts/Native/IStrings.cs new file mode 100644 index 0000000..481fbe3 --- /dev/null +++ b/GLibPorts/Native/IStrings.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native { + public interface IStrings { + void sprintf(StringBuilder sb, string format, IntPtr args); + int vscprintf(string format, IntPtr args); + } +} diff --git a/GLibPorts/Native/Platform.cs b/GLibPorts/Native/Platform.cs new file mode 100644 index 0000000..5bdba64 --- /dev/null +++ b/GLibPorts/Native/Platform.cs @@ -0,0 +1,30 @@ +using GLibPorts.Native.Varargs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native { + public static class Platform { + public static IModuleLoader ModuleLoader; + public static IStrings Strings; + + public static IVariableCombiner MakeVariableCombiner(params VariableArgument[] args) { + if (Utils.IsUnix()) + return new UnixVariableCombiner(args); + else + return new Win32VariableCombiner(args); + } + + static Platform() { + if (Utils.IsUnix()) { + ModuleLoader = new Unix.UnixModuleLoader(); + Strings = new Unix.UnixStrings(); + } else { + ModuleLoader = new Win32.Win32ModuleLoader(); + Strings = new Win32.Win32Strings(); + } + } + } +} diff --git a/GLibPorts/Native/Unix/FileStream.cs b/GLibPorts/Native/Unix/FileStream.cs new file mode 100644 index 0000000..20f9165 --- /dev/null +++ b/GLibPorts/Native/Unix/FileStream.cs @@ -0,0 +1,50 @@ +using GLibPorts.Native.Varargs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +namespace GLibPorts.Native.Unix { + public class UnixFileStream : IFileStream { + private IntPtr stream; + + internal UnixFileStream(IntPtr streamHandle) { + stream = streamHandle; + } + + public static void InitilizeStatic() { + GLib.FileStream.stdin = new UnixFileStream(GLib.File.stdin); + GLib.FileStream.stderr = new UnixFileStream(GLib.File.stderr); + GLib.FileStream.stdout = new UnixFileStream(GLib.File.stdout); + } + + public void Dispose() { + if(stream != IntPtr.Zero) { + NativeImports.fclose(stream); + stream = IntPtr.Zero; + } + } + + public int fileno() { + return NativeImports.fileno(stream); + } + + public int printf(string format, params VariableArgument[] args) { + return UnixFile.fprintf(stream, format, args); + } + + public int putc(int c) { + return NativeImports.putc(c, stream); + } + + public int puts(string str) { + return NativeImports.fputs(str, stream); + } + + public static IFileStream open(string filePath, string mode) { + return new UnixFileStream(NativeImports.fopen(filePath, mode)); + } + } +} diff --git a/GLibPorts/Native/Unix/NativeImports.cs b/GLibPorts/Native/Unix/NativeImports.cs new file mode 100644 index 0000000..b137f15 --- /dev/null +++ b/GLibPorts/Native/Unix/NativeImports.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Unix { + internal class NativeImports { + public const int STDIN_FILENO = 0; + public const int STDOUT_FILENO = 1; + public const int STDERR_FILENO = 2; + + public const int O_RDONLY = 0x0000; + public const int O_WRONLY = 0x0001; + public const int O_RDWR = 0x0002; + public const int O_CREAT = 0x0100; + + public const int RTLD_LOCAL = 0; + public const int RTLD_LAZY = 0x00001; + public const int RTLD_NOW = 0x00002; + public const int RTLD_NOLOAD = 0x00004; + public const int RTLD_DEEPBIND = 0x00008; + public const int RTLD_GLOBAL = 0x00100; + public const int RTLD_NODELETE = 0x01000; + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr fopen(string filename, string mode); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int fclose(IntPtr handle); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int open([MarshalAs(UnmanagedType.LPStr)] string filename, int oflag, int pmode = 0); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int close(int fd); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int dup2(int oldfd, int newfd); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int dup(int oldfd); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr fdopen(int fd, string mode); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int fileno(IntPtr stream); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int fputs(string str, IntPtr stream); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int putc(int ch, IntPtr stream); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int vfprintf(IntPtr stream, string format, IntPtr args); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int vsprintf( + StringBuilder buffer, + string format, + IntPtr ptr); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + public static extern int vsnprintf(StringBuilder sb, uint n, string format, IntPtr args); + + [DllImport("libc", CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr mktemp(IntPtr template); + + public static string mktemp(string template) { + IntPtr templatePtr = Marshal.StringToHGlobalAnsi(template); + IntPtr resultPtr = mktemp(templatePtr); + + string result = null; + if (resultPtr != IntPtr.Zero) + result = Marshal.PtrToStringAnsi(resultPtr); + + Marshal.FreeHGlobal(templatePtr); + return result; + } + + [DllImport("libdl.so", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr dlopen(string filename, int flags); + + [DllImport("libdl.so", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr dlsym(IntPtr handle, string symbol); + + [DllImport("libdl.so", CallingConvention = CallingConvention.Cdecl)] + public static extern int dlclose(IntPtr handle); + } +} diff --git a/GLibPorts/Native/Unix/UnixFile.cs b/GLibPorts/Native/Unix/UnixFile.cs new file mode 100644 index 0000000..3e29b86 --- /dev/null +++ b/GLibPorts/Native/Unix/UnixFile.cs @@ -0,0 +1,49 @@ +using GLibPorts.Native.Varargs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using static GLibPorts.Native.Unix.NativeImports; + +namespace GLibPorts.Native.Unix { + public class UnixFile { + private static IntPtr openFile(int fd, string mode) { + // Copy Handle + int copy_fd = dup(fd); + + // Open Copy + return fdopen(fd, mode); + } + + public static void InitializeStatic() { + DisposeStatic(); + GLib.File.stdin = openFile(STDIN_FILENO, "r"); + GLib.File.stdout = openFile(STDOUT_FILENO, "w"); + GLib.File.stderr = openFile(STDERR_FILENO, "w"); + } + + public static void DisposeStatic() { + if (GLib.File.stdin != IntPtr.Zero) + fclose(GLib.File.stdin); + + if (GLib.File.stderr != IntPtr.Zero) + fclose(GLib.File.stderr); + + if (GLib.File.stdout != IntPtr.Zero) + fclose(GLib.File.stdout); + + GLib.File.stdin = IntPtr.Zero; + GLib.File.stderr = IntPtr.Zero; + GLib.File.stdout = IntPtr.Zero; + + } + + public static int fprintf(IntPtr handle, string format, params VariableArgument[] args) { + using (var combinedVariables = Platform.MakeVariableCombiner(args)) { + return vfprintf(handle, format, combinedVariables.GetPtr()); + } + } + } +} diff --git a/GLibPorts/Native/Unix/UnixModuleLoader.cs b/GLibPorts/Native/Unix/UnixModuleLoader.cs new file mode 100644 index 0000000..7204b7b --- /dev/null +++ b/GLibPorts/Native/Unix/UnixModuleLoader.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Unix { + public class UnixModuleLoader : IModuleLoader { + public void FreeLibrary(IntPtr handle) { + NativeImports.dlclose(handle); + } + + public IntPtr GetModuleHandle(string moduleName) { + if(moduleName == null) { + return NativeImports.dlopen(null, NativeImports.RTLD_LAZY); + } else { + throw new NotImplementedException(); + } + } + + public IntPtr GetProcAddress(IntPtr handle, string symbol_name) { + return NativeImports.dlsym(handle, symbol_name); + } + + public IntPtr LoadLibrary(string library_path) { + return NativeImports.dlopen(library_path, NativeImports.RTLD_LAZY); + } + } +} diff --git a/GLibPorts/Native/Unix/UnixStrings.cs b/GLibPorts/Native/Unix/UnixStrings.cs new file mode 100644 index 0000000..1458333 --- /dev/null +++ b/GLibPorts/Native/Unix/UnixStrings.cs @@ -0,0 +1,24 @@ +using GLibPorts.Native.Varargs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Unix { + public class UnixStrings : IStrings { + public void sprintf(StringBuilder sb, string format, IntPtr args) { + NativeImports.vsprintf(sb, format, args); + } + + public int vscprintf(string format, params VariableArgument[] args) { + using (var combined = Platform.MakeVariableCombiner(args)) { + return NativeImports.vsnprintf(null, 0, format, combined.GetPtr()); + } + } + + public int vscprintf(string format, IntPtr args) { + return NativeImports.vsnprintf(null, 0, format, args); + } + } +} diff --git a/GLibPorts/Native/Varargs.cs b/GLibPorts/Native/Varargs.cs deleted file mode 100644 index 96d8a38..0000000 --- a/GLibPorts/Native/Varargs.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace GLibPorts.Native { - #region VariableCombiner - public class CombinedVariables : IDisposable { - readonly IntPtr _ptr; - readonly IList _disposables; - - bool _disposed; - - public CombinedVariables(VariableArgument[] args) { - _disposables = new List(); - - _ptr = Marshal.AllocHGlobal(args.Sum(arg => arg.GetSize())); - var curPtr = _ptr; - - foreach (var arg in args) { - _disposables.Add(arg.Write(curPtr)); - curPtr += arg.GetSize(); - } - } - - public IntPtr GetPtr() { - if (_disposed) - throw new InvalidOperationException("Disposed already."); - - return _ptr; - } - - public void Dispose() { - if (!_disposed) { - _disposed = true; - - foreach (var disposable in _disposables) - disposable.Dispose(); - - Marshal.FreeHGlobal(_ptr); - } - } - } - #endregion - - #region VariableArgument - - public abstract class VariableArgument { - #region SentinelDispose - - protected static readonly IDisposable SentinelDisposable = - new SentinelDispose(); - - class SentinelDispose : IDisposable { - public void Dispose() { - - } - } - - #endregion - - public abstract IDisposable Write(IntPtr buffer); - - public virtual int GetSize() { - return IntPtr.Size; - } - - public static implicit operator VariableArgument(int input) { - return new VariableIntegerArgument(input); - } - - public static implicit operator VariableArgument(string input) { - return new VariableStringArgument(input); - } - - public static implicit operator VariableArgument(double input) { - return new VariableDoubleArgument(input); - } - } - - #endregion - - #region VariableIntegerArgument - - sealed class VariableIntegerArgument : VariableArgument { - readonly int _value; - - public VariableIntegerArgument(int value) { - _value = value; - } - - public override IDisposable Write(IntPtr buffer) { - Marshal.Copy(new[] { _value }, 0, buffer, 1); - return SentinelDisposable; - } - } - - #endregion - - #region VariableDoubleArgument - - sealed class VariableDoubleArgument : VariableArgument { - readonly double _value; - - public VariableDoubleArgument(double value) { - _value = value; - } - - public override int GetSize() { - return 8; - } - - public override IDisposable Write(IntPtr buffer) { - Marshal.Copy(new[] { _value }, 0, buffer, 1); - return SentinelDisposable; - } - } - - #endregion - - #region VariableStringArgument - - sealed class VariableStringArgument : VariableArgument { - readonly string _value; - - public VariableStringArgument(string value) { - _value = value; - } - - public override IDisposable Write(IntPtr buffer) { - var ptr = Marshal.StringToHGlobalAnsi(_value); - - Marshal.Copy(new[] { ptr }, 0, buffer, 1); - - return new StringArgumentDisposable(ptr); - } - - #region StringArgumentDisposable - - class StringArgumentDisposable : IDisposable { - IntPtr _ptr; - - public StringArgumentDisposable(IntPtr ptr) { - _ptr = ptr; - } - - public void Dispose() { - if (_ptr != IntPtr.Zero) { - Marshal.FreeHGlobal(_ptr); - _ptr = IntPtr.Zero; - } - } - } - - #endregion - } - #endregion -} diff --git a/GLibPorts/Native/Varargs/IVariableCombiner.cs b/GLibPorts/Native/Varargs/IVariableCombiner.cs new file mode 100644 index 0000000..61d4c4f --- /dev/null +++ b/GLibPorts/Native/Varargs/IVariableCombiner.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Varargs { + public interface IVariableCombiner : IDisposable { + void Build(); + IntPtr GetPtr(); + } +} diff --git a/GLibPorts/Native/Varargs/UnixVariableCombiner.cs b/GLibPorts/Native/Varargs/UnixVariableCombiner.cs new file mode 100644 index 0000000..840703e --- /dev/null +++ b/GLibPorts/Native/Varargs/UnixVariableCombiner.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Varargs { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct UnixVaList { + public uint gp_offset; + public uint fp_offset; + public IntPtr overflow_arg_area; + public IntPtr reg_save_area; + } + + public class UnixVariableCombiner : Win32VariableCombiner{ + private IntPtr _va_list_ptr; + + public UnixVariableCombiner(VariableArgument[] args) : base(args) { + } + + public override void Build() { + _disposables.Clear(); + + UnixVaList va_list = new UnixVaList(); + if(IntPtr.Size == 8) { + va_list.gp_offset = 48; //6 registers * 8 bytes + va_list.fp_offset = va_list.gp_offset + 256; //16 fp registers * 16 bytes + va_list.reg_save_area = IntPtr.Zero; + va_list.overflow_arg_area = base.GetPtr(); + } + + _va_list_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(va_list)); + Marshal.StructureToPtr(va_list, _va_list_ptr, false); + } + + public override IntPtr GetPtr() { + if (_va_list_ptr == IntPtr.Zero) + Build(); + + if (_disposed) + throw new InvalidOperationException("Disposed already."); + + return _va_list_ptr; + } + + public override void Dispose() { + base.Dispose(); + + if (_va_list_ptr != IntPtr.Zero) + Marshal.FreeHGlobal(_va_list_ptr); + } + } +} diff --git a/GLibPorts/Native/Varargs/VariableArgument.cs b/GLibPorts/Native/Varargs/VariableArgument.cs new file mode 100644 index 0000000..01e724f --- /dev/null +++ b/GLibPorts/Native/Varargs/VariableArgument.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Varargs { + public abstract class VariableArgument { + #region SentinelDispose + + protected static readonly IDisposable SentinelDisposable = + new SentinelDispose(); + + class SentinelDispose : IDisposable { + public void Dispose() { + + } + } + + #endregion + + public abstract IDisposable Write(IntPtr buffer); + + public virtual int GetSize() { + return IntPtr.Size; + } + + public static implicit operator VariableArgument(int input) { + return new VariableIntegerArgument(input); + } + + public static implicit operator VariableArgument(string input) { + return new VariableStringArgument(input); + } + + public static implicit operator VariableArgument(double input) { + return new VariableDoubleArgument(input); + } + } +} diff --git a/GLibPorts/Native/Varargs/VariableDoubleArgument.cs b/GLibPorts/Native/Varargs/VariableDoubleArgument.cs new file mode 100644 index 0000000..8bc1d7a --- /dev/null +++ b/GLibPorts/Native/Varargs/VariableDoubleArgument.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Varargs { + sealed class VariableDoubleArgument : VariableArgument { + readonly double _value; + + public VariableDoubleArgument(double value) { + _value = value; + } + + public override int GetSize() { + return 8; + } + + public override IDisposable Write(IntPtr buffer) { + Marshal.Copy(new[] { _value }, 0, buffer, 1); + return SentinelDisposable; + } + } +} diff --git a/GLibPorts/Native/Varargs/VariableIntegerArgument.cs b/GLibPorts/Native/Varargs/VariableIntegerArgument.cs new file mode 100644 index 0000000..deb1664 --- /dev/null +++ b/GLibPorts/Native/Varargs/VariableIntegerArgument.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Varargs { + sealed class VariableIntegerArgument : VariableArgument { + readonly int _value; + + public VariableIntegerArgument(int value) { + _value = value; + } + + public override IDisposable Write(IntPtr buffer) { + Marshal.Copy(new[] { _value }, 0, buffer, 1); + return SentinelDisposable; + } + } +} diff --git a/GLibPorts/Native/Varargs/VariableStringArgument.cs b/GLibPorts/Native/Varargs/VariableStringArgument.cs new file mode 100644 index 0000000..d7c56cb --- /dev/null +++ b/GLibPorts/Native/Varargs/VariableStringArgument.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Varargs { + sealed class VariableStringArgument : VariableArgument { + readonly string _value; + + public VariableStringArgument(string value) { + _value = value; + } + + public override IDisposable Write(IntPtr buffer) { + var ptr = Marshal.StringToHGlobalAnsi(_value); + + Marshal.Copy(new[] { ptr }, 0, buffer, 1); + + return new StringArgumentDisposable(ptr); + } + + #region StringArgumentDisposable + + class StringArgumentDisposable : IDisposable { + IntPtr _ptr; + + public StringArgumentDisposable(IntPtr ptr) { + _ptr = ptr; + } + + public void Dispose() { + if (_ptr != IntPtr.Zero) { + Marshal.FreeHGlobal(_ptr); + _ptr = IntPtr.Zero; + } + } + } + + #endregion + } +} \ No newline at end of file diff --git a/GLibPorts/Native/Varargs/Win32VariableCombiner.cs b/GLibPorts/Native/Varargs/Win32VariableCombiner.cs new file mode 100644 index 0000000..55c21fb --- /dev/null +++ b/GLibPorts/Native/Varargs/Win32VariableCombiner.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Varargs { + public class Win32VariableCombiner : IVariableCombiner, IDisposable { + protected readonly IList _disposables = new List(); + protected IntPtr _ptr = IntPtr.Zero; + + public VariableArgument[] args; + protected bool _disposed; + + public Win32VariableCombiner(VariableArgument[] args) { + this.args = args; + } + + private void _build() { + _disposables.Clear(); + + _ptr = Marshal.AllocHGlobal(args.Sum(arg => arg.GetSize())); + var curPtr = _ptr; + + foreach (var arg in args) { + _disposables.Add(arg.Write(curPtr)); + curPtr += arg.GetSize(); + } + } + + public virtual void Build() { + _build(); + } + + public virtual IntPtr GetPtr() { + if (_ptr == IntPtr.Zero) + _build(); + + if (_disposed) + throw new InvalidOperationException("Disposed already."); + + return _ptr; + } + + public virtual void Dispose() { + if (!_disposed) { + _disposed = true; + + foreach (var disposable in _disposables) + disposable.Dispose(); + + if(_ptr != IntPtr.Zero) + Marshal.FreeHGlobal(_ptr); + } + } + } +} diff --git a/GLibPorts/Native/Win32/FileStream.cs b/GLibPorts/Native/Win32/FileStream.cs new file mode 100644 index 0000000..f272015 --- /dev/null +++ b/GLibPorts/Native/Win32/FileStream.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using GLibPorts.Native; +using GLibPorts.Native.Varargs; + +namespace GLibPorts.Native.Win32 { + public class Win32FileStream : IFileStream { + private IntPtr stream; + + internal Win32FileStream(IntPtr streamHandle) { + stream = streamHandle; + NativeImports.setvbuf(stream, null, NativeImports._IONBF, 0); + } + + public static void InitializeStatic() { + GLib.FileStream.stdin = new Win32FileStream(GLib.File.stdin); + GLib.FileStream.stderr = new Win32FileStream(GLib.File.stderr); + GLib.FileStream.stdout = new Win32FileStream(GLib.File.stdout); + } + + public void Dispose() { + if (stream != IntPtr.Zero) { + NativeImports.fclose(stream); + stream = IntPtr.Zero; + } + } + + public int fileno() { + return NativeImports._fileno(stream); + } + + public int printf(string format, params VariableArgument[] args) { + return Win32File.fprintf(stream, format, args); + } + + public int puts(string str) { + return NativeImports.fputs(str, stream); + } + + public int putc(int c) { + return NativeImports.putc(c, stream); + } + + public static Win32FileStream fdopen(int fd, string mode) { + return new Win32FileStream(NativeImports._fdopen(fd, mode)); + } + + public static Win32FileStream open(string filename, string mode) { + return new Win32FileStream(NativeImports.fopen(filename, mode)); + } + } +} diff --git a/GLibPorts/Native/Win32.cs b/GLibPorts/Native/Win32/NativeImports.cs similarity index 98% rename from GLibPorts/Native/Win32.cs rename to GLibPorts/Native/Win32/NativeImports.cs index 069f1ed..b93b684 100644 --- a/GLibPorts/Native/Win32.cs +++ b/GLibPorts/Native/Win32/NativeImports.cs @@ -5,8 +5,8 @@ using System.Text; using System.Threading.Tasks; -namespace GLibPorts.Native { - internal class Win32 { +namespace GLibPorts.Native.Win32 { + internal class NativeImports { public const int STD_INPUT_HANDLE = -10; public const int STD_OUTPUT_HANDLE = -11; public const int STD_ERROR_HANDLE = -12; diff --git a/GLibPorts/Native/File.cs b/GLibPorts/Native/Win32/Win32File.cs similarity index 55% rename from GLibPorts/Native/File.cs rename to GLibPorts/Native/Win32/Win32File.cs index 3e1fea8..76915ff 100644 --- a/GLibPorts/Native/File.cs +++ b/GLibPorts/Native/Win32/Win32File.cs @@ -1,18 +1,15 @@ -using System; +using GLibPorts.Native.Varargs; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; -using static GLibPorts.Native.Win32; - -namespace GLibPorts.Native { - public class File { - public static IntPtr stdin; - public static IntPtr stderr; - public static IntPtr stdout; +using static GLibPorts.Native.Win32.NativeImports; +namespace GLibPorts.Native.Win32 { + public class Win32File { private static IntPtr openFile(int handle, string mode) { // Get Handle IntPtr handlePtr = GetStdHandle(handle); @@ -32,29 +29,29 @@ private static IntPtr openFile(int handle, string mode) { public static void InitializeStatic() { DisposeStatic(); - stdin = openFile(STD_INPUT_HANDLE, "r"); - stdout = openFile(STD_OUTPUT_HANDLE, "w"); - stderr = openFile(STD_ERROR_HANDLE, "w"); + GLib.File.stdin = openFile(STD_INPUT_HANDLE, "r"); + GLib.File.stdout = openFile(STD_OUTPUT_HANDLE, "w"); + GLib.File.stderr = openFile(STD_ERROR_HANDLE, "w"); } public static void DisposeStatic() { - if (stdin != IntPtr.Zero) - fclose(stdin); + if (GLib.File.stdin != IntPtr.Zero) + fclose(GLib.File.stdin); - if (stderr != IntPtr.Zero) - fclose(stderr); + if (GLib.File.stderr != IntPtr.Zero) + fclose(GLib.File.stderr); - if (stdout != IntPtr.Zero) - fclose(stdout); + if (GLib.File.stdout != IntPtr.Zero) + fclose(GLib.File.stdout); - stdin = IntPtr.Zero; - stderr = IntPtr.Zero; - stdout = IntPtr.Zero; + GLib.File.stdin = IntPtr.Zero; + GLib.File.stderr = IntPtr.Zero; + GLib.File.stdout = IntPtr.Zero; } public static int fprintf(IntPtr handle, string format, params VariableArgument[] args) { - using (var combinedVariables = new CombinedVariables(args)) { + using (var combinedVariables = Platform.MakeVariableCombiner(args)) { return vfprintf_s(handle, format, combinedVariables.GetPtr()); } } diff --git a/GLibPorts/Native/Win32/Win32ModuleLoader.cs b/GLibPorts/Native/Win32/Win32ModuleLoader.cs new file mode 100644 index 0000000..e493774 --- /dev/null +++ b/GLibPorts/Native/Win32/Win32ModuleLoader.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Win32 { + public class Win32ModuleLoader : IModuleLoader { + public void FreeLibrary(IntPtr handle) { + NativeImports.FreeLibrary(handle); + } + + public IntPtr GetModuleHandle(string moduleName) { + return NativeImports.GetModuleHandle(moduleName); + } + + public IntPtr GetProcAddress(IntPtr handle, string symbol_name) { + return NativeImports.GetProcAddress(handle, symbol_name); + } + + public IntPtr LoadLibrary(string library_path) { + return NativeImports.LoadLibrary(library_path); + } + } +} diff --git a/GLibPorts/Native/Win32/Win32Strings.cs b/GLibPorts/Native/Win32/Win32Strings.cs new file mode 100644 index 0000000..4a9adf3 --- /dev/null +++ b/GLibPorts/Native/Win32/Win32Strings.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GLibPorts.Native.Win32 { + public class Win32Strings : IStrings { + public void sprintf(StringBuilder sb, string format, IntPtr args) { + NativeImports.vsprintf(sb, format, args); + } + + public int vscprintf(string format, IntPtr args) { + return NativeImports._vscprintf(format, args); + } + } +} diff --git a/GLibPorts/StringExtensions.cs b/GLibPorts/StringExtensions.cs index 1b6576b..5640220 100644 --- a/GLibPorts/StringExtensions.cs +++ b/GLibPorts/StringExtensions.cs @@ -5,6 +5,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using GLibPorts.Native; +using GLibPorts.Native.Varargs; namespace Vala { public static class StringExtensions { @@ -40,11 +41,11 @@ public static string printf(this String format, params VariableArgument[] args) if (!args.Any()) return format; - using (var combinedVariables = new CombinedVariables(args)) { - var bufferCapacity = Win32._vscprintf(format, combinedVariables.GetPtr()); + using (var combinedVariables = Platform.MakeVariableCombiner(args)) { + var bufferCapacity = Platform.Strings.vscprintf(format, combinedVariables.GetPtr()); var stringBuilder = new StringBuilder(bufferCapacity + 1); - Win32.vsprintf(stringBuilder, format, combinedVariables.GetPtr()); + Platform.Strings.sprintf(stringBuilder, format, combinedVariables.GetPtr()); return stringBuilder.ToString(); } diff --git a/GLibPorts/Utils.cs b/GLibPorts/Utils.cs index 51744de..96b349c 100644 --- a/GLibPorts/Utils.cs +++ b/GLibPorts/Utils.cs @@ -5,12 +5,10 @@ using System.Threading.Tasks; namespace GLibPorts { - public partial class GLib { - public class Utils { - public static bool IsUnix() { - int p = (int)Environment.OSVersion.Platform; - return ((p == 4) || (p == 6) || (p == 128)); - } + public class Utils { + public static bool IsUnix() { + int p = (int)Environment.OSVersion.Platform; + return ((p == 4) || (p == 6) || (p == 128)); } } } diff --git a/Lang/Code/CodeWriter.cs b/Lang/Code/CodeWriter.cs index 5693be4..fb4d1e5 100644 --- a/Lang/Code/CodeWriter.cs +++ b/Lang/Code/CodeWriter.cs @@ -1,4 +1,5 @@ using GLibPorts; +using GLibPorts.Native; using System; using System.Collections.Generic; using System.IO; @@ -29,7 +30,7 @@ public class CodeWriter : CodeVisitor { private CodeContext context; - GLib.FileStream stream; + IFileStream stream; int indent; /* at begin of line */ diff --git a/Lang/Parser/Parser.cs b/Lang/Parser/Parser.cs index e1e9c51..96da24d 100644 --- a/Lang/Parser/Parser.cs +++ b/Lang/Parser/Parser.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using GLibPorts.Native; +using GLibPorts.Native.Varargs; using Vala.Lang.CodeNodes; using Vala.Lang.Expressions; using Vala.Lang.Literals;