зеркало из https://github.com/xamarin/XtermSharp.git
Fix passing arg and env arguments to the native helper in .NET6
This commit is contained in:
Родитель
861e649149
Коммит
83186d0ad9
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace XtermSharp {
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
@ -19,7 +21,7 @@ namespace XtermSharp {
|
|||
extern static int execve (string process, string [] args, string [] env);
|
||||
|
||||
[DllImport ("libpty.dylib", EntryPoint="fork_and_exec")]
|
||||
extern static int HeavyFork (string process, string [] args, string [] env, out int master, UnixWindowSize winSize);
|
||||
extern static unsafe int HeavyFork (string process, byte** args, byte** env, out int master, UnixWindowSize winSize);
|
||||
|
||||
static bool HeavyDuty = true;
|
||||
/// <summary>
|
||||
|
@ -34,7 +36,7 @@ namespace XtermSharp {
|
|||
public static int ForkAndExec (string programName, string [] args, string [] env, out int master, UnixWindowSize winSize)
|
||||
{
|
||||
if (HeavyDuty) {
|
||||
return HeavyFork (programName, args, env, out master, winSize);
|
||||
return DoHeavyFork (programName, args, env, out master, winSize);
|
||||
} else {
|
||||
var pid = forkpty (out master, IntPtr.Zero, IntPtr.Zero, ref winSize);
|
||||
if (pid < 0)
|
||||
|
@ -47,6 +49,67 @@ namespace XtermSharp {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static unsafe int DoHeavyFork (string programName, string [] args, string [] env, out int master, UnixWindowSize winSize)
|
||||
{
|
||||
byte** argvPtr = null, envpPtr = null;
|
||||
int result = -1;
|
||||
try {
|
||||
AllocNullTerminatedArray (args, ref argvPtr);
|
||||
AllocNullTerminatedArray (env, ref envpPtr);
|
||||
result = HeavyFork (programName, argvPtr, envpPtr, out master, winSize);
|
||||
return result == 0 ? 0 : Marshal.GetLastWin32Error ();
|
||||
} finally {
|
||||
FreeArray (argvPtr, args.Length);
|
||||
FreeArray (envpPtr, env.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void AllocNullTerminatedArray (string [] arr, ref byte** arrPtr)
|
||||
{
|
||||
int arrLength = arr.Length + 1; // +1 is for null termination
|
||||
|
||||
// Allocate the unmanaged array to hold each string pointer.
|
||||
// It needs to have an extra element to null terminate the array.
|
||||
arrPtr = (byte**)Marshal.AllocHGlobal (sizeof (IntPtr) * arrLength);
|
||||
Debug.Assert (arrPtr != null);
|
||||
|
||||
// Zero the memory so that if any of the individual string allocations fails,
|
||||
// we can loop through the array to free any that succeeded.
|
||||
// The last element will remain null.
|
||||
for (int i = 0; i < arrLength; i++) {
|
||||
arrPtr [i] = null;
|
||||
}
|
||||
|
||||
// Now copy each string to unmanaged memory referenced from the array.
|
||||
// We need the data to be an unmanaged, null-terminated array of UTF8-encoded bytes.
|
||||
for (int i = 0; i < arr.Length; i++) {
|
||||
byte [] byteArr = Encoding.UTF8.GetBytes (arr [i]);
|
||||
|
||||
arrPtr [i] = (byte*)Marshal.AllocHGlobal (byteArr.Length + 1); //+1 for null termination
|
||||
Debug.Assert (arrPtr [i] != null);
|
||||
|
||||
Marshal.Copy (byteArr, 0, (IntPtr)arrPtr [i], byteArr.Length); // copy over the data from the managed byte array
|
||||
arrPtr [i] [byteArr.Length] = (byte)'\0'; // null terminate
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void FreeArray (byte** arr, int length)
|
||||
{
|
||||
if (arr != null) {
|
||||
// Free each element of the array
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (arr [i] != null) {
|
||||
Marshal.FreeHGlobal ((IntPtr)arr [i]);
|
||||
arr [i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// And then the array itself
|
||||
Marshal.FreeHGlobal ((IntPtr)arr);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport ("libc", SetLastError = true)]
|
||||
extern static int ioctl (int fd, long cmd, ref UnixWindowSize WinSz);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче