@@ -192,7 +192,8 @@ static wchar_t *cbm_resolve_comspec(void) {
192192
193193/* On failure returns NULL with *stage naming the failing step and *gle the
194194 * GetLastError value captured at that step (0 when errno is the signal). */
195- static FILE * cbm_popen_isolated (const char * cmd , const char * * stage , DWORD * gle ) {
195+ static FILE * cbm_popen_isolated (const char * cmd , const char * const * argv , const char * * stage ,
196+ DWORD * gle ) {
196197 * stage = "" ;
197198 * gle = 0 ;
198199 InitOnceExecuteOnce (& g_popen_once , cbm_popen_init , NULL , NULL );
@@ -246,12 +247,19 @@ static FILE *cbm_popen_isolated(const char *cmd, const char **stage, DWORD *gle)
246247 si .StartupInfo .hStdError = nul ;
247248 si .lpAttributeList = attr ;
248249
249- /* Run through cmd.exe /c so command quoting and `2>NUL` behave as under
250- * _popen. The command line is heap-composed (no fixed-size truncation)
251- * and widened via UTF-8 so non-ASCII repo paths survive intact. */
252- wchar_t * app = cbm_resolve_comspec ();
250+ /* Shell commands run through cmd.exe /c for _popen compatibility. Argv
251+ * callers bypass the shell and pin the requested executable directly.
252+ * Both paths use heap-composed UTF-8 command lines so non-ASCII paths
253+ * survive intact. */
254+ wchar_t * app = NULL ;
253255 wchar_t * wcmdline = NULL ;
254- if (app ) {
256+ if (argv ) {
257+ app = cbm_utf8_to_wide (argv [0 ]);
258+ wcmdline = cbm_build_cmdline (argv );
259+ } else {
260+ app = cbm_resolve_comspec ();
261+ }
262+ if (app && !argv ) {
255263 size_t u8len = strlen (cmd ) + sizeof ("cmd.exe /c " );
256264 char * u8 = (char * )malloc (u8len );
257265 if (u8 ) {
@@ -334,7 +342,7 @@ FILE *cbm_popen(const char *cmd, const char *mode) {
334342 if (mode && mode [0 ] == 'r' && mode [1 ] == '\0' ) {
335343 const char * stage = "" ;
336344 DWORD gle = 0 ;
337- FILE * fp = cbm_popen_isolated (cmd , & stage , & gle );
345+ FILE * fp = cbm_popen_isolated (cmd , NULL , & stage , & gle );
338346 g_popen_last_isolated = (fp != NULL );
339347 if (!fp ) {
340348 char glebuf [CBM_SZ_16 ];
@@ -350,6 +358,24 @@ FILE *cbm_popen(const char *cmd, const char *mode) {
350358 return _popen (cmd , mode );
351359}
352360
361+ FILE * cbm_popen_argv (const char * const * argv ) {
362+ if (!argv || !argv [0 ] || !argv [0 ][0 ]) {
363+ return NULL ;
364+ }
365+ const char * stage = "" ;
366+ DWORD gle = 0 ;
367+ FILE * fp = cbm_popen_isolated (NULL , argv , & stage , & gle );
368+ g_popen_last_isolated = (fp != NULL );
369+ if (!fp ) {
370+ char glebuf [CBM_SZ_16 ];
371+ char errnobuf [CBM_SZ_16 ];
372+ snprintf (glebuf , sizeof (glebuf ), "%lu" , (unsigned long )gle );
373+ snprintf (errnobuf , sizeof (errnobuf ), "%d" , errno );
374+ cbm_log_warn ("compat.popen_argv_failed" , "stage" , stage , "gle" , glebuf , "errno" , errnobuf );
375+ }
376+ return fp ;
377+ }
378+
353379int cbm_pclose (FILE * f ) {
354380 InitOnceExecuteOnce (& g_popen_once , cbm_popen_init , NULL , NULL );
355381
0 commit comments