diff -ruN flex-2.6.4-orig/src/filter.c flex-2.6.4-mod/src/filter.c --- flex-2.6.4-orig/src/filter.c 2026-03-20 14:51:42 +++ flex-2.6.4-mod/src/filter.c 2026-03-20 14:52:03 @@ -22,6 +22,22 @@ /* PURPOSE. */ #include "flexdef.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +static intptr_t filter_child_pid = -1; + +void filter_wait_for_children (void) +{ + if (filter_child_pid != -1) { + _cwait (NULL, filter_child_pid, 0); + filter_child_pid = -1; + } +} +#endif + static const char * check_4_gnu_m4 = "m4_dnl ifdef(`__gnu__', ," "`errprint(Flex requires GNU M4. Set the PATH or set the M4 environment variable to its path name.)" @@ -127,6 +143,61 @@ */ bool filter_apply_chain (struct filter * chain) { +#ifdef _WIN32 + /* + * Windows implementation: no fork(), so internal filters + * (filter_tee_header, filter_fix_linedirs) cannot run as child + * processes. We skip them here; the caller writes the m4 + * preamble that tee_header would have provided. + * External filters (m4) are spawned with _spawnvp and piped. + */ + int pipes[2]; + + if (chain) + filter_apply_chain (chain->next); + else + return true; + + if (chain->filter_func) { + /* Internal filter — cannot fork on Windows, skip. */ + return true; + } + + fflush (stdout); + fflush (stderr); + + if (_pipe (pipes, 65536, _O_BINARY) == -1) + flexerror (_("pipe failed")); + + /* Prevent m4 from inheriting the pipe write end; otherwise + * m4 holds the handle open and never sees EOF on stdin. */ + SetHandleInformation ((HANDLE) _get_osfhandle (pipes[1]), + HANDLE_FLAG_INHERIT, 0); + + { + intptr_t spawn_pid; + int saved_stdin_fd = dup (fileno (stdin)); + + if (dup2 (pipes[0], fileno (stdin)) == -1) + flexfatal (_("dup2(pipes[0],0)")); + close (pipes[0]); + + spawn_pid = _spawnvp (_P_NOWAIT, chain->argv[0], + (const char *const *) chain->argv); + if (spawn_pid == -1) + lerr_fatal (_("exec of %s failed"), chain->argv[0]); + filter_child_pid = spawn_pid; + + dup2 (saved_stdin_fd, fileno (stdin)); + close (saved_stdin_fd); + + dup2 (pipes[1], fileno (stdout)); + close (pipes[1]); + } + + fseek (stdout, 0, SEEK_CUR); + return true; +#else int pid, pipes[2]; @@ -196,6 +267,7 @@ fseek (stdout, 0, SEEK_CUR); return true; +#endif } /** Truncate the chain to max_len number of filters. @@ -322,12 +394,21 @@ lerr (_("error closing output file %s"), outfilename ? outfilename : ""); +#ifdef HAVE_SYS_WAIT_H while (wait (0) > 0) ; +#endif FLEX_EXIT (0); return 0; } +static bool is_blank_line (const char *str) +{ + while (isspace((unsigned char)*str)) + str++; + return (*str == '\0'); +} + /** Adjust the line numbers in the #line directives of the generated scanner. * After the m4 expansion, the line numbers are incorrect since the m4 macros * can add or remove lines. This only adjusts line numbers for generated code, @@ -403,9 +484,7 @@ } /* squeeze blank lines from generated code */ - else if (in_gen - && regexec (®ex_blank_line, buf, 0, NULL, - 0) == 0) { + else if (in_gen && is_blank_line(buf)) { if (last_was_blank) continue; else diff -ruN flex-2.6.4-orig/src/flexdef.h flex-2.6.4-mod/src/flexdef.h --- flex-2.6.4-orig/src/flexdef.h 2026-03-20 14:51:42 +++ flex-2.6.4-mod/src/flexdef.h 2026-03-20 14:51:47 @@ -44,7 +44,6 @@ #include #include #include -#include /* for XPG version of basename(3) */ #include #include @@ -57,26 +56,74 @@ #ifdef HAVE_LIMITS_H #include #endif -/* Required: dup() and dup2() in */ +#ifdef HAVE_UNISTD_H #include +#endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_PARAMS_H #include #endif -/* Required: stat() in */ #include -/* Required: wait() in */ +#ifdef HAVE_SYS_WAIT_H #include +#endif #include #include -/* Required: regcomp(), regexec() and regerror() in */ +#ifdef HAVE_REGEX_H #include -/* Required: strcasecmp() in */ +#endif +#ifdef HAVE_STRINGS_H #include +#endif #include "flexint.h" +#ifdef _WIN32 +#include +#include +#include +#include +#define YY_NO_UNISTD_H 1 +#ifndef S_ISREG +#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG) +#endif +#ifndef S_IXUSR +#define S_IXUSR _S_IEXEC +#endif +#ifdef _MSC_VER +#define dup _dup +#define dup2 _dup2 +#define fileno _fileno +#define isatty _isatty +#define popen _popen +#define pclose _pclose +#define fdopen _fdopen +#define strcasecmp _stricmp +#define close _close +#define read _read +#define htonl(x) _byteswap_ulong(x) +#define htons(x) _byteswap_ushort(x) +#endif +void filter_wait_for_children(void); +#endif /* _WIN32 */ + +#ifndef HAVE_REGEX_H +typedef struct { int unused; } regex_t; +typedef struct { int rm_so; int rm_eo; } regmatch_t; +#define REG_EXTENDED 1 +int flex_regcomp_stub(regex_t *preg, const char *pattern, int cflags); +int flex_regexec_stub(const regex_t *preg, const char *string, + size_t nmatch, regmatch_t pmatch[], int eflags); +size_t flex_regerror_stub(int errcode, const regex_t *preg, + char *errbuf, size_t errbuf_size); +void flex_regfree_stub(regex_t *preg); +#define regcomp flex_regcomp_stub +#define regexec flex_regexec_stub +#define regerror flex_regerror_stub +#define regfree flex_regfree_stub +#endif + /* We use gettext. So, when we write strings which should be translated, we mark them with _() */ #ifdef ENABLE_NLS #ifdef HAVE_LOCALE_H @@ -1131,7 +1178,7 @@ * From "regex.c" */ -extern regex_t regex_linedir, regex_blank_line; +extern regex_t regex_linedir; bool flex_init_regex(void); void flex_regcomp(regex_t *preg, const char *regex, int cflags); char *regmatch_dup (regmatch_t * m, const char *src); diff -ruN flex-2.6.4-orig/src/main.c flex-2.6.4-mod/src/main.c --- flex-2.6.4-orig/src/main.c 2026-03-20 14:51:42 +++ flex-2.6.4-mod/src/main.c 2026-03-20 14:51:47 @@ -152,16 +152,18 @@ fflush(stdout); fclose(stdout); } +#ifdef HAVE_SYS_WAIT_H while (wait(&child_status) > 0){ if (!WIFEXITED (child_status) || WEXITSTATUS (child_status) != 0){ - /* report an error of a child - */ if( exit_status <= 1 ) exit_status = 2; } } +#elif defined(_WIN32) + filter_wait_for_children(); +#endif return exit_status - 1; } @@ -356,7 +358,11 @@ size_t length = strlen(path); struct stat sbuf; +#ifdef _WIN32 + const char *endOfDir = strchr(path, ';'); +#else const char *endOfDir = strchr(path, ':'); +#endif if (!endOfDir) endOfDir = path+length; @@ -390,6 +396,22 @@ } yyout = stdout; +#ifdef _WIN32 + /* On Windows, filter_tee_header cannot run as a child process + * (no fork). Write the m4 preamble that it would have emitted + * so that m4 knows how to process the skeleton macros. + */ + fputs ("m4_dnl ifdef(`__gnu__', ," + "`errprint(Flex requires GNU M4." + " Set the PATH or set the M4 environment variable to its path name.)" + " m4exit(2)')\n", stdout); + fputs ("m4_changecom`'m4_dnl\n", stdout); + fputs ("m4_changequote`'m4_dnl\n", stdout); + fputs ("m4_changequote([[,]])[[]]m4_dnl\n", stdout); + fputs ("m4_define([[M4_YY_NOOP]])[[]]m4_dnl\n", stdout); + fprintf (stdout, "m4_define( [[M4_YY_OUTFILE_NAME]],[[%s]])m4_dnl\n", + outfilename ? outfilename : ""); +#endif /* always generate the tablesverify flag. */ buf_m4_define (&m4defs_buf, "M4_YY_TABLES_VERIFY", tablesverify ? "1" : "0"); @@ -994,7 +1016,7 @@ flex_init_regex(); /* Enable C++ if program name ends with '+'. */ - program_name = basename (argv[0]); + program_name = argv[0]; if (program_name != NULL && program_name[strlen (program_name) - 1] == '+') @@ -1201,7 +1223,7 @@ break; case OPT_VERSION: - printf (_("%s %s\n"), program_name, flex_version); + printf (_("%s %s\n"), (C_plus_plus ? "flex++" : "flex"), flex_version); FLEX_EXIT (0); case OPT_WARN: diff -ruN flex-2.6.4-orig/src/regex.c flex-2.6.4-mod/src/regex.c --- flex-2.6.4-orig/src/regex.c 2026-03-20 14:51:42 +++ flex-2.6.4-mod/src/regex.c 2026-03-20 14:51:47 @@ -23,12 +23,62 @@ #include "flexdef.h" +#ifndef HAVE_REGEX_H +int flex_regcomp_stub(regex_t *preg, const char *pattern, int cflags) +{ + (void)preg; (void)pattern; (void)cflags; + return 0; +} +static int match_linedir(const char *s, size_t nmatch, regmatch_t pmatch[]) +{ + const char *p = s; + if (*p++ != '#') return -1; + if (strncmp(p, "line ", 5) != 0) return -1; + p += 5; + while (*p == ' ') p++; + if (!(*p >= '0' && *p <= '9')) return -1; + const char *num_start = p; + while (*p >= '0' && *p <= '9') p++; + const char *num_end = p; + if (*p++ != ' ') return -1; + if (*p++ != '"') return -1; + const char *fname_start = p; + while (*p && *p != '"' && *p != '\n') p++; + const char *fname_end = p; + if (*p != '"') return -1; + + if (nmatch > 0) { pmatch[0].rm_so = 0; pmatch[0].rm_eo = (int)(p + 1 - s); } + if (nmatch > 1) { pmatch[1].rm_so = (int)(num_start - s); pmatch[1].rm_eo = (int)(num_end - s); } + if (nmatch > 2) { pmatch[2].rm_so = (int)(fname_start - s); pmatch[2].rm_eo = (int)(fname_end - s); } + return 0; +} + +int flex_regexec_stub(const regex_t *preg, const char *string, + size_t nmatch, regmatch_t pmatch[], int eflags) +{ + (void)preg; (void)eflags; + return match_linedir(string, nmatch, pmatch); +} + +size_t flex_regerror_stub(int errcode, const regex_t *preg, + char *errbuf, size_t errbuf_size) +{ + (void)errcode; (void)preg; + if (errbuf && errbuf_size > 0) + snprintf(errbuf, errbuf_size, "regex error"); + return 12; +} + +void flex_regfree_stub(regex_t *preg) +{ + (void)preg; +} +#endif /* !HAVE_REGEX_H */ + static const char* REGEXP_LINEDIR = "^#line ([[:digit:]]+) \"(.*)\""; -static const char* REGEXP_BLANK_LINE = "^[[:space:]]*$"; regex_t regex_linedir; /**< matches line directives */ -regex_t regex_blank_line; /**< matches blank lines */ /** Initialize the regular expressions. @@ -36,9 +86,9 @@ */ bool flex_init_regex(void) { +#ifdef HAVE_REGEX_H flex_regcomp(®ex_linedir, REGEXP_LINEDIR, REG_EXTENDED); - flex_regcomp(®ex_blank_line, REGEXP_BLANK_LINE, REG_EXTENDED); - +#endif return true; } diff -ruN flex-2.6.4-orig/src/scanopt.c flex-2.6.4-mod/src/scanopt.c --- flex-2.6.4-orig/src/scanopt.c 2026-03-20 14:51:42 +++ flex-2.6.4-mod/src/scanopt.c 2026-03-20 14:51:47 @@ -247,16 +247,7 @@ fprintf (fp, "%s\n", usage); } else { - /* Find the basename of argv[0] */ - const char *p; - - p = s->argv[0] + strlen (s->argv[0]); - while (p != s->argv[0] && *p != '/') - --p; - if (*p == '/') - p++; - - fprintf (fp, _("Usage: %s [OPTIONS]...\n"), p); + fprintf (fp, _("Usage: %s [OPTIONS]...\n"), s->argv[0]); } fprintf (fp, "\n");