From 675263de44de1c5a9581d175f3672a95fed1eada Mon Sep 17 00:00:00 2001
From: Adeel <3840695+am11@users.noreply.github.com>
Date: Tue, 28 Jul 2026 19:33:13 +0300
Subject: [PATCH] Implement GetCommandLineArgs fallback on Unix
---
.../System.Native/Interop.GetCommandLine.cs | 16 +
.../System.Private.CoreLib.Shared.projitems | 3 +
.../src/System/Environment.Browser.cs | 6 -
.../src/System/Environment.Unix.cs | 8 -
.../src/System/Environment.UnixOrBrowser.cs | 25 +
.../src/System/Environment.cs | 2 +
.../System/Environment.GetCommandLineArgs.cs | 13 +-
src/native/libs/System.Native/entrypoints.c | 2 +
src/native/libs/System.Native/pal_process.c | 11 +
src/native/libs/System.Native/pal_process.h | 11 +
.../libs/System.Native/pal_process_wasi.c | 11 +
src/native/minipal/getcmdline.h | 435 ++++++++++++++++++
12 files changed, 519 insertions(+), 24 deletions(-)
create mode 100644 src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetCommandLine.cs
create mode 100644 src/native/minipal/getcmdline.h
diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetCommandLine.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetCommandLine.cs
new file mode 100644
index 00000000000000..7eccb665dec75c
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetCommandLine.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Sys
+ {
+ [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetCommandLine")]
+ internal static unsafe partial byte** GetCommandLine(out int count);
+
+ [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_FreeCommandLine")]
+ internal static unsafe partial void FreeCommandLine(byte** buffer);
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index d297affcabc559..0935a27185c6cb 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -2523,6 +2523,9 @@
Common\Interop\Unix\System.Native\Interop.GetProcessPath.cs
+
+ Common\Interop\Unix\System.Native\Interop.GetCommandLine.cs
+
Common\Interop\Unix\System.Native\Interop.GetRandomBytes.cs
diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Browser.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Browser.cs
index 312f065e325c2e..6d3aabb565fba6 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Environment.Browser.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Browser.cs
@@ -34,11 +34,5 @@ private static OperatingSystem GetOSVersion()
///
/// Path of the executable that started the currently executing process
private static string? GetProcessPath() => null;
-
-#if !MONO
- // This is only used for delegate created from native host
- private static string[] GetCommandLineArgsNative() => [];
-#endif
-
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs
index 7dd6f903cf9dfa..6f62f672217c8c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Unix.cs
@@ -33,13 +33,5 @@ public static string MachineName
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Avoid inlining PInvoke frame into the hot path
private static string? GetProcessPath() => Interop.Sys.GetProcessPath();
-
- private static string[] GetCommandLineArgsNative()
- {
- // This is only used for delegate created from native host
-
- // Consider to use /proc/self/cmdline to get command line
- return [];
- }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.UnixOrBrowser.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.UnixOrBrowser.cs
index 693c36b15d6d63..1d954fcefb714c 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Environment.UnixOrBrowser.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Environment.UnixOrBrowser.cs
@@ -5,6 +5,7 @@
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
@@ -97,5 +98,29 @@ public static ProcessCpuUsage CpuUsage
/// Gets the number of milliseconds elapsed since the system started.
/// A 64-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started.
public static long TickCount64 => Interop.Sys.GetLowResolutionTimestamp();
+
+ private static unsafe string[] GetCommandLineArgsNative()
+ {
+ byte** nativeArgv = Interop.Sys.GetCommandLine(out int argc);
+ if (nativeArgv == null || argc <= 0)
+ {
+ return [];
+ }
+
+ try
+ {
+ string[] args = new string[argc];
+ for (int i = 0; i < argc; i++)
+ {
+ args[i] = Utf8StringMarshaller.ConvertToManaged(nativeArgv[i]) ?? string.Empty;
+ }
+
+ return args;
+ }
+ finally
+ {
+ Interop.Sys.FreeCommandLine(nativeArgv);
+ }
+ }
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.cs
index dabc44cab4c4bf..0425ae678e48be 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Environment.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Environment.cs
@@ -2,9 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
+using System.Text;
namespace System
{
diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs
index 2d19226a2787d8..20852e71c714f2 100644
--- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs
+++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Environment.GetCommandLineArgs.cs
@@ -74,11 +74,9 @@ public static int CheckCommandLineArgs(string[] args)
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void GetCommandLineArgs_Fallback_Returns()
{
- if (PlatformDetection.IsNotMonoRuntime
- && PlatformDetection.IsNotNativeAot
- && PlatformDetection.IsWindows)
+ if (PlatformDetection.IsNotMonoRuntime)
{
- // Currently fallback command line is only implemented on Windows coreclr
+ // Currently fallback command line is not implemented by mono
RemoteExecutor.Invoke(CheckCommandLineArgsFallback).Dispose();
}
}
@@ -104,12 +102,7 @@ public static int CheckCommandLineArgsFallback()
return RemoteExecutor.SuccessExitCode;
}
- public static bool IsWindowsCoreCLRJit
- => PlatformDetection.IsWindows
- && PlatformDetection.IsNotMonoRuntime
- && PlatformDetection.IsNotNativeAot;
-
- [ConditionalTheory(typeof(GetCommandLineArgs), nameof(IsWindowsCoreCLRJit))]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows), nameof(PlatformDetection.IsNotMonoRuntime))]
[InlineData(@"cmd ""abc"" d e", new[] { "cmd", "abc", "d", "e" })]
[InlineData(@"cmd a\\b d""e f""g h", new[] { "cmd", @"a\\b", "de fg", "h" })]
[InlineData(@"cmd a\\\""b c d", new[] { "cmd", @"a\""b", "c", "d" })]
diff --git a/src/native/libs/System.Native/entrypoints.c b/src/native/libs/System.Native/entrypoints.c
index 78e08565015511..0c81fc156f6959 100644
--- a/src/native/libs/System.Native/entrypoints.c
+++ b/src/native/libs/System.Native/entrypoints.c
@@ -230,6 +230,8 @@ static const Entry s_sysNative[] =
DllImportEntry(SystemNative_SchedSetAffinity)
DllImportEntry(SystemNative_SchedGetAffinity)
DllImportEntry(SystemNative_GetProcessPath)
+ DllImportEntry(SystemNative_GetCommandLine)
+ DllImportEntry(SystemNative_FreeCommandLine)
DllImportEntry(SystemNative_GetNonCryptographicallySecureRandomBytes)
DllImportEntry(SystemNative_GetCryptographicallySecureRandomBytes)
DllImportEntry(SystemNative_GetUnixRelease)
diff --git a/src/native/libs/System.Native/pal_process.c b/src/native/libs/System.Native/pal_process.c
index c5af90e397287e..902b61e5615250 100644
--- a/src/native/libs/System.Native/pal_process.c
+++ b/src/native/libs/System.Native/pal_process.c
@@ -64,6 +64,7 @@
#endif
#include
+#include
// Validate that our SysLogPriority values are correct for the platform
c_static_assert(PAL_LOG_EMERG == LOG_EMERG);
@@ -1388,3 +1389,13 @@ char* SystemNative_GetProcessPath(void)
{
return minipal_getexepath();
}
+
+char** SystemNative_GetCommandLine(int* argc)
+{
+ return minipal_getcmdline(argc);
+}
+
+void SystemNative_FreeCommandLine(char** buffer)
+{
+ free(buffer);
+}
diff --git a/src/native/libs/System.Native/pal_process.h b/src/native/libs/System.Native/pal_process.h
index 515cfa5ea8e090..566322bde7057e 100644
--- a/src/native/libs/System.Native/pal_process.h
+++ b/src/native/libs/System.Native/pal_process.h
@@ -243,3 +243,14 @@ PALEXPORT int32_t SystemNative_SchedGetAffinity(int32_t pid, intptr_t* mask);
* resolving symbolic links. The caller is responsible for releasing the buffer.
*/
PALEXPORT char* SystemNative_GetProcessPath(void);
+
+/**
+ * Returns the command line for the current process as an array of arguments.
+ * The caller is responsible for releasing the buffer.
+ */
+PALEXPORT char** SystemNative_GetCommandLine(int* argc);
+
+/**
+ * Releases the command line buffer returned by SystemNative_GetCommandLine.
+ */
+PALEXPORT void SystemNative_FreeCommandLine(char** buffer);
diff --git a/src/native/libs/System.Native/pal_process_wasi.c b/src/native/libs/System.Native/pal_process_wasi.c
index 8bfa5ef3438bc7..bc2b8e23271995 100644
--- a/src/native/libs/System.Native/pal_process_wasi.c
+++ b/src/native/libs/System.Native/pal_process_wasi.c
@@ -16,6 +16,7 @@
#include
#include
+#include
int32_t SystemNative_ForkAndExecProcess(const char* filename,
char* const argv[],
@@ -127,3 +128,13 @@ char* SystemNative_GetProcessPath(void)
{
return minipal_getexepath();
}
+
+char** SystemNative_GetCommandLine(int* argc)
+{
+ return minipal_getcmdline(argc);
+}
+
+void SystemNative_FreeCommandLine(char** buffer)
+{
+ free(buffer);
+}
diff --git a/src/native/minipal/getcmdline.h b/src/native/minipal/getcmdline.h
new file mode 100644
index 00000000000000..cde9178fad3071
--- /dev/null
+++ b/src/native/minipal/getcmdline.h
@@ -0,0 +1,435 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef HAVE_MINIPAL_GETCMDLINE_H
+#define HAVE_MINIPAL_GETCMDLINE_H
+
+#include
+#include
+#include
+
+#if defined(__APPLE__)
+#include
+#include
+#elif defined(__FreeBSD__)
+#include
+#include
+#include
+#include
+#elif defined(__OpenBSD__)
+#include
+#include
+#include
+#include
+#elif defined(_WIN32)
+#include
+#elif defined(__HAIKU__)
+#include
+#include
+#elif defined(TARGET_WASI)
+#include
+#elif HAVE_GETAUXVAL
+#include
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get the raw command line for the current process as an array of strings.
+ * The returned array is NULL-terminated (the last element is NULL).
+ * The caller is responsible for releasing the memory by calling a single free() on the returned pointer.
+ *
+ * @param count A pointer to an integer that receives the number of arguments returned.
+ * @return A NULL-terminated array of null-terminated strings, or NULL if an error occurs.
+ */
+static inline char** minipal_getcmdline(int* count)
+{
+ if (count == NULL)
+ {
+ return NULL;
+ }
+ *count = 0;
+
+#if defined(TARGET_BROWSER)
+ size_t allocSize = (2 * sizeof(char*)) + 2;
+ char** resultArgv = (char**)malloc(allocSize);
+ if (resultArgv == NULL)
+ {
+ return NULL;
+ }
+ char* stringBuffer = (char*)(resultArgv + 2);
+ stringBuffer[0] = '/';
+ stringBuffer[1] = '\0';
+
+ resultArgv[0] = stringBuffer;
+ resultArgv[1] = NULL;
+
+ *count = 1;
+ return resultArgv;
+
+#elif defined(__linux__) || defined(__sun)
+ int fd = open("/proc/self/cmdline", O_RDONLY);
+ if (fd < 0)
+ {
+ return NULL;
+ }
+
+ size_t bufSize = 1024;
+ char* buf = (char*)malloc(bufSize);
+ size_t totalBytes = 0;
+ ssize_t bytesRead;
+
+ while ((bytesRead = read(fd, buf + totalBytes, bufSize - totalBytes - 1)) > 0)
+ {
+ totalBytes += (size_t)bytesRead;
+ if (totalBytes >= bufSize - 1)
+ {
+ bufSize *= 2;
+ char* newBuf = (char*)realloc(buf, bufSize);
+ if (newBuf == NULL)
+ {
+ free(buf);
+ close(fd);
+ return NULL;
+ }
+ buf = newBuf;
+ }
+ }
+ close(fd);
+
+ if (totalBytes == 0)
+ {
+ free(buf);
+ return NULL;
+ }
+ buf[totalBytes] = '\0';
+
+ int argc = 0;
+ for (size_t i = 0; i < totalBytes; i++)
+ {
+ if (buf[i] == '\0')
+ {
+ argc++;
+ }
+ }
+ if (totalBytes > 0 && buf[totalBytes - 1] != '\0')
+ {
+ argc++;
+ }
+
+ size_t allocSize = ((size_t)(argc + 1) * sizeof(char*)) + totalBytes + 1;
+ char** resultArgv = (char**)malloc(allocSize);
+ if (resultArgv == NULL)
+ {
+ free(buf);
+ return NULL;
+ }
+
+ char* stringBuffer = (char*)(resultArgv + argc + 1);
+ memcpy(stringBuffer, buf, totalBytes + 1);
+ free(buf);
+
+ int idx = 0;
+ char* ptr = stringBuffer;
+ while (idx < argc)
+ {
+ resultArgv[idx++] = ptr;
+ ptr += strlen(ptr) + 1;
+ }
+ resultArgv[argc] = NULL;
+
+ *count = argc;
+ return resultArgv;
+
+#elif defined(__FreeBSD__)
+ int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, getpid() };
+ size_t len = 0;
+ if (sysctl(name, 4, NULL, &len, NULL, 0) != 0 || len == 0)
+ {
+ return NULL;
+ }
+
+ char* sysctlBuf = (char*)malloc(len);
+ if (sysctlBuf == NULL)
+ {
+ return NULL;
+ }
+
+ if (sysctl(name, 4, sysctlBuf, &len, NULL, 0) != 0)
+ {
+ free(sysctlBuf);
+ return NULL;
+ }
+
+ int argc = 0;
+ for (size_t i = 0; i < len; i++)
+ {
+ if (sysctlBuf[i] == '\0')
+ {
+ argc++;
+ }
+ }
+
+ size_t allocSize = ((size_t)(argc + 1) * sizeof(char*)) + len;
+ char** resultArgv = (char**)malloc(allocSize);
+ if (resultArgv == NULL)
+ {
+ free(sysctlBuf);
+ return NULL;
+ }
+
+ char* stringBuffer = (char*)(resultArgv + argc + 1);
+ memcpy(stringBuffer, sysctlBuf, len);
+ free(sysctlBuf);
+
+ int idx = 0;
+ char* ptr = stringBuffer;
+ while (idx < argc)
+ {
+ resultArgv[idx++] = ptr;
+ ptr += strlen(ptr) + 1;
+ }
+ resultArgv[argc] = NULL;
+
+ *count = argc;
+ return resultArgv;
+
+#elif defined(__OpenBSD__)
+ int name[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
+ size_t len = 0;
+ if (sysctl(name, 4, NULL, &len, NULL, 0) != 0 || len == 0)
+ {
+ return NULL;
+ }
+
+ char* sysctlBuf = (char*)malloc(len);
+ if (sysctlBuf == NULL)
+ {
+ return NULL;
+ }
+
+ if (sysctl(name, 4, sysctlBuf, &len, NULL, 0) != 0)
+ {
+ free(sysctlBuf);
+ return NULL;
+ }
+
+ char** openbsdArgv = (char**)sysctlBuf;
+ int argc = 0;
+ size_t totalStringBytes = 0;
+ while (openbsdArgv[argc] != NULL)
+ {
+ totalStringBytes += strlen(openbsdArgv[argc]) + 1;
+ argc++;
+ }
+
+ size_t allocSize = ((size_t)(argc + 1) * sizeof(char*)) + totalStringBytes;
+ char** resultArgv = (char**)malloc(allocSize);
+ if (resultArgv == NULL)
+ {
+ free(sysctlBuf);
+ return NULL;
+ }
+
+ char* stringBuffer = (char*)(resultArgv + argc + 1);
+ for (int i = 0; i < argc; i++)
+ {
+ resultArgv[i] = stringBuffer;
+ size_t argLen = strlen(openbsdArgv[i]) + 1;
+ memcpy(stringBuffer, openbsdArgv[i], argLen);
+ stringBuffer += argLen;
+ }
+ resultArgv[argc] = NULL;
+
+ *count = argc;
+ free(sysctlBuf);
+ return resultArgv;
+#elif defined(__APPLE__)
+ int name[] = { CTL_KERN, KERN_PROCARGS2, getpid() };
+ size_t len = 0;
+ if (sysctl(name, 3, NULL, &len, NULL, 0) != 0)
+ {
+ return NULL;
+ }
+
+ char* sysctlBuf = (char*)malloc(len);
+ if (sysctlBuf == NULL)
+ {
+ return NULL;
+ }
+
+ if (sysctl(name, 3, sysctlBuf, &len, NULL, 0) != 0)
+ {
+ free(sysctlBuf);
+ return NULL;
+ }
+
+ int argc = 0;
+ memcpy(&argc, sysctlBuf, sizeof(argc));
+
+ char* ptr = sysctlBuf + sizeof(argc);
+ ptr += strlen(ptr) + 1;
+
+ while (ptr < sysctlBuf + len && *ptr == '\0')
+ {
+ ptr++;
+ }
+
+ char* startPtr = ptr;
+ size_t totalStringBytes = 0;
+ int actualCount = 0;
+ for (int i = 0; i < argc; i++)
+ {
+ if (ptr >= sysctlBuf + len)
+ {
+ break;
+ }
+ size_t argLen = strlen(ptr) + 1;
+ totalStringBytes += argLen;
+ ptr += argLen;
+ actualCount++;
+ }
+
+ size_t allocSize = (((size_t)actualCount + 1) * sizeof(char*)) + totalStringBytes;
+ char** resultArgv = (char**)malloc(allocSize);
+ if (resultArgv == NULL)
+ {
+ free(sysctlBuf);
+ return NULL;
+ }
+
+ char* stringBuffer = (char*)(resultArgv + actualCount + 1);
+ if (totalStringBytes > 0)
+ {
+ memcpy(stringBuffer, startPtr, totalStringBytes);
+ }
+ free(sysctlBuf);
+
+ char* fillPtr = stringBuffer;
+ for (int i = 0; i < actualCount; i++)
+ {
+ resultArgv[i] = fillPtr;
+ fillPtr += strlen(fillPtr) + 1;
+ }
+ resultArgv[actualCount] = NULL;
+
+ *count = actualCount;
+ return resultArgv;
+
+#elif defined(__HAIKU__)
+ image_info info;
+ int32 cookie = 0;
+ while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK)
+ {
+ if (info.type == B_APP_IMAGE)
+ {
+ size_t len = strlen(info.args);
+ int argc = 0;
+
+ if (len > 0) argc = 1;
+ for (size_t i = 0; i < len; i++)
+ {
+ if (info.args[i] == ' ') argc++;
+ }
+
+ size_t allocSize = ((size_t)(argc + 1) * sizeof(char*)) + len + 1;
+ char** resultArgv = (char**)malloc(allocSize);
+ if (resultArgv == NULL)
+ {
+ return NULL;
+ }
+
+ char* stringBuffer = (char*)(resultArgv + argc + 1);
+ memcpy(stringBuffer, info.args, len + 1);
+
+ int idx = 0;
+ char* scanPtr = stringBuffer;
+ if (len > 0)
+ {
+ resultArgv[idx++] = scanPtr;
+ }
+ for (size_t i = 0; i < len; i++)
+ {
+ if (stringBuffer[i] == ' ')
+ {
+ stringBuffer[i] = '\0';
+ resultArgv[idx++] = &stringBuffer[i + 1];
+ }
+ }
+ resultArgv[argc] = NULL;
+
+ *count = argc;
+ return resultArgv;
+ }
+ }
+ return NULL;
+
+#elif defined(TARGET_WASI)
+ unsigned short __wasi_args_sizes_get(size_t *retptr0, size_t *retptr1) __attribute__((__import_module__("wasi_snapshot_preview1"), __import_name__("args_sizes_get")));
+ unsigned short __wasi_args_get(uint8_t **argv, uint8_t *argv_buf) __attribute__((__import_module__("wasi_snapshot_preview1"), __import_name__("args_get")));
+
+ size_t argc = 0;
+ size_t argvBufSize = 0;
+ if (__wasi_args_sizes_get(&argc, &argvBufSize) != 0)
+ {
+ return NULL;
+ }
+
+ char** wasiArgv = (char**)malloc((argc + 1) * sizeof(char*));
+ char* wasiBuf = (char*)malloc(argvBufSize);
+ if (wasiArgv == NULL || wasiBuf == NULL)
+ {
+ free(wasiArgv);
+ free(wasiBuf);
+ return NULL;
+ }
+
+ if (__wasi_args_get((uint8_t**)wasiArgv, (uint8_t*)wasiBuf) != 0)
+ {
+ free(wasiArgv);
+ free(wasiBuf);
+ return NULL;
+ }
+
+ size_t allocSize = ((argc + 1) * sizeof(char*)) + argvBufSize;
+ char** resultArgv = (char**)malloc(allocSize);
+ if (resultArgv == NULL)
+ {
+ free(wasiArgv);
+ free(wasiBuf);
+ return NULL;
+ }
+
+ char* stringBuffer = (char*)((char**)resultArgv + argc + 1);
+ memcpy(stringBuffer, wasiBuf, argvBufSize);
+
+ size_t wasiOffset = 0;
+ size_t k = 0;
+wasi_rebase:
+ if (k < argc)
+ {
+ resultArgv[k] = stringBuffer + wasiOffset;
+ wasiOffset += strlen(stringBuffer + wasiOffset) + 1;
+ k++;
+ goto wasi_rebase;
+ }
+ resultArgv[argc] = NULL;
+
+ *count = (int)argc;
+
+ free(wasiArgv);
+ free(wasiBuf);
+ return resultArgv;
+
+#else
+ return NULL;
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif // extern "C"
+
+#endif // HAVE_MINIPAL_GETCMDLINE_H