From 6573b3b18cbd8be15f56c13a7fff3d25d6139ab0 Mon Sep 17 00:00:00 2001 From: n-a-c-h <> Date: Wed, 8 Mar 2006 01:46:06 +0000 Subject: [PATCH] Rejoice! Windows now uses a safer popen() which returns 0 on program launch fail, and allows you to see stdout on initial usages. --- zsnes/src/Makefile.in | 2 +- zsnes/src/argv.h | 152 ++++++++++++++++++++++++++++++++++++++ zsnes/src/linux/safelib.c | 150 +------------------------------------ zsnes/src/makefile.ms | 8 +- zsnes/src/win/safelib.c | 85 +++++++++++++++++++++ zsnes/src/win/safelib.h | 12 +++ zsnes/src/zmovie.c | 3 +- 7 files changed, 258 insertions(+), 154 deletions(-) create mode 100644 zsnes/src/argv.h create mode 100644 zsnes/src/win/safelib.c create mode 100644 zsnes/src/win/safelib.h diff --git a/zsnes/src/Makefile.in b/zsnes/src/Makefile.in index 348a2e8a..e816c83f 100644 --- a/zsnes/src/Makefile.in +++ b/zsnes/src/Makefile.in @@ -275,7 +275,7 @@ ${WINDIR}/sdllink.o: ${WINDIR}/sdllink.c asm_call.h gblhdr.h ${WINDIR}/sw_draw.h ${WINDIR}/gl_draw.h ${WINDIR}/safelib.h ${WINDIR}/sw_draw.o: ${WINDIR}/sw_draw.c gblhdr.h ${WINDIR}/zfilew.o: ${WINDIR}/zfilew.c -${WINDIR}/safelib.o: ${WINDIR}/safelib.c ${WINDIR}/safelib.h +${WINDIR}/safelib.o: ${WINDIR}/safelib.c ${WINDIR}/safelib.h argv.h ${ZIPDIR}/unzip.o: ${ZIPDIR}/unzip.c gblhdr.h ${ZIPDIR}/zunzip.h ${ZIPDIR}/zpng.o: ${ZIPDIR}/zpng.c gblhdr.h ${ZIPDIR}/zpng.h diff --git a/zsnes/src/argv.h b/zsnes/src/argv.h new file mode 100644 index 00000000..899f5b18 --- /dev/null +++ b/zsnes/src/argv.h @@ -0,0 +1,152 @@ +#ifndef ARGV_H +#define ARGV_H + +static char *decode_string(char *str) +{ + size_t str_len = strlen(str), i = 0; + char *dest = str; + + if ((str_len > 1) && ((*str == '\"') || (*str == '\'')) && (str[str_len-1] == *str)) + { + memmove(str, str+1, str_len-2); + str[str_len-2] = 0; + } + + while (*str) + { + if (*str == '\\') + { + str++; + } + dest[i++] = *str++; + } + dest[i] = 0; + return(dest); +} + +static char *find_next_match(char *str, char match_char) +{ + char *pos = 0; + + while (*str) + { + if (*str == match_char) + { + pos = str; + break; + } + if (*str == '\\') + { + if (str[1]) + { + str++; + } + else + { + break; + } + } + str++; + } + return(pos); +} + +static char *get_param(char *str) +{ + static char *pos = 0; + char *token = 0; + + if (str) //Start a new string? + { + pos = str; + } + + if (pos) + { + //Skip delimiters + while (*pos == ' ') { pos++; } + if (*pos) + { + token = pos; + + //Skip non-delimiters + while (*pos && (*pos != ' ')) + { + //Skip quoted characters + if ((*pos == '\"') || (*pos == '\'')) + { + char *match_pos = 0; + if ((match_pos = find_next_match(pos+1, *pos))) + { + pos = match_pos; + } + } + //Skip escaped spaces + if (*pos == '\\') { pos++; } + pos++; + } + if (*pos) { *pos++ = '\0'; } + } + } + return(token); +} + +static size_t count_param(char *str) +{ + size_t i = 0; + + while (*str) + { + //Skip delimiters + while (*str == ' ') { str++; } + //Skip non-delimiters + while (*str && (*str != ' ')) + { + //Skip quoted characters + if ((*str == '\"') || (*str == '\'')) + { + char *match_str = 0; + if ((match_str = find_next_match(str+1, *str))) + { + str = match_str; + } + } + //Skip escaped spaces + if (*str == '\\') { str++; } + str++; + } + i++; + } + return(i); +} + +static char **build_argv(char *str) +{ + size_t argc = count_param(str); + char **argv = (char **)malloc(sizeof(char *)*(argc+1)); + + if (argv) + { + char *p, **argp = argv; + for (p = get_param(str); p; p = get_param(0), argp++) + { + *argp = decode_string(p); + } + *argp = 0; + return(argv); + } + return(0); +} + +static void argv_print(char **argv) +{ + char **argp = argv; + while (*argp) + { + printf("argv[%u]: %s\n", argp-argv, *argp); + argp++; + } + printf("argv[%u]: NULL\n", argp-argv); +} + +#endif diff --git a/zsnes/src/linux/safelib.c b/zsnes/src/linux/safelib.c index ff2056ad..e9a0fe39 100644 --- a/zsnes/src/linux/safelib.c +++ b/zsnes/src/linux/safelib.c @@ -34,6 +34,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "safelib.h" +#include "../argv.h" + //C++ style code in C #define bool unsigned char #define true 1 @@ -179,154 +181,6 @@ pid_t safe_fork(int *a, size_t size) //Introducing a popen which doesn't return until it knows for sure of program launched or couldn't open -Nach -static char *decode_string(char *str) -{ - size_t str_len = strlen(str), i = 0; - char *dest = str; - - if ((str_len > 1) && ((*str == '\"') || (*str == '\'')) && (str[str_len-1] == *str)) - { - memmove(str, str+1, str_len-2); - str[str_len-2] = 0; - } - - while (*str) - { - if (*str == '\\') - { - str++; - } - dest[i++] = *str++; - } - dest[i] = 0; - return(dest); -} - -static char *find_next_match(char *str, char match_char) -{ - char *pos = 0; - - while (*str) - { - if (*str == match_char) - { - pos = str; - break; - } - if (*str == '\\') - { - if (str[1]) - { - str++; - } - else - { - break; - } - } - str++; - } - return(pos); -} - -static char *get_param(char *str) -{ - static char *pos = 0; - char *token = 0; - - if (str) //Start a new string? - { - pos = str; - } - - if (pos) - { - //Skip delimiters - while (*pos == ' ') { pos++; } - if (*pos) - { - token = pos; - - //Skip non-delimiters - while (*pos && (*pos != ' ')) - { - //Skip quoted characters - if ((*pos == '\"') || (*pos == '\'')) - { - char *match_pos = 0; - if ((match_pos = find_next_match(pos+1, *pos))) - { - pos = match_pos; - } - } - //Skip escaped spaces - if (*pos == '\\') { pos++; } - pos++; - } - if (*pos) { *pos++ = '\0'; } - } - } - return(token); -} - -static size_t count_param(char *str) -{ - size_t i = 0; - - while (*str) - { - //Skip delimiters - while (*str == ' ') { str++; } - //Skip non-delimiters - while (*str && (*str != ' ')) - { - //Skip quoted characters - if ((*str == '\"') || (*str == '\'')) - { - char *match_str = 0; - if ((match_str = find_next_match(str+1, *str))) - { - str = match_str; - } - } - //Skip escaped spaces - if (*str == '\\') { str++; } - str++; - } - i++; - } - return(i); -} - -static char **build_argv(char *str) -{ - size_t argc = count_param(str); - char **argv = (char **)malloc(sizeof(char *)*(argc+1)); - - if (argv) - { - char *p, **argp = argv; - for (p = get_param(str); p; p = get_param(0), argp++) - { - *argp = decode_string(p); - } - *argp = 0; - return(argv); - } - return(0); -} - -static void argv_print(char **argv) -{ - char **argp = argv; - while (*argp) - { - printf("argv[%u]: %s\n", argp-argv, *argp); - argp++; - } - printf("argv[%u]: NULL\n", argp-argv); -} - //Forks, parent is paused until child successfully execs (returns child pid) or child exits (returns failure) static pid_t parent_pause_fork() diff --git a/zsnes/src/makefile.ms b/zsnes/src/makefile.ms index cff5fb1e..ed0e3859 100644 --- a/zsnes/src/makefile.ms +++ b/zsnes/src/makefile.ms @@ -172,7 +172,7 @@ JMAOBJ=${JMADIR}/7zlzma${OE} ${JMADIR}/crc32${OE} ${JMADIR}/iiostrm${OE}\ ${JMADIR}/winout${OE} ${JMADIR}/zsnesjma${OE} MAINOBJ=cfgload${OE} endmem${OE} init${OE} initc${OE} uic${OE} patch${OE}\ - ui${OE} vcache${OE} version${OE} zmovie${OE} zstate${OE} zloader${OE} \ + ui${OE} vcache${OE} version${OE} zmovie${OE} zstate${OE} zloader${OE}\ cfg${OE} md${OE} NETOBJ= @@ -183,12 +183,13 @@ VIDEOBJ=${VIDEODIR}/makev16b${OE} ${VIDEODIR}/makev16t${OE} ${VIDEODIR}/makevid$ ${VIDEODIR}/mode716e${OE} ${VIDEODIR}/mode716t${OE} ${VIDEODIR}/mode7${OE}\ ${VIDEODIR}/mode7ext${OE} ${VIDEODIR}/mv16tms${OE} ${VIDEODIR}/newg162${OE}\ ${VIDEODIR}/newgfx16${OE} ${VIDEODIR}/newgfx2${OE} ${VIDEODIR}/newgfx${OE}\ - ${VIDEODIR}/m716text${OE} ${VIDEODIR}/procvid${OE} ${VIDEODIR}/procvidc${OE} \ + ${VIDEODIR}/m716text${OE} ${VIDEODIR}/procvid${OE} ${VIDEODIR}/procvidc${OE}\ ${VIDEODIR}/ntsc${OE} #only used on Win32 WINOBJ=${WINDIR}/copyvwin${OE} ${DRESOBJ}\ - ${WINDIR}/winintrf${OE} ${WINDIR}/winlink${OE} ${WINDIR}/zfilew${OE} + ${WINDIR}/winintrf${OE} ${WINDIR}/winlink${OE} ${WINDIR}/zfilew${OE}\ + ${WINDIR}/safelib${OE} WINVIDOBJ=${VIDEODIR}/sw_draw${OE} ${VIDEODIR}/hq2x16${OE} ${VIDEODIR}/hq2x32${OE}\ ${VIDEODIR}/2xsaiw${OE} ${VIDEODIR}/hq3x16${OE} ${VIDEODIR}/hq3x32${OE}\ @@ -393,6 +394,7 @@ ${VIDEODIR}/ntsc${OE}: ${VIDEODIR}/ntsc.c ${WINDIR}/copyvwin${OE}: ${WINDIR}/copyvwin.asm macros.mac ${WINDIR}/winintrf${OE}: ${WINDIR}/winintrf.asm macros.mac ${WINDIR}/zfilew${OE}: ${WINDIR}/zfilew.c ${WINDIR}/resource.h +${WINDIR}/safelib${OE}: ${WINDIR}/safelib.c argv.h ifeq (${ENV},msvc) ${WINDIR}/winlink.obj: ${WINDIR}/winlink.cpp ${WINDIR}/resource.h ${WINDIR}/zsnes.res: ${WINDIR}/zsnes.rc ${WINDIR}/afxres.h ${WINDIR}/resource.h diff --git a/zsnes/src/win/safelib.c b/zsnes/src/win/safelib.c new file mode 100644 index 00000000..936fe398 --- /dev/null +++ b/zsnes/src/win/safelib.c @@ -0,0 +1,85 @@ +#define _POSIX_ +#include +#include +#include +#include +#include +#include + +#include "../argv.h" + +//These are here because I don't believe in MSVC's prefixing affixation +#define dup _dup +#define dup2 _dup2 +#define pipe _pipe +#define flushall _flushall +#define fdopen _fdopen + +//Introducing a popen which doesn't return until it knows for sure of program launched or couldn't open -Nach + +#define READ_FD 0 +#define WRITE_FD 1 + +FILE *safe_popen(char *command, const char *mode) +{ + FILE *ret = 0; + char **argv = build_argv(command); + if (argv) + { + int filedes[2]; + + if ((*mode == 'r' || *mode == 'w') && + !pipe(filedes, 512, (mode[1] == 'b' ? O_BINARY : O_TEXT) | O_NOINHERIT)) + { + int fd_original; + FILE *fp; + + if (*mode == 'r') + { + fd_original = dup(STDOUT_FILENO); + dup2(filedes[WRITE_FD], STDOUT_FILENO); + if (!(fp = fdopen(filedes[READ_FD], mode))) + { + close(filedes[READ_FD]); + } + } + else + { + fd_original = dup(STDIN_FILENO); + dup2(filedes[READ_FD], STDIN_FILENO); + if (!(fp = fdopen(filedes[WRITE_FD], mode))) + { + close(filedes[WRITE_FD]); + } + } + + if (fp) + { + int status; + flushall(); + + status = spawnvp(P_NOWAIT, argv[0], (const char* const*)argv); + if (status > 0) + { + ret = fp; + } + else + { + fclose(fp); + } + } + + if (*mode == 'r') + { + dup2(fd_original, STDIN_FILENO); + } + else + { + dup2(fd_original, STDOUT_FILENO); + } + close(fd_original); + } + free(argv); + } + return(ret); +} diff --git a/zsnes/src/win/safelib.h b/zsnes/src/win/safelib.h new file mode 100644 index 00000000..cd4d8906 --- /dev/null +++ b/zsnes/src/win/safelib.h @@ -0,0 +1,12 @@ +#ifndef SAFELIB_H +#define SAFELIB_H + +#include + +FILE *safe_popen(char *, const char *); +void safe_pclose(FILE *); + +#define popen safe_popen +#define pclose fclose + +#endif diff --git a/zsnes/src/zmovie.c b/zsnes/src/zmovie.c index 86f54e74..c74ed8e2 100644 --- a/zsnes/src/zmovie.c +++ b/zsnes/src/zmovie.c @@ -39,9 +39,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #ifdef __WIN32__ #include #include +#include "win/safelib.h" #define ftruncate chsize -#define popen _popen -#define pclose _pclose #else #include #endif