iverilog: Allow tool path to have spaces in it
When invoking the various subcommands make sure the path to the executable is quoted. This allows it to contain spaces. On Windows quoting the command passed to `system()` or `popen()` is not enough. The default behavior under windows will strip quotes from the beginning and end of the command string under certain conditions. For this reason implement `system()` and `popen()` equivalents that do not suffer from this. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
311c22e4de
commit
5b66163a4d
12
Makefile.in
12
Makefile.in
|
|
@ -59,6 +59,8 @@ SUBDIRS += driver-vpi
|
|||
# rebuild the lexor_keyword.cc file. If we do, then we want to use the
|
||||
# local version instead of the one is $(srcdir).
|
||||
vpath lexor_keyword.cc .
|
||||
vpath %.c $(srcdir)/libmisc
|
||||
vpath %.c $(srcdir)
|
||||
vpath %.cc $(srcdir)/libmisc
|
||||
vpath %.cc $(srcdir)
|
||||
|
||||
|
|
@ -109,7 +111,8 @@ M = LineInfo.o StringHeap.o
|
|||
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o t-dll-analog.o
|
||||
FF = cprop.o exposenodes.o nodangle.o synth.o synth2.o syn-rules.o
|
||||
|
||||
O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
|
||||
C_OBJ = CmdExec.o
|
||||
CXX_OBJ = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
|
||||
elab_expr.o elaborate_analog.o elab_lval.o elab_net.o \
|
||||
elab_scope.o elab_sig.o elab_sig_analog.o elab_type.o \
|
||||
emit.o eval_attrib.o \
|
||||
|
|
@ -128,6 +131,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
|
|||
Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PFunction.o \
|
||||
PGate.o PGenerate.o PModport.o PNamedItem.o PPackage.o PScope.o PSpec.o PTimingCheck.o \
|
||||
PTask.o PUdp.o PWire.o Statement.o AStatement.o $M $(FF) $(TT)
|
||||
O = $(C_OBJ) $(CXX_OBJ)
|
||||
|
||||
all: dep config.h _pli_types.h version_tag.h version_base.h ivl@EXEEXT@
|
||||
$(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true
|
||||
|
|
@ -174,7 +178,7 @@ ifneq (@srcdir@,.)
|
|||
endif
|
||||
rm -rf autom4te.cache
|
||||
|
||||
cppcheck: $(O:.o=.cc) $(srcdir)/dosify.c
|
||||
cppcheck: $(C_OBJ:.o=.c) $(CXX_OBJ:.o=.cc) $(srcdir)/dosify.c
|
||||
cppcheck --enable=all --std=c99 --std=c++11 -f \
|
||||
--check-level=exhaustive \
|
||||
--suppressions-list=$(srcdir)/cppcheck-global.sup \
|
||||
|
|
@ -232,6 +236,10 @@ endif
|
|||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
|
||||
mv $*.d dep/$*.d
|
||||
|
||||
%.o: %.c config.h | dep
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
|
||||
mv $*.d dep/$*.d
|
||||
|
||||
# Here are some explicit dependencies needed to get things going.
|
||||
main.o: main.cc version_tag.h
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,10 @@ unusedFunction:vpi_modules.cc:90
|
|||
// vpi_sim_control()
|
||||
unusedFunction:vpi_modules.cc:110
|
||||
|
||||
// CmdExec.c is shared by multiple executables, so each cppcheck target sees
|
||||
// some exported helpers that are used only by another target.
|
||||
unusedFunction:libmisc/CmdExec.c
|
||||
|
||||
// These are the functions that the compiler exports to the targets.
|
||||
//ivl_branch_island()
|
||||
unusedFunction:t-dll-api.cc:39
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ builddir=@builddir@
|
|||
top_builddir=@top_builddir@
|
||||
|
||||
VPATH = $(srcdir)
|
||||
vpath %.c $(srcdir)/../libmisc
|
||||
|
||||
bindir = $(exec_prefix)/bin
|
||||
libdir = $(exec_prefix)/lib
|
||||
|
|
@ -50,16 +51,16 @@ MAN = @MAN@
|
|||
PS2PDF = @PS2PDF@
|
||||
|
||||
ifeq (@srcdir@,.)
|
||||
INCLUDE_PATH = -I. -I..
|
||||
INCLUDE_PATH = -I. -I.. -I../libmisc
|
||||
else
|
||||
INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/..
|
||||
INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../libmisc
|
||||
endif
|
||||
|
||||
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@
|
||||
CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
O = main.o substit.o cflexor.o cfparse.o
|
||||
O = main.o substit.o cflexor.o cfparse.o CmdExec.o
|
||||
|
||||
all: dep iverilog@EXEEXT@ iverilog.man
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ memleakOnRealloc
|
|||
nullPointerArithmeticOutOfMemory
|
||||
nullPointerOutOfMemory
|
||||
|
||||
// CmdExec.c is shared by multiple executables, so this target sees helpers
|
||||
// that are used only by another target.
|
||||
unusedFunction:../libmisc/CmdExec.c
|
||||
|
||||
// Errors/limitations in the generated yacc and lex files
|
||||
duplicateBreak:cflexor.lex
|
||||
constVariablePointer:cfparse.y
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ extern const char*optarg;
|
|||
#endif
|
||||
|
||||
# include "globals.h"
|
||||
# include "CmdExec.h"
|
||||
#include "cfparse_misc.h" /* cfparse() */
|
||||
#include "ivl_alloc.h"
|
||||
|
||||
|
|
@ -335,16 +336,16 @@ static int t_version_only(void)
|
|||
free(source_path);
|
||||
|
||||
fflush(0);
|
||||
snprintf(tmp, sizeof tmp, "%s%civlpp -V", ivlpp_dir, sep);
|
||||
rc = system(tmp);
|
||||
snprintf(tmp, sizeof tmp, "\"%s%civlpp\" -V", ivlpp_dir, sep);
|
||||
rc = ivl_run_cmd(tmp, verbose_flag);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "Unable to get version from \"%s\"\n", tmp);
|
||||
}
|
||||
|
||||
fflush(0);
|
||||
snprintf(tmp, sizeof tmp, "%s%civl -V -C\"%s\" -C\"%s\"", ivl_dir, sep,
|
||||
snprintf(tmp, sizeof tmp, "\"%s%civl\" -V -C\"%s\" -C\"%s\"", ivl_dir, sep,
|
||||
iconfig_path, iconfig_common_path);
|
||||
rc = system(tmp);
|
||||
rc = ivl_run_cmd(tmp, verbose_flag);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "Unable to get version from \"%s\"\n", tmp);
|
||||
}
|
||||
|
|
@ -363,7 +364,7 @@ static int t_version_only(void)
|
|||
|
||||
static void build_preprocess_command(int e_flag)
|
||||
{
|
||||
snprintf(tmp, sizeof tmp, "%s%civlpp%s%s%s -F\"%s\" -f\"%s\" -p\"%s\"%s",
|
||||
snprintf(tmp, sizeof tmp, "\"%s%civlpp\"%s%s%s -F\"%s\" -f\"%s\" -p\"%s\"%s",
|
||||
ivlpp_dir, sep,
|
||||
verbose_flag ? " -v" : "",
|
||||
e_flag ? "" : " -L",
|
||||
|
|
@ -395,7 +396,7 @@ static int t_preprocess_only(void)
|
|||
if (verbose_flag)
|
||||
printf("preprocess: %s\n", cmd);
|
||||
|
||||
rc = system(cmd);
|
||||
rc = ivl_run_cmd(cmd, verbose_flag);
|
||||
remove(source_path);
|
||||
free(source_path);
|
||||
|
||||
|
|
@ -449,7 +450,7 @@ static int t_compile(void)
|
|||
#endif
|
||||
|
||||
/* Build the ivl command. */
|
||||
snprintf(tmp, sizeof tmp, "%s%civl", ivl_dir, sep);
|
||||
snprintf(tmp, sizeof tmp, "\"%s%civl\"", ivl_dir, sep);
|
||||
rc = strlen(tmp);
|
||||
cmd = realloc(cmd, ncmd+rc+1);
|
||||
strcpy(cmd+ncmd, tmp);
|
||||
|
|
@ -496,7 +497,7 @@ static int t_compile(void)
|
|||
printf("translate: %s\n", cmd);
|
||||
|
||||
|
||||
rc = system(cmd);
|
||||
rc = ivl_run_cmd(cmd, verbose_flag);
|
||||
if ( ! getenv("IVERILOG_ICONFIG")) {
|
||||
remove(source_path);
|
||||
free(source_path);
|
||||
|
|
@ -1484,7 +1485,7 @@ int main(int argc, char **argv)
|
|||
|
||||
if (vhdlpp_work == 0)
|
||||
vhdlpp_work = "ivl_vhdl_work";
|
||||
fprintf(defines_file, "vhdlpp:%s%cvhdlpp\n", vhdlpp_dir, sep);
|
||||
fprintf(defines_file, "vhdlpp:\"%s%cvhdlpp\"\n", vhdlpp_dir, sep);
|
||||
fprintf(defines_file, "vhdlpp-work:%s\n", vhdlpp_work);
|
||||
for (unsigned idx = 0 ; idx < vhdlpp_libdir_cnt ; idx += 1)
|
||||
fprintf(defines_file, "vhdlpp-libdir:%s\n", vhdlpp_libdir[idx]);
|
||||
|
|
@ -1547,7 +1548,7 @@ int main(int argc, char **argv)
|
|||
/* Write the preprocessor command needed to preprocess a
|
||||
single file. This may be used to preprocess library
|
||||
files. */
|
||||
fprintf(iconfig_file, "ivlpp:%s%civlpp %s -L -F\"%s\" -P\"%s\"\n",
|
||||
fprintf(iconfig_file, "ivlpp:\"%s%civlpp\" %s -L -F\"%s\" -P\"%s\"\n",
|
||||
ivlpp_dir, sep,
|
||||
strchr(warning_flags, 'r') ? "-Wredef-all" :
|
||||
strchr(warning_flags, 'R') ? "-Wredef-chg" : "",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ exec_prefix = @exec_prefix@
|
|||
srcdir = @srcdir@
|
||||
|
||||
VPATH = $(srcdir)
|
||||
vpath %.c $(srcdir)/../libmisc
|
||||
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
|
|
@ -38,16 +39,16 @@ INSTALL_DATA = @INSTALL_DATA@
|
|||
LEX = @LEX@
|
||||
|
||||
ifeq (@srcdir@,.)
|
||||
INCLUDE_PATH = -I. -I..
|
||||
INCLUDE_PATH = -I. -I.. -I../libmisc
|
||||
else
|
||||
INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/..
|
||||
INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../libmisc
|
||||
endif
|
||||
|
||||
CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@
|
||||
CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
O = main.o lexor.o
|
||||
O = main.o lexor.o CmdExec.o
|
||||
|
||||
all: ivlpp@EXEEXT@
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ memleakOnRealloc
|
|||
nullPointerArithmeticOutOfMemory
|
||||
nullPointerOutOfMemory
|
||||
|
||||
// CmdExec.c is shared by multiple executables, so this target sees helpers
|
||||
// that are used only by another target.
|
||||
unusedFunction:../libmisc/CmdExec.c
|
||||
|
||||
// Errors/limitations in the generated yacc and lex files
|
||||
ctunullpointerOutOfMemory:lexor.lex
|
||||
memleakOnRealloc:lexor.lex
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
# include <ctype.h>
|
||||
# include <assert.h>
|
||||
|
||||
# include "CmdExec.h"
|
||||
# include "globals.h"
|
||||
# include "ivl_alloc.h"
|
||||
|
||||
|
|
@ -2128,12 +2129,12 @@ static void open_input_file(struct include_stack_t*isp)
|
|||
cmdlen += liblen;
|
||||
|
||||
char*cmd = malloc(cmdlen);
|
||||
snprintf(cmd, cmdlen, "%s -w\"%s\"%s %s", vhdlpp_path, vhdlpp_work, libs, isp->path);
|
||||
snprintf(cmd, cmdlen, "%s -w\"%s\"%s \"%s\"", vhdlpp_path, vhdlpp_work, libs, isp->path);
|
||||
|
||||
if (verbose_flag) fprintf(stderr, "Invoke vhdlpp: %s\n", cmd);
|
||||
|
||||
isp->file = popen(cmd, "r");
|
||||
isp->file_close = pclose;
|
||||
isp->file = ivl_run_cmd_pipe(cmd);
|
||||
isp->file_close = ivl_close_cmd_pipe;
|
||||
|
||||
free(libs);
|
||||
free(cmd);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include "CmdExec.h"
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
||||
#ifdef __MINGW32__
|
||||
# if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
|
||||
# undef _WIN32_WINNT
|
||||
# define _WIN32_WINNT 0x0600
|
||||
# endif
|
||||
# if !defined(WINVER) || WINVER < 0x0600
|
||||
# undef WINVER
|
||||
# define WINVER 0x0600
|
||||
# endif
|
||||
# include <fcntl.h>
|
||||
# include <io.h>
|
||||
# include <stdint.h>
|
||||
# include <windows.h>
|
||||
|
||||
static char *get_cmd_exe(void)
|
||||
{
|
||||
DWORD n = GetEnvironmentVariableA("COMSPEC", NULL, 0);
|
||||
char *buf;
|
||||
|
||||
if (n > 0) {
|
||||
buf = (char *)malloc(n);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
DWORD len = GetEnvironmentVariableA("COMSPEC", buf, n);
|
||||
|
||||
if (len > 0 && len < n)
|
||||
return buf;
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/* Fallback. This avoids searching PATH for cmd.exe. */
|
||||
{
|
||||
char sysdir[MAX_PATH];
|
||||
UINT len = GetSystemDirectoryA(sysdir, sizeof(sysdir));
|
||||
|
||||
if (len > 0 && len < sizeof(sysdir)) {
|
||||
static const char suffix[] = "\\cmd.exe";
|
||||
size_t need = strlen(sysdir) + sizeof(suffix);
|
||||
|
||||
buf = (char *)malloc(need);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
strcpy(buf, sysdir);
|
||||
strcat(buf, suffix);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
return _strdup("cmd.exe");
|
||||
}
|
||||
|
||||
/*
|
||||
* On Windows `system()` runs the string as cmd.exe /C <command>.
|
||||
* `popen()` similarly runs the string through CMD.exe and attaches one side of
|
||||
* a pipe.
|
||||
*
|
||||
* cmd.exe has special quote handling for /C. Quote characters are preserved
|
||||
* only if all of the following are true:
|
||||
* - there is no /S switch;
|
||||
* - there are exactly two quote characters;
|
||||
* - there are no special characters between them, where special is one
|
||||
* of &<>()@^|;
|
||||
* - there is whitespace between them;
|
||||
* - the string between them is the name of an executable file.
|
||||
*
|
||||
* For an input like "C:\Program Files\...\ivlpp" -F"...\defs" "input file.v"
|
||||
* the quotes at the beginning and the end get stripped, which results in
|
||||
* incorrect behavior.
|
||||
*
|
||||
* Below are versions of `system()` and `popen()` that call cmd.exe with /C /S,
|
||||
* which will preserve the quotes. Select cmd.exe from COMSPEC, with a fallback
|
||||
* to the system directory, and pass it as the application name so PATH is not
|
||||
* searched.
|
||||
*
|
||||
* Also pass /D to suppress AutoRun commands so a registry setting cannot
|
||||
* modify this parsing path.
|
||||
*/
|
||||
static int start_cmd_process(const char *cmd, HANDLE stdout_handle,
|
||||
PROCESS_INFORMATION *pi,
|
||||
DWORD *last_error)
|
||||
{
|
||||
STARTUPINFOEX siex;
|
||||
STARTUPINFO si;
|
||||
STARTUPINFO *startup_info;
|
||||
HANDLE child_stdout = NULL;
|
||||
HANDLE inherit_handles[3];
|
||||
DWORD creation_flags = 0;
|
||||
BOOL inherit = FALSE;
|
||||
SIZE_T attr_size = 0;
|
||||
unsigned inherit_count = 0;
|
||||
char *cmd_exe = get_cmd_exe();
|
||||
size_t cmd2len;
|
||||
char *cmd2;
|
||||
LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL;
|
||||
int attr_list_initialized = 0;
|
||||
int rc = -1;
|
||||
|
||||
if (last_error != NULL)
|
||||
*last_error = 0;
|
||||
|
||||
if (cmd_exe == NULL)
|
||||
return -1;
|
||||
|
||||
cmd2len = strlen(cmd_exe) + strlen(cmd) + 16;
|
||||
cmd2 = (char *)malloc(cmd2len);
|
||||
if (cmd2 == NULL)
|
||||
goto out;
|
||||
|
||||
snprintf(cmd2, cmd2len, "\"%s\" /D /S /C \"%s\"", cmd_exe, cmd);
|
||||
|
||||
memset(&si, 0x00, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
startup_info = &si;
|
||||
|
||||
if (stdout_handle != NULL) {
|
||||
HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
|
||||
HANDLE std_error = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
memset(&siex, 0x00, sizeof(siex));
|
||||
siex.StartupInfo.cb = sizeof(siex);
|
||||
siex.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
if (!DuplicateHandle(GetCurrentProcess(), stdout_handle, GetCurrentProcess(),
|
||||
&child_stdout, 0, TRUE, DUPLICATE_SAME_ACCESS))
|
||||
goto out;
|
||||
|
||||
/* The normal system()/popen() path already relies on standard
|
||||
* handles being inheritable. Only the pipe writer is duplicated.
|
||||
*/
|
||||
if (std_input != NULL && std_input != INVALID_HANDLE_VALUE)
|
||||
inherit_handles[inherit_count++] = std_input;
|
||||
inherit_handles[inherit_count++] = child_stdout;
|
||||
if (std_error != NULL && std_error != INVALID_HANDLE_VALUE)
|
||||
inherit_handles[inherit_count++] = std_error;
|
||||
|
||||
siex.StartupInfo.hStdInput = std_input;
|
||||
siex.StartupInfo.hStdOutput = child_stdout;
|
||||
siex.StartupInfo.hStdError = std_error;
|
||||
|
||||
InitializeProcThreadAttributeList(NULL, 1, 0, &attr_size);
|
||||
attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST)malloc(attr_size);
|
||||
if (attr_list == NULL)
|
||||
goto out;
|
||||
if (!InitializeProcThreadAttributeList(attr_list, 1, 0, &attr_size))
|
||||
goto out;
|
||||
attr_list_initialized = 1;
|
||||
if (!UpdateProcThreadAttribute(attr_list, 0,
|
||||
PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
|
||||
inherit_handles,
|
||||
inherit_count * sizeof(inherit_handles[0]),
|
||||
NULL, NULL))
|
||||
goto out;
|
||||
|
||||
siex.lpAttributeList = attr_list;
|
||||
startup_info = &siex.StartupInfo;
|
||||
creation_flags = EXTENDED_STARTUPINFO_PRESENT;
|
||||
inherit = TRUE;
|
||||
}
|
||||
memset(pi, 0x00, sizeof(*pi));
|
||||
|
||||
if (!CreateProcess(cmd_exe, cmd2, NULL, NULL, inherit,
|
||||
creation_flags, NULL, NULL, startup_info, pi)) {
|
||||
if (last_error != NULL)
|
||||
*last_error = GetLastError();
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
if (attr_list_initialized)
|
||||
DeleteProcThreadAttributeList(attr_list);
|
||||
if (attr_list != NULL)
|
||||
free(attr_list);
|
||||
if (child_stdout != NULL)
|
||||
CloseHandle(child_stdout);
|
||||
free(cmd2);
|
||||
free(cmd_exe);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ivl_run_cmd(const char *cmd, int verbose)
|
||||
{
|
||||
if (verbose)
|
||||
fprintf(stderr, "Executing: %s", cmd);
|
||||
|
||||
#ifdef __MINGW32__
|
||||
DWORD exit_code = 1;
|
||||
DWORD last_error;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
if (start_cmd_process(cmd, NULL, &pi, &last_error) != 0) {
|
||||
if (last_error != 0)
|
||||
fprintf(stderr, "CreateProcess failed (%lu).\n", last_error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
GetExitCodeProcess(pi.hProcess, &exit_code);
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
|
||||
return exit_code;
|
||||
#else
|
||||
return system(cmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
FILE *ivl_run_cmd_pipe(const char *cmd)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
HANDLE read_pipe = NULL;
|
||||
HANDLE write_pipe = NULL;
|
||||
PROCESS_INFORMATION pi;
|
||||
int fd;
|
||||
FILE *fp;
|
||||
|
||||
memset(&sa, 0x00, sizeof(sa));
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.bInheritHandle = FALSE;
|
||||
|
||||
if (!CreatePipe(&read_pipe, &write_pipe, &sa, 0))
|
||||
return NULL;
|
||||
|
||||
if (start_cmd_process(cmd, write_pipe, &pi, NULL) != 0) {
|
||||
CloseHandle(read_pipe);
|
||||
CloseHandle(write_pipe);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CloseHandle(write_pipe);
|
||||
CloseHandle(pi.hThread);
|
||||
|
||||
/* Match popen("r") text-mode semantics. The lexer expects CRLF from
|
||||
* Windows command output to be normalized before it sees `line directives.
|
||||
*/
|
||||
fd = _open_osfhandle((intptr_t)read_pipe, _O_RDONLY | _O_TEXT);
|
||||
if (fd < 0) {
|
||||
CloseHandle(read_pipe);
|
||||
TerminateProcess(pi.hProcess, 1);
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fp = _fdopen(fd, "rt");
|
||||
if (fp == NULL) {
|
||||
_close(fd);
|
||||
TerminateProcess(pi.hProcess, 1);
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The child owns the pipe writer. We do not need the process handle
|
||||
* unless we want pclose() style exit status.
|
||||
*/
|
||||
CloseHandle(pi.hProcess);
|
||||
return fp;
|
||||
#else
|
||||
return popen(cmd, "r");
|
||||
#endif
|
||||
}
|
||||
|
||||
int ivl_close_cmd_pipe(FILE *fp)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
return fclose(fp);
|
||||
#else
|
||||
return pclose(fp);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef IVL_CmdExec_H
|
||||
#define IVL_CmdExec_H
|
||||
/*
|
||||
* Copyright (c) 2026 Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
# include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ivl_run_cmd(const char *cmd, int verbose);
|
||||
FILE *ivl_run_cmd_pipe(const char *cmd);
|
||||
int ivl_close_cmd_pipe(FILE *fp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* IVL_CmdExec_H */
|
||||
14
pform.cc
14
pform.cc
|
|
@ -44,6 +44,7 @@
|
|||
# include <cstdlib>
|
||||
# include <cctype>
|
||||
|
||||
# include "CmdExec.h"
|
||||
# include "ivl_assert.h"
|
||||
# include "ivl_alloc.h"
|
||||
|
||||
|
|
@ -3466,17 +3467,14 @@ int pform_parse(const char*path)
|
|||
if (strcmp(path, "-") == 0) {
|
||||
vl_input = stdin;
|
||||
} else if (ivlpp_string) {
|
||||
char*cmdline = static_cast<char*>(malloc(strlen(ivlpp_string) +
|
||||
strlen(path) + 4));
|
||||
strcpy(cmdline, ivlpp_string);
|
||||
strcat(cmdline, " \"");
|
||||
strcat(cmdline, path);
|
||||
strcat(cmdline, "\"");
|
||||
size_t cmdlen = strlen(ivlpp_string) + strlen(path) + 4;
|
||||
char*cmdline = static_cast<char*>(malloc(cmdlen));
|
||||
snprintf(cmdline, cmdlen, "%s \"%s\"", ivlpp_string, path);
|
||||
|
||||
if (verbose_flag)
|
||||
cerr << "Executing: " << cmdline << endl<< flush;
|
||||
|
||||
vl_input = popen(cmdline, "r");
|
||||
vl_input = ivl_run_cmd_pipe(cmdline);
|
||||
if (vl_input == 0) {
|
||||
cerr << "Unable to preprocess " << path << "." << endl;
|
||||
return 1;
|
||||
|
|
@ -3526,7 +3524,7 @@ int pform_parse(const char*path)
|
|||
|
||||
if (vl_input != stdin) {
|
||||
if (ivlpp_string)
|
||||
pclose(vl_input);
|
||||
ivl_close_cmd_pipe(vl_input);
|
||||
else
|
||||
fclose(vl_input);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue