Command (Windows): detects command not found error (WIP)

This commit is contained in:
李通洲
2026-10-10 11:14:07 +08:00
committed by Carter Li
parent a7e19308cc
commit 0806145f4d
4 changed files with 22 additions and 2 deletions
+7
View File
@@ -466,6 +466,13 @@ static inline bool ffStrbufInitJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length; return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
} }
//
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline bool ffStrbufContainAnyC(const FFstrbuf* strbuf, const char* cs) {
assert(cs != nullptr);
return strpbrk(strbuf->chars, cs) != nullptr;
}
[[gnu::nonnull(1, 3), gnu::pure, nodiscard]] static inline uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) { [[gnu::nonnull(1, 3), gnu::pure, nodiscard]] static inline uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) {
assert(start <= strbuf->length); assert(start <= strbuf->length);
+8 -1
View File
@@ -29,7 +29,7 @@ static void argvToCmdline(char* const argv[], FFstrbuf* result) {
} }
// Add quotes around string if whitespace chars are present (with slash duplicating at the end of string) // Add quotes around string if whitespace chars are present (with slash duplicating at the end of string)
if (ffStrbufFirstIndexS(&temp, " \t") != temp.length) { if (ffStrbufContainAnyC(&temp, " \t")) {
uint32_t pos = temp.length; uint32_t pos = temp.length;
uint32_t cnt = 0; uint32_t cnt = 0;
while (pos > 0 && temp.chars[pos - 1] == '\\') { ++cnt, --pos; } while (pos > 0 && temp.chars[pos - 1] == '\\') { ++cnt, --pos; }
@@ -142,6 +142,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFNativeFD stdinF
{ {
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
argvToCmdline(argv, &buf); argvToCmdline(argv, &buf);
FF_DEBUG("Command line: %s", buf.chars);
uint32_t cmdlineBytes = (buf.length + 1) * sizeof(wchar_t); uint32_t cmdlineBytes = (buf.length + 1) * sizeof(wchar_t);
cmdline = malloc(cmdlineBytes); cmdline = malloc(cmdlineBytes);
NTSTATUS status = RtlUTF8ToUnicodeN(cmdline, cmdlineBytes, nullptr, buf.chars, buf.length + 1); NTSTATUS status = RtlUTF8ToUnicodeN(cmdline, cmdlineBytes, nullptr, buf.chars, buf.length + 1);
@@ -265,6 +266,12 @@ exit: {
if (NT_SUCCESS(status)) { if (NT_SUCCESS(status)) {
assert(size == sizeof(info)); assert(size == sizeof(info));
if (info.ExitStatus != STILL_ACTIVE && info.ExitStatus != 0) { if (info.ExitStatus != STILL_ACTIVE && info.ExitStatus != 0) {
if (info.ExitStatus == 9009) {
// Note: CMD swallows 9009 errorlevel and returns 1 by default.
// One must use `& call exit %^ERRORLEVEL%` to propagate the correct error code.
FF_DEBUG("Child process exited with error code 9009 (command not found)");
return "command not found";
}
FF_DEBUG("Child process exited with an error: %x %s", (unsigned) info.ExitStatus, ffDebugNtStatus(info.ExitStatus)); FF_DEBUG("Child process exited with an error: %x %s", (unsigned) info.ExitStatus, ffDebugNtStatus(info.ExitStatus));
return "Child process exited with an error"; return "Child process exited with an error";
} }
+6
View File
@@ -15,6 +15,12 @@ static const char* spawnProcess(FFCommandOptions* options, FFProcessHandle* hand
return "No command text specified"; return "No command text specified";
} }
#if _WIN32
if (ffStrbufEqualS(&options->shell, "cmd.exe") && ffStrbufEqualS(&options->param, "/d/c")) {
ffStrbufAppendS(&options->text, " & exit %^errorlevel%"); // Necessary to propagate 9009 from CMD
}
#endif
return ffProcessSpawn(options->param.length ? (char* const[]) { return ffProcessSpawn(options->param.length ? (char* const[]) {
options->shell.chars, options->shell.chars,
options->param.chars, options->param.chars,
+1 -1
View File
@@ -162,7 +162,7 @@ void ffInitCommandOptions(FFCommandOptions* options) {
); );
ffStrbufInitStatic(&options->param, ffStrbufInitStatic(&options->param,
#ifdef _WIN32 #ifdef _WIN32
"/c" "/d/c"
#else #else
"-c" "-c"
#endif #endif