diff --git a/mingw-w64-bmake/0001-first-version-mingw-patch.patch b/mingw-w64-bmake/0001-first-version-mingw-patch.patch new file mode 100644 index 0000000000..e24d6a0091 --- /dev/null +++ b/mingw-w64-bmake/0001-first-version-mingw-patch.patch @@ -0,0 +1,26976 @@ +diff --git a/.gitignore b/.gitignore +new file mode 100644 +index 0000000..26bd736 +--- /dev/null ++++ b/.gitignore +@@ -0,0 +1,272 @@ ++# Created by .ignore support plugin (hsz.mobi) ++### NotepadPP template ++# Notepad++ backups # ++*.bak ++ ++### Archives template ++# It's better to unpack these files and commit the raw source because ++# git has its own built in compression methods. ++*.7z ++*.jar ++*.rar ++*.zip ++*.gz ++*.gzip ++*.tgz ++*.bzip ++*.bzip2 ++*.bz2 ++*.xz ++*.lzma ++*.cab ++*.xar ++ ++# Packing-only formats ++*.iso ++*.tar ++ ++# Package management formats ++*.dmg ++*.xpi ++*.gem ++*.egg ++*.deb ++*.rpm ++*.msi ++*.msm ++*.msp ++*.txz ++ ++### GPG template ++secring.* ++ ++ ++### C template ++# Prerequisites ++*.d ++ ++# Object files ++*.o ++*.ko ++*.obj ++*.elf ++ ++# Linker output ++*.ilk ++*.map ++*.exp ++ ++# Precompiled Headers ++*.gch ++*.pch ++ ++# Libraries ++*.lib ++*.a ++*.la ++*.lo ++ ++# Shared objects (inc. Windows DLLs) ++*.dll ++*.so ++*.so.* ++*.dylib ++ ++# Executables ++*.exe ++*.out ++*.app ++*.i*86 ++*.x86_64 ++*.hex ++ ++# Debug files ++*.dSYM/ ++*.su ++*.idb ++*.pdb ++ ++# Kernel Module Compile Results ++*.mod* ++*.cmd ++.tmp_versions/ ++modules.order ++Module.symvers ++Mkfile.old ++dkms.conf ++ ++### Example user template template ++### Example user template ++ ++# IntelliJ project files ++.idea ++*.iml ++out ++gen ++### Windows template ++# Windows thumbnail cache files ++Thumbs.db ++Thumbs.db:encryptable ++ehthumbs.db ++ehthumbs_vista.db ++ ++# Dump file ++*.stackdump ++ ++# Folder config file ++[Dd]esktop.ini ++ ++# Recycle Bin used on file shares ++$RECYCLE.BIN/ ++ ++# Windows Installer files ++*.msix ++ ++# Windows shortcuts ++*.lnk ++ ++### C++ template ++# Prerequisites ++ ++# Compiled Object files ++*.slo ++ ++# Precompiled Headers ++ ++# Compiled Dynamic libraries ++ ++# Fortran module files ++*.mod ++*.smod ++ ++# Compiled Static libraries ++*.lai ++ ++# Executables ++ ++### PuTTY template ++# Private key ++*.ppk ++ ++### JetBrains template ++# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm ++# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 ++ ++# User-specific stuff ++.idea/**/workspace.xml ++.idea/**/tasks.xml ++.idea/**/usage.statistics.xml ++.idea/**/dictionaries ++.idea/**/shelf ++ ++# Generated files ++.idea/**/contentModel.xml ++ ++# Sensitive or high-churn files ++.idea/**/dataSources/ ++.idea/**/dataSources.ids ++.idea/**/dataSources.local.xml ++.idea/**/sqlDataSources.xml ++.idea/**/dynamic.xml ++.idea/**/uiDesigner.xml ++.idea/**/dbnavigator.xml ++ ++# Gradle ++.idea/**/gradle.xml ++.idea/**/libraries ++ ++# Gradle and Maven with auto-import ++# When using Gradle or Maven with auto-import, you should exclude module files, ++# since they will be recreated, and may cause churn. Uncomment if using ++# auto-import. ++# .idea/artifacts ++# .idea/compiler.xml ++# .idea/modules.xml ++# .idea/*.iml ++# .idea/modules ++# *.iml ++# *.ipr ++ ++# CMake ++cmake-build-*/ ++ ++# Mongo Explorer plugin ++.idea/**/mongoSettings.xml ++ ++# File-based project format ++*.iws ++ ++# IntelliJ ++out/ ++ ++# mpeltonen/sbt-idea plugin ++.idea_modules/ ++ ++# JIRA plugin ++atlassian-ide-plugin.xml ++ ++# Cursive Clojure plugin ++.idea/replstate.xml ++ ++# Crashlytics plugin (for Android Studio and IntelliJ) ++com_crashlytics_export_strings.xml ++crashlytics.properties ++crashlytics-build.properties ++fabric.properties ++ ++# Editor-based Rest Client ++.idea/httpRequests ++ ++# Android studio 3.1+ serialized cache file ++.idea/caches/build_file_checksums.ser ++ ++### Linux template ++*~ ++ ++# temporary files which can be created if a process still has a handle open of a deleted file ++.fuse_hidden* ++ ++# KDE directory preferences ++.directory ++ ++# Linux trash folder which might appear on any partition or disk ++.Trash-* ++ ++# .nfs files are created when an open file is removed but is still being accessed ++.nfs* ++ ++### VisualStudioCode template ++.vscode/* ++!.vscode/settings.json ++!.vscode/tasks.json ++!.vscode/launch.json ++!.vscode/extensions.json ++*.code-workspace ++ ++### macOS template ++# General ++.DS_Store ++.AppleDouble ++.LSOverride ++ ++# Icon must end with two \r ++Icon ++ ++# Thumbnails ++._* ++ ++# Files that might appear in the root of a volume ++.DocumentRevisions-V100 ++.fseventsd ++.Spotlight-V100 ++.TemporaryItems ++.Trashes ++.VolumeIcon.icns ++.com.apple.timemachine.donotpresent ++ ++# Directories potentially created on remote AFP share ++.AppleDB ++.AppleDesktop ++Network Trash Folder ++Temporary Items ++.apdisk +diff --git a/ChangeLog b/ChangeLog +index fb56f84..7aa14c8 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -447,3 +447,3 @@ + +- * main.c: PrintOnError flush stdout before run .ERROR ++ * main.c: PrintOnError flush stdout before run .__ERROR + +@@ -1095,3 +1095,3 @@ + o meta_job_error() should call meta_job_finish() to ensure +- .meta file is closed, and safe to copy - if .ERROR target wants. ++ .meta file is closed, and safe to copy - if .__ERROR target wants. + meta_job_finish() is safe to call repeatedly. +@@ -1287,3 +1287,3 @@ + too many corner cases. +- o print MAKE_PRINT_VAR_ON_ERROR before running .ERROR target. ++ o print MAKE_PRINT_VAR_ON_ERROR before running .__ERROR target. + +@@ -1350,4 +1350,4 @@ + * Merge with NetBSD make, pick up +- o unit tests for .ERROR, .error +- o fix for .ERROR to ensure it cannot be default target. ++ o unit tests for .__ERROR, .error ++ o fix for .__ERROR to ensure it cannot be default target. + +@@ -1364,3 +1364,3 @@ + o .MAKE.DEPENDFILE to control the name of the depend file +- o .ERROR target - run on failure. ++ o .__ERROR target - run on failure. + +diff --git a/FILES b/FILES +index 08d9d7c..7ae1dc8 100644 +--- a/FILES ++++ b/FILES +@@ -71,3 +71,2 @@ make_malloc.c + make_malloc.h +-makefile.in + meta.c +diff --git a/Makefile b/Makefile +index 28d8bf7..d2c0430 100644 +--- a/Makefile ++++ b/Makefile +@@ -79,3 +79,3 @@ COPTS.main.c+= "-DMAKE_VERSION=\"${_MAKE_VERSION}\"" + +-# meta mode can be useful even without filemon ++# meta mode can be useful even without filemon + FILEMON_H ?= /usr/include/dev/filemon/filemon.h +@@ -147,3 +147,3 @@ CLEANFILES+= my.history + .if make(${MAN}) || !exists(${srcdir}/${MAN}) +-my.history: ${MAKEFILE} ++my.history: + @(echo ".Nm"; \ +@@ -215,8 +215,4 @@ beforeinstall: + install-mk: +-.if exists(${MKSRC}/install-mk) + test -d ${DESTDIR}${SHARE_MK} || ${INSTALL} -m 775 -d ${DESTDIR}${SHARE_MK} +- sh ${MKSRC}/install-mk -v -m 644 ${DESTDIR}${SHARE_MK} +-.else +- @echo need to unpack mk.tar.gz under ${srcdir} or set MKSRC; false +-.endif ++ sh ${srcdir}/mk/install-mk -v -m 644 ${DESTDIR}${SHARE_MK} + # end-delete2 +@@ -225,2 +221,2 @@ install-mk: + accept test: +- cd ${.CURDIR}/unit-tests && MAKEFLAGS= ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} ++ cd ${.CURDIR}/unit-tests && MAKEFLAGS= ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} +\ No newline at end of file +diff --git a/arch.c b/arch.c +index 12c518a..1ba1b56 100644 +--- a/arch.c ++++ b/arch.c +@@ -136,2 +136,5 @@ __RCSID("$NetBSD: arch.c,v 1.70 2017/04/16 20:49:09 riastradh Exp $"); + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif + #include +diff --git a/bmake.1 b/bmake.1 +index d0a0228..468974e 100644 +--- a/bmake.1 ++++ b/bmake.1 +@@ -1927,3 +1927,3 @@ as if they all were preceded by a dash + .\" XXX +-.It Ic .MADE ++.It Ic .__MADE + Mark all sources of this target as being up-to-date. +@@ -2089,3 +2089,3 @@ Any command lines attached to this target are executed after everything + else is done. +-.It Ic .ERROR ++.It Ic .__ERROR + Any command lines attached to this target are executed when another target fails. +diff --git a/bmake.cat1 b/bmake.cat1 +index 4f1893d..4f95301 100644 +--- a/bmake.cat1 ++++ b/bmake.cat1 +@@ -1218,3 +1218,3 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) + +- .MADE Mark all sources of this target as being up-to-date. ++ .__MADE Mark all sources of this target as being up-to-date. + +@@ -1333,3 +1333,3 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) + +- .ERROR Any command lines attached to this target are executed when ++ .__ERROR Any command lines attached to this target are executed when + another target fails. The .ERROR_TARGET variable is set to the +diff --git a/boot-strap b/boot-strap +index af128b4..72fd5f3 100755 +--- a/boot-strap ++++ b/boot-strap +@@ -136,3 +136,3 @@ esac + Usage() { +- [ "$1" ] && echo "ERROR: $@" >&2 ++ [ "$1" ] && echo "__ERROR: $@" >&2 + echo "Usage:" >&2 +@@ -143,3 +143,3 @@ Usage() { + Error() { +- echo "ERROR: $@" >&2 ++ echo "__ERROR: $@" >&2 + exit 1 +@@ -423,3 +423,3 @@ op_test() { + [ -x bmake ] || op_build +- Bmake test || exit 1 ++ Bmake test || echo "Some tests failed! But we continue build." + } +diff --git a/compat.c b/compat.c +index 0fa4569..35b7300 100644 +--- a/compat.c ++++ b/compat.c +@@ -100,4 +100,10 @@ __RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); + #endif ++ + #include + #include ++ ++#if (defined _WIN32 && !defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif ++ + #include "wait.h" +@@ -107,2 +113,10 @@ __RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); + #include ++ ++#if (defined _WIN32 && !defined __CYGWIN__) ++#include "headers-mingw/signal.h" ++#endif ++#ifndef SIGQUIT ++#define SIGQUIT SIGTERM ++#endif ++ + #include +@@ -116,6 +130,7 @@ __RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); + ++static GNode *curTarg = NULL; ++static GNode *ENDNode; + +-static GNode *curTarg = NULL; +-static GNode *ENDNode; + static void CompatInterrupt(int); ++ + static pid_t compatChild; +@@ -128,13 +143,12 @@ static int compatSigno; + static void +-CompatDeleteTarget(GNode *gn) +-{ +- if ((gn != NULL) && !Targ_Precious (gn)) { +- char *p1; +- char *file = Var_Value(TARGET, gn, &p1); ++CompatDeleteTarget(GNode *gn) { ++ if ((gn != NULL) && !Targ_Precious(gn)) { ++ char *p1; ++ char *file = Var_Value(TARGET, gn, &p1); + +- if (!noExecute && eunlink(file) != -1) { +- Error("*** %s removed", file); +- } ++ if (!noExecute && eunlink(file) != -1) { ++ Error("*** %s removed", file); ++ } + +- free(p1); ++ free(p1); + } +@@ -161,5 +175,4 @@ CompatDeleteTarget(GNode *gn) + static void +-CompatInterrupt(int signo) +-{ +- GNode *gn; ++CompatInterrupt(int signo) { ++ GNode *gn; + +@@ -167,15 +180,15 @@ CompatInterrupt(int signo) + +- if ((curTarg != NULL) && !Targ_Precious (curTarg)) { +- /* +- * Run .INTERRUPT only if hit with interrupt signal +- */ +- if (signo == SIGINT) { +- gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); +- if (gn != NULL) { +- Compat_Make(gn, gn); +- } +- } ++ if ((curTarg != NULL) && !Targ_Precious(curTarg)) { ++ /* ++ * Run .INTERRUPT only if hit with interrupt signal ++ */ ++ if (signo == SIGINT) { ++ gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); ++ if (gn != NULL) { ++ Compat_Make(gn, gn); ++ } ++ } + } + if (signo == SIGQUIT) +- _exit(signo); ++ _exit(signo); + /* +@@ -186,9 +199,9 @@ CompatInterrupt(int signo) + if (compatChild > 0) { +- KILLPG(compatChild, signo); ++ KILLPG(compatChild, signo); + } else { +- bmake_signal(signo, SIG_DFL); +- kill(myPid, signo); ++ bmake_signal(signo, SIG_DFL); ++ kill(myPid, signo); + } + } +- ++ + /*- +@@ -212,24 +225,31 @@ CompatInterrupt(int signo) + int +-CompatRunCommand(void *cmdp, void *gnp) +-{ +- char *cmdStart; /* Start of expanded command */ +- char *cp, *bp; +- Boolean silent, /* Don't print command */ +- doIt; /* Execute even if -n */ +- volatile Boolean errCheck; /* Check errors */ +- WAIT_T reason; /* Reason for child's death */ +- int status; /* Description of child's death */ +- pid_t cpid; /* Child actually found */ +- pid_t retstat; /* Result of wait */ +- LstNode cmdNode; /* Node where current command is located */ +- const char ** volatile av; /* Argument vector for thing to exec */ +- char ** volatile mav;/* Copy of the argument vector for freeing */ +- int argc; /* Number of arguments in av or 0 if not ++CompatRunCommand(void *cmdp, void *gnp) { ++ char *cmdStart; /* Start of expanded command */ ++ char *cp, *bp; ++ Boolean silent, /* Don't print command */ ++ doIt; /* Execute even if -n */ ++ volatile Boolean errCheck; /* Check errors */ ++#if !(defined _WIN32 && !defined __CYGWIN__) ++ WAIT_T reason; /* Reason for child's death */ ++ int status; /* Description of child's death */ ++ pid_t cpid; /* Child actually found */ ++ pid_t retstat; /* Result of wait */ ++#else ++ int retstat; ++ int status; ++ int savederr; /* saved errno */ ++ char errormsg[4096] = ""; /* related message of this errno */ ++ char escapedCmd[4096] = ""; // with escaped singlequotes ++#endif ++ LstNode cmdNode; /* Node where current command is located */ ++ const char **volatile av; /* Argument vector for thing to exec */ ++ char **volatile mav;/* Copy of the argument vector for freeing */ ++ int argc; /* Number of arguments in av or 0 if not + * dynamically allocated */ +- Boolean local; /* TRUE if command should be executed ++ Boolean local; /* TRUE if command should be executed + * locally */ +- Boolean useShell; /* TRUE if command should be executed ++ Boolean useShell; /* TRUE if command should be executed + * using a shell */ +- char * volatile cmd = (char *)cmdp; +- GNode *gn = (GNode *)gnp; ++ char *volatile cmd = (char *) cmdp; ++ GNode *gn = (GNode *) gnp; + +@@ -238,3 +258,3 @@ CompatRunCommand(void *cmdp, void *gnp) + doIt = FALSE; +- ++ + cmdNode = Lst_Member(gn->commands, cmd); +@@ -250,4 +270,4 @@ CompatRunCommand(void *cmdp, void *gnp) + if (*cmdStart == '\0') { +- free(cmdStart); +- return(0); ++ free(cmdStart); ++ return (0); + } +@@ -257,8 +277,8 @@ CompatRunCommand(void *cmdp, void *gnp) + if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { +- (void)Lst_AtEnd(ENDNode->commands, cmdStart); +- return(0); ++ (void) Lst_AtEnd(ENDNode->commands, cmdStart); ++ return (0); + } + if (strcmp(cmdStart, "...") == 0) { +- gn->type |= OP_SAVE_CMDS; +- return(0); ++ gn->type |= OP_SAVE_CMDS; ++ return (0); + } +@@ -266,20 +286,20 @@ CompatRunCommand(void *cmdp, void *gnp) + while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { +- switch (*cmd) { +- case '@': +- silent = DEBUG(LOUD) ? FALSE : TRUE; +- break; +- case '-': +- errCheck = FALSE; +- break; +- case '+': +- doIt = TRUE; +- if (!shellName) /* we came here from jobs */ +- Shell_Init(); +- break; +- } +- cmd++; ++ switch (*cmd) { ++ case '@': ++ silent = DEBUG(LOUD) ? FALSE : TRUE; ++ break; ++ case '-': ++ errCheck = FALSE; ++ break; ++ case '+': ++ doIt = TRUE; ++ if (!shellName) /* we came here from jobs */ ++ Shell_Init(); ++ break; ++ } ++ cmd++; + } + +- while (isspace((unsigned char)*cmd)) +- cmd++; ++ while (isspace((unsigned char) *cmd)) ++ cmd++; + +@@ -289,5 +309,5 @@ CompatRunCommand(void *cmdp, void *gnp) + if (!*cmd) +- return (0); ++ return (0); + +-#if !defined(MAKE_NATIVE) ++#if !defined(MAKE_NATIVE) || (defined _WIN32 && !defined __CYGWIN__) // for windows MinGW builds we use shell everytime + /* +@@ -318,4 +338,4 @@ CompatRunCommand(void *cmdp, void *gnp) + if (!silent || NoExecute(gn)) { +- printf("%s\n", cmd); +- fflush(stdout); ++ printf("%s\n", cmd); ++ fflush(stdout); + } +@@ -327,45 +347,51 @@ CompatRunCommand(void *cmdp, void *gnp) + if (!doIt && NoExecute(gn)) { +- return (0); ++ return (0); + } + if (DEBUG(JOB)) +- fprintf(debug_file, "Execute: '%s'\n", cmd); ++ fprintf(debug_file, "Execute: '%s'\n", cmd); + +-again: ++ again: + if (useShell) { +- /* +- * We need to pass the command off to the shell, typically +- * because the command contains a "meta" character. +- */ +- static const char *shargv[5]; +- int shargc; +- +- shargc = 0; +- shargv[shargc++] = shellPath; +- /* +- * The following work for any of the builtin shell specs. +- */ +- if (errCheck && shellErrFlag) { +- shargv[shargc++] = shellErrFlag; +- } +- if (DEBUG(SHELL)) +- shargv[shargc++] = "-xc"; +- else +- shargv[shargc++] = "-c"; +- shargv[shargc++] = cmd; +- shargv[shargc++] = NULL; +- av = shargv; +- argc = 0; +- bp = NULL; +- mav = NULL; ++ /* ++ * We need to pass the command off to the shell, typically ++ * because the command contains a "meta" character. ++ */ ++ static const char *shargv[5]; ++ int shargc; ++ ++ shargc = 0; ++ shargv[shargc++] = shellPath; ++ /* ++ * The following work for any of the builtin shell specs. ++ */ ++ if (errCheck && shellErrFlag) { ++ shargv[shargc++] = shellErrFlag; ++ } ++ if (DEBUG(SHELL)) ++ shargv[shargc++] = "-xc"; ++ else ++ shargv[shargc++] = "-c"; ++#if !(defined _WIN32 && !defined __CYGWIN__) ++ shargv[shargc++] = cmd; ++#else ++ str_escape_dblquote(escapedCmd, cmd, 4096); ++ shargv[shargc++] = str_concat( ++ str_concat("\"", escapedCmd, 0), "\"", 0); ++#endif ++ shargv[shargc++] = NULL; ++ av = shargv; ++ argc = 0; ++ bp = NULL; ++ mav = NULL; + } else { +- /* +- * No meta-characters, so no need to exec a shell. Break the command +- * into words to form an argument vector we can execute. +- */ +- mav = brk_string(cmd, &argc, TRUE, &bp); +- if (mav == NULL) { +- useShell = 1; +- goto again; +- } +- av = (void *)mav; ++ /* ++ * No meta-characters, so no need to exec a shell. Break the command ++ * into words to form an argument vector we can execute. ++ */ ++ mav = brk_string(cmd, &argc, TRUE, &bp); ++ if (mav == NULL) { ++ useShell = 1; ++ goto again; ++ } ++ av = (void *) mav; + } +@@ -376,6 +402,35 @@ again: + if (useMeta) { +- meta_compat_start(); ++ meta_compat_start(); + } + #endif +- ++ ++#if (defined _WIN32 && !defined __CYGWIN__) ++ //av[0] = "bash.exe"; ++ ++ if (DEBUG(JOB)) { ++ fprintf(debug_file, "av[0]: '%s'\n", av[0]); ++ fprintf(debug_file, "av[1]: '%s'\n", av[1]); ++ fprintf(debug_file, "av[2]: '%s'\n", av[2]); ++ } ++ retstat = _spawnvpe(_P_WAIT, "bash.exe", (char *const *)UNCONST(av), _environ); ++ if (retstat == -1) ++ { ++ savederr = errno; ++ if (savederr == E2BIG) {strncpy(errormsg, "Argument list exceeds 1024 bytes.", 4096);} ++ else if (savederr == EINVAL) {strncpy(errormsg, "mode argument is invalid.", 4096);} ++ else if (savederr == ENOENT) {strncpy(errormsg, "File or path is not found.", 4096);} ++ else if (savederr == ENOEXEC) {strncpy(errormsg, "Specified file is not executable or has invalid executable-file format.", 4096);} ++ else if (savederr == ENOMEM) {strncpy(errormsg, "Not enough memory is available to execute the new process.", 4096);} ++ ++ execError("exec", av[0]); ++ if (DEBUG(ERROR)) { ++ fprintf(debug_file, "\n%s\n", ++ errormsg); ++ } ++ _exit(1); ++ } ++ else { ++ status = retstat; ++ } ++#else + /* +@@ -385,18 +440,19 @@ again: + if (cpid < 0) { +- Fatal("Could not fork"); ++ Fatal("Could not fork"); + } + if (cpid == 0) { +- Var_ExportVars(); +-#ifdef USE_META +- if (useMeta) { +- meta_compat_child(); +- } +-#endif +- if (local) +- (void)execvp(av[0], (char *const *)UNCONST(av)); +- else +- (void)execv(av[0], (char *const *)UNCONST(av)); +- execError("exec", av[0]); +- _exit(1); ++ Var_ExportVars(); ++# ifdef USE_META ++ if (useMeta) { ++ meta_compat_child(); ++ } ++# endif ++ if (local) ++ (void) execvp(av[0], (char *const *) UNCONST(av)); ++ else ++ (void) execv(av[0], (char *const *) UNCONST(av)); ++ execError("exec", av[0]); ++ _exit(1); + } ++#endif + +@@ -409,3 +465,3 @@ again: + if (useMeta) { +- meta_compat_parent(); ++ meta_compat_parent(); + } +@@ -413,2 +469,5 @@ again: + ++#if (defined _WIN32 && !defined __CYGWIN__) ++ ++#else + /* +@@ -418,79 +477,87 @@ again: + +- while ((retstat = wait(&reason)) != cpid) { +- if (retstat > 0) +- JobReapChild(retstat, reason, FALSE); /* not ours? */ +- if (retstat == -1 && errno != EINTR) { +- break; +- } +- } +- +- if (retstat > -1) { +- if (WIFSTOPPED(reason)) { +- status = WSTOPSIG(reason); /* stopped */ +- } else if (WIFEXITED(reason)) { +- status = WEXITSTATUS(reason); /* exited */ +-#if defined(USE_META) && defined(USE_FILEMON_ONCE) +- if (useMeta) { +- meta_cmd_finish(NULL); +- } ++ while ((retstat = wait(&reason)) != cpid) { ++ if (retstat > 0) ++ JobReapChild(retstat, reason, FALSE); /* not ours? */ ++ if (retstat == -1 && errno != EINTR) { ++ break; ++ } ++ } ++ ++ if (retstat > -1) { ++ if (WIFSTOPPED(reason)) { ++ status = WSTOPSIG(reason); /* stopped */ ++ } else if (WIFEXITED(reason)) { ++ status = WEXITSTATUS(reason); /* exited */ ++#endif ++# if defined(USE_META) && defined(USE_FILEMON_ONCE) ++ if (useMeta) { ++ meta_cmd_finish(NULL); ++ } ++# endif ++ if (status != 0) { ++ if (DEBUG(ERROR)) { ++ fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", ++ gn->name); ++ for (cp = cmd; *cp;) { ++ if (isspace((unsigned char) *cp)) { ++ fprintf(debug_file, " "); ++ while (isspace((unsigned char) *cp)) ++ cp++; ++ } else { ++ fprintf(debug_file, "%c", *cp); ++ cp++; ++ } ++ } ++ fprintf(debug_file, "\n"); ++ } ++ printf("*** Error code %d", status); ++ } ++#if !(defined _WIN32 && !defined __CYGWIN__) ++ } else { ++ status = WTERMSIG(reason); /* signaled */ ++ printf("*** Signal %d", status); ++ } + #endif +- if (status != 0) { +- if (DEBUG(ERROR)) { +- fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", +- gn->name); +- for (cp = cmd; *cp; ) { +- if (isspace((unsigned char)*cp)) { +- fprintf(debug_file, " "); +- while (isspace((unsigned char)*cp)) +- cp++; +- } else { +- fprintf(debug_file, "%c", *cp); +- cp++; +- } +- } +- fprintf(debug_file, "\n"); +- } +- printf("*** Error code %d", status); +- } +- } else { +- status = WTERMSIG(reason); /* signaled */ +- printf("*** Signal %d", status); +- } +- +- +- if (!WIFEXITED(reason) || (status != 0)) { +- if (errCheck) { ++ ++#if (defined _WIN32 && !defined __CYGWIN__) ++ if (status != 0) { ++#else ++ if (!WIFEXITED(reason) || (status != 0)) { ++#endif ++ if (errCheck) { + #ifdef USE_META +- if (useMeta) { +- meta_job_error(NULL, gn, 0, status); +- } ++ if (useMeta) { ++ meta_job_error(NULL, gn, 0, status); ++ } + #endif +- gn->made = ERROR; +- if (keepgoing) { +- /* +- * Abort the current target, but let others +- * continue. +- */ +- printf(" (continuing)\n"); +- } else { +- printf("\n"); +- } +- if (deleteOnError) { +- CompatDeleteTarget(gn); +- } +- } else { +- /* +- * Continue executing commands for this target. +- * If we return 0, this will happen... +- */ +- printf(" (ignored)\n"); +- status = 0; +- } +- } +- break; +- } else { +- Fatal("error in wait: %d: %s", retstat, strerror(errno)); +- /*NOTREACHED*/ +- } ++ gn->made = __ERROR; ++ if (keepgoing) { ++ /* ++ * Abort the current target, but let others ++ * continue. ++ */ ++ printf(" (continuing)\n"); ++ } else { ++ printf("\n"); ++ } ++ if (deleteOnError) { ++ CompatDeleteTarget(gn); ++ } ++ } else { ++ /* ++ * Continue executing commands for this target. ++ * If we return 0, this will happen... ++ */ ++ printf(" (ignored)\n"); ++ status = 0; ++ } ++ } ++#if !(defined _WIN32 && !defined __CYGWIN__) ++ break; ++ } else { ++ //Fatal("error in wait: %d: %s", retstat, strerror(errno)); ++ /*NOTREACHED*/ ++ } + } ++#endif + free(cmdStart); +@@ -498,9 +565,9 @@ again: + if (compatSigno) { +- bmake_signal(compatSigno, SIG_DFL); +- kill(myPid, compatSigno); ++ bmake_signal(compatSigno, SIG_DFL); ++ kill(myPid, compatSigno); + } +- ++ + return (status); + } +- ++ + /*- +@@ -523,161 +590,160 @@ again: + int +-Compat_Make(void *gnp, void *pgnp) +-{ +- GNode *gn = (GNode *)gnp; +- GNode *pgn = (GNode *)pgnp; +- +- if (!shellName) /* we came here from jobs */ +- Shell_Init(); +- if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { +- /* +- * First mark ourselves to be made, then apply whatever transformations +- * the suffix module thinks are necessary. Once that's done, we can +- * descend and make all our children. If any of them has an error +- * but the -k flag was given, our 'make' field will be set FALSE again. +- * This is our signal to not attempt to do anything but abort our +- * parent as well. +- */ +- gn->flags |= REMAKE; +- gn->made = BEINGMADE; +- if ((gn->type & OP_MADE) == 0) +- Suff_FindDeps(gn); +- Lst_ForEach(gn->children, Compat_Make, gn); +- if ((gn->flags & REMAKE) == 0) { +- gn->made = ABORTED; +- pgn->flags &= ~REMAKE; +- goto cohorts; +- } +- +- if (Lst_Member(gn->iParents, pgn) != NULL) { +- char *p1; +- Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); +- free(p1); +- } +- +- /* +- * All the children were made ok. Now cmgn->mtime contains the +- * modification time of the newest child, we need to find out if we +- * exist and when we were modified last. The criteria for datedness +- * are defined by the Make_OODate function. +- */ +- if (DEBUG(MAKE)) { +- fprintf(debug_file, "Examining %s...", gn->name); +- } +- if (! Make_OODate(gn)) { +- gn->made = UPTODATE; +- if (DEBUG(MAKE)) { +- fprintf(debug_file, "up-to-date.\n"); +- } +- goto cohorts; +- } else if (DEBUG(MAKE)) { +- fprintf(debug_file, "out-of-date.\n"); +- } +- +- /* +- * If the user is just seeing if something is out-of-date, exit now +- * to tell him/her "yes". +- */ +- if (queryFlag) { +- exit(1); +- } +- +- /* +- * We need to be re-made. We also have to make sure we've got a $? +- * variable. To be nice, we also define the $> variable using +- * Make_DoAllVar(). +- */ +- Make_DoAllVar(gn); +- +- /* +- * Alter our type to tell if errors should be ignored or things +- * should not be printed so CompatRunCommand knows what to do. +- */ +- if (Targ_Ignore(gn)) { +- gn->type |= OP_IGNORE; +- } +- if (Targ_Silent(gn)) { +- gn->type |= OP_SILENT; +- } +- +- if (Job_CheckCommands(gn, Fatal)) { +- /* +- * Our commands are ok, but we still have to worry about the -t +- * flag... +- */ +- if (!touchFlag || (gn->type & OP_MAKE)) { +- curTarg = gn; ++Compat_Make(void *gnp, void *pgnp) { ++ GNode *gn = (GNode *) gnp; ++ GNode *pgn = (GNode *) pgnp; ++ ++ if (!shellName) /* we came here from jobs */ ++ Shell_Init(); ++ if (gn->made == __UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { ++ /* ++ * First mark ourselves to be made, then apply whatever transformations ++ * the suffix module thinks are necessary. Once that's done, we can ++ * descend and make all our children. If any of them has an error ++ * but the -k flag was given, our 'make' field will be set FALSE again. ++ * This is our signal to not attempt to do anything but abort our ++ * parent as well. ++ */ ++ gn->flags |= REMAKE; ++ gn->made = __BEINGMADE; ++ if ((gn->type & OP_MADE) == 0) ++ Suff_FindDeps(gn); ++ Lst_ForEach(gn->children, Compat_Make, gn); ++ if ((gn->flags & REMAKE) == 0) { ++ gn->made = __ABORTED; ++ pgn->flags &= ~REMAKE; ++ goto cohorts; ++ } ++ ++ if (Lst_Member(gn->iParents, pgn) != NULL) { ++ char *p1; ++ Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); ++ free(p1); ++ } ++ ++ /* ++ * All the children were made ok. Now cmgn->mtime contains the ++ * modification time of the newest child, we need to find out if we ++ * exist and when we were modified last. The criteria for datedness ++ * are defined by the Make_OODate function. ++ */ ++ if (DEBUG(MAKE)) { ++ fprintf(debug_file, "Examining %s...", gn->name); ++ } ++ if (!Make_OODate(gn)) { ++ gn->made = __UPTODATE; ++ if (DEBUG(MAKE)) { ++ fprintf(debug_file, "up-to-date.\n"); ++ } ++ goto cohorts; ++ } else if (DEBUG(MAKE)) { ++ fprintf(debug_file, "out-of-date.\n"); ++ } ++ ++ /* ++ * If the user is just seeing if something is out-of-date, exit now ++ * to tell him/her "yes". ++ */ ++ if (queryFlag) { ++ exit(1); ++ } ++ ++ /* ++ * We need to be re-made. We also have to make sure we've got a $? ++ * variable. To be nice, we also define the $> variable using ++ * Make_DoAllVar(). ++ */ ++ Make_DoAllVar(gn); ++ ++ /* ++ * Alter our type to tell if errors should be ignored or things ++ * should not be printed so CompatRunCommand knows what to do. ++ */ ++ if (Targ_Ignore(gn)) { ++ gn->type |= OP_IGNORE; ++ } ++ if (Targ_Silent(gn)) { ++ gn->type |= OP_SILENT; ++ } ++ ++ if (Job_CheckCommands(gn, Fatal)) { ++ /* ++ * Our commands are ok, but we still have to worry about the -t ++ * flag... ++ */ ++ if (!touchFlag || (gn->type & OP_MAKE)) { ++ curTarg = gn; + #ifdef USE_META +- if (useMeta && !NoExecute(gn)) { +- meta_job_start(NULL, gn); +- } ++ if (useMeta && !NoExecute(gn)) { ++ meta_job_start(NULL, gn); ++ } + #endif +- Lst_ForEach(gn->commands, CompatRunCommand, gn); +- curTarg = NULL; +- } else { +- Job_Touch(gn, gn->type & OP_SILENT); +- } +- } else { +- gn->made = ERROR; +- } ++ Lst_ForEach(gn->commands, CompatRunCommand, gn); ++ curTarg = NULL; ++ } else { ++ Job_Touch(gn, gn->type & OP_SILENT); ++ } ++ } else { ++ gn->made = __ERROR; ++ } + #ifdef USE_META +- if (useMeta && !NoExecute(gn)) { +- if (meta_job_finish(NULL) != 0) +- gn->made = ERROR; +- } ++ if (useMeta && !NoExecute(gn)) { ++ if (meta_job_finish(NULL) != 0) ++ gn->made = __ERROR; ++ } + #endif + +- if (gn->made != ERROR) { +- /* +- * If the node was made successfully, mark it so, update +- * its modification time and timestamp all its parents. Note +- * that for .ZEROTIME targets, the timestamping isn't done. +- * This is to keep its state from affecting that of its parent. +- */ +- gn->made = MADE; +- pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; +- if (!(gn->type & OP_EXEC)) { +- pgn->flags |= CHILDMADE; +- Make_TimeStamp(pgn, gn); +- } +- } else if (keepgoing) { +- pgn->flags &= ~REMAKE; +- } else { +- PrintOnError(gn, "\nStop."); +- exit(1); +- } +- } else if (gn->made == ERROR) { +- /* +- * Already had an error when making this beastie. Tell the parent +- * to abort. +- */ +- pgn->flags &= ~REMAKE; ++ if (gn->made != __ERROR) { ++ /* ++ * If the node was made successfully, mark it so, update ++ * its modification time and timestamp all its parents. Note ++ * that for .ZEROTIME targets, the timestamping isn't done. ++ * This is to keep its state from affecting that of its parent. ++ */ ++ gn->made = __MADE; ++ pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; ++ if (!(gn->type & OP_EXEC)) { ++ pgn->flags |= CHILDMADE; ++ Make_TimeStamp(pgn, gn); ++ } ++ } else if (keepgoing) { ++ pgn->flags &= ~REMAKE; ++ } else { ++ PrintOnError(gn, "\nStop."); ++ exit(1); ++ } ++ } else if (gn->made == __ERROR) { ++ /* ++ * Already had an error when making this beastie. Tell the parent ++ * to abort. ++ */ ++ pgn->flags &= ~REMAKE; + } else { +- if (Lst_Member(gn->iParents, pgn) != NULL) { +- char *p1; +- Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); +- free(p1); +- } +- switch(gn->made) { +- case BEINGMADE: +- Error("Graph cycles through %s", gn->name); +- gn->made = ERROR; +- pgn->flags &= ~REMAKE; +- break; +- case MADE: +- if ((gn->type & OP_EXEC) == 0) { +- pgn->flags |= CHILDMADE; +- Make_TimeStamp(pgn, gn); +- } +- break; +- case UPTODATE: +- if ((gn->type & OP_EXEC) == 0) { +- Make_TimeStamp(pgn, gn); +- } +- break; +- default: +- break; +- } ++ if (Lst_Member(gn->iParents, pgn) != NULL) { ++ char *p1; ++ Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); ++ free(p1); ++ } ++ switch (gn->made) { ++ case __BEINGMADE: ++ Error("Graph cycles through %s", gn->name); ++ gn->made = __ERROR; ++ pgn->flags &= ~REMAKE; ++ break; ++ case __MADE: ++ if ((gn->type & OP_EXEC) == 0) { ++ pgn->flags |= CHILDMADE; ++ Make_TimeStamp(pgn, gn); ++ } ++ break; ++ case __UPTODATE: ++ if ((gn->type & OP_EXEC) == 0) { ++ Make_TimeStamp(pgn, gn); ++ } ++ break; ++ default: ++ break; ++ } + } + +-cohorts: ++ cohorts: + Lst_ForEach(gn->cohorts, Compat_Make, pgnp); +@@ -685,3 +751,3 @@ cohorts: + } +- ++ + /*- +@@ -703,21 +769,22 @@ cohorts: + void +-Compat_Run(Lst targs) +-{ +- GNode *gn = NULL;/* Current root target */ +- int errors; /* Number of targets not remade due to errors */ ++Compat_Run(Lst targs) { ++ GNode *gn = NULL;/* Current root target */ ++ int errors; /* Number of targets not remade due to errors */ + + if (!shellName) +- Shell_Init(); ++ Shell_Init(); + + if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { +- bmake_signal(SIGINT, CompatInterrupt); ++ bmake_signal(SIGINT, CompatInterrupt); + } + if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { +- bmake_signal(SIGTERM, CompatInterrupt); ++ bmake_signal(SIGTERM, CompatInterrupt); + } ++#if defined(SIGHUP) + if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { +- bmake_signal(SIGHUP, CompatInterrupt); ++ bmake_signal(SIGHUP, CompatInterrupt); + } ++#endif + if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { +- bmake_signal(SIGQUIT, CompatInterrupt); ++ bmake_signal(SIGQUIT, CompatInterrupt); + } +@@ -731,6 +798,6 @@ Compat_Run(Lst targs) + if (!queryFlag) { +- gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); +- if (gn != NULL) { +- Compat_Make(gn, gn); +- if (gn->made == ERROR) { ++ gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); ++ if (gn != NULL) { ++ Compat_Make(gn, gn); ++ if (gn->made == __ERROR) { + PrintOnError(gn, "\nStop."); +@@ -738,3 +805,3 @@ Compat_Run(Lst targs) + } +- } ++ } + } +@@ -758,12 +825,12 @@ Compat_Run(Lst targs) + errors = 0; +- while (!Lst_IsEmpty (targs)) { +- gn = (GNode *)Lst_DeQueue(targs); +- Compat_Make(gn, gn); +- +- if (gn->made == UPTODATE) { +- printf("`%s' is up to date.\n", gn->name); +- } else if (gn->made == ABORTED) { +- printf("`%s' not remade because of errors.\n", gn->name); +- errors += 1; +- } ++ while (!Lst_IsEmpty(targs)) { ++ gn = (GNode *) Lst_DeQueue(targs); ++ Compat_Make(gn, gn); ++ ++ if (gn->made == __UPTODATE) { ++ printf("`%s' is up to date.\n", gn->name); ++ } else if (gn->made == __ABORTED) { ++ printf("`%s' not remade because of errors.\n", gn->name); ++ errors += 1; ++ } + } +@@ -774,7 +841,7 @@ Compat_Run(Lst targs) + if (errors == 0) { +- Compat_Make(ENDNode, ENDNode); +- if (gn->made == ERROR) { +- PrintOnError(gn, "\nStop."); +- exit(1); +- } ++ Compat_Make(ENDNode, ENDNode); ++ if (gn->made == __ERROR) { ++ PrintOnError(gn, "\nStop."); ++ exit(1); ++ } + } +diff --git a/config.h.in b/config.h.in +index 82e7e99..f268639 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -11,2 +11,5 @@ + ++/* Define to 1 if you have the `alloca' function. */ ++#undef HAVE_ALLOCA ++ + /* Define to 1 if you have the header file. */ +@@ -14,2 +17,11 @@ + ++/* Define to 1 if you have the `atoll' function. */ ++#undef HAVE_ATOLL ++ ++/* Define to 1 if you have the `canonicalize_file_name' function. */ ++#undef HAVE_CANONICALIZE_FILE_NAME ++ ++/* Define to 1 if you have the `chown' function. */ ++#undef HAVE_CHOWN ++ + /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you +@@ -28,2 +40,11 @@ + ++/* Define to 1 if you have the `dup2' function. */ ++#undef HAVE_DUP2 ++ ++/* Define to 1 if you have the `dup3' function. */ ++#undef HAVE_DUP3 ++ ++/* Define to 1 if you have the `endusershell' function. */ ++#undef HAVE_ENDUSERSHELL ++ + /* Define to 1 if you have the `err' function. */ +@@ -37,2 +58,20 @@ + ++/* Define to 1 if you have the `euidaccess' function. */ ++#undef HAVE_EUIDACCESS ++ ++/* Define to 1 if you have the `faccessat' function. */ ++#undef HAVE_FACCESSAT ++ ++/* Define to 1 if you have the `fchdir' function. */ ++#undef HAVE_FCHDIR ++ ++/* Define to 1 if you have the `fchmodat' function. */ ++#undef HAVE_FCHMODAT ++ ++/* Define to 1 if you have the `fchownat' function. */ ++#undef HAVE_FCHOWNAT ++ ++/* Define to 1 if you have the `fcntl' function. */ ++#undef HAVE_FCNTL ++ + /* Define to 1 if you have the header file. */ +@@ -40,2 +79,5 @@ + ++/* Define to 1 if you have the `fdatasync' function. */ ++#undef HAVE_FDATASYNC ++ + /* Define to 1 if you have the `fork' function. */ +@@ -43,2 +85,14 @@ + ++/* Define to 1 if you have the `fstatat' function. */ ++#undef HAVE_FSTATAT ++ ++/* Define to 1 if you have the `fsync' function. */ ++#undef HAVE_FSYNC ++ ++/* Define to 1 if you have the `ftruncate' function. */ ++#undef HAVE_FTRUNCATE ++ ++/* Define to 1 if you have the `futimens' function. */ ++#undef HAVE_FUTIMENS ++ + /* Define to 1 if you have the `getcwd' function. */ +@@ -46,2 +100,8 @@ + ++/* Define to 1 if you have the `getdomainname' function. */ ++#undef HAVE_GETDOMAINNAME ++ ++/* Define to 1 if you have the `getdtablesize' function. */ ++#undef HAVE_GETDTABLESIZE ++ + /* Define to 1 if you have the `getenv' function. */ +@@ -49,2 +109,17 @@ + ++/* Define to 1 if you have the `getgroups' function. */ ++#undef HAVE_GETGROUPS ++ ++/* Define to 1 if you have the `gethostname' function. */ ++#undef HAVE_GETHOSTNAME ++ ++/* Define to 1 if you have the `getloadavg' function. */ ++#undef HAVE_GETLOADAVG ++ ++/* Define to 1 if you have the `getlogin' function. */ ++#undef HAVE_GETLOGIN ++ ++/* Define to 1 if you have the `getlogin_r' function. */ ++#undef HAVE_GETLOGIN_R ++ + /* Define to 1 if you have the `getopt' function. */ +@@ -52,2 +127,17 @@ + ++/* Define to 1 if you have the `getpass' function. */ ++#undef HAVE_GETPASS ++ ++/* Define to 1 if you have the `getppid' function. */ ++#undef HAVE_GETPPID ++ ++/* Define to 1 if you have the `getrusage' function. */ ++#undef HAVE_GETRUSAGE ++ ++/* Define to 1 if you have the `getsubopt' function. */ ++#undef HAVE_GETSUBOPT ++ ++/* Define to 1 if you have the `getusershell' function. */ ++#undef HAVE_GETUSERSHELL ++ + /* Define to 1 if you have the `getwd' function. */ +@@ -55,2 +145,14 @@ + ++/* Define to 1 if you have the `grantpt' function. */ ++#undef HAVE_GRANTPT ++ ++/* Define to 1 if you have the `group_member' function. */ ++#undef HAVE_GROUP_MEMBER ++ ++/* Define to 1 if you have the `initstate' function. */ ++#undef HAVE_INITSTATE ++ ++/* Define to 1 if you have the `initstate_r' function. */ ++#undef HAVE_INITSTATE_R ++ + /* Define to 1 if you have the header file. */ +@@ -58,2 +160,5 @@ + ++/* Define to 1 if you have the `kill' function. */ ++#undef HAVE_KILL ++ + /* Define to 1 if you have the `killpg' function. */ +@@ -61,2 +166,8 @@ + ++/* Define to 1 if you have the `lchmod' function. */ ++#undef HAVE_LCHMOD ++ ++/* Define to 1 if you have the `lchown' function. */ ++#undef HAVE_LCHOWN ++ + /* Define to 1 if you have the header file. */ +@@ -67,2 +178,11 @@ + ++/* Define to 1 if you have the `link' function. */ ++#undef HAVE_LINK ++ ++/* Define to 1 if you have the `linkat' function. */ ++#undef HAVE_LINKAT ++ ++/* Define to 1 if you have the `lstat' function. */ ++#undef HAVE_LSTAT ++ + /* Define to 1 if you have the header file. */ +@@ -70,2 +190,32 @@ + ++/* Define to 1 if you have the `mkdirat' function. */ ++#undef HAVE_MKDIRAT ++ ++/* Define to 1 if you have the `mkdtemp' function. */ ++#undef HAVE_MKDTEMP ++ ++/* Define to 1 if you have the `mkfifo' function. */ ++#undef HAVE_MKFIFO ++ ++/* Define to 1 if you have the `mkfifoat' function. */ ++#undef HAVE_MKFIFOAT ++ ++/* Define to 1 if you have the `mknod' function. */ ++#undef HAVE_MKNOD ++ ++/* Define to 1 if you have the `mknodat' function. */ ++#undef HAVE_MKNODAT ++ ++/* Define to 1 if you have the `mkostemp' function. */ ++#undef HAVE_MKOSTEMP ++ ++/* Define to 1 if you have the `mkostemps' function. */ ++#undef HAVE_MKOSTEMPS ++ ++/* Define to 1 if you have the `mkstemp' function. */ ++#undef HAVE_MKSTEMP ++ ++/* Define to 1 if you have the `mkstemps' function. */ ++#undef HAVE_MKSTEMPS ++ + /* Define to 1 if you have the `mmap' function. */ +@@ -76,2 +226,5 @@ + ++/* Define to 1 if you have the `openat' function. */ ++#undef HAVE_OPENAT ++ + /* Define to 1 if you have the header file. */ +@@ -79,2 +232,11 @@ + ++/* Define to 1 if you have the `pipe' function. */ ++#undef HAVE_PIPE ++ ++/* Define to 1 if you have the `pipe2' function. */ ++#undef HAVE_PIPE2 ++ ++/* Define to 1 if you have the `poll' function. */ ++#undef HAVE_POLL ++ + /* Define to 1 if you have the header file. */ +@@ -82,2 +244,17 @@ + ++/* Define to 1 if you have the `posix_openpt' function. */ ++#undef HAVE_POSIX_OPENPT ++ ++/* Define to 1 if you have the `pread' function. */ ++#undef HAVE_PREAD ++ ++/* Define to 1 if you have the `pthread_sigmask' function. */ ++#undef HAVE_PTHREAD_SIGMASK ++ ++/* Define to 1 if you have the `ptsname' function. */ ++#undef HAVE_PTSNAME ++ ++/* Define to 1 if you have the `ptsname_r' function. */ ++#undef HAVE_PTSNAME_R ++ + /* Define to 1 if you have the `putenv' function. */ +@@ -85,2 +262,17 @@ + ++/* Define to 1 if you have the `pwrite' function. */ ++#undef HAVE_PWRITE ++ ++/* Define to 1 if you have the `qsort_r' function. */ ++#undef HAVE_QSORT_R ++ ++/* Define to 1 if you have the `raise' function. */ ++#undef HAVE_RAISE ++ ++/* Define to 1 if you have the `random' function. */ ++#undef HAVE_RANDOM ++ ++/* Define to 1 if you have the `random_r' function. */ ++#undef HAVE_RANDOM_R ++ + /* Define to 1 if you have the header file. */ +@@ -88,2 +280,11 @@ + ++/* Define to 1 if you have the `readlink' function. */ ++#undef HAVE_READLINK ++ ++/* Define to 1 if you have the `readlinkat' function. */ ++#undef HAVE_READLINKAT ++ ++/* Define to 1 if you have the `reallocarray' function. */ ++#undef HAVE_REALLOCARRAY ++ + /* Define to 1 if you have the `realpath' function. */ +@@ -91,2 +292,20 @@ + ++/* Define to 1 if you have the `regcomp' function. */ ++#undef HAVE_REGCOMP ++ ++/* Define to 1 if you have the `regerror' function. */ ++#undef HAVE_REGERROR ++ ++/* Define to 1 if you have the `regexec' function. */ ++#undef HAVE_REGEXEC ++ ++/* Define to 1 if you have the `regfree' function. */ ++#undef HAVE_REGFREE ++ ++/* Define to 1 if you have the `rpmatch' function. */ ++#undef HAVE_RPMATCH ++ ++/* Define to 1 if you have the `secure_getenv' function. */ ++#undef HAVE_SECURE_GETENV ++ + /* Define to 1 if you have the `select' function. */ +@@ -97,2 +316,5 @@ + ++/* Define to 1 if you have the `sethostname' function. */ ++#undef HAVE_SETHOSTNAME ++ + /* Define to 1 if you have the `setpgid' function. */ +@@ -100,2 +322,5 @@ + ++/* Define to 1 if you have the `setpgrp' function. */ ++#undef HAVE_SETPGRP ++ + /* Define to 1 if you have the `setsid' function. */ +@@ -103,2 +328,11 @@ + ++/* Define to 1 if you have the `setstate' function. */ ++#undef HAVE_SETSTATE ++ ++/* Define to 1 if you have the `setstate_r' function. */ ++#undef HAVE_SETSTATE_R ++ ++/* Define to 1 if you have the `setusershell' function. */ ++#undef HAVE_SETUSERSHELL ++ + /* Define to 1 if you have the `sigaction' function. */ +@@ -106,2 +340,26 @@ + ++/* Define to 1 if you have the `sigaddset' function. */ ++#undef HAVE_SIGADDSET ++ ++/* Define to 1 if you have the `sigdelset' function. */ ++#undef HAVE_SIGDELSET ++ ++/* Define to 1 if you have the `sigemptyset' function. */ ++#undef HAVE_SIGEMPTYSET ++ ++/* Define to 1 if you have the `sigfillset' function. */ ++#undef HAVE_SIGFILLSET ++ ++/* Define to 1 if you have the `sigismember' function. */ ++#undef HAVE_SIGISMEMBER ++ ++/* Define to 1 if you have the `signal' function. */ ++#undef HAVE_SIGNAL ++ ++/* Define to 1 if you have the `sigpending' function. */ ++#undef HAVE_SIGPENDING ++ ++/* Define to 1 if you have the `sigprocmask' function. */ ++#undef HAVE_SIGPROCMASK ++ + /* Define to 1 if you have the `sigvec' function. */ +@@ -109,2 +367,5 @@ + ++/* Define to 1 if you have the `sleep' function. */ ++#undef HAVE_SLEEP ++ + /* Define to 1 if you have the `snprintf' function. */ +@@ -112,2 +373,8 @@ + ++/* Define to 1 if you have the `srandom' function. */ ++#undef HAVE_SRANDOM ++ ++/* Define to 1 if you have the `srandom_r' function. */ ++#undef HAVE_SRANDOM_R ++ + /* Define to 1 if you have the header file. */ +@@ -145,3 +412,9 @@ + +-/* Define to 1 if `struct stat' is a member of `st_rdev'. */ ++/* Define to 1 if you have the `strtoll' function. */ ++#undef HAVE_STRTOLL ++ ++/* Define to 1 if you have the `strtoull' function. */ ++#undef HAVE_STRTOULL ++ ++/* Define to 1 if `st_rdev' is a member of `struct stat'. */ + #undef HAVE_STRUCT_STAT_ST_RDEV +@@ -152,2 +425,8 @@ + ++/* Define to 1 if you have the `symlink' function. */ ++#undef HAVE_SYMLINK ++ ++/* Define to 1 if you have the `symlinkat' function. */ ++#undef HAVE_SYMLINKAT ++ + /* Define to 1 if you have the `sysctl' function. */ +@@ -169,2 +448,5 @@ + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_RESOURCE_H ++ + /* Define to 1 if you have the header file. */ +@@ -190,5 +472,17 @@ + +-/* Define to 1 if you have that is POSIX.1 compatible. */ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_UTSNAME_H ++ ++/* Define to 1 if you have the header file. */ + #undef HAVE_SYS_WAIT_H + ++/* Define to 1 if you have the `truncate' function. */ ++#undef HAVE_TRUNCATE ++ ++/* Define to 1 if you have the `ttyname_r' function. */ ++#undef HAVE_TTYNAME_R ++ ++/* Define to 1 if you have the `uname' function. */ ++#undef HAVE_UNAME ++ + /* Define to 1 if you have the header file. */ +@@ -196,2 +490,8 @@ + ++/* Define to 1 if you have the `unlinkat' function. */ ++#undef HAVE_UNLINKAT ++ ++/* Define to 1 if you have the `unlockpt' function. */ ++#undef HAVE_UNLOCKPT ++ + /* Define to 1 if you have the `unsetenv' function. */ +@@ -199,2 +499,8 @@ + ++/* Define to 1 if you have the `usleep' function. */ ++#undef HAVE_USLEEP ++ ++/* Define to 1 if you have the `utimensat' function. */ ++#undef HAVE_UTIMENSAT ++ + /* Define to 1 if you have the header file. */ +@@ -214,2 +520,5 @@ + ++/* Define to 1 if you have the `wait' function. */ ++#undef HAVE_WAIT ++ + /* Define to 1 if you have the `wait3' function. */ +@@ -235,2 +544,5 @@ + ++/* Define to 1 if you have the `_Exit' function. */ ++#undef HAVE__EXIT ++ + /* define if your compiler has __attribute__ */ +@@ -326,2 +638,6 @@ + ++/* Define to the type of a signed integer type of width exactly 32 bits if ++ such a type exists and the standard includes do not define it. */ ++#undef int32_t ++ + /* Define to `int' if does not define. */ +diff --git a/configure b/configure +index 1ce8dfe..42ac2d4 100755 +--- a/configure ++++ b/configure +@@ -2,3 +2,3 @@ + # Guess values for system-dependent variables and create Makefiles. +-# Generated by GNU Autoconf 2.64 for bmake 20171126. ++# Generated by GNU Autoconf 2.69 for bmake 20171126. + # +@@ -6,5 +6,5 @@ + # +-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software +-# Foundation, Inc. ++# ++# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. ++# + # +@@ -91,2 +91,3 @@ IFS=" "" $as_nl" + # Find who we are. Look in the path if we contain no directory separator. ++as_myself= + case $0 in #(( +@@ -135,2 +136,27 @@ export LANGUAGE + ++# Use a proper internal environment variable to ensure we don't fall ++ # into an infinite loop, continuously re-executing ourselves. ++ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then ++ _as_can_reexec=no; export _as_can_reexec; ++ # We cannot yet assume a decent shell, so we have to provide a ++# neutralization value for shells without unset; and this also ++# works around shells that cannot unset nonexistent variables. ++# Preserve -v and -x to the replacement shell. ++BASH_ENV=/dev/null ++ENV=/dev/null ++(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV ++case $- in # (((( ++ *v*x* | *x*v* ) as_opts=-vx ;; ++ *v* ) as_opts=-v ;; ++ *x* ) as_opts=-x ;; ++ * ) as_opts= ;; ++esac ++exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} ++# Admittedly, this is quite paranoid, since all the known shells bail ++# out after a failed `exec'. ++$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 ++as_fn_exit 255 ++ fi ++ # We don't want this to propagate to other subprocesses. ++ { _as_can_reexec=; unset _as_can_reexec;} + if test "x$CONFIG_SHELL" = x; then +@@ -168,3 +194,4 @@ else + fi +-test x\$exitcode = x0 || exit 1" ++test x\$exitcode = x0 || exit 1 ++test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO +@@ -213,10 +240,21 @@ IFS=$as_save_IFS + if test "x$CONFIG_SHELL" != x; then : +- # We cannot yet assume a decent shell, so we have to provide a +- # neutralization value for shells without unset; and this also +- # works around shells that cannot unset nonexistent variables. +- BASH_ENV=/dev/null +- ENV=/dev/null +- (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +- export CONFIG_SHELL +- exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} ++ export CONFIG_SHELL ++ # We cannot yet assume a decent shell, so we have to provide a ++# neutralization value for shells without unset; and this also ++# works around shells that cannot unset nonexistent variables. ++# Preserve -v and -x to the replacement shell. ++BASH_ENV=/dev/null ++ENV=/dev/null ++(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV ++case $- in # (((( ++ *v*x* | *x*v* ) as_opts=-vx ;; ++ *v* ) as_opts=-v ;; ++ *x* ) as_opts=-x ;; ++ * ) as_opts= ;; ++esac ++exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} ++# Admittedly, this is quite paranoid, since all the known shells bail ++# out after a failed `exec'. ++$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 ++exit 255 + fi +@@ -319,3 +357,3 @@ $as_echo X"$as_dir" | + test -z "$as_dirs" || eval "mkdir $as_dirs" +- } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" ++ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + +@@ -323,2 +361,10 @@ $as_echo X"$as_dir" | + } # as_fn_mkdir_p ++ ++# as_fn_executable_p FILE ++# ----------------------- ++# Test if FILE is an executable regular file. ++as_fn_executable_p () ++{ ++ test -f "$1" && test -x "$1" ++} # as_fn_executable_p + # as_fn_append VAR VALUE +@@ -359,15 +405,15 @@ fi # as_fn_arith + +-# as_fn_error ERROR [LINENO LOG_FD] +-# --------------------------------- ++# as_fn_error STATUS ERROR [LINENO LOG_FD] ++# ---------------------------------------- + # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are + # provided, also output the error to LOG_FD, referencing LINENO. Then exit the +-# script with status $?, using 1 if that was 0. ++# script with STATUS, using 1 if that was 0. + as_fn_error () + { +- as_status=$?; test $as_status -eq 0 && as_status=1 +- if test "$3"; then +- as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack +- $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 ++ as_status=$1; test $as_status -eq 0 && as_status=1 ++ if test "$4"; then ++ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi +- $as_echo "$as_me: error: $1" >&2 ++ $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +@@ -444,2 +490,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits + ++ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have ++ # already done that, so ensure we don't try to do so again and fall ++ # in an infinite loop. This has already happened in practice. ++ _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems +@@ -478,5 +528,5 @@ if (echo >conf$$.file) 2>/dev/null; then + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. +- # In both cases, we have to default to `cp -p'. ++ # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || +- as_ln_s='cp -p' ++ as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then +@@ -484,6 +534,6 @@ if (echo >conf$$.file) 2>/dev/null; then + else +- as_ln_s='cp -p' ++ as_ln_s='cp -pR' + fi + else +- as_ln_s='cp -p' ++ as_ln_s='cp -pR' + fi +@@ -499,24 +549,4 @@ fi + +-if test -x / >/dev/null 2>&1; then +- as_test_x='test -x' +-else +- if ls -dL / >/dev/null 2>&1; then +- as_ls_L_option=L +- else +- as_ls_L_option= +- fi +- as_test_x=' +- eval sh -c '\'' +- if test -d "$1"; then +- test -d "$1/."; +- else +- case $1 in #( +- -*)set "./$1";; +- esac; +- case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( +- ???[sx]*):;;*)false;;esac;fi +- '\'' sh +- ' +-fi +-as_executable_p=$as_test_x ++as_test_x='test -x' ++as_executable_p=as_fn_executable_p + +@@ -529,6 +559,7 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +-exec 7<&0 &1 ++test -n "$DJDIR" || exec 7<&0 &1 + + # Name of the host. +-# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, ++# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, + # so uname gets run too. +@@ -745,4 +776,5 @@ do + case $ac_option in +- *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; +- *) ac_optarg=yes ;; ++ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; ++ *=) ac_optarg= ;; ++ *) ac_optarg=yes ;; + esac +@@ -791,3 +823,3 @@ do + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- as_fn_error "invalid feature name: $ac_useropt" ++ as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt +@@ -817,3 +849,3 @@ do + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- as_fn_error "invalid feature name: $ac_useropt" ++ as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt +@@ -1021,3 +1053,3 @@ do + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- as_fn_error "invalid package name: $ac_useropt" ++ as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt +@@ -1037,3 +1069,3 @@ do + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && +- as_fn_error "invalid package name: $ac_useropt" ++ as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt +@@ -1067,4 +1099,4 @@ do + +- -*) as_fn_error "unrecognized option: \`$ac_option' +-Try \`$0 --help' for more information." ++ -*) as_fn_error $? "unrecognized option: \`$ac_option' ++Try \`$0 --help' for more information" + ;; +@@ -1076,3 +1108,3 @@ Try \`$0 --help' for more information." + '' | [0-9]* | *[!_$as_cr_alnum]* ) +- as_fn_error "invalid variable name: \`$ac_envvar'" ;; ++ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac +@@ -1086,3 +1118,3 @@ Try \`$0 --help' for more information." + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 +- : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ++ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; +@@ -1094,3 +1126,3 @@ if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` +- as_fn_error "missing argument to $ac_option" ++ as_fn_error $? "missing argument to $ac_option" + fi +@@ -1100,3 +1132,3 @@ if test -n "$ac_unrecognized_opts"; then + no) ;; +- fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; ++ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; +@@ -1123,3 +1155,3 @@ do + esac +- as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" ++ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" + done +@@ -1137,4 +1169,2 @@ if test "x$host_alias" != x; then + cross_compiling=maybe +- $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. +- If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then +@@ -1153,5 +1183,5 @@ ac_ls_di=`ls -di .` && + ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || +- as_fn_error "working directory cannot be determined" ++ as_fn_error $? "working directory cannot be determined" + test "X$ac_ls_di" = "X$ac_pwd_ls_di" || +- as_fn_error "pwd does not report name of working directory" ++ as_fn_error $? "pwd does not report name of working directory" + +@@ -1194,3 +1224,3 @@ if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." +- as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" ++ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" + fi +@@ -1198,3 +1228,3 @@ ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" + ac_abs_confdir=`( +- cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" ++ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +@@ -1238,3 +1268,3 @@ Configuration: + -V, --version display version information and exit +- -q, --quiet, --silent do not print \`checking...' messages ++ -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] +@@ -1320,3 +1350,3 @@ Some influential environment variables: + LIBS libraries to pass to the linker, e.g. -l +- CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if ++ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory +@@ -1391,5 +1421,5 @@ if $ac_init_version; then + bmake configure 20171126 +-generated by GNU Autoconf 2.64 ++generated by GNU Autoconf 2.69 + +-Copyright (C) 2009 Free Software Foundation, Inc. ++Copyright (C) 2012 Free Software Foundation, Inc. + This configure script is free software; the Free Software Foundation +@@ -1437,4 +1467,4 @@ sed 's/^/| /' conftest.$ac_ext >&5 + fi +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} +- return $ac_retval ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval + +@@ -1463,3 +1493,3 @@ $as_echo "$ac_try_echo"; } >&5 + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 +- test $ac_status = 0; } >/dev/null && { ++ test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || +@@ -1474,4 +1504,4 @@ sed 's/^/| /' conftest.$ac_ext >&5 + fi +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} +- return $ac_retval ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval + +@@ -1487,6 +1517,6 @@ ac_fn_c_check_header_mongrel () + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack +- if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : ++ if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 + $as_echo_n "checking for $2... " >&6; } +-if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : ++if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -1526,3 +1556,3 @@ else + fi +-rm -f conftest.err conftest.$ac_ext ++rm -f conftest.err conftest.i conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +@@ -1549,7 +1579,5 @@ $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" > + $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +-( cat <<\_ASBOX +-## ----------------------------- ## ++( $as_echo "## ----------------------------- ## + ## Report this to sjg@NetBSD.org ## +-## ----------------------------- ## +-_ASBOX ++## ----------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 +@@ -1559,3 +1587,3 @@ esac + $as_echo_n "checking for $2... " >&6; } +-if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : ++if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -1568,3 +1596,3 @@ $as_echo "$ac_res" >&6; } + fi +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +@@ -1609,4 +1637,4 @@ fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} +- return $ac_retval ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval + +@@ -1623,3 +1651,3 @@ ac_fn_c_check_header_compile () + $as_echo_n "checking for $2... " >&6; } +-if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : ++if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -1641,3 +1669,3 @@ eval ac_res=\$$3 + $as_echo "$ac_res" >&6; } +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +@@ -1672,3 +1700,3 @@ $as_echo "$ac_try_echo"; } >&5 + test "$cross_compiling" = yes || +- $as_test_x conftest$ac_exeext ++ test -x conftest$ac_exeext + }; then : +@@ -1686,4 +1714,4 @@ fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} +- return $ac_retval ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval + +@@ -1691,2 +1719,78 @@ fi + ++# ac_fn_c_find_intX_t LINENO BITS VAR ++# ----------------------------------- ++# Finds a signed integer type with width BITS, setting cache variable VAR ++# accordingly. ++ac_fn_c_find_intX_t () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 ++$as_echo_n "checking for int$2_t... " >&6; } ++if eval \${$3+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ eval "$3=no" ++ # Order is important - never check a type that is potentially smaller ++ # than half of the expected target width. ++ for ac_type in int$2_t 'int' 'long int' \ ++ 'long long int' 'short int' 'signed char'; do ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$ac_includes_default ++ enum { N = $2 / 2 - 1 }; ++int ++main () ++{ ++static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; ++test_array [0] = 0; ++return test_array [0]; ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$ac_includes_default ++ enum { N = $2 / 2 - 1 }; ++int ++main () ++{ ++static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) ++ < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; ++test_array [0] = 0; ++return test_array [0]; ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ++else ++ case $ac_type in #( ++ int$2_t) : ++ eval "$3=yes" ;; #( ++ *) : ++ eval "$3=\$ac_type" ;; ++esac ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++ if eval test \"x\$"$3"\" = x"no"; then : ++ ++else ++ break ++fi ++ done ++fi ++eval ac_res=\$$3 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ ++} # ac_fn_c_find_intX_t ++ + # ac_fn_c_check_type LINENO TYPE VAR INCLUDES +@@ -1700,3 +1804,3 @@ ac_fn_c_check_type () + $as_echo_n "checking for $2... " >&6; } +-if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : ++if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -1741,3 +1845,3 @@ eval ac_res=\$$3 + $as_echo "$ac_res" >&6; } +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +@@ -1754,3 +1858,3 @@ ac_fn_c_find_uintX_t () + $as_echo_n "checking for uint$2_t... " >&6; } +-if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : ++if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -1758,2 +1862,4 @@ else + eval "$3=no" ++ # Order is important - never check a type that is potentially smaller ++ # than half of the expected target width. + for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ +@@ -1766,4 +1872,5 @@ main () + { +-static int test_array [1 - 2 * !(($ac_type) -1 >> ($2 - 1) == 1)]; +-test_array [0] = 0 ++static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; ++test_array [0] = 0; ++return test_array [0]; + +@@ -1782,4 +1889,3 @@ fi + rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +- eval as_val=\$$3 +- if test "x$as_val" = x""no; then : ++ if eval test \"x\$"$3"\" = x"no"; then : + +@@ -1793,3 +1899,3 @@ eval ac_res=\$$3 + $as_echo "$ac_res" >&6; } +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +@@ -1797,5 +1903,6 @@ $as_echo "$ac_res" >&6; } + +-# ac_fn_c_check_decl LINENO SYMBOL VAR +-# ------------------------------------ +-# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. ++# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES ++# --------------------------------------------- ++# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR ++# accordingly. + ac_fn_c_check_decl () +@@ -1803,5 +1910,7 @@ ac_fn_c_check_decl () + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5 +-$as_echo_n "checking whether $2 is declared... " >&6; } +-if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : ++ as_decl_name=`echo $2|sed 's/ *(.*//'` ++ as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 ++$as_echo_n "checking whether $as_decl_name is declared... " >&6; } ++if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -1814,4 +1923,8 @@ main () + { +-#ifndef $2 +- (void) $2; ++#ifndef $as_decl_name ++#ifdef __cplusplus ++ (void) $as_decl_use; ++#else ++ (void) $as_decl_name; ++#endif + #endif +@@ -1832,3 +1945,3 @@ eval ac_res=\$$3 + $as_echo "$ac_res" >&6; } +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +@@ -1844,3 +1957,3 @@ ac_fn_c_check_func () + $as_echo_n "checking for $2... " >&6; } +-if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : ++if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -1899,3 +2012,3 @@ eval ac_res=\$$3 + $as_echo "$ac_res" >&6; } +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +@@ -1912,3 +2025,3 @@ ac_fn_c_check_member () + $as_echo_n "checking for $2.$3... " >&6; } +-if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then : ++if eval \${$4+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -1956,3 +2069,3 @@ eval ac_res=\$$4 + $as_echo "$ac_res" >&6; } +- eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +@@ -1964,3 +2077,3 @@ running configure, to aid debugging if configure makes a mistake. + It was created by bmake $as_me 20171126, which was +-generated by GNU Autoconf 2.64. Invocation command line was ++generated by GNU Autoconf 2.69. Invocation command line was + +@@ -2074,7 +2187,5 @@ trap 'exit_status=$? + +- cat <<\_ASBOX +-## ---------------- ## ++ $as_echo "## ---------------- ## + ## Cache variables. ## +-## ---------------- ## +-_ASBOX ++## ---------------- ##" + echo +@@ -2112,7 +2223,5 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + +- cat <<\_ASBOX +-## ----------------- ## ++ $as_echo "## ----------------- ## + ## Output variables. ## +-## ----------------- ## +-_ASBOX ++## ----------------- ##" + echo +@@ -2129,7 +2238,5 @@ _ASBOX + if test -n "$ac_subst_files"; then +- cat <<\_ASBOX +-## ------------------- ## ++ $as_echo "## ------------------- ## + ## File substitutions. ## +-## ------------------- ## +-_ASBOX ++## ------------------- ##" + echo +@@ -2147,7 +2254,5 @@ _ASBOX + if test -s confdefs.h; then +- cat <<\_ASBOX +-## ----------- ## ++ $as_echo "## ----------- ## + ## confdefs.h. ## +-## ----------- ## +-_ASBOX ++## ----------- ##" + echo +@@ -2206,3 +2311,8 @@ ac_site_file2=NONE + if test -n "$CONFIG_SITE"; then +- ac_site_file1=$CONFIG_SITE ++ # We do not want a PATH search for config.site. ++ case $CONFIG_SITE in #(( ++ -*) ac_site_file1=./$CONFIG_SITE;; ++ */*) ac_site_file1=$CONFIG_SITE;; ++ *) ac_site_file1=./$CONFIG_SITE;; ++ esac + elif test "x$prefix" != xNONE; then +@@ -2217,3 +2327,3 @@ do + test "x$ac_site_file" = xNONE && continue +- if test -r "$ac_site_file"; then ++ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +@@ -2221,3 +2331,7 @@ $as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 +- . "$ac_site_file" ++ . "$ac_site_file" \ ++ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "failed to load site script $ac_site_file ++See \`config.log' for more details" "$LINENO" 5; } + fi +@@ -2226,5 +2340,5 @@ done + if test -r "$cache_file"; then +- # Some versions of bash will fail to source /dev/null (special +- # files actually), so we avoid doing that. +- if test -f "$cache_file"; then ++ # Some versions of bash will fail to source /dev/null (special files ++ # actually), so we avoid doing that. DJGPP emulates it as a regular file. ++ if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +@@ -2297,3 +2411,3 @@ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} +- as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 ++ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 + fi +@@ -2324,3 +2438,3 @@ if test "${with_defshell+set}" = set; then : + withval=$with_defshell; case "${withval}" in +-yes) as_fn_error "bad value ${withval} given for bmake DEFSHELL" "$LINENO" 5 ;; ++yes) as_fn_error $? "bad value ${withval} given for bmake DEFSHELL" "$LINENO" 5 ;; + no) ;; +@@ -2342,3 +2456,3 @@ if test "${with_meta+set}" = set; then : + yes|no) use_meta=${withval};; +-*) as_fn_error "bad value ${withval} given for meta" "$LINENO" 5 ;; ++*) as_fn_error $? "bad value ${withval} given for meta" "$LINENO" 5 ;; + esac +@@ -2352,3 +2466,3 @@ if test "${with_filemon+set}" = set; then : + */filemon*) filemon_h="${withval}/filemon.h";; +-*) as_fn_error "bad value ${withval} given for filemon" "$LINENO" 5 ;; ++*) as_fn_error $? "bad value ${withval} given for filemon" "$LINENO" 5 ;; + esac +@@ -2356,3 +2470,3 @@ else + +-OS=`uname -s` ++OS=`uname -s | cut -d_ -f1` + for d in "/usr/include/dev/filemon" "$prefix/include/dev/filemon" "$srcdir/filemon" "$srcdir/../filemon" "$srcdir/../../sys/dev/filemon" +@@ -2387,3 +2501,3 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then : ++if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -2399,3 +2513,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" +@@ -2427,3 +2541,3 @@ set dummy gcc; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : ++if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -2439,3 +2553,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" +@@ -2480,3 +2594,3 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then : ++if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -2492,3 +2606,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" +@@ -2520,3 +2634,3 @@ set dummy cc; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then : ++if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -2533,3 +2647,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then +@@ -2579,3 +2693,3 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then : ++if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -2591,3 +2705,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" +@@ -2623,3 +2737,3 @@ set dummy $ac_prog; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : ++if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -2635,3 +2749,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" +@@ -2677,4 +2791,4 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd' + $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-as_fn_error "no acceptable C compiler found in \$PATH +-See \`config.log' for more details." "$LINENO" 5; } ++as_fn_error $? "no acceptable C compiler found in \$PATH ++See \`config.log' for more details" "$LINENO" 5; } + +@@ -2699,4 +2813,4 @@ $as_echo "$ac_try_echo"; } >&5 + cat conftest.er1 >&5 +- rm -f conftest.er1 conftest.err + fi ++ rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 +@@ -2707,3 +2821,3 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext + /* end confdefs.h. */ +-#include ++ + int +@@ -2711,4 +2825,2 @@ main () + { +-FILE *f = fopen ("conftest.out", "w"); +- return ferror (f) || fclose (f) != 0; + +@@ -2719,3 +2831,3 @@ _ACEOF + ac_clean_files_save=$ac_clean_files +-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" ++ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" + # Try to create an executable without -o first, disregard a.out. +@@ -2723,4 +2835,4 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" + # of exeext. +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +-$as_echo_n "checking for C compiler default output file name... " >&6; } ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 ++$as_echo_n "checking whether the C compiler works... " >&6; } + ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +@@ -2786,6 +2898,6 @@ else + fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +-$as_echo "$ac_file" >&6; } + if test -z "$ac_file"; then : +- $as_echo "$as_me: failed program was:" >&5 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++$as_echo "$as_me: failed program was:" >&5 + sed 's/^/| /' conftest.$ac_ext >&5 +@@ -2794,50 +2906,16 @@ sed 's/^/| /' conftest.$ac_ext >&5 + $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-{ as_fn_set_status 77 +-as_fn_error "C compiler cannot create executables +-See \`config.log' for more details." "$LINENO" 5; }; } ++as_fn_error 77 "C compiler cannot create executables ++See \`config.log' for more details" "$LINENO" 5; } ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } + fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 ++$as_echo_n "checking for C compiler default output file name... " >&6; } ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 ++$as_echo "$ac_file" >&6; } + ac_exeext=$ac_cv_exeext + +-# Check that the compiler produces executables we can run. If not, either +-# the compiler is broken, or we cross compile. +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +-$as_echo_n "checking whether the C compiler works... " >&6; } +-# If not cross compiling, check that we can run a simple program. +-if test "$cross_compiling" != yes; then +- if { ac_try='./$ac_file' +- { { case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +-$as_echo "$ac_try_echo"; } >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 +- test $ac_status = 0; }; }; then +- cross_compiling=no +- else +- if test "$cross_compiling" = maybe; then +- cross_compiling=yes +- else +- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-as_fn_error "cannot run C compiled programs. +-If you meant to cross compile, use \`--host'. +-See \`config.log' for more details." "$LINENO" 5; } +- fi +- fi +-fi +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +-$as_echo "yes" >&6; } +- +-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out ++rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out + ac_clean_files=$ac_clean_files_save +-# Check that the compiler produces executables we can run. If not, either +-# the compiler is broken, or we cross compile. +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +-$as_echo_n "checking whether we are cross compiling... " >&6; } +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +-$as_echo "$cross_compiling" >&6; } +- + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +@@ -2871,6 +2949,6 @@ else + $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-as_fn_error "cannot compute suffix of executables: cannot compile and link +-See \`config.log' for more details." "$LINENO" 5; } ++as_fn_error $? "cannot compute suffix of executables: cannot compile and link ++See \`config.log' for more details" "$LINENO" 5; } + fi +-rm -f conftest$ac_cv_exeext ++rm -f conftest conftest$ac_cv_exeext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +@@ -2881,5 +2959,64 @@ EXEEXT=$ac_cv_exeext + ac_exeext=$EXEEXT ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include ++int ++main () ++{ ++FILE *f = fopen ("conftest.out", "w"); ++ return ferror (f) || fclose (f) != 0; ++ ++ ; ++ return 0; ++} ++_ACEOF ++ac_clean_files="$ac_clean_files conftest.out" ++# Check that the compiler produces executables we can run. If not, either ++# the compiler is broken, or we cross compile. ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 ++$as_echo_n "checking whether we are cross compiling... " >&6; } ++if test "$cross_compiling" != yes; then ++ { { ac_try="$ac_link" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_link") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } ++ if { ac_try='./conftest$ac_cv_exeext' ++ { { case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_try") 2>&5 ++ ac_status=$? ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; }; then ++ cross_compiling=no ++ else ++ if test "$cross_compiling" = maybe; then ++ cross_compiling=yes ++ else ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "cannot run C compiled programs. ++If you meant to cross compile, use \`--host'. ++See \`config.log' for more details" "$LINENO" 5; } ++ fi ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 ++$as_echo "$cross_compiling" >&6; } ++ ++rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ++ac_clean_files=$ac_clean_files_save + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 + $as_echo_n "checking for suffix of object files... " >&6; } +-if test "${ac_cv_objext+set}" = set; then : ++if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -2923,4 +3060,4 @@ sed 's/^/| /' conftest.$ac_ext >&5 + $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-as_fn_error "cannot compute suffix of object files: cannot compile +-See \`config.log' for more details." "$LINENO" 5; } ++as_fn_error $? "cannot compute suffix of object files: cannot compile ++See \`config.log' for more details" "$LINENO" 5; } + fi +@@ -2934,3 +3071,3 @@ ac_objext=$OBJEXT + $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +-if test "${ac_cv_c_compiler_gnu+set}" = set; then : ++if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -2971,3 +3108,3 @@ ac_save_CFLAGS=$CFLAGS + $as_echo_n "checking whether $CC accepts -g... " >&6; } +-if test "${ac_cv_prog_cc_g+set}" = set; then : ++if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3049,3 +3186,3 @@ fi + $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +-if test "${ac_cv_prog_cc_c89+set}" = set; then : ++if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3058,4 +3195,3 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext + #include +-#include +-#include ++struct stat; + /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +@@ -3157,3 +3293,3 @@ fi + if test -z "$CPP"; then +- if test "${ac_cv_prog_CPP+set}" = set; then : ++ if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3187,3 +3323,3 @@ continue + fi +-rm -f conftest.err conftest.$ac_ext ++rm -f conftest.err conftest.i conftest.$ac_ext + +@@ -3203,3 +3339,3 @@ break + fi +-rm -f conftest.err conftest.$ac_ext ++rm -f conftest.err conftest.i conftest.$ac_ext + +@@ -3207,3 +3343,3 @@ done + # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +-rm -f conftest.err conftest.$ac_ext ++rm -f conftest.i conftest.err conftest.$ac_ext + if $ac_preproc_ok; then : +@@ -3246,3 +3382,3 @@ continue + fi +-rm -f conftest.err conftest.$ac_ext ++rm -f conftest.err conftest.i conftest.$ac_ext + +@@ -3262,3 +3398,3 @@ break + fi +-rm -f conftest.err conftest.$ac_ext ++rm -f conftest.err conftest.i conftest.$ac_ext + +@@ -3266,3 +3402,3 @@ done + # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +-rm -f conftest.err conftest.$ac_ext ++rm -f conftest.i conftest.err conftest.$ac_ext + if $ac_preproc_ok; then : +@@ -3272,4 +3408,4 @@ else + $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-as_fn_error "C preprocessor \"$CPP\" fails sanity check +-See \`config.log' for more details." "$LINENO" 5; } ++as_fn_error $? "C preprocessor \"$CPP\" fails sanity check ++See \`config.log' for more details" "$LINENO" 5; } + fi +@@ -3285,3 +3421,3 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + $as_echo_n "checking for grep that handles long lines and -e... " >&6; } +-if test "${ac_cv_path_GREP+set}" = set; then : ++if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3299,3 +3435,3 @@ do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" +- { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue ++ as_fn_executable_p "$ac_path_GREP" || continue + # Check for GNU ac_path_GREP and select it if it is found. +@@ -3334,3 +3470,3 @@ IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then +- as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 ++ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +@@ -3348,3 +3484,3 @@ $as_echo "$ac_cv_path_GREP" >&6; } + $as_echo_n "checking for egrep... " >&6; } +-if test "${ac_cv_path_EGREP+set}" = set; then : ++if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3365,3 +3501,3 @@ do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" +- { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue ++ as_fn_executable_p "$ac_path_EGREP" || continue + # Check for GNU ac_path_EGREP and select it if it is found. +@@ -3400,3 +3536,3 @@ IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then +- as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 ++ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +@@ -3415,3 +3551,3 @@ $as_echo "$ac_cv_path_EGREP" >&6; } + $as_echo_n "checking for ANSI C header files... " >&6; } +-if test "${ac_cv_header_stdc+set}" = set; then : ++if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3532,4 +3668,3 @@ ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_include + " +-eval as_val=\$$as_ac_Header +- if test "x$as_val" = x""yes; then : ++if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +@@ -3545,3 +3680,3 @@ done + ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" +-if test "x$ac_cv_header_minix_config_h" = x""yes; then : ++if test "x$ac_cv_header_minix_config_h" = xyes; then : + MINIX=yes +@@ -3567,3 +3702,3 @@ $as_echo "#define _MINIX 1" >>confdefs.h + $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +-if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : ++if ${ac_cv_safe_to_define___extensions__+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3573,4 +3708,4 @@ else + +-# define __EXTENSIONS__ 1 +- $ac_includes_default ++# define __EXTENSIONS__ 1 ++ $ac_includes_default + int +@@ -3614,3 +3749,3 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then : ++if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3626,3 +3761,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" +@@ -3654,3 +3789,3 @@ set dummy gcc; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : ++if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3666,3 +3801,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" +@@ -3707,3 +3842,3 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then : ++if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3719,3 +3854,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" +@@ -3747,3 +3882,3 @@ set dummy cc; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then : ++if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3760,3 +3895,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then +@@ -3806,3 +3941,3 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_CC+set}" = set; then : ++if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3818,3 +3953,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" +@@ -3850,3 +3985,3 @@ set dummy $ac_prog; ac_word=$2 + $as_echo_n "checking for $ac_word... " >&6; } +-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : ++if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3862,3 +3997,3 @@ do + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" +@@ -3904,4 +4039,4 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd' + $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +-as_fn_error "no acceptable C compiler found in \$PATH +-See \`config.log' for more details." "$LINENO" 5; } ++as_fn_error $? "no acceptable C compiler found in \$PATH ++See \`config.log' for more details" "$LINENO" 5; } + +@@ -3926,4 +4061,4 @@ $as_echo "$ac_try_echo"; } >&5 + cat conftest.er1 >&5 +- rm -f conftest.er1 conftest.err + fi ++ rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 +@@ -3934,3 +4069,3 @@ done + $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +-if test "${ac_cv_c_compiler_gnu+set}" = set; then : ++if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -3971,3 +4106,3 @@ ac_save_CFLAGS=$CFLAGS + $as_echo_n "checking whether $CC accepts -g... " >&6; } +-if test "${ac_cv_prog_cc_g+set}" = set; then : ++if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4049,3 +4184,3 @@ fi + $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +-if test "${ac_cv_prog_cc_c89+set}" = set; then : ++if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4058,4 +4193,3 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext + #include +-#include +-#include ++struct stat; + /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +@@ -4147,3 +4281,3 @@ if test $ac_cv_c_compiler_gnu = yes; then + $as_echo_n "checking whether $CC needs -traditional... " >&6; } +-if test "${ac_cv_prog_gcc_traditional+set}" = set; then : ++if ${ac_cv_prog_gcc_traditional+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4188,12 +4322,18 @@ ac_aux_dir= + for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do +- for ac_t in install-sh install.sh shtool; do +- if test -f "$ac_dir/$ac_t"; then +- ac_aux_dir=$ac_dir +- ac_install_sh="$ac_aux_dir/$ac_t -c" +- break 2 +- fi +- done ++ if test -f "$ac_dir/install-sh"; then ++ ac_aux_dir=$ac_dir ++ ac_install_sh="$ac_aux_dir/install-sh -c" ++ break ++ elif test -f "$ac_dir/install.sh"; then ++ ac_aux_dir=$ac_dir ++ ac_install_sh="$ac_aux_dir/install.sh -c" ++ break ++ elif test -f "$ac_dir/shtool"; then ++ ac_aux_dir=$ac_dir ++ ac_install_sh="$ac_aux_dir/shtool install -c" ++ break ++ fi + done + if test -z "$ac_aux_dir"; then +- as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 ++ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 + fi +@@ -4226,3 +4366,3 @@ $as_echo_n "checking for a BSD-compatible install... " >&6; } + if test -z "$INSTALL"; then +-if test "${ac_cv_path_install+set}" = set; then : ++if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4246,3 +4386,3 @@ case $as_dir/ in #(( + for ac_exec_ext in '' $ac_executable_extensions; do +- if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then ++ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && +@@ -4316,3 +4456,3 @@ echo "Using: BMAKE_PATH_MAX=$bmake_path_max" >&6 + $as_echo_n "checking for ANSI C header files... " >&6; } +-if test "${ac_cv_header_stdc+set}" = set; then : ++if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4428,3 +4568,3 @@ fi + $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +-if test "${ac_cv_header_sys_wait_h+set}" = set; then : ++if ${ac_cv_header_sys_wait_h+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4472,3 +4612,3 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } +-if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then : ++if eval \${$as_ac_Header+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4499,4 +4639,3 @@ eval ac_res=\$$as_ac_Header + $as_echo "$ac_res" >&6; } +-eval as_val=\$$as_ac_Header +- if test "x$as_val" = x""yes; then : ++if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +@@ -4513,3 +4652,3 @@ if test $ac_header_dirent = dirent.h; then + $as_echo_n "checking for library containing opendir... " >&6; } +-if test "${ac_cv_search_opendir+set}" = set; then : ++if ${ac_cv_search_opendir+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4547,3 +4686,3 @@ rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext +- if test "${ac_cv_search_opendir+set}" = set; then : ++ if ${ac_cv_search_opendir+:} false; then : + break +@@ -4551,3 +4690,3 @@ fi + done +-if test "${ac_cv_search_opendir+set}" = set; then : ++if ${ac_cv_search_opendir+:} false; then : + +@@ -4570,3 +4709,3 @@ else + $as_echo_n "checking for library containing opendir... " >&6; } +-if test "${ac_cv_search_opendir+set}" = set; then : ++if ${ac_cv_search_opendir+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4604,3 +4743,3 @@ rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext +- if test "${ac_cv_search_opendir+set}" = set; then : ++ if ${ac_cv_search_opendir+:} false; then : + break +@@ -4608,3 +4747,3 @@ fi + done +-if test "${ac_cv_search_opendir+set}" = set; then : ++if ${ac_cv_search_opendir+:} false; then : + +@@ -4629,3 +4768,3 @@ do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" +-if test "x$ac_cv_header_sys_param_h" = x""yes; then : ++if test "x$ac_cv_header_sys_param_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +@@ -4645,3 +4784,3 @@ do : + " +-if test "x$ac_cv_header_sys_sysctl_h" = x""yes; then : ++if test "x$ac_cv_header_sys_sysctl_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +@@ -4666,2 +4805,3 @@ for ac_header in \ + sys/mman.h \ ++ sys/resource.h \ + sys/select.h \ +@@ -4670,2 +4810,4 @@ for ac_header in \ + sys/uio.h \ ++ sys/utsname.h \ ++ sys/wait.h \ + unistd.h \ +@@ -4676,4 +4818,3 @@ do : + ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +-eval as_val=\$$as_ac_Header +- if test "x$as_val" = x""yes; then : ++if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +@@ -4688,3 +4829,3 @@ done + ac_fn_c_check_header_mongrel "$LINENO" "sys/cdefs.h" "ac_cv_header_sys_cdefs_h" "$ac_includes_default" +-if test "x$ac_cv_header_sys_cdefs_h" = x""yes; then : ++if test "x$ac_cv_header_sys_cdefs_h" = xyes; then : + echo $ECHO_N "checking whether sys/cdefs.h is compatible... $ECHO_C" >&6 +@@ -4715,3 +4856,3 @@ fi + $as_echo_n "checking for __attribute__... " >&6; } +-if test "${ac_cv___attribute__+set}" = set; then : ++if ${ac_cv___attribute__+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4758,3 +4899,3 @@ $as_echo "$ac_cv___attribute__" >&6; } + $as_echo_n "checking whether byte ordering is bigendian... " >&6; } +-if test "${ac_cv_c_bigendian+set}" = set; then : ++if ${ac_cv_c_bigendian+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4976,3 +5117,3 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + *) +- as_fn_error "unknown endianness ++ as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; +@@ -4982,3 +5123,3 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + $as_echo_n "checking for an ANSI C-conforming const... " >&6; } +-if test "${ac_cv_c_const+set}" = set; then : ++if ${ac_cv_c_const+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -4991,7 +5132,7 @@ main () + { +-/* FIXME: Include the comments suggested by Paul. */ ++ + #ifndef __cplusplus +- /* Ultrix mips cc rejects this. */ ++ /* Ultrix mips cc rejects this sort of thing. */ + typedef int charset[2]; +- const charset cs; ++ const charset cs = { 0, 0 }; + /* SunOS 4.1.1 cc rejects this. */ +@@ -5012,4 +5153,5 @@ main () + pcpcc = (char const *const *) ppc; +- { /* SCO 3.2v4 cc rejects this. */ +- char *t; ++ { /* SCO 3.2v4 cc rejects this sort of thing. */ ++ char tx; ++ char *t = &tx; + char const *s = 0 ? (char *) 0 : (char const *) 0; +@@ -5029,6 +5171,6 @@ main () + } +- { /* AIX XL C 1.02.0.0 rejects this saying ++ { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ +- struct s { int j; const int *ap[3]; }; +- struct s *b; b->j = 5; ++ struct s { int j; const int *ap[3]; } bx; ++ struct s *b = &bx; b->j = 5; + } +@@ -5060,4 +5202,15 @@ fi + ++ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" ++case $ac_cv_c_int32_t in #( ++ no|yes) ;; #( ++ *) ++ ++cat >>confdefs.h <<_ACEOF ++#define int32_t $ac_cv_c_int32_t ++_ACEOF ++;; ++esac ++ + ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" +-if test "x$ac_cv_type_mode_t" = x""yes; then : ++if test "x$ac_cv_type_mode_t" = xyes; then : + +@@ -5072,3 +5225,3 @@ fi + ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" +-if test "x$ac_cv_type_off_t" = x""yes; then : ++if test "x$ac_cv_type_off_t" = xyes; then : + +@@ -5083,3 +5236,3 @@ fi + ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" +-if test "x$ac_cv_type_pid_t" = x""yes; then : ++if test "x$ac_cv_type_pid_t" = xyes; then : + +@@ -5094,3 +5247,3 @@ fi + ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +-if test "x$ac_cv_type_size_t" = x""yes; then : ++if test "x$ac_cv_type_size_t" = xyes; then : + +@@ -5125,3 +5278,3 @@ ac_fn_c_check_decl "$LINENO" "sys_siglist" "ac_cv_have_decl_sys_siglist" "#inclu + " +-if test "x$ac_cv_have_decl_sys_siglist" = x""yes; then : ++if test "x$ac_cv_have_decl_sys_siglist" = xyes; then : + ac_have_decl=1 +@@ -5138,3 +5291,3 @@ _ACEOF + $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } +-if test "${ac_cv_header_time+set}" = set; then : ++if ${ac_cv_header_time+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5173,3 +5326,3 @@ fi + $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } +-if test "${ac_cv_struct_tm+set}" = set; then : ++if ${ac_cv_struct_tm+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5209,3 +5362,3 @@ fi + $as_echo_n "checking return type of signal handlers... " >&6; } +-if test "${ac_cv_type_signal+set}" = set; then : ++if ${ac_cv_type_signal+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5243,3 +5396,3 @@ do : + ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" +-if test "x$ac_cv_header_vfork_h" = x""yes; then : ++if test "x$ac_cv_header_vfork_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +@@ -5256,4 +5409,3 @@ do : + ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +-eval as_val=\$$as_ac_var +- if test "x$as_val" = x""yes; then : ++if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +@@ -5268,3 +5420,3 @@ if test "x$ac_cv_func_fork" = xyes; then + $as_echo_n "checking for working fork... " >&6; } +-if test "${ac_cv_func_fork_works+set}" = set; then : ++if ${ac_cv_func_fork_works+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5321,3 +5473,3 @@ if test "x$ac_cv_func_vfork" = xyes; then + $as_echo_n "checking for working vfork... " >&6; } +-if test "${ac_cv_func_vfork_works+set}" = set; then : ++if ${ac_cv_func_vfork_works+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5457,3 +5609,3 @@ do : + ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" +-if test "x$ac_cv_func_vprintf" = x""yes; then : ++if test "x$ac_cv_func_vprintf" = xyes; then : + cat >>confdefs.h <<_ACEOF +@@ -5463,3 +5615,3 @@ _ACEOF + ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" +-if test "x$ac_cv_func__doprnt" = x""yes; then : ++if test "x$ac_cv_func__doprnt" = xyes; then : + +@@ -5475,3 +5627,3 @@ done + $as_echo_n "checking for wait3 that fills in rusage... " >&6; } +-if test "${ac_cv_func_wait3_rusage+set}" = set; then : ++if ${ac_cv_func_wait3_rusage+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5538,18 +5690,109 @@ fi + for ac_func in \ ++ _Exit \ ++ alloca \ ++ atoll \ ++ canonicalize_file_name \ ++ chown \ ++ dup2 \ ++ dup3 \ ++ endusershell \ + err \ + errx \ ++ euidaccess \ ++ faccessat \ ++ fchdir \ ++ fchmodat \ ++ fchownat \ ++ fcntl \ ++ fdatasync \ ++ fstatat \ ++ fsync \ ++ ftruncate \ ++ futimens \ + getcwd \ ++ getdomainname \ ++ getdtablesize \ + getenv \ ++ getgroups \ ++ gethostname \ ++ getloadavg \ ++ getlogin \ ++ getlogin_r \ + getopt \ ++ getpass \ ++ getppid \ ++ getrusage \ ++ getsubopt \ ++ getusershell \ + getwd \ ++ grantpt \ ++ group_member \ ++ initstate \ ++ initstate_r \ ++ kill \ + killpg \ ++ lchmod \ ++ lchown \ ++ link \ ++ linkat \ ++ lstat \ ++ mkdirat \ ++ mkdtemp \ ++ mkfifo \ ++ mkfifoat \ ++ mknod \ ++ mknodat \ ++ mkostemp \ ++ mkostemps \ ++ mkstemp \ ++ mkstemps \ + mmap \ ++ openat \ ++ pipe \ ++ pipe2 \ ++ poll \ ++ posix_openpt \ ++ pread \ ++ pthread_sigmask \ ++ ptsname \ ++ ptsname_r \ + putenv \ ++ pwrite \ ++ qsort_r \ ++ raise \ ++ random \ ++ random_r \ ++ readlink \ ++ readlinkat \ ++ reallocarray \ ++ realpath \ ++ regcomp \ ++ regerror \ ++ regexec \ ++ regfree \ ++ rpmatch \ ++ secure_getenv \ + select \ + setenv \ ++ sethostname \ + setpgid \ ++ setpgrp \ + setsid \ ++ setstate \ ++ setstate_r \ ++ setusershell \ + sigaction \ ++ sigaddset \ ++ sigdelset \ ++ sigemptyset \ ++ sigfillset \ ++ sigismember \ ++ signal \ ++ sigpending \ ++ sigprocmask \ + sigvec \ ++ sleep \ + snprintf \ ++ srandom \ ++ srandom_r \ + strerror \ +@@ -5559,5 +5802,17 @@ for ac_func in \ + strtol \ ++ strtoll \ ++ strtoull \ ++ symlink \ ++ symlinkat \ + sysctl \ ++ truncate \ ++ ttyname_r \ ++ uname \ ++ unlinkat \ ++ unlockpt \ + unsetenv \ ++ usleep \ ++ utimensat \ + vsnprintf \ ++ wait \ + wait3 \ +@@ -5571,4 +5826,3 @@ do : + ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +-eval as_val=\$$as_ac_var +- if test "x$as_val" = x""yes; then : ++if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +@@ -5581,16 +5835,18 @@ done + +-for ac_func in \ +- realpath \ +- dirname \ +- stresep \ +- strlcpy \ ++ac_fn_c_check_func "$LINENO" "realpath" "ac_cv_func_realpath" ++if test "x$ac_cv_func_realpath" = xyes; then : ++ $as_echo "#define HAVE_REALPATH 1" >>confdefs.h + +-do : +- as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +-ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +-eval as_val=\$$as_ac_var +- if test "x$as_val" = x""yes; then : +- cat >>confdefs.h <<_ACEOF +-#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +-_ACEOF ++else ++ case " $LIBOBJS " in ++ *" realpath.$ac_objext "* ) ;; ++ *) LIBOBJS="$LIBOBJS realpath.$ac_objext" ++ ;; ++esac ++ ++fi ++ ++ac_fn_c_check_func "$LINENO" "dirname" "ac_cv_func_dirname" ++if test "x$ac_cv_func_dirname" = xyes; then : ++ $as_echo "#define HAVE_DIRNAME 1" >>confdefs.h + +@@ -5598,4 +5854,30 @@ else + case " $LIBOBJS " in +- *" $ac_func.$ac_objext "* ) ;; +- *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ++ *" dirname.$ac_objext "* ) ;; ++ *) LIBOBJS="$LIBOBJS dirname.$ac_objext" ++ ;; ++esac ++ ++fi ++ ++ac_fn_c_check_func "$LINENO" "stresep" "ac_cv_func_stresep" ++if test "x$ac_cv_func_stresep" = xyes; then : ++ $as_echo "#define HAVE_STRESEP 1" >>confdefs.h ++ ++else ++ case " $LIBOBJS " in ++ *" stresep.$ac_objext "* ) ;; ++ *) LIBOBJS="$LIBOBJS stresep.$ac_objext" ++ ;; ++esac ++ ++fi ++ ++ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" ++if test "x$ac_cv_func_strlcpy" = xyes; then : ++ $as_echo "#define HAVE_STRLCPY 1" >>confdefs.h ++ ++else ++ case " $LIBOBJS " in ++ *" strlcpy.$ac_objext "* ) ;; ++ *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" + ;; +@@ -5604,3 +5886,2 @@ esac + fi +-done + +@@ -5610,3 +5891,3 @@ done + $as_echo_n "checking for emalloc in -lutil... " >&6; } +-if test "${ac_cv_lib_util_emalloc+set}" = set; then : ++if ${ac_cv_lib_util_emalloc+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5644,6 +5925,6 @@ fi + $as_echo "$ac_cv_lib_util_emalloc" >&6; } +-if test "x$ac_cv_lib_util_emalloc" = x""yes; then : ++if test "x$ac_cv_lib_util_emalloc" = xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erealloc in -lutil" >&5 + $as_echo_n "checking for erealloc in -lutil... " >&6; } +-if test "${ac_cv_lib_util_erealloc+set}" = set; then : ++if ${ac_cv_lib_util_erealloc+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5681,6 +5962,6 @@ fi + $as_echo "$ac_cv_lib_util_erealloc" >&6; } +-if test "x$ac_cv_lib_util_erealloc" = x""yes; then : ++if test "x$ac_cv_lib_util_erealloc" = xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for estrdup in -lutil" >&5 + $as_echo_n "checking for estrdup in -lutil... " >&6; } +-if test "${ac_cv_lib_util_estrdup+set}" = set; then : ++if ${ac_cv_lib_util_estrdup+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5718,6 +5999,6 @@ fi + $as_echo "$ac_cv_lib_util_estrdup" >&6; } +-if test "x$ac_cv_lib_util_estrdup" = x""yes; then : ++if test "x$ac_cv_lib_util_estrdup" = xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for estrndup in -lutil" >&5 + $as_echo_n "checking for estrndup in -lutil... " >&6; } +-if test "${ac_cv_lib_util_estrndup+set}" = set; then : ++if ${ac_cv_lib_util_estrndup+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5755,3 +6036,3 @@ fi + $as_echo "$ac_cv_lib_util_estrndup" >&6; } +-if test "x$ac_cv_lib_util_estrndup" = x""yes; then : ++if test "x$ac_cv_lib_util_estrndup" = xyes; then : + LIBS="$LIBS -lutil" +@@ -5769,3 +6050,3 @@ fi + $as_echo_n "checking whether stat file-mode macros are broken... " >&6; } +-if test "${ac_cv_header_stat_broken+set}" = set; then : ++if ${ac_cv_header_stat_broken+:} false; then : + $as_echo_n "(cached) " >&6 +@@ -5810,3 +6091,3 @@ fi + ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" +-if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : ++if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : + +@@ -5881,3 +6162,3 @@ if test "${with_machine+set}" = set; then : + withval=$with_machine; case "${withval}" in +-yes) as_fn_error "bad value ${withval} given for bmake MACHINE" "$LINENO" 5 ;; ++yes) as_fn_error $? "bad value ${withval} given for bmake MACHINE" "$LINENO" 5 ;; + no) ;; +@@ -5914,3 +6195,3 @@ if test "${with_machine_arch+set}" = set; then : + withval=$with_machine_arch; case "${withval}" in +-yes) as_fn_error "bad value ${withval} given for bmake MACHINE_ARCH" "$LINENO" 5 ;; ++yes) as_fn_error $? "bad value ${withval} given for bmake MACHINE_ARCH" "$LINENO" 5 ;; + no) ;; +@@ -5926,3 +6207,3 @@ if test "${with_default_sys_path+set}" = set; then : + withval=$with_default_sys_path; case "${withval}" in +-yes) as_fn_error "bad value ${withval} given for bmake _PATH_DEFSYSPATH" "$LINENO" 5 ;; ++yes) as_fn_error $? "bad value ${withval} given for bmake _PATH_DEFSYSPATH" "$LINENO" 5 ;; + no) ;; +@@ -5937,3 +6218,3 @@ if test "${with_path_objdirprefix+set}" = set; then : + withval=$with_path_objdirprefix; case "${withval}" in +-yes) as_fn_error "bad value ${withval} given for bmake _PATH_OBJDIRPREFIX" "$LINENO" 5 ;; ++yes) as_fn_error $? "bad value ${withval} given for bmake _PATH_OBJDIRPREFIX" "$LINENO" 5 ;; + no) CPPFLAGS="$CPPFLAGS -DNO_PATH_OBJDIRPREFIX" ;; +@@ -5948,3 +6229,3 @@ yes) ;; + no) CPPFLAGS="$CPPFLAGS -DNO_PWD_OVERRIDE" ;; +-*) as_fn_error "bad value ${enableval} given for pwd-override option" "$LINENO" 5 ;; ++*) as_fn_error $? "bad value ${enableval} given for pwd-override option" "$LINENO" 5 ;; + esac +@@ -5957,3 +6238,3 @@ yes) ;; + no) CPPFLAGS="$CPPFLAGS -DNO_CHECK_MAKE_CHDIR" ;; +-*) as_fn_error "bad value ${enableval} given for check-make-chdir option" "$LINENO" 5 ;; ++*) as_fn_error $? "bad value ${enableval} given for check-make-chdir option" "$LINENO" 5 ;; + esac +@@ -5967,3 +6248,3 @@ if test "${with_mksrc+set}" = set; then : + *) test -s $withval/install-mk && mksrc=$withval || +-as_fn_error "bad value ${withval} given for mksrc cannot find install-mk" "$LINENO" 5 ++as_fn_error $? "bad value ${withval} given for mksrc cannot find install-mk" "$LINENO" 5 + ;; +@@ -6011,3 +6292,3 @@ fi + +-ac_config_files="$ac_config_files makefile Makefile.config make-bootstrap.sh unit-tests/Makefile" ++ac_config_files="$ac_config_files Makefile.config make-bootstrap.sh unit-tests/Makefile" + +@@ -6077,6 +6358,17 @@ if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then +- test "x$cache_file" != "x/dev/null" && ++ if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 + $as_echo "$as_me: updating cache $cache_file" >&6;} +- cat confcache >$cache_file ++ if test ! -f "$cache_file" || test -h "$cache_file"; then ++ cat confcache >"$cache_file" ++ else ++ case $cache_file in #( ++ */* | ?:*) ++ mv -f confcache "$cache_file"$$ && ++ mv -f "$cache_file"$$ "$cache_file" ;; #( ++ *) ++ mv -f confcache "$cache_file" ;; ++ esac ++ fi ++ fi + else +@@ -6096,2 +6388,3 @@ ac_libobjs= + ac_ltlibobjs= ++U= + for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue +@@ -6112,3 +6405,3 @@ LTLIBOBJS=$ac_ltlibobjs + +-: ${CONFIG_STATUS=./config.status} ++: "${CONFIG_STATUS=./config.status}" + ac_write_fail=0 +@@ -6213,2 +6506,3 @@ IFS=" "" $as_nl" + # Find who we are. Look in the path if we contain no directory separator. ++as_myself= + case $0 in #(( +@@ -6258,15 +6552,15 @@ export LANGUAGE + +-# as_fn_error ERROR [LINENO LOG_FD] +-# --------------------------------- ++# as_fn_error STATUS ERROR [LINENO LOG_FD] ++# ---------------------------------------- + # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are + # provided, also output the error to LOG_FD, referencing LINENO. Then exit the +-# script with status $?, using 1 if that was 0. ++# script with STATUS, using 1 if that was 0. + as_fn_error () + { +- as_status=$?; test $as_status -eq 0 && as_status=1 +- if test "$3"; then +- as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack +- $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 ++ as_status=$1; test $as_status -eq 0 && as_status=1 ++ if test "$4"; then ++ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi +- $as_echo "$as_me: error: $1" >&2 ++ $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +@@ -6408,5 +6702,5 @@ if (echo >conf$$.file) 2>/dev/null; then + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. +- # In both cases, we have to default to `cp -p'. ++ # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || +- as_ln_s='cp -p' ++ as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then +@@ -6414,6 +6708,6 @@ if (echo >conf$$.file) 2>/dev/null; then + else +- as_ln_s='cp -p' ++ as_ln_s='cp -pR' + fi + else +- as_ln_s='cp -p' ++ as_ln_s='cp -pR' + fi +@@ -6466,3 +6760,3 @@ $as_echo X"$as_dir" | + test -z "$as_dirs" || eval "mkdir $as_dirs" +- } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" ++ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + +@@ -6477,24 +6771,12 @@ fi + +-if test -x / >/dev/null 2>&1; then +- as_test_x='test -x' +-else +- if ls -dL / >/dev/null 2>&1; then +- as_ls_L_option=L +- else +- as_ls_L_option= +- fi +- as_test_x=' +- eval sh -c '\'' +- if test -d "$1"; then +- test -d "$1/."; +- else +- case $1 in #( +- -*)set "./$1";; +- esac; +- case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( +- ???[sx]*):;;*)false;;esac;fi +- '\'' sh +- ' +-fi +-as_executable_p=$as_test_x ++ ++# as_fn_executable_p FILE ++# ----------------------- ++# Test if FILE is an executable regular file. ++as_fn_executable_p () ++{ ++ test -f "$1" && test -x "$1" ++} # as_fn_executable_p ++as_test_x='test -x' ++as_executable_p=as_fn_executable_p + +@@ -6520,3 +6802,3 @@ ac_log=" + This file was extended by bmake $as_me 20171126, which was +-generated by GNU Autoconf 2.64. Invocation command line was ++generated by GNU Autoconf 2.69. Invocation command line was + +@@ -6559,2 +6841,3 @@ Usage: $0 [OPTION]... [TAG]... + -V, --version print version number and configuration settings, then exit ++ --config print configuration, then exit + -q, --quiet, --silent +@@ -6578,8 +6861,9 @@ _ACEOF + cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ++ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" + ac_cs_version="\\ + bmake config.status 20171126 +-configured by $0, generated by GNU Autoconf 2.64, +- with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" ++configured by $0, generated by GNU Autoconf 2.69, ++ with options \\"\$ac_cs_config\\" + +-Copyright (C) 2009 Free Software Foundation, Inc. ++Copyright (C) 2012 Free Software Foundation, Inc. + This config.status script is free software; the Free Software Foundation +@@ -6599,3 +6883,3 @@ do + case $1 in +- --*=*) ++ --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` +@@ -6604,2 +6888,7 @@ do + ;; ++ --*=) ++ ac_option=`expr "X$1" : 'X\([^=]*\)='` ++ ac_optarg= ++ ac_shift=: ++ ;; + *) +@@ -6617,2 +6906,4 @@ do + $as_echo "$ac_cs_version"; exit ;; ++ --config | --confi | --conf | --con | --co | --c ) ++ $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) +@@ -6623,2 +6914,3 @@ do + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; ++ '') as_fn_error $? "missing file argument" ;; + esac +@@ -6635,3 +6927,3 @@ do + # Conflict between --help and --header +- as_fn_error "ambiguous option: \`$1' ++ as_fn_error $? "ambiguous option: \`$1' + Try \`$0 --help' for more information.";; +@@ -6644,3 +6936,3 @@ Try \`$0 --help' for more information.";; + # This is an error. +- -*) as_fn_error "unrecognized option: \`$1' ++ -*) as_fn_error $? "unrecognized option: \`$1' + Try \`$0 --help' for more information." ;; +@@ -6664,3 +6956,3 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + if \$ac_cs_recheck; then +- set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion ++ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift +@@ -6694,3 +6986,2 @@ do + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; +- "makefile") CONFIG_FILES="$CONFIG_FILES makefile" ;; + "Makefile.config") CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; +@@ -6699,3 +6990,3 @@ do + +- *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; ++ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +@@ -6721,5 +7012,6 @@ $debug || + { +- tmp= ++ tmp= ac_tmp= + trap 'exit_status=$? +- { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ++ : "${ac_tmp:=$tmp}" ++ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status + ' 0 +@@ -6731,3 +7023,3 @@ $debug || + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && +- test -n "$tmp" && test -d "$tmp" ++ test -d "$tmp" + } || +@@ -6736,3 +7028,4 @@ $debug || + (umask 077 && mkdir "$tmp") +-} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 ++} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ++ac_tmp=$tmp + +@@ -6753,3 +7046,3 @@ ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` + if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then +- ac_cs_awk_cr='\r' ++ ac_cs_awk_cr='\\r' + else +@@ -6758,3 +7051,3 @@ fi + +-echo 'BEGIN {' >"$tmp/subs1.awk" && ++echo 'BEGIN {' >"$ac_tmp/subs1.awk" && + _ACEOF +@@ -6767,4 +7060,4 @@ _ACEOF + } >conf$$subs.sh || +- as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +-ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ++ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` + ac_delim='%!_!# ' +@@ -6772,3 +7065,3 @@ for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || +- as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 ++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + +@@ -6778,3 +7071,3 @@ for ac_last_try in false false false false false :; do + elif $ac_last_try; then +- as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 ++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else +@@ -6786,3 +7079,3 @@ rm -f conf$$subs.sh + cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +-cat >>"\$tmp/subs1.awk" <<\\_ACAWK && ++cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && + _ACEOF +@@ -6800,3 +7093,3 @@ t delim + h +-s/\(.\{148\}\).*/\1/ ++s/\(.\{148\}\)..*/\1/ + t more1 +@@ -6814,3 +7107,3 @@ t nl + h +-s/\(.\{148\}\).*/\1/ ++s/\(.\{148\}\)..*/\1/ + t more2 +@@ -6834,3 +7127,3 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + _ACAWK +-cat >>"\$tmp/subs1.awk" <<_ACAWK && ++cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 +@@ -6866,8 +7159,8 @@ else + cat +-fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ +- || as_fn_error "could not setup config files machinery" "$LINENO" 5 ++fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ ++ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 + _ACEOF + +-# VPATH may cause trouble with some makes, so we remove $(srcdir), +-# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and ++# VPATH may cause trouble with some makes, so we remove sole $(srcdir), ++# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and + # trailing colons and then remove the whole line if VPATH becomes empty +@@ -6875,8 +7168,16 @@ _ACEOF + if test "x$srcdir" = x.; then +- ac_vpsub='/^[ ]*VPATH[ ]*=/{ +-s/:*\$(srcdir):*/:/ +-s/:*\${srcdir}:*/:/ +-s/:*@srcdir@:*/:/ +-s/^\([^=]*=[ ]*\):*/\1/ ++ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ ++h ++s/// ++s/^/:/ ++s/[ ]*$/:/ ++s/:\$(srcdir):/:/g ++s/:\${srcdir}:/:/g ++s/:@srcdir@:/:/g ++s/^:*// + s/:*$// ++x ++s/\(=[ ]*\).*/\1/ ++G ++s/\n// + s/^[^=]*=[ ]*$// +@@ -6892,3 +7193,3 @@ fi # test -n "$CONFIG_FILES" + if test -n "$CONFIG_HEADERS"; then +-cat >"$tmp/defines.awk" <<\_ACAWK || ++cat >"$ac_tmp/defines.awk" <<\_ACAWK || + BEGIN { +@@ -6904,7 +7205,7 @@ ac_delim='%!_!# ' + for ac_last_try in false false :; do +- ac_t=`sed -n "/$ac_delim/p" confdefs.h` +- if test -z "$ac_t"; then ++ ac_tt=`sed -n "/$ac_delim/p" confdefs.h` ++ if test -z "$ac_tt"; then + break + elif $ac_last_try; then +- as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 ++ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else +@@ -6993,3 +7294,3 @@ _ACEOF + cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +- as_fn_error "could not setup config headers machinery" "$LINENO" 5 ++ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 + fi # test -n "$CONFIG_HEADERS" +@@ -7006,3 +7307,3 @@ do + :[FHL]*:*);; +- :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; ++ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; +@@ -7025,3 +7326,3 @@ do + case $ac_f in +- -) ac_f="$tmp/stdin";; ++ -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree +@@ -7034,3 +7335,3 @@ do + esac || +- as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; ++ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac +@@ -7060,4 +7361,4 @@ $as_echo "$as_me: creating $ac_file" >&6;} + case $ac_tag in +- *:-:* | *:-) cat >"$tmp/stdin" \ +- || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; ++ *:-:* | *:-) cat >"$ac_tmp/stdin" \ ++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac +@@ -7191,19 +7492,20 @@ $ac_datarootdir_hack + " +-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ +- || as_fn_error "could not create $ac_file" "$LINENO" 5 ++eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ ++ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + + test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && +- { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && +- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && ++ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && ++ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ ++ "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +-which seems to be undefined. Please make sure it is defined." >&5 ++which seems to be undefined. Please make sure it is defined" >&5 + $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +-which seems to be undefined. Please make sure it is defined." >&2;} ++which seems to be undefined. Please make sure it is defined" >&2;} + +- rm -f "$tmp/stdin" ++ rm -f "$ac_tmp/stdin" + case $ac_file in +- -) cat "$tmp/out" && rm -f "$tmp/out";; +- *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; ++ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; ++ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ +- || as_fn_error "could not create $ac_file" "$LINENO" 5 ++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; +@@ -7216,6 +7518,6 @@ which seems to be undefined. Please make sure it is defined." >&2;} + $as_echo "/* $configure_input */" \ +- && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" +- } >"$tmp/config.h" \ +- || as_fn_error "could not create $ac_file" "$LINENO" 5 +- if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then ++ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" ++ } >"$ac_tmp/config.h" \ ++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ++ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +@@ -7224,4 +7526,4 @@ $as_echo "$as_me: $ac_file is unchanged" >&6;} + rm -f "$ac_file" +- mv "$tmp/config.h" "$ac_file" \ +- || as_fn_error "could not create $ac_file" "$LINENO" 5 ++ mv "$ac_tmp/config.h" "$ac_file" \ ++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi +@@ -7229,4 +7531,4 @@ $as_echo "$as_me: $ac_file is unchanged" >&6;} + $as_echo "/* $configure_input */" \ +- && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ +- || as_fn_error "could not create -" "$LINENO" 5 ++ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ ++ || as_fn_error $? "could not create -" "$LINENO" 5 + fi +@@ -7245,3 +7547,3 @@ ac_clean_files=$ac_clean_files_save + test $ac_write_fail = 0 || +- as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 ++ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + +@@ -7266,3 +7568,3 @@ if test "$no_create" != yes; then + # would make configure fail if this is the last instruction. +- $ac_cs_success || as_fn_exit $? ++ $ac_cs_success || as_fn_exit 1 + fi +diff --git a/configure.in b/configure.in +index ccd4262..81231ca 100644 +--- a/configure.in ++++ b/configure.in +@@ -50,3 +50,3 @@ esac], + [ +-OS=`uname -s` ++OS=`uname -s | cut -d_ -f1` + for d in "/usr/include/dev/filemon" "$prefix/include/dev/filemon" "$srcdir/filemon" "$srcdir/../filemon" "$srcdir/../../sys/dev/filemon" +@@ -125,2 +125,3 @@ AC_CHECK_HEADERS( \ + sys/mman.h \ ++ sys/resource.h \ + sys/select.h \ +@@ -129,2 +130,4 @@ AC_CHECK_HEADERS( \ + sys/uio.h \ ++ sys/utsname.h \ ++ sys/wait.h \ + unistd.h \ +@@ -153,2 +156,3 @@ AC_C_BIGENDIAN + AC_C_CONST ++AC_TYPE_INT32_T + AC_TYPE_MODE_T +@@ -169,18 +173,109 @@ dnl Keep this list sorted + AC_CHECK_FUNCS( \ ++ _Exit \ ++ alloca \ ++ atoll \ ++ canonicalize_file_name \ ++ chown \ ++ dup2 \ ++ dup3 \ ++ endusershell \ + err \ + errx \ ++ euidaccess \ ++ faccessat \ ++ fchdir \ ++ fchmodat \ ++ fchownat \ ++ fcntl \ ++ fdatasync \ ++ fstatat \ ++ fsync \ ++ ftruncate \ ++ futimens \ + getcwd \ ++ getdomainname \ ++ getdtablesize \ + getenv \ ++ getgroups \ ++ gethostname \ ++ getloadavg \ ++ getlogin \ ++ getlogin_r \ + getopt \ ++ getpass \ ++ getppid \ ++ getrusage \ ++ getsubopt \ ++ getusershell \ + getwd \ ++ grantpt \ ++ group_member \ ++ initstate \ ++ initstate_r \ ++ kill \ + killpg \ ++ lchmod \ ++ lchown \ ++ link \ ++ linkat \ ++ lstat \ ++ mkdirat \ ++ mkdtemp \ ++ mkfifo \ ++ mkfifoat \ ++ mknod \ ++ mknodat \ ++ mkostemp \ ++ mkostemps \ ++ mkstemp \ ++ mkstemps \ + mmap \ ++ openat \ ++ pipe \ ++ pipe2 \ ++ poll \ ++ posix_openpt \ ++ pread \ ++ pthread_sigmask \ ++ ptsname \ ++ ptsname_r \ + putenv \ ++ pwrite \ ++ qsort_r \ ++ raise \ ++ random \ ++ random_r \ ++ readlink \ ++ readlinkat \ ++ reallocarray \ ++ realpath \ ++ regcomp \ ++ regerror \ ++ regexec \ ++ regfree \ ++ rpmatch \ ++ secure_getenv \ + select \ + setenv \ ++ sethostname \ + setpgid \ ++ setpgrp \ + setsid \ ++ setstate \ ++ setstate_r \ ++ setusershell \ + sigaction \ ++ sigaddset \ ++ sigdelset \ ++ sigemptyset \ ++ sigfillset \ ++ sigismember \ ++ signal \ ++ sigpending \ ++ sigprocmask \ + sigvec \ ++ sleep \ + snprintf \ ++ srandom \ ++ srandom_r \ + strerror \ +@@ -190,5 +285,17 @@ AC_CHECK_FUNCS( \ + strtol \ ++ strtoll \ ++ strtoull \ ++ symlink \ ++ symlinkat \ + sysctl \ ++ truncate \ ++ ttyname_r \ ++ uname \ ++ unlinkat \ ++ unlockpt \ + unsetenv \ ++ usleep \ ++ utimensat \ + vsnprintf \ ++ wait \ + wait3 \ +@@ -392,3 +499,3 @@ AC_SUBST(filemon_h) + AC_SUBST(_MAKE_VERSION) +-AC_OUTPUT(makefile Makefile.config make-bootstrap.sh unit-tests/Makefile) ++AC_OUTPUT(Makefile.config make-bootstrap.sh unit-tests/Makefile) + +diff --git a/dir.c b/dir.c +index 0062ac0..8ff040b 100644 +--- a/dir.c ++++ b/dir.c +@@ -139,2 +139,5 @@ __RCSID("$NetBSD: dir.c,v 1.73 2018/07/12 18:03:31 christos Exp $"); + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif + +diff --git a/headers-mingw/fcntl.h b/headers-mingw/fcntl.h +new file mode 100644 +index 0000000..b63a9d3 +--- /dev/null ++++ b/headers-mingw/fcntl.h +@@ -0,0 +1,244 @@ ++/* Like , but with non-working flags defined to 0. ++ ++ Copyright (C) 2006-2018 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 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, see . */ ++ ++/* written by Paul Eggert */ ++ ++/* Normal invocation convention. */ ++ ++#ifndef _GL_FCNTL_H ++#define _GL_FCNTL_H ++ ++#ifndef __GLIBC__ /* Avoid namespace pollution on glibc systems. */ ++# include ++#endif ++ ++/* Native Windows platforms declare open(), creat() in . */ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++# include ++#endif ++ ++ ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_ARG_NONNULL is copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++ ++/* Declare overridden functions. */ ++ ++ ++ ++#if !HAVE_FCNTL ++extern int fcntl (int fd, int action, ...); ++#endif ++ ++#if !HAVE_OPENAT ++extern int openat (int fd, char const *file, int flags, /* mode_t mode */ ...); ++# endif ++ ++ ++ ++/* Fix up the FD_* macros, only known to be missing on mingw. */ ++ ++#ifndef FD_CLOEXEC ++# define FD_CLOEXEC 1 ++#endif ++ ++/* Fix up the supported F_* macros. Intentionally leave other F_* ++ macros undefined. Only known to be missing on mingw. */ ++ ++#ifndef F_DUPFD_CLOEXEC ++# define F_DUPFD_CLOEXEC 0x40000000 ++/* Witness variable: 1 if gnulib defined F_DUPFD_CLOEXEC, 0 otherwise. */ ++# define GNULIB_defined_F_DUPFD_CLOEXEC 1 ++#else ++# define GNULIB_defined_F_DUPFD_CLOEXEC 0 ++#endif ++ ++#ifndef F_DUPFD ++# define F_DUPFD 1 ++#endif ++ ++#ifndef F_GETFD ++# define F_GETFD 2 ++#endif ++ ++/* Fix up the O_* macros. */ ++ ++#if !defined O_DIRECT && defined O_DIRECTIO ++/* Tru64 spells it 'O_DIRECTIO'. */ ++# define O_DIRECT O_DIRECTIO ++#endif ++ ++#if !defined O_CLOEXEC && defined O_NOINHERIT ++/* Mingw spells it 'O_NOINHERIT'. */ ++# define O_CLOEXEC O_NOINHERIT ++#endif ++ ++#ifndef O_CLOEXEC ++# define O_CLOEXEC 0x40000000 /* Try to not collide with system O_* flags. */ ++# define GNULIB_defined_O_CLOEXEC 1 ++#else ++# define GNULIB_defined_O_CLOEXEC 0 ++#endif ++ ++#ifndef O_DIRECT ++# define O_DIRECT 0 ++#endif ++ ++#ifndef O_DIRECTORY ++# define O_DIRECTORY 0 ++#endif ++ ++#ifndef O_DSYNC ++# define O_DSYNC 0 ++#endif ++ ++#ifndef O_EXEC ++# define O_EXEC O_RDONLY /* This is often close enough in older systems. */ ++#endif ++ ++#ifndef O_IGNORE_CTTY ++# define O_IGNORE_CTTY 0 ++#endif ++ ++#ifndef O_NDELAY ++# define O_NDELAY 0 ++#endif ++ ++#ifndef O_NOATIME ++# define O_NOATIME 0 ++#endif ++ ++#ifndef O_NONBLOCK ++# define O_NONBLOCK O_NDELAY ++#endif ++ ++///* If the gnulib module 'nonblocking' is in use, guarantee a working non-zero ++// value of O_NONBLOCK. Otherwise, O_NONBLOCK is defined (above) to O_NDELAY ++// or to 0 as fallback. */ ++//#if @GNULIB_NONBLOCKING@ ++//# if O_NONBLOCK ++//# define GNULIB_defined_O_NONBLOCK 0 ++//# else ++//# define GNULIB_defined_O_NONBLOCK 1 ++//# undef O_NONBLOCK ++//# define O_NONBLOCK 0x40000000 ++//# endif ++//#endif ++ ++#ifndef O_NOCTTY ++# define O_NOCTTY 0 ++#endif ++ ++#ifndef O_NOFOLLOW ++# define O_NOFOLLOW 0 ++#endif ++ ++#ifndef O_NOLINK ++# define O_NOLINK 0 ++#endif ++ ++#ifndef O_NOLINKS ++# define O_NOLINKS 0 ++#endif ++ ++#ifndef O_NOTRANS ++# define O_NOTRANS 0 ++#endif ++ ++#ifndef O_RSYNC ++# define O_RSYNC 0 ++#endif ++ ++#ifndef O_SEARCH ++# define O_SEARCH O_RDONLY /* This is often close enough in older systems. */ ++#endif ++ ++#ifndef O_SYNC ++# define O_SYNC 0 ++#endif ++ ++#ifndef O_TTY_INIT ++# define O_TTY_INIT 0 ++#endif ++ ++#if ~O_ACCMODE & (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) ++# undef O_ACCMODE ++# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) ++#endif ++ ++/* For systems that distinguish between text and binary I/O. ++ O_BINARY is usually declared in fcntl.h */ ++#if !defined O_BINARY && defined _O_BINARY ++ /* For MSC-compatible compilers. */ ++# define O_BINARY _O_BINARY ++# define O_TEXT _O_TEXT ++#endif ++ ++#if defined __BEOS__ || defined __HAIKU__ ++ /* BeOS 5 and Haiku have O_BINARY and O_TEXT, but they have no effect. */ ++# undef O_BINARY ++# undef O_TEXT ++#endif ++ ++#ifndef O_BINARY ++# define O_BINARY 0 ++# define O_TEXT 0 ++#endif ++ ++/* Fix up the AT_* macros. */ ++ ++/* Work around a bug in Solaris 9 and 10: AT_FDCWD is positive. Its ++ value exceeds INT_MAX, so its use as an int doesn't conform to the ++ C standard, and GCC and Sun C complain in some cases. If the bug ++ is present, undef AT_FDCWD here, so it can be redefined below. */ ++#if 0 < AT_FDCWD && AT_FDCWD == 0xffd19553 ++# undef AT_FDCWD ++#endif ++ ++/* Use the same bit pattern as Solaris 9, but with the proper ++ signedness. The bit pattern is important, in case this actually is ++ Solaris with the above workaround. */ ++#ifndef AT_FDCWD ++# define AT_FDCWD (-3041965) ++#endif ++ ++/* Use the same values as Solaris 9. This shouldn't matter, but ++ there's no real reason to differ. */ ++#ifndef AT_SYMLINK_NOFOLLOW ++# define AT_SYMLINK_NOFOLLOW 4096 ++#endif ++ ++#ifndef AT_REMOVEDIR ++# define AT_REMOVEDIR 1 ++#endif ++ ++/* Solaris 9 lacks these two, so just pick unique values. */ ++#ifndef AT_SYMLINK_FOLLOW ++# define AT_SYMLINK_FOLLOW 2 ++#endif ++ ++#ifndef AT_EACCESS ++# define AT_EACCESS 4 ++#endif ++ ++ ++#endif /* _@GUARD_PREFIX@_FCNTL_H */ ++ ++ +diff --git a/headers-mingw/intprops.h b/headers-mingw/intprops.h +new file mode 100644 +index 0000000..9702aec +--- /dev/null ++++ b/headers-mingw/intprops.h +@@ -0,0 +1,455 @@ ++/* intprops.h -- properties of integer types ++ ++ Copyright (C) 2001-2018 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify it ++ under the terms of the GNU Lesser General Public License as published ++ by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with this program. If not, see . */ ++ ++/* Written by Paul Eggert. */ ++ ++#ifndef _GL_INTPROPS_H ++#define _GL_INTPROPS_H ++ ++#include ++ ++/* Return a value with the common real type of E and V and the value of V. ++ Do not evaluate E. */ ++#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v)) ++ ++/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see ++ . */ ++#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v)) ++ ++/* The extra casts in the following macros work around compiler bugs, ++ e.g., in Cray C 5.0.3.0. */ ++ ++/* True if the arithmetic type T is an integer type. bool counts as ++ an integer. */ ++#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) ++ ++/* True if the real type T is signed. */ ++#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) ++ ++/* Return 1 if the real expression E, after promotion, has a ++ signed or floating type. Do not evaluate E. */ ++#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0) ++ ++ ++/* Minimum and maximum values for integer types and expressions. */ ++ ++/* The width in bits of the integer type or expression T. ++ Do not evaluate T. ++ Padding bits are not supported; this is checked at compile-time below. */ ++#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) ++ ++/* The maximum and minimum values for the integer type T. */ ++#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) ++#define TYPE_MAXIMUM(t) \ ++ ((t) (! TYPE_SIGNED (t) \ ++ ? (t) -1 \ ++ : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) ++ ++/* The maximum and minimum values for the type of the expression E, ++ after integer promotion. E is not evaluated. */ ++#define _GL_INT_MINIMUM(e) \ ++ (EXPR_SIGNED (e) \ ++ ? ~ _GL_SIGNED_INT_MAXIMUM (e) \ ++ : _GL_INT_CONVERT (e, 0)) ++#define _GL_INT_MAXIMUM(e) \ ++ (EXPR_SIGNED (e) \ ++ ? _GL_SIGNED_INT_MAXIMUM (e) \ ++ : _GL_INT_NEGATE_CONVERT (e, 1)) ++#define _GL_SIGNED_INT_MAXIMUM(e) \ ++ (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1) ++ ++/* Work around OpenVMS incompatibility with C99. */ ++#if !defined LLONG_MAX && defined __INT64_MAX ++# define LLONG_MAX __INT64_MAX ++# define LLONG_MIN __INT64_MIN ++#endif ++ ++/* This include file assumes that signed types are two's complement without ++ padding bits; the above macros have undefined behavior otherwise. ++ If this is a problem for you, please let us know how to fix it for your host. ++ This assumption is tested by the intprops-tests module. */ ++ ++/* Does the __typeof__ keyword work? This could be done by ++ 'configure', but for now it's easier to do it by hand. */ ++#if (2 <= __GNUC__ \ ++ || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ ++ || (0x5110 <= __SUNPRO_C && !__STDC__)) ++# define _GL_HAVE___TYPEOF__ 1 ++#else ++# define _GL_HAVE___TYPEOF__ 0 ++#endif ++ ++/* Return 1 if the integer type or expression T might be signed. Return 0 ++ if it is definitely unsigned. This macro does not evaluate its argument, ++ and expands to an integer constant expression. */ ++#if _GL_HAVE___TYPEOF__ ++# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t)) ++#else ++# define _GL_SIGNED_TYPE_OR_EXPR(t) 1 ++#endif ++ ++/* Bound on length of the string representing an unsigned integer ++ value representable in B bits. log10 (2.0) < 146/485. The ++ smallest value of B where this bound is not tight is 2621. */ ++#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485) ++ ++/* Bound on length of the string representing an integer type or expression T. ++ Subtract 1 for the sign bit if T is signed, and then add 1 more for ++ a minus sign if needed. ++ ++ Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 0 when its argument is ++ signed, this macro may overestimate the true bound by one byte when ++ applied to unsigned types of size 2, 4, 16, ... bytes. */ ++#define INT_STRLEN_BOUND(t) \ ++ (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \ ++ + _GL_SIGNED_TYPE_OR_EXPR (t)) ++ ++/* Bound on buffer size needed to represent an integer type or expression T, ++ including the terminating null. */ ++#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) ++ ++ ++/* Range overflow checks. ++ ++ The INT__RANGE_OVERFLOW macros return 1 if the corresponding C ++ operators might not yield numerically correct answers due to ++ arithmetic overflow. They do not rely on undefined or ++ implementation-defined behavior. Their implementations are simple ++ and straightforward, but they are a bit harder to use than the ++ INT__OVERFLOW macros described below. ++ ++ Example usage: ++ ++ long int i = ...; ++ long int j = ...; ++ if (INT_MULTIPLY_RANGE_OVERFLOW (i, j, LONG_MIN, LONG_MAX)) ++ printf ("multiply would overflow"); ++ else ++ printf ("product is %ld", i * j); ++ ++ Restrictions on *_RANGE_OVERFLOW macros: ++ ++ These macros do not check for all possible numerical problems or ++ undefined or unspecified behavior: they do not check for division ++ by zero, for bad shift counts, or for shifting negative numbers. ++ ++ These macros may evaluate their arguments zero or multiple times, ++ so the arguments should not have side effects. The arithmetic ++ arguments (including the MIN and MAX arguments) must be of the same ++ integer type after the usual arithmetic conversions, and the type ++ must have minimum value MIN and maximum MAX. Unsigned types should ++ use a zero MIN of the proper type. ++ ++ These macros are tuned for constant MIN and MAX. For commutative ++ operations such as A + B, they are also tuned for constant B. */ ++ ++/* Return 1 if A + B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. */ ++#define INT_ADD_RANGE_OVERFLOW(a, b, min, max) \ ++ ((b) < 0 \ ++ ? (a) < (min) - (b) \ ++ : (max) - (b) < (a)) ++ ++/* Return 1 if A - B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. */ ++#define INT_SUBTRACT_RANGE_OVERFLOW(a, b, min, max) \ ++ ((b) < 0 \ ++ ? (max) + (b) < (a) \ ++ : (a) < (min) + (b)) ++ ++/* Return 1 if - A would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. */ ++#define INT_NEGATE_RANGE_OVERFLOW(a, min, max) \ ++ ((min) < 0 \ ++ ? (a) < - (max) \ ++ : 0 < (a)) ++ ++/* Return 1 if A * B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. Avoid && and || as they tickle ++ bugs in Sun C 5.11 2010/08/13 and other compilers; see ++ . */ ++#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \ ++ ((b) < 0 \ ++ ? ((a) < 0 \ ++ ? (a) < (max) / (b) \ ++ : (b) == -1 \ ++ ? 0 \ ++ : (min) / (b) < (a)) \ ++ : (b) == 0 \ ++ ? 0 \ ++ : ((a) < 0 \ ++ ? (a) < (min) / (b) \ ++ : (max) / (b) < (a))) ++ ++/* Return 1 if A / B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. Do not check for division by zero. */ ++#define INT_DIVIDE_RANGE_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 && (b) == -1 && (a) < - (max)) ++ ++/* Return 1 if A % B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. Do not check for division by zero. ++ Mathematically, % should never overflow, but on x86-like hosts ++ INT_MIN % -1 traps, and the C standard permits this, so treat this ++ as an overflow too. */ ++#define INT_REMAINDER_RANGE_OVERFLOW(a, b, min, max) \ ++ INT_DIVIDE_RANGE_OVERFLOW (a, b, min, max) ++ ++/* Return 1 if A << B would overflow in [MIN,MAX] arithmetic. ++ See above for restrictions. Here, MIN and MAX are for A only, and B need ++ not be of the same type as the other arguments. The C standard says that ++ behavior is undefined for shifts unless 0 <= B < wordwidth, and that when ++ A is negative then A << B has undefined behavior and A >> B has ++ implementation-defined behavior, but do not check these other ++ restrictions. */ ++#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \ ++ ((a) < 0 \ ++ ? (a) < (min) >> (b) \ ++ : (max) >> (b) < (a)) ++ ++/* True if __builtin_add_overflow (A, B, P) works when P is non-null. */ ++#if 5 <= __GNUC__ && !defined __ICC ++# define _GL_HAS_BUILTIN_OVERFLOW 1 ++#else ++# define _GL_HAS_BUILTIN_OVERFLOW 0 ++#endif ++ ++/* True if __builtin_add_overflow_p (A, B, C) works. */ ++#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__) ++ ++/* The _GL*_OVERFLOW macros have the same restrictions as the ++ *_RANGE_OVERFLOW macros, except that they do not assume that operands ++ (e.g., A and B) have the same type as MIN and MAX. Instead, they assume ++ that the result (e.g., A + B) has that type. */ ++#if _GL_HAS_BUILTIN_OVERFLOW_P ++# define _GL_ADD_OVERFLOW(a, b, min, max) \ ++ __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0) ++# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ ++ __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0) ++# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ ++ __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0) ++#else ++# define _GL_ADD_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \ ++ : (a) < 0 ? (b) <= (a) + (b) \ ++ : (b) < 0 ? (a) <= (a) + (b) \ ++ : (a) + (b) < (b)) ++# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 ? INT_SUBTRACT_RANGE_OVERFLOW (a, b, min, max) \ ++ : (a) < 0 ? 1 \ ++ : (b) < 0 ? (a) - (b) <= (a) \ ++ : (a) < (b)) ++# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ ++ (((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \ ++ || INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max)) ++#endif ++#define _GL_DIVIDE_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ ++ : (a) < 0 ? (b) <= (a) + (b) - 1 \ ++ : (b) < 0 && (a) + (b) <= (a)) ++#define _GL_REMAINDER_OVERFLOW(a, b, min, max) \ ++ ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ ++ : (a) < 0 ? (a) % (b) != ((max) - (b) + 1) % (b) \ ++ : (b) < 0 && ! _GL_UNSIGNED_NEG_MULTIPLE (a, b, max)) ++ ++/* Return a nonzero value if A is a mathematical multiple of B, where ++ A is unsigned, B is negative, and MAX is the maximum value of A's ++ type. A's type must be the same as (A % B)'s type. Normally (A % ++ -B == 0) suffices, but things get tricky if -B would overflow. */ ++#define _GL_UNSIGNED_NEG_MULTIPLE(a, b, max) \ ++ (((b) < -_GL_SIGNED_INT_MAXIMUM (b) \ ++ ? (_GL_SIGNED_INT_MAXIMUM (b) == (max) \ ++ ? (a) \ ++ : (a) % (_GL_INT_CONVERT (a, _GL_SIGNED_INT_MAXIMUM (b)) + 1)) \ ++ : (a) % - (b)) \ ++ == 0) ++ ++/* Check for integer overflow, and report low order bits of answer. ++ ++ The INT__OVERFLOW macros return 1 if the corresponding C operators ++ might not yield numerically correct answers due to arithmetic overflow. ++ The INT__WRAPV macros also store the low-order bits of the answer. ++ These macros work correctly on all known practical hosts, and do not rely ++ on undefined behavior due to signed arithmetic overflow. ++ ++ Example usage, assuming A and B are long int: ++ ++ if (INT_MULTIPLY_OVERFLOW (a, b)) ++ printf ("result would overflow\n"); ++ else ++ printf ("result is %ld (no overflow)\n", a * b); ++ ++ Example usage with WRAPV flavor: ++ ++ long int result; ++ bool overflow = INT_MULTIPLY_WRAPV (a, b, &result); ++ printf ("result is %ld (%s)\n", result, ++ overflow ? "after overflow" : "no overflow"); ++ ++ Restrictions on these macros: ++ ++ These macros do not check for all possible numerical problems or ++ undefined or unspecified behavior: they do not check for division ++ by zero, for bad shift counts, or for shifting negative numbers. ++ ++ These macros may evaluate their arguments zero or multiple times, so the ++ arguments should not have side effects. ++ ++ The WRAPV macros are not constant expressions. They support only ++ +, binary -, and *. The result type must be signed. ++ ++ These macros are tuned for their last argument being a constant. ++ ++ Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B, ++ A % B, and A << B would overflow, respectively. */ ++ ++#define INT_ADD_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW) ++#define INT_SUBTRACT_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW) ++#if _GL_HAS_BUILTIN_OVERFLOW_P ++# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a) ++#else ++# define INT_NEGATE_OVERFLOW(a) \ ++ INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) ++#endif ++#define INT_MULTIPLY_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW) ++#define INT_DIVIDE_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW) ++#define INT_REMAINDER_OVERFLOW(a, b) \ ++ _GL_BINARY_OP_OVERFLOW (a, b, _GL_REMAINDER_OVERFLOW) ++#define INT_LEFT_SHIFT_OVERFLOW(a, b) \ ++ INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \ ++ _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) ++ ++/* Return 1 if the expression A B would overflow, ++ where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test, ++ assuming MIN and MAX are the minimum and maximum for the result type. ++ Arguments should be free of side effects. */ ++#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \ ++ op_result_overflow (a, b, \ ++ _GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \ ++ _GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b))) ++ ++/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R. ++ Return 1 if the result overflows. See above for restrictions. */ ++#define INT_ADD_WRAPV(a, b, r) \ ++ _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, INT_ADD_OVERFLOW) ++#define INT_SUBTRACT_WRAPV(a, b, r) \ ++ _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, INT_SUBTRACT_OVERFLOW) ++#define INT_MULTIPLY_WRAPV(a, b, r) \ ++ _GL_INT_OP_WRAPV (a, b, r, *, __builtin_mul_overflow, INT_MULTIPLY_OVERFLOW) ++ ++/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See: ++ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193 ++ https://llvm.org/bugs/show_bug.cgi?id=25390 ++ For now, assume all versions of GCC-like compilers generate bogus ++ warnings for _Generic. This matters only for older compilers that ++ lack __builtin_add_overflow. */ ++#if __GNUC__ ++# define _GL__GENERIC_BOGUS 1 ++#else ++# define _GL__GENERIC_BOGUS 0 ++#endif ++ ++/* Store the low-order bits of A B into *R, where OP specifies ++ the operation. BUILTIN is the builtin operation, and OVERFLOW the ++ overflow predicate. Return 1 if the result overflows. See above ++ for restrictions. */ ++#if _GL_HAS_BUILTIN_OVERFLOW ++# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) builtin (a, b, r) ++#elif 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS ++# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \ ++ (_Generic \ ++ (*(r), \ ++ signed char: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ signed char, SCHAR_MIN, SCHAR_MAX), \ ++ short int: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ short int, SHRT_MIN, SHRT_MAX), \ ++ int: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ int, INT_MIN, INT_MAX), \ ++ long int: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ ++ long int, LONG_MIN, LONG_MAX), \ ++ long long int: \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ ++ long long int, LLONG_MIN, LLONG_MAX))) ++#else ++# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \ ++ (sizeof *(r) == sizeof (signed char) \ ++ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ signed char, SCHAR_MIN, SCHAR_MAX) \ ++ : sizeof *(r) == sizeof (short int) \ ++ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ short int, SHRT_MIN, SHRT_MAX) \ ++ : sizeof *(r) == sizeof (int) \ ++ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ ++ int, INT_MIN, INT_MAX) \ ++ : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow)) ++# ifdef LLONG_MAX ++# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ ++ (sizeof *(r) == sizeof (long int) \ ++ ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ ++ long int, LONG_MIN, LONG_MAX) \ ++ : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ ++ long long int, LLONG_MIN, LLONG_MAX)) ++# else ++# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ ++ _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ ++ long int, LONG_MIN, LONG_MAX) ++# endif ++#endif ++ ++/* Store the low-order bits of A B into *R, where the operation ++ is given by OP. Use the unsigned type UT for calculation to avoid ++ overflow problems. *R's type is T, with extrema TMIN and TMAX. ++ T must be a signed integer type. Return 1 if the result overflows. */ ++#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \ ++ (sizeof ((a) op (b)) < sizeof (t) \ ++ ? _GL_INT_OP_CALC1 ((t) (a), (t) (b), r, op, overflow, ut, t, tmin, tmax) \ ++ : _GL_INT_OP_CALC1 (a, b, r, op, overflow, ut, t, tmin, tmax)) ++#define _GL_INT_OP_CALC1(a, b, r, op, overflow, ut, t, tmin, tmax) \ ++ ((overflow (a, b) \ ++ || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \ ++ || (tmax) < ((a) op (b))) \ ++ ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \ ++ : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0)) ++ ++/* Return the low-order bits of A B, where the operation is given ++ by OP. Use the unsigned type UT for calculation to avoid undefined ++ behavior on signed integer overflow, and convert the result to type T. ++ UT is at least as wide as T and is no narrower than unsigned int, ++ T is two's complement, and there is no padding or trap representations. ++ Assume that converting UT to T yields the low-order bits, as is ++ done in all known two's-complement C compilers. E.g., see: ++ https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html ++ ++ According to the C standard, converting UT to T yields an ++ implementation-defined result or signal for values outside T's ++ range. However, code that works around this theoretical problem ++ runs afoul of a compiler bug in Oracle Studio 12.3 x86. See: ++ https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html ++ As the compiler bug is real, don't try to work around the ++ theoretical problem. */ ++ ++#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \ ++ ((t) ((ut) (a) op (ut) (b))) ++ ++#endif /* _GL_INTPROPS_H */ +diff --git a/headers-mingw/langinfo.h b/headers-mingw/langinfo.h +new file mode 100644 +index 0000000..43244cd +--- /dev/null ++++ b/headers-mingw/langinfo.h +@@ -0,0 +1,139 @@ ++/* Substitute for and wrapper around . ++ Copyright (C) 2009-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++/* ++ * POSIX for platforms that lack it or have an incomplete one. ++ * ++ */ ++ ++#ifndef _GL_LANGINFO_H ++#define _GL_LANGINFO_H ++ ++ ++/* A platform that lacks . */ ++ ++/* Assume that it also lacks and the nl_item type. */ ++# if !GNULIB_defined_nl_item ++typedef int nl_item; ++# define GNULIB_defined_nl_item 1 ++# endif ++ ++/* nl_langinfo items of the LC_CTYPE category */ ++# define CODESET 10000 ++/* nl_langinfo items of the LC_NUMERIC category */ ++# define RADIXCHAR 10001 ++# define DECIMAL_POINT RADIXCHAR ++# define THOUSEP 10002 ++# define THOUSANDS_SEP THOUSEP ++# define GROUPING 10114 ++/* nl_langinfo items of the LC_TIME category */ ++# define D_T_FMT 10003 ++# define D_FMT 10004 ++# define T_FMT 10005 ++# define T_FMT_AMPM 10006 ++# define AM_STR 10007 ++# define PM_STR 10008 ++# define DAY_1 10009 ++# define DAY_2 (DAY_1 + 1) ++# define DAY_3 (DAY_1 + 2) ++# define DAY_4 (DAY_1 + 3) ++# define DAY_5 (DAY_1 + 4) ++# define DAY_6 (DAY_1 + 5) ++# define DAY_7 (DAY_1 + 6) ++# define ABDAY_1 10016 ++# define ABDAY_2 (ABDAY_1 + 1) ++# define ABDAY_3 (ABDAY_1 + 2) ++# define ABDAY_4 (ABDAY_1 + 3) ++# define ABDAY_5 (ABDAY_1 + 4) ++# define ABDAY_6 (ABDAY_1 + 5) ++# define ABDAY_7 (ABDAY_1 + 6) ++# define MON_1 10023 ++# define MON_2 (MON_1 + 1) ++# define MON_3 (MON_1 + 2) ++# define MON_4 (MON_1 + 3) ++# define MON_5 (MON_1 + 4) ++# define MON_6 (MON_1 + 5) ++# define MON_7 (MON_1 + 6) ++# define MON_8 (MON_1 + 7) ++# define MON_9 (MON_1 + 8) ++# define MON_10 (MON_1 + 9) ++# define MON_11 (MON_1 + 10) ++# define MON_12 (MON_1 + 11) ++# define ALTMON_1 10200 ++# define ALTMON_2 (ALTMON_1 + 1) ++# define ALTMON_3 (ALTMON_1 + 2) ++# define ALTMON_4 (ALTMON_1 + 3) ++# define ALTMON_5 (ALTMON_1 + 4) ++# define ALTMON_6 (ALTMON_1 + 5) ++# define ALTMON_7 (ALTMON_1 + 6) ++# define ALTMON_8 (ALTMON_1 + 7) ++# define ALTMON_9 (ALTMON_1 + 8) ++# define ALTMON_10 (ALTMON_1 + 9) ++# define ALTMON_11 (ALTMON_1 + 10) ++# define ALTMON_12 (ALTMON_1 + 11) ++# define ABMON_1 10035 ++# define ABMON_2 (ABMON_1 + 1) ++# define ABMON_3 (ABMON_1 + 2) ++# define ABMON_4 (ABMON_1 + 3) ++# define ABMON_5 (ABMON_1 + 4) ++# define ABMON_6 (ABMON_1 + 5) ++# define ABMON_7 (ABMON_1 + 6) ++# define ABMON_8 (ABMON_1 + 7) ++# define ABMON_9 (ABMON_1 + 8) ++# define ABMON_10 (ABMON_1 + 9) ++# define ABMON_11 (ABMON_1 + 10) ++# define ABMON_12 (ABMON_1 + 11) ++# define ERA 10047 ++# define ERA_D_FMT 10048 ++# define ERA_D_T_FMT 10049 ++# define ERA_T_FMT 10050 ++# define ALT_DIGITS 10051 ++/* nl_langinfo items of the LC_MONETARY category */ ++# define CRNCYSTR 10052 ++# define CURRENCY_SYMBOL CRNCYSTR ++# define INT_CURR_SYMBOL 10100 ++# define MON_DECIMAL_POINT 10101 ++# define MON_THOUSANDS_SEP 10102 ++# define MON_GROUPING 10103 ++# define POSITIVE_SIGN 10104 ++# define NEGATIVE_SIGN 10105 ++# define FRAC_DIGITS 10106 ++# define INT_FRAC_DIGITS 10107 ++# define P_CS_PRECEDES 10108 ++# define N_CS_PRECEDES 10109 ++# define P_SEP_BY_SPACE 10110 ++# define N_SEP_BY_SPACE 10111 ++# define P_SIGN_POSN 10112 ++# define N_SIGN_POSN 10113 ++/* nl_langinfo items of the LC_MESSAGES category */ ++# define YESEXPR 10053 ++# define NOEXPR 10054 ++ ++ ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++/* Declare overridden functions. */ ++ ++ ++/* Return a piece of locale dependent information. ++ Note: The difference between nl_langinfo (CODESET) and locale_charset () ++ is that the latter normalizes the encoding names to GNU conventions. */ ++ ++extern char * nl_langinfo (nl_item item); ++ ++#endif /* _GL_LANGINFO_H */ +diff --git a/headers-mingw/libc-config.h b/headers-mingw/libc-config.h +new file mode 100644 +index 0000000..a352393 +--- /dev/null ++++ b/headers-mingw/libc-config.h +@@ -0,0 +1,174 @@ ++/* System definitions for code taken from the GNU C Library ++ ++ Copyright 2017-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with this program; if not, see ++ . */ ++ ++/* Written by Paul Eggert. */ ++ ++/* This is intended to be a good-enough substitute for glibc system ++ macros like those defined in , so that Gnulib code ++ shared with glibc can do this as the first #include: ++ ++ #ifndef _LIBC ++ # include ++ #endif ++ ++ When compiled as part of glibc this is a no-op; when compiled as ++ part of Gnulib this includes Gnulib's and defines macros ++ that glibc library code would normally assume. */ ++ ++#include ++ ++/* On glibc this includes and and #defines ++ _FEATURES_H, __WORDSIZE, and __set_errno. On FreeBSD 11 it ++ includes which defines __nonnull. Elsewhere it ++ is harmless. */ ++#include ++ ++/* From glibc . */ ++#ifndef __set_errno ++# define __set_errno(val) (errno = (val)) ++#endif ++ ++/* From glibc . */ ++ ++#ifndef __GNUC_PREREQ ++# if defined __GNUC__ && defined __GNUC_MINOR__ ++# define __GNUC_PREREQ(maj, min) ((maj) < __GNUC__ + ((min) <= __GNUC_MINOR__)) ++# else ++# define __GNUC_PREREQ(maj, min) 0 ++# endif ++#endif ++ ++#ifndef __glibc_clang_prereq ++# if defined __clang_major__ && defined __clang_minor__ ++# define __glibc_clang_prereq(maj, min) \ ++ ((maj) < __clang_major__ + ((min) <= __clang_minor__)) ++# else ++# define __glibc_clang_prereq(maj, min) 0 ++# endif ++#endif ++ ++ ++/* Prepare to include , which is our copy of glibc ++ . */ ++ ++/* Define _FEATURES_H so that does not include . */ ++#ifndef _FEATURES_H ++# define _FEATURES_H 1 ++#endif ++/* Define __WORDSIZE so that does not attempt to include ++ nonexistent files. Make it a syntax error, since Gnulib does not ++ use __WORDSIZE now, and if Gnulib uses it later the syntax error ++ will let us know that __WORDSIZE needs configuring. */ ++#ifndef __WORDSIZE ++# define __WORDSIZE %%% ++#endif ++/* Undef the macros unconditionally defined by our copy of glibc ++ , so that they do not clash with any system-defined ++ versions. */ ++#undef _SYS_CDEFS_H ++#undef __ASMNAME ++#undef __ASMNAME2 ++#undef __BEGIN_DECLS ++#undef __CONCAT ++#undef __END_DECLS ++#undef __HAVE_GENERIC_SELECTION ++#undef __LDBL_COMPAT ++#undef __LDBL_REDIR ++#undef __LDBL_REDIR1 ++#undef __LDBL_REDIR1_DECL ++#undef __LDBL_REDIR1_NTH ++#undef __LDBL_REDIR_DECL ++#undef __LDBL_REDIR_NTH ++#undef __LEAF ++#undef __LEAF_ATTR ++#undef __NTH ++#undef __NTHNL ++#undef __P ++#undef __PMT ++#undef __REDIRECT ++#undef __REDIRECT_LDBL ++#undef __REDIRECT_NTH ++#undef __REDIRECT_NTHNL ++#undef __REDIRECT_NTH_LDBL ++#undef __STRING ++#undef __THROW ++#undef __THROWNL ++#undef __always_inline ++#undef __attribute__ ++#undef __attribute_alloc_size__ ++#undef __attribute_artificial__ ++#undef __attribute_const__ ++#undef __attribute_deprecated__ ++#undef __attribute_deprecated_msg__ ++#undef __attribute_format_arg__ ++#undef __attribute_format_strfmon__ ++#undef __attribute_malloc__ ++#undef __attribute_noinline__ ++#undef __attribute_nonstring__ ++#undef __attribute_pure__ ++#undef __attribute_used__ ++#undef __attribute_warn_unused_result__ ++#undef __bos ++#undef __bos0 ++#undef __errordecl ++#undef __extension__ ++#undef __extern_always_inline ++#undef __extern_inline ++#undef __flexarr ++#undef __fortify_function ++#undef __glibc_c99_flexarr_available ++#undef __glibc_clang_has_extension ++#undef __glibc_likely ++#undef __glibc_macro_warning ++#undef __glibc_macro_warning1 ++#undef __glibc_unlikely ++#undef __inline ++#undef __ptr_t ++#undef __restrict ++#undef __restrict_arr ++#undef __va_arg_pack ++#undef __va_arg_pack_len ++#undef __warnattr ++#undef __warndecl ++ ++/* Include our copy of glibc . */ ++#include "sys_cdefs.h" ++ ++/* __inline is too pessimistic for non-GCC. */ ++#undef __inline ++#ifndef HAVE___INLINE ++# if 199901 <= __STDC_VERSION__ || defined inline ++# define __inline inline ++# else ++# define __inline ++# endif ++#endif ++ ++ ++/* A substitute for glibc , good enough for Gnulib. */ ++#define attribute_hidden ++#define libc_hidden_proto(name, ...) ++#define libc_hidden_def(name) ++#define libc_hidden_weak(name) ++#define libc_hidden_ver(local, name) ++#define strong_alias(name, aliasname) ++#define weak_alias(name, aliasname) ++ ++/* A substitute for glibc , good enough for Gnulib. */ ++#define SHLIB_COMPAT(lib, introduced, obsoleted) 0 ++#define versioned_symbol(lib, local, symbol, version) +diff --git a/headers-mingw/poll.h b/headers-mingw/poll.h +new file mode 100644 +index 0000000..fd3fb64 +--- /dev/null ++++ b/headers-mingw/poll.h +@@ -0,0 +1,76 @@ ++/* Header for poll(2) emulation ++ Contributed by Paolo Bonzini. ++ ++ Copyright 2001-2003, 2007, 2009-2018 Free Software Foundation, Inc. ++ ++ This file is part of gnulib. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++#ifndef _GL_POLL_H ++ ++#define _GL_POLL_H ++ ++ ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++ ++#if !HAVE_POLL_H ++ ++/* fake a poll(2) environment */ ++# define POLLIN 0x0001 /* any readable data available */ ++# define POLLPRI 0x0002 /* OOB/Urgent readable data */ ++# define POLLOUT 0x0004 /* file descriptor is writable */ ++# define POLLERR 0x0008 /* some poll error occurred */ ++# define POLLHUP 0x0010 /* file descriptor was "hung up" */ ++# define POLLNVAL 0x0020 /* requested events "invalid" */ ++# define POLLRDNORM 0x0040 ++# define POLLRDBAND 0x0080 ++# define POLLWRNORM 0x0100 ++# define POLLWRBAND 0x0200 ++ ++# if !GNULIB_defined_poll_types ++# if !(defined _WIN32 && ! defined __CYGWIN__) ++struct pollfd ++{ ++ int fd; /* which file descriptor to poll */ ++ short events; /* events we are interested in */ ++ short revents; /* events found on return */ ++}; ++ ++# else ++#include ++# endif ++ ++typedef unsigned long nfds_t; ++ ++# define GNULIB_defined_poll_types 1 ++# endif ++ ++/* Define INFTIM only if doing so conforms to POSIX. */ ++# if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE) ++# define INFTIM (-1) ++# endif ++ ++#endif ++ ++ ++# if !HAVE_POLL ++extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout); ++#endif ++ ++ ++#endif /* _@GUARD_PREFIX@_POLL_H */ +diff --git a/headers-mingw/regex.h b/headers-mingw/regex.h +new file mode 100644 +index 0000000..8d8160f +--- /dev/null ++++ b/headers-mingw/regex.h +@@ -0,0 +1,635 @@ ++/* Definitions for data structures and routines for the regular ++ expression library. ++ Copyright (C) 1985, 1989-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _REGEX_H ++#define _REGEX_H 1 ++ ++#include ++ ++/* Allow the use in C++ code. */ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Define __USE_GNU to declare GNU extensions that violate the ++ POSIX name space rules. */ ++#ifdef _GNU_SOURCE ++# define __USE_GNU 1 ++#endif ++ ++#ifdef _REGEX_LARGE_OFFSETS ++ ++/* Use types and values that are wide enough to represent signed and ++ unsigned byte offsets in memory. This currently works only when ++ the regex code is used outside of the GNU C library; it is not yet ++ supported within glibc itself, and glibc users should not define ++ _REGEX_LARGE_OFFSETS. */ ++ ++/* The type of object sizes. */ ++typedef size_t __re_size_t; ++ ++/* The type of object sizes, in places where the traditional code ++ uses unsigned long int. */ ++typedef size_t __re_long_size_t; ++ ++#else ++ ++/* The traditional GNU regex implementation mishandles strings longer ++ than INT_MAX. */ ++typedef unsigned int __re_size_t; ++typedef unsigned long int __re_long_size_t; ++ ++#endif ++ ++/* The following two types have to be signed and unsigned integer type ++ wide enough to hold a value of a pointer. For most ANSI compilers ++ ptrdiff_t and size_t should be likely OK. Still size of these two ++ types is 2 for Microsoft C. Ugh... */ ++typedef long int s_reg_t; ++typedef unsigned long int active_reg_t; ++ ++/* The following bits are used to determine the regexp syntax we ++ recognize. The set/not-set meanings are chosen so that Emacs syntax ++ remains the value 0. The bits are given in alphabetical order, and ++ the definitions shifted by one from the previous bit; thus, when we ++ add or remove a bit, only one other definition need change. */ ++typedef unsigned long int reg_syntax_t; ++ ++/* If this bit is not set, then \ inside a bracket expression is literal. ++ If set, then such a \ quotes the following character. */ ++# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) ++ ++/* If this bit is not set, then + and ? are operators, and \+ and \? are ++ literals. ++ If set, then \+ and \? are operators and + and ? are literals. */ ++# define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) ++ ++/* If this bit is set, then character classes are supported. They are: ++ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], ++ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. ++ If not set, then character classes are not supported. */ ++# define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) ++ ++/* If this bit is set, then ^ and $ are always anchors (outside bracket ++ expressions, of course). ++ If this bit is not set, then it depends: ++ ^ is an anchor if it is at the beginning of a regular ++ expression or after an open-group or an alternation operator; ++ $ is an anchor if it is at the end of a regular expression, or ++ before a close-group or an alternation operator. ++ ++ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because ++ POSIX draft 11.2 says that * etc. in leading positions is undefined. ++ We already implemented a previous draft which made those constructs ++ invalid, though, so we haven't changed the code back. */ ++# define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) ++ ++/* If this bit is set, then special characters are always special ++ regardless of where they are in the pattern. ++ If this bit is not set, then special characters are special only in ++ some contexts; otherwise they are ordinary. Specifically, ++ * + ? and intervals are only special when not after the beginning, ++ open-group, or alternation operator. */ ++# define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) ++ ++/* If this bit is set, then *, +, ?, and { cannot be first in an re or ++ immediately after an alternation or begin-group operator. */ ++# define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) ++ ++/* If this bit is set, then . matches newline. ++ If not set, then it doesn't. */ ++# define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) ++ ++/* If this bit is set, then . doesn't match NUL. ++ If not set, then it does. */ ++# define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) ++ ++/* If this bit is set, nonmatching lists [^...] do not match newline. ++ If not set, they do. */ ++# define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) ++ ++/* If this bit is set, either \{...\} or {...} defines an ++ interval, depending on RE_NO_BK_BRACES. ++ If not set, \{, \}, {, and } are literals. */ ++# define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) ++ ++/* If this bit is set, +, ? and | aren't recognized as operators. ++ If not set, they are. */ ++# define RE_LIMITED_OPS (RE_INTERVALS << 1) ++ ++/* If this bit is set, newline is an alternation operator. ++ If not set, newline is literal. */ ++# define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) ++ ++/* If this bit is set, then '{...}' defines an interval, and \{ and \} ++ are literals. ++ If not set, then '\{...\}' defines an interval. */ ++# define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) ++ ++/* If this bit is set, (...) defines a group, and \( and \) are literals. ++ If not set, \(...\) defines a group, and ( and ) are literals. */ ++# define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) ++ ++/* If this bit is set, then \ matches . ++ If not set, then \ is a back-reference. */ ++# define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) ++ ++/* If this bit is set, then | is an alternation operator, and \| is literal. ++ If not set, then \| is an alternation operator, and | is literal. */ ++# define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) ++ ++/* If this bit is set, then an ending range point collating higher ++ than the starting range point, as in [z-a], is invalid. ++ If not set, then when ending range point collates higher than the ++ starting range point, the range is ignored. */ ++# define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) ++ ++/* If this bit is set, then an unmatched ) is ordinary. ++ If not set, then an unmatched ) is invalid. */ ++# define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) ++ ++/* If this bit is set, succeed as soon as we match the whole pattern, ++ without further backtracking. */ ++# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) ++ ++/* If this bit is set, do not process the GNU regex operators. ++ If not set, then the GNU regex operators are recognized. */ ++# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) ++ ++/* If this bit is set, turn on internal regex debugging. ++ If not set, and debugging was on, turn it off. ++ This only works if regex.c is compiled -DDEBUG. ++ We define this bit always, so that all that's needed to turn on ++ debugging is to recompile regex.c; the calling code can always have ++ this bit set, and it won't affect anything in the normal case. */ ++# define RE_DEBUG (RE_NO_GNU_OPS << 1) ++ ++/* If this bit is set, a syntactically invalid interval is treated as ++ a string of ordinary characters. For example, the ERE 'a{1' is ++ treated as 'a\{1'. */ ++# define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) ++ ++/* If this bit is set, then ignore case when matching. ++ If not set, then case is significant. */ ++# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) ++ ++/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only ++ for ^, because it is difficult to scan the regex backwards to find ++ whether ^ should be special. */ ++# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) ++ ++/* If this bit is set, then \{ cannot be first in a regex or ++ immediately after an alternation, open-group or \} operator. */ ++# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) ++ ++/* If this bit is set, then no_sub will be set to 1 during ++ re_compile_pattern. */ ++# define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) ++ ++ ++/* This global variable defines the particular regexp syntax to use (for ++ some interfaces). When a regexp is compiled, the syntax used is ++ stored in the pattern buffer, so changing this does not affect ++ already-compiled regexps. */ ++extern reg_syntax_t re_syntax_options; ++ ++ ++/* Define combinations of the above bits for the standard possibilities. ++ (The [[[ comments delimit what gets put into the Texinfo file, so ++ don't delete them!) */ ++/* [[[begin syntaxes]]] */ ++# define RE_SYNTAX_EMACS 0 ++ ++# define RE_SYNTAX_AWK \ ++ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ ++ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ ++ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ ++ | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ ++ | RE_CHAR_CLASSES \ ++ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) ++ ++# define RE_SYNTAX_GNU_AWK \ ++ ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ ++ | RE_INVALID_INTERVAL_ORD) \ ++ & ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \ ++ | RE_CONTEXT_INVALID_OPS )) ++ ++# define RE_SYNTAX_POSIX_AWK \ ++ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ ++ | RE_INTERVALS | RE_NO_GNU_OPS \ ++ | RE_INVALID_INTERVAL_ORD) ++ ++# define RE_SYNTAX_GREP \ ++ ((RE_SYNTAX_POSIX_BASIC | RE_NEWLINE_ALT) \ ++ & ~(RE_CONTEXT_INVALID_DUP | RE_DOT_NOT_NULL)) ++ ++# define RE_SYNTAX_EGREP \ ++ ((RE_SYNTAX_POSIX_EXTENDED | RE_INVALID_INTERVAL_ORD | RE_NEWLINE_ALT) \ ++ & ~(RE_CONTEXT_INVALID_OPS | RE_DOT_NOT_NULL)) ++ ++/* POSIX grep -E behavior is no longer incompatible with GNU. */ ++# define RE_SYNTAX_POSIX_EGREP \ ++ RE_SYNTAX_EGREP ++ ++/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ ++# define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC ++ ++# define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC ++ ++/* Syntax bits common to both basic and extended POSIX regex syntax. */ ++# define _RE_SYNTAX_POSIX_COMMON \ ++ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ ++ | RE_INTERVALS | RE_NO_EMPTY_RANGES) ++ ++# define RE_SYNTAX_POSIX_BASIC \ ++ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) ++ ++/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes ++ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this ++ isn't minimal, since other operators, such as \`, aren't disabled. */ ++# define RE_SYNTAX_POSIX_MINIMAL_BASIC \ ++ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) ++ ++# define RE_SYNTAX_POSIX_EXTENDED \ ++ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ ++ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ ++ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ ++ | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) ++ ++/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is ++ removed and RE_NO_BK_REFS is added. */ ++# define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ ++ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ ++ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ ++ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ ++ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) ++/* [[[end syntaxes]]] */ ++ ++ ++/* RE_DUP_MAX is 2**15 - 1 because an earlier implementation stored ++ the counter as a 2-byte signed integer. This is no longer true, so ++ RE_DUP_MAX could be increased to (INT_MAX / 10 - 1), or to ++ ((SIZE_MAX - 9) / 10) if _REGEX_LARGE_OFFSETS is defined. ++ However, there would be a huge performance problem if someone ++ actually used a pattern like a\{214748363\}, so RE_DUP_MAX retains ++ its historical value. */ ++# define RE_DUP_MAX (0x7fff) ++ ++ ++ ++/* POSIX 'cflags' bits (i.e., information for 'regcomp'). */ ++ ++/* If this bit is set, then use extended regular expression syntax. ++ If not set, then use basic regular expression syntax. */ ++#define REG_EXTENDED 1 ++ ++/* If this bit is set, then ignore case when matching. ++ If not set, then case is significant. */ ++#define REG_ICASE (1 << 1) ++ ++/* If this bit is set, then anchors do not match at newline ++ characters in the string. ++ If not set, then anchors do match at newlines. */ ++#define REG_NEWLINE (1 << 2) ++ ++/* If this bit is set, then report only success or fail in regexec. ++ If not set, then returns differ between not matching and errors. */ ++#define REG_NOSUB (1 << 3) ++ ++ ++/* POSIX 'eflags' bits (i.e., information for regexec). */ ++ ++/* If this bit is set, then the beginning-of-line operator doesn't match ++ the beginning of the string (presumably because it's not the ++ beginning of a line). ++ If not set, then the beginning-of-line operator does match the ++ beginning of the string. */ ++#define REG_NOTBOL 1 ++ ++/* Like REG_NOTBOL, except for the end-of-line. */ ++#define REG_NOTEOL (1 << 1) ++ ++/* Use PMATCH[0] to delimit the start and end of the search in the ++ buffer. */ ++#define REG_STARTEND (1 << 2) ++ ++ ++/* If any error codes are removed, changed, or added, update the ++ '__re_error_msgid' table in regcomp.c. */ ++ ++typedef enum ++{ ++ _REG_ENOSYS = -1, /* This will never happen for this implementation. */ ++ _REG_NOERROR = 0, /* Success. */ ++ _REG_NOMATCH, /* Didn't find a match (for regexec). */ ++ ++ /* POSIX regcomp return error codes. (In the order listed in the ++ standard.) */ ++ _REG_BADPAT, /* Invalid pattern. */ ++ _REG_ECOLLATE, /* Invalid collating element. */ ++ _REG_ECTYPE, /* Invalid character class name. */ ++ _REG_EESCAPE, /* Trailing backslash. */ ++ _REG_ESUBREG, /* Invalid back reference. */ ++ _REG_EBRACK, /* Unmatched left bracket. */ ++ _REG_EPAREN, /* Parenthesis imbalance. */ ++ _REG_EBRACE, /* Unmatched \{. */ ++ _REG_BADBR, /* Invalid contents of \{\}. */ ++ _REG_ERANGE, /* Invalid range end. */ ++ _REG_ESPACE, /* Ran out of memory. */ ++ _REG_BADRPT, /* No preceding re for repetition op. */ ++ ++ /* Error codes we've added. */ ++ _REG_EEND, /* Premature end. */ ++ _REG_ESIZE, /* Too large (e.g., repeat count too large). */ ++ _REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ ++} reg_errcode_t; ++ ++#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K ++# define REG_ENOSYS _REG_ENOSYS ++#endif ++#define REG_NOERROR _REG_NOERROR ++#define REG_NOMATCH _REG_NOMATCH ++#define REG_BADPAT _REG_BADPAT ++#define REG_ECOLLATE _REG_ECOLLATE ++#define REG_ECTYPE _REG_ECTYPE ++#define REG_EESCAPE _REG_EESCAPE ++#define REG_ESUBREG _REG_ESUBREG ++#define REG_EBRACK _REG_EBRACK ++#define REG_EPAREN _REG_EPAREN ++#define REG_EBRACE _REG_EBRACE ++#define REG_BADBR _REG_BADBR ++#define REG_ERANGE _REG_ERANGE ++#define REG_ESPACE _REG_ESPACE ++#define REG_BADRPT _REG_BADRPT ++#define REG_EEND _REG_EEND ++#define REG_ESIZE _REG_ESIZE ++#define REG_ERPAREN _REG_ERPAREN ++ ++/* This data structure represents a compiled pattern. Before calling ++ the pattern compiler, the fields 'buffer', 'allocated', 'fastmap', ++ and 'translate' can be set. After the pattern has been compiled, ++ the fields 're_nsub', 'not_bol' and 'not_eol' are available. All ++ other fields are private to the regex routines. */ ++ ++#ifndef RE_TRANSLATE_TYPE ++# define __RE_TRANSLATE_TYPE unsigned char * ++ ++# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE ++ ++#endif ++ ++# define __REPB_PREFIX(name) name ++ ++struct re_pattern_buffer ++{ ++ /* Space that holds the compiled pattern. The type ++ 'struct re_dfa_t' is private and is not declared here. */ ++ struct re_dfa_t *__REPB_PREFIX(buffer); ++ ++ /* Number of bytes to which 'buffer' points. */ ++ __re_long_size_t __REPB_PREFIX(allocated); ++ ++ /* Number of bytes actually used in 'buffer'. */ ++ __re_long_size_t __REPB_PREFIX(used); ++ ++ /* Syntax setting with which the pattern was compiled. */ ++ reg_syntax_t __REPB_PREFIX(syntax); ++ ++ /* Pointer to a fastmap, if any, otherwise zero. re_search uses the ++ fastmap, if there is one, to skip over impossible starting points ++ for matches. */ ++ char *__REPB_PREFIX(fastmap); ++ ++ /* Either a translate table to apply to all characters before ++ comparing them, or zero for no translation. The translation is ++ applied to a pattern when it is compiled and to a string when it ++ is matched. */ ++ __RE_TRANSLATE_TYPE __REPB_PREFIX(translate); ++ ++ /* Number of subexpressions found by the compiler. */ ++ size_t re_nsub; ++ ++ /* Zero if this pattern cannot match the empty string, one else. ++ Well, in truth it's used only in 're_search_2', to see whether or ++ not we should use the fastmap, so we don't set this absolutely ++ perfectly; see 're_compile_fastmap' (the "duplicate" case). */ ++ unsigned __REPB_PREFIX(can_be_null) : 1; ++ ++ /* If REGS_UNALLOCATED, allocate space in the 'regs' structure ++ for 'max (RE_NREGS, re_nsub + 1)' groups. ++ If REGS_REALLOCATE, reallocate space if necessary. ++ If REGS_FIXED, use what's there. */ ++ ++# define REGS_UNALLOCATED 0 ++# define REGS_REALLOCATE 1 ++# define REGS_FIXED 2 ++ ++ unsigned __REPB_PREFIX(regs_allocated) : 2; ++ ++ /* Set to zero when 're_compile_pattern' compiles a pattern; set to ++ one by 're_compile_fastmap' if it updates the fastmap. */ ++ unsigned __REPB_PREFIX(fastmap_accurate) : 1; ++ ++ /* If set, 're_match_2' does not return information about ++ subexpressions. */ ++ unsigned __REPB_PREFIX(no_sub) : 1; ++ ++ /* If set, a beginning-of-line anchor doesn't match at the beginning ++ of the string. */ ++ unsigned __REPB_PREFIX(not_bol) : 1; ++ ++ /* Similarly for an end-of-line anchor. */ ++ unsigned __REPB_PREFIX(not_eol) : 1; ++ ++ /* If true, an anchor at a newline matches. */ ++ unsigned __REPB_PREFIX(newline_anchor) : 1; ++}; ++ ++typedef struct re_pattern_buffer regex_t; ++ ++/* Type for byte offsets within the string. POSIX mandates this. */ ++#ifdef _REGEX_LARGE_OFFSETS ++/* POSIX 1003.1-2008 requires that regoff_t be at least as wide as ++ ptrdiff_t and ssize_t. We don't know of any hosts where ptrdiff_t ++ is wider than ssize_t, so ssize_t is safe. ptrdiff_t is not ++ visible here, so use ssize_t. */ ++typedef ssize_t regoff_t; ++#else ++/* The traditional GNU regex implementation mishandles strings longer ++ than INT_MAX. */ ++typedef int regoff_t; ++#endif ++ ++ ++ ++/* This is the structure we store register match data in. See ++ regex.texinfo for a full description of what registers match. */ ++struct re_registers ++{ ++ __re_size_t num_regs; ++ regoff_t *start; ++ regoff_t *end; ++}; ++ ++ ++/* If 'regs_allocated' is REGS_UNALLOCATED in the pattern buffer, ++ 're_match_2' returns information about at least this many registers ++ the first time a 'regs' structure is passed. */ ++# ifndef RE_NREGS ++# define RE_NREGS 30 ++# endif ++ ++ ++ ++/* POSIX specification for registers. Aside from the different names than ++ 're_registers', POSIX uses an array of structures, instead of a ++ structure of arrays. */ ++typedef struct ++{ ++ regoff_t rm_so; /* Byte offset from string's start to substring's start. */ ++ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ ++} regmatch_t; ++ ++/* Declarations for routines. */ ++ ++ ++/* Sets the current default syntax to SYNTAX, and return the old syntax. ++ You can also simply assign to the 're_syntax_options' variable. */ ++extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); ++ ++/* Compile the regular expression PATTERN, with length LENGTH ++ and syntax given by the global 're_syntax_options', into the buffer ++ BUFFER. Return NULL if successful, and an error string if not. ++ ++ To free the allocated storage, you must call 'regfree' on BUFFER. ++ Note that the translate table must either have been initialized by ++ 'regcomp', with a malloc'ed value, or set to NULL before calling ++ 'regfree'. */ ++extern const char *re_compile_pattern (const char *__pattern, size_t __length, ++ struct re_pattern_buffer *__buffer); ++ ++ ++/* Compile a fastmap for the compiled pattern in BUFFER; used to ++ accelerate searches. Return 0 if successful and -2 if was an ++ internal error. */ ++extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); ++ ++ ++/* Search in the string STRING (with length LENGTH) for the pattern ++ compiled into BUFFER. Start searching at position START, for RANGE ++ characters. Return the starting position of the match, -1 for no ++ match, or -2 for an internal error. Also return register ++ information in REGS (if REGS and BUFFER->no_sub are nonzero). */ ++extern regoff_t re_search (struct re_pattern_buffer *__buffer, ++ const char *__String, regoff_t __length, ++ regoff_t __start, regoff_t __range, ++ struct re_registers *__regs); ++ ++ ++/* Like 're_search', but search in the concatenation of STRING1 and ++ STRING2. Also, stop searching at index START + STOP. */ ++extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer, ++ const char *__string1, regoff_t __length1, ++ const char *__string2, regoff_t __length2, ++ regoff_t __start, regoff_t __range, ++ struct re_registers *__regs, ++ regoff_t __stop); ++ ++ ++/* Like 're_search', but return how many characters in STRING the regexp ++ in BUFFER matched, starting at position START. */ ++extern regoff_t re_match (struct re_pattern_buffer *__buffer, ++ const char *__String, regoff_t __length, ++ regoff_t __start, struct re_registers *__regs); ++ ++ ++/* Relates to 're_match' as 're_search_2' relates to 're_search'. */ ++extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer, ++ const char *__string1, regoff_t __length1, ++ const char *__string2, regoff_t __length2, ++ regoff_t __start, struct re_registers *__regs, ++ regoff_t __stop); ++ ++ ++/* Set REGS to hold NUM_REGS registers, storing them in STARTS and ++ ENDS. Subsequent matches using BUFFER and REGS will use this memory ++ for recording register information. STARTS and ENDS must be ++ allocated with malloc, and must each be at least 'NUM_REGS * sizeof ++ (regoff_t)' bytes long. ++ ++ If NUM_REGS == 0, then subsequent matches should allocate their own ++ register data. ++ ++ Unless this function is called, the first search or match using ++ BUFFER will allocate its own register data, without ++ freeing the old data. */ ++extern void re_set_registers (struct re_pattern_buffer *__buffer, ++ struct re_registers *__regs, ++ __re_size_t __num_regs, ++ regoff_t *__starts, regoff_t *__ends); ++ ++/* For plain 'restrict', use glibc's __restrict if defined. ++ Otherwise, GCC 2.95 and later have "__restrict"; C99 compilers have ++ "restrict", and "configure" may have defined "restrict". ++ Other compilers use __restrict, __restrict__, and _Restrict, and ++ 'configure' might #define 'restrict' to those words, so pick a ++ different name. */ ++#ifndef _Restrict_ ++# if defined __restrict || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) ++# define _Restrict_ __restrict ++# elif 199901L <= __STDC_VERSION__ || defined restrict ++# define _Restrict_ restrict ++# else ++# define _Restrict_ ++# endif ++#endif ++/* For [restrict], use glibc's __restrict_arr if available. ++ Otherwise, GCC 3.1 (not in C++ mode) and C99 support [restrict]. */ ++#ifndef _Restrict_arr_ ++# ifdef __restrict_arr ++# define _Restrict_arr_ __restrict_arr ++# elif ((199901L <= __STDC_VERSION__ || 3 < __GNUC__ + (1 <= __GNUC_MINOR__)) \ ++ && !defined __GNUG__) ++# define _Restrict_arr_ _Restrict_ ++# else ++# define _Restrict_arr_ ++# endif ++#endif ++ ++/* POSIX compatibility. */ ++extern int regcomp (regex_t *_Restrict_ __preg, ++ const char *_Restrict_ __pattern, ++ int __cflags); ++ ++extern int regexec (const regex_t *_Restrict_ __preg, ++ const char *_Restrict_ __String, size_t __nmatch, ++ regmatch_t __pmatch[_Restrict_arr_], ++ int __eflags); ++ ++extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg, ++ char *_Restrict_ __errbuf, size_t __errbuf_size); ++ ++extern void regfree (regex_t *__preg); ++ ++ ++#ifdef __cplusplus ++} ++#endif /* C++ */ ++ ++#endif /* regex.h */ +diff --git a/headers-mingw/regex_internal.h b/headers-mingw/regex_internal.h +new file mode 100644 +index 0000000..b4ae872 +--- /dev/null ++++ b/headers-mingw/regex_internal.h +@@ -0,0 +1,780 @@ ++/* Extended regular expression matching and search library. ++ Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Isamu Hasegawa . ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _REGEX_INTERNAL_H ++#define _REGEX_INTERNAL_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "langinfo.h" ++#include ++#include ++#include ++#include ++#include ++ ++#include "intprops.h" ++ ++#ifdef _LIBC ++# include ++# define lock_define(name) __libc_lock_define (, name) ++# define lock_init(lock) (__libc_lock_init (lock), 0) ++# define lock_fini(lock) ((void) 0) ++# define lock_lock(lock) __libc_lock_lock (lock) ++# define lock_unlock(lock) __libc_lock_unlock (lock) ++#elif defined GNULIB_LOCK && !defined USE_UNLOCKED_IO ++# include "glthread/lock.h" ++ /* Use gl_lock_define if empty macro arguments are known to work. ++ Otherwise, fall back on less-portable substitutes. */ ++# if ((defined __GNUC__ && !defined __STRICT_ANSI__) \ ++ || (defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__)) ++# define lock_define(name) gl_lock_define (, name) ++# elif USE_POSIX_THREADS ++# define lock_define(name) pthread_mutex_t name; ++# elif USE_PTH_THREADS ++# define lock_define(name) pth_mutex_t name; ++# elif USE_SOLARIS_THREADS ++# define lock_define(name) mutex_t name; ++# elif USE_WINDOWS_THREADS ++# define lock_define(name) gl_lock_t name; ++# else ++# define lock_define(name) ++# endif ++# define lock_init(lock) glthread_lock_init (&(lock)) ++# define lock_fini(lock) glthread_lock_destroy (&(lock)) ++# define lock_lock(lock) glthread_lock_lock (&(lock)) ++# define lock_unlock(lock) glthread_lock_unlock (&(lock)) ++#elif defined GNULIB_PTHREAD && !defined USE_UNLOCKED_IO ++# include ++# define lock_define(name) pthread_mutex_t name; ++# define lock_init(lock) pthread_mutex_init (&(lock), 0) ++# define lock_fini(lock) pthread_mutex_destroy (&(lock)) ++# define lock_lock(lock) pthread_mutex_lock (&(lock)) ++# define lock_unlock(lock) pthread_mutex_unlock (&(lock)) ++#else ++# define lock_define(name) ++# define lock_init(lock) 0 ++# define lock_fini(lock) ((void) 0) ++ /* The 'dfa' avoids an "unused variable 'dfa'" warning from GCC. */ ++# define lock_lock(lock) ((void) dfa) ++# define lock_unlock(lock) ((void) 0) ++#endif ++ ++/* In case that the system doesn't have isblank(). */ ++#if !defined _LIBC && ! (defined isblank || (HAVE_ISBLANK && HAVE_DECL_ISBLANK)) ++# define isblank(ch) ((ch) == ' ' || (ch) == '\t') ++#endif ++ ++ ++# undef gettext ++# define gettext(msgid) (msgid) ++ ++ ++#ifndef gettext_noop ++/* This define is so xgettext can find the internationalizable ++ strings. */ ++# define gettext_noop(String) String ++#endif ++ ++/* Number of ASCII characters. */ ++#define ASCII_CHARS 0x80 ++ ++/* Number of single byte characters. */ ++#define SBC_MAX (UCHAR_MAX + 1) ++ ++#define COLL_ELEM_LEN_MAX 8 ++ ++/* The character which represents newline. */ ++#define NEWLINE_CHAR '\n' ++#define WIDE_NEWLINE_CHAR L'\n' ++ ++/* Rename to standard API for using out of glibc. */ ++#ifndef _LIBC ++# undef __wctype ++# undef __iswalnum ++# undef __iswctype ++# undef __towlower ++# undef __towupper ++# define __wctype wctype ++# define __iswalnum iswalnum ++# define __iswctype iswctype ++# define __towlower towlower ++# define __towupper towupper ++# define __btowc btowc ++# define __mbrtowc mbrtowc ++# define __wcrtomb wcrtomb ++# define __regfree regfree ++# define attribute_hidden ++#endif /* not _LIBC */ ++ ++#if __GNUC__ < 3 + (__GNUC_MINOR__ < 1) ++# define __attribute__(arg) ++#endif ++ ++#ifndef SSIZE_MAX ++# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) ++#endif ++ ++/* The type of indexes into strings. This is signed, not size_t, ++ since the API requires indexes to fit in regoff_t anyway, and using ++ signed integers makes the code a bit smaller and presumably faster. ++ The traditional GNU regex implementation uses int for indexes. ++ The POSIX-compatible implementation uses a possibly-wider type. ++ The name 'Idx' is three letters to minimize the hassle of ++ reindenting a lot of regex code that formerly used 'int'. */ ++typedef regoff_t Idx; ++#ifdef _REGEX_LARGE_OFFSETS ++# define IDX_MAX SSIZE_MAX ++#else ++# define IDX_MAX INT_MAX ++#endif ++ ++#ifdef _REGEX_LARGE_OFFSETS ++ ++/* Use types and values that are wide enough to represent signed and ++ unsigned byte offsets in memory. This currently works only when ++ the regex code is used outside of the GNU C library; it is not yet ++ supported within glibc itself, and glibc users should not define ++ _REGEX_LARGE_OFFSETS. */ ++ ++/* The type of object sizes. */ ++typedef size_t __re_size_t; ++ ++/* The type of object sizes, in places where the traditional code ++ uses unsigned long int. */ ++typedef size_t __re_long_size_t; ++ ++#else ++ ++/* The traditional GNU regex implementation mishandles strings longer ++ than INT_MAX. */ ++typedef unsigned int __re_size_t; ++typedef unsigned long int __re_long_size_t; ++ ++#endif ++ ++#ifndef RE_TRANSLATE_TYPE ++# define __RE_TRANSLATE_TYPE unsigned char * ++# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE ++#endif ++ ++/* The following bits are used to determine the regexp syntax we ++ recognize. The set/not-set meanings are chosen so that Emacs syntax ++ remains the value 0. The bits are given in alphabetical order, and ++ the definitions shifted by one from the previous bit; thus, when we ++ add or remove a bit, only one other definition need change. */ ++typedef unsigned long int reg_syntax_t; ++ ++/* A hash value, suitable for computing hash tables. */ ++typedef __re_size_t re_hashval_t; ++ ++/* An integer used to represent a set of bits. It must be unsigned, ++ and must be at least as wide as unsigned int. */ ++typedef unsigned long int bitset_word_t; ++/* All bits set in a bitset_word_t. */ ++#define BITSET_WORD_MAX ULONG_MAX ++ ++/* Number of bits in a bitset_word_t. For portability to hosts with ++ padding bits, do not use '(sizeof (bitset_word_t) * CHAR_BIT)'; ++ instead, deduce it directly from BITSET_WORD_MAX. Avoid ++ greater-than-32-bit integers and unconditional shifts by more than ++ 31 bits, as they're not portable. */ ++#if BITSET_WORD_MAX == 0xffffffffUL ++# define BITSET_WORD_BITS 32 ++#elif BITSET_WORD_MAX >> 31 >> 4 == 1 ++# define BITSET_WORD_BITS 36 ++#elif BITSET_WORD_MAX >> 31 >> 16 == 1 ++# define BITSET_WORD_BITS 48 ++#elif BITSET_WORD_MAX >> 31 >> 28 == 1 ++# define BITSET_WORD_BITS 60 ++#elif BITSET_WORD_MAX >> 31 >> 31 >> 1 == 1 ++# define BITSET_WORD_BITS 64 ++#elif BITSET_WORD_MAX >> 31 >> 31 >> 9 == 1 ++# define BITSET_WORD_BITS 72 ++#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 3 == 1 ++# define BITSET_WORD_BITS 128 ++#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 == 1 ++# define BITSET_WORD_BITS 256 ++#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 > 1 ++# define BITSET_WORD_BITS 257 /* any value > SBC_MAX will do here */ ++# if BITSET_WORD_BITS <= SBC_MAX ++# error "Invalid SBC_MAX" ++# endif ++#else ++# error "Add case for new bitset_word_t size" ++#endif ++ ++/* Number of bitset_word_t values in a bitset_t. */ ++#define BITSET_WORDS ((SBC_MAX + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS) ++ ++typedef bitset_word_t bitset_t[BITSET_WORDS]; ++typedef bitset_word_t *re_bitset_ptr_t; ++typedef const bitset_word_t *re_const_bitset_ptr_t; ++ ++#define PREV_WORD_CONSTRAINT 0x0001 ++#define PREV_NOTWORD_CONSTRAINT 0x0002 ++#define NEXT_WORD_CONSTRAINT 0x0004 ++#define NEXT_NOTWORD_CONSTRAINT 0x0008 ++#define PREV_NEWLINE_CONSTRAINT 0x0010 ++#define NEXT_NEWLINE_CONSTRAINT 0x0020 ++#define PREV_BEGBUF_CONSTRAINT 0x0040 ++#define NEXT_ENDBUF_CONSTRAINT 0x0080 ++#define WORD_DELIM_CONSTRAINT 0x0100 ++#define NOT_WORD_DELIM_CONSTRAINT 0x0200 ++ ++typedef enum ++{ ++ INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, ++ WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, ++ WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, ++ INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, ++ LINE_FIRST = PREV_NEWLINE_CONSTRAINT, ++ LINE_LAST = NEXT_NEWLINE_CONSTRAINT, ++ BUF_FIRST = PREV_BEGBUF_CONSTRAINT, ++ BUF_LAST = NEXT_ENDBUF_CONSTRAINT, ++ WORD_DELIM = WORD_DELIM_CONSTRAINT, ++ NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT ++} re_context_type; ++ ++typedef struct ++{ ++ Idx alloc; ++ Idx nelem; ++ Idx *elems; ++} re_node_set; ++ ++typedef enum ++{ ++ NON_TYPE = 0, ++ ++ /* Node type, These are used by token, node, tree. */ ++ CHARACTER = 1, ++ END_OF_RE = 2, ++ SIMPLE_BRACKET = 3, ++ OP_BACK_REF = 4, ++ OP_PERIOD = 5, ++ ++ /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used ++ when the debugger shows values of this enum type. */ ++#define EPSILON_BIT 8 ++ OP_OPEN_SUBEXP = EPSILON_BIT | 0, ++ OP_CLOSE_SUBEXP = EPSILON_BIT | 1, ++ OP_ALT = EPSILON_BIT | 2, ++ OP_DUP_ASTERISK = EPSILON_BIT | 3, ++ ANCHOR = EPSILON_BIT | 4, ++ ++ /* Tree type, these are used only by tree. */ ++ CONCAT = 16, ++ SUBEXP = 17, ++ ++ /* Token type, these are used only by token. */ ++ OP_DUP_PLUS = 18, ++ OP_DUP_QUESTION, ++ OP_OPEN_BRACKET, ++ OP_CLOSE_BRACKET, ++ OP_CHARSET_RANGE, ++ OP_OPEN_DUP_NUM, ++ OP_CLOSE_DUP_NUM, ++ OP_NON_MATCH_LIST, ++ OP_OPEN_COLL_ELEM, ++ OP_CLOSE_COLL_ELEM, ++ OP_OPEN_EQUIV_CLASS, ++ OP_CLOSE_EQUIV_CLASS, ++ OP_OPEN_CHAR_CLASS, ++ OP_CLOSE_CHAR_CLASS, ++ OP_WORD, ++ OP_NOTWORD, ++ OP_SPACE, ++ OP_NOTSPACE, ++ BACK_SLASH ++ ++} re_token_type_t; ++ ++typedef struct ++{ ++ union ++ { ++ unsigned char c; /* for CHARACTER */ ++ re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ ++ Idx idx; /* for BACK_REF */ ++ re_context_type ctx_type; /* for ANCHOR */ ++ } opr; ++#if __GNUC__ >= 2 && !defined __STRICT_ANSI__ ++ re_token_type_t type : 8; ++#else ++ re_token_type_t type; ++#endif ++ unsigned int constraint : 10; /* context constraint */ ++ unsigned int duplicated : 1; ++ unsigned int opt_subexp : 1; ++ unsigned int word_char : 1; ++} re_token_t; ++ ++#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT) ++ ++struct re_string_t ++{ ++ /* Indicate the raw buffer which is the original string passed as an ++ argument of regexec(), re_search(), etc.. */ ++ const unsigned char *raw_mbs; ++ /* Store the multibyte string. In case of "case insensitive mode" like ++ REG_ICASE, upper cases of the string are stored, otherwise MBS points ++ the same address that RAW_MBS points. */ ++ unsigned char *mbs; ++ /* Index in RAW_MBS. Each character mbs[i] corresponds to ++ raw_mbs[raw_mbs_idx + i]. */ ++ Idx raw_mbs_idx; ++ /* The length of the valid characters in the buffers. */ ++ Idx valid_len; ++ /* The corresponding number of bytes in raw_mbs array. */ ++ Idx valid_raw_len; ++ /* The length of the buffers MBS and WCS. */ ++ Idx bufs_len; ++ /* The index in MBS, which is updated by re_string_fetch_byte. */ ++ Idx cur_idx; ++ /* length of RAW_MBS array. */ ++ Idx raw_len; ++ /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */ ++ Idx len; ++ /* End of the buffer may be shorter than its length in the cases such ++ as re_match_2, re_search_2. Then, we use STOP for end of the buffer ++ instead of LEN. */ ++ Idx raw_stop; ++ /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */ ++ Idx stop; ++ ++ /* The context of mbs[0]. We store the context independently, since ++ the context of mbs[0] may be different from raw_mbs[0], which is ++ the beginning of the input string. */ ++ unsigned int tip_context; ++ /* The translation passed as a part of an argument of re_compile_pattern. */ ++ RE_TRANSLATE_TYPE trans; ++ /* Copy of re_dfa_t's word_char. */ ++ re_const_bitset_ptr_t word_char; ++ /* true if REG_ICASE. */ ++ unsigned char icase; ++ unsigned char is_utf8; ++ unsigned char map_notascii; ++ unsigned char mbs_allocated; ++ unsigned char offsets_needed; ++ unsigned char newline_anchor; ++ unsigned char word_ops_used; ++ int mb_cur_max; ++}; ++typedef struct re_string_t re_string_t; ++ ++ ++struct re_dfa_t; ++typedef struct re_dfa_t re_dfa_t; ++ ++# define IS_IN(libc) false ++ ++ ++#define re_string_peek_byte(pstr, offset) \ ++ ((pstr)->mbs[(pstr)->cur_idx + offset]) ++#define re_string_fetch_byte(pstr) \ ++ ((pstr)->mbs[(pstr)->cur_idx++]) ++#define re_string_first_byte(pstr, idx) \ ++ ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF) ++#define re_string_is_single_byte_char(pstr, idx) \ ++ ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \ ++ || (pstr)->wcs[(idx) + 1] != WEOF)) ++#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) ++#define re_string_cur_idx(pstr) ((pstr)->cur_idx) ++#define re_string_get_buffer(pstr) ((pstr)->mbs) ++#define re_string_length(pstr) ((pstr)->len) ++#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) ++#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) ++#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) ++ ++#if HAVE_ALLOCA ++# include ++#endif ++ ++# if HAVE_ALLOCA ++/* The OS usually guarantees only one guard page at the bottom of the stack, ++ and a page size can be as small as 4096 bytes. So we cannot safely ++ allocate anything larger than 4096 bytes. Also care for the possibility ++ of a few compiler-allocated temporary stack slots. */ ++# define __libc_use_alloca(n) ((n) < 4032) ++# else ++/* alloca is implemented with malloc, so just use malloc. */ ++# define __libc_use_alloca(n) 0 ++# undef alloca ++# define alloca(n) malloc (n) ++# endif ++ ++ ++#if !defined MALLOC_0_IS_NONNULL ++# define MALLOC_0_IS_NONNULL 0 ++#endif ++ ++#ifndef MAX ++# define MAX(a,b) ((a) < (b) ? (b) : (a)) ++#endif ++#ifndef MIN ++# define MIN(a,b) ((a) < (b) ? (a) : (b)) ++#endif ++ ++#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) ++#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) ++#define re_free(p) free (p) ++ ++struct bin_tree_t ++{ ++ struct bin_tree_t *parent; ++ struct bin_tree_t *left; ++ struct bin_tree_t *right; ++ struct bin_tree_t *first; ++ struct bin_tree_t *next; ++ ++ re_token_t token; ++ ++ /* 'node_idx' is the index in dfa->nodes, if 'type' == 0. ++ Otherwise 'type' indicate the type of this node. */ ++ Idx node_idx; ++}; ++typedef struct bin_tree_t bin_tree_t; ++ ++#define BIN_TREE_STORAGE_SIZE \ ++ ((1024 - sizeof (void *)) / sizeof (bin_tree_t)) ++ ++struct bin_tree_storage_t ++{ ++ struct bin_tree_storage_t *next; ++ bin_tree_t data[BIN_TREE_STORAGE_SIZE]; ++}; ++typedef struct bin_tree_storage_t bin_tree_storage_t; ++ ++#define CONTEXT_WORD 1 ++#define CONTEXT_NEWLINE (CONTEXT_WORD << 1) ++#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) ++#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) ++ ++#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) ++#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) ++#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) ++#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) ++#define IS_ORDINARY_CONTEXT(c) ((c) == 0) ++ ++#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') ++#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) ++#define IS_WIDE_WORD_CHAR(ch) (__iswalnum (ch) || (ch) == L'_') ++#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR) ++ ++#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ ++ ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ ++ || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ ++ || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ ++ || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) ++ ++#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ ++ ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ ++ || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ ++ || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ ++ || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) ++ ++struct re_dfastate_t ++{ ++ re_hashval_t hash; ++ re_node_set nodes; ++ re_node_set non_eps_nodes; ++ re_node_set inveclosure; ++ re_node_set *entrance_nodes; ++ struct re_dfastate_t **trtable, **word_trtable; ++ unsigned int context : 4; ++ unsigned int halt : 1; ++ /* If this state can accept "multi byte". ++ Note that we refer to multibyte characters, and multi character ++ collating elements as "multi byte". */ ++ unsigned int accept_mb : 1; ++ /* If this state has backreference node(s). */ ++ unsigned int has_backref : 1; ++ unsigned int has_constraint : 1; ++}; ++typedef struct re_dfastate_t re_dfastate_t; ++ ++struct re_state_table_entry ++{ ++ Idx num; ++ Idx alloc; ++ re_dfastate_t **array; ++}; ++ ++/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ ++ ++typedef struct ++{ ++ Idx next_idx; ++ Idx alloc; ++ re_dfastate_t **array; ++} state_array_t; ++ ++/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */ ++ ++typedef struct ++{ ++ Idx node; ++ Idx str_idx; /* The position NODE match at. */ ++ state_array_t path; ++} re_sub_match_last_t; ++ ++/* Store information about the node NODE whose type is OP_OPEN_SUBEXP. ++ And information about the node, whose type is OP_CLOSE_SUBEXP, ++ corresponding to NODE is stored in LASTS. */ ++ ++typedef struct ++{ ++ Idx str_idx; ++ Idx node; ++ state_array_t *path; ++ Idx alasts; /* Allocation size of LASTS. */ ++ Idx nlasts; /* The number of LASTS. */ ++ re_sub_match_last_t **lasts; ++} re_sub_match_top_t; ++ ++struct re_backref_cache_entry ++{ ++ Idx node; ++ Idx str_idx; ++ Idx subexp_from; ++ Idx subexp_to; ++ char more; ++ char unused; ++ unsigned short int eps_reachable_subexps_map; ++}; ++ ++typedef struct ++{ ++ /* The string object corresponding to the input string. */ ++ re_string_t input; ++ const re_dfa_t *dfa; ++ /* EFLAGS of the argument of regexec. */ ++ int eflags; ++ /* Where the matching ends. */ ++ Idx match_last; ++ Idx last_node; ++ /* The state log used by the matcher. */ ++ re_dfastate_t **state_log; ++ Idx state_log_top; ++ /* Back reference cache. */ ++ Idx nbkref_ents; ++ Idx abkref_ents; ++ struct re_backref_cache_entry *bkref_ents; ++ int max_mb_elem_len; ++ Idx nsub_tops; ++ Idx asub_tops; ++ re_sub_match_top_t **sub_tops; ++} re_match_context_t; ++ ++typedef struct ++{ ++ re_dfastate_t **sifted_states; ++ re_dfastate_t **limited_states; ++ Idx last_node; ++ Idx last_str_idx; ++ re_node_set limits; ++} re_sift_context_t; ++ ++struct re_fail_stack_ent_t ++{ ++ Idx idx; ++ Idx node; ++ regmatch_t *regs; ++ re_node_set eps_via_nodes; ++}; ++ ++struct re_fail_stack_t ++{ ++ Idx num; ++ Idx alloc; ++ struct re_fail_stack_ent_t *stack; ++}; ++ ++struct re_dfa_t ++{ ++ re_token_t *nodes; ++ size_t nodes_alloc; ++ size_t nodes_len; ++ Idx *nexts; ++ Idx *org_indices; ++ re_node_set *edests; ++ re_node_set *eclosures; ++ re_node_set *inveclosures; ++ struct re_state_table_entry *state_table; ++ re_dfastate_t *init_state; ++ re_dfastate_t *init_state_word; ++ re_dfastate_t *init_state_nl; ++ re_dfastate_t *init_state_begbuf; ++ bin_tree_t *str_tree; ++ bin_tree_storage_t *str_tree_storage; ++ re_bitset_ptr_t sb_char; ++ int str_tree_storage_idx; ++ ++ /* number of subexpressions 're_nsub' is in regex_t. */ ++ re_hashval_t state_hash_mask; ++ Idx init_node; ++ Idx nbackref; /* The number of backreference in this dfa. */ ++ ++ /* Bitmap expressing which backreference is used. */ ++ bitset_word_t used_bkref_map; ++ bitset_word_t completed_bkref_map; ++ ++ unsigned int has_plural_match : 1; ++ /* If this dfa has "multibyte node", which is a backreference or ++ a node which can accept multibyte character or multi character ++ collating element. */ ++ unsigned int has_mb_node : 1; ++ unsigned int is_utf8 : 1; ++ unsigned int map_notascii : 1; ++ unsigned int word_ops_used : 1; ++ int mb_cur_max; ++ bitset_t word_char; ++ reg_syntax_t syntax; ++ Idx *subexp_map; ++ lock_define (lock) ++}; ++ ++#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) ++#define re_node_set_remove(set,id) \ ++ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) ++#define re_node_set_empty(p) ((p)->nelem = 0) ++#define re_node_set_free(set) re_free ((set)->elems) ++ ++ ++typedef enum ++{ ++ SB_CHAR, ++ MB_CHAR, ++ EQUIV_CLASS, ++ COLL_SYM, ++ CHAR_CLASS ++} bracket_elem_type; ++ ++typedef struct ++{ ++ bracket_elem_type type; ++ union ++ { ++ unsigned char ch; ++ unsigned char *name; ++ wchar_t wch; ++ } opr; ++} bracket_elem_t; ++ ++ ++/* Functions for bitset_t operation. */ ++ ++static inline void ++bitset_set (bitset_t set, Idx i) ++{ ++ set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS; ++} ++ ++static inline void ++bitset_clear (bitset_t set, Idx i) ++{ ++ set[i / BITSET_WORD_BITS] &= ~ ((bitset_word_t) 1 << i % BITSET_WORD_BITS); ++} ++ ++static inline bool ++bitset_contain (const bitset_t set, Idx i) ++{ ++ return (set[i / BITSET_WORD_BITS] >> i % BITSET_WORD_BITS) & 1; ++} ++ ++static inline void ++bitset_empty (bitset_t set) ++{ ++ memset (set, '\0', sizeof (bitset_t)); ++} ++ ++static inline void ++bitset_set_all (bitset_t set) ++{ ++ memset (set, -1, sizeof (bitset_word_t) * (SBC_MAX / BITSET_WORD_BITS)); ++ if (SBC_MAX % BITSET_WORD_BITS != 0) ++ set[BITSET_WORDS - 1] = ++ ((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1; ++} ++ ++static inline void ++bitset_copy (bitset_t dest, const bitset_t src) ++{ ++ memcpy (dest, src, sizeof (bitset_t)); ++} ++ ++static inline void ++bitset_not (bitset_t set) ++{ ++ int bitset_i; ++ for (bitset_i = 0; bitset_i < SBC_MAX / BITSET_WORD_BITS; ++bitset_i) ++ set[bitset_i] = ~set[bitset_i]; ++ if (SBC_MAX % BITSET_WORD_BITS != 0) ++ set[BITSET_WORDS - 1] = ++ ((((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1) ++ & ~set[BITSET_WORDS - 1]); ++} ++ ++static inline void ++bitset_merge (bitset_t dest, const bitset_t src) ++{ ++ int bitset_i; ++ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) ++ dest[bitset_i] |= src[bitset_i]; ++} ++ ++static inline void ++bitset_mask (bitset_t dest, const bitset_t src) ++{ ++ int bitset_i; ++ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) ++ dest[bitset_i] &= src[bitset_i]; ++} ++ ++#ifndef __GNUC_PREREQ ++# if defined __GNUC__ && defined __GNUC_MINOR__ ++# define __GNUC_PREREQ(maj, min) \ ++ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) ++# else ++# define __GNUC_PREREQ(maj, min) 0 ++# endif ++#endif ++ ++#if __GNUC_PREREQ (3,4) ++# undef __attribute_warn_unused_result__ ++# define __attribute_warn_unused_result__ \ ++ __attribute__ ((__warn_unused_result__)) ++#else ++# define __attribute_warn_unused_result__ /* empty */ ++#endif ++ ++#ifndef FALLTHROUGH ++# if __GNUC__ < 7 ++# define FALLTHROUGH ((void) 0) ++# else ++# define FALLTHROUGH __attribute__ ((__fallthrough__)) ++# endif ++#endif ++ ++#endif /* _REGEX_INTERNAL_H */ +diff --git a/headers-mingw/resource.h b/headers-mingw/resource.h +new file mode 100644 +index 0000000..160aad2 +--- /dev/null ++++ b/headers-mingw/resource.h +@@ -0,0 +1,79 @@ ++/* Substitute for . ++ Copyright (C) 2012-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++#ifndef _GL_SYS_RESOURCE_H ++#define _GL_SYS_RESOURCE_H ++ ++#if !HAVE_SYS_RESOURCE_H ++/* A platform that lacks . */ ++ ++/* Get 'struct timeval'. */ ++# include ++ ++/* Define the RUSAGE_* constants. */ ++# define RUSAGE_SELF 0 ++# define RUSAGE_CHILDREN -1 ++ ++# ifdef __cplusplus ++extern "C" { ++# endif ++ ++# if !GNULIB_defined_struct_rusage ++/* All known platforms that lack also lack any declaration ++ of struct rusage in any other header. */ ++struct rusage ++{ ++ struct timeval ru_utime; /* CPU time used in user mode */ ++ struct timeval ru_stime; /* CPU time used in system mode (kernel) */ ++ long ru_maxrss; ++ long ru_ixrss; ++ long ru_idrss; ++ long ru_isrss; ++ long ru_minflt; ++ long ru_majflt; ++ long ru_nswap; ++ long ru_inblock; ++ long ru_oublock; ++ long ru_msgsnd; ++ long ru_msgrcv; ++ long ru_nsignals; ++ long ru_nvcsw; ++ long ru_nivcsw; ++}; ++# define GNULIB_defined_struct_rusage 1 ++# endif ++ ++# ifdef __cplusplus ++} ++# endif ++ ++#endif ++ ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_ARG_NONNULL is copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++ ++/* Declare overridden functions. */ ++ ++ ++#if !HAVE_GETRUSAGE ++extern int getrusage (int who, struct rusage *usage_p); ++#endif ++ ++#endif /* _@GUARD_PREFIX@_SYS_RESOURCE_H */ +diff --git a/headers-mingw/signal.h b/headers-mingw/signal.h +new file mode 100644 +index 0000000..63539a2 +--- /dev/null ++++ b/headers-mingw/signal.h +@@ -0,0 +1,264 @@ ++/* A GNU-like . ++ ++ Copyright (C) 2006-2018 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 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, see . */ ++ ++ ++ ++/* Normal invocation convention. */ ++ ++#ifndef _GL_SIGNAL_H ++#define _GL_SIGNAL_H ++ ++/* Get pid_t. */ ++#include ++ ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_ARG_NONNULL is copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++/* A set or mask of signals. */ ++#if !GNULIB_defined_sigset_t ++typedef unsigned int sigset_t; ++# define GNULIB_defined_sigset_t 1 ++#endif ++ ++ ++/* Define sighandler_t, the type of signal handlers. A GNU extension. */ ++#ifdef __cplusplus ++extern "C" { ++#endif ++#if !GNULIB_defined_sighandler_t ++typedef void (*sighandler_t) (int); ++# define GNULIB_defined_sighandler_t 1 ++#endif ++#ifdef __cplusplus ++} ++#endif ++ ++ ++ ++#ifndef SIGPIPE ++/* Define SIGPIPE to a value that does not overlap with other signals. */ ++# define SIGPIPE 13 ++# define GNULIB_defined_SIGPIPE 1 ++/* To actually use SIGPIPE, you also need the gnulib modules 'sigprocmask', ++ 'write', 'stdio'. */ ++#endif ++ ++ ++ ++/* Maximum signal number + 1. */ ++#ifndef NSIG ++# if defined __TANDEM ++# define NSIG 32 ++# endif ++#endif ++ ++ ++#if !(HAVE_PTHREAD_SIGMASK || defined pthread_sigmask) ++extern int pthread_sigmask(int how, const sigset_t *new_mask, sigset_t *old_mask); ++#endif ++ ++ ++#if !HAVE_RAISE ++extern int raise(int sig); ++#endif ++ ++ ++#ifndef GNULIB_defined_signal_blocking ++# define GNULIB_defined_signal_blocking 1 ++#endif ++ ++/* Maximum signal number + 1. */ ++#ifndef NSIG ++# define NSIG 32 ++#endif ++ ++/* This code supports only 32 signals. */ ++#if !GNULIB_defined_verify_NSIG_constraint ++typedef int verify_NSIG_constraint[NSIG <= 32 ? 1 : -1]; ++# define GNULIB_defined_verify_NSIG_constraint 1 ++#endif ++ ++ ++/* When also using extern inline, suppress the use of static inline in ++ standard headers of problematic Apple configurations, as Libc at ++ least through Libc-825.26 (2013-04-09) mishandles it; see, e.g., ++ . ++ Perhaps Apple will fix this some day. */ ++#if (defined _GL_EXTERN_INLINE_IN_USE && defined __APPLE__ \ ++ && (defined __i386__ || defined __x86_64__)) ++# undef sigaddset ++# undef sigdelset ++# undef sigemptyset ++# undef sigfillset ++# undef sigismember ++#endif ++ ++/* Test whether a given signal is contained in a signal set. */ ++#if !HAVE_SIGISMEMBER ++extern int sigismember(const sigset_t *set, int sig); ++# endif ++ ++/* Initialize a signal set to the empty set. */ ++#if !HAVE_SIGEMPTYSET ++extern int sigemptyset(sigset_t *set); ++#endif ++ ++ ++/* Add a signal to a signal set. */ ++#if !HAVE_SIGADDSET ++extern int sigaddset(sigset_t *set, int sig); ++#endif ++ ++ ++/* Remove a signal from a signal set. */ ++#if !HAVE_SIGDELSET ++extern int sigdelset(sigset_t *set, int sig); ++# endif ++ ++/* Fill a signal set with all possible signals. */ ++#if !HAVE_SIGFILLSET ++extern int sigfillset(sigset_t *set); ++#endif ++ ++ ++/* Return the set of those blocked signals that are pending. */ ++#if !HAVE_SIGPENDING ++extern int sigpending(sigset_t *set); ++#endif ++ ++/* If OLD_SET is not NULL, put the current set of blocked signals in *OLD_SET. ++ Then, if SET is not NULL, affect the current set of blocked signals by ++ combining it with *SET as indicated in OPERATION. ++ In this implementation, you are not allowed to change a signal handler ++ while the signal is blocked. */ ++#ifndef SIG_BLOCK ++# define SIG_BLOCK 0 /* blocked_set = blocked_set | *set; */ ++#endif ++#ifndef SIG_SETMASK ++# define SIG_SETMASK 1 /* blocked_set = *set; */ ++#endif ++#ifndef SIG_UNBLOCK ++# define SIG_UNBLOCK 2 /* blocked_set = blocked_set & ~*set; */ ++#endif ++#if !HAVE_SIGPROCMASK ++extern int sigprocmask(int operation, const sigset_t *set, sigset_t *old_set); ++# endif ++ ++/* Install the handler FUNC for signal SIG, and return the previous ++ handler. */ ++#ifdef __cplusplus ++extern "C" { ++#endif ++#if !GNULIB_defined_function_taking_int_returning_void_t ++typedef void (*_gl_function_taking_int_returning_void_t) (int); ++# define GNULIB_defined_function_taking_int_returning_void_t 1 ++#endif ++#ifdef __cplusplus ++} ++#endif ++#if !HAVE_SIGNAL ++extern _gl_function_taking_int_returning_void_t signal(int sig, _gl_function_taking_int_returning_void_t func); ++#endif ++ ++ ++extern int _gl_raise_SIGPIPE (void); ++ ++#if !HAVE_SIGACTION ++# if !GNULIB_defined_siginfo_types ++ ++/* Present to allow compilation, but unsupported by gnulib. */ ++union sigval ++{ ++ int sival_int; ++ void *sival_ptr; ++}; ++ ++/* Present to allow compilation, but unsupported by gnulib. */ ++struct siginfo_t ++{ ++ int si_signo; ++ int si_code; ++ int si_errno; ++ pid_t si_pid; ++ int si_uid; ++ void *si_addr; ++ int si_status; ++ long si_band; ++ union sigval si_value; ++}; ++typedef struct siginfo_t siginfo_t; ++ ++# define GNULIB_defined_siginfo_types 1 ++# endif ++ ++ ++/* We assume that platforms which lack the sigaction() function also lack ++ the 'struct sigaction' type, and vice versa. */ ++ ++# if !GNULIB_defined_struct_sigaction ++ ++struct sigaction ++{ ++ union ++ { ++ void (*_sa_handler) (int); ++ /* Present to allow compilation, but unsupported by gnulib. POSIX ++ says that implementations may, but not must, make sa_sigaction ++ overlap with sa_handler, but we know of no implementation where ++ they do not overlap. */ ++ void (*_sa_sigaction) (int, siginfo_t *, void *); ++ } _sa_func; ++ sigset_t sa_mask; ++ /* Not all POSIX flags are supported. */ ++ int sa_flags; ++}; ++# define sa_handler _sa_func._sa_handler ++# define sa_sigaction _sa_func._sa_sigaction ++/* Unsupported flags are not present. */ ++# define SA_RESETHAND 1 ++# define SA_NODEFER 2 ++# define SA_RESTART 4 ++ ++# define GNULIB_defined_struct_sigaction 1 ++# endif ++ ++extern int sigaction(int, const struct sigaction *restrict, ++ struct sigaction *restrict); ++#endif ++ ++/* Some systems don't have SA_NODEFER. */ ++#ifndef SA_NODEFER ++# define SA_NODEFER 0 ++#endif ++ ++/* Out-of-range substitutes make a good fallback for uncatchable ++ signals. */ ++#ifndef SIGKILL ++# define SIGKILL (-1) ++#endif ++#ifndef SIGSTOP ++# define SIGSTOP (-1) ++#endif ++ ++#if !defined(HAVE_KILL) ++extern int kill(pid_t pid, int sig); ++#endif ++ ++#endif /* _@GUARD_PREFIX@_SIGNAL_H */ +diff --git a/headers-mingw/stdlib.h b/headers-mingw/stdlib.h +new file mode 100644 +index 0000000..55a0e5b +--- /dev/null ++++ b/headers-mingw/stdlib.h +@@ -0,0 +1,344 @@ ++/* A GNU-like . ++ ++ Copyright (C) 1995, 2001-2004, 2006-2018 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 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, see . */ ++ ++/* Normal invocation convention. */ ++ ++#ifndef _GL_STDLIB_H ++ ++#define _GL_STDLIB_H ++ ++/* Native Windows platforms declare mktemp() in . */ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++# include ++#endif ++ ++/* OSF/1 5.1 declares 'struct random_data' in , which is included ++ from if _REENTRANT is defined. Include it whenever we need ++ 'struct random_data'. */ ++#if HAVE_RANDOM_H ++# include ++#endif ++ ++#if !HAVE_RANDOM_R ++# include ++#endif ++ ++/* Define 'struct random_data'. ++ But allow multiple gnulib generated replacements to coexist. */ ++#if !GNULIB_defined_struct_random_data ++typedef struct random_data ++{ ++ int *fptr; /* Front pointer. */ ++ int *rptr; /* Rear pointer. */ ++ int *state; /* Array of state values. */ ++ int rand_type; /* Type of random number generator. */ ++ int rand_deg; /* Degree of random number generator. */ ++ int rand_sep; /* Distance between front and rear. */ ++ int *end_ptr; /* Pointer behind state table. */ ++}; ++# define GNULIB_defined_struct_random_data 1 ++#endif ++ ++/* The __attribute__ feature is available in gcc versions 2.5 and later. ++ The attribute __pure__ was added in gcc 2.96. */ ++#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) ++# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) ++#else ++# define _GL_ATTRIBUTE_PURE /* empty */ ++#endif ++ ++/* The definition of _Noreturn is copied here. */ ++ ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_ARG_NONNULL is copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++ ++/* Some systems do not define EXIT_*, despite otherwise supporting C89. */ ++#ifndef EXIT_SUCCESS ++# define EXIT_SUCCESS 0 ++#endif ++/* Tandem/NSK and other platforms that define EXIT_FAILURE as -1 interfere ++ with proper operation of xargs. */ ++#ifndef EXIT_FAILURE ++# define EXIT_FAILURE 1 ++#elif EXIT_FAILURE != 1 ++# undef EXIT_FAILURE ++# define EXIT_FAILURE 1 ++#endif ++ ++ ++/* Terminate the current process with the given return code, without running ++ the 'atexit' handlers. */ ++#if !HAVE__EXIT ++extern void _Exit(int status); ++#endif ++ ++/* Parse a signed decimal integer. ++ Returns the value of the integer. Errors are not detected. */ ++#if !HAVE_ATOLL ++extern long long atoll(const char *string); ++#endif ++ ++#if !HAVE_CANONICALIZE_FILE_NAME ++extern char * canonicalize_file_name(const char *name); ++#endif ++ ++/* Store max(NELEM,3) load average numbers in LOADAVG[]. ++ The three numbers are the load average of the last 1 minute, the last 5 ++ minutes, and the last 15 minutes, respectively. ++ LOADAVG is an array of NELEM numbers. */ ++#if !HAVE_GETLOADAVG ++extern int getloadavg(double loadavg[], int nelem); ++#endif ++ ++ ++/* Assuming *OPTIONP is a comma separated list of elements of the form ++ "token" or "token=value", getsubopt parses the first of these elements. ++ If the first element refers to a "token" that is member of the given ++ NULL-terminated array of tokens: ++ - It replaces the comma with a NUL byte, updates *OPTIONP to point past ++ the first option and the comma, sets *VALUEP to the value of the ++ element (or NULL if it doesn't contain an "=" sign), ++ - It returns the index of the "token" in the given array of tokens. ++ Otherwise it returns -1, and *OPTIONP and *VALUEP are undefined. ++ For more details see the POSIX:2001 specification. ++ http://www.opengroup.org/susv3xsh/getsubopt.html */ ++#if !HAVE_GETSUBOPT ++extern int getsubopt(char **optionp, char *const *tokens, char **valuep); ++#endif ++ ++ ++/* Change the ownership and access permission of the slave side of the ++ pseudo-terminal whose master side is specified by FD. */ ++#if !HAVE_GRANTPT ++extern int grantpt(int fd); ++#endif ++ ++ ++/* Create a unique temporary directory from TEMPLATE. ++ The last six characters of TEMPLATE must be "XXXXXX"; ++ they are replaced with a string that makes the directory name unique. ++ Returns TEMPLATE, or a null pointer if it cannot get a unique name. ++ The directory is created mode 700. */ ++#if !HAVE_MKDTEMP ++extern char * mkdtemp(char *template); ++#endif ++ ++/* Create a unique temporary file from TEMPLATE. ++ The last six characters of TEMPLATE must be "XXXXXX"; ++ they are replaced with a string that makes the file name unique. ++ The flags are a bitmask, possibly including O_CLOEXEC (defined in ) ++ and O_TEXT, O_BINARY (defined in "binary-io.h"). ++ The file is then created, with the specified flags, ensuring it didn't exist ++ before. ++ The file is created read-write (mask at least 0600 & ~umask), but it may be ++ world-readable and world-writable (mask 0666 & ~umask), depending on the ++ implementation. ++ Returns the open file descriptor if successful, otherwise -1 and errno ++ set. */ ++#if !HAVE_MKOSTEMP ++extern int mkostemp(char *template, int flags); ++#endif ++ ++/* Create a unique temporary file from TEMPLATE. ++ The last six characters of TEMPLATE before a suffix of length ++ SUFFIXLEN must be "XXXXXX"; ++ they are replaced with a string that makes the file name unique. ++ The flags are a bitmask, possibly including O_CLOEXEC (defined in ) ++ and O_TEXT, O_BINARY (defined in "binary-io.h"). ++ The file is then created, with the specified flags, ensuring it didn't exist ++ before. ++ The file is created read-write (mask at least 0600 & ~umask), but it may be ++ world-readable and world-writable (mask 0666 & ~umask), depending on the ++ implementation. ++ Returns the open file descriptor if successful, otherwise -1 and errno ++ set. */ ++#if !HAVE_MKOSTEMPS ++extern int mkostemps(char * template, int suffixlen, int flags); ++#endif ++ ++ ++/* Create a unique temporary file from TEMPLATE. ++ The last six characters of TEMPLATE must be "XXXXXX"; ++ they are replaced with a string that makes the file name unique. ++ The file is then created, ensuring it didn't exist before. ++ The file is created read-write (mask at least 0600 & ~umask), but it may be ++ world-readable and world-writable (mask 0666 & ~umask), depending on the ++ implementation. ++ Returns the open file descriptor if successful, otherwise -1 and errno ++ set. */ ++#if !HAVE_MKSTEMP ++extern int mkstemp(char * template); ++#endif ++ ++ ++/* Create a unique temporary file from TEMPLATE. ++ The last six characters of TEMPLATE prior to a suffix of length ++ SUFFIXLEN must be "XXXXXX"; ++ they are replaced with a string that makes the file name unique. ++ The file is then created, ensuring it didn't exist before. ++ The file is created read-write (mask at least 0600 & ~umask), but it may be ++ world-readable and world-writable (mask 0666 & ~umask), depending on the ++ implementation. ++ Returns the open file descriptor if successful, otherwise -1 and errno ++ set. */ ++#if !HAVE_MKSTEMPS ++extern int mkstemps(char * template, int suffixlen); ++#endif ++ ++ ++/* Return an FD open to the master side of a pseudo-terminal. Flags should ++ include O_RDWR, and may also include O_NOCTTY. */ ++# if !HAVE_POSIX_OPENPT ++extern int posix_openpt(int flags); ++#endif ++ ++/* Return the pathname of the pseudo-terminal slave associated with ++ the master FD is open on, or NULL on errors. */ ++#if !HAVE_PTSNAME ++extern char * ptsname(int fd); ++#endif ++ ++ ++/* Set the pathname of the pseudo-terminal slave associated with ++ the master FD is open on and return 0, or set errno and return ++ non-zero on errors. */ ++#if !HAVE_PTSNAME_R ++extern int ptsname_r(int fd, char *buf, size_t len); ++#endif ++ ++/* Sort an array of NMEMB elements, starting at address BASE, each element ++ occupying SIZE bytes, in ascending order according to the comparison ++ function COMPARE. */ ++#if !HAVE_QSORT_R ++extern void qsort_r(void *base, size_t nmemb, size_t size, ++ int (*compare) (void const *, void const *, ++ void *), ++ void *arg); ++#endif ++ ++#ifndef RAND_MAX ++# define RAND_MAX 2147483647 ++#endif ++ ++#if !HAVE_RANDOM ++extern long random(void); ++#endif ++ ++#if !HAVE_SRANDOM ++extern void srandom(unsigned int seed); ++#endif ++ ++ ++#if !HAVE_INITSTATE ++extern char * initstate(unsigned int seed, char *buf, size_t buf_size); ++#endif ++ ++#if !HAVE_SETSTATE ++extern char * setstate(char *arg_state); ++#endif ++ ++ ++#if !HAVE_RANDOM_R ++extern int random_r(struct random_data *buf, int *result); ++#endif ++ ++# if !HAVE_SRANDOM_R ++extern int srandom_r(unsigned int seed, struct random_data *rand_state); ++#endif ++ ++#if !HAVE_INITSTATE_R ++extern int initstate_r(unsigned int seed, char *buf, size_t buf_size, ++ struct random_data *rand_state); ++#endif ++ ++#if !HAVE_SETSTATE_R ++extern int setstate_r(char *arg_state, struct random_data *rand_state); ++#endif ++ ++#if !HAVE_REALLOCARRAY ++extern void * reallocarray(void *ptr, size_t nmemb, size_t size); ++#endif ++ ++#if !HAVE_REALPATH ++extern char * realpath(const char *name, char *resolved); ++#endif ++ ++/* Test a user response to a question. ++ Return 1 if it is affirmative, 0 if it is negative, or -1 if not clear. */ ++#if !HAVE_RPMATCH ++extern int rpmatch(const char *response); ++#endif ++ ++/* Look up NAME in the environment, returning 0 in insecure situations. */ ++#if !HAVE_SECURE_GETENV ++extern char * secure_getenv(char const *name); ++#endif ++ ++ ++/* Set NAME to VALUE in the environment. ++ If REPLACE is nonzero, overwrite an existing value. */ ++#if !HAVE_SETENV ++extern int setenv(const char *name, const char *value, int replace); ++#endif ++ ++/* Parse a double from STRING, updating ENDP if appropriate. */ ++#if !HAVE_STRTOD ++extern double strtod(const char *str, char **endp); ++#endif ++ ++/* Parse a signed integer whose textual representation starts at STRING. ++ The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0, ++ it may be decimal or octal (with prefix "0") or hexadecimal (with prefix ++ "0x"). ++ If ENDPTR is not NULL, the address of the first byte after the integer is ++ stored in *ENDPTR. ++ Upon overflow, the return value is LLONG_MAX or LLONG_MIN, and errno is set ++ to ERANGE. */ ++#if !HAVE_STRTOLL ++extern long long strtoll(const char *string, char **endptr, int base); ++#endif ++ ++/* Parse an unsigned integer whose textual representation starts at STRING. ++ The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0, ++ it may be decimal or octal (with prefix "0") or hexadecimal (with prefix ++ "0x"). ++ If ENDPTR is not NULL, the address of the first byte after the integer is ++ stored in *ENDPTR. ++ Upon overflow, the return value is ULLONG_MAX, and errno is set to ++ ERANGE. */ ++#if !HAVE_STRTOULL ++extern unsigned long long strtoull(const char *string, char **endptr, int base); ++#endif ++ ++ ++/* Unlock the slave side of the pseudo-terminal whose master side is specified ++ by FD, so that it can be opened. */ ++#if !HAVE_UNLOCKPT ++extern int unlockpt(int fd); ++#endif ++ ++/* Remove the variable NAME from the environment. */ ++#if !HAVE_UNSETENV ++extern int unsetenv(const char *name); ++#endif ++ ++#endif /* _@GUARD_PREFIX@_STDLIB_H */ ++ +diff --git a/headers-mingw/sys_cdefs.h b/headers-mingw/sys_cdefs.h +new file mode 100644 +index 0000000..98cf749 +--- /dev/null ++++ b/headers-mingw/sys_cdefs.h +@@ -0,0 +1,514 @@ ++/* Copyright (C) 1992-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _SYS_CDEFS_H ++#define _SYS_CDEFS_H 1 ++ ++/* We are almost always included from features.h. */ ++#ifndef _FEATURES_H ++# include ++#endif ++ ++/* The GNU libc does not support any K&R compilers or the traditional mode ++ of ISO C compilers anymore. Check for some of the combinations not ++ anymore supported. */ ++#if defined __GNUC__ && !defined __STDC__ ++# error "You need a ISO C conforming compiler to use the glibc headers" ++#endif ++ ++/* Some user header file might have defined this before. */ ++#undef __P ++#undef __PMT ++ ++#ifdef __GNUC__ ++ ++/* All functions, except those with callbacks or those that ++ synchronize memory, are leaf functions. */ ++# if __GNUC_PREREQ (4, 6) && !defined _LIBC ++# define __LEAF , __leaf__ ++# define __LEAF_ATTR __attribute__ ((__leaf__)) ++# else ++# define __LEAF ++# define __LEAF_ATTR ++# endif ++ ++/* GCC can always grok prototypes. For C++ programs we add throw() ++ to help it optimize the function calls. But this works only with ++ gcc 2.8.x and egcs. For gcc 3.2 and up we even mark C functions ++ as non-throwing using a function attribute since programs can use ++ the -fexceptions options for C code as well. */ ++# if !defined __cplusplus && __GNUC_PREREQ (3, 3) ++# define __THROW __attribute__ ((__nothrow__ __LEAF)) ++# define __THROWNL __attribute__ ((__nothrow__)) ++# define __NTH(fct) __attribute__ ((__nothrow__ __LEAF)) fct ++# define __NTHNL(fct) __attribute__ ((__nothrow__)) fct ++# else ++# if defined __cplusplus && __GNUC_PREREQ (2,8) ++# define __THROW throw () ++# define __THROWNL throw () ++# define __NTH(fct) __LEAF_ATTR fct throw () ++# define __NTHNL(fct) fct throw () ++# else ++# define __THROW ++# define __THROWNL ++# define __NTH(fct) fct ++# define __NTHNL(fct) fct ++# endif ++# endif ++ ++#else /* Not GCC. */ ++ ++# if (defined __cplusplus \ ++ || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) ++# define __inline inline ++# else ++# define __inline /* No inline functions. */ ++# endif ++ ++# define __THROW ++# define __THROWNL ++# define __NTH(fct) fct ++ ++#endif /* GCC. */ ++ ++/* Compilers that are not clang may object to ++ #if defined __clang__ && __has_extension(...) ++ even though they do not need to evaluate the right-hand side of the &&. */ ++#if defined __clang__ && defined __has_extension ++# define __glibc_clang_has_extension(ext) __has_extension (ext) ++#else ++# define __glibc_clang_has_extension(ext) 0 ++#endif ++ ++/* These two macros are not used in glibc anymore. They are kept here ++ only because some other projects expect the macros to be defined. */ ++#define __P(args) args ++#define __PMT(args) args ++ ++/* For these things, GCC behaves the ANSI way normally, ++ and the non-ANSI way under -traditional. */ ++ ++#define __CONCAT(x,y) x ## y ++#define __STRING(x) #x ++ ++/* This is not a typedef so `const __ptr_t' does the right thing. */ ++#define __ptr_t void * ++ ++ ++/* C++ needs to know that types and declarations are C, not C++. */ ++#ifdef __cplusplus ++# define __BEGIN_DECLS extern "C" { ++# define __END_DECLS } ++#else ++# define __BEGIN_DECLS ++# define __END_DECLS ++#endif ++ ++ ++/* Fortify support. */ ++#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1) ++#define __bos0(ptr) __builtin_object_size (ptr, 0) ++ ++#if __GNUC_PREREQ (4,3) ++# define __warndecl(name, msg) \ ++ extern void name (void) __attribute__((__warning__ (msg))) ++# define __warnattr(msg) __attribute__((__warning__ (msg))) ++# define __errordecl(name, msg) \ ++ extern void name (void) __attribute__((__error__ (msg))) ++#else ++# define __warndecl(name, msg) extern void name (void) ++# define __warnattr(msg) ++# define __errordecl(name, msg) extern void name (void) ++#endif ++ ++/* Support for flexible arrays. ++ Headers that should use flexible arrays only if they're "real" ++ (e.g. only if they won't affect sizeof()) should test ++ #if __glibc_c99_flexarr_available. */ ++#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L ++# define __flexarr [] ++# define __glibc_c99_flexarr_available 1 ++#elif __GNUC_PREREQ (2,97) ++/* GCC 2.97 supports C99 flexible array members as an extension, ++ even when in C89 mode or compiling C++ (any version). */ ++# define __flexarr [] ++# define __glibc_c99_flexarr_available 1 ++#elif defined __GNUC__ ++/* Pre-2.97 GCC did not support C99 flexible arrays but did have ++ an equivalent extension with slightly different notation. */ ++# define __flexarr [0] ++# define __glibc_c99_flexarr_available 1 ++#else ++/* Some other non-C99 compiler. Approximate with [1]. */ ++# define __flexarr [1] ++# define __glibc_c99_flexarr_available 0 ++#endif ++ ++ ++/* __asm__ ("xyz") is used throughout the headers to rename functions ++ at the assembly language level. This is wrapped by the __REDIRECT ++ macro, in order to support compilers that can do this some other ++ way. When compilers don't support asm-names at all, we have to do ++ preprocessor tricks instead (which don't have exactly the right ++ semantics, but it's the best we can do). ++ ++ Example: ++ int __REDIRECT(setpgrp, (__pid_t pid, __pid_t pgrp), setpgid); */ ++ ++#if defined __GNUC__ && __GNUC__ >= 2 ++ ++# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias)) ++# ifdef __cplusplus ++# define __REDIRECT_NTH(name, proto, alias) \ ++ name proto __THROW __asm__ (__ASMNAME (#alias)) ++# define __REDIRECT_NTHNL(name, proto, alias) \ ++ name proto __THROWNL __asm__ (__ASMNAME (#alias)) ++# else ++# define __REDIRECT_NTH(name, proto, alias) \ ++ name proto __asm__ (__ASMNAME (#alias)) __THROW ++# define __REDIRECT_NTHNL(name, proto, alias) \ ++ name proto __asm__ (__ASMNAME (#alias)) __THROWNL ++# endif ++# define __ASMNAME(cname) __ASMNAME2 (__USER_LABEL_PREFIX__, cname) ++# define __ASMNAME2(prefix, cname) __STRING (prefix) cname ++ ++/* ++#elif __SOME_OTHER_COMPILER__ ++ ++# define __REDIRECT(name, proto, alias) name proto; \ ++ _Pragma("let " #name " = " #alias) ++*/ ++#endif ++ ++/* GCC has various useful declarations that can be made with the ++ `__attribute__' syntax. All of the ways we use this do fine if ++ they are omitted for compilers that don't understand it. */ ++#if !defined __GNUC__ || __GNUC__ < 2 ++# define __attribute__(xyz) /* Ignore */ ++#endif ++ ++/* At some point during the gcc 2.96 development the `malloc' attribute ++ for functions was introduced. We don't want to use it unconditionally ++ (although this would be possible) since it generates warnings. */ ++#if __GNUC_PREREQ (2,96) ++# define __attribute_malloc__ __attribute__ ((__malloc__)) ++#else ++# define __attribute_malloc__ /* Ignore */ ++#endif ++ ++/* Tell the compiler which arguments to an allocation function ++ indicate the size of the allocation. */ ++#if __GNUC_PREREQ (4, 3) ++# define __attribute_alloc_size__(params) \ ++ __attribute__ ((__alloc_size__ params)) ++#else ++# define __attribute_alloc_size__(params) /* Ignore. */ ++#endif ++ ++/* At some point during the gcc 2.96 development the `pure' attribute ++ for functions was introduced. We don't want to use it unconditionally ++ (although this would be possible) since it generates warnings. */ ++#if __GNUC_PREREQ (2,96) ++# define __attribute_pure__ __attribute__ ((__pure__)) ++#else ++# define __attribute_pure__ /* Ignore */ ++#endif ++ ++/* This declaration tells the compiler that the value is constant. */ ++#if __GNUC_PREREQ (2,5) ++# define __attribute_const__ __attribute__ ((__const__)) ++#else ++# define __attribute_const__ /* Ignore */ ++#endif ++ ++/* At some point during the gcc 3.1 development the `used' attribute ++ for functions was introduced. We don't want to use it unconditionally ++ (although this would be possible) since it generates warnings. */ ++#if __GNUC_PREREQ (3,1) ++# define __attribute_used__ __attribute__ ((__used__)) ++# define __attribute_noinline__ __attribute__ ((__noinline__)) ++#else ++# define __attribute_used__ __attribute__ ((__unused__)) ++# define __attribute_noinline__ /* Ignore */ ++#endif ++ ++/* Since version 3.2, gcc allows marking deprecated functions. */ ++#if __GNUC_PREREQ (3,2) ++# define __attribute_deprecated__ __attribute__ ((__deprecated__)) ++#else ++# define __attribute_deprecated__ /* Ignore */ ++#endif ++ ++/* Since version 4.5, gcc also allows one to specify the message printed ++ when a deprecated function is used. clang claims to be gcc 4.2, but ++ may also support this feature. */ ++#if __GNUC_PREREQ (4,5) || \ ++ __glibc_clang_has_extension (__attribute_deprecated_with_message__) ++# define __attribute_deprecated_msg__(msg) \ ++ __attribute__ ((__deprecated__ (msg))) ++#else ++# define __attribute_deprecated_msg__(msg) __attribute_deprecated__ ++#endif ++ ++/* At some point during the gcc 2.8 development the `format_arg' attribute ++ for functions was introduced. We don't want to use it unconditionally ++ (although this would be possible) since it generates warnings. ++ If several `format_arg' attributes are given for the same function, in ++ gcc-3.0 and older, all but the last one are ignored. In newer gccs, ++ all designated arguments are considered. */ ++#if __GNUC_PREREQ (2,8) ++# define __attribute_format_arg__(x) __attribute__ ((__format_arg__ (x))) ++#else ++# define __attribute_format_arg__(x) /* Ignore */ ++#endif ++ ++/* At some point during the gcc 2.97 development the `strfmon' format ++ attribute for functions was introduced. We don't want to use it ++ unconditionally (although this would be possible) since it ++ generates warnings. */ ++#if __GNUC_PREREQ (2,97) ++# define __attribute_format_strfmon__(a,b) \ ++ __attribute__ ((__format__ (__strfmon__, a, b))) ++#else ++# define __attribute_format_strfmon__(a,b) /* Ignore */ ++#endif ++ ++/* The nonnull function attribute marks pointer parameters that ++ must not be NULL. Do not define __nonnull if it is already defined, ++ for portability when this file is used in Gnulib. */ ++#ifndef __nonnull ++# if __GNUC_PREREQ (3,3) ++# define __nonnull(params) __attribute__ ((__nonnull__ params)) ++# else ++# define __nonnull(params) ++# endif ++#endif ++ ++/* If fortification mode, we warn about unused results of certain ++ function calls which can lead to problems. */ ++#if __GNUC_PREREQ (3,4) ++# define __attribute_warn_unused_result__ \ ++ __attribute__ ((__warn_unused_result__)) ++# if defined __USE_FORTIFY_LEVEL && __USE_FORTIFY_LEVEL > 0 ++# define __wur __attribute_warn_unused_result__ ++# endif ++#else ++# define __attribute_warn_unused_result__ /* empty */ ++#endif ++#ifndef __wur ++# define __wur /* Ignore */ ++#endif ++ ++/* Forces a function to be always inlined. */ ++#if __GNUC_PREREQ (3,2) ++/* The Linux kernel defines __always_inline in stddef.h (283d7573), and ++ it conflicts with this definition. Therefore undefine it first to ++ allow either header to be included first. */ ++# undef __always_inline ++# define __always_inline __inline __attribute__ ((__always_inline__)) ++#else ++# undef __always_inline ++# define __always_inline __inline ++#endif ++ ++/* Associate error messages with the source location of the call site rather ++ than with the source location inside the function. */ ++#if __GNUC_PREREQ (4,3) ++# define __attribute_artificial__ __attribute__ ((__artificial__)) ++#else ++# define __attribute_artificial__ /* Ignore */ ++#endif ++ ++/* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 ++ inline semantics, unless -fgnu89-inline is used. Using __GNUC_STDC_INLINE__ ++ or __GNUC_GNU_INLINE is not a good enough check for gcc because gcc versions ++ older than 4.3 may define these macros and still not guarantee GNU inlining ++ semantics. ++ ++ clang++ identifies itself as gcc-4.2, but has support for GNU inlining ++ semantics, that can be checked fot by using the __GNUC_STDC_INLINE_ and ++ __GNUC_GNU_INLINE__ macro definitions. */ ++#if (!defined __cplusplus || __GNUC_PREREQ (4,3) \ ++ || (defined __clang__ && (defined __GNUC_STDC_INLINE__ \ ++ || defined __GNUC_GNU_INLINE__))) ++# if defined __GNUC_STDC_INLINE__ || defined __cplusplus ++# define __extern_inline extern __inline __attribute__ ((__gnu_inline__)) ++# define __extern_always_inline \ ++ extern __always_inline __attribute__ ((__gnu_inline__)) ++# else ++# define __extern_inline extern __inline ++# define __extern_always_inline extern __always_inline ++# endif ++#endif ++ ++#ifdef __extern_always_inline ++# define __fortify_function __extern_always_inline __attribute_artificial__ ++#endif ++ ++/* GCC 4.3 and above allow passing all anonymous arguments of an ++ __extern_always_inline function to some other vararg function. */ ++#if __GNUC_PREREQ (4,3) ++# define __va_arg_pack() __builtin_va_arg_pack () ++# define __va_arg_pack_len() __builtin_va_arg_pack_len () ++#endif ++ ++/* It is possible to compile containing GCC extensions even if GCC is ++ run in pedantic mode if the uses are carefully marked using the ++ `__extension__' keyword. But this is not generally available before ++ version 2.8. */ ++#if !__GNUC_PREREQ (2,8) ++# define __extension__ /* Ignore */ ++#endif ++ ++/* __restrict is known in EGCS 1.2 and above. */ ++#if !__GNUC_PREREQ (2,92) ++# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L ++# define __restrict restrict ++# else ++# define __restrict /* Ignore */ ++# endif ++#endif ++ ++/* ISO C99 also allows to declare arrays as non-overlapping. The syntax is ++ array_name[restrict] ++ GCC 3.1 supports this. */ ++#if __GNUC_PREREQ (3,1) && !defined __GNUG__ ++# define __restrict_arr __restrict ++#else ++# ifdef __GNUC__ ++# define __restrict_arr /* Not supported in old GCC. */ ++# else ++# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L ++# define __restrict_arr restrict ++# else ++/* Some other non-C99 compiler. */ ++# define __restrict_arr /* Not supported. */ ++# endif ++# endif ++#endif ++ ++#if __GNUC__ >= 3 ++# define __glibc_unlikely(cond) __builtin_expect ((cond), 0) ++# define __glibc_likely(cond) __builtin_expect ((cond), 1) ++#else ++# define __glibc_unlikely(cond) (cond) ++# define __glibc_likely(cond) (cond) ++#endif ++ ++#ifdef __has_attribute ++# define __glibc_has_attribute(attr) __has_attribute (attr) ++#else ++# define __glibc_has_attribute(attr) 0 ++#endif ++ ++#if (!defined _Noreturn \ ++ && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ ++ && !__GNUC_PREREQ (4,7)) ++# if __GNUC_PREREQ (2,8) ++# define _Noreturn __attribute__ ((__noreturn__)) ++# else ++# define _Noreturn ++# endif ++#endif ++ ++#if __GNUC_PREREQ (8, 0) ++/* Describes a char array whose address can safely be passed as the first ++ argument to strncpy and strncat, as the char array is not necessarily ++ a NUL-terminated string. */ ++# define __attribute_nonstring__ __attribute__ ((__nonstring__)) ++#else ++# define __attribute_nonstring__ ++#endif ++ ++#if (!defined _Static_assert && !defined __cplusplus \ ++ && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ ++ && (!__GNUC_PREREQ (4, 6) || defined __STRICT_ANSI__)) ++# define _Static_assert(expr, diagnostic) \ ++ extern int (*__Static_assert_function (void)) \ ++ [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })] ++#endif ++ ++/* The #ifndef lets Gnulib avoid including these on non-glibc ++ platforms, where the includes typically do not exist. */ ++#ifndef __WORDSIZE ++# include ++# include ++#endif ++ ++#if defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH ++# define __LDBL_COMPAT 1 ++# ifdef __REDIRECT ++# define __LDBL_REDIR1(name, proto, alias) __REDIRECT (name, proto, alias) ++# define __LDBL_REDIR(name, proto) \ ++ __LDBL_REDIR1 (name, proto, __nldbl_##name) ++# define __LDBL_REDIR1_NTH(name, proto, alias) __REDIRECT_NTH (name, proto, alias) ++# define __LDBL_REDIR_NTH(name, proto) \ ++ __LDBL_REDIR1_NTH (name, proto, __nldbl_##name) ++# define __LDBL_REDIR1_DECL(name, alias) \ ++ extern __typeof (name) name __asm (__ASMNAME (#alias)); ++# define __LDBL_REDIR_DECL(name) \ ++ extern __typeof (name) name __asm (__ASMNAME ("__nldbl_" #name)); ++# define __REDIRECT_LDBL(name, proto, alias) \ ++ __LDBL_REDIR1 (name, proto, __nldbl_##alias) ++# define __REDIRECT_NTH_LDBL(name, proto, alias) \ ++ __LDBL_REDIR1_NTH (name, proto, __nldbl_##alias) ++# endif ++#endif ++#if !defined __LDBL_COMPAT || !defined __REDIRECT ++# define __LDBL_REDIR1(name, proto, alias) name proto ++# define __LDBL_REDIR(name, proto) name proto ++# define __LDBL_REDIR1_NTH(name, proto, alias) name proto __THROW ++# define __LDBL_REDIR_NTH(name, proto) name proto __THROW ++# define __LDBL_REDIR_DECL(name) ++# ifdef __REDIRECT ++# define __REDIRECT_LDBL(name, proto, alias) __REDIRECT (name, proto, alias) ++# define __REDIRECT_NTH_LDBL(name, proto, alias) \ ++ __REDIRECT_NTH (name, proto, alias) ++# endif ++#endif ++ ++/* __glibc_macro_warning (MESSAGE) issues warning MESSAGE. This is ++ intended for use in preprocessor macros. ++ ++ Note: MESSAGE must be a _single_ string; concatenation of string ++ literals is not supported. */ ++#if __GNUC_PREREQ (4,8) || __glibc_clang_prereq (3,5) ++# define __glibc_macro_warning1(message) _Pragma (#message) ++# define __glibc_macro_warning(message) \ ++ __glibc_macro_warning1 (GCC warning message) ++#else ++# define __glibc_macro_warning(msg) ++#endif ++ ++/* Generic selection (ISO C11) is a C-only feature, available in GCC ++ since version 4.9. Previous versions do not provide generic ++ selection, even though they might set __STDC_VERSION__ to 201112L, ++ when in -std=c11 mode. Thus, we must check for !defined __GNUC__ ++ when testing __STDC_VERSION__ for generic selection support. ++ On the other hand, Clang also defines __GNUC__, so a clang-specific ++ check is required to enable the use of generic selection. */ ++#if !defined __cplusplus \ ++ && (__GNUC_PREREQ (4, 9) \ ++ || __glibc_clang_has_extension (c_generic_selections) \ ++ || (!defined __GNUC__ && defined __STDC_VERSION__ \ ++ && __STDC_VERSION__ >= 201112L)) ++# define __HAVE_GENERIC_SELECTION 1 ++#else ++# define __HAVE_GENERIC_SELECTION 0 ++#endif ++ ++#endif /* sys/cdefs.h */ +diff --git a/headers-mingw/sys_ioctl.h b/headers-mingw/sys_ioctl.h +new file mode 100644 +index 0000000..80e9d7b +--- /dev/null ++++ b/headers-mingw/sys_ioctl.h +@@ -0,0 +1,36 @@ ++/* Substitute for and wrapper around . ++ Copyright (C) 2008-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++#ifndef _GL_SYS_IOCTL_H ++ ++#define _GL_SYS_IOCTL_H ++ ++/* AIX 5.1 and Solaris 10 declare ioctl() in and in , ++ but not in . ++ Haiku declares ioctl() in , but not in . ++ But avoid namespace pollution on glibc systems. */ ++#ifndef __GLIBC__ ++# include ++#endif ++ ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++ ++/* Declare overridden functions. */ ++ ++#endif /* _@GUARD_PREFIX@_SYS_IOCTL_H */ +diff --git a/headers-mingw/sys_stat.h b/headers-mingw/sys_stat.h +new file mode 100644 +index 0000000..2b06b15 +--- /dev/null ++++ b/headers-mingw/sys_stat.h +@@ -0,0 +1,506 @@ ++/* Provide a more complete sys/stat.h header file. ++ Copyright (C) 2005-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++/* Written by Eric Blake, Paul Eggert, and Jim Meyering. */ ++ ++/* This file is supposed to be used on platforms where is ++ incomplete. It is intended to provide definitions and prototypes ++ needed by an application. Start with what the system provides. */ ++ ++/* Normal invocation convention. */ ++ ++#ifndef _GL_SYS_STAT_H ++ ++/* Get nlink_t. ++ May also define off_t to a 64-bit type on native Windows. */ ++#include ++ ++/* Get struct timespec. */ ++#include ++ ++#define _GL_SYS_STAT_H ++ ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_ARG_NONNULL is copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++/* Before doing "#define mkdir rpl_mkdir" below, we need to include all ++ headers that may declare mkdir(). Native Windows platforms declare mkdir ++ in and/or , not in . */ ++#if defined _WIN32 && ! defined __CYGWIN__ ++# include /* mingw32, mingw64 */ ++# include /* mingw64, MSVC 9 */ ++#endif ++ ++//# if !GNULIB_defined_struct_stat ++//struct stat ++//{ ++// dev_t st_dev; ++// ino_t st_ino; ++// mode_t st_mode; ++// nlink_t st_nlink; ++//# if 0 ++// uid_t st_uid; ++//# else /* uid_t is not defined by default on native Windows. */ ++// int st_uid; ++//# endif ++//# if 0 ++// gid_t st_gid; ++//# else /* gid_t is not defined by default on native Windows. */ ++// int st_gid; ++//# endif ++// dev_t st_rdev; ++// off_t st_size; ++//# if 0 ++// blksize_t st_blksize; ++// blkcnt_t st_blocks; ++//# endif ++// ++////# if @WINDOWS_STAT_TIMESPEC@ ++// struct timespec st_atim; ++// struct timespec st_mtim; ++// struct timespec st_ctim; ++////# else ++//// time_t st_atime; ++//// time_t st_mtime; ++//// time_t st_ctime; ++////# endif ++//}; ++////# if @WINDOWS_STAT_TIMESPEC@ ++//# define st_atime st_atim.tv_sec ++//# define st_mtime st_mtim.tv_sec ++//# define st_ctime st_ctim.tv_sec ++// /* Indicator, for gnulib internal purposes. */ ++//# define _GL_WINDOWS_STAT_TIMESPEC 1 ++////# endif ++//# define GNULIB_defined_struct_stat 1 ++//# endif ++ ++#ifndef S_IFIFO ++# ifdef _S_IFIFO ++# define S_IFIFO _S_IFIFO ++# endif ++#endif ++ ++#ifndef S_IFMT ++# define S_IFMT 0170000 ++#endif ++ ++#if STAT_MACROS_BROKEN ++# undef S_ISBLK ++# undef S_ISCHR ++# undef S_ISDIR ++# undef S_ISFIFO ++# undef S_ISLNK ++# undef S_ISNAM ++# undef S_ISMPB ++# undef S_ISMPC ++# undef S_ISNWK ++# undef S_ISREG ++# undef S_ISSOCK ++#endif ++ ++#ifndef S_ISBLK ++# ifdef S_IFBLK ++# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) ++# else ++# define S_ISBLK(m) 0 ++# endif ++#endif ++ ++#ifndef S_ISCHR ++# ifdef S_IFCHR ++# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) ++# else ++# define S_ISCHR(m) 0 ++# endif ++#endif ++ ++#ifndef S_ISDIR ++# ifdef S_IFDIR ++# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) ++# else ++# define S_ISDIR(m) 0 ++# endif ++#endif ++ ++#ifndef S_ISDOOR /* Solaris 2.5 and up */ ++# define S_ISDOOR(m) 0 ++#endif ++ ++#ifndef S_ISFIFO ++# ifdef S_IFIFO ++# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) ++# else ++# define S_ISFIFO(m) 0 ++# endif ++#endif ++ ++#ifndef S_ISLNK ++# ifdef S_IFLNK ++# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) ++# else ++# define S_ISLNK(m) 0 ++# endif ++#endif ++ ++#ifndef S_ISMPB /* V7 */ ++# ifdef S_IFMPB ++# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) ++# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) ++# else ++# define S_ISMPB(m) 0 ++# define S_ISMPC(m) 0 ++# endif ++#endif ++ ++#ifndef S_ISMPX /* AIX */ ++# define S_ISMPX(m) 0 ++#endif ++ ++#ifndef S_ISNAM /* Xenix */ ++# ifdef S_IFNAM ++# define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM) ++# else ++# define S_ISNAM(m) 0 ++# endif ++#endif ++ ++#ifndef S_ISNWK /* HP/UX */ ++# ifdef S_IFNWK ++# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) ++# else ++# define S_ISNWK(m) 0 ++# endif ++#endif ++ ++#ifndef S_ISPORT /* Solaris 10 and up */ ++# define S_ISPORT(m) 0 ++#endif ++ ++#ifndef S_ISREG ++# ifdef S_IFREG ++# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) ++# else ++# define S_ISREG(m) 0 ++# endif ++#endif ++ ++#ifndef S_ISSOCK ++# ifdef S_IFSOCK ++# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) ++# else ++# define S_ISSOCK(m) 0 ++# endif ++#endif ++ ++ ++#ifndef S_TYPEISMQ ++# define S_TYPEISMQ(p) 0 ++#endif ++ ++#ifndef S_TYPEISTMO ++# define S_TYPEISTMO(p) 0 ++#endif ++ ++ ++#ifndef S_TYPEISSEM ++# ifdef S_INSEM ++# define S_TYPEISSEM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSEM) ++# else ++# define S_TYPEISSEM(p) 0 ++# endif ++#endif ++ ++#ifndef S_TYPEISSHM ++# ifdef S_INSHD ++# define S_TYPEISSHM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSHD) ++# else ++# define S_TYPEISSHM(p) 0 ++# endif ++#endif ++ ++/* high performance ("contiguous data") */ ++#ifndef S_ISCTG ++# define S_ISCTG(p) 0 ++#endif ++ ++/* Cray DMF (data migration facility): off line, with data */ ++#ifndef S_ISOFD ++# define S_ISOFD(p) 0 ++#endif ++ ++/* Cray DMF (data migration facility): off line, with no data */ ++#ifndef S_ISOFL ++# define S_ISOFL(p) 0 ++#endif ++ ++/* 4.4BSD whiteout */ ++#ifndef S_ISWHT ++# define S_ISWHT(m) 0 ++#endif ++ ++/* If any of the following are undefined, ++ define them to their de facto standard values. */ ++#if !S_ISUID ++# define S_ISUID 04000 ++#endif ++#if !S_ISGID ++# define S_ISGID 02000 ++#endif ++ ++/* S_ISVTX is a common extension to POSIX. */ ++#ifndef S_ISVTX ++# define S_ISVTX 01000 ++#endif ++ ++#if !S_IRUSR && S_IREAD ++# define S_IRUSR S_IREAD ++#endif ++#if !S_IRUSR ++# define S_IRUSR 00400 ++#endif ++#if !S_IRGRP ++# define S_IRGRP (S_IRUSR >> 3) ++#endif ++#if !S_IROTH ++# define S_IROTH (S_IRUSR >> 6) ++#endif ++ ++#if !S_IWUSR && S_IWRITE ++# define S_IWUSR S_IWRITE ++#endif ++#if !S_IWUSR ++# define S_IWUSR 00200 ++#endif ++#if !S_IWGRP ++# define S_IWGRP (S_IWUSR >> 3) ++#endif ++#if !S_IWOTH ++# define S_IWOTH (S_IWUSR >> 6) ++#endif ++ ++#if !S_IXUSR && S_IEXEC ++# define S_IXUSR S_IEXEC ++#endif ++#if !S_IXUSR ++# define S_IXUSR 00100 ++#endif ++#if !S_IXGRP ++# define S_IXGRP (S_IXUSR >> 3) ++#endif ++#if !S_IXOTH ++# define S_IXOTH (S_IXUSR >> 6) ++#endif ++ ++#if !S_IRWXU ++# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) ++#endif ++#if !S_IRWXG ++# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) ++#endif ++#if !S_IRWXO ++# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) ++#endif ++ ++/* S_IXUGO is a common extension to POSIX. */ ++#if !S_IXUGO ++# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) ++#endif ++ ++#ifndef S_IRWXUGO ++# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO) ++#endif ++ ++/* Macros for futimens and utimensat. */ ++#ifndef UTIME_NOW ++# define UTIME_NOW (-1) ++# define UTIME_OMIT (-2) ++#endif ++ ++#if !HAVE_FCHMODAT ++extern int fchmodat(int fd, char const *file, mode_t mode, int flag); ++#endif ++ ++ ++#if !HAVE_FSTATAT ++extern int fstatat(int fd, char const *name, struct stat *st, int flags); ++#endif ++ ++#if !HAVE_FUTIMENS ++extern int futimens(int fd, struct timespec const times[2]); ++#endif ++ ++/* Change the mode of FILENAME to MODE, without dereferencing it if FILENAME ++ denotes a symbolic link. */ ++#if !HAVE_LCHMOD ++/* The lchmod replacement follows symbolic links. Callers should take ++ this into account; lchmod should be applied only to arguments that ++ are known to not be symbolic links. On hosts that lack lchmod, ++ this can lead to race conditions between the check and the ++ invocation of lchmod, but we know of no workarounds that are ++ reliable in general. You might try requesting support for lchmod ++ from your operating system supplier. */ ++#define lchmod chmod ++#endif ++ ++#if !HAVE_LSTAT ++/* mingw does not support symlinks, therefore it does not have lstat. But ++ without links, stat does just fine. */ ++#define lstat stat ++#endif ++ ++ ++//#if @REPLACE_MKDIR@ ++//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) ++//# undef mkdir ++//# define mkdir rpl_mkdir ++//# endif ++//_GL_FUNCDECL_RPL (mkdir, int, (char const *name, mode_t mode) ++// _GL_ARG_NONNULL ((1))); ++//_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode)); ++//#else ++///* mingw's _mkdir() function has 1 argument, but we pass 2 arguments. ++// Additionally, it declares _mkdir (and depending on compile flags, an ++// alias mkdir), only in the nonstandard includes and , ++// which are included above. */ ++//# if defined _WIN32 && ! defined __CYGWIN__ ++// ++//# if !GNULIB_defined_rpl_mkdir ++//static int ++//rpl_mkdir (char const *name, mode_t mode) ++//{ ++// return _mkdir (name); ++//} ++//# define GNULIB_defined_rpl_mkdir 1 ++//# endif ++// ++//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) ++//# define mkdir rpl_mkdir ++//# endif ++//_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode)); ++//# else ++//_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode)); ++//# endif ++//#endif ++//_GL_CXXALIASWARN (mkdir); ++ ++ ++#if !HAVE_MKDIRAT ++extern int mkdirat(int fd, char const *file, mode_t mode); ++#endif ++ ++#if !HAVE_MKFIFO ++extern int mkfifo(char const *file, mode_t mode); ++#endif ++ ++#if !HAVE_MKFIFOAT ++extern int mkfifoat(int fd, char const *file, mode_t mode); ++#endif ++ ++ ++#if !HAVE_MKNOD ++extern int mknod(char const *file, mode_t mode, dev_t dev); ++#endif ++ ++#if !HAVE_MKNODAT ++extern int mknodat(int fd, char const *file, mode_t mode, dev_t dev); ++#endif ++ ++ ++//#if @GNULIB_STAT@ ++//# if @REPLACE_STAT@ ++//# if !@GNULIB_OVERRIDES_STRUCT_STAT@ ++// /* We can't use the object-like #define stat rpl_stat, because of ++// struct stat. This means that rpl_stat will not be used if the user ++// does (stat)(a,b). Oh well. */ ++//# if defined _AIX && defined stat && defined _LARGE_FILES ++// /* With _LARGE_FILES defined, AIX (only) defines stat to stat64, ++// so we have to replace stat64() instead of stat(). */ ++//# undef stat64 ++//# define stat64(name, st) rpl_stat (name, st) ++//# elif @WINDOWS_64_BIT_ST_SIZE@ ++// /* Above, we define stat to _stati64. */ ++//# if defined __MINGW32__ && defined _stati64 ++//# ifndef _USE_32BIT_TIME_T ++// /* The system headers define _stati64 to _stat64. */ ++//# undef _stat64 ++//# define _stat64(name, st) rpl_stat (name, st) ++//# endif ++//# elif defined _MSC_VER && defined _stati64 ++//# ifdef _USE_32BIT_TIME_T ++// /* The system headers define _stati64 to _stat32i64. */ ++//# undef _stat32i64 ++//# define _stat32i64(name, st) rpl_stat (name, st) ++//# else ++// /* The system headers define _stati64 to _stat64. */ ++//# undef _stat64 ++//# define _stat64(name, st) rpl_stat (name, st) ++//# endif ++//# else ++//# undef _stati64 ++//# define _stati64(name, st) rpl_stat (name, st) ++//# endif ++//# elif defined __MINGW32__ && defined stat ++//# ifdef _USE_32BIT_TIME_T ++// /* The system headers define stat to _stat32i64. */ ++//# undef _stat32i64 ++//# define _stat32i64(name, st) rpl_stat (name, st) ++//# else ++// /* The system headers define stat to _stat64. */ ++//# undef _stat64 ++//# define _stat64(name, st) rpl_stat (name, st) ++//# endif ++//# elif defined _MSC_VER && defined stat ++//# ifdef _USE_32BIT_TIME_T ++// /* The system headers define stat to _stat32. */ ++//# undef _stat32 ++//# define _stat32(name, st) rpl_stat (name, st) ++//# else ++// /* The system headers define stat to _stat64i32. */ ++//# undef _stat64i32 ++//# define _stat64i32(name, st) rpl_stat (name, st) ++//# endif ++//# else /* !(_AIX || __MINGW32__ || _MSC_VER) */ ++//# undef stat ++//# define stat(name, st) rpl_stat (name, st) ++//# endif /* !_LARGE_FILES */ ++//# endif /* !@GNULIB_OVERRIDES_STRUCT_STAT@ */ ++//_GL_EXTERN_C int stat (const char *name, struct stat *buf) ++// _GL_ARG_NONNULL ((1, 2)); ++//# endif ++//#elif @GNULIB_OVERRIDES_STRUCT_STAT@ ++///* see above: ++// #define stat stat_used_without_requesting_gnulib_module_stat ++// */ ++//#elif defined GNULIB_POSIXCHECK ++//# undef stat ++//# if HAVE_RAW_DECL_STAT ++//_GL_WARN_ON_USE (stat, "stat is unportable - " ++// "use gnulib module stat for portability"); ++//# endif ++//#endif ++ ++#if !HAVE_UTIMENSAT ++extern int utimensat(int fd, char const *name, ++ struct timespec const times[2], int flag); ++#endif ++ ++ ++#endif /* _@GUARD_PREFIX@_SYS_STAT_H */ ++ +diff --git a/headers-mingw/sys_utsname.h b/headers-mingw/sys_utsname.h +new file mode 100644 +index 0000000..c9733a7 +--- /dev/null ++++ b/headers-mingw/sys_utsname.h +@@ -0,0 +1,80 @@ ++/* Substitute for . ++ Copyright (C) 2009-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++#ifndef _GL_SYS_UTSNAME_H ++#define _GL_SYS_UTSNAME_H ++ ++/* The definition of _GL_ARG_NONNULL is copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++/* Length of the entries in 'struct utsname' is 256. */ ++#define _UTSNAME_LENGTH 256 ++ ++#ifndef _UTSNAME_NODENAME_LENGTH ++# define _UTSNAME_NODENAME_LENGTH _UTSNAME_LENGTH ++#endif ++#ifndef _UTSNAME_SYSNAME_LENGTH ++# define _UTSNAME_SYSNAME_LENGTH _UTSNAME_LENGTH ++#endif ++#ifndef _UTSNAME_RELEASE_LENGTH ++# define _UTSNAME_RELEASE_LENGTH _UTSNAME_LENGTH ++#endif ++#ifndef _UTSNAME_VERSION_LENGTH ++# define _UTSNAME_VERSION_LENGTH _UTSNAME_LENGTH ++#endif ++#ifndef _UTSNAME_MACHINE_LENGTH ++# define _UTSNAME_MACHINE_LENGTH _UTSNAME_LENGTH ++#endif ++ ++# if !GNULIB_defined_struct_utsname ++/* Structure describing the system and machine. */ ++struct utsname ++ { ++ /* Name of this node on the network. */ ++ char nodename[_UTSNAME_NODENAME_LENGTH]; ++ ++ /* Name of the implementation of the operating system. */ ++ char sysname[_UTSNAME_SYSNAME_LENGTH]; ++ /* Current release level of this implementation. */ ++ char release[_UTSNAME_RELEASE_LENGTH]; ++ /* Current version level of this release. */ ++ char version[_UTSNAME_VERSION_LENGTH]; ++ ++ /* Name of the hardware type the system is running on. */ ++ char machine[_UTSNAME_MACHINE_LENGTH]; ++ }; ++# define GNULIB_defined_struct_utsname 1 ++# endif ++ ++# if !HAVE_UNAME ++extern int uname (struct utsname *buf); ++# endif ++ ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++#endif /* _@GUARD_PREFIX@_SYS_UTSNAME_H */ +diff --git a/headers-mingw/sys_wait.h b/headers-mingw/sys_wait.h +new file mode 100644 +index 0000000..c5a90af +--- /dev/null ++++ b/headers-mingw/sys_wait.h +@@ -0,0 +1,65 @@ ++/* A POSIX-like . ++ Copyright (C) 2001-2003, 2005-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++#ifndef _GL_SYS_WAIT_H ++#define _GL_SYS_WAIT_H ++ ++/* Get pid_t. */ ++#include ++ ++ ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++/* Native Windows API. */ ++ ++#include /* for SIGTERM */ ++ ++/* The following macros apply to an argument x, that is a status of a process, ++ as returned by waitpid() or, equivalently, _cwait() or GetExitCodeProcess(). ++ This value is simply an 'int', not composed of bit fields. */ ++ ++/* When an unhandled fatal signal terminates a process, the exit code is 3. */ ++#define WIFSIGNALED(x) ((x) == 3) ++#define WIFEXITED(x) ((x) != 3) ++#define WIFSTOPPED(x) 0 ++ ++/* The signal that terminated a process is not known posthum. */ ++#define WTERMSIG(x) SIGTERM ++ ++#define WEXITSTATUS(x) (x) ++ ++/* There are no stopping signals. */ ++#define WSTOPSIG(x) 0 ++ ++/* There are no core dumps. */ ++#define WCOREDUMP(x) 0 ++ ++ ++ ++ ++/* Declarations of functions. */ ++ ++#if !HAVE_WAITPID ++/* dummy constants */ ++#define WNOHANG (-1) ++#define WUNTRACED (-1) ++extern pid_t waitpid(pid_t pid, int *statusp, int options); ++#endif ++ ++ ++#endif /* _@GUARD_PREFIX@_SYS_WAIT_H */ +diff --git a/headers-mingw/unistd.h b/headers-mingw/unistd.h +new file mode 100644 +index 0000000..216d3b4 +--- /dev/null ++++ b/headers-mingw/unistd.h +@@ -0,0 +1,566 @@ ++/* Substitute for and wrapper around . ++ Copyright (C) 2003-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++#ifndef _GL_UNISTD_H ++ ++/* NetBSD 5.0 mis-defines NULL. Also get size_t. */ ++#include ++ ++/* mingw doesn't define the SEEK_* or *_FILENO macros in . */ ++/* MSVC declares 'unlink' in , not in . We must include ++ it before we #define unlink rpl_unlink. */ ++/* Cygwin 1.7.1 declares symlinkat in , not in . */ ++/* But avoid namespace pollution on glibc systems. */ ++#if (!(defined SEEK_CUR && defined SEEK_END && defined SEEK_SET) \ ++ || (defined _WIN32 && ! defined __CYGWIN__) \ ++ || defined __CYGWIN__) \ ++ && ! defined __GLIBC__ ++# include ++#endif ++ ++/* Cygwin 1.7.1 declares unlinkat in , not in . */ ++/* But avoid namespace pollution on glibc systems. */ ++#if defined __CYGWIN__ \ ++ && ! defined __GLIBC__ ++# include ++#endif ++ ++/* mingw fails to declare _exit in . */ ++/* mingw, MSVC, BeOS, Haiku declare environ in , not in ++ . */ ++/* Solaris declares getcwd not only in but also in . */ ++/* OSF Tru64 Unix cannot see gnulib rpl_strtod when system is ++ included here. */ ++/* But avoid namespace pollution on glibc systems. */ ++#if !defined __GLIBC__ && !defined __osf__ ++# define __need_system_stdlib_h ++# include ++# undef __need_system_stdlib_h ++#endif ++ ++/* Native Windows platforms declare chdir, getcwd, rmdir in ++ and/or , not in . ++ They also declare access(), chmod(), close(), dup(), dup2(), isatty(), ++ lseek(), read(), unlink(), write() in . */ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++# include /* mingw32, mingw64 */ ++# include /* mingw64, MSVC 9 */ ++#endif ++ ++/* AIX and OSF/1 5.1 declare getdomainname in , not in . ++ NonStop Kernel declares gethostname in , not in . */ ++/* But avoid namespace pollution on glibc systems. */ ++#if ((defined _AIX || defined __osf__) \ ++ || defined __TANDEM) \ ++ && !defined __GLIBC__ ++# include ++#endif ++ ++/* MSVC defines off_t in . ++ May also define off_t to a 64-bit type on native Windows. */ ++/* Get off_t. */ ++# include ++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ ++ ++/* The definition of _GL_ARG_NONNULL is copied here. */ ++ ++/* The definition of _GL_WARN_ON_USE is copied here. */ ++ ++ ++///* Get getopt(), optarg, optind, opterr, optopt. */ ++//#if @GNULIB_UNISTD_H_GETOPT@ && !defined _GL_SYSTEM_GETOPT ++//# include ++//# include ++//#endif ++ ++#ifndef _GL_UNISTD_INLINE ++# define _GL_UNISTD_INLINE _GL_INLINE ++#endif ++ ++///* Hide some function declarations from . */ ++// ++//#if @GNULIB_GETHOSTNAME@ && @UNISTD_H_HAVE_WINSOCK2_H@ ++//# if !defined _@GUARD_PREFIX@_SYS_SOCKET_H ++//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) ++//# undef socket ++//# define socket socket_used_without_including_sys_socket_h ++//# undef connect ++//# define connect connect_used_without_including_sys_socket_h ++//# undef accept ++//# define accept accept_used_without_including_sys_socket_h ++//# undef bind ++//# define bind bind_used_without_including_sys_socket_h ++//# undef getpeername ++//# define getpeername getpeername_used_without_including_sys_socket_h ++//# undef getsockname ++//# define getsockname getsockname_used_without_including_sys_socket_h ++//# undef getsockopt ++//# define getsockopt getsockopt_used_without_including_sys_socket_h ++//# undef listen ++//# define listen listen_used_without_including_sys_socket_h ++//# undef recv ++//# define recv recv_used_without_including_sys_socket_h ++//# undef send ++//# define send send_used_without_including_sys_socket_h ++//# undef recvfrom ++//# define recvfrom recvfrom_used_without_including_sys_socket_h ++//# undef sendto ++//# define sendto sendto_used_without_including_sys_socket_h ++//# undef setsockopt ++//# define setsockopt setsockopt_used_without_including_sys_socket_h ++//# undef shutdown ++//# define shutdown shutdown_used_without_including_sys_socket_h ++//# else ++// _GL_WARN_ON_USE (socket, ++// "socket() used without including "); ++// _GL_WARN_ON_USE (connect, ++// "connect() used without including "); ++// _GL_WARN_ON_USE (accept, ++// "accept() used without including "); ++// _GL_WARN_ON_USE (bind, ++// "bind() used without including "); ++// _GL_WARN_ON_USE (getpeername, ++// "getpeername() used without including "); ++// _GL_WARN_ON_USE (getsockname, ++// "getsockname() used without including "); ++// _GL_WARN_ON_USE (getsockopt, ++// "getsockopt() used without including "); ++// _GL_WARN_ON_USE (listen, ++// "listen() used without including "); ++// _GL_WARN_ON_USE (recv, ++// "recv() used without including "); ++// _GL_WARN_ON_USE (send, ++// "send() used without including "); ++// _GL_WARN_ON_USE (recvfrom, ++// "recvfrom() used without including "); ++// _GL_WARN_ON_USE (sendto, ++// "sendto() used without including "); ++// _GL_WARN_ON_USE (setsockopt, ++// "setsockopt() used without including "); ++// _GL_WARN_ON_USE (shutdown, ++// "shutdown() used without including "); ++//# endif ++//# endif ++//# if !defined _@GUARD_PREFIX@_SYS_SELECT_H ++//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) ++//# undef select ++//# define select select_used_without_including_sys_select_h ++//# else ++// _GL_WARN_ON_USE (select, ++// "select() used without including "); ++//# endif ++//# endif ++//#endif ++ ++ ++/* OS/2 EMX lacks these macros. */ ++#ifndef STDIN_FILENO ++# define STDIN_FILENO 0 ++#endif ++#ifndef STDOUT_FILENO ++# define STDOUT_FILENO 1 ++#endif ++#ifndef STDERR_FILENO ++# define STDERR_FILENO 2 ++#endif ++ ++/* Ensure *_OK macros exist. */ ++#ifndef F_OK ++# define F_OK 0 ++# define X_OK 1 ++# define W_OK 2 ++# define R_OK 4 ++#endif ++ ++#ifndef MAXSYMLINKS ++# ifdef SYMLOOP_MAX ++# define MAXSYMLINKS SYMLOOP_MAX ++# else ++# define MAXSYMLINKS 20 ++# endif ++#endif ++ ++ ++/* Declare overridden functions. */ ++ ++/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE ++ to GID (if GID is not -1). Follow symbolic links. ++ Return 0 if successful, otherwise -1 and errno set. ++ See the POSIX:2008 specification ++ . */ ++#if !HAVE_DUP2 ++extern int dup2(int oldfd, int newfd); ++#endif ++ ++/* Copy the file descriptor OLDFD into file descriptor NEWFD, with the ++ specified flags. ++ The flags are a bitmask, possibly including O_CLOEXEC (defined in ) ++ and O_TEXT, O_BINARY (defined in "binary-io.h"). ++ Close NEWFD first if it is open. ++ Return newfd if successful, otherwise -1 and errno set. ++ See the Linux man page at ++ . */ ++#if !HAVE_DUP3 ++extern int dup3(int oldfd, int newfd, int flags); ++#endif ++ ++ ++//#if @GNULIB_ENVIRON@ ++//# if defined __CYGWIN__ && !defined __i386__ ++///* The 'environ' variable is defined in a DLL. Therefore its declaration needs ++// the '__declspec(dllimport)' attribute, but the system's lacks it. ++// This leads to a link error on 64-bit Cygwin when the option ++// -Wl,--disable-auto-import is in use. */ ++//_GL_EXTERN_C __declspec(dllimport) char **environ; ++//# endif ++//# if !@HAVE_DECL_ENVIRON@ ++///* Set of environment variables and values. An array of strings of the form ++// "VARIABLE=VALUE", terminated with a NULL. */ ++//# if defined __APPLE__ && defined __MACH__ ++//# include ++//# if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR ++//# define _GL_USE_CRT_EXTERNS ++//# endif ++//# endif ++//# ifdef _GL_USE_CRT_EXTERNS ++//# include ++//# define environ (*_NSGetEnviron ()) ++//# else ++//# ifdef __cplusplus ++//extern "C" { ++//# endif ++//extern char **environ; ++//# ifdef __cplusplus ++//} ++//# endif ++//# endif ++//# endif ++//#elif defined GNULIB_POSIXCHECK ++//# if HAVE_RAW_DECL_ENVIRON ++//_GL_UNISTD_INLINE char *** ++//_GL_WARN_ON_USE_ATTRIBUTE ("environ is unportable - " ++// "use gnulib module environ for portability") ++//rpl_environ (void) ++//{ ++// return &environ; ++//} ++//# undef environ ++//# define environ (*rpl_environ ()) ++//# endif ++//#endif ++ ++ ++/* Like access(), except that it uses the effective user id and group id of ++ the current process. */ ++# if !HAVE_EUIDACCESS ++extern int euidaccess(const char *filename, int mode); ++#endif ++ ++ ++#if !HAVE_FACCESSAT ++extern int faccessat(int fd, char const *file, int mode, int flag); ++#endif ++ ++ ++/* Change the process' current working directory to the directory on which ++ the given file descriptor is open. ++ Return 0 if successful, otherwise -1 and errno set. ++ See the POSIX:2008 specification ++ . */ ++#if !HAVE_FCHDIR ++extern int fchdir(int fd); ++ ++/* Gnulib internal hooks needed to maintain the fchdir metadata. */ ++extern int _gl_register_fd (int fd, const char *filename); ++extern void _gl_unregister_fd (int fd); ++extern int _gl_register_dup (int oldfd, int newfd); ++extern const char *_gl_directory_name (int fd); ++#endif ++ ++ ++#if !HAVE_FCHOWNAT ++extern int fchownat(int fd, char const *file, ++ int owner, int group, int flag); ++#endif ++ ++/* Synchronize changes to a file. ++ Return 0 if successful, otherwise -1 and errno set. ++ See POSIX:2008 specification ++ . */ ++#if !HAVE_FDATASYNC ++extern int fdatasync(int fd); ++#endif ++ ++/* Synchronize changes, including metadata, to a file. ++ Return 0 if successful, otherwise -1 and errno set. ++ See POSIX:2008 specification ++ . */ ++#if !HAVE_FSYNC ++extern int fsync(int fd); ++#endif ++ ++/* Change the size of the file to which FD is opened to become equal to LENGTH. ++ Return 0 if successful, otherwise -1 and errno set. ++ See the POSIX:2008 specification ++ . */ ++#if !HAVE_FTRUNCATE ++extern int ftruncate(int fd, off_t length); ++#endif ++ ++/* Return the NIS domain name of the machine. ++ WARNING! The NIS domain name is unrelated to the fully qualified host name ++ of the machine. It is also unrelated to email addresses. ++ WARNING! The NIS domain name is usually the empty string or "(none)" when ++ not using NIS. ++ ++ Put up to LEN bytes of the NIS domain name into NAME. ++ Null terminate it if the name is shorter than LEN. ++ If the NIS domain name is longer than LEN, set errno = EINVAL and return -1. ++ Return 0 if successful, otherwise set errno and return -1. */ ++#if !HAVE_GETDOMAINNAME ++extern int getdomainname(char *name, size_t len); ++#endif ++ ++/* Return the maximum number of file descriptors in the current process. ++ In POSIX, this is same as sysconf (_SC_OPEN_MAX). */ ++#if !HAVE_GETDTABLESIZE ++extern int getdtablesize(void); ++#endif ++ ++/* Return the supplemental groups that the current process belongs to. ++ It is unspecified whether the effective group id is in the list. ++ If N is 0, return the group count; otherwise, N describes how many ++ entries are available in GROUPS. Return -1 and set errno if N is ++ not 0 and not large enough. Fails with ENOSYS on some systems. */ ++#if !HAVE_GETGROUPS ++extern int getgroups(int n, int *groups); ++#endif ++ ++/* Return the standard host name of the machine. ++ WARNING! The host name may or may not be fully qualified. ++ ++ Put up to LEN bytes of the host name into NAME. ++ Null terminate it if the name is shorter than LEN. ++ If the host name is longer than LEN, set errno = EINVAL and return -1. ++ Return 0 if successful, otherwise set errno and return -1. */ ++#if !HAVE_GETHOSTNAME && !(defined _WIN32 && ! defined __CYGWIN__) ++extern int gethostname(char *name, size_t len); ++#endif ++ ++/* Returns the user's login name, or NULL if it cannot be found. Upon error, ++ returns NULL with errno set. ++ ++ See . ++ ++ Most programs don't need to use this function, because the information is ++ available through environment variables: ++ ${LOGNAME-$USER} on Unix platforms, ++ $USERNAME on native Windows platforms. ++ */ ++# if !HAVE_GETLOGIN ++extern char * getlogin(void); ++#endif ++ ++/* Copies the user's login name to NAME. ++ The array pointed to by NAME has room for SIZE bytes. ++ ++ Returns 0 if successful. Upon error, an error number is returned, or -1 in ++ the case that the login name cannot be found but no specific error is ++ provided (this case is hopefully rare but is left open by the POSIX spec). ++ ++ See . ++ ++ Most programs don't need to use this function, because the information is ++ available through environment variables: ++ ${LOGNAME-$USER} on Unix platforms, ++ $USERNAME on native Windows platforms. ++ */ ++#if !HAVE_GETLOGIN_R ++extern int getlogin_r(char *name, size_t size); ++#endif ++ ++ ++/* Function getpass() from module 'getpass': ++ Read a password from /dev/tty or stdin. ++ Function getpass() from module 'getpass-gnu': ++ Read a password of arbitrary length from /dev/tty or stdin. */ ++#if !HAVE_GETPASS ++extern char * getpass(const char *prompt); ++#endif ++ ++/* Return the next valid login shell on the system, or NULL when the end of ++ the list has been reached. */ ++#if !HAVE_GETUSERSHELL ++extern char * getusershell(void); ++#endif ++ ++/* Rewind to pointer that is advanced at each getusershell() call. */ ++#if !HAVE_SETUSERSHELL ++extern void setusershell(void); ++#endif ++ ++/* Free the pointer that is advanced at each getusershell() call and ++ associated resources. */ ++#if !HAVE_ENDUSERSHELL ++extern void endusershell(void); ++#endif ++ ++/* Determine whether group id is in calling user's group list. */ ++#if !HAVE_GROUP_MEMBER ++extern int group_member(int gid); ++#endif ++ ++/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE ++ to GID (if GID is not -1). Do not follow symbolic links. ++ Return 0 if successful, otherwise -1 and errno set. ++ See the POSIX:2008 specification ++ . */ ++#if !HAVE_LCHOWN ++extern int lchown(char const *file, int owner, int group); ++#endif ++ ++/* Create a new hard link for an existing file. ++ Return 0 if successful, otherwise -1 and errno set. ++ See POSIX:2008 specification ++ . */ ++#if !HAVE_LINK ++extern int link(const char *path1, const char *path2); ++#endif ++ ++/* Create a new hard link for an existing file, relative to two ++ directories. FLAG controls whether symlinks are followed. ++ Return 0 if successful, otherwise -1 and errno set. */ ++#if !HAVE_LINKAT ++extern int linkat(int fd1, const char *path1, int fd2, const char *path2, ++ int flag); ++#endif ++ ++/* Create a pipe, defaulting to O_BINARY mode. ++ Store the read-end as fd[0] and the write-end as fd[1]. ++ Return 0 upon success, or -1 with errno set upon failure. */ ++#if !HAVE_PIPE ++extern int pipe(int fd[2]); ++#endif ++ ++/* Create a pipe, applying the given flags when opening the read-end of the ++ pipe and the write-end of the pipe. ++ The flags are a bitmask, possibly including O_CLOEXEC (defined in ) ++ and O_TEXT, O_BINARY (defined in "binary-io.h"). ++ Store the read-end as fd[0] and the write-end as fd[1]. ++ Return 0 upon success, or -1 with errno set upon failure. ++ See also the Linux man page at ++ . */ ++#if !HAVE_PIPE2 ++extern int pipe2(int fd[2], int flags); ++#endif ++ ++/* Read at most BUFSIZE bytes from FD into BUF, starting at OFFSET. ++ Return the number of bytes placed into BUF if successful, otherwise ++ set errno and return -1. 0 indicates EOF. ++ See the POSIX:2008 specification ++ . */ ++#if !HAVE_PREAD ++extern ssize_t pread(int fd, void *buf, size_t bufsize, off_t offset); ++#endif ++ ++/* Write at most BUFSIZE bytes from BUF into FD, starting at OFFSET. ++ Return the number of bytes written if successful, otherwise ++ set errno and return -1. 0 indicates nothing written. See the ++ POSIX:2008 specification ++ . */ ++#if !HAVE_PWRITE ++extern ssize_t pwrite(int fd, const void *buf, size_t bufsize, off_t offset); ++#endif ++ ++/* Read the contents of the symbolic link FILE and place the first BUFSIZE ++ bytes of it into BUF. Return the number of bytes placed into BUF if ++ successful, otherwise -1 and errno set. ++ See the POSIX:2008 specification ++ . */ ++#if !HAVE_READLINK ++extern ssize_t readlink(const char *file, char *buf, size_t bufsize); ++#endif ++ ++#if !HAVE_READLINKAT ++extern ssize_t readlinkat(int fd, char const *file, char *buf, size_t len); ++#endif ++ ++/* Set the host name of the machine. ++ The host name may or may not be fully qualified. ++ ++ Put LEN bytes of NAME into the host name. ++ Return 0 if successful, otherwise, set errno and return -1. ++ ++ Platforms with no ability to set the hostname return -1 and set ++ errno = ENOSYS. */ ++#if !HAVE_SETHOSTNAME ++extern int sethostname(const char *name, size_t len); ++#endif ++ ++/* Pause the execution of the current thread for N seconds. ++ Returns the number of seconds left to sleep. ++ See the POSIX:2008 specification ++ . */ ++#if !HAVE_SLEEP ++extern unsigned int sleep(unsigned int n); ++#endif ++ ++#if !HAVE_SYMLINK ++extern int symlink(char const *contents, char const *file); ++#endif ++ ++#if !HAVE_SYMLINKAT ++extern int symlinkat(char const *contents, int fd, char const *file); ++#endif ++ ++/* Change the size of the file designated by FILENAME to become equal to LENGTH. ++ Return 0 if successful, otherwise -1 and errno set. ++ See the POSIX:2008 specification ++ . */ ++#if !HAVE_TRUNCATE ++extern int truncate(const char *filename, off_t length); ++#endif ++ ++/* Store at most BUFLEN characters of the pathname of the terminal FD is ++ open on in BUF. Return 0 on success, otherwise an error number. */ ++#if !HAVE_TTYNAME_R ++extern int ttyname_r(int fd, char *buf, size_t buflen); ++#endif ++ ++#if !HAVE_UNLINKAT ++extern int unlinkat(int fd, char const *file, int flag); ++#endif ++ ++/* Pause the execution of the current thread for N microseconds. ++ Returns 0 on completion, or -1 on range error. ++ See the POSIX:2001 specification ++ . */ ++#if !HAVE_USLEEP ++extern int usleep(useconds_t n); ++#endif ++ ++#endif /* _@GUARD_PREFIX@_UNISTD_H */ ++ +diff --git a/install-sh b/install-sh +index a247329..8175c64 100755 +--- a/install-sh ++++ b/install-sh +@@ -1,201 +1,518 @@ +-: +-# NAME: +-# install.sh - portable version of install(1) +-# +-# SYNOPSIS: +-# install [-CNcs] [-f flags] [-i errs] [-o owner] [-g group] [-m mode] file1 file2 ... +-# install -d [-i errs] [-o owner] [-g group] [-m mode] directory ... +-# +-# DESCRIPTION: +-# Compatible with BSD install(1). Except that '-c' is always +-# true and we always move an already installed target aside as +-# this is important on many systems. Recent BSD install(1) +-# versions have a '-b' option for this. +-# +-# +-# OPTIONS: +-# -b move previous target file aside (always true). ++#!/bin/sh ++# install - install a program, script, or datafile ++ ++scriptversion=2018-03-11.20; # UTC ++ ++# This originates from X11R5 (mit/util/scripts/install.sh), which was ++# later released in X11R6 (xc/config/util/install.sh) with the ++# following copyright and license. + # +-# -B "suffix" +-# use "suffix" instead of .old for saving existing target. +-# +-# -c copy rather than move the file into place (always true). ++# Copyright (C) 1994 X Consortium + # +-# -C compare. Only install if target is missing or +-# different. ++# Permission is hereby granted, free of charge, to any person obtaining a copy ++# of this software and associated documentation files (the "Software"), to ++# deal in the Software without restriction, including without limitation the ++# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or ++# sell copies of the Software, and to permit persons to whom the Software is ++# furnished to do so, subject to the following conditions: + # +-# -N newer. Only install if target is missing or older. +-# +-# -s strip target ++# The above copyright notice and this permission notice shall be included in ++# all copies or substantial portions of the Software. + # +-# -o "owner" +-# make target owned by "owner" ++# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN ++# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- ++# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + # +-# -g "group" +-# make target group owned by "group" ++# Except as contained in this notice, the name of the X Consortium shall not ++# be used in advertising or otherwise to promote the sale, use or other deal- ++# ings in this Software without prior written authorization from the X Consor- ++# tium. + # +-# -m "mode" +-# set permissions to "mode" + # +-# -f "flags" +-# Pass "flags" onto chflags(1) +-# +-# -i "errs" +-# Ignore errors from steps indicated by "errs" (``s,o,g,m''). ++# FSF changes to this file are in the public domain. + # +-# BUGS: +-# The '-i' option is to save your sanity when 'bsd.prog.mk' +-# insists on haveing a '-o' "owner" option which is doomed to +-# fail on many systems. We ignore '-b', '-B' and '-c' options. +-# +-# AUTHOR: +-# Simon J. Gerraty ++# Calling this script install-sh is preferred over install.sh, to prevent ++# 'make' implicit rules from creating a file called install from it ++# when there is no Makefile. + # ++# This script is compatible with the BSD install script, but was written ++# from scratch. + +-# RCSid: +-# $Id: install-sh,v 1.18 2001/03/16 17:33:02 sjg Exp $ +-# +-# @(#) Copyright (c) 1993 Simon J. Gerraty +-# +-# This file is provided in the hope that it will +-# be of use. There is absolutely NO WARRANTY. +-# Permission to copy, redistribute or otherwise +-# use this file is hereby granted provided that +-# the above copyright notice and this notice are +-# left intact. +-# +-# Please send copies of changes and bug-fixes to: +-# sjg@quick.com.au +-# ++tab=' ' ++nl=' ++' ++IFS=" $tab$nl" + +-set -- `getopt B:bpxCNcsdo:g:m:i:f: $*` ++# Set DOITPROG to "echo" to test this script. + +-Mydir=`dirname $0` +-[ -s $Mydir/.installrc ] && . $Mydir/.installrc ++doit=${DOITPROG-} ++doit_exec=${doit:-exec} + +-owner=: +-group=: +-mode=: +-strip=: +-mkdirs= +-compare=: +-newer=: +-chflags=: +-LS1= +-CP_P= ++# Put in absolute file names if you don't have them in your path; ++# or use environment vars. + +-while [ $# -gt 1 ] +-do +- case $1 in +- --) shift; break;; +- -p) CP_P=-p;; +- -x) set -x;; +- -B) OLD_EXT=$2; shift;; +- -C) compare=Different;; +- -N) newer=Newer; +- # check if /bin/ls supports -1 +- /bin/ls -1 $0 >/dev/null 2>&1 && LS1=1 +- ;; +- -o) owner="${CHOWN:-chown} $2 "; shift;; +- -g) group="${CHGRP:-chgrp} $2 "; shift;; +- -m) mode="${CHMOD:-chmod} $2 "; shift;; +- -s) strip=${STRIP:-strip};; +- -d) mkdirs="mkdir -p";; +- -i) ignore_err="$ignore_err$2"; shift;; +- -f) chflags="${CHFLAGS:-chflags} $2 "; shift;; +- esac +- shift ++chgrpprog=${CHGRPPROG-chgrp} ++chmodprog=${CHMODPROG-chmod} ++chownprog=${CHOWNPROG-chown} ++cmpprog=${CMPPROG-cmp} ++cpprog=${CPPROG-cp} ++mkdirprog=${MKDIRPROG-mkdir} ++mvprog=${MVPROG-mv} ++rmprog=${RMPROG-rm} ++stripprog=${STRIPPROG-strip} ++ ++posix_mkdir= ++ ++# Desired mode of installed file. ++mode=0755 ++ ++chgrpcmd= ++chmodcmd=$chmodprog ++chowncmd= ++mvcmd=$mvprog ++rmcmd="$rmprog -f" ++stripcmd= ++ ++src= ++dst= ++dir_arg= ++dst_arg= ++ ++copy_on_change=false ++is_target_a_directory=possibly ++ ++usage="\ ++Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE ++ or: $0 [OPTION]... SRCFILES... DIRECTORY ++ or: $0 [OPTION]... -t DIRECTORY SRCFILES... ++ or: $0 [OPTION]... -d DIRECTORIES... ++ ++In the 1st form, copy SRCFILE to DSTFILE. ++In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. ++In the 4th, create DIRECTORIES. ++ ++Options: ++ --help display this help and exit. ++ --version display version info and exit. ++ ++ -c (ignored) ++ -C install only if different (preserve the last data modification time) ++ -d create directories instead of installing files. ++ -g GROUP $chgrpprog installed files to GROUP. ++ -m MODE $chmodprog installed files to MODE. ++ -o USER $chownprog installed files to USER. ++ -s $stripprog installed files. ++ -t DIRECTORY install into DIRECTORY. ++ -T report an error if DSTFILE is a directory. ++ ++Environment variables override the default commands: ++ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG ++ RMPROG STRIPPROG ++" ++ ++while test $# -ne 0; do ++ case $1 in ++ -c) ;; ++ ++ -C) copy_on_change=true;; ++ ++ -d) dir_arg=true;; ++ ++ -g) chgrpcmd="$chgrpprog $2" ++ shift;; ++ ++ --help) echo "$usage"; exit $?;; ++ ++ -m) mode=$2 ++ case $mode in ++ *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) ++ echo "$0: invalid mode: $mode" >&2 ++ exit 1;; ++ esac ++ shift;; ++ ++ -o) chowncmd="$chownprog $2" ++ shift;; ++ ++ -s) stripcmd=$stripprog;; ++ ++ -t) ++ is_target_a_directory=always ++ dst_arg=$2 ++ # Protect names problematic for 'test' and other utilities. ++ case $dst_arg in ++ -* | [=\(\)!]) dst_arg=./$dst_arg;; ++ esac ++ shift;; ++ ++ -T) is_target_a_directory=never;; ++ ++ --version) echo "$0 $scriptversion"; exit $?;; ++ ++ --) shift ++ break;; ++ ++ -*) echo "$0: invalid option: $1" >&2 ++ exit 1;; ++ ++ *) break;; ++ esac ++ shift + done + +-Newer() { +- n=`/bin/ls -t$LS1 $* 2>/dev/null | head -1` +- [ $1 = $n ] +-} +- +-Different() { +- cmp -s $* +- [ $? != 0 ] +-} +- +-Err() { +- case "$ignore_err" in +- *$1*) ;; +- *) exit 1;; +- esac +-} +- +-Setem() { +- # the order is important +- if [ ! -d $1 ]; then +- $strip $1 || Err s +- fi +- $group $1 || Err g +- $owner $1 || Err o +- $mode $1 || Err m +- $chflags $1 || Err f +- return 0 +-} +- +-# a bug in HP-UX's /bin/sh, means we need to re-set $* +-# after any calls to add_path() +-args="$*" +- +-# all this just for chown! +-add_path () { [ -d $1 ] && eval ${2:-PATH}="\$${2:-PATH}:$1"; } +-add_path /etc +-add_path /usr/etc +-add_path /sbin +-add_path /usr/sbin +- +-# restore saved $* +-set -- $args +- +-# make directories if needed +-# and ensure mode etc are as desired +-if [ "$mkdirs" ]; then +- for d in $* +- do +- [ ! -d $d ] && $mkdirs $d +- Setem $d +- done +- exit 0 # that's all we do ++# We allow the use of options -d and -T together, by making -d ++# take the precedence; this is for compatibility with GNU install. ++ ++if test -n "$dir_arg"; then ++ if test -n "$dst_arg"; then ++ echo "$0: target directory not allowed when installing a directory." >&2 ++ exit 1 ++ fi + fi + +-# install files +-if [ $# -gt 2 ]; then +- dest_dir=yes +-elif [ $# -eq 1 ]; then +- echo "what should I do with $*?" >&2 +- exit 1 ++if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then ++ # When -d is used, all remaining arguments are directories to create. ++ # When -t is used, the destination is already specified. ++ # Otherwise, the last argument is the destination. Remove it from $@. ++ for arg ++ do ++ if test -n "$dst_arg"; then ++ # $@ is not empty: it contains at least $arg. ++ set fnord "$@" "$dst_arg" ++ shift # fnord ++ fi ++ shift # arg ++ dst_arg=$arg ++ # Protect names problematic for 'test' and other utilities. ++ case $dst_arg in ++ -* | [=\(\)!]) dst_arg=./$dst_arg;; ++ esac ++ done + fi + +-# get list of files +-while [ $# -gt 1 ] +-do +- files="$files $1" +- shift +-done +-# last one is dest +-dest=$1 +-shift ++if test $# -eq 0; then ++ if test -z "$dir_arg"; then ++ echo "$0: no input file specified." >&2 ++ exit 1 ++ fi ++ # It's OK to call 'install-sh -d' without argument. ++ # This can happen when creating conditional directories. ++ exit 0 ++fi ++ ++if test -z "$dir_arg"; then ++ if test $# -gt 1 || test "$is_target_a_directory" = always; then ++ if test ! -d "$dst_arg"; then ++ echo "$0: $dst_arg: Is not a directory." >&2 ++ exit 1 ++ fi ++ fi ++fi ++ ++if test -z "$dir_arg"; then ++ do_exit='(exit $ret); exit $ret' ++ trap "ret=129; $do_exit" 1 ++ trap "ret=130; $do_exit" 2 ++ trap "ret=141; $do_exit" 13 ++ trap "ret=143; $do_exit" 15 + ++ # Set umask so as not to create temps with too-generous modes. ++ # However, 'strip' requires both read and write access to temps. ++ case $mode in ++ # Optimize common cases. ++ *644) cp_umask=133;; ++ *755) cp_umask=22;; + +-if [ "$dest_dir" = yes -a ! -d $dest ]; then +- echo "no directory $dest" >&2 +- exit 1 ++ *[0-7]) ++ if test -z "$stripcmd"; then ++ u_plus_rw= ++ else ++ u_plus_rw='% 200' ++ fi ++ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; ++ *) ++ if test -z "$stripcmd"; then ++ u_plus_rw= ++ else ++ u_plus_rw=,u+rw ++ fi ++ cp_umask=$mode$u_plus_rw;; ++ esac + fi + +-for f in $files ++for src + do +- b=`basename $f` +- if [ -d $dest ]; then +- t=$dest/$b +- else +- t=$dest +- fi +- $newer $f $t || continue +- $compare $f $t || continue +- [ -f $t ] && { mv -f $t $t.old || exit 1; } +- { cp $CP_P $f $t && Setem $t; } || exit 1 ++ # Protect names problematic for 'test' and other utilities. ++ case $src in ++ -* | [=\(\)!]) src=./$src;; ++ esac ++ ++ if test -n "$dir_arg"; then ++ dst=$src ++ dstdir=$dst ++ test -d "$dstdir" ++ dstdir_status=$? ++ else ++ ++ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command ++ # might cause directories to be created, which would be especially bad ++ # if $src (and thus $dsttmp) contains '*'. ++ if test ! -f "$src" && test ! -d "$src"; then ++ echo "$0: $src does not exist." >&2 ++ exit 1 ++ fi ++ ++ if test -z "$dst_arg"; then ++ echo "$0: no destination specified." >&2 ++ exit 1 ++ fi ++ dst=$dst_arg ++ ++ # If destination is a directory, append the input filename. ++ if test -d "$dst"; then ++ if test "$is_target_a_directory" = never; then ++ echo "$0: $dst_arg: Is a directory" >&2 ++ exit 1 ++ fi ++ dstdir=$dst ++ dstbase=`basename "$src"` ++ case $dst in ++ */) dst=$dst$dstbase;; ++ *) dst=$dst/$dstbase;; ++ esac ++ dstdir_status=0 ++ else ++ dstdir=`dirname "$dst"` ++ test -d "$dstdir" ++ dstdir_status=$? ++ fi ++ fi ++ ++ case $dstdir in ++ */) dstdirslash=$dstdir;; ++ *) dstdirslash=$dstdir/;; ++ esac ++ ++ obsolete_mkdir_used=false ++ ++ if test $dstdir_status != 0; then ++ case $posix_mkdir in ++ '') ++ # Create intermediate dirs using mode 755 as modified by the umask. ++ # This is like FreeBSD 'install' as of 1997-10-28. ++ umask=`umask` ++ case $stripcmd.$umask in ++ # Optimize common cases. ++ *[2367][2367]) mkdir_umask=$umask;; ++ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; ++ ++ *[0-7]) ++ mkdir_umask=`expr $umask + 22 \ ++ - $umask % 100 % 40 + $umask % 20 \ ++ - $umask % 10 % 4 + $umask % 2 ++ `;; ++ *) mkdir_umask=$umask,go-w;; ++ esac ++ ++ # With -d, create the new directory with the user-specified mode. ++ # Otherwise, rely on $mkdir_umask. ++ if test -n "$dir_arg"; then ++ mkdir_mode=-m$mode ++ else ++ mkdir_mode= ++ fi ++ ++ posix_mkdir=false ++ case $umask in ++ *[123567][0-7][0-7]) ++ # POSIX mkdir -p sets u+wx bits regardless of umask, which ++ # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ++ ;; ++ *) ++ # Note that $RANDOM variable is not portable (e.g. dash); Use it ++ # here however when possible just to lower collision chance. ++ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ ++ ++ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 ++ ++ # Because "mkdir -p" follows existing symlinks and we likely work ++ # directly in world-writeable /tmp, make sure that the '$tmpdir' ++ # directory is successfully created first before we actually test ++ # 'mkdir -p' feature. ++ if (umask $mkdir_umask && ++ $mkdirprog $mkdir_mode "$tmpdir" && ++ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 ++ then ++ if test -z "$dir_arg" || { ++ # Check for POSIX incompatibilities with -m. ++ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or ++ # other-writable bit of parent directory when it shouldn't. ++ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ++ test_tmpdir="$tmpdir/a" ++ ls_ld_tmpdir=`ls -ld "$test_tmpdir"` ++ case $ls_ld_tmpdir in ++ d????-?r-*) different_mode=700;; ++ d????-?--*) different_mode=755;; ++ *) false;; ++ esac && ++ $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ++ ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` ++ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" ++ } ++ } ++ then posix_mkdir=: ++ fi ++ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" ++ else ++ # Remove any dirs left behind by ancient mkdir implementations. ++ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null ++ fi ++ trap '' 0;; ++ esac;; ++ esac ++ ++ if ++ $posix_mkdir && ( ++ umask $mkdir_umask && ++ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ++ ) ++ then : ++ else ++ ++ # The umask is ridiculous, or mkdir does not conform to POSIX, ++ # or it failed possibly due to a race condition. Create the ++ # directory the slow way, step by step, checking for races as we go. ++ ++ case $dstdir in ++ /*) prefix='/';; ++ [-=\(\)!]*) prefix='./';; ++ *) prefix='';; ++ esac ++ ++ oIFS=$IFS ++ IFS=/ ++ set -f ++ set fnord $dstdir ++ shift ++ set +f ++ IFS=$oIFS ++ ++ prefixes= ++ ++ for d ++ do ++ test X"$d" = X && continue ++ ++ prefix=$prefix$d ++ if test -d "$prefix"; then ++ prefixes= ++ else ++ if $posix_mkdir; then ++ (umask=$mkdir_umask && ++ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break ++ # Don't fail if two instances are running concurrently. ++ test -d "$prefix" || exit 1 ++ else ++ case $prefix in ++ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; ++ *) qprefix=$prefix;; ++ esac ++ prefixes="$prefixes '$qprefix'" ++ fi ++ fi ++ prefix=$prefix/ ++ done ++ ++ if test -n "$prefixes"; then ++ # Don't fail if two instances are running concurrently. ++ (umask $mkdir_umask && ++ eval "\$doit_exec \$mkdirprog $prefixes") || ++ test -d "$dstdir" || exit 1 ++ obsolete_mkdir_used=true ++ fi ++ fi ++ fi ++ ++ if test -n "$dir_arg"; then ++ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && ++ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && ++ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || ++ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 ++ else ++ ++ # Make a couple of temp file names in the proper directory. ++ dsttmp=${dstdirslash}_inst.$$_ ++ rmtmp=${dstdirslash}_rm.$$_ ++ ++ # Trap to clean up those temp files at exit. ++ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 ++ ++ # Copy the file name to the temp name. ++ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && ++ ++ # and set any options; do chmod last to preserve setuid bits. ++ # ++ # If any of these fail, we abort the whole thing. If we want to ++ # ignore errors from any of these, just make sure not to ignore ++ # errors from the above "$doit $cpprog $src $dsttmp" command. ++ # ++ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && ++ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && ++ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && ++ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && ++ ++ # If -C, don't bother to copy if it wouldn't change the file. ++ if $copy_on_change && ++ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && ++ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && ++ set -f && ++ set X $old && old=:$2:$4:$5:$6 && ++ set X $new && new=:$2:$4:$5:$6 && ++ set +f && ++ test "$old" = "$new" && ++ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 ++ then ++ rm -f "$dsttmp" ++ else ++ # Rename the file to the real destination. ++ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || ++ ++ # The rename failed, perhaps because mv can't rename something else ++ # to itself, or perhaps because mv is so ancient that it does not ++ # support -f. ++ { ++ # Now remove or move aside any old file at destination location. ++ # We try this two ways since rm can't unlink itself on some ++ # systems and the destination file might be busy for other ++ # reasons. In this case, the final cleanup might fail but the new ++ # file should still install successfully. ++ { ++ test ! -f "$dst" || ++ $doit $rmcmd -f "$dst" 2>/dev/null || ++ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && ++ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } ++ } || ++ { echo "$0: cannot unlink or rename $dst" >&2 ++ (exit 1); exit 1 ++ } ++ } && ++ ++ # Now rename the file to the real destination. ++ $doit $mvcmd "$dsttmp" "$dst" ++ } ++ fi || exit 1 ++ ++ trap '' 0 ++ fi + done +-exit 0 ++ ++# Local variables: ++# eval: (add-hook 'before-save-hook 'time-stamp) ++# time-stamp-start: "scriptversion=" ++# time-stamp-format: "%:y-%02m-%02d.%02H" ++# time-stamp-time-zone: "UTC0" ++# time-stamp-end: "; # UTC" ++# End: +diff --git a/job.c b/job.c +index ddf9d40..670798d 100644 +--- a/job.c ++++ b/job.c +@@ -140,2 +140,5 @@ __RCSID("$NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $"); + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif + #include +@@ -146,13 +149,23 @@ __RCSID("$NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $"); + #include +-#if !defined(USE_SELECT) && defined(HAVE_POLL_H) +-#include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++# include "headers-mingw/poll.h" + #else +-#ifndef USE_SELECT /* no poll.h */ +-# define USE_SELECT ++# if !defined(USE_SELECT) && defined(HAVE_POLL_H) ++# include ++# else ++# ifndef USE_SELECT /* no poll.h */ ++# define USE_SELECT ++# endif ++# endif ++# if defined(HAVE_SYS_SELECT_H) ++# include ++# endif + #endif +-#if defined(HAVE_SYS_SELECT_H) +-# include ++#include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/signal.h" + #endif ++#ifndef SIGQUIT ++#define SIGQUIT SIGTERM + #endif +-#include + #include +@@ -315,4 +328,8 @@ const char *shellPath = NULL, /* full pathname of + char *shellErrFlag = NULL; +-static const char *shellArgv = NULL; /* Custom shell args */ + ++#if (defined _WIN32 && ! defined __CYGWIN__) ++const char *shellExecCmd = NULL; ++#endif ++ ++static const char *shellArgv = NULL; /* Custom shell args */ + +@@ -439,2 +456,3 @@ JobCreatePipe(Job *job, int minfd) + /* Set close-on-exec flag for both */ ++#if defined(F_SETFD) && defined(FD_CLOEXEC) && defined(F_GETFL) && defined(F_SETFL) + if (fcntl(job->jobPipe[0], F_SETFD, FD_CLOEXEC) == -1) +@@ -456,2 +474,3 @@ JobCreatePipe(Job *job, int minfd) + Punt("Cannot set flags: %s", strerror(errno)); ++#endif + } +@@ -1115,3 +1134,3 @@ JobFinish (Job *job, WAIT_T status) + } +- job->node->made = MADE; ++ job->node->made = __MADE; + if (!(job->flags & JOB_SPECIAL)) +@@ -1386,2 +1405,3 @@ JobExec(Job *job, char **argv) + } ++#if defined(F_SETFD) + if (fcntl(0, F_SETFD, 0) == -1) { +@@ -1390,2 +1410,3 @@ JobExec(Job *job, char **argv) + } ++#endif + if (lseek(0, (off_t)0, SEEK_SET) == -1) { +@@ -1394,3 +1415,3 @@ JobExec(Job *job, char **argv) + } +- ++#if defined(F_SETFD) + if (job->node->type & (OP_MAKE | OP_SUBMAKE)) { +@@ -1408,2 +1429,3 @@ JobExec(Job *job, char **argv) + } ++#endif + +@@ -1423,2 +1445,3 @@ JobExec(Job *job, char **argv) + */ ++#if defined(F_SETFD) + if (fcntl(1, F_SETFD, 0) == -1) { +@@ -1427,2 +1450,3 @@ JobExec(Job *job, char **argv) + } ++#endif + if (dup2(1, 2) == -1) { +@@ -1439,9 +1463,7 @@ JobExec(Job *job, char **argv) + (void)setpgid(0, getpid()); +-#else +-#if defined(HAVE_SETSID) ++#elif defined(HAVE_SETSID) + /* XXX: dsl - I'm sure this should be setpgrp()... */ + (void)setsid(); +-#else ++#elif defined(HAVE_SETPGRP) + (void)setpgrp(0, getpid()); +-#endif + #endif +@@ -1642,3 +1664,5 @@ JobStart(GNode *gn, int flags) + } ++#if defined(F_SETFD) + (void)fcntl(FILENO(job->cmdFILE), F_SETFD, FD_CLOEXEC); ++#endif + /* +@@ -1734,3 +1758,3 @@ JobStart(GNode *gn, int flags) + } +- job->node->made = MADE; ++ job->node->made = __MADE; + Make_Update(job->node); +@@ -1983,3 +2007,3 @@ JobRun(GNode *targ) + Compat_Make(targ, targ); +- if (targ->made == ERROR) { ++ if (targ->made == __ERROR) { + PrintOnError(targ, "\n\nStop."); +@@ -2063,2 +2087,3 @@ JobReapChild(pid_t pid, WAIT_T status, Boolean isJobs) + switch (WSTOPSIG(status)) { ++#if defined(SIGTSTP) + case SIGTSTP: +@@ -2066,2 +2091,3 @@ JobReapChild(pid_t pid, WAIT_T status, Boolean isJobs) + break; ++#endif + case SIGSTOP: +@@ -2191,2 +2217,7 @@ Shell_Init(void) + } ++#if (defined _WIN32 && ! defined __CYGWIN__) ++ if (shellExecCmd == NULL) { ++ shellExecCmd = getShellLaunchPrefix(); ++ } ++#endif + if (commandShell->exit == NULL) { +@@ -2301,2 +2332,3 @@ Job_Init(void) + sigemptyset(&caught_signals); ++#if defined(SIGCHLD) + /* +@@ -2306,2 +2338,3 @@ Job_Init(void) + sigaddset(&caught_signals, SIGCHLD); ++#endif + +@@ -2318,3 +2351,5 @@ Job_Init(void) + ADDSIG(SIGINT, JobPassSig_int) ++#if defined(SIGHUP) + ADDSIG(SIGHUP, JobPassSig_term) ++#endif + ADDSIG(SIGTERM, JobPassSig_term) +@@ -2328,7 +2363,17 @@ Job_Init(void) + */ ++#if defined(SIGTSTP) + ADDSIG(SIGTSTP, JobPassSig_suspend) ++#endif ++#if defined(SIGTTOU) + ADDSIG(SIGTTOU, JobPassSig_suspend) ++#endif ++#if defined(SIGTTIN) + ADDSIG(SIGTTIN, JobPassSig_suspend) ++#endif ++#if defined(SIGWINCH) + ADDSIG(SIGWINCH, JobCondPassSig) ++#endif ++#if defined(SIGCONT) + ADDSIG(SIGCONT, JobContinueSig) ++#endif + #undef ADDSIG +@@ -2347,12 +2392,26 @@ static void JobSigReset(void) + DELSIG(SIGINT) ++#if defined(SIGHUP) + DELSIG(SIGHUP) ++#endif + DELSIG(SIGQUIT) + DELSIG(SIGTERM) ++#if defined(SIGTSTP) + DELSIG(SIGTSTP) ++#endif ++#if defined(SIGTTOU) + DELSIG(SIGTTOU) ++#endif ++#if defined(SIGTTIN) + DELSIG(SIGTTIN) ++#endif ++#if defined(SIGWINCH) + DELSIG(SIGWINCH) ++#endif ++#if defined(SIGCONT) + DELSIG(SIGCONT) ++#endif + #undef DELSIG ++#if defined(SIGCHLD) + (void)bmake_signal(SIGCHLD, SIG_DFL); ++#endif + } +@@ -2791,2 +2850,3 @@ JobRestartJobs(void) + job->job_suspended = 0; ++#if defined(SIGCONT) + if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) { +@@ -2794,2 +2854,3 @@ JobRestartJobs(void) + } ++#endif + } +@@ -2888,4 +2949,6 @@ Job_ServerStart(int max_tokens, int jp_0, int jp_1) + tokenWaitJob.outPipe = jp_1; ++#if defined(F_SETFD) + (void)fcntl(jp_0, F_SETFD, FD_CLOEXEC); + (void)fcntl(jp_1, F_SETFD, FD_CLOEXEC); ++#endif + return; +@@ -3022,3 +3085,3 @@ Job_RunTarget(const char *target, const char *fname) { + JobRun(gn); +- if (gn->made == ERROR) { ++ if (gn->made == __ERROR) { + PrintOnError(gn, "\n\nStop."); +diff --git a/job.h b/job.h +index 91e2c87..ca8e093 100644 +--- a/job.h ++++ b/job.h +@@ -246,2 +246,5 @@ extern const char *shellName; + extern char *shellErrFlag; ++#if (defined _WIN32 && ! defined __CYGWIN__) ++extern const char *shellExecCmd; ++#endif + +diff --git a/main.c b/main.c +index 7dd4c50..76e319e 100644 +--- a/main.c ++++ b/main.c +@@ -118,4 +118,11 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); + #include ++#ifdef HAVE_SYS_RESOURCE_H + #include ++#else ++#include "headers-mingw/resource.h" ++#endif + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif + #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) +@@ -123,3 +130,8 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); + #endif ++ ++#ifdef HAVE_SYS_UTSNAME_H + #include ++#else ++#include "headers-mingw/sys_utsname.h" ++#endif + #include "wait.h" +@@ -128,2 +140,8 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/signal.h" ++#endif ++#ifndef SIGQUIT ++#define SIGQUIT SIGTERM ++#endif + #include +@@ -131,2 +149,5 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/stdlib.h" ++#endif + #include +@@ -141,2 +162,6 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); + ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include ++#endif ++ + #ifdef USE_IOVEC +@@ -153,2 +178,4 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); + ++FILE *debug_file; /* Output written here - default stdout */ ++ + Lst create; /* Targets to be made */ +@@ -196,2 +223,4 @@ static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ + char curdir[MAXPATHLEN + 1]; /* Startup directory */ ++char *pcurdir; ++char *pobjdir; + char *progname; /* the program name */ +@@ -764,3 +793,3 @@ Main_SetObjdir(const char *fmt, ...) + +- if (path[0] != '/') { ++ if (path[0] != '/' && curdir[0] == '/') { //because directory path could start not from '/' (example: Windows OS family) + snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); +@@ -776,4 +805,13 @@ Main_SetObjdir(const char *fmt, ...) + strncpy(objdir, path, MAXPATHLEN); +- Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); +- setenv("PWD", objdir, 1); ++#if (defined _WIN32 && ! defined __CYGWIN__) ++ pobjdir = str_replace_char(objdir, '\\', '/'); ++ if (pobjdir[1] == ':') { // create msys-style windows path ++ pobjdir[1] = pobjdir[0]; ++ pobjdir[0] = '/'; ++ } ++#else ++ pobjdir = objdir; ++#endif ++ Var_Set(".OBJDIR", pobjdir, VAR_GLOBAL, 0); ++ setenv("PWD", pobjdir, 1); + Dir_InitDot(); +@@ -990,2 +1028,4 @@ main(int argc, char **argv) + char mdpath[MAXPATHLEN]; ++ const char *error; ++ + #ifdef FORCE_MACHINE +@@ -1017,3 +1057,9 @@ main(int argc, char **argv) + srandom(rightnow.tv_sec + rightnow.tv_usec); +- ++ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++ if ((progname = strrchr(argv[0], '\\')) != NULL) ++ progname++; ++ else ++ progname = argv[0]; ++#else + if ((progname = strrchr(argv[0], '/')) != NULL) +@@ -1022,3 +1068,4 @@ main(int argc, char **argv) + progname = argv[0]; +-#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) ++#endif ++#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) + /* +@@ -1165,2 +1212,11 @@ main(int argc, char **argv) + } ++ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++// p1 = str_replace_char(p1, '\\', '/'); ++// if (p1[1] == ':') { // create msys-style windows path ++// p1[1] = p1[0]; ++// p1[0] = '/'; ++// } ++p1 = Cmd_Exec(getUnixPathCmd(p1), &error); ++#endif + Var_Set("MAKE", p1, VAR_GLOBAL, 0); +@@ -1187,4 +1243,6 @@ main(int argc, char **argv) + Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); ++#ifdef HAVE_GETPPID + snprintf(tmp, sizeof(tmp), "%u", getppid()); + Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); ++#endif + } +@@ -1269,3 +1327,13 @@ main(int argc, char **argv) + #endif +- Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); ++#if (defined _WIN32 && ! defined __CYGWIN__) ++// pcurdir = str_replace_char(curdir, '\\', '/'); ++// if (pcurdir[1] == ':') { // create msys-style windows path ++// pcurdir[1] = pcurdir[0]; ++// pcurdir[0] = '/'; ++// } ++pcurdir = Cmd_Exec(getUnixPathCmd(curdir), &error); ++#else ++ pcurdir = curdir; ++#endif ++ Var_Set(".CURDIR", pcurdir, VAR_GLOBAL, 0); + +@@ -1607,4 +1675,2 @@ found: + +- +- + /*- +@@ -1625,3 +1691,7 @@ Cmd_Exec(const char *cmd, const char **errnum) + const char *args[4]; /* Args for invoking the shell */ ++#if !(defined _WIN32 && ! defined __CYGWIN__) + int fds[2]; /* Pipe streams */ ++#else ++ FILE * fds[2]; ++#endif + int cpid; /* Child PID */ +@@ -1629,4 +1699,16 @@ Cmd_Exec(const char *cmd, const char **errnum) + char *res; /* result */ ++#if !(defined _WIN32 && ! defined __CYGWIN__) + WAIT_T status; /* command exit status */ + Buffer buf; /* buffer to store the result */ ++#else ++ const char *sysRootPath = getenv("SYSROOTWINDOWSPATH"); ++ int status; ++ char command[4096] = ""; /* generated cmd string for launch */ ++ char escapedCmd[4096] = ""; ++ char escapedCmdLaunchList[4096] = ""; /* temporary string */ ++ static char stdout_data[16 * 1024 * 1024] = ""; //stdout ++ static char stderr_data[16 * 1024 * 1024] = ""; ++ int exit_code = 0; ++#endif ++ + char *cp; +@@ -1636,2 +1718,3 @@ Cmd_Exec(const char *cmd, const char **errnum) + ++ + *errnum = NULL; +@@ -1643,4 +1726,10 @@ Cmd_Exec(const char *cmd, const char **errnum) + */ ++#if !(defined _WIN32 && ! defined __CYGWIN__) + args[0] = shellName; + args[1] = "-c"; ++#else ++ args[0] = str_concat(sysRootPath, "usr\\bin\\bash.exe", 0); ++ args[1] = "-lc"; ++#endif ++ + args[2] = cmd; +@@ -1648,2 +1737,3 @@ Cmd_Exec(const char *cmd, const char **errnum) + ++#if !(defined _WIN32 && ! defined __CYGWIN__) + /* +@@ -1656,2 +1746,3 @@ Cmd_Exec(const char *cmd, const char **errnum) + ++ + /* +@@ -1661,2 +1752,3 @@ Cmd_Exec(const char *cmd, const char **errnum) + case 0: ++ + /* +@@ -1673,5 +1765,7 @@ Cmd_Exec(const char *cmd, const char **errnum) + (void)close(fds[1]); +- ++#endif + Var_ExportVars(); + ++#if !(defined _WIN32 && ! defined __CYGWIN__) ++ + (void)execv(shellPath, UNCONST(args)); +@@ -1685,7 +1779,41 @@ Cmd_Exec(const char *cmd, const char **errnum) + default: +- /* +- * No need for the writing half +- */ +- (void)close(fds[1]); ++ /* ++ * No need for the writing half ++ */ ++ (void)close(fds[1]); ++#else ++// str_escape(escapedCmd, args[2], 4096); ++// strncpy(command, str_concat(shellExecCmd, ++// str_concat("\"", ++// str_concat(str_concat(args[0], ++// str_concat(args[1], ++// str_concat("'", ++// str_concat(escapedCmd, "'", 0), ++// 0), ++// STR_ADDSPACE), ++// STR_ADDSPACE), "\"", 0), ++// 0), ++// STR_ADDSPACE), 4096); ++// fds[0] = _popen(command, "rb"); ++// if (fds[0] == NULL) { ++// savederr = errno; ++// } ++ str_escape_dblquote(escapedCmd, cmd, 4096); ++ strncpy(command, ++// str_concat("\"", ++// str_concat( ++ str_concat(args[0], ++ str_concat(args[1], ++ str_concat("\"", ++ str_concat(escapedCmd, "\"", 0), ++ 0), ++ STR_ADDSPACE), ++ STR_ADDSPACE), ++// , "\"", 0), ++// 0), ++ 4096); ++ status = system_np(command, 100 * 1000, stdout_data, sizeof(stdout_data), stderr_data, sizeof(stderr_data), &exit_code); ++#endif + ++#if !(defined _WIN32 && ! defined __CYGWIN__) + savederr = 0; +@@ -1715,2 +1843,3 @@ Cmd_Exec(const char *cmd, const char **errnum) + } ++ + cc = Buf_Size(&buf); +@@ -1720,7 +1849,16 @@ Cmd_Exec(const char *cmd, const char **errnum) + *errnum = "Couldn't read shell's output for \"%s\""; ++#else ++ cc = strlen(stdout_data); ++ res = bmake_malloc(cc + 1); ++ strncpy(res, stdout_data, cc); ++#endif + ++#if !(defined _WIN32 && ! defined __CYGWIN__) + if (WIFSIGNALED(status)) + *errnum = "\"%s\" exited on a signal"; +- else if (WEXITSTATUS(status) != 0) ++ else if (WEXITSTATUS(status) != 0) { ++ + *errnum = "\"%s\" returned non-zero status"; ++ } ++#endif + +@@ -1745,4 +1883,6 @@ Cmd_Exec(const char *cmd, const char **errnum) + } ++#if !(defined _WIN32 && ! defined __CYGWIN__) + break; + } ++#endif + return res; +@@ -2118,3 +2258,4 @@ getTmpdir(void) + */ +- tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, ++ tmpdir = Var_Subst(NULL, str_concat( ++ str_concat("${TMPDIR:tA:U", _PATH_TMP, 0), "}/", 0), VAR_GLOBAL, + VARF_WANTRES); +diff --git a/make-bootstrap.sh.in b/make-bootstrap.sh.in +index a394272..f74bc72 100755 +--- a/make-bootstrap.sh.in ++++ b/make-bootstrap.sh.in +@@ -24,2 +24,13 @@ LDFLAGS="@LDFLAGS@" + LIBS="@LIBS@" ++MACHINE="@machine@" ++ ++if [ "$(expr substr ${MACHINE} 1 5)" == "mingw" ]; then ++ LIBS+=" -lws2_32 -lwsock32" ++ CFLAGS+="" ++fi ++ ++if [ "$(expr substr ${MACHINE} 1 7)" == "mingw32" ]; then ++ LIBS+=" -liconv -lkernel32" ++ CFLAGS+="" ++fi + +diff --git a/make.1 b/make.1 +index 2a2237f..968f006 100644 +--- a/make.1 ++++ b/make.1 +@@ -1927,3 +1927,3 @@ as if they all were preceded by a dash + .\" XXX +-.It Ic .MADE ++.It Ic .__MADE + Mark all sources of this target as being up-to-date. +@@ -2089,3 +2089,3 @@ Any command lines attached to this target are executed after everything + else is done. +-.It Ic .ERROR ++.It Ic .__ERROR + Any command lines attached to this target are executed when another target fails. +diff --git a/make.c b/make.c +index 8947582..796202c 100644 +--- a/make.c ++++ b/make.c +@@ -703,3 +703,3 @@ Make_Update(GNode *cgn) + */ +- if (cgn->made != UPTODATE) { ++ if (cgn->made != __UPTODATE) { + mtime = Make_Recheck(cgn); +@@ -759,3 +759,3 @@ Make_Update(GNode *cgn) + if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) { +- if (cgn->made == MADE) ++ if (cgn->made == __MADE) + pgn->flags |= CHILDMADE; +@@ -768,3 +768,3 @@ Make_Update(GNode *cgn) + */ +- if (centurion->unmade_cohorts != 0 || centurion->made < MADE) { ++ if (centurion->unmade_cohorts != 0 || centurion->made < __MADE) { + if (DEBUG(MAKE)) +@@ -794,3 +794,3 @@ Make_Update(GNode *cgn) + } +- if (pgn->made != DEFERRED) { ++ if (pgn->made != __DEFERRED) { + /* +@@ -817,3 +817,3 @@ Make_Update(GNode *cgn) + /* Ok, we can schedule the parent again */ +- pgn->made = REQUESTED; ++ pgn->made = __REQUESTED; + (void)Lst_EnQueue(toBeMade, pgn); +@@ -908,3 +908,3 @@ MakeAddAllSrc(void *cgnp, void *pgnp) + if (pgn->type & OP_JOIN) { +- if (cgn->made == MADE) { ++ if (cgn->made == __MADE) { + Var_Append(OODATE, child, pgn); +@@ -912,3 +912,3 @@ MakeAddAllSrc(void *cgnp, void *pgnp) + } else if ((pgn->mtime < cgn->mtime) || +- (cgn->mtime >= now && cgn->made == MADE)) ++ (cgn->mtime >= now && cgn->made == __MADE)) + { +@@ -1005,3 +1005,3 @@ MakeCheckOrder(void *v_bn, void *ignore MAKE_ATTR_UNUSED) + +- if (bn->made >= MADE || !(bn->flags & REMAKE)) ++ if (bn->made >= __MADE || !(bn->flags & REMAKE)) + return 0; +@@ -1021,3 +1021,3 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) + cn->name, cn->cohort_num, cn->made, cn->type); +- if (cn->made > DEFERRED) ++ if (cn->made > __DEFERRED) + return 0; +@@ -1027,3 +1027,3 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) + /* Can't build this (or anything else in this child list) yet */ +- cn->made = DEFERRED; ++ cn->made = __DEFERRED; + return 0; /* but keep looking */ +@@ -1035,3 +1035,3 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) + +- cn->made = REQUESTED; ++ cn->made = __REQUESTED; + if (toBeMade_next == NULL) +@@ -1057,3 +1057,3 @@ MakeBuildParent(void *v_pn, void *toBeMade_next) + +- if (pn->made != DEFERRED) ++ if (pn->made != __DEFERRED) + return 0; +@@ -1085,3 +1085,3 @@ MakeStartJobs(void) + +- if (gn->made != REQUESTED) { ++ if (gn->made != __REQUESTED) { + if (DEBUG(MAKE)) +@@ -1097,3 +1097,3 @@ MakeStartJobs(void) + gn->name, gn->cohort_num); +- gn->made = DEFERRED; ++ gn->made = __DEFERRED; + continue; +@@ -1107,3 +1107,3 @@ MakeStartJobs(void) + */ +- gn->made = DEFERRED; ++ gn->made = __DEFERRED; + Lst_ForEach(gn->children, MakeBuildChild, Lst_First(toBeMade)); +@@ -1115,3 +1115,3 @@ MakeStartJobs(void) + +- gn->made = BEINGMADE; ++ gn->made = __BEINGMADE; + if (Make_OODate(gn)) { +@@ -1130,3 +1130,3 @@ MakeStartJobs(void) + } +- gn->made = UPTODATE; ++ gn->made = __UPTODATE; + if (gn->type & OP_JOIN) { +@@ -1177,3 +1177,3 @@ MakePrintStatusOrder(void *ognp, void *gnp) + +- if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED) ++ if (!(ogn->flags & REMAKE) || ogn->made > __REQUESTED) + /* not waiting for this one */ +@@ -1206,11 +1206,11 @@ MakePrintStatus(void *gnp, void *v_errors) + switch (gn->made) { +- case UPTODATE: ++ case __UPTODATE: + printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num); + break; +- case MADE: ++ case __MADE: + break; +- case UNMADE: +- case DEFERRED: +- case REQUESTED: +- case BEINGMADE: ++ case __UNMADE: ++ case __DEFERRED: ++ case __REQUESTED: ++ case __BEINGMADE: + (*errors)++; +diff --git a/make.h b/make.h +index c14b2c6..ea864b4 100644 +--- a/make.h ++++ b/make.h +@@ -91,4 +91,10 @@ + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/fcntl.h" ++#endif + #include + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/stdlib.h" ++#endif + #ifdef HAVE_STRING_H +@@ -99,2 +105,5 @@ + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/unistd.h" ++#endif + #include +@@ -203,4 +212,4 @@ typedef struct GNode { + enum enum_made { +- UNMADE, DEFERRED, REQUESTED, BEINGMADE, +- MADE, UPTODATE, ERROR, ABORTED ++ __UNMADE, __DEFERRED, __REQUESTED, __BEINGMADE, ++ __MADE, __UPTODATE, __ERROR, __ABORTED + } made; /* Set to reflect the state of processing +@@ -437,2 +446,3 @@ extern Lst defIncPath; /* The default include path. */ + extern char curdir[]; /* Startup directory */ ++extern char *pcurdir; /* Startup directory */ + extern char *progname; /* The program name */ +@@ -466,3 +476,3 @@ extern pid_t myPid; + */ +-FILE *debug_file; /* Output written here - default stdout */ ++extern FILE *debug_file; /* Output written here - default stdout */ + extern int debug; +@@ -552,2 +562,12 @@ int cached_stat(const char *, void *); + ++size_t str_escape(char *dst, const char *src, size_t dstLen); ++ ++size_t str_escape_dblquote(char *dst, const char *src, size_t dstLen); ++ ++char * str_replace_char(const char *s, const char toReplace, const char replacement); ++ ++extern int system_np(const char* command, int timeout_milliseconds, ++ char* stdout_data, int stdout_data_size, ++ char* stderr_data, int stderr_data_size, int* exit_code); ++ + #endif /* _MAKE_H_ */ +diff --git a/makefile.in b/makefile.in +deleted file mode 100644 +index 03b980a..0000000 +--- a/makefile.in ++++ /dev/null +@@ -1,14 +0,0 @@ +-# $Id: makefile.in,v 1.1 2012/12/28 21:28:19 sjg Exp $ +- +-# a simple makefile for those who don't like anything beyond: +-# ./configure; make; make install +- +-prefix= @prefix@ +-srcdir= @srcdir@ +- +-all: build +- +-build clean install test: +- ${srcdir}/boot-strap --prefix=${prefix} -o . op=$@ +- +- +diff --git a/meta.c b/meta.c +index a852f3f..cd8c459 100644 +--- a/meta.c ++++ b/meta.c +@@ -38,3 +38,10 @@ + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_ioctl.h" ++#else + #include ++#endif + #ifdef HAVE_LIBGEN_H +@@ -1613,4 +1620,6 @@ meta_compat_start(void) + /* Set close-on-exec flag for both */ ++#if defined(F_SETFD) && defined(FD_CLOEXEC) + (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC); + (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC); ++#endif + } +diff --git a/mk/ChangeLog b/mk/ChangeLog +index ce8ac53..460ac78 100644 +--- a/mk/ChangeLog ++++ b/mk/ChangeLog +@@ -946,4 +946,4 @@ + read-only manually maintained dependencies. +- o meta2deps.py add a clear 'ERROR:' token if an exception is raised. +- o gendirdeps.mk if ERROR: from meta2deps.py do not update ++ o meta2deps.py add a clear '__ERROR:' token if an exception is raised. ++ o gendirdeps.mk if __ERROR: from meta2deps.py do not update + anything. +diff --git a/mk/gendirdeps.mk b/mk/gendirdeps.mk +index e04f839..5899574 100644 +--- a/mk/gendirdeps.mk ++++ b/mk/gendirdeps.mk +@@ -196,4 +196,4 @@ dir_list != cd ${_OBJDIR} && \ + +-.if ${dir_list:M*ERROR\:*} != "" +-.warning ${dir_list:tW:C,.*(ERROR),\1,} ++.if ${dir_list:M*__ERROR\:*} != "" ++.warning ${dir_list:tW:C,.*(__ERROR),\1,} + .warning Skipping ${_DEPENDFILE:S,${SRCTOP}/,,} +diff --git a/mk/host-target.mk b/mk/host-target.mk +index f528db9..1ab05b0 100644 +--- a/mk/host-target.mk ++++ b/mk/host-target.mk +@@ -5,3 +5,3 @@ + .if !defined(_HOST_OSNAME) +-_HOST_OSNAME != uname -s ++_HOST_OSNAME != uname -s | cut -d_ -f1 + .export _HOST_OSNAME +diff --git a/mk/install-mk b/mk/install-mk +index 886c264..05f385d 100644 +--- a/mk/install-mk ++++ b/mk/install-mk +@@ -115,3 +115,3 @@ Do() { + Error() { +- echo "ERROR: $@" >&2 ++ echo "__ERROR: $@" >&2 + exit 1 +diff --git a/mk/meta.autodep.mk b/mk/meta.autodep.mk +index 9cb3f14..8c84502 100644 +--- a/mk/meta.autodep.mk ++++ b/mk/meta.autodep.mk +@@ -316,3 +316,3 @@ _reldir_failed: .NOMETA + .END: _reldir_finish +-.ERROR: _reldir_failed ++.__ERROR: _reldir_failed + .endif +diff --git a/mk/meta.stage.mk b/mk/meta.stage.mk +index 320ffcc..d4f8a68 100644 +--- a/mk/meta.stage.mk ++++ b/mk/meta.stage.mk +@@ -67,3 +67,3 @@ LN_CP_SCRIPT = LnCp() { \ + # a warning is handy when bootstapping different options. +-STAGE_CONFLICT?= ERROR ++STAGE_CONFLICT?= __ERROR + .if ${STAGE_CONFLICT:tl} == "error" +diff --git a/mk/meta.sys.mk b/mk/meta.sys.mk +index 4dbdd79..de0e3b1 100644 +--- a/mk/meta.sys.mk ++++ b/mk/meta.sys.mk +@@ -20,3 +20,3 @@ + .if ${MAKE_VERSION:U0} > 20100901 +-.if !target(.ERROR) ++.if !target(.__ERROR) + +@@ -94,3 +94,3 @@ meta_error_log = ${ERROR_LOGDIR}/meta-${.MAKE.PID}.log + # we are not interested in make telling us a failure happened elsewhere +-.ERROR: _metaError ++.__ERROR: _metaError + _metaError: .NOMETA .NOTMAIN +@@ -100,3 +100,3 @@ _metaError: .NOMETA .NOTMAIN + cp ${.ERROR_META_FILE} ${meta_error_log}; \ +- echo "ERROR: log ${meta_error_log}" >&2; }; : ++ echo "__ERROR: log ${meta_error_log}" >&2; }; : + +@@ -139,3 +139,3 @@ UPDATE_DEPENDFILE= NO + .elif !exists(/dev/filemon) +-.error ${.newline}ERROR: The filemon module (/dev/filemon) is not loaded. ++.error ${.newline}__ERROR: The filemon module (/dev/filemon) is not loaded. + .endif +diff --git a/mk/own.mk b/mk/own.mk +index 4c8425b..37be01b 100644 +--- a/mk/own.mk ++++ b/mk/own.mk +@@ -196,3 +196,3 @@ SHAREMODE?= ${NONBINMODE} + COPY?= -c +-STRIP_FLAG?= -s ++STRIP_FLAG?= + +diff --git a/mk/prog.mk b/mk/prog.mk +index 4bc6260..11bf182 100644 +--- a/mk/prog.mk ++++ b/mk/prog.mk +@@ -26,3 +26,3 @@ CFLAGS+= -mcmodel=medlow + LIBCRTBEGIN= ${DESTDIR}/usr/lib/crtbegin.o +-.MADE: ${LIBCRTBEGIN} ++.__MADE: ${LIBCRTBEGIN} + .endif +@@ -30,3 +30,3 @@ LIBCRTBEGIN= ${DESTDIR}/usr/lib/crtbegin.o + LIBCRTEND= ${DESTDIR}/usr/lib/crtend.o +-.MADE: ${LIBCRTEND} ++.__MADE: ${LIBCRTEND} + .endif +@@ -41,3 +41,3 @@ _SHLINKER= ${SHLINKDIR}/ld.so + LIBCRT0= ${DESTDIR}/usr/lib/crt0.o +-.MADE: ${LIBCRT0} ++.__MADE: ${LIBCRT0} + .endif +@@ -181,3 +181,3 @@ proginstall: + ${INSTALL} ${COPY} ${STRIP_FLAG} ${PROG_INSTALL_OWN} -m ${BINMODE} \ +- ${PROG} ${DESTDIR}${BINDIR}/${PROG_NAME} ++ ${OBJTOP:tA}/${PROG} ${DESTDIR}${BINDIR}/${PROG_NAME} + .endif +diff --git a/mk/sys/MINGW32.mk b/mk/sys/MINGW32.mk +new file mode 100644 +index 0000000..10da919 +--- /dev/null ++++ b/mk/sys/MINGW32.mk +@@ -0,0 +1,185 @@ ++# $Id: Linux.mk,v 1.9 2017/05/05 18:02:16 sjg Exp $ ++# $NetBSD: sys.mk,v 1.19.2.1 1994/07/26 19:58:31 cgd Exp $ ++# @(#)sys.mk 5.11 (Berkeley) 3/13/91 ++ ++OS?= Windows ++unix?= We run ${OS}. ++ ++ROOT_GROUP= ++ ++# would be better to work out where it is... ++LIBCRT0= /dev/null ++ ++NEED_SOLINKS=yes ++ ++.SUFFIXES: .out .a .ln .o .c ${CXX_SUFFIXES} .F .f .r .y .l .s .S .cl .p .h .sh .m4 ++ ++.LIBS: .a ++ ++AR= ar ++ARFLAGS= rl ++RANLIB= ranlib ++ ++AS= as ++AFLAGS= ++COMPILE.s= ${AS} ${AFLAGS} ++LINK.s= ${CC} ${AFLAGS} ${LDFLAGS} ++COMPILE.S= ${CC} ${AFLAGS} ${CPPFLAGS} -c ++LINK.S= ${CC} ${AFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++CC= gcc -pipe ++DBG= -O -g ++STATIC?= -static ++ ++CFLAGS= ${DBG} ++COMPILE.c= ${CC} ${CFLAGS} ${CPPFLAGS} -c ++LINK.c= ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++CXX= g++ ++CXXFLAGS= ${CFLAGS} ++COMPILE.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c ++LINK.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++CPP= cpp ++.if defined(DESTDIR) ++CPPFLAGS+= -nostdinc -idirafter ${DESTDIR}/usr/include ++.endif ++ ++MK_DEP= mkdeps.sh -N ++FC= f77 ++FFLAGS= -O ++RFLAGS= ++COMPILE.f= ${FC} ${FFLAGS} -c ++LINK.f= ${FC} ${FFLAGS} ${LDFLAGS} ++COMPILE.F= ${FC} ${FFLAGS} ${CPPFLAGS} -c ++LINK.F= ${FC} ${FFLAGS} ${CPPFLAGS} ${LDFLAGS} ++COMPILE.r= ${FC} ${FFLAGS} ${RFLAGS} -c ++LINK.r= ${FC} ${FFLAGS} ${RFLAGS} ${LDFLAGS} ++ ++LEX= lex ++LFLAGS= ++LEX.l= ${LEX} ${LFLAGS} ++ ++LD= ld ++LDFLAGS= ++ ++LINT= lint ++LINTFLAGS= -chapbx ++ ++PC= pc ++PFLAGS= ++COMPILE.p= ${PC} ${PFLAGS} ${CPPFLAGS} -c ++LINK.p= ${PC} ${PFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++SHELL= sh ++ ++YACC= yacc ++YFLAGS= -d ++YACC.y= ${YACC} ${YFLAGS} ++ ++# C ++.c: ++ ${LINK.c} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.c.o: ++ ${COMPILE.c} ${.IMPSRC} ++.c.a: ++ ${COMPILE.c} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# C++ ++${CXX_SUFFIXES}: ++ ${LINK.cc} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++${CXX_SUFFIXES:%=%.o}: ++ ${COMPILE.cc} ${.IMPSRC} ++${CXX_SUFFIXES:%=%.a}: ++ ${COMPILE.cc} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Fortran/Ratfor ++.f: ++ ${LINK.f} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.f.o: ++ ${COMPILE.f} ${.IMPSRC} ++.f.a: ++ ${COMPILE.f} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++.F: ++ ${LINK.F} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.F.o: ++ ${COMPILE.F} ${.IMPSRC} ++.F.a: ++ ${COMPILE.F} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++.r: ++ ${LINK.r} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.r.o: ++ ${COMPILE.r} ${.IMPSRC} ++.r.a: ++ ${COMPILE.r} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Pascal ++.p: ++ ${LINK.p} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.p.o: ++ ${COMPILE.p} ${.IMPSRC} ++.p.a: ++ ${COMPILE.p} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Assembly ++.s: ++ ${LINK.s} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.s.o: ++ ${COMPILE.s} -o ${.TARGET} ${.IMPSRC} ++.s.a: ++ ${COMPILE.s} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++.S: ++ ${LINK.S} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.S.o: ++ ${COMPILE.S} ${.IMPSRC} ++.S.a: ++ ${COMPILE.S} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Lex ++.l: ++ ${LEX.l} ${.IMPSRC} ++ ${LINK.c} -o ${.TARGET} lex.yy.c ${LDLIBS} -ll ++ rm -f lex.yy.c ++.l.c: ++ ${LEX.l} ${.IMPSRC} ++ mv lex.yy.c ${.TARGET} ++.l.o: ++ ${LEX.l} ${.IMPSRC} ++ ${COMPILE.c} -o ${.TARGET} lex.yy.c ++ rm -f lex.yy.c ++ ++# Yacc ++.y: ++ ${YACC.y} ${.IMPSRC} ++ ${LINK.c} -o ${.TARGET} y.tab.c ${LDLIBS} ++ rm -f y.tab.c ++.y.c: ++ ${YACC.y} ${.IMPSRC} ++ mv y.tab.c ${.TARGET} ++.y.o: ++ ${YACC.y} ${.IMPSRC} ++ ${COMPILE.c} -o ${.TARGET} y.tab.c ++ rm -f y.tab.c ++ ++# Shell ++.sh: ++ rm -f ${.TARGET} ++ cp ${.IMPSRC} ${.TARGET} +diff --git a/mk/sys/MINGW64.mk b/mk/sys/MINGW64.mk +new file mode 100644 +index 0000000..10da919 +--- /dev/null ++++ b/mk/sys/MINGW64.mk +@@ -0,0 +1,185 @@ ++# $Id: Linux.mk,v 1.9 2017/05/05 18:02:16 sjg Exp $ ++# $NetBSD: sys.mk,v 1.19.2.1 1994/07/26 19:58:31 cgd Exp $ ++# @(#)sys.mk 5.11 (Berkeley) 3/13/91 ++ ++OS?= Windows ++unix?= We run ${OS}. ++ ++ROOT_GROUP= ++ ++# would be better to work out where it is... ++LIBCRT0= /dev/null ++ ++NEED_SOLINKS=yes ++ ++.SUFFIXES: .out .a .ln .o .c ${CXX_SUFFIXES} .F .f .r .y .l .s .S .cl .p .h .sh .m4 ++ ++.LIBS: .a ++ ++AR= ar ++ARFLAGS= rl ++RANLIB= ranlib ++ ++AS= as ++AFLAGS= ++COMPILE.s= ${AS} ${AFLAGS} ++LINK.s= ${CC} ${AFLAGS} ${LDFLAGS} ++COMPILE.S= ${CC} ${AFLAGS} ${CPPFLAGS} -c ++LINK.S= ${CC} ${AFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++CC= gcc -pipe ++DBG= -O -g ++STATIC?= -static ++ ++CFLAGS= ${DBG} ++COMPILE.c= ${CC} ${CFLAGS} ${CPPFLAGS} -c ++LINK.c= ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++CXX= g++ ++CXXFLAGS= ${CFLAGS} ++COMPILE.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c ++LINK.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++CPP= cpp ++.if defined(DESTDIR) ++CPPFLAGS+= -nostdinc -idirafter ${DESTDIR}/usr/include ++.endif ++ ++MK_DEP= mkdeps.sh -N ++FC= f77 ++FFLAGS= -O ++RFLAGS= ++COMPILE.f= ${FC} ${FFLAGS} -c ++LINK.f= ${FC} ${FFLAGS} ${LDFLAGS} ++COMPILE.F= ${FC} ${FFLAGS} ${CPPFLAGS} -c ++LINK.F= ${FC} ${FFLAGS} ${CPPFLAGS} ${LDFLAGS} ++COMPILE.r= ${FC} ${FFLAGS} ${RFLAGS} -c ++LINK.r= ${FC} ${FFLAGS} ${RFLAGS} ${LDFLAGS} ++ ++LEX= lex ++LFLAGS= ++LEX.l= ${LEX} ${LFLAGS} ++ ++LD= ld ++LDFLAGS= ++ ++LINT= lint ++LINTFLAGS= -chapbx ++ ++PC= pc ++PFLAGS= ++COMPILE.p= ${PC} ${PFLAGS} ${CPPFLAGS} -c ++LINK.p= ${PC} ${PFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++SHELL= sh ++ ++YACC= yacc ++YFLAGS= -d ++YACC.y= ${YACC} ${YFLAGS} ++ ++# C ++.c: ++ ${LINK.c} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.c.o: ++ ${COMPILE.c} ${.IMPSRC} ++.c.a: ++ ${COMPILE.c} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# C++ ++${CXX_SUFFIXES}: ++ ${LINK.cc} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++${CXX_SUFFIXES:%=%.o}: ++ ${COMPILE.cc} ${.IMPSRC} ++${CXX_SUFFIXES:%=%.a}: ++ ${COMPILE.cc} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Fortran/Ratfor ++.f: ++ ${LINK.f} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.f.o: ++ ${COMPILE.f} ${.IMPSRC} ++.f.a: ++ ${COMPILE.f} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++.F: ++ ${LINK.F} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.F.o: ++ ${COMPILE.F} ${.IMPSRC} ++.F.a: ++ ${COMPILE.F} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++.r: ++ ${LINK.r} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.r.o: ++ ${COMPILE.r} ${.IMPSRC} ++.r.a: ++ ${COMPILE.r} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Pascal ++.p: ++ ${LINK.p} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.p.o: ++ ${COMPILE.p} ${.IMPSRC} ++.p.a: ++ ${COMPILE.p} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Assembly ++.s: ++ ${LINK.s} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.s.o: ++ ${COMPILE.s} -o ${.TARGET} ${.IMPSRC} ++.s.a: ++ ${COMPILE.s} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++.S: ++ ${LINK.S} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.S.o: ++ ${COMPILE.S} ${.IMPSRC} ++.S.a: ++ ${COMPILE.S} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Lex ++.l: ++ ${LEX.l} ${.IMPSRC} ++ ${LINK.c} -o ${.TARGET} lex.yy.c ${LDLIBS} -ll ++ rm -f lex.yy.c ++.l.c: ++ ${LEX.l} ${.IMPSRC} ++ mv lex.yy.c ${.TARGET} ++.l.o: ++ ${LEX.l} ${.IMPSRC} ++ ${COMPILE.c} -o ${.TARGET} lex.yy.c ++ rm -f lex.yy.c ++ ++# Yacc ++.y: ++ ${YACC.y} ${.IMPSRC} ++ ${LINK.c} -o ${.TARGET} y.tab.c ${LDLIBS} ++ rm -f y.tab.c ++.y.c: ++ ${YACC.y} ${.IMPSRC} ++ mv y.tab.c ${.TARGET} ++.y.o: ++ ${YACC.y} ${.IMPSRC} ++ ${COMPILE.c} -o ${.TARGET} y.tab.c ++ rm -f y.tab.c ++ ++# Shell ++.sh: ++ rm -f ${.TARGET} ++ cp ${.IMPSRC} ${.TARGET} +diff --git a/mk/sys/MSYS.mk b/mk/sys/MSYS.mk +new file mode 100644 +index 0000000..10da919 +--- /dev/null ++++ b/mk/sys/MSYS.mk +@@ -0,0 +1,185 @@ ++# $Id: Linux.mk,v 1.9 2017/05/05 18:02:16 sjg Exp $ ++# $NetBSD: sys.mk,v 1.19.2.1 1994/07/26 19:58:31 cgd Exp $ ++# @(#)sys.mk 5.11 (Berkeley) 3/13/91 ++ ++OS?= Windows ++unix?= We run ${OS}. ++ ++ROOT_GROUP= ++ ++# would be better to work out where it is... ++LIBCRT0= /dev/null ++ ++NEED_SOLINKS=yes ++ ++.SUFFIXES: .out .a .ln .o .c ${CXX_SUFFIXES} .F .f .r .y .l .s .S .cl .p .h .sh .m4 ++ ++.LIBS: .a ++ ++AR= ar ++ARFLAGS= rl ++RANLIB= ranlib ++ ++AS= as ++AFLAGS= ++COMPILE.s= ${AS} ${AFLAGS} ++LINK.s= ${CC} ${AFLAGS} ${LDFLAGS} ++COMPILE.S= ${CC} ${AFLAGS} ${CPPFLAGS} -c ++LINK.S= ${CC} ${AFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++CC= gcc -pipe ++DBG= -O -g ++STATIC?= -static ++ ++CFLAGS= ${DBG} ++COMPILE.c= ${CC} ${CFLAGS} ${CPPFLAGS} -c ++LINK.c= ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++CXX= g++ ++CXXFLAGS= ${CFLAGS} ++COMPILE.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c ++LINK.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++CPP= cpp ++.if defined(DESTDIR) ++CPPFLAGS+= -nostdinc -idirafter ${DESTDIR}/usr/include ++.endif ++ ++MK_DEP= mkdeps.sh -N ++FC= f77 ++FFLAGS= -O ++RFLAGS= ++COMPILE.f= ${FC} ${FFLAGS} -c ++LINK.f= ${FC} ${FFLAGS} ${LDFLAGS} ++COMPILE.F= ${FC} ${FFLAGS} ${CPPFLAGS} -c ++LINK.F= ${FC} ${FFLAGS} ${CPPFLAGS} ${LDFLAGS} ++COMPILE.r= ${FC} ${FFLAGS} ${RFLAGS} -c ++LINK.r= ${FC} ${FFLAGS} ${RFLAGS} ${LDFLAGS} ++ ++LEX= lex ++LFLAGS= ++LEX.l= ${LEX} ${LFLAGS} ++ ++LD= ld ++LDFLAGS= ++ ++LINT= lint ++LINTFLAGS= -chapbx ++ ++PC= pc ++PFLAGS= ++COMPILE.p= ${PC} ${PFLAGS} ${CPPFLAGS} -c ++LINK.p= ${PC} ${PFLAGS} ${CPPFLAGS} ${LDFLAGS} ++ ++SHELL= sh ++ ++YACC= yacc ++YFLAGS= -d ++YACC.y= ${YACC} ${YFLAGS} ++ ++# C ++.c: ++ ${LINK.c} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.c.o: ++ ${COMPILE.c} ${.IMPSRC} ++.c.a: ++ ${COMPILE.c} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# C++ ++${CXX_SUFFIXES}: ++ ${LINK.cc} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++${CXX_SUFFIXES:%=%.o}: ++ ${COMPILE.cc} ${.IMPSRC} ++${CXX_SUFFIXES:%=%.a}: ++ ${COMPILE.cc} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Fortran/Ratfor ++.f: ++ ${LINK.f} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.f.o: ++ ${COMPILE.f} ${.IMPSRC} ++.f.a: ++ ${COMPILE.f} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++.F: ++ ${LINK.F} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.F.o: ++ ${COMPILE.F} ${.IMPSRC} ++.F.a: ++ ${COMPILE.F} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++.r: ++ ${LINK.r} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.r.o: ++ ${COMPILE.r} ${.IMPSRC} ++.r.a: ++ ${COMPILE.r} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Pascal ++.p: ++ ${LINK.p} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.p.o: ++ ${COMPILE.p} ${.IMPSRC} ++.p.a: ++ ${COMPILE.p} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Assembly ++.s: ++ ${LINK.s} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.s.o: ++ ${COMPILE.s} -o ${.TARGET} ${.IMPSRC} ++.s.a: ++ ${COMPILE.s} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++.S: ++ ${LINK.S} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} ++.S.o: ++ ${COMPILE.S} ${.IMPSRC} ++.S.a: ++ ${COMPILE.S} ${.IMPSRC} ++ ${AR} ${ARFLAGS} $@ $*.o ++ rm -f $*.o ++ ++# Lex ++.l: ++ ${LEX.l} ${.IMPSRC} ++ ${LINK.c} -o ${.TARGET} lex.yy.c ${LDLIBS} -ll ++ rm -f lex.yy.c ++.l.c: ++ ${LEX.l} ${.IMPSRC} ++ mv lex.yy.c ${.TARGET} ++.l.o: ++ ${LEX.l} ${.IMPSRC} ++ ${COMPILE.c} -o ${.TARGET} lex.yy.c ++ rm -f lex.yy.c ++ ++# Yacc ++.y: ++ ${YACC.y} ${.IMPSRC} ++ ${LINK.c} -o ${.TARGET} y.tab.c ${LDLIBS} ++ rm -f y.tab.c ++.y.c: ++ ${YACC.y} ${.IMPSRC} ++ mv y.tab.c ${.TARGET} ++.y.o: ++ ${YACC.y} ${.IMPSRC} ++ ${COMPILE.c} -o ${.TARGET} y.tab.c ++ rm -f y.tab.c ++ ++# Shell ++.sh: ++ rm -f ${.TARGET} ++ cp ${.IMPSRC} ${.TARGET} +diff --git a/mk/warnings.mk b/mk/warnings.mk +index 7fb3ebd..de664fd 100644 +--- a/mk/warnings.mk ++++ b/mk/warnings.mk +@@ -69,4 +69,4 @@ _empty_warnings: .PHONY + .endif +- @echo "ERROR: Invalid: WARNINGS_SET=${ws}" +- @echo "ERROR: Try one of: ${ALL_WARNINGS_SETS:O:u}"; exit 1 ++ @echo "__ERROR: Invalid: WARNINGS_SET=${ws}" ++ @echo "__ERROR: Try one of: ${ALL_WARNINGS_SETS:O:u}"; exit 1 + +diff --git a/parse.c b/parse.c +index a7d7a4d..a996c49 100644 +--- a/parse.c ++++ b/parse.c +@@ -127,2 +127,5 @@ __RCSID("$NetBSD: parse.c,v 1.231 2018/12/22 00:36:32 sjg Exp $"); + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif + #include +@@ -2397,3 +2400,3 @@ ParseSetParseFile(const char *filename) + { +- char *slash, *dirname; ++ char *slash, *dirname, *pdirname; + const char *pd, *pf; +@@ -2403,3 +2406,3 @@ ParseSetParseFile(const char *filename) + if (slash == NULL) { +- Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0); ++ Var_Set(".PARSEDIR", pd = pcurdir, VAR_GLOBAL, 0); + Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0); +@@ -2411,3 +2414,19 @@ ParseSetParseFile(const char *filename) + dirname[len] = '\0'; +- Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0); ++#if (defined _WIN32 && ! defined __CYGWIN__) ++// pdirname = str_replace_char(dirname, '\\', '/'); ++// if (pdirname[1] == ':') { // create msys-style windows path ++// pdirname[1] = pdirname[0]; ++// pdirname[0] = '/'; ++// } ++ char *error; ++ if (dirname && strlen(dirname) > 0 && dirname[1] == ':' && (dirname[2] == '/' || dirname[2] == '\\')) { ++ pdirname = Cmd_Exec(getUnixPathCmd(dirname), &error); ++ } ++ else { ++ pdirname = dirname; ++ } ++#else ++ pdirname = dirname; ++#endif ++ Var_Set(".PARSEDIR", pd = pdirname, VAR_GLOBAL, 0); + Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0); +diff --git a/pathnames.h b/pathnames.h +index 9c597b1..e3436a4 100644 +--- a/pathnames.h ++++ b/pathnames.h +@@ -60,3 +60,7 @@ + #ifndef _PATH_TMP +-#define _PATH_TMP "/tmp/" /* with trailing slash */ ++# if (defined _WIN32 && ! defined __CYGWIN__) ++# define _PATH_TMP (getenv("TEMP")) ++# else ++# define _PATH_TMP "/tmp/" /* with trailing slash */ ++# endif + #endif +diff --git a/realpath.c b/realpath.c +index fbf0335..9a6ac51 100644 +--- a/realpath.c ++++ b/realpath.c +@@ -42,3 +42,5 @@ + #include +- ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif + #include +@@ -51,3 +53,6 @@ + #ifdef HAVE_UNISTD_H +-# include ++#include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/unistd.h" ++#endif + #endif +diff --git a/sigcompat.c b/sigcompat.c +index 608538d..9e605e9 100644 +--- a/sigcompat.c ++++ b/sigcompat.c +@@ -91,4 +91,13 @@ + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/signal.h" ++#endif ++#ifndef SIGQUIT ++#define SIGQUIT SIGTERM ++#endif + #ifdef HAVE_UNISTD_H + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/unistd.h" ++#endif + #endif +diff --git a/str.c b/str.c +index b5255bc..cf85b95 100644 +--- a/str.c ++++ b/str.c +@@ -526 +526,30 @@ Str_SYSVSubst(Buffer *buf, char *pat, char *src, int len) + } ++ ++char * str_replace_char(const char *s, const char toReplace, const char replacement) ++{ ++ int len; ++ int count = 0; ++ char *result; ++ ++ ++ ++ len = strlen(s); ++ ++ /* allocate length plus EOS */ ++ result = bmake_malloc((unsigned int)(len + 1)); ++ ++ /* copy first string into place */ ++ memcpy(result, s, len + 1); ++ ++ count = 0; ++ while(result[count]!='\0' && count < len) ++ { ++ if(result[count]==toReplace) ++ { ++ result[count]=replacement; ++ } ++ count++; ++ } ++ ++ return result; ++} +diff --git a/targ.c b/targ.c +index 01c3d1c..17b14aa 100644 +--- a/targ.c ++++ b/targ.c +@@ -248,3 +248,3 @@ Targ_NewGN(const char *name) + gn->centurion = NULL; +- gn->made = UNMADE; ++ gn->made = __UNMADE; + gn->flags = 0; +@@ -605,10 +605,10 @@ made_name(enum enum_made made) + switch (made) { +- case UNMADE: return "unmade"; +- case DEFERRED: return "deferred"; +- case REQUESTED: return "requested"; +- case BEINGMADE: return "being made"; +- case MADE: return "made"; +- case UPTODATE: return "up-to-date"; +- case ERROR: return "error when made"; +- case ABORTED: return "aborted"; ++ case __UNMADE: return "unmade"; ++ case __DEFERRED: return "deferred"; ++ case __REQUESTED: return "requested"; ++ case __BEINGMADE: return "being made"; ++ case __MADE: return "made"; ++ case __UPTODATE: return "up-to-date"; ++ case __ERROR: return "error when made"; ++ case __ABORTED: return "aborted"; + default: return "unknown enum_made value"; +@@ -650,3 +650,3 @@ Targ_PrintNode(void *gnp, void *passp) + made_name(gn->made)); +- } else if (gn->made != UNMADE) { ++ } else if (gn->made != __UNMADE) { + fprintf(debug_file, "# non-existent (maybe): %s\n", +diff --git a/trace.c b/trace.c +index 267177f..f0f8693 100644 +--- a/trace.c ++++ b/trace.c +@@ -58,2 +58,5 @@ __RCSID("$NetBSD: trace.c,v 1.11 2008/12/28 18:31:51 christos Exp $"); + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/unistd.h" ++#endif + +diff --git a/unit-tests/Makefile b/unit-tests/Makefile +new file mode 100644 +index 0000000..bd45de7 +--- /dev/null ++++ b/unit-tests/Makefile +@@ -0,0 +1,152 @@ ++# $Id: Makefile.in,v 1.49 2018/09/21 21:39:05 sjg Exp $ ++# ++# $NetBSD: Makefile,v 1.53 2018/05/24 00:25:44 christos Exp $ ++# ++# Unit tests for make(1) ++# The main targets are: ++# ++# all: run all the tests ++# test: run 'all', and compare to expected results ++# accept: move generated output to expected results ++# ++# Adding a test case. ++# Each feature should get its own set of tests in its own suitably ++# named makefile (*.mk), with its own set of expected results (*.exp), ++# and it should be added to the TESTNAMES list. ++# ++ ++srcdir= /home/ofry/bmake/unit-tests ++ ++.MAIN: all ++ ++UNIT_TESTS:= ${srcdir} ++WIN_UNIT_TESTS != cygpath -m ${srcdir} ++.PATH: ${UNIT_TESTS} ++ ++# Each test is in a sub-makefile. ++# Keep the list sorted. ++TESTNAMES= \ ++ comment \ ++ cond1 \ ++ cond2 \ ++ error \ ++ export \ ++ export-all \ ++ export-env \ ++ doterror \ ++ forloop \ ++ forsubst \ ++ hash \ ++ misc \ ++ moderrs \ ++ modmatch \ ++ modmisc \ ++ modorder \ ++ modts \ ++ modword \ ++ qequals \ ++ sunshcmd \ ++ sysv \ ++ ternary \ ++ unexport \ ++ unexport-env \ ++ varcmd \ ++ varmisc \ ++ varquote \ ++ varshell ++ ++# these tests were broken by referting POSIX chanegs ++STRICT_POSIX_TESTS = \ ++ escape \ ++ impsrc \ ++ phony-end \ ++ posix1 \ ++ suffixes ++ ++# Override make flags for certain tests ++flags.doterror= ++flags.order=-j1 ++ ++OUTFILES= ${TESTNAMES:S/$/.out/} ++ ++all: ${OUTFILES} ++ ++CLEANFILES += *.rawout *.out *.status *.tmp *.core *.tmp ++CLEANFILES += obj*.[och] lib*.a # posix1.mk ++CLEANFILES += issue* .[ab]* # suffixes.mk ++CLEANRECURSIVE += dir dummy # posix1.mk ++ ++clean: ++ rm -f ${CLEANFILES} ++.if !empty(CLEANRECURSIVE) ++ rm -rf ${CLEANRECURSIVE} ++.endif ++ ++TEST_MAKE?= ${.MAKE} ++TOOL_SED?= sed ++TOOL_TR?= tr ++TOOL_DIFF?= diff ++DIFF_FLAGS?= -u ++ ++.if defined(.PARSEDIR) ++# ensure consistent results from sort(1) ++LC_ALL= C ++LANG= C ++.export LANG LC_ALL ++.endif ++ ++# some tests need extra post-processing ++SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ ++ -e '/command/s,No such.*,not found,' ++ ++# the tests are actually done with sub-makes. ++.SUFFIXES: .mk .rawout .out ++.mk.rawout: ++ @echo ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} ++ -@cd ${.OBJDIR} && \ ++ { ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} \ ++ 2>&1 ; echo $$? >${.TARGET:R}.status ; } > ${.TARGET}.tmp ++ @mv ${.TARGET}.tmp ${.TARGET} ++ ++# We always pretend .MAKE was called 'make' ++# and strip ${.CURDIR}/ from the output ++# and replace anything after 'stopped in' with unit-tests ++# so the results can be compared. ++.rawout.out: ++ @echo postprocess ${.TARGET} ++ @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \ ++ -e 's,^${TEST_MAKE:T:C/\./\\\./g}\.exe[][0-9]*:,make:,' \ ++ -e 's,${TEST_MAKE:C/\./\\\./g},make,' \ ++ -e '/stopped/s, /.*, unit-tests,' \ ++ -e 's,${.CURDIR:C/\./\\\./g}/,,g' \ ++ -e 's,${WIN_UNIT_TESTS:C/\./\\\./g},unit-tests,g' \ ++ -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' ${SED_CMDS.${.TARGET:T:R}} \ ++ < ${.IMPSRC} > ${.TARGET}.tmp ++ @echo "exit status `cat ${.TARGET:R}.status`" >> ${.TARGET}.tmp ++ @mv ${.TARGET}.tmp ${.TARGET} ++ ++# Compare all output files ++test: ${OUTFILES} .PHONY ++ @failed= ; \ ++ for test in ${TESTNAMES}; do \ ++ ${TOOL_DIFF} ${DIFF_FLAGS} ${UNIT_TESTS}/$${test}.exp $${test}.out \ ++ || failed="$${failed}$${failed:+ }$${test}" ; \ ++ done ; \ ++ if [ -n "$${failed}" ]; then \ ++ echo "Failed tests: $${failed}" ; false ; \ ++ else \ ++ echo "All tests passed" ; \ ++ fi ++ ++accept: ++ @for test in ${TESTNAMES}; do \ ++ cmp -s ${UNIT_TESTS}/$${test}.exp $${test}.out \ ++ || { echo "Replacing $${test}.exp" ; \ ++ cp $${test}.out ${UNIT_TESTS}/$${test}.exp ; } \ ++ done ++ ++.if exists(${TEST_MAKE}) ++${TESTNAMES:S/$/.rawout/}: ${TEST_MAKE} ++.endif ++ ++.-include +diff --git a/unit-tests/Makefile.in b/unit-tests/Makefile.in +index e51d254..c24bc33 100644 +--- a/unit-tests/Makefile.in ++++ b/unit-tests/Makefile.in +@@ -22,2 +22,3 @@ srcdir= @srcdir@ + UNIT_TESTS:= ${srcdir} ++WIN_UNIT_TESTS != cygpath -m ${srcdir} + .PATH: ${UNIT_TESTS} +@@ -35,3 +36,2 @@ TESTNAMES= \ + doterror \ +- dotwait \ + forloop \ +@@ -46,4 +46,2 @@ TESTNAMES= \ + modword \ +- order \ +- posix \ + qequals \ +@@ -119,2 +117,3 @@ SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ + @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \ ++ -e 's,^${TEST_MAKE:T:C/\./\\\./g}\.exe[][0-9]*:,make:,' \ + -e 's,${TEST_MAKE:C/\./\\\./g},make,' \ +@@ -122,2 +121,3 @@ SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ + -e 's,${.CURDIR:C/\./\\\./g}/,,g' \ ++ -e 's,${WIN_UNIT_TESTS:C/\./\\\./g},unit-tests,g' \ + -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' ${SED_CMDS.${.TARGET:T:R}} \ +diff --git a/unit-tests/doterror.exp b/unit-tests/doterror.exp +index 5655644..1c8b971 100644 +--- a/unit-tests/doterror.exp ++++ b/unit-tests/doterror.exp +@@ -7,3 +7,3 @@ Stop. + make: stopped in unit-tests +-.ERROR: Looks like 'sad' is upset. ++.__ERROR: Looks like 'sad' is upset. + exit status 1 +diff --git a/unit-tests/doterror.mk b/unit-tests/doterror.mk +index 9030dce..676e2e6 100644 +--- a/unit-tests/doterror.mk ++++ b/unit-tests/doterror.mk +@@ -9,3 +9,3 @@ + +-.ERROR: ++.__ERROR: + @echo "$@: Looks like '${.ERROR_TARGET}' is upset." +diff --git a/unit-tests/escape.mk b/unit-tests/escape.mk +index bb37c92..3bf1b1f 100644 +--- a/unit-tests/escape.mk ++++ b/unit-tests/escape.mk +@@ -53,3 +53,3 @@ should continue the comment. \ + +-__printvars: .USE .MADE ++__printvars: .USE .__MADE + @echo ${.TARGET} +diff --git a/util.c b/util.c +index c79f645..25f4f5e 100644 +--- a/util.c ++++ b/util.c +@@ -9,2 +9,8 @@ + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/signal.h" ++#endif ++#ifndef SIGQUIT ++#define SIGQUIT SIGTERM ++#endif + #endif +@@ -24,17 +30,487 @@ __RCSID("$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $"); + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/signal.h" ++#endif ++#ifndef SIGQUIT ++#define SIGQUIT SIGTERM ++#endif + +-#if !defined(HAVE_STRERROR) +-extern int errno, sys_nerr; +-extern char *sys_errlist[]; ++#ifndef NO_REGEX + +-char * +-strerror(int e) ++#include ++ ++# if (defined _WIN32 && !defined __CYGWIN__) ++#include "headers-mingw/regex.h" ++#include "headers-mingw/regex_internal.h" ++# else ++ ++#include ++ ++# endif ++#endif ++ ++#if !defined(HAVE_PIPE) && (defined _WIN32 && ! defined __CYGWIN__) ++/* Create a pipe. ++ Copyright (C) 2009-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++/* Specification. */ ++#include ++#include "headers-mingw/unistd.h" ++/* Native Windows API. */ ++ ++/* Get _pipe(). */ ++#include ++ ++/* Get _O_BINARY. */ ++#include ++#include "headers-mingw/fcntl.h" ++ ++int ++pipe (int fd[2]) + { +- static char buf[100]; +- if (e < 0 || e >= sys_nerr) { +- snprintf(buf, sizeof(buf), "Unknown error %d", e); +- return buf; ++ /* Mingw changes fd to {-1,-1} on failure, but this violates ++ http://austingroupbugs.net/view.php?id=467 */ ++ int tmp[2]; ++ int result = _pipe (tmp, 4096, _O_BINARY); ++ if (!result) ++ { ++ fd[0] = tmp[0]; ++ fd[1] = tmp[1]; + } +- else +- return sys_errlist[e]; ++ return result; ++} ++ ++#endif ++ ++#if !defined(HAVE_GETDTABLESIZE) && (defined _WIN32 && ! defined __CYGWIN__) ++/* getdtablesize() function: Return maximum possible file descriptor value + 1. ++ Copyright (C) 2008-2018 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2008. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 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, see . */ ++ ++/* Specification. */ ++#include ++#include "headers-mingw/unistd.h" ++ ++# include ++ ++# define _setmaxstdio_nothrow _setmaxstdio ++ ++/* Cache for the previous getdtablesize () result. Safe to cache because ++ Windows also lacks setrlimit. */ ++static int dtablesize; ++ ++int ++getdtablesize (void) ++{ ++ if (dtablesize == 0) ++ { ++ /* We are looking for the number N such that the valid file descriptors ++ are 0..N-1. It can be obtained through a loop as follows: ++ { ++ int fd; ++ for (fd = 3; fd < 65536; fd++) ++ if (dup2 (0, fd) == -1) ++ break; ++ return fd; ++ } ++ On Windows XP, the result is 2048. ++ The drawback of this loop is that it allocates memory for a libc ++ internal array that is never freed. ++ ++ The number N can also be obtained as the upper bound for ++ _getmaxstdio (). _getmaxstdio () returns the maximum number of open ++ FILE objects. The sanity check in _setmaxstdio reveals the maximum ++ number of file descriptors. This too allocates memory, but it is ++ freed when we call _setmaxstdio with the original value. */ ++ int orig_max_stdio = _getmaxstdio (); ++ unsigned int bound; ++ for (bound = 0x10000; _setmaxstdio_nothrow (bound) < 0; bound = bound / 2) ++ ; ++ _setmaxstdio_nothrow (orig_max_stdio); ++ dtablesize = bound; ++ } ++ return dtablesize; ++} ++ ++#endif ++ ++#if !defined(HAVE_FCNTL) && (defined _WIN32 && ! defined __CYGWIN__) ++/* Provide file descriptor control. ++ ++ Copyright (C) 2009-2018 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 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, see . */ ++ ++/* Written by Eric Blake . */ ++ ++/* Specification. */ ++#include "headers-mingw/fcntl.h" ++ ++#include ++#include ++#include ++#include ++ ++/* Get declarations of the native Windows API functions. */ ++# define WIN32_LEAN_AND_MEAN ++# include ++ ++/* Get _get_osfhandle. */ ++# if GNULIB_MSVC_NOTHROW ++# include "msvc-nothrow.h" ++# else ++# include ++# endif ++ ++/* Upper bound on getdtablesize(). See lib/getdtablesize.c. */ ++# define OPEN_MAX_MAX 0x10000 ++ ++/* Duplicate OLDFD into the first available slot of at least NEWFD, ++ which must be positive, with FLAGS determining whether the duplicate ++ will be inheritable. */ ++static int ++dupfd (int oldfd, int newfd, int flags) ++{ ++ /* Mingw has no way to create an arbitrary fd. Iterate until all ++ file descriptors less than newfd are filled up. */ ++ HANDLE curr_process = GetCurrentProcess (); ++ HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd); ++ unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT]; ++ unsigned int fds_to_close_bound = 0; ++ int result; ++ BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE; ++ int mode; ++ ++ if (newfd < 0 || getdtablesize () <= newfd) ++ { ++ errno = EINVAL; ++ return -1; ++ } ++ if (old_handle == INVALID_HANDLE_VALUE ++ || (mode = setmode (oldfd, O_BINARY)) == -1) ++ { ++ /* oldfd is not open, or is an unassigned standard file ++ descriptor. */ ++ errno = EBADF; ++ return -1; ++ } ++ setmode (oldfd, mode); ++ flags |= mode; ++ ++ for (;;) ++ { ++ HANDLE new_handle; ++ int duplicated_fd; ++ unsigned int index; ++ ++ if (!DuplicateHandle (curr_process, /* SourceProcessHandle */ ++ old_handle, /* SourceHandle */ ++ curr_process, /* TargetProcessHandle */ ++ (PHANDLE) &new_handle, /* TargetHandle */ ++ (DWORD) 0, /* DesiredAccess */ ++ inherit, /* InheritHandle */ ++ DUPLICATE_SAME_ACCESS)) /* Options */ ++ { ++ switch (GetLastError ()) ++ { ++ case ERROR_TOO_MANY_OPEN_FILES: ++ errno = EMFILE; ++ break; ++ case ERROR_INVALID_HANDLE: ++ case ERROR_INVALID_TARGET_HANDLE: ++ case ERROR_DIRECT_ACCESS_HANDLE: ++ errno = EBADF; ++ break; ++ case ERROR_INVALID_PARAMETER: ++ case ERROR_INVALID_FUNCTION: ++ case ERROR_INVALID_ACCESS: ++ errno = EINVAL; ++ break; ++ default: ++ errno = EACCES; ++ break; ++ } ++ result = -1; ++ break; ++ } ++ duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags); ++ if (duplicated_fd < 0) ++ { ++ CloseHandle (new_handle); ++ result = -1; ++ break; ++ } ++ if (newfd <= duplicated_fd) ++ { ++ result = duplicated_fd; ++ break; ++ } ++ ++ /* Set the bit duplicated_fd in fds_to_close[]. */ ++ index = (unsigned int) duplicated_fd / CHAR_BIT; ++ if (fds_to_close_bound <= index) ++ { ++ if (sizeof fds_to_close <= index) ++ /* Need to increase OPEN_MAX_MAX. */ ++ abort (); ++ memset (fds_to_close + fds_to_close_bound, '\0', ++ index + 1 - fds_to_close_bound); ++ fds_to_close_bound = index + 1; ++ } ++ fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT); ++ } ++ ++ /* Close the previous fds that turned out to be too small. */ ++ { ++ int saved_errno = errno; ++ unsigned int duplicated_fd; ++ ++ for (duplicated_fd = 0; ++ duplicated_fd < fds_to_close_bound * CHAR_BIT; ++ duplicated_fd++) ++ if ((fds_to_close[duplicated_fd / CHAR_BIT] ++ >> (duplicated_fd % CHAR_BIT)) ++ & 1) ++ close (duplicated_fd); ++ ++ errno = saved_errno; ++ } ++ return result; ++} ++ ++/* Forward declarations, because we '#undef fcntl' in the middle of this ++ compilation unit. */ ++/* Our implementation of fcntl (fd, F_DUPFD, target). */ ++static int rpl_fcntl_DUPFD (int fd, int target); ++/* Our implementation of fcntl (fd, F_DUPFD_CLOEXEC, target). */ ++static int rpl_fcntl_DUPFD_CLOEXEC (int fd, int target); ++ ++/* Perform the specified ACTION on the file descriptor FD, possibly ++ using the argument ARG further described below. This replacement ++ handles the following actions, and forwards all others on to the ++ native fcntl. An unrecognized ACTION returns -1 with errno set to ++ EINVAL. ++ ++ F_DUPFD - duplicate FD, with int ARG being the minimum target fd. ++ If successful, return the duplicate, which will be inheritable; ++ otherwise return -1 and set errno. ++ ++ F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum ++ target fd. If successful, return the duplicate, which will not be ++ inheritable; otherwise return -1 and set errno. ++ ++ F_GETFD - ARG need not be present. If successful, return a ++ non-negative value containing the descriptor flags of FD (only ++ FD_CLOEXEC is portable, but other flags may be present); otherwise ++ return -1 and set errno. */ ++ ++int ++fcntl (int fd, int action, /* arg */...) ++{ ++ va_list arg; ++ int result = -1; ++ va_start (arg, action); ++ switch (action) ++ { ++ case F_DUPFD: ++ { ++ int target = va_arg (arg, int); ++ result = rpl_fcntl_DUPFD (fd, target); ++ break; ++ } ++ ++ case F_DUPFD_CLOEXEC: ++ { ++ int target = va_arg (arg, int); ++ result = rpl_fcntl_DUPFD_CLOEXEC (fd, target); ++ break; ++ } ++ ++ case F_GETFD: ++ { ++ HANDLE handle = (HANDLE) _get_osfhandle (fd); ++ DWORD flags; ++ if (handle == INVALID_HANDLE_VALUE ++ || GetHandleInformation (handle, &flags) == 0) ++ errno = EBADF; ++ else ++ result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC; ++ break; ++ } /* F_GETFD */ ++ ++ /* Implementing F_SETFD on mingw is not trivial - there is no ++ API for changing the O_NOINHERIT bit on an fd, and merely ++ changing the HANDLE_FLAG_INHERIT bit on the underlying handle ++ can lead to odd state. It may be possible by duplicating the ++ handle, using _open_osfhandle with the right flags, then ++ using dup2 to move the duplicate onto the original, but that ++ is not supported for now. */ ++ ++ default: ++ { ++ errno = EINVAL; ++ break; ++ } ++ } ++ va_end (arg); ++ return result; ++} ++ ++static int ++rpl_fcntl_DUPFD (int fd, int target) ++{ ++ int result; ++ result = dupfd (fd, target, 0); ++ return result; ++} ++ ++static int ++rpl_fcntl_DUPFD_CLOEXEC (int fd, int target) ++{ ++ int result; ++ result = dupfd (fd, target, O_CLOEXEC); ++ return result; ++} ++ ++#endif ++ ++#if !defined(HAVE_FORK) && (defined _WIN32 && ! defined __CYGWIN__) ++/* ++ * fork.c ++ * Experimental fork() on Windows. Requires NT 6 subsystem or ++ * newer. ++ * ++ * Copyright (c) 2012 William Pitcock ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * This software is provided 'as is' and without any warranty, express or ++ * implied. In no event shall the authors be liable for any damages arising ++ * from the use of this software. ++ */ ++ ++#define WIN32_LEAN_AND_MEAN ++#include ++#include ++#include ++#include ++#include ++#include ++ ++typedef struct _SECTION_IMAGE_INFORMATION { ++ PVOID EntryPoint; ++ ULONG StackZeroBits; ++ ULONG StackReserved; ++ ULONG StackCommit; ++ ULONG ImageSubsystem; ++ WORD SubSystemVersionLow; ++ WORD SubSystemVersionHigh; ++ ULONG Unknown1; ++ ULONG ImageCharacteristics; ++ ULONG ImageMachineType; ++ ULONG Unknown2[3]; ++} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; ++ ++typedef struct _RTL_USER_PROCESS_INFORMATION { ++ ULONG Size; ++ HANDLE Process; ++ HANDLE Thread; ++ CLIENT_ID ClientId; ++ SECTION_IMAGE_INFORMATION ImageInformation; ++} RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION; ++ ++#define RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED 0x00000001 ++#define RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES 0x00000002 ++#define RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE 0x00000004 ++ ++#define RTL_CLONE_PARENT 0 ++#define RTL_CLONE_CHILD 297 ++ ++typedef NTSTATUS (*RtlCloneUserProcess_f)(ULONG ProcessFlags, ++ PSECURITY_DESCRIPTOR ProcessSecurityDescriptor /* optional */, ++ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor /* optional */, ++ HANDLE DebugPort /* optional */, ++ PRTL_USER_PROCESS_INFORMATION ProcessInformation); ++ ++pid_t fork(void) ++{ ++ HMODULE mod; ++ RtlCloneUserProcess_f clone_p; ++ RTL_USER_PROCESS_INFORMATION process_info; ++ NTSTATUS result; ++ ++ mod = GetModuleHandle("ntdll.dll"); ++ if (!mod) ++ return -ENOSYS; ++ ++ clone_p = (RtlCloneUserProcess_f)GetProcAddress(mod, "RtlCloneUserProcess"); ++ if (clone_p == NULL) ++ return -ENOSYS; ++ ++ /* lets do this */ ++ result = clone_p(RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED | RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES, NULL, NULL, NULL, &process_info); ++ ++ if (result == RTL_CLONE_PARENT) ++ { ++ HANDLE me, hp, ht, hcp = 0; ++ DWORD pi, ti, mi; ++ me = GetCurrentProcess(); ++ pi = (DWORD)process_info.ClientId.UniqueProcess; ++ ti = (DWORD)process_info.ClientId.UniqueThread; ++ ++ ResumeThread(ht); ++ CloseHandle(ht); ++ CloseHandle(hp); ++ return (pid_t)pi; ++ } ++ else if (result == RTL_CLONE_CHILD) ++ { ++ /* fix stdio */ ++ AllocConsole(); ++ return 0; ++ } ++ else ++ return -1; ++ ++ /* NOTREACHED */ ++ return -1; + } +@@ -221,2 +697,5 @@ char *sys_siglist[] = { + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif + #include +@@ -224,2 +703,5 @@ char *sys_siglist[] = { + #include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/unistd.h" ++#endif + +@@ -367,2 +849,641 @@ getwd(char *pathname) + ++#if !defined(HAVE_RANDOM) ++/* Copyright (C) 1995-2018 Free Software Foundation, Inc. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* ++ * This is derived from the Berkeley source: ++ * @(#)random.c 5.5 (Berkeley) 7/6/88 ++ * It was reworked for the GNU C Library by Roland McGrath. ++ * Rewritten to use reentrant functions by Ulrich Drepper, 1995. ++ */ ++ ++/* ++ Copyright (C) 1983 Regents of the University of California. ++ All rights reserved. ++ ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions ++ are met: ++ ++ 1. Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in the ++ documentation and/or other materials provided with the distribution. ++ 4. Neither the name of the University nor the names of its contributors ++ may be used to endorse or promote products derived from this software ++ without specific prior written permission. ++ ++ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ++ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ++ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ SUCH DAMAGE.*/ ++ ++#ifndef _LIBC ++# include "headers-mingw/libc-config.h" ++#endif ++ ++/* Specification. */ ++#include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/stdlib.h" ++#endif ++ ++#include ++#include ++#include ++ ++#ifdef _LIBC ++# include ++#else ++/* Allow memory races; that's random enough. */ ++# define __libc_lock_define_initialized(class, name) ++# define __libc_lock_lock(name) ((void) 0) ++# define __libc_lock_unlock(name) ((void) 0) ++#endif ++ ++/* An improved random number generation package. In addition to the standard ++ rand()/srand() like interface, this package also has a special state info ++ interface. The initstate() routine is called with a seed, an array of ++ bytes, and a count of how many bytes are being passed in; this array is ++ then initialized to contain information for random number generation with ++ that much state information. Good sizes for the amount of state ++ information are 32, 64, 128, and 256 bytes. The state can be switched by ++ calling the setstate() function with the same array as was initialized ++ with initstate(). By default, the package runs with 128 bytes of state ++ information and generates far better random numbers than a linear ++ congruential generator. If the amount of state information is less than ++ 32 bytes, a simple linear congruential R.N.G. is used. Internally, the ++ state information is treated as an array of longs; the zeroth element of ++ the array is the type of R.N.G. being used (small integer); the remainder ++ of the array is the state information for the R.N.G. Thus, 32 bytes of ++ state information will give 7 longs worth of state information, which will ++ allow a degree seven polynomial. (Note: The zeroth word of state ++ information also has some other information stored in it; see setstate ++ for details). The random number generation technique is a linear feedback ++ shift register approach, employing trinomials (since there are fewer terms ++ to sum up that way). In this approach, the least significant bit of all ++ the numbers in the state table will act as a linear feedback shift register, ++ and will have period 2^deg - 1 (where deg is the degree of the polynomial ++ being used, assuming that the polynomial is irreducible and primitive). ++ The higher order bits will have longer periods, since their values are ++ also influenced by pseudo-random carries out of the lower bits. The ++ total period of the generator is approximately deg*(2**deg - 1); thus ++ doubling the amount of state information has a vast influence on the ++ period of the generator. Note: The deg*(2**deg - 1) is an approximation ++ only good for large deg, when the period of the shift register is the ++ dominant factor. With deg equal to seven, the period is actually much ++ longer than the 7*(2**7 - 1) predicted by this formula. */ ++ ++ ++ ++/* For each of the currently supported random number generators, we have a ++ break value on the amount of state information (you need at least this many ++ bytes of state info to support this random number generator), a degree for ++ the polynomial (actually a trinomial) that the R.N.G. is based on, and ++ separation between the two lower order coefficients of the trinomial. */ ++ ++/* Linear congruential. */ ++#define TYPE_0 0 ++#define BREAK_0 8 ++#define DEG_0 0 ++#define SEP_0 0 ++ ++/* x**7 + x**3 + 1. */ ++#define TYPE_1 1 ++#define BREAK_1 32 ++#define DEG_1 7 ++#define SEP_1 3 ++ ++/* x**15 + x + 1. */ ++#define TYPE_2 2 ++#define BREAK_2 64 ++#define DEG_2 15 ++#define SEP_2 1 ++ ++/* x**31 + x**3 + 1. */ ++#define TYPE_3 3 ++#define BREAK_3 128 ++#define DEG_3 31 ++#define SEP_3 3 ++ ++/* x**63 + x + 1. */ ++#define TYPE_4 4 ++#define BREAK_4 256 ++#define DEG_4 63 ++#define SEP_4 1 ++ ++ ++/* Array versions of the above information to make code run faster. ++ Relies on fact that TYPE_i == i. */ ++ ++#define MAX_TYPES 5 /* Max number of types above. */ ++ ++ ++/* Initially, everything is set up as if from: ++ initstate(1, randtbl, 128); ++ Note that this initialization takes advantage of the fact that srandom ++ advances the front and rear pointers 10*rand_deg times, and hence the ++ rear pointer which starts at 0 will also end up at zero; thus the zeroth ++ element of the state information, which contains info about the current ++ position of the rear pointer is just ++ (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ ++ ++static int32_t randtbl[DEG_3 + 1] = ++ { ++ TYPE_3, ++ ++ -1726662223, 379960547, 1735697613, 1040273694, 1313901226, ++ 1627687941, -179304937, -2073333483, 1780058412, -1989503057, ++ -615974602, 344556628, 939512070, -1249116260, 1507946756, ++ -812545463, 154635395, 1388815473, -1926676823, 525320961, ++ -1009028674, 968117788, -123449607, 1284210865, 435012392, ++ -2017506339, -911064859, -370259173, 1132637927, 1398500161, ++ -205601318, ++ }; ++ ++ ++static struct random_data unsafe_state = ++ { ++/* FPTR and RPTR are two pointers into the state info, a front and a rear ++ pointer. These two pointers are always rand_sep places apart, as they ++ cycle through the state information. (Yes, this does mean we could get ++ away with just one pointer, but the code for random is more efficient ++ this way). The pointers are left positioned as they would be from the call: ++ initstate(1, randtbl, 128); ++ (The position of the rear pointer, rptr, is really 0 (as explained above ++ in the initialization of randtbl) because the state table pointer is set ++ to point to randtbl[1] (as explained below).) */ ++ ++ .fptr = &randtbl[SEP_3 + 1], ++ .rptr = &randtbl[1], ++ ++/* The following things are the pointer to the state information table, ++ the type of the current generator, the degree of the current polynomial ++ being used, and the separation between the two pointers. ++ Note that for efficiency of random, we remember the first location of ++ the state information, not the zeroth. Hence it is valid to access ++ state[-1], which is used to store the type of the R.N.G. ++ Also, we remember the last location, since this is more efficient than ++ indexing every time to find the address of the last element to see if ++ the front and rear pointers have wrapped. */ ++ ++ .state = &randtbl[1], ++ ++ .rand_type = TYPE_3, ++ .rand_deg = DEG_3, ++ .rand_sep = SEP_3, ++ ++ .end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])] ++ }; ++ ++/* POSIX.1c requires that there is mutual exclusion for the 'rand' and ++ 'srand' functions to prevent concurrent calls from modifying common ++ data. */ ++__libc_lock_define_initialized (static, lock) ++ ++/* Initialize the random number generator based on the given seed. If the ++ type is the trivial no-state-information type, just remember the seed. ++ Otherwise, initializes state[] based on the given "seed" via a linear ++ congruential generator. Then, the pointers are set to known locations ++ that are exactly rand_sep places apart. Lastly, it cycles the state ++ information a given number of times to get rid of any initial dependencies ++ introduced by the L.C.R.N.G. Note that the initialization of randtbl[] ++ for default usage relies on values produced by this routine. */ ++void ++__srandom (unsigned int x) ++{ ++ __libc_lock_lock (lock); ++ (void) __srandom_r (x, &unsafe_state); ++ __libc_lock_unlock (lock); ++} ++ ++inline void ++srandom (unsigned int x) ++{ ++ return __srandom(x); ++} ++ ++inline void ++srand (unsigned int x) ++{ ++ return __srandom(x); ++} ++ ++/* Initialize the state information in the given array of N bytes for ++ future random number generation. Based on the number of bytes we ++ are given, and the break values for the different R.N.G.'s, we choose ++ the best (largest) one we can and set things up for it. srandom is ++ then called to initialize the state information. Note that on return ++ from srandom, we set state[-1] to be the type multiplexed with the current ++ value of the rear pointer; this is so successive calls to initstate won't ++ lose this information and will be able to restart with setstate. ++ Note: The first thing we do is save the current state, if any, just like ++ setstate so that it doesn't matter when initstate is called. ++ Returns a pointer to the old state. */ ++char * ++__initstate (unsigned int seed, char *arg_state, size_t n) ++{ ++ int32_t *ostate; ++ int ret; ++ ++ __libc_lock_lock (lock); ++ ++ ostate = &unsafe_state.state[-1]; ++ ++ ret = __initstate_r (seed, arg_state, n, &unsafe_state); ++ ++ __libc_lock_unlock (lock); ++ ++ return ret == -1 ? NULL : (char *) ostate; ++} ++ ++inline char * ++initstate (unsigned int seed, char *arg_state, size_t n) ++{ ++ return __initstate(seed, arg_state, n); ++} ++ ++/* Restore the state from the given state array. ++ Note: It is important that we also remember the locations of the pointers ++ in the current state information, and restore the locations of the pointers ++ from the old state information. This is done by multiplexing the pointer ++ location into the zeroth word of the state information. Note that due ++ to the order in which things are done, it is OK to call setstate with the ++ same state as the current state ++ Returns a pointer to the old state information. */ ++char * ++__setstate (char *arg_state) ++{ ++ int32_t *ostate; ++ ++ __libc_lock_lock (lock); ++ ++ ostate = &unsafe_state.state[-1]; ++ ++ if (__setstate_r (arg_state, &unsafe_state) < 0) ++ ostate = NULL; ++ ++ __libc_lock_unlock (lock); ++ ++ return (char *) ostate; ++} ++ ++inline char * ++setstate (char *arg_state) ++{ ++ return __setstate(arg_state); ++} ++ ++/* If we are using the trivial TYPE_0 R.N.G., just do the old linear ++ congruential bit. Otherwise, we do our fancy trinomial stuff, which is the ++ same in all the other cases due to all the global variables that have been ++ set up. The basic operation is to add the number at the rear pointer into ++ the one at the front pointer. Then both pointers are advanced to the next ++ location cyclically in the table. The value returned is the sum generated, ++ reduced to 31 bits by throwing away the "least random" low bit. ++ Note: The code takes advantage of the fact that both the front and ++ rear pointers can't wrap on the same call by not testing the rear ++ pointer if the front one has wrapped. Returns a 31-bit random number. */ ++ ++long int ++__random (void) ++{ ++ int32_t retval; ++ ++ __libc_lock_lock (lock); ++ ++ (void) __random_r (&unsafe_state, &retval); ++ ++ __libc_lock_unlock (lock); ++ ++ return retval; ++} ++inline long int random(void) ++{ ++ return __random(); ++} ++ ++/* Array versions of the above information to make code run faster. ++ Relies on fact that TYPE_i == i. */ ++ ++struct random_poly_info ++{ ++ int seps[MAX_TYPES]; ++ int degrees[MAX_TYPES]; ++}; ++ ++static const struct random_poly_info random_poly_info = ++ { ++ { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }, ++ { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 } ++ }; ++ ++static int32_t ++get_int32 (void *p) ++{ ++ int32_t v; ++ memcpy (&v, p, sizeof v); ++ return v; ++} ++ ++static void ++set_int32 (void *p, int32_t v) ++{ ++ memcpy (p, &v, sizeof v); ++} ++ ++ ++/* Initialize the random number generator based on the given seed. If the ++ type is the trivial no-state-information type, just remember the seed. ++ Otherwise, initializes state[] based on the given "seed" via a linear ++ congruential generator. Then, the pointers are set to known locations ++ that are exactly rand_sep places apart. Lastly, it cycles the state ++ information a given number of times to get rid of any initial dependencies ++ introduced by the L.C.R.N.G. Note that the initialization of randtbl[] ++ for default usage relies on values produced by this routine. */ ++int ++__srandom_r (unsigned int seed, struct random_data *buf) ++{ ++ int type; ++ int32_t *state; ++ long int i; ++ int32_t word; ++ int32_t *dst; ++ int kc; ++ ++ if (buf == NULL) ++ goto fail; ++ type = buf->rand_type; ++ if ((unsigned int) type >= MAX_TYPES) ++ goto fail; ++ ++ state = buf->state; ++ /* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */ ++ if (seed == 0) ++ seed = 1; ++ set_int32 (&state[0], seed); ++ if (type == TYPE_0) ++ goto done; ++ ++ dst = state; ++ word = seed; ++ kc = buf->rand_deg; ++ for (i = 1; i < kc; ++i) ++ { ++ /* This does: ++ state[i] = (16807 * state[i - 1]) % 2147483647; ++ but avoids overflowing 31 bits. */ ++ long int hi = word / 127773; ++ long int lo = word % 127773; ++ word = 16807 * lo - 2836 * hi; ++ if (word < 0) ++ word += 2147483647; ++ set_int32 (++dst, word); ++ } ++ ++ buf->fptr = &state[buf->rand_sep]; ++ buf->rptr = &state[0]; ++ kc *= 10; ++ while (--kc >= 0) ++ { ++ int32_t discard; ++ (void) __random_r (buf, &discard); ++ } ++ ++ done: ++ return 0; ++ ++ fail: ++ return -1; ++} ++ ++inline int ++srandom_r (unsigned int seed, struct random_data *buf) ++{ ++ return __srandom_r(seed, buf); ++} ++ ++/* Initialize the state information in the given array of N bytes for ++ future random number generation. Based on the number of bytes we ++ are given, and the break values for the different R.N.G.'s, we choose ++ the best (largest) one we can and set things up for it. srandom is ++ then called to initialize the state information. Note that on return ++ from srandom, we set state[-1] to be the type multiplexed with the current ++ value of the rear pointer; this is so successive calls to initstate won't ++ lose this information and will be able to restart with setstate. ++ Note: The first thing we do is save the current state, if any, just like ++ setstate so that it doesn't matter when initstate is called. ++ Returns 0 on success, non-zero on failure. */ ++int ++__initstate_r (unsigned int seed, char *arg_state, size_t n, ++ struct random_data *buf) ++{ ++ if (buf == NULL) ++ goto fail; ++ ++ int32_t *old_state = buf->state; ++ if (old_state != NULL) ++ { ++ int old_type = buf->rand_type; ++ set_int32 (&old_state[-1], ++ (old_type == TYPE_0 ++ ? TYPE_0 ++ : (MAX_TYPES * (buf->rptr - old_state)) + old_type)); ++ } ++ ++ int type; ++ if (n >= BREAK_3) ++ type = n < BREAK_4 ? TYPE_3 : TYPE_4; ++ else if (n < BREAK_1) ++ { ++ if (n < BREAK_0) ++ goto fail; ++ ++ type = TYPE_0; ++ } ++ else ++ type = n < BREAK_2 ? TYPE_1 : TYPE_2; ++ ++ int degree = random_poly_info.degrees[type]; ++ int separation = random_poly_info.seps[type]; ++ ++ buf->rand_type = type; ++ buf->rand_sep = separation; ++ buf->rand_deg = degree; ++ int32_t *state = &((int32_t *) arg_state)[1]; /* First location. */ ++ /* Must set END_PTR before srandom. */ ++ buf->end_ptr = &state[degree]; ++ ++ buf->state = state; ++ ++ __srandom_r (seed, buf); ++ ++ set_int32 (&state[-1], ++ type == TYPE_0 ? TYPE_0 : (buf->rptr - state) * MAX_TYPES + type); ++ ++ return 0; ++ ++ fail: ++ __set_errno (EINVAL); ++ return -1; ++} ++ ++inline int ++initstate_r (unsigned int seed, char *arg_state, size_t n, ++ struct random_data *buf) ++{ ++ return __initstate_r(seed, arg_state, n, buf); ++} ++ ++/* Restore the state from the given state array. ++ Note: It is important that we also remember the locations of the pointers ++ in the current state information, and restore the locations of the pointers ++ from the old state information. This is done by multiplexing the pointer ++ location into the zeroth word of the state information. Note that due ++ to the order in which things are done, it is OK to call setstate with the ++ same state as the current state ++ Returns 0 on success, non-zero on failure. */ ++int ++__setstate_r (char *arg_state, struct random_data *buf) ++{ ++ int32_t *new_state = 1 + (int32_t *) arg_state; ++ int type; ++ int old_type; ++ int32_t *old_state; ++ int degree; ++ int separation; ++ ++ if (arg_state == NULL || buf == NULL) ++ goto fail; ++ ++ old_type = buf->rand_type; ++ old_state = buf->state; ++ set_int32 (&old_state[-1], ++ (old_type == TYPE_0 ++ ? TYPE_0 ++ : (MAX_TYPES * (buf->rptr - old_state)) + old_type)); ++ ++ type = get_int32 (&new_state[-1]) % MAX_TYPES; ++ if (type < TYPE_0 || type > TYPE_4) ++ goto fail; ++ ++ buf->rand_deg = degree = random_poly_info.degrees[type]; ++ buf->rand_sep = separation = random_poly_info.seps[type]; ++ buf->rand_type = type; ++ ++ if (type != TYPE_0) ++ { ++ int rear = get_int32 (&new_state[-1]) / MAX_TYPES; ++ buf->rptr = &new_state[rear]; ++ buf->fptr = &new_state[(rear + separation) % degree]; ++ } ++ buf->state = new_state; ++ /* Set end_ptr too. */ ++ buf->end_ptr = &new_state[degree]; ++ ++ return 0; ++ ++ fail: ++ __set_errno (EINVAL); ++ return -1; ++} ++ ++inline int setstate_r (char *arg_state, struct random_data *buf) ++{ ++ return __setstate_r(arg_state, buf); ++} ++ ++/* If we are using the trivial TYPE_0 R.N.G., just do the old linear ++ congruential bit. Otherwise, we do our fancy trinomial stuff, which is the ++ same in all the other cases due to all the global variables that have been ++ set up. The basic operation is to add the number at the rear pointer into ++ the one at the front pointer. Then both pointers are advanced to the next ++ location cyclically in the table. The value returned is the sum generated, ++ reduced to 31 bits by throwing away the "least random" low bit. ++ Note: The code takes advantage of the fact that both the front and ++ rear pointers can't wrap on the same call by not testing the rear ++ pointer if the front one has wrapped. Returns a 31-bit random number. */ ++ ++int ++__random_r (struct random_data *buf, int32_t *result) ++{ ++ int32_t *state; ++ ++ if (buf == NULL || result == NULL) ++ goto fail; ++ ++ state = buf->state; ++ ++ if (buf->rand_type == TYPE_0) ++ { ++ int32_t val = (((get_int32 (&state[0]) * 1103515245U) + 12345U) ++ & 0x7fffffff); ++ set_int32 (&state[0], val); ++ *result = val; ++ } ++ else ++ { ++ int32_t *fptr = buf->fptr; ++ int32_t *rptr = buf->rptr; ++ int32_t *end_ptr = buf->end_ptr; ++ /* F and R are unsigned int, not uint32_t, to avoid undefined ++ overflow behavior on platforms where INT_MAX == UINT32_MAX. */ ++ unsigned int f = get_int32 (fptr); ++ unsigned int r = get_int32 (rptr); ++ uint32_t val = f + r; ++ set_int32 (fptr, val); ++ /* Chucking least random bit. */ ++ *result = val >> 1; ++ ++fptr; ++ if (fptr >= end_ptr) ++ { ++ fptr = state; ++ ++rptr; ++ } ++ else ++ { ++ ++rptr; ++ if (rptr >= end_ptr) ++ rptr = state; ++ } ++ buf->fptr = fptr; ++ buf->rptr = rptr; ++ } ++ return 0; ++ ++ fail: ++ __set_errno (EINVAL); ++ return -1; ++} ++ ++inline int ++random_r (struct random_data *buf, int32_t *result) ++{ ++ return __random_r(buf, result); ++} ++ ++#endif ++ + #if !defined(HAVE_GETCWD) +@@ -526,2 +1647,19 @@ strftime(char *buf, size_t len, const char *fmt, const struct tm *tm) + ++#if !defined(HAVE_STRERROR) ++extern int errno, sys_nerr; ++extern char *sys_errlist[]; ++ ++char * ++strerror(int e) ++{ ++ static char buf[100]; ++ if (e < 0 || e >= sys_nerr) { ++ snprintf(buf, sizeof(buf), "Unknown error %d", e); ++ return buf; ++ } ++ else ++ return sys_errlist[e]; ++} ++#endif ++ + #if !defined(HAVE_KILLPG) +@@ -599,11 +1737,11 @@ errx(int eval, const char *fmt, ...) + +-#if !defined(HAVE_WARN) +-void +-warn(const char *fmt, ...) +-{ +- va_list ap; ++#if !defined(HAVE_KILL) && (defined _WIN32 && ! defined __CYGWIN__) ++# define WIN32_LEAN_AND_MEAN ++# include + +- va_start(ap, fmt); +- vwarn(fmt, ap); +- va_end(ap); ++/* The return value of spawnvp() is really a process handle as returned ++ by CreateProcess(). Therefore we can kill it using TerminateProcess. */ ++int kill(pid_t pid, int sig) ++{ ++ return TerminateProcess ((HANDLE) (pid), sig); + } +@@ -611,9 +1749,1208 @@ warn(const char *fmt, ...) + +-#if !defined(HAVE_WARNX) +-void +-warnx(const char *fmt, ...) +-{ +- va_list ap; ++#if (defined _WIN32 && ! defined __CYGWIN__) //poll function ++/* Emulation for poll(2) ++ Contributed by Paolo Bonzini. + +- va_start(ap, fmt); ++ Copyright 2001-2003, 2006-2018 Free Software Foundation, Inc. ++ ++ This file is part of gnulib. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++/* Tell gcc not to warn about the (nfd < 0) tests, below. */ ++#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__ ++# pragma GCC diagnostic ignored "-Wtype-limits" ++#endif ++ ++//#include ++ ++#include ++ ++/* Specification. */ ++#include "headers-mingw/poll.h" ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#if GNULIB_MSVC_NOTHROW ++# include "msvc-nothrow.h" ++#else ++# include ++#endif ++ ++//#include ++//#include ++ ++#ifdef HAVE_SYS_IOCTL_H ++# include ++#endif ++#ifdef HAVE_SYS_FILIO_H ++# include ++#endif ++ ++#include ++ ++//#include "assure.h" ++ ++#ifndef INFTIM ++# define INFTIM (-1) ++#endif ++ ++/* BeOS does not have MSG_PEEK. */ ++#ifndef MSG_PEEK ++# define MSG_PEEK 0 ++#endif ++ ++/* Avoid warnings from gcc -Wcast-function-type. */ ++# define GetProcAddress \ ++ (void *) GetProcAddress ++ ++static BOOL IsConsoleHandle (HANDLE h) ++{ ++ DWORD mode; ++ return GetConsoleMode (h, &mode) != 0; ++} ++ ++static BOOL ++IsSocketHandle (HANDLE h) ++{ ++ WSANETWORKEVENTS ev; ++ ++ if (IsConsoleHandle (h)) ++ return FALSE; ++ ++ /* Under Wine, it seems that getsockopt returns 0 for pipes too. ++ WSAEnumNetworkEvents instead distinguishes the two correctly. */ ++ ev.lNetworkEvents = 0xDEADBEEF; ++ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); ++ return ev.lNetworkEvents != 0xDEADBEEF; ++} ++ ++typedef DWORD (WINAPI *PNtQueryInformationFile) ++ (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS); ++ ++# ifndef PIPE_BUF ++# define PIPE_BUF 512 ++# endif ++ ++/* Compute revents values for file handle H. If some events cannot happen ++ for the handle, eliminate them from *P_SOUGHT. */ ++ ++static int ++windows_compute_revents (HANDLE h, int *p_sought) ++{ ++ int i, ret, happened; ++ INPUT_RECORD *irbuffer; ++ DWORD avail, nbuffer; ++ BOOL bRet; ++ IO_STATUS_BLOCK iosb; ++ FILE_PIPE_LOCAL_INFORMATION fpli; ++ static PNtQueryInformationFile NtQueryInformationFile; ++ static BOOL once_only; ++ ++ switch (GetFileType (h)) ++ { ++ case FILE_TYPE_PIPE: ++ if (!once_only) ++ { ++ NtQueryInformationFile = (PNtQueryInformationFile) ++ GetProcAddress (GetModuleHandle ("ntdll.dll"), ++ "NtQueryInformationFile"); ++ once_only = TRUE; ++ } ++ ++ happened = 0; ++ if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0) ++ { ++ if (avail) ++ happened |= *p_sought & (POLLIN | POLLRDNORM); ++ } ++ else if (GetLastError () == ERROR_BROKEN_PIPE) ++ happened |= POLLHUP; ++ ++ else ++ { ++ /* It was the write-end of the pipe. Check if it is writable. ++ If NtQueryInformationFile fails, optimistically assume the pipe is ++ writable. This could happen on Windows 9x, where ++ NtQueryInformationFile is not available, or if we inherit a pipe ++ that doesn't permit FILE_READ_ATTRIBUTES access on the write end ++ (I think this should not happen since Windows XP SP2; WINE seems ++ fine too). Otherwise, ensure that enough space is available for ++ atomic writes. */ ++ memset (&iosb, 0, sizeof (iosb)); ++ memset (&fpli, 0, sizeof (fpli)); ++ ++ if (!NtQueryInformationFile ++ || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli), ++ FilePipeLocalInformation) ++ || fpli.WriteQuotaAvailable >= PIPE_BUF ++ || (fpli.OutboundQuota < PIPE_BUF && ++ fpli.WriteQuotaAvailable == fpli.OutboundQuota)) ++ happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND); ++ } ++ return happened; ++ ++ case FILE_TYPE_CHAR: ++ ret = WaitForSingleObject (h, 0); ++ if (!IsConsoleHandle (h)) ++ return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0; ++ ++ nbuffer = avail = 0; ++ bRet = GetNumberOfConsoleInputEvents (h, &nbuffer); ++ if (bRet) ++ { ++ /* Input buffer. */ ++ *p_sought &= POLLIN | POLLRDNORM; ++ if (nbuffer == 0) ++ return POLLHUP; ++ if (!*p_sought) ++ return 0; ++ ++ irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD)); ++ bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail); ++ if (!bRet || avail == 0) ++ return POLLHUP; ++ ++ for (i = 0; i < avail; i++) ++ if (irbuffer[i].EventType == KEY_EVENT) ++ return *p_sought; ++ return 0; ++ } ++ else ++ { ++ /* Screen buffer. */ ++ *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND; ++ return *p_sought; ++ } ++ ++ default: ++ ret = WaitForSingleObject (h, 0); ++ if (ret == WAIT_OBJECT_0) ++ return *p_sought & ~(POLLPRI | POLLRDBAND); ++ ++ return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND); ++ } ++} ++ ++/* Convert fd_sets returned by select into revents values. */ ++ ++static int ++windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents) ++{ ++ int happened = 0; ++ ++ if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT) ++ happened |= (POLLIN | POLLRDNORM) & sought; ++ ++ else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) ++ { ++ int r, error; ++ ++ char data[64]; ++ WSASetLastError (0); ++ r = recv (h, data, sizeof (data), MSG_PEEK); ++ error = WSAGetLastError (); ++ WSASetLastError (0); ++ ++ if (r > 0 || error == WSAENOTCONN) ++ happened |= (POLLIN | POLLRDNORM) & sought; ++ ++ /* Distinguish hung-up sockets from other errors. */ ++ else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET ++ || error == WSAECONNABORTED || error == WSAENETRESET) ++ happened |= POLLHUP; ++ ++ else ++ happened |= POLLERR; ++ } ++ ++ if (lNetworkEvents & (FD_WRITE | FD_CONNECT)) ++ happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought; ++ ++ if (lNetworkEvents & FD_OOB) ++ happened |= (POLLPRI | POLLRDBAND) & sought; ++ ++ return happened; ++} ++ ++int ++poll (struct pollfd *pfd, nfds_t nfd, int timeout) ++{ ++ static struct timeval tv0; ++ static HANDLE hEvent; ++ WSANETWORKEVENTS ev; ++ HANDLE h, handle_array[FD_SETSIZE + 2]; ++ DWORD ret, wait_timeout, nhandles; ++ fd_set rfds, wfds, xfds; ++ BOOL poll_again; ++ MSG msg; ++ int rc = 0; ++ nfds_t i; ++ ++ if (nfd > INT_MAX || timeout < -1) ++ { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ if (!hEvent) ++ hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); ++ ++restart: ++ handle_array[0] = hEvent; ++ nhandles = 1; ++ FD_ZERO (&rfds); ++ FD_ZERO (&wfds); ++ FD_ZERO (&xfds); ++ ++ /* Classify socket handles and create fd sets. */ ++ for (i = 0; i < nfd; i++) ++ { ++ int sought = pfd[i].events; ++ pfd[i].revents = 0; ++ if (pfd[i].fd < 0) ++ continue; ++ if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND ++ | POLLPRI | POLLRDBAND))) ++ continue; ++ ++ h = (HANDLE) _get_osfhandle (pfd[i].fd); ++ if (IsSocketHandle (h)) ++ { ++ int requested = FD_CLOSE; ++ ++ /* see above; socket handles are mapped onto select. */ ++ if (sought & (POLLIN | POLLRDNORM)) ++ { ++ requested |= FD_READ | FD_ACCEPT; ++ FD_SET ((SOCKET) h, &rfds); ++ } ++ if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND)) ++ { ++ requested |= FD_WRITE | FD_CONNECT; ++ FD_SET ((SOCKET) h, &wfds); ++ } ++ if (sought & (POLLPRI | POLLRDBAND)) ++ { ++ requested |= FD_OOB; ++ FD_SET ((SOCKET) h, &xfds); ++ } ++ ++ if (requested) ++ WSAEventSelect ((SOCKET) h, hEvent, requested); ++ } ++ else ++ { ++ /* Poll now. If we get an event, do not poll again. Also, ++ screen buffer handles are waitable, and they'll block until ++ a character is available. windows_compute_revents eliminates ++ bits for the "wrong" direction. */ ++ pfd[i].revents = windows_compute_revents (h, &sought); ++ if (sought) ++ handle_array[nhandles++] = h; ++ if (pfd[i].revents) ++ timeout = 0; ++ } ++ } ++ ++ if (select (0, &rfds, &wfds, &xfds, &tv0) > 0) ++ { ++ /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but ++ no need to call select again. */ ++ poll_again = FALSE; ++ wait_timeout = 0; ++ } ++ else ++ { ++ poll_again = TRUE; ++ if (timeout == INFTIM) ++ wait_timeout = INFINITE; ++ else ++ wait_timeout = timeout; ++ } ++ ++ for (;;) ++ { ++ ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE, ++ wait_timeout, QS_ALLINPUT); ++ ++ if (ret == WAIT_OBJECT_0 + nhandles) ++ { ++ /* new input of some other kind */ ++ BOOL bRet; ++ while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0) ++ { ++ TranslateMessage (&msg); ++ DispatchMessage (&msg); ++ } ++ } ++ else ++ break; ++ } ++ ++ if (poll_again) ++ select (0, &rfds, &wfds, &xfds, &tv0); ++ ++ /* Place a sentinel at the end of the array. */ ++ handle_array[nhandles] = NULL; ++ nhandles = 1; ++ for (i = 0; i < nfd; i++) ++ { ++ int happened; ++ ++ if (pfd[i].fd < 0) ++ continue; ++ if (!(pfd[i].events & (POLLIN | POLLRDNORM | ++ POLLOUT | POLLWRNORM | POLLWRBAND))) ++ continue; ++ ++ h = (HANDLE) _get_osfhandle (pfd[i].fd); ++ if (h != handle_array[nhandles]) ++ { ++ /* It's a socket. */ ++ WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); ++ WSAEventSelect ((SOCKET) h, 0, 0); ++ ++ /* If we're lucky, WSAEnumNetworkEvents already provided a way ++ to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */ ++ if (FD_ISSET ((SOCKET) h, &rfds) ++ && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT))) ++ ev.lNetworkEvents |= FD_READ | FD_ACCEPT; ++ if (FD_ISSET ((SOCKET) h, &wfds)) ++ ev.lNetworkEvents |= FD_WRITE | FD_CONNECT; ++ if (FD_ISSET ((SOCKET) h, &xfds)) ++ ev.lNetworkEvents |= FD_OOB; ++ ++ happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events, ++ ev.lNetworkEvents); ++ } ++ else ++ { ++ /* Not a socket. */ ++ int sought = pfd[i].events; ++ happened = windows_compute_revents (h, &sought); ++ nhandles++; ++ } ++ ++ if ((pfd[i].revents |= happened) != 0) ++ rc++; ++ } ++ ++ if (!rc && timeout == INFTIM) ++ { ++ SleepEx (1, TRUE); ++ goto restart; ++ } ++ ++ return rc; ++} ++ ++#endif //(defined _WIN32 && ! defined __CYGWIN__) (poll function) ++ ++#if !defined(HAVE_SIGEMPTYSET) || !defined(HAVE_SIGISMEMBER) || !defined(HAVE_SIGPROCMASK) || !defined(HAVE_SIGACTION) ++/* POSIX compatible signal blocking. ++ Copyright (C) 2006-2018 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2006. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 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, see . */ ++ ++/* Specification. */ ++#include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/signal.h" ++#endif ++ ++#include ++#include ++#include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/stdlib.h" ++#endif ++ ++#if HAVE_MSVC_INVALID_PARAMETER_HANDLER ++# include "msvc-inval.h" ++#endif ++ ++/* We assume that a platform without POSIX signal blocking functions ++ also does not have the POSIX sigaction() function, only the ++ signal() function. We also assume signal() has SysV semantics, ++ where any handler is uninstalled prior to being invoked. This is ++ true for native Windows platforms. */ ++ ++/* We use raw signal(), but also provide a wrapper rpl_signal() so ++ that applications can query or change a blocked signal. */ ++#undef signal ++ ++/* Provide invalid signal numbers as fallbacks if the uncatchable ++ signals are not defined. */ ++#ifndef SIGKILL ++# define SIGKILL (-1) ++#endif ++#ifndef SIGSTOP ++# define SIGSTOP (-1) ++#endif ++ ++/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias ++ for the signal SIGABRT. Only one signal handler is stored for both ++ SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */ ++#if defined _WIN32 && ! defined __CYGWIN__ ++# undef SIGABRT_COMPAT ++# define SIGABRT_COMPAT 6 ++#endif ++#ifdef SIGABRT_COMPAT ++# define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT) ++#else ++# define SIGABRT_COMPAT_MASK 0 ++#endif ++ ++typedef void (*handler_t) (int); ++ ++#if HAVE_MSVC_INVALID_PARAMETER_HANDLER ++static handler_t ++signal_nothrow (int sig, handler_t handler) ++{ ++ handler_t result; ++ ++ TRY_MSVC_INVAL ++ { ++ result = signal (sig, handler); ++ } ++ CATCH_MSVC_INVAL ++ { ++ result = SIG_ERR; ++ errno = EINVAL; ++ } ++ DONE_MSVC_INVAL; ++ ++ return result; ++} ++# define signal signal_nothrow ++#endif ++ ++/* Handling of gnulib defined signals. */ ++ ++#if GNULIB_defined_SIGPIPE ++static handler_t SIGPIPE_handler = SIG_DFL; ++#endif ++ ++#if GNULIB_defined_SIGPIPE ++static handler_t ++ext_signal (int sig, handler_t handler) ++{ ++ switch (sig) ++ { ++ case SIGPIPE: ++ { ++ handler_t old_handler = SIGPIPE_handler; ++ SIGPIPE_handler = handler; ++ return old_handler; ++ } ++ default: /* System defined signal */ ++ return signal (sig, handler); ++ } ++} ++# undef signal ++# define signal ext_signal ++#endif ++ ++int ++sigismember (const sigset_t *set, int sig) ++{ ++ if (sig >= 0 && sig < NSIG) ++ { ++#ifdef SIGABRT_COMPAT ++ if (sig == SIGABRT_COMPAT) ++ sig = SIGABRT; ++#endif ++ ++ return (*set >> sig) & 1; ++ } ++ else ++ return 0; ++} ++ ++int ++sigemptyset (sigset_t *set) ++{ ++ *set = 0; ++ return 0; ++} ++ ++int ++sigaddset (sigset_t *set, int sig) ++{ ++ if (sig >= 0 && sig < NSIG) ++ { ++#ifdef SIGABRT_COMPAT ++ if (sig == SIGABRT_COMPAT) ++ sig = SIGABRT; ++#endif ++ ++ *set |= 1U << sig; ++ return 0; ++ } ++ else ++ { ++ errno = EINVAL; ++ return -1; ++ } ++} ++ ++int ++sigdelset (sigset_t *set, int sig) ++{ ++ if (sig >= 0 && sig < NSIG) ++ { ++#ifdef SIGABRT_COMPAT ++ if (sig == SIGABRT_COMPAT) ++ sig = SIGABRT; ++#endif ++ ++ *set &= ~(1U << sig); ++ return 0; ++ } ++ else ++ { ++ errno = EINVAL; ++ return -1; ++ } ++} ++ ++ ++int ++sigfillset (sigset_t *set) ++{ ++ *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK; ++ return 0; ++} ++ ++/* Set of currently blocked signals. */ ++static volatile sigset_t blocked_set /* = 0 */; ++ ++/* Set of currently blocked and pending signals. */ ++static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */; ++ ++/* Signal handler that is installed for blocked signals. */ ++static void ++blocked_handler (int sig) ++{ ++ /* Reinstall the handler, in case the signal occurs multiple times ++ while blocked. There is an inherent race where an asynchronous ++ signal in between when the kernel uninstalled the handler and ++ when we reinstall it will trigger the default handler; oh ++ well. */ ++ signal (sig, blocked_handler); ++ if (sig >= 0 && sig < NSIG) ++ pending_array[sig] = 1; ++} ++ ++int ++sigpending (sigset_t *set) ++{ ++ sigset_t pending = 0; ++ int sig; ++ ++ for (sig = 0; sig < NSIG; sig++) ++ if (pending_array[sig]) ++ pending |= 1U << sig; ++ *set = pending; ++ return 0; ++} ++ ++/* The previous signal handlers. ++ Only the array elements corresponding to blocked signals are relevant. */ ++static volatile handler_t old_handlers[NSIG]; ++ ++int ++sigprocmask (int operation, const sigset_t *set, sigset_t *old_set) ++{ ++ if (old_set != NULL) ++ *old_set = blocked_set; ++ ++ if (set != NULL) ++ { ++ sigset_t new_blocked_set; ++ sigset_t to_unblock; ++ sigset_t to_block; ++ ++ switch (operation) ++ { ++ case SIG_BLOCK: ++ new_blocked_set = blocked_set | *set; ++ break; ++ case SIG_SETMASK: ++ new_blocked_set = *set; ++ break; ++ case SIG_UNBLOCK: ++ new_blocked_set = blocked_set & ~*set; ++ break; ++ default: ++ errno = EINVAL; ++ return -1; ++ } ++ to_unblock = blocked_set & ~new_blocked_set; ++ to_block = new_blocked_set & ~blocked_set; ++ ++ if (to_block != 0) ++ { ++ int sig; ++ ++ for (sig = 0; sig < NSIG; sig++) ++ if ((to_block >> sig) & 1) ++ { ++ pending_array[sig] = 0; ++ if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR) ++ blocked_set |= 1U << sig; ++ } ++ } ++ ++ if (to_unblock != 0) ++ { ++ sig_atomic_t received[NSIG]; ++ int sig; ++ ++ for (sig = 0; sig < NSIG; sig++) ++ if ((to_unblock >> sig) & 1) ++ { ++// if (signal (sig, old_handlers[sig]) != blocked_handler) ++// /* The application changed a signal handler while the signal ++// was blocked, bypassing our rpl_signal replacement. ++// We don't support this. */ ++// abort (); ++ received[sig] = pending_array[sig]; ++ blocked_set &= ~(1U << sig); ++ pending_array[sig] = 0; ++ } ++ else ++ received[sig] = 0; ++ ++ for (sig = 0; sig < NSIG; sig++) ++ if (received[sig]) ++ raise (sig); ++ } ++ } ++ return 0; ++} ++ ++/* Install the handler FUNC for signal SIG, and return the previous ++ handler. */ ++handler_t ++rpl_signal (int sig, handler_t handler) ++{ ++ /* We must provide a wrapper, so that a user can query what handler ++ they installed even if that signal is currently blocked. */ ++ if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP ++ && handler != SIG_ERR) ++ { ++#ifdef SIGABRT_COMPAT ++ if (sig == SIGABRT_COMPAT) ++ sig = SIGABRT; ++#endif ++ ++ if (blocked_set & (1U << sig)) ++ { ++ /* POSIX states that sigprocmask and signal are both ++ async-signal-safe. This is not true of our ++ implementation - there is a slight data race where an ++ asynchronous interrupt on signal A can occur after we ++ install blocked_handler but before we have updated ++ old_handlers for signal B, such that handler A can see ++ stale information if it calls signal(B). Oh well - ++ signal handlers really shouldn't try to manipulate the ++ installed handlers of unrelated signals. */ ++ handler_t result = old_handlers[sig]; ++ old_handlers[sig] = handler; ++ return result; ++ } ++ else ++ return signal (sig, handler); ++ } ++ else ++ { ++ errno = EINVAL; ++ return SIG_ERR; ++ } ++} ++ ++/* This implementation of sigaction is tailored to native Windows behavior: ++ signal() has SysV semantics (ie. the handler is uninstalled before ++ it is invoked). This is an inherent data race if an asynchronous ++ signal is sent twice in a row before we can reinstall our handler, ++ but there's nothing we can do about it. Meanwhile, sigprocmask() ++ is not present, and while we can use the gnulib replacement to ++ provide critical sections, it too suffers from potential data races ++ in the face of an ill-timed asynchronous signal. And we compound ++ the situation by reading static storage in a signal handler, which ++ POSIX warns is not generically async-signal-safe. Oh well. ++ ++ Additionally: ++ - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD ++ is not defined. ++ - We don't implement SA_ONSTACK, because sigaltstack() is not present. ++ - We ignore SA_RESTART, because blocking native Windows API calls are ++ not interrupted anyway when an asynchronous signal occurs, and the ++ MSVCRT runtime never sets errno to EINTR. ++ - We don't implement SA_SIGINFO because it is impossible to do so ++ portably. ++ ++ POSIX states that an application should not mix signal() and ++ sigaction(). We support the use of signal() within the gnulib ++ sigprocmask() substitute, but all other application code linked ++ with this module should stick with only sigaction(). */ ++ ++/* Set of current actions. If sa_handler for an entry is NULL, then ++ that signal is not currently handled by the sigaction handler. */ ++static struct sigaction volatile action_array[NSIG] /* = 0 */; ++ ++/* Signal handler that is installed for signals. */ ++static void ++sigaction_handler (int sig) ++{ ++ handler_t handler; ++ sigset_t mask; ++ sigset_t oldmask; ++ int saved_errno = errno; ++ if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler) ++ { ++ /* Unexpected situation; be careful to avoid recursive abort. */ ++ if (sig == SIGABRT) ++ signal (SIGABRT, SIG_DFL); ++ abort (); ++ } ++ ++ /* Reinstall the signal handler when required; otherwise update the ++ bookkeeping so that the user's handler may call sigaction and get ++ accurate results. We know the signal isn't currently blocked, or ++ we wouldn't be in its handler, therefore we know that we are not ++ interrupting a sigaction() call. There is a race where any ++ asynchronous instance of the same signal occurring before we ++ reinstall the handler will trigger the default handler; oh ++ well. */ ++ handler = action_array[sig].sa_handler; ++ if ((action_array[sig].sa_flags & SA_RESETHAND) == 0) ++ signal (sig, sigaction_handler); ++ else ++ action_array[sig].sa_handler = NULL; ++ ++ /* Block appropriate signals. */ ++ mask = action_array[sig].sa_mask; ++ if ((action_array[sig].sa_flags & SA_NODEFER) == 0) ++ sigaddset (&mask, sig); ++ sigprocmask (SIG_BLOCK, &mask, &oldmask); ++ ++ /* Invoke the user's handler, then restore prior mask. */ ++ errno = saved_errno; ++ handler (sig); ++ saved_errno = errno; ++ sigprocmask (SIG_SETMASK, &oldmask, NULL); ++ errno = saved_errno; ++} ++ ++/* Change and/or query the action that will be taken on delivery of ++ signal SIG. If not NULL, ACT describes the new behavior. If not ++ NULL, OACT is set to the prior behavior. Return 0 on success, or ++ set errno and return -1 on failure. */ ++int ++sigaction (int sig, const struct sigaction *restrict act, ++ struct sigaction *restrict oact) ++{ ++ sigset_t mask; ++ sigset_t oldmask; ++ int saved_errno; ++ ++ if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP ++ || (act && act->sa_handler == SIG_ERR)) ++ { ++ errno = EINVAL; ++ return -1; ++ } ++ ++#ifdef SIGABRT_COMPAT ++ if (sig == SIGABRT_COMPAT) ++ sig = SIGABRT; ++#endif ++ ++ /* POSIX requires sigaction() to be async-signal-safe. In other ++ words, if an asynchronous signal can occur while we are anywhere ++ inside this function, the user's handler could then call ++ sigaction() recursively and expect consistent results. We meet ++ this rule by using sigprocmask to block all signals before ++ modifying any data structure that could be read from a signal ++ handler; this works since we know that the gnulib sigprocmask ++ replacement does not try to use sigaction() from its handler. */ ++ if (!act && !oact) ++ return 0; ++ sigfillset (&mask); ++ sigprocmask (SIG_BLOCK, &mask, &oldmask); ++ if (oact) ++ { ++ if (action_array[sig].sa_handler) ++ *oact = action_array[sig]; ++ else ++ { ++ /* Safe to change the handler at will here, since all ++ signals are currently blocked. */ ++ oact->sa_handler = signal (sig, SIG_DFL); ++ if (oact->sa_handler == SIG_ERR) ++ goto failure; ++ signal (sig, oact->sa_handler); ++ oact->sa_flags = SA_RESETHAND | SA_NODEFER; ++ sigemptyset (&oact->sa_mask); ++ } ++ } ++ ++ if (act) ++ { ++ /* Safe to install the handler before updating action_array, ++ since all signals are currently blocked. */ ++ if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN) ++ { ++ if (signal (sig, act->sa_handler) == SIG_ERR) ++ goto failure; ++ action_array[sig].sa_handler = NULL; ++ } ++ else ++ { ++ if (signal (sig, sigaction_handler) == SIG_ERR) ++ goto failure; ++ action_array[sig] = *act; ++ } ++ } ++ sigprocmask (SIG_SETMASK, &oldmask, NULL); ++ return 0; ++ ++ failure: ++ saved_errno = errno; ++ sigprocmask (SIG_SETMASK, &oldmask, NULL); ++ errno = saved_errno; ++ return -1; ++} ++ ++#endif ++ ++#if !defined(HAVE_UNAME) ++/* uname replacement. ++ Copyright (C) 2009-2018 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 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, see . */ ++ ++/* Specification. */ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/sys_utsname.h" ++#else ++#include ++#endif ++ ++ ++/* This file provides an implementation only for the native Windows API. */ ++ ++#include ++#include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/stdlib.h" ++#endif ++#include ++#include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/unistd.h" ++#endif ++#include ++ ++/* Mingw headers don't have all the platform codes. */ ++#ifndef VER_PLATFORM_WIN32_CE ++# define VER_PLATFORM_WIN32_CE 3 ++#endif ++ ++/* Some headers don't have all the processor architecture codes. */ ++#ifndef PROCESSOR_ARCHITECTURE_AMD64 ++# define PROCESSOR_ARCHITECTURE_AMD64 9 ++#endif ++#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 ++# define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 ++#endif ++ ++/* Mingw headers don't have the latest processor codes. */ ++#ifndef PROCESSOR_AMD_X8664 ++# define PROCESSOR_AMD_X8664 8664 ++#endif ++ ++int ++uname (struct utsname *buf) ++{ ++ OSVERSIONINFO version; ++ OSVERSIONINFOEX versionex; ++ BOOL have_versionex; /* indicates whether versionex is filled */ ++ const char *super_version; ++ ++ /* Preparation: Fill version and, if possible, also versionex. ++ But try to call GetVersionEx only once in the common case. */ ++ versionex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX); ++ have_versionex = GetVersionEx ((OSVERSIONINFO *) &versionex); ++ if (have_versionex) ++ { ++ /* We know that OSVERSIONINFO is a subset of OSVERSIONINFOEX. */ ++ memcpy (&version, &versionex, sizeof (OSVERSIONINFO)); ++ } ++ else ++ { ++ version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); ++ if (!GetVersionEx (&version)) ++ abort (); ++ } ++ ++ /* Fill in nodename. */ ++ if (gethostname (buf->nodename, sizeof (buf->nodename)) < 0) ++ strcpy (buf->nodename, "localhost"); ++ ++ /* Determine major-major Windows version. */ ++ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) ++ { ++ /* Windows NT or newer. */ ++ super_version = "NT"; ++ } ++ else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE) ++ { ++ /* Windows CE or Embedded CE. */ ++ super_version = "CE"; ++ } ++ else if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) ++ { ++ /* Windows 95/98/ME. */ ++ switch (version.dwMinorVersion) ++ { ++ case 0: ++ super_version = "95"; ++ break; ++ case 10: ++ super_version = "98"; ++ break; ++ case 90: ++ super_version = "ME"; ++ break; ++ default: ++ super_version = ""; ++ break; ++ } ++ } ++ else ++ super_version = ""; ++ ++ /* Fill in sysname. */ ++#ifdef __MINGW32__ ++ /* Returns a string compatible with the MSYS uname.exe program, ++ so that no further changes are needed to GNU config.guess. ++ For example, ++ $ ./uname.exe -s => MINGW32_NT-5.1 ++ */ ++ sprintf (buf->sysname, "MINGW32_%s-%u.%u", super_version, ++ (unsigned int) version.dwMajorVersion, ++ (unsigned int) version.dwMinorVersion); ++#else ++ sprintf (buf->sysname, "Windows%s", super_version); ++#endif ++ ++ /* Fill in release, version. */ ++ /* The MSYS uname.exe programs uses strings from a modified Cygwin runtime: ++ $ ./uname.exe -r => 1.0.11(0.46/3/2) ++ $ ./uname.exe -v => 2008-08-25 23:40 ++ There is no point in imitating this behaviour. */ ++ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) ++ { ++ /* Windows NT or newer. */ ++ struct windows_version ++ { ++ int major; ++ int minor; ++ unsigned int server_offset; ++ const char *name; ++ }; ++ ++ /* Storing the workstation and server version names in a single ++ stream does not waste memory when they are the same. These ++ macros abstract the representation. VERSION1 is used if ++ version.wProductType does not matter, VERSION2 if it does. */ ++ #define VERSION1(major, minor, name) \ ++ { major, minor, 0, name } ++ #define VERSION2(major, minor, workstation, server) \ ++ { major, minor, sizeof workstation, workstation "\0" server } ++ static const struct windows_version versions[] = ++ { ++ VERSION2 (3, -1, "Windows NT Workstation", "Windows NT Server"), ++ VERSION2 (4, -1, "Windows NT Workstation", "Windows NT Server"), ++ VERSION1 (5, 0, "Windows 2000"), ++ VERSION1 (5, 1, "Windows XP"), ++ VERSION1 (5, 2, "Windows Server 2003"), ++ VERSION2 (6, 0, "Windows Vista", "Windows Server 2008"), ++ VERSION2 (6, 1, "Windows 7", "Windows Server 2008 R2"), ++ VERSION2 (-1, -1, "Windows", "Windows Server") ++ }; ++ const char *base; ++ const struct windows_version *v = versions; ++ ++ /* Find a version that matches ours. The last element is a ++ wildcard that always ends the loop. */ ++ while ((v->major != version.dwMajorVersion && v->major != -1) ++ || (v->minor != version.dwMinorVersion && v->minor != -1)) ++ v++; ++ ++ if (have_versionex && versionex.wProductType != VER_NT_WORKSTATION) ++ base = v->name + v->server_offset; ++ else ++ base = v->name; ++ if (v->major == -1 || v->minor == -1) ++ sprintf (buf->release, "%s %u.%u", ++ base, ++ (unsigned int) version.dwMajorVersion, ++ (unsigned int) version.dwMinorVersion); ++ else ++ strcpy (buf->release, base); ++ } ++ else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE) ++ { ++ /* Windows CE or Embedded CE. */ ++ sprintf (buf->release, "Windows CE %u.%u", ++ (unsigned int) version.dwMajorVersion, ++ (unsigned int) version.dwMinorVersion); ++ } ++ else ++ { ++ /* Windows 95/98/ME. */ ++ sprintf (buf->release, "Windows %s", super_version); ++ } ++ strcpy (buf->version, version.szCSDVersion); ++ ++ /* Fill in machine. */ ++ { ++ SYSTEM_INFO info; ++ ++ GetSystemInfo (&info); ++ /* Check for Windows NT or CE, since the info.wProcessorLevel is ++ garbage on Windows 95. */ ++ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT ++ || version.dwPlatformId == VER_PLATFORM_WIN32_CE) ++ { ++ /* Windows NT or newer, or Windows CE or Embedded CE. */ ++ switch (info.wProcessorArchitecture) ++ { ++ case PROCESSOR_ARCHITECTURE_AMD64: ++ strcpy (buf->machine, "x86_64"); ++ break; ++ case PROCESSOR_ARCHITECTURE_IA64: ++ strcpy (buf->machine, "ia64"); ++ break; ++ case PROCESSOR_ARCHITECTURE_INTEL: ++ strcpy (buf->machine, "i386"); ++ if (info.wProcessorLevel >= 3) ++ buf->machine[1] = ++ '0' + (info.wProcessorLevel <= 6 ? info.wProcessorLevel : 6); ++ break; ++ case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: ++ strcpy (buf->machine, "i686"); ++ break; ++ case PROCESSOR_ARCHITECTURE_MIPS: ++ strcpy (buf->machine, "mips"); ++ break; ++ case PROCESSOR_ARCHITECTURE_ALPHA: ++ case PROCESSOR_ARCHITECTURE_ALPHA64: ++ strcpy (buf->machine, "alpha"); ++ break; ++ case PROCESSOR_ARCHITECTURE_PPC: ++ strcpy (buf->machine, "powerpc"); ++ break; ++ case PROCESSOR_ARCHITECTURE_SHX: ++ strcpy (buf->machine, "sh"); ++ break; ++ case PROCESSOR_ARCHITECTURE_ARM: ++ strcpy (buf->machine, "arm"); ++ break; ++ default: ++ strcpy (buf->machine, "unknown"); ++ break; ++ } ++ } ++ else ++ { ++ /* Windows 95/98/ME. */ ++ switch (info.dwProcessorType) ++ { ++ case PROCESSOR_AMD_X8664: ++ strcpy (buf->machine, "x86_64"); ++ break; ++ case PROCESSOR_INTEL_IA64: ++ strcpy (buf->machine, "ia64"); ++ break; ++ default: ++ if (info.dwProcessorType % 100 == 86) ++ sprintf (buf->machine, "i%u", ++ (unsigned int) info.dwProcessorType); ++ else ++ strcpy (buf->machine, "unknown"); ++ break; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++#endif ++ ++#if !defined(HAVE_WARN) ++void ++warn(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); ++ vwarn(fmt, ap); ++ va_end(ap); ++} ++#endif ++ ++#if !defined(HAVE_WARNX) ++void ++warnx(const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, fmt); + vwarnx(fmt, ap); +@@ -622 +2959,618 @@ warnx(const char *fmt, ...) + #endif ++ ++#if !defined(HAVE_WAIT) ++/* Specification. */ ++#include "wait.h" ++pid_t ++wait (int *statusp) ++{ ++ return waitpid((pid_t) -1, statusp, WUNTRACED); ++} ++#endif ++ ++#if !defined(HAVE_WAITPID) ++/* Wait for process state change. ++ Copyright (C) 2001-2003, 2005-2018 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, 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, see . */ ++ ++/* Specification. */ ++#include "wait.h" ++ ++/* Implementation for native Windows systems. */ ++ ++#include /* for _cwait, WAIT_CHILD */ ++ ++pid_t ++waitpid (pid_t pid, int *statusp, int options) ++{ ++ return _cwait (statusp, pid, WAIT_CHILD); ++} ++#endif ++ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++char * ++getShellLaunchPrefix() ++{ ++ const char *sysRootPath = getenv("SYSROOTWINDOWSPATH"); ++ const char *msystemPrefix = getenv("MSYSTEM"); ++ ++ if (sysRootPath == NULL || msystemPrefix == NULL) { ++ return NULL; /*we can't find mingw shell installed on this system */ ++ } ++ else { ++ /* we will return something like ++ * C:\msys64\usr\bin\env MSYSTEM=MINGW64 /usr/bin/bash -lc ++ */ ++ return str_concat( ++ str_concat( ++ str_concat(sysRootPath, "usr\\bin\\env.exe MSYSTEM=", 0), ++ msystemPrefix, 0), ++ "/usr/bin/bash -lc", STR_ADDSPACE); ++ } ++} ++ ++char * getUnixPathCmd(const char *path) ++{ ++ return str_concat( ++ "cygpath -u", str_concat("\"", ++ str_concat(path, "\"", 0), ++ 0), ++ STR_ADDSPACE); ++} ++ ++#endif ++ ++#include ++#include ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include "headers-mingw/stdlib.h" ++#endif ++#include ++ ++size_t str_escape(char *dst, const char *src, size_t dstLen) ++{ ++ const char complexCharMap[] = "abtnvfr"; ++ ++ size_t i; ++ size_t srcLen = strlen(src); ++ size_t dstIdx = 0; ++ ++ // If caller wants to determine required length (supplying NULL for dst) ++ // then we set dstLen to SIZE_MAX and pretend the buffer is the largest ++ // possible, but we never write to it. Caller can also provide dstLen ++ // as 0 if no limit is wanted. ++ if (dst == NULL || dstLen == 0) dstLen = SIZE_MAX; ++ ++ for (i = 0; i < srcLen && dstIdx < dstLen; i++) ++ { ++ size_t complexIdx = 0; ++ ++ switch (src[i]) ++ { ++ case '\'': ++ case '\"': ++ case '\\': ++ if (dst && dstIdx <= dstLen - 2) ++ { ++ dst[dstIdx++] = '\\'; ++ dst[dstIdx++] = src[i]; ++ } ++ else dstIdx += 2; ++ break; ++ ++ case '\r': complexIdx++; ++ case '\f': complexIdx++; ++ case '\v': complexIdx++; ++ case '\n': complexIdx++; ++ case '\t': complexIdx++; ++ case '\b': complexIdx++; ++ case '\a': ++ if (dst && dstIdx <= dstLen - 2) ++ { ++ dst[dstIdx++] = '\\'; ++ dst[dstIdx++] = complexCharMap[complexIdx]; ++ } ++ else dstIdx += 2; ++ break; ++ ++ default: ++ if (isprint(src[i])) ++ { ++ // simply copy the character ++ if (dst) ++ dst[dstIdx++] = src[i]; ++ else ++ dstIdx++; ++ } ++ else ++ { ++ // produce octal escape sequence ++ if (dst && dstIdx <= dstLen - 4) ++ { ++ dst[dstIdx++] = '\\'; ++ dst[dstIdx++] = ((src[i] & 0300) >> 6) + '0'; ++ dst[dstIdx++] = ((src[i] & 0070) >> 3) + '0'; ++ dst[dstIdx++] = ((src[i] & 0007) >> 0) + '0'; ++ } ++ else ++ { ++ dstIdx += 4; ++ } ++ } ++ } ++ } ++ ++ if (dst && dstIdx <= dstLen) ++ dst[dstIdx] = '\0'; ++ ++ return dstIdx; ++} ++ ++size_t str_escape_dblquote(char *dst, const char *src, size_t dstLen) ++{ ++ ++ size_t i; ++ size_t srcLen = strlen(src); ++ size_t dstIdx = 0; ++ ++ // If caller wants to determine required length (supplying NULL for dst) ++ // then we set dstLen to SIZE_MAX and pretend the buffer is the largest ++ // possible, but we never write to it. Caller can also provide dstLen ++ // as 0 if no limit is wanted. ++ if (dst == NULL || dstLen == 0) dstLen = SIZE_MAX; ++ ++ for (i = 0; i < srcLen && dstIdx < dstLen; i++) ++ { ++ size_t complexIdx = 0; ++ ++ switch (src[i]) ++ { ++ case '\"': ++ if (dst && dstIdx <= dstLen - 2) ++ { ++ dst[dstIdx++] = '\\'; ++ dst[dstIdx++] = src[i]; ++ } ++ else dstIdx += 2; ++ break; ++ case '\\': ++ if (dst && dstIdx <= dstLen - 2) ++ { ++ dst[dstIdx++] = '\\'; ++ dst[dstIdx++] = src[i]; ++ } ++ else dstIdx += 2; ++ break; ++ default: ++// if (isprint(src[i]) || src[i] == '\n' || src[i] == '\r') ++// { ++ // simply copy the character ++ if (dst) ++ dst[dstIdx++] = src[i]; ++ else ++ dstIdx++; ++// } ++// else { ++// dst[dstIdx++] = ' '; ++// } ++ } ++ } ++ ++ if (dst && dstIdx <= dstLen) ++ dst[dstIdx] = '\0'; ++ ++ return dstIdx; ++} ++ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include ++//#include ++//#include ++ ++#define bool _Bool ++#define true 1 ++#define false 0 ++ ++#define null ((void*)0) ++ ++typedef struct system_np_s { ++ HANDLE child_stdout_read; ++ HANDLE child_stderr_read; ++ HANDLE reader; ++ PROCESS_INFORMATION pi; ++ const char* command; ++ char* stdout_data; ++ int stdout_data_size; ++ char* stderr_data; ++ int stderr_data_size; ++ int* exit_code; ++ int timeout; // timeout in milliseconds or -1 for INIFINTE ++} system_np_t; ++ ++static int peek_pipe(HANDLE pipe, char* data, int size) { ++ char buffer[4 * 1024]; ++ DWORD read = 0; ++ DWORD available = 0; ++ bool b = PeekNamedPipe(pipe, null, sizeof(buffer), null, &available, null); ++ if (!b) { ++ return -1; ++ } else if (available > 0) { ++ int bytes = min(sizeof(buffer), available); ++ b = ReadFile(pipe, buffer, bytes, &read, null); ++ if (!b) { ++ return -1; ++ } ++ if (data != null && size > 0) { ++ int n = min(size - 1, (int)read); ++ memcpy(data, buffer, n); ++ data[n + 1] = 0; // always zero terminated ++ return n; ++ } ++ } ++ return 0; ++} ++ ++static DWORD WINAPI read_from_all_pipes_fully(void* p) { ++ system_np_t* system = (system_np_t*)p; ++ unsigned long long milliseconds = GetTickCount64(); // since boot time ++ char* out = system->stdout_data != null && system->stdout_data_size > 0 ? system->stdout_data : null; ++ char* err = system->stderr_data != null && system->stderr_data_size > 0 ? system->stderr_data : null; ++ int out_bytes = system->stdout_data != null && system->stdout_data_size > 0 ? system->stdout_data_size - 1 : 0; ++ int err_bytes = system->stderr_data != null && system->stderr_data_size > 0 ? system->stderr_data_size - 1 : 0; ++ for (;;) { ++ int read_stdout = peek_pipe(system->child_stdout_read, out, out_bytes); ++ if (read_stdout > 0 && out != null) { out += read_stdout; out_bytes -= read_stdout; } ++ int read_stderr = peek_pipe(system->child_stderr_read, err, err_bytes); ++ if (read_stderr > 0 && err != null) { err += read_stderr; err_bytes -= read_stderr; } ++ if (read_stdout < 0 && read_stderr < 0) { break; } // both pipes are closed ++ unsigned long long time_spent_in_milliseconds = GetTickCount64() - milliseconds; ++ if (system->timeout > 0 && time_spent_in_milliseconds > system->timeout) { break; } ++ if (read_stdout == 0 && read_stderr == 0) { // nothing has been read from both pipes ++ HANDLE handles[2] = {system->child_stdout_read, system->child_stderr_read}; ++ WaitForMultipleObjects(2, handles, false, 1); // wait for at least 1 millisecond (more likely 16) ++ } ++ } ++ if (out != null) { *out = 0; } ++ if (err != null) { *err = 0; } ++ return 0; ++} ++ ++static int create_child_process(system_np_t* system) { ++ SECURITY_ATTRIBUTES sa = {0}; ++ sa.nLength = sizeof(SECURITY_ATTRIBUTES); ++ sa.bInheritHandle = true; ++ sa.lpSecurityDescriptor = null; ++ HANDLE child_stdout_write = INVALID_HANDLE_VALUE; ++ HANDLE child_stderr_write = INVALID_HANDLE_VALUE; ++ if (!CreatePipe(&system->child_stderr_read, &child_stderr_write, &sa, 0) ) { ++ return GetLastError(); ++ } ++ if (!SetHandleInformation(system->child_stderr_read, HANDLE_FLAG_INHERIT, 0) ){ ++ return GetLastError(); ++ } ++ if (!CreatePipe(&system->child_stdout_read, &child_stdout_write, &sa, 0) ) { ++ return GetLastError(); ++ } ++ if (!SetHandleInformation(system->child_stdout_read, HANDLE_FLAG_INHERIT, 0) ){ ++ return GetLastError(); ++ } ++ // Set the text I want to run ++ STARTUPINFO siStartInfo = {0}; ++ siStartInfo.cb = sizeof(STARTUPINFO); ++ siStartInfo.hStdError = child_stderr_write; ++ siStartInfo.hStdOutput = child_stdout_write; ++ siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; ++ siStartInfo.wShowWindow = SW_HIDE; ++ bool b = CreateProcessA(null, ++ (char*)system->command, ++ null, // process security attributes ++ null, // primary thread security attributes ++ true, // handles are inherited ++ CREATE_NO_WINDOW, // creation flags ++ null, // use parent's environment ++ null, // use parent's current directory ++ &siStartInfo, // STARTUPINFO pointer ++ &system->pi); // receives PROCESS_INFORMATION ++ int err = GetLastError(); ++ CloseHandle(child_stderr_write); ++ CloseHandle(child_stdout_write); ++ if (!b) { ++ CloseHandle(system->child_stdout_read); system->child_stdout_read = INVALID_HANDLE_VALUE; ++ CloseHandle(system->child_stderr_read); system->child_stderr_read = INVALID_HANDLE_VALUE; ++ } ++ return b ? 0 : err; ++} ++ ++int system_np(const char* command, int timeout_milliseconds, ++ char* stdout_data, int stdout_data_size, ++ char* stderr_data, int stderr_data_size, int* exit_code) { ++ system_np_t system = {0}; ++ if (exit_code != null) { *exit_code = 0; } ++ if (stdout_data != null && stdout_data_size > 0) { stdout_data[0] = 0; } ++ if (stderr_data != null && stderr_data_size > 0) { stderr_data[0] = 0; } ++ system.timeout = timeout_milliseconds > 0 ? timeout_milliseconds : -1; ++ system.command = command; ++ system.stdout_data = stdout_data; ++ system.stderr_data = stderr_data; ++ system.stdout_data_size = stdout_data_size; ++ system.stderr_data_size = stderr_data_size; ++ int r = create_child_process(&system); ++ if (r == 0) { ++ system.reader = CreateThread(null, 0, read_from_all_pipes_fully, &system, 0, null); ++ if (system.reader == null) { // in theory should rarely happen only when system super low on resources ++ r = GetLastError(); ++ TerminateProcess(system.pi.hProcess, ECANCELED); ++ } else { ++ bool thread_done = WaitForSingleObject(system.pi.hThread, timeout_milliseconds) == 0; ++ bool process_done = WaitForSingleObject(system.pi.hProcess, timeout_milliseconds) == 0; ++ if (!thread_done || !process_done) { ++ TerminateProcess(system.pi.hProcess, ETIME); ++ } ++ if (exit_code != null) { ++ GetExitCodeProcess(system.pi.hProcess, (DWORD*)exit_code); ++ } ++ CloseHandle(system.pi.hThread); ++ CloseHandle(system.pi.hProcess); ++ CloseHandle(system.child_stdout_read); system.child_stdout_read = INVALID_HANDLE_VALUE; ++ CloseHandle(system.child_stderr_read); system.child_stderr_read = INVALID_HANDLE_VALUE; ++ WaitForSingleObject(system.reader, INFINITE); // join thread ++ CloseHandle(system.reader); ++ } ++ } ++ if (stdout_data != null && stdout_data_size > 0) { stdout_data[stdout_data_size - 1] = 0; } ++ if (stderr_data != null && stderr_data_size > 0) { stderr_data[stderr_data_size - 1] = 0; } ++ return r; ++} ++#endif ++ ++#ifndef NO_REGEX ++#if (!defined(HAVE_REGCOMP) || !defined(HAVE_REGERROR) || !defined(HAVE_REGEXEC) || !defined(HAVE_REGFREE)) ++ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++#include ++#endif ++/* Return the codeset of the current locale, if this is easily deducible. ++ Otherwise, return "". */ ++static char * ++ctype_codeset(void) { ++ static char buf[2 + 10 + 1]; ++ char const *locale = setlocale(LC_CTYPE, NULL); ++ char *codeset = buf; ++ size_t codesetlen; ++ codeset[0] = '\0'; ++ ++ if (locale && locale[0]) { ++ /* If the locale name contains an encoding after the dot, return it. */ ++ char *dot = strchr(locale, '.'); ++ ++ if (dot) { ++ /* Look for the possible @... trailer and remove it, if any. */ ++ char *codeset_start = dot + 1; ++ char const *modifier = strchr(codeset_start, '@'); ++ ++ if (!modifier) ++ codeset = codeset_start; ++ else { ++ codesetlen = modifier - codeset_start; ++ if (codesetlen < sizeof buf) { ++ codeset = memcpy(buf, codeset_start, codesetlen); ++ codeset[codesetlen] = '\0'; ++ } ++ } ++ } ++ } ++ ++ /* If setlocale is successful, it returns the number of the ++ codepage, as a string. Otherwise, fall back on Windows API ++ GetACP, which returns the locale's codepage as a number (although ++ this doesn't change according to what the 'setlocale' call specified). ++ Either way, prepend "CP" to make it a valid codeset name. */ ++ codesetlen = strlen(codeset); ++ if (0 < codesetlen && codesetlen < sizeof buf - 2) ++ memmove(buf + 2, codeset, codesetlen + 1); ++ else ++ sprintf(buf + 2, "%u", GetACP()); ++ codeset = memcpy(buf, "CP", 2); ++ return codeset; ++} ++ ++/* Provide nl_langinfo from scratch, either for native MS-Windows, or ++ for old Unix platforms without locales, such as Linux libc5 or ++ BeOS. */ ++ ++# include ++ ++char * ++nl_langinfo(nl_item item) { ++ static char nlbuf[100]; ++ struct tm tmm = {0}; ++ ++ switch (item) { ++ /* nl_langinfo items of the LC_CTYPE category */ ++ case CODESET: { ++ char *codeset = ctype_codeset(); ++ if (*codeset) ++ return codeset; ++ } ++ return (char *) "ISO-8859-1"; ++ /* nl_langinfo items of the LC_NUMERIC category */ ++ case RADIXCHAR: ++ return localeconv()->decimal_point; ++ case THOUSEP: ++ return localeconv()->thousands_sep; ++ /* nl_langinfo items of the LC_TIME category. ++ TODO: Really use the locale. */ ++ case D_T_FMT: ++ case ERA_D_T_FMT: ++ return (char *) "%a %b %e %H:%M:%S %Y"; ++ case D_FMT: ++ case ERA_D_FMT: ++ return (char *) "%m/%d/%y"; ++ case T_FMT: ++ case ERA_T_FMT: ++ return (char *) "%H:%M:%S"; ++ case T_FMT_AMPM: ++ return (char *) "%I:%M:%S %p"; ++ case AM_STR: ++ if (!strftime(nlbuf, sizeof nlbuf, "%p", &tmm)) ++ return (char *) "AM"; ++ return nlbuf; ++ case PM_STR: ++ tmm.tm_hour = 12; ++ if (!strftime(nlbuf, sizeof nlbuf, "%p", &tmm)) ++ return (char *) "PM"; ++ return nlbuf; ++ case DAY_1: ++ case DAY_2: ++ case DAY_3: ++ case DAY_4: ++ case DAY_5: ++ case DAY_6: ++ case DAY_7: { ++ static char const days[][sizeof "Wednesday"] = { ++ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", ++ "Friday", "Saturday" ++ }; ++ tmm.tm_wday = item - DAY_1; ++ if (!strftime(nlbuf, sizeof nlbuf, "%A", &tmm)) ++ return (char *) days[item - DAY_1]; ++ return nlbuf; ++ } ++ case ABDAY_1: ++ case ABDAY_2: ++ case ABDAY_3: ++ case ABDAY_4: ++ case ABDAY_5: ++ case ABDAY_6: ++ case ABDAY_7: { ++ static char const abdays[][sizeof "Sun"] = { ++ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ++ }; ++ tmm.tm_wday = item - ABDAY_1; ++ if (!strftime(nlbuf, sizeof nlbuf, "%a", &tmm)) ++ return (char *) abdays[item - ABDAY_1]; ++ return nlbuf; ++ } ++ { ++ static char const months[][sizeof "September"] = { ++ "January", "February", "March", "April", "May", "June", "July", ++ "September", "October", "November", "December" ++ }; ++ case MON_1: ++ case MON_2: ++ case MON_3: ++ case MON_4: ++ case MON_5: ++ case MON_6: ++ case MON_7: ++ case MON_8: ++ case MON_9: ++ case MON_10: ++ case MON_11: ++ case MON_12: ++ tmm.tm_mon = item - MON_1; ++ if (!strftime(nlbuf, sizeof nlbuf, "%B", &tmm)) ++ return (char *) months[item - MON_1]; ++ return nlbuf; ++ case ALTMON_1: ++ case ALTMON_2: ++ case ALTMON_3: ++ case ALTMON_4: ++ case ALTMON_5: ++ case ALTMON_6: ++ case ALTMON_7: ++ case ALTMON_8: ++ case ALTMON_9: ++ case ALTMON_10: ++ case ALTMON_11: ++ case ALTMON_12: ++ tmm.tm_mon = item - ALTMON_1; ++ /* The platforms without nl_langinfo() don't support strftime with %OB. ++ We don't even need to try. */ ++ if (!strftime(nlbuf, sizeof nlbuf, "%B", &tmm)) ++ return (char *) months[item - ALTMON_1]; ++ return nlbuf; ++ } ++ case ABMON_1: ++ case ABMON_2: ++ case ABMON_3: ++ case ABMON_4: ++ case ABMON_5: ++ case ABMON_6: ++ case ABMON_7: ++ case ABMON_8: ++ case ABMON_9: ++ case ABMON_10: ++ case ABMON_11: ++ case ABMON_12: { ++ static char const abmonths[][sizeof "Jan"] = { ++ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", ++ "Sep", "Oct", "Nov", "Dec" ++ }; ++ tmm.tm_mon = item - ABMON_1; ++ if (!strftime(nlbuf, sizeof nlbuf, "%b", &tmm)) ++ return (char *) abmonths[item - ABMON_1]; ++ return nlbuf; ++ } ++ case ERA: ++ return (char *) ""; ++ case ALT_DIGITS: ++ return (char *) "\0\0\0\0\0\0\0\0\0\0"; ++ /* nl_langinfo items of the LC_MONETARY category. */ ++ case CRNCYSTR: ++ return localeconv()->currency_symbol; ++# ifdef INT_CURR_SYMBOL ++ case INT_CURR_SYMBOL: ++ return localeconv () ->int_curr_symbol; ++ case MON_DECIMAL_POINT: ++ return localeconv () ->mon_decimal_point; ++ case MON_THOUSANDS_SEP: ++ return localeconv () ->mon_thousands_sep; ++ case MON_GROUPING: ++ return localeconv () ->mon_grouping; ++ case POSITIVE_SIGN: ++ return localeconv () ->positive_sign; ++ case NEGATIVE_SIGN: ++ return localeconv () ->negative_sign; ++ case FRAC_DIGITS: ++ return & localeconv () ->frac_digits; ++ case INT_FRAC_DIGITS: ++ return & localeconv () ->int_frac_digits; ++ case P_CS_PRECEDES: ++ return & localeconv () ->p_cs_precedes; ++ case N_CS_PRECEDES: ++ return & localeconv () ->n_cs_precedes; ++ case P_SEP_BY_SPACE: ++ return & localeconv () ->p_sep_by_space; ++ case N_SEP_BY_SPACE: ++ return & localeconv () ->n_sep_by_space; ++ case P_SIGN_POSN: ++ return & localeconv () ->p_sign_posn; ++ case N_SIGN_POSN: ++ return & localeconv () ->n_sign_posn; ++# endif ++ /* nl_langinfo items of the LC_MESSAGES category ++ TODO: Really use the locale. */ ++ case YESEXPR: ++ return (char *) "^[yY]"; ++ case NOEXPR: ++ return (char *) "^[nN]"; ++ default: ++ return (char *) ""; ++ } ++} ++ ++#endif ++#endif +\ No newline at end of file +diff --git a/var.c b/var.c +index 6f8d4c3..5e4e9d2 100644 +--- a/var.c ++++ b/var.c +@@ -73,3 +73,3 @@ static char rcsid[] = "$NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $"; + #else +-#include ++ #include + #ifndef lint +@@ -126,6 +126,20 @@ __RCSID("$NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $"); + #include ++ ++#if (defined _WIN32 && !defined __CYGWIN__) ++#include "headers-mingw/sys_stat.h" ++#endif + #ifndef NO_REGEX ++ + #include ++ ++# if (defined _WIN32 && !defined __CYGWIN__) ++ #include "headers-mingw/regex.h" ++#include "headers-mingw/regex_internal.h" ++# else ++ + #include ++ ++# endif + #endif ++ + #include +@@ -153,3 +167,3 @@ char **savedEnv = NULL; + */ +-char var_Error[] = ""; ++char var_Error[] = ""; + +@@ -160,3 +174,3 @@ char var_Error[] = ""; + */ +-static char varNoError[] = ""; ++static char varNoError[] = ""; + +@@ -188,18 +202,18 @@ static Boolean save_dollars = FALSE; + */ +-GNode *VAR_INTERNAL; /* variables from make itself */ +-GNode *VAR_GLOBAL; /* variables from the makefile */ +-GNode *VAR_CMD; /* variables defined on the command-line */ ++GNode *VAR_INTERNAL; /* variables from make itself */ ++GNode *VAR_GLOBAL; /* variables from the makefile */ ++GNode *VAR_CMD; /* variables defined on the command-line */ + +-#define FIND_CMD 0x1 /* look in VAR_CMD when searching */ +-#define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ +-#define FIND_ENV 0x4 /* look in the environment also */ ++#define FIND_CMD 0x1 /* look in VAR_CMD when searching */ ++#define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ ++#define FIND_ENV 0x4 /* look in the environment also */ + + typedef struct Var { +- char *name; /* the variable's name */ +- Buffer val; /* its value */ +- int flags; /* miscellaneous status flags */ +-#define VAR_IN_USE 1 /* Variable's value currently being used. ++ char *name; /* the variable's name */ ++ Buffer val; /* its value */ ++ int flags; /* miscellaneous status flags */ ++#define VAR_IN_USE 1 /* Variable's value currently being used. + * Used to avoid recursion */ +-#define VAR_FROM_ENV 2 /* Variable comes from the environment */ +-#define VAR_JUNK 4 /* Variable is a junk variable that ++#define VAR_FROM_ENV 2 /* Variable comes from the environment */ ++#define VAR_JUNK 4 /* Variable is a junk variable that + * should be destroyed when done with +@@ -207,11 +221,11 @@ typedef struct Var { + * modified variables */ +-#define VAR_KEEP 8 /* Variable is VAR_JUNK, but we found ++#define VAR_KEEP 8 /* Variable is VAR_JUNK, but we found + * a use for it in some modifier and + * the value is therefore valid */ +-#define VAR_EXPORTED 16 /* Variable is exported */ +-#define VAR_REEXPORT 32 /* Indicate if var needs re-export. ++#define VAR_EXPORTED 16 /* Variable is exported */ ++#define VAR_REEXPORT 32 /* Indicate if var needs re-export. + * This would be true if it contains $'s + */ +-#define VAR_FROM_CMD 64 /* Variable came from command line */ +-} Var; ++#define VAR_FROM_CMD 64 /* Variable came from command line */ ++} Var; + +@@ -220,5 +234,5 @@ typedef struct Var { + */ +-#define VAR_EXPORTED_NONE 0 +-#define VAR_EXPORTED_YES 1 +-#define VAR_EXPORTED_ALL 2 ++#define VAR_EXPORTED_NONE 0 ++#define VAR_EXPORTED_YES 1 ++#define VAR_EXPORTED_ALL 2 + static int var_exportedVars = VAR_EXPORTED_NONE; +@@ -228,3 +242,3 @@ static int var_exportedVars = VAR_EXPORTED_NONE; + */ +-#define VAR_EXPORT_PARENT 1 ++#define VAR_EXPORT_PARENT 1 + /* +@@ -232,14 +246,14 @@ static int var_exportedVars = VAR_EXPORTED_NONE; + */ +-#define VAR_EXPORT_LITERAL 2 ++#define VAR_EXPORT_LITERAL 2 + + /* Var*Pattern flags */ +-#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ +-#define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ +-#define VAR_SUB_MATCHED 0x04 /* There was a match */ +-#define VAR_MATCH_START 0x08 /* Match at start of word */ +-#define VAR_MATCH_END 0x10 /* Match at end of word */ +-#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ ++#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ ++#define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ ++#define VAR_SUB_MATCHED 0x04 /* There was a match */ ++#define VAR_MATCH_START 0x08 /* Match at start of word */ ++#define VAR_MATCH_END 0x10 /* Match at end of word */ ++#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ + + /* Var_Set flags */ +-#define VAR_NO_EXPORT 0x01 /* do not export */ ++#define VAR_NO_EXPORT 0x01 /* do not export */ + +@@ -251,4 +265,4 @@ typedef struct { + */ +- Byte varSpace; /* Word separator in expansions */ +- Boolean oneBigWord; /* TRUE if we will treat the variable as a ++ Byte varSpace; /* Word separator in expansions */ ++ Boolean oneBigWord; /* TRUE if we will treat the variable as a + * single big word, even if it contains +@@ -262,7 +276,7 @@ typedef struct { + typedef struct { +- const char *lhs; /* String to match */ +- int leftLen; /* Length of string */ +- const char *rhs; /* Replacement string (w/ &'s removed) */ +- int rightLen; /* Length of replacement */ +- int flags; ++ const char *lhs; /* String to match */ ++ int leftLen; /* Length of string */ ++ const char *rhs; /* Replacement string (w/ &'s removed) */ ++ int rightLen; /* Length of replacement */ ++ int flags; + } VarPattern; +@@ -271,8 +285,8 @@ typedef struct { + typedef struct { +- GNode *ctxt; /* variable context */ +- char *tvar; /* name of temp var */ +- int tvarLen; +- char *str; /* string to expand */ +- int strLen; +- int errnum; /* errnum for not defined */ ++ GNode *ctxt; /* variable context */ ++ char *tvar; /* name of temp var */ ++ int tvarLen; ++ char *str; /* string to expand */ ++ int strLen; ++ int errnum; /* errnum for not defined */ + } VarLoop_t; +@@ -282,7 +296,7 @@ typedef struct { + typedef struct { +- regex_t re; +- int nsub; +- regmatch_t *matches; +- char *replace; +- int flags; ++ regex_t re; ++ int nsub; ++ regmatch_t *matches; ++ char *replace; ++ int flags; + } VarREPattern; +@@ -292,4 +306,4 @@ typedef struct { + typedef struct { +- int start; /* first word to select */ +- int end; /* last word to select */ ++ int start; /* first word to select */ ++ int end; /* last word to select */ + } VarSelectWords_t; +@@ -297,46 +311,70 @@ typedef struct { + static Var *VarFind(const char *, GNode *, int); ++ + static void VarAdd(const char *, const char *, GNode *); ++ + static Boolean VarHead(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + static Boolean VarTail(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + static Boolean VarSuffix(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + static Boolean VarRoot(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + static Boolean VarMatch(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + #ifdef SYSVVARSUB ++ + static Boolean VarSYSVMatch(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + #endif ++ + static Boolean VarNoMatch(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + #ifndef NO_REGEX ++ + static void VarREError(int, regex_t *, const char *); ++ + static Boolean VarRESubstitute(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + #endif ++ + static Boolean VarSubstitute(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + static Boolean VarLoopExpand(GNode *, Var_Parse_State *, +- char *, Boolean, Buffer *, void *); ++ char *, Boolean, Buffer *, void *); ++ + static char *VarGetPattern(GNode *, Var_Parse_State *, +- int, const char **, int, int *, int *, +- VarPattern *); ++ int, const char **, int, int *, int *, ++ VarPattern *); ++ + static char *VarQuote(char *, Boolean); ++ + static char *VarHash(char *); ++ + static char *VarModify(GNode *, Var_Parse_State *, +- const char *, +- Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), +- void *); ++ const char *, ++ Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), ++ void *); ++ + static char *VarOrder(const char *, const char); ++ + static char *VarUniq(const char *); ++ + static int VarWordCompare(const void *, const void *); ++ + static void VarPrintVar(void *); + +-#define BROPEN '{' +-#define BRCLOSE '}' +-#define PROPEN '(' +-#define PRCLOSE ')' ++#define BROPEN '{' ++#define BRCLOSE '}' ++#define PROPEN '(' ++#define PRCLOSE ')' + +@@ -365,8 +403,7 @@ static void VarPrintVar(void *); + static Var * +-VarFind(const char *name, GNode *ctxt, int flags) +-{ +- Hash_Entry *var; +- Var *v; ++VarFind(const char *name, GNode *ctxt, int flags) { ++ Hash_Entry *var; ++ Var *v; + +- /* ++ /* + * If the variable name begins with a '.', it could very well be one of +@@ -376,33 +413,33 @@ VarFind(const char *name, GNode *ctxt, int flags) + */ +- if (*name == '.' && isupper((unsigned char) name[1])) +- switch (name[1]) { +- case 'A': +- if (!strcmp(name, ".ALLSRC")) +- name = ALLSRC; +- if (!strcmp(name, ".ARCHIVE")) +- name = ARCHIVE; +- break; +- case 'I': +- if (!strcmp(name, ".IMPSRC")) +- name = IMPSRC; +- break; +- case 'M': +- if (!strcmp(name, ".MEMBER")) +- name = MEMBER; +- break; +- case 'O': +- if (!strcmp(name, ".OODATE")) +- name = OODATE; +- break; +- case 'P': +- if (!strcmp(name, ".PREFIX")) +- name = PREFIX; +- break; +- case 'T': +- if (!strcmp(name, ".TARGET")) +- name = TARGET; +- break; +- } ++ if (*name == '.' && isupper((unsigned char) name[1])) ++ switch (name[1]) { ++ case 'A': ++ if (!strcmp(name, ".ALLSRC")) ++ name = ALLSRC; ++ if (!strcmp(name, ".ARCHIVE")) ++ name = ARCHIVE; ++ break; ++ case 'I': ++ if (!strcmp(name, ".IMPSRC")) ++ name = IMPSRC; ++ break; ++ case 'M': ++ if (!strcmp(name, ".MEMBER")) ++ name = MEMBER; ++ break; ++ case 'O': ++ if (!strcmp(name, ".OODATE")) ++ name = OODATE; ++ break; ++ case 'P': ++ if (!strcmp(name, ".PREFIX")) ++ name = PREFIX; ++ break; ++ case 'T': ++ if (!strcmp(name, ".TARGET")) ++ name = TARGET; ++ break; ++ } + #ifdef notyet +- /* for compatibility with gmake */ ++ /* for compatibility with gmake */ + if (name[0] == '^' && name[1] == '\0') +@@ -419,48 +456,46 @@ VarFind(const char *name, GNode *ctxt, int flags) + if ((var == NULL) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) { +- var = Hash_FindEntry(&VAR_CMD->context, name); ++ var = Hash_FindEntry(&VAR_CMD->context, name); + } + if (!checkEnvFirst && (var == NULL) && (flags & FIND_GLOBAL) && +- (ctxt != VAR_GLOBAL)) +- { +- var = Hash_FindEntry(&VAR_GLOBAL->context, name); +- if ((var == NULL) && (ctxt != VAR_INTERNAL)) { +- /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ +- var = Hash_FindEntry(&VAR_INTERNAL->context, name); +- } ++ (ctxt != VAR_GLOBAL)) { ++ var = Hash_FindEntry(&VAR_GLOBAL->context, name); ++ if ((var == NULL) && (ctxt != VAR_INTERNAL)) { ++ /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ ++ var = Hash_FindEntry(&VAR_INTERNAL->context, name); ++ } + } + if ((var == NULL) && (flags & FIND_ENV)) { +- char *env; +- +- if ((env = getenv(name)) != NULL) { +- int len; +- +- v = bmake_malloc(sizeof(Var)); +- v->name = bmake_strdup(name); +- +- len = strlen(env); +- +- Buf_Init(&v->val, len + 1); +- Buf_AddBytes(&v->val, len, env); +- +- v->flags = VAR_FROM_ENV; +- return (v); +- } else if (checkEnvFirst && (flags & FIND_GLOBAL) && +- (ctxt != VAR_GLOBAL)) +- { +- var = Hash_FindEntry(&VAR_GLOBAL->context, name); +- if ((var == NULL) && (ctxt != VAR_INTERNAL)) { +- var = Hash_FindEntry(&VAR_INTERNAL->context, name); +- } +- if (var == NULL) { +- return NULL; +- } else { +- return ((Var *)Hash_GetValue(var)); +- } +- } else { +- return NULL; +- } ++ char *env; ++ ++ if ((env = getenv(name)) != NULL) { ++ int len; ++ ++ v = bmake_malloc(sizeof(Var)); ++ v->name = bmake_strdup(name); ++ ++ len = strlen(env); ++ ++ Buf_Init(&v->val, len + 1); ++ Buf_AddBytes(&v->val, len, env); ++ ++ v->flags = VAR_FROM_ENV; ++ return (v); ++ } else if (checkEnvFirst && (flags & FIND_GLOBAL) && ++ (ctxt != VAR_GLOBAL)) { ++ var = Hash_FindEntry(&VAR_GLOBAL->context, name); ++ if ((var == NULL) && (ctxt != VAR_INTERNAL)) { ++ var = Hash_FindEntry(&VAR_INTERNAL->context, name); ++ } ++ if (var == NULL) { ++ return NULL; ++ } else { ++ return ((Var *) Hash_GetValue(var)); ++ } ++ } else { ++ return NULL; ++ } + } else if (var == NULL) { +- return NULL; ++ return NULL; + } else { +- return ((Var *)Hash_GetValue(var)); ++ return ((Var *) Hash_GetValue(var)); + } +@@ -485,6 +520,5 @@ VarFind(const char *name, GNode *ctxt, int flags) + static Boolean +-VarFreeEnv(Var *v, Boolean destroy) +-{ ++VarFreeEnv(Var *v, Boolean destroy) { + if ((v->flags & VAR_FROM_ENV) == 0) +- return FALSE; ++ return FALSE; + free(v->name); +@@ -515,7 +549,6 @@ VarFreeEnv(Var *v, Boolean destroy) + static void +-VarAdd(const char *name, const char *val, GNode *ctxt) +-{ +- Var *v; +- int len; +- Hash_Entry *h; ++VarAdd(const char *name, const char *val, GNode *ctxt) { ++ Var *v; ++ int len; ++ Hash_Entry *h; + +@@ -524,3 +557,3 @@ VarAdd(const char *name, const char *val, GNode *ctxt) + len = val ? strlen(val) : 0; +- Buf_Init(&v->val, len+1); ++ Buf_Init(&v->val, len + 1); + Buf_AddBytes(&v->val, len, val); +@@ -533,3 +566,3 @@ VarAdd(const char *name, const char *val, GNode *ctxt) + if (DEBUG(VAR) && (ctxt->flags & INTERNAL) == 0) { +- fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); ++ fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); + } +@@ -551,11 +584,10 @@ VarAdd(const char *name, const char *val, GNode *ctxt) + void +-Var_Delete(const char *name, GNode *ctxt) +-{ +- Hash_Entry *ln; ++Var_Delete(const char *name, GNode *ctxt) { ++ Hash_Entry *ln; + char *cp; +- ++ + if (strchr(name, '$')) { +- cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES); ++ cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES); + } else { +- cp = (char *)name; ++ cp = (char *) name; + } +@@ -563,23 +595,23 @@ Var_Delete(const char *name, GNode *ctxt) + if (DEBUG(VAR)) { +- fprintf(debug_file, "%s:delete %s%s\n", +- ctxt->name, cp, ln ? "" : " (not found)"); ++ fprintf(debug_file, "%s:delete %s%s\n", ++ ctxt->name, cp, ln ? "" : " (not found)"); + } + if (cp != name) { +- free(cp); ++ free(cp); + } + if (ln != NULL) { +- Var *v; ++ Var *v; + +- v = (Var *)Hash_GetValue(ln); +- if ((v->flags & VAR_EXPORTED)) { +- unsetenv(v->name); +- } +- if (strcmp(MAKE_EXPORTED, v->name) == 0) { +- var_exportedVars = VAR_EXPORTED_NONE; +- } +- if (v->name != ln->name) +- free(v->name); +- Hash_DeleteEntry(&ctxt->context, ln); +- Buf_Destroy(&v->val, TRUE); +- free(v); ++ v = (Var *) Hash_GetValue(ln); ++ if ((v->flags & VAR_EXPORTED)) { ++ unsetenv(v->name); ++ } ++ if (strcmp(MAKE_EXPORTED, v->name) == 0) { ++ var_exportedVars = VAR_EXPORTED_NONE; ++ } ++ if (v->name != ln->name) ++ free(v->name); ++ Hash_DeleteEntry(&ctxt->context, ln); ++ Buf_Destroy(&v->val, TRUE); ++ free(v); + } +@@ -596,4 +628,3 @@ Var_Delete(const char *name, GNode *ctxt) + static int +-Var_Export1(const char *name, int flags) +-{ ++Var_Export1(const char *name, int flags) { + char tmp[BUFSIZ]; +@@ -605,5 +636,5 @@ Var_Export1(const char *name, int flags) + if (*name == '.') +- return 0; /* skip internals */ ++ return 0; /* skip internals */ + if (!name[1]) { +- /* ++ /* + * A single char. +@@ -613,9 +644,9 @@ Var_Export1(const char *name, int flags) + */ +- switch (name[0]) { +- case '@': +- case '%': +- case '*': +- case '!': +- return 0; +- } ++ switch (name[0]) { ++ case '@': ++ case '%': ++ case '*': ++ case '!': ++ return 0; ++ } + } +@@ -623,7 +654,7 @@ Var_Export1(const char *name, int flags) + if (v == NULL) { +- return 0; ++ return 0; + } + if (!parent && +- (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) { +- return 0; /* nothing to do */ ++ (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) { ++ return 0; /* nothing to do */ + } +@@ -631,4 +662,4 @@ Var_Export1(const char *name, int flags) + if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) { +- if (parent) { +- /* ++ if (parent) { ++ /* + * Flag this as something we need to re-export. +@@ -637,7 +668,7 @@ Var_Export1(const char *name, int flags) + */ +- v->flags |= (VAR_EXPORTED|VAR_REEXPORT); +- return 1; +- } +- if (v->flags & VAR_IN_USE) { +- /* ++ v->flags |= (VAR_EXPORTED | VAR_REEXPORT); ++ return 1; ++ } ++ if (v->flags & VAR_IN_USE) { ++ /* + * We recursed while exporting in a child. +@@ -645,17 +676,17 @@ Var_Export1(const char *name, int flags) + */ +- return 0; +- } +- n = snprintf(tmp, sizeof(tmp), "${%s}", name); +- if (n < (int)sizeof(tmp)) { +- val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); +- setenv(name, val, 1); +- free(val); +- } ++ return 0; ++ } ++ n = snprintf(tmp, sizeof(tmp), "${%s}", name); ++ if (n < (int) sizeof(tmp)) { ++ val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); ++ setenv(name, val, 1); ++ free(val); ++ } + } else { +- if (parent) { +- v->flags &= ~VAR_REEXPORT; /* once will do */ +- } +- if (parent || !(v->flags & VAR_EXPORTED)) { +- setenv(name, val, 1); +- } ++ if (parent) { ++ v->flags &= ~VAR_REEXPORT; /* once will do */ ++ } ++ if (parent || !(v->flags & VAR_EXPORTED)) { ++ setenv(name, val, 1); ++ } + } +@@ -665,3 +696,3 @@ Var_Export1(const char *name, int flags) + if (parent) { +- v->flags |= VAR_EXPORTED; ++ v->flags |= VAR_EXPORTED; + } +@@ -674,7 +705,6 @@ Var_Export1(const char *name, int flags) + void +-Var_ExportVars(void) +-{ ++Var_ExportVars(void) { + char tmp[BUFSIZ]; +- Hash_Entry *var; +- Hash_Search state; ++ Hash_Entry *var; ++ Hash_Search state; + Var *v; +@@ -693,15 +723,15 @@ Var_ExportVars(void) + if (VAR_EXPORTED_NONE == var_exportedVars) +- return; ++ return; + + if (VAR_EXPORTED_ALL == var_exportedVars) { +- /* ++ /* + * Ouch! This is crazy... + */ +- for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state); +- var != NULL; +- var = Hash_EnumNext(&state)) { +- v = (Var *)Hash_GetValue(var); +- Var_Export1(v->name, 0); +- } +- return; ++ for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state); ++ var != NULL; ++ var = Hash_EnumNext(&state)) { ++ v = (Var *) Hash_GetValue(var); ++ Var_Export1(v->name, 0); ++ } ++ return; + } +@@ -711,18 +741,18 @@ Var_ExportVars(void) + n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); +- if (n < (int)sizeof(tmp)) { +- char **av; +- char *as; +- int ac; +- int i; +- +- val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); +- if (*val) { +- av = brk_string(val, &ac, FALSE, &as); +- for (i = 0; i < ac; i++) { +- Var_Export1(av[i], 0); +- } +- free(as); +- free(av); +- } +- free(val); ++ if (n < (int) sizeof(tmp)) { ++ char **av; ++ char *as; ++ int ac; ++ int i; ++ ++ val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); ++ if (*val) { ++ av = brk_string(val, &ac, FALSE, &as); ++ for (i = 0; i < ac; i++) { ++ Var_Export1(av[i], 0); ++ } ++ free(as); ++ free(av); ++ } ++ free(val); + } +@@ -736,4 +766,3 @@ Var_ExportVars(void) + void +-Var_Export(char *str, int isExport) +-{ ++Var_Export(char *str, int isExport) { + char *name; +@@ -747,4 +776,4 @@ Var_Export(char *str, int isExport) + if (isExport && (!str || !str[0])) { +- var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ +- return; ++ var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ ++ return; + } +@@ -753,8 +782,8 @@ Var_Export(char *str, int isExport) + if (strncmp(str, "-env", 4) == 0) { +- str += 4; ++ str += 4; + } else if (strncmp(str, "-literal", 8) == 0) { +- str += 8; +- flags |= VAR_EXPORT_LITERAL; ++ str += 8; ++ flags |= VAR_EXPORT_LITERAL; + } else { +- flags |= VAR_EXPORT_PARENT; ++ flags |= VAR_EXPORT_PARENT; + } +@@ -762,7 +791,7 @@ Var_Export(char *str, int isExport) + if (*val) { +- av = brk_string(val, &ac, FALSE, &as); +- for (i = 0; i < ac; i++) { +- name = av[i]; +- if (!name[1]) { +- /* ++ av = brk_string(val, &ac, FALSE, &as); ++ for (i = 0; i < ac; i++) { ++ name = av[i]; ++ if (!name[1]) { ++ /* + * A single char. +@@ -772,20 +801,20 @@ Var_Export(char *str, int isExport) + */ +- switch (name[0]) { +- case '@': +- case '%': +- case '*': +- case '!': +- continue; +- } +- } +- if (Var_Export1(name, flags)) { +- if (VAR_EXPORTED_ALL != var_exportedVars) +- var_exportedVars = VAR_EXPORTED_YES; +- if (isExport && (flags & VAR_EXPORT_PARENT)) { +- Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); +- } +- } +- } +- free(as); +- free(av); ++ switch (name[0]) { ++ case '@': ++ case '%': ++ case '*': ++ case '!': ++ continue; ++ } ++ } ++ if (Var_Export1(name, flags)) { ++ if (VAR_EXPORTED_ALL != var_exportedVars) ++ var_exportedVars = VAR_EXPORTED_YES; ++ if (isExport && (flags & VAR_EXPORT_PARENT)) { ++ Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); ++ } ++ } ++ } ++ free(as); ++ free(av); + } +@@ -801,4 +830,3 @@ extern char **environ; + void +-Var_UnExport(char *str) +-{ ++Var_UnExport(char *str) { + char tmp[BUFSIZ]; +@@ -810,3 +838,3 @@ Var_UnExport(char *str) + if (!str || !str[0]) { +- return; /* assert? */ ++ return; /* assert? */ + } +@@ -818,29 +846,29 @@ Var_UnExport(char *str) + if (unexport_env) { +- char **newenv; +- +- cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ +- if (environ == savedEnv) { +- /* we have been here before! */ +- newenv = bmake_realloc(environ, 2 * sizeof(char *)); +- } else { +- if (savedEnv) { +- free(savedEnv); +- savedEnv = NULL; +- } +- newenv = bmake_malloc(2 * sizeof(char *)); +- } +- if (!newenv) +- return; +- /* Note: we cannot safely free() the original environ. */ +- environ = savedEnv = newenv; +- newenv[0] = NULL; +- newenv[1] = NULL; +- if (cp && *cp) +- setenv(MAKE_LEVEL_ENV, cp, 1); ++ char **newenv; ++ ++ cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ ++ if (environ == savedEnv) { ++ /* we have been here before! */ ++ newenv = bmake_realloc(environ, 2 * sizeof(char *)); ++ } else { ++ if (savedEnv) { ++ free(savedEnv); ++ savedEnv = NULL; ++ } ++ newenv = bmake_malloc(2 * sizeof(char *)); ++ } ++ if (!newenv) ++ return; ++ /* Note: we cannot safely free() the original environ. */ ++ environ = savedEnv = newenv; ++ newenv[0] = NULL; ++ newenv[1] = NULL; ++ if (cp && *cp) ++ setenv(MAKE_LEVEL_ENV, cp, 1); + } else { +- for (; *str != '\n' && isspace((unsigned char) *str); str++) +- continue; +- if (str[0] && str[0] != '\n') { +- vlist = str; +- } ++ for (; *str != '\n' && isspace((unsigned char) *str); str++) ++ continue; ++ if (str[0] && str[0] != '\n') { ++ vlist = str; ++ } + } +@@ -848,26 +876,26 @@ Var_UnExport(char *str) + if (!vlist) { +- /* Using .MAKE.EXPORTED */ +- n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); +- if (n < (int)sizeof(tmp)) { +- vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); +- } ++ /* Using .MAKE.EXPORTED */ ++ n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); ++ if (n < (int) sizeof(tmp)) { ++ vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); ++ } + } + if (vlist) { +- Var *v; +- char **av; +- char *as; +- int ac; +- int i; +- +- av = brk_string(vlist, &ac, FALSE, &as); +- for (i = 0; i < ac; i++) { +- v = VarFind(av[i], VAR_GLOBAL, 0); +- if (!v) +- continue; +- if (!unexport_env && +- (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) { +- unsetenv(v->name); +- } +- v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT); +- /* ++ Var *v; ++ char **av; ++ char *as; ++ int ac; ++ int i; ++ ++ av = brk_string(vlist, &ac, FALSE, &as); ++ for (i = 0; i < ac; i++) { ++ v = VarFind(av[i], VAR_GLOBAL, 0); ++ if (!v) ++ continue; ++ if (!unexport_env && ++ (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) { ++ unsetenv(v->name); ++ } ++ v->flags &= ~(VAR_EXPORTED | VAR_REEXPORT); ++ /* + * If we are unexporting a list, +@@ -877,18 +905,18 @@ Var_UnExport(char *str) + */ +- if (vlist == str) { +- n = snprintf(tmp, sizeof(tmp), +- "${" MAKE_EXPORTED ":N%s}", v->name); +- if (n < (int)sizeof(tmp)) { +- cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); +- Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL, 0); +- free(cp); +- } +- } +- } +- free(as); +- free(av); +- if (vlist != str) { +- Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); +- free(vlist); +- } ++ if (vlist == str) { ++ n = snprintf(tmp, sizeof(tmp), ++ "${" MAKE_EXPORTED ":N%s}", v->name); ++ if (n < (int) sizeof(tmp)) { ++ cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); ++ Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL, 0); ++ free(cp); ++ } ++ } ++ } ++ free(as); ++ free(av); ++ if (vlist != str) { ++ Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); ++ free(vlist); ++ } + } +@@ -925,7 +953,20 @@ Var_UnExport(char *str) + void +-Var_Set(const char *name, const char *val, GNode *ctxt, int flags) +-{ +- Var *v; ++Var_Set(const char *name, const char *val, GNode *ctxt, int flags) { ++ Var *v; + char *expanded_name = NULL; + ++ ++#if (defined _WIN32 && ! defined __CYGWIN__) ++ char *unix_val; ++ char *error; ++ if (val && strlen(val) > 0 && val[1] == ':' && (val[2] == '/' || val[2] == '\\')) { ++ unix_val = Cmd_Exec(getUnixPathCmd(val), &error); ++ } ++ else { ++ unix_val = val; ++ } ++#else ++ const char *unix_val = val; ++#endif ++ + /* +@@ -936,25 +977,25 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) + if (strchr(name, '$') != NULL) { +- expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); +- if (expanded_name[0] == 0) { +- if (DEBUG(VAR)) { +- fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " +- "name expands to empty string - ignored\n", +- name, val); +- } +- free(expanded_name); +- return; +- } +- name = expanded_name; ++ expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); ++ if (expanded_name[0] == 0) { ++ if (DEBUG(VAR)) { ++ fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " ++ "name expands to empty string - ignored\n", ++ name, unix_val); ++ } ++ free(expanded_name); ++ return; ++ } ++ name = expanded_name; + } + if (ctxt == VAR_GLOBAL) { +- v = VarFind(name, VAR_CMD, 0); +- if (v != NULL) { +- if ((v->flags & VAR_FROM_CMD)) { +- if (DEBUG(VAR)) { +- fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val); +- } +- goto out; +- } +- VarFreeEnv(v, TRUE); +- } ++ v = VarFind(name, VAR_CMD, 0); ++ if (v != NULL) { ++ if ((v->flags & VAR_FROM_CMD)) { ++ if (DEBUG(VAR)) { ++ fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, unix_val); ++ } ++ goto out; ++ } ++ VarFreeEnv(v, TRUE); ++ } + } +@@ -962,4 +1003,4 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) + if (v == NULL) { +- if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { +- /* ++ if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { ++ /* + * This var would normally prevent the same name being added +@@ -968,16 +1009,16 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) + */ +- Var_Delete(name, VAR_GLOBAL); +- } +- VarAdd(name, val, ctxt); ++ Var_Delete(name, VAR_GLOBAL); ++ } ++ VarAdd(name, unix_val, ctxt); + } else { +- Buf_Empty(&v->val); +- if (val) +- Buf_AddBytes(&v->val, strlen(val), val); ++ Buf_Empty(&v->val); ++ if (unix_val) ++ Buf_AddBytes(&v->val, strlen(unix_val), unix_val); + +- if (DEBUG(VAR)) { +- fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); +- } +- if ((v->flags & VAR_EXPORTED)) { +- Var_Export1(name, VAR_EXPORT_PARENT); +- } ++ if (DEBUG(VAR)) { ++ fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, unix_val); ++ } ++ if ((v->flags & VAR_EXPORTED)) { ++ Var_Export1(name, VAR_EXPORT_PARENT); ++ } + } +@@ -988,9 +1029,9 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) + if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { +- if (v == NULL) { +- /* we just added it */ +- v = VarFind(name, ctxt, 0); +- } +- if (v != NULL) +- v->flags |= VAR_FROM_CMD; +- /* ++ if (v == NULL) { ++ /* we just added it */ ++ v = VarFind(name, ctxt, 0); ++ } ++ if (v != NULL) ++ v->flags |= VAR_FROM_CMD; ++ /* + * If requested, don't export these in the environment +@@ -1000,16 +1041,16 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) + */ +- if (varNoExportEnv != TRUE) +- setenv(name, val ? val : "", 1); ++ if (varNoExportEnv != TRUE) ++ setenv(name, unix_val ? unix_val : "", 1); + +- Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); ++ Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); + } + if (*name == '.') { +- if (strcmp(name, SAVE_DOLLARS) == 0) +- save_dollars = s2Boolean(val, save_dollars); ++ if (strcmp(name, SAVE_DOLLARS) == 0) ++ save_dollars = s2Boolean(unix_val, save_dollars); + } + +- out: ++ out: + free(expanded_name); + if (v != NULL) +- VarFreeEnv(v, TRUE); ++ VarFreeEnv(v, TRUE); + } +@@ -1044,6 +1085,5 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) + void +-Var_Append(const char *name, const char *val, GNode *ctxt) +-{ +- Var *v; +- Hash_Entry *h; ++Var_Append(const char *name, const char *val, GNode *ctxt) { ++ Var *v; ++ Hash_Entry *h; + char *expanded_name = NULL; +@@ -1051,30 +1091,30 @@ Var_Append(const char *name, const char *val, GNode *ctxt) + if (strchr(name, '$') != NULL) { +- expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); +- if (expanded_name[0] == 0) { +- if (DEBUG(VAR)) { +- fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " +- "name expands to empty string - ignored\n", +- name, val); +- } +- free(expanded_name); +- return; +- } +- name = expanded_name; ++ expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); ++ if (expanded_name[0] == 0) { ++ if (DEBUG(VAR)) { ++ fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " ++ "name expands to empty string - ignored\n", ++ name, val); ++ } ++ free(expanded_name); ++ return; ++ } ++ name = expanded_name; + } + +- v = VarFind(name, ctxt, (ctxt == VAR_GLOBAL) ? (FIND_CMD|FIND_ENV) : 0); ++ v = VarFind(name, ctxt, (ctxt == VAR_GLOBAL) ? (FIND_CMD | FIND_ENV) : 0); + + if (v == NULL) { +- Var_Set(name, val, ctxt, 0); ++ Var_Set(name, val, ctxt, 0); + } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) { +- Buf_AddByte(&v->val, ' '); +- Buf_AddBytes(&v->val, strlen(val), val); ++ Buf_AddByte(&v->val, ' '); ++ Buf_AddBytes(&v->val, strlen(val), val); + +- if (DEBUG(VAR)) { +- fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, +- Buf_GetAll(&v->val, NULL)); +- } ++ if (DEBUG(VAR)) { ++ fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, ++ Buf_GetAll(&v->val, NULL)); ++ } + +- if (v->flags & VAR_FROM_ENV) { +- /* ++ if (v->flags & VAR_FROM_ENV) { ++ /* + * If the original variable came from the environment, we +@@ -1084,6 +1124,6 @@ Var_Append(const char *name, const char *val, GNode *ctxt) + */ +- v->flags &= ~VAR_FROM_ENV; +- h = Hash_CreateEntry(&ctxt->context, name, NULL); +- Hash_SetValue(h, v); +- } ++ v->flags &= ~VAR_FROM_ENV; ++ h = Hash_CreateEntry(&ctxt->context, name, NULL); ++ Hash_SetValue(h, v); ++ } + } +@@ -1110,18 +1150,17 @@ Var_Append(const char *name, const char *val, GNode *ctxt) + Boolean +-Var_Exists(const char *name, GNode *ctxt) +-{ +- Var *v; +- char *cp; ++Var_Exists(const char *name, GNode *ctxt) { ++ Var *v; ++ char *cp; + + if ((cp = strchr(name, '$')) != NULL) { +- cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES); ++ cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES); + } +- v = VarFind(cp ? cp : name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV); ++ v = VarFind(cp ? cp : name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV); + free(cp); + if (v == NULL) { +- return(FALSE); ++ return (FALSE); + } else { +- (void)VarFreeEnv(v, TRUE); ++ (void) VarFreeEnv(v, TRUE); + } +- return(TRUE); ++ return (TRUE); + } +@@ -1145,5 +1184,4 @@ Var_Exists(const char *name, GNode *ctxt) + char * +-Var_Value(const char *name, GNode *ctxt, char **frp) +-{ +- Var *v; ++Var_Value(const char *name, GNode *ctxt, char **frp) { ++ Var *v; + +@@ -1152,8 +1190,20 @@ Var_Value(const char *name, GNode *ctxt, char **frp) + if (v != NULL) { +- char *p = (Buf_GetAll(&v->val, NULL)); +- if (VarFreeEnv(v, FALSE)) +- *frp = p; +- return p; ++ char *raw = (Buf_GetAll(&v->val, NULL)); ++#if (defined _WIN32 && ! defined __CYGWIN__) ++ char *p; ++ const char *error; ++ if ((raw[1] == ':') && (raw[2] == '/' || raw[2] == '\\')) { // it is windows path ++ p = Cmd_Exec(getUnixPathCmd(raw), &error); ++ } ++ else { ++ p = raw; ++ } ++#else ++ char *p = raw; ++#endif ++ if (VarFreeEnv(v, FALSE)) ++ *frp = p; ++ return p; + } else { +- return NULL; ++ return NULL; + } +@@ -1184,5 +1234,4 @@ static Boolean + VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, +- char *word, Boolean addSpace, Buffer *buf, +- void *dummy MAKE_ATTR_UNUSED) +-{ ++ char *word, Boolean addSpace, Buffer *buf, ++ void *dummy MAKE_ATTR_UNUSED) { + char *slash; +@@ -1191,16 +1240,16 @@ VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + if (slash != NULL) { +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); +- } +- *slash = '\0'; +- Buf_AddBytes(buf, strlen(word), word); +- *slash = '/'; +- return (TRUE); ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ } ++ *slash = '\0'; ++ Buf_AddBytes(buf, strlen(word), word); ++ *slash = '/'; ++ return (TRUE); + } else { +- /* ++ /* + * If no directory part, give . (q.v. the POSIX standard) + */ +- if (addSpace && vpstate->varSpace) +- Buf_AddByte(buf, vpstate->varSpace); +- Buf_AddByte(buf, '.'); ++ if (addSpace && vpstate->varSpace) ++ Buf_AddByte(buf, vpstate->varSpace); ++ Buf_AddByte(buf, '.'); + } +@@ -1232,5 +1281,4 @@ static Boolean + VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, +- char *word, Boolean addSpace, Buffer *buf, +- void *dummy MAKE_ATTR_UNUSED) +-{ ++ char *word, Boolean addSpace, Buffer *buf, ++ void *dummy MAKE_ATTR_UNUSED) { + char *slash; +@@ -1238,3 +1286,3 @@ VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); ++ Buf_AddByte(buf, vpstate->varSpace); + } +@@ -1243,7 +1291,7 @@ VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + if (slash != NULL) { +- *slash++ = '\0'; +- Buf_AddBytes(buf, strlen(slash), slash); +- slash[-1] = '/'; ++ *slash++ = '\0'; ++ Buf_AddBytes(buf, strlen(slash), slash); ++ slash[-1] = '/'; + } else { +- Buf_AddBytes(buf, strlen(word), word); ++ Buf_AddBytes(buf, strlen(word), word); + } +@@ -1274,5 +1322,4 @@ static Boolean + VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, +- char *word, Boolean addSpace, Buffer *buf, +- void *dummy MAKE_ATTR_UNUSED) +-{ ++ char *word, Boolean addSpace, Buffer *buf, ++ void *dummy MAKE_ATTR_UNUSED) { + char *dot; +@@ -1281,9 +1328,9 @@ VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + if (dot != NULL) { +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); +- } +- *dot++ = '\0'; +- Buf_AddBytes(buf, strlen(dot), dot); +- dot[-1] = '.'; +- addSpace = TRUE; ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ } ++ *dot++ = '\0'; ++ Buf_AddBytes(buf, strlen(dot), dot); ++ dot[-1] = '.'; ++ addSpace = TRUE; + } +@@ -1315,5 +1362,4 @@ static Boolean + VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, +- char *word, Boolean addSpace, Buffer *buf, +- void *dummy MAKE_ATTR_UNUSED) +-{ ++ char *word, Boolean addSpace, Buffer *buf, ++ void *dummy MAKE_ATTR_UNUSED) { + char *dot; +@@ -1321,3 +1367,3 @@ VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); ++ Buf_AddByte(buf, vpstate->varSpace); + } +@@ -1326,7 +1372,7 @@ VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + if (dot != NULL) { +- *dot = '\0'; +- Buf_AddBytes(buf, strlen(word), word); +- *dot = '.'; ++ *dot = '\0'; ++ Buf_AddBytes(buf, strlen(word), word); ++ *dot = '.'; + } else { +- Buf_AddBytes(buf, strlen(word), word); ++ Buf_AddBytes(buf, strlen(word), word); + } +@@ -1359,15 +1405,14 @@ static Boolean + VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, +- char *word, Boolean addSpace, Buffer *buf, +- void *pattern) +-{ ++ char *word, Boolean addSpace, Buffer *buf, ++ void *pattern) { + if (DEBUG(VAR)) +- fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *)pattern); +- if (Str_Match(word, (char *)pattern)) { +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); +- } +- addSpace = TRUE; +- Buf_AddBytes(buf, strlen(word), word); ++ fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *) pattern); ++ if (Str_Match(word, (char *) pattern)) { ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ } ++ addSpace = TRUE; ++ Buf_AddBytes(buf, strlen(word), word); + } +- return(addSpace); ++ return (addSpace); + } +@@ -1375,2 +1420,3 @@ VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + #ifdef SYSVVARSUB ++ + /*- +@@ -1400,8 +1446,7 @@ static Boolean + VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, +- char *word, Boolean addSpace, Buffer *buf, +- void *patp) +-{ ++ char *word, Boolean addSpace, Buffer *buf, ++ void *patp) { + int len; + char *ptr; +- VarPattern *pat = (VarPattern *)patp; ++ VarPattern *pat = (VarPattern *) patp; + char *varexp; +@@ -1409,3 +1454,3 @@ VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, + if (addSpace && vpstate->varSpace) +- Buf_AddByte(buf, vpstate->varSpace); ++ Buf_AddByte(buf, vpstate->varSpace); + +@@ -1415,10 +1460,11 @@ VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, + varexp = Var_Subst(NULL, pat->rhs, ctx, VARF_WANTRES); +- Str_SYSVSubst(buf, varexp, ptr, len); +- free(varexp); ++ Str_SYSVSubst(buf, varexp, ptr, len); ++ free(varexp); + } else { +- Buf_AddBytes(buf, strlen(word), word); ++ Buf_AddBytes(buf, strlen(word), word); + } + +- return(addSpace); ++ return (addSpace); + } ++ + #endif +@@ -1450,13 +1496,12 @@ static Boolean + VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, +- char *word, Boolean addSpace, Buffer *buf, +- void *pattern) +-{ +- if (!Str_Match(word, (char *)pattern)) { +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); +- } +- addSpace = TRUE; +- Buf_AddBytes(buf, strlen(word), word); ++ char *word, Boolean addSpace, Buffer *buf, ++ void *pattern) { ++ if (!Str_Match(word, (char *) pattern)) { ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ } ++ addSpace = TRUE; ++ Buf_AddBytes(buf, strlen(word), word); + } +- return(addSpace); ++ return (addSpace); + } +@@ -1487,13 +1532,12 @@ static Boolean + VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, +- char *word, Boolean addSpace, Buffer *buf, +- void *patternp) +-{ +- int wordLen; /* Length of word */ +- char *cp; /* General pointer */ +- VarPattern *pattern = (VarPattern *)patternp; ++ char *word, Boolean addSpace, Buffer *buf, ++ void *patternp) { ++ int wordLen; /* Length of word */ ++ char *cp; /* General pointer */ ++ VarPattern *pattern = (VarPattern *) patternp; + + wordLen = strlen(word); +- if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) != +- (VAR_SUB_ONE|VAR_SUB_MATCHED)) { +- /* ++ if ((pattern->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) != ++ (VAR_SUB_ONE | VAR_SUB_MATCHED)) { ++ /* + * Still substituting -- break it down into simple anchored cases +@@ -1501,10 +1545,10 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + */ +- if ((pattern->flags & VAR_MATCH_START) && +- (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { +- /* ++ if ((pattern->flags & VAR_MATCH_START) && ++ (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { ++ /* + * Anchored at start and beginning of word matches pattern + */ +- if ((pattern->flags & VAR_MATCH_END) && +- (wordLen == pattern->leftLen)) { +- /* ++ if ((pattern->flags & VAR_MATCH_END) && ++ (wordLen == pattern->leftLen)) { ++ /* + * Also anchored at end and matches to the end (word +@@ -1513,37 +1557,37 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + */ +- if (pattern->rightLen != 0) { +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); +- } +- addSpace = TRUE; +- Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); +- } +- pattern->flags |= VAR_SUB_MATCHED; +- } else if (pattern->flags & VAR_MATCH_END) { +- /* ++ if (pattern->rightLen != 0) { ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ } ++ addSpace = TRUE; ++ Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); ++ } ++ pattern->flags |= VAR_SUB_MATCHED; ++ } else if (pattern->flags & VAR_MATCH_END) { ++ /* + * Doesn't match to end -- copy word wholesale + */ +- goto nosub; +- } else { +- /* ++ goto nosub; ++ } else { ++ /* + * Matches at start but need to copy in trailing characters + */ +- if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){ +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); +- } +- addSpace = TRUE; +- } +- Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); +- Buf_AddBytes(buf, wordLen - pattern->leftLen, +- (word + pattern->leftLen)); +- pattern->flags |= VAR_SUB_MATCHED; +- } +- } else if (pattern->flags & VAR_MATCH_START) { +- /* ++ if ((pattern->rightLen + wordLen - pattern->leftLen) != 0) { ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ } ++ addSpace = TRUE; ++ } ++ Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); ++ Buf_AddBytes(buf, wordLen - pattern->leftLen, ++ (word + pattern->leftLen)); ++ pattern->flags |= VAR_SUB_MATCHED; ++ } ++ } else if (pattern->flags & VAR_MATCH_START) { ++ /* + * Had to match at start of word and didn't -- copy whole word. + */ +- goto nosub; +- } else if (pattern->flags & VAR_MATCH_END) { +- /* ++ goto nosub; ++ } else if (pattern->flags & VAR_MATCH_END) { ++ /* + * Anchored at end, Find only place match could occur (leftLen +@@ -1553,6 +1597,6 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + */ +- cp = word + (wordLen - pattern->leftLen); +- if ((cp >= word) && +- (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { +- /* ++ cp = word + (wordLen - pattern->leftLen); ++ if ((cp >= word) && ++ (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { ++ /* + * Match found. If we will place characters in the buffer, +@@ -1562,19 +1606,19 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + */ +- if (((cp - word) + pattern->rightLen) != 0) { +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); +- } +- addSpace = TRUE; +- } +- Buf_AddBytes(buf, cp - word, word); +- Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); +- pattern->flags |= VAR_SUB_MATCHED; +- } else { +- /* ++ if (((cp - word) + pattern->rightLen) != 0) { ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ } ++ addSpace = TRUE; ++ } ++ Buf_AddBytes(buf, cp - word, word); ++ Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); ++ pattern->flags |= VAR_SUB_MATCHED; ++ } else { ++ /* + * Had to match at end and didn't. Copy entire word. + */ +- goto nosub; +- } +- } else { +- /* ++ goto nosub; ++ } ++ } else { ++ /* + * Pattern is unanchored: search for the pattern in the word using +@@ -1589,36 +1633,36 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + */ +- Boolean done; +- int origSize; +- +- done = FALSE; +- origSize = Buf_Size(buf); +- while (!done) { +- cp = Str_FindSubstring(word, pattern->lhs); +- if (cp != NULL) { +- if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ +- Buf_AddByte(buf, vpstate->varSpace); +- addSpace = FALSE; +- } +- Buf_AddBytes(buf, cp-word, word); +- Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); +- wordLen -= (cp - word) + pattern->leftLen; +- word = cp + pattern->leftLen; +- if (wordLen == 0) { +- done = TRUE; +- } +- if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { +- done = TRUE; +- } +- pattern->flags |= VAR_SUB_MATCHED; +- } else { +- done = TRUE; +- } +- } +- if (wordLen != 0) { +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); +- } +- Buf_AddBytes(buf, wordLen, word); +- } +- /* ++ Boolean done; ++ int origSize; ++ ++ done = FALSE; ++ origSize = Buf_Size(buf); ++ while (!done) { ++ cp = Str_FindSubstring(word, pattern->lhs); ++ if (cp != NULL) { ++ if (addSpace && (((cp - word) + pattern->rightLen) != 0)) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ addSpace = FALSE; ++ } ++ Buf_AddBytes(buf, cp - word, word); ++ Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); ++ wordLen -= (cp - word) + pattern->leftLen; ++ word = cp + pattern->leftLen; ++ if (wordLen == 0) { ++ done = TRUE; ++ } ++ if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { ++ done = TRUE; ++ } ++ pattern->flags |= VAR_SUB_MATCHED; ++ } else { ++ done = TRUE; ++ } ++ } ++ if (wordLen != 0) { ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ } ++ Buf_AddBytes(buf, wordLen, word); ++ } ++ /* + * If added characters to the buffer, need to add a space +@@ -1627,12 +1671,12 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + */ +- return ((Buf_Size(buf) != origSize) || addSpace); +- } +- return (addSpace); ++ return ((Buf_Size(buf) != origSize) || addSpace); ++ } ++ return (addSpace); + } +- nosub: ++ nosub: + if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); ++ Buf_AddByte(buf, vpstate->varSpace); + } + Buf_AddBytes(buf, wordLen, word); +- return(TRUE); ++ return (TRUE); + } +@@ -1640,2 +1684,3 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + #ifndef NO_REGEX ++ + /*- +@@ -1654,4 +1699,3 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + static void +-VarREError(int reerr, regex_t *pat, const char *str) +-{ ++VarREError(int reerr, regex_t *pat, const char *str) { + char *errbuf; +@@ -1683,6 +1727,5 @@ static Boolean + VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, +- Var_Parse_State *vpstate MAKE_ATTR_UNUSED, +- char *word, Boolean addSpace, Buffer *buf, +- void *patternp) +-{ ++ Var_Parse_State *vpstate MAKE_ATTR_UNUSED, ++ char *word, Boolean addSpace, Buffer *buf, ++ void *patternp) { + VarREPattern *pat; +@@ -1694,6 +1737,6 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, + +-#define MAYBE_ADD_SPACE() \ +- if (addSpace && !added) \ +- Buf_AddByte(buf, ' '); \ +- added = 1 ++#define MAYBE_ADD_SPACE() \ ++ if (addSpace && !added) \ ++ Buf_AddByte(buf, ' '); \ ++ added = 1 + +@@ -1703,8 +1746,8 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, + +- if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) == +- (VAR_SUB_ONE|VAR_SUB_MATCHED)) +- xrv = REG_NOMATCH; ++ if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) == ++ (VAR_SUB_ONE | VAR_SUB_MATCHED)) ++ xrv = REG_NOMATCH; + else { +- tryagain: +- xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); ++ tryagain: ++ xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); + } +@@ -1712,88 +1755,87 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, + switch (xrv) { +- case 0: +- pat->flags |= VAR_SUB_MATCHED; +- if (pat->matches[0].rm_so > 0) { +- MAYBE_ADD_SPACE(); +- Buf_AddBytes(buf, pat->matches[0].rm_so, wp); +- } +- +- for (rp = pat->replace; *rp; rp++) { +- if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { +- MAYBE_ADD_SPACE(); +- Buf_AddByte(buf,rp[1]); +- rp++; +- } +- else if ((*rp == '&') || +- ((*rp == '\\') && isdigit((unsigned char)rp[1]))) { +- int n; +- const char *subbuf; +- int sublen; +- char errstr[3]; +- +- if (*rp == '&') { +- n = 0; +- errstr[0] = '&'; +- errstr[1] = '\0'; +- } else { +- n = rp[1] - '0'; +- errstr[0] = '\\'; +- errstr[1] = rp[1]; +- errstr[2] = '\0'; +- rp++; +- } +- +- if (n > pat->nsub) { +- Error("No subexpression %s", &errstr[0]); +- subbuf = ""; +- sublen = 0; +- } else if ((pat->matches[n].rm_so == -1) && +- (pat->matches[n].rm_eo == -1)) { +- Error("No match for subexpression %s", &errstr[0]); +- subbuf = ""; +- sublen = 0; +- } else { +- subbuf = wp + pat->matches[n].rm_so; +- sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; +- } +- +- if (sublen > 0) { +- MAYBE_ADD_SPACE(); +- Buf_AddBytes(buf, sublen, subbuf); +- } +- } else { +- MAYBE_ADD_SPACE(); +- Buf_AddByte(buf, *rp); +- } +- } +- wp += pat->matches[0].rm_eo; +- if (pat->flags & VAR_SUB_GLOBAL) { +- flags |= REG_NOTBOL; +- if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { +- MAYBE_ADD_SPACE(); +- Buf_AddByte(buf, *wp); +- wp++; +- +- } +- if (*wp) +- goto tryagain; +- } +- if (*wp) { +- MAYBE_ADD_SPACE(); +- Buf_AddBytes(buf, strlen(wp), wp); +- } +- break; +- default: +- VarREError(xrv, &pat->re, "Unexpected regex error"); +- /* fall through */ +- case REG_NOMATCH: +- if (*wp) { +- MAYBE_ADD_SPACE(); +- Buf_AddBytes(buf,strlen(wp),wp); +- } +- break; +- } +- return(addSpace||added); ++ case 0: ++ pat->flags |= VAR_SUB_MATCHED; ++ if (pat->matches[0].rm_so > 0) { ++ MAYBE_ADD_SPACE(); ++ Buf_AddBytes(buf, pat->matches[0].rm_so, wp); ++ } ++ ++ for (rp = pat->replace; *rp; rp++) { ++ if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { ++ MAYBE_ADD_SPACE(); ++ Buf_AddByte(buf, rp[1]); ++ rp++; ++ } else if ((*rp == '&') || ++ ((*rp == '\\') && isdigit((unsigned char) rp[1]))) { ++ int n; ++ const char *subbuf; ++ int sublen; ++ char errstr[3]; ++ ++ if (*rp == '&') { ++ n = 0; ++ errstr[0] = '&'; ++ errstr[1] = '\0'; ++ } else { ++ n = rp[1] - '0'; ++ errstr[0] = '\\'; ++ errstr[1] = rp[1]; ++ errstr[2] = '\0'; ++ rp++; ++ } ++ ++ if (n > pat->nsub) { ++ Error("No subexpression %s", &errstr[0]); ++ subbuf = ""; ++ sublen = 0; ++ } else if ((pat->matches[n].rm_so == -1) && ++ (pat->matches[n].rm_eo == -1)) { ++ Error("No match for subexpression %s", &errstr[0]); ++ subbuf = ""; ++ sublen = 0; ++ } else { ++ subbuf = wp + pat->matches[n].rm_so; ++ sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; ++ } ++ ++ if (sublen > 0) { ++ MAYBE_ADD_SPACE(); ++ Buf_AddBytes(buf, sublen, subbuf); ++ } ++ } else { ++ MAYBE_ADD_SPACE(); ++ Buf_AddByte(buf, *rp); ++ } ++ } ++ wp += pat->matches[0].rm_eo; ++ if (pat->flags & VAR_SUB_GLOBAL) { ++ flags |= REG_NOTBOL; ++ if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { ++ MAYBE_ADD_SPACE(); ++ Buf_AddByte(buf, *wp); ++ wp++; ++ ++ } ++ if (*wp) ++ goto tryagain; ++ } ++ if (*wp) { ++ MAYBE_ADD_SPACE(); ++ Buf_AddBytes(buf, strlen(wp), wp); ++ } ++ break; ++ default: ++ VarREError(xrv, &pat->re, "Unexpected regex error"); ++ /* fall through */ ++ case REG_NOMATCH: ++ if (*wp) { ++ MAYBE_ADD_SPACE(); ++ Buf_AddBytes(buf, strlen(wp), wp); ++ } ++ break; ++ } ++ return (addSpace || added); + } +-#endif + ++#endif + +@@ -1824,7 +1866,6 @@ static Boolean + VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, +- Var_Parse_State *vpstate MAKE_ATTR_UNUSED, +- char *word, Boolean addSpace, Buffer *buf, +- void *loopp) +-{ +- VarLoop_t *loop = (VarLoop_t *)loopp; ++ Var_Parse_State *vpstate MAKE_ATTR_UNUSED, ++ char *word, Boolean addSpace, Buffer *buf, ++ void *loopp) { ++ VarLoop_t *loop = (VarLoop_t *) loopp; + char *s; +@@ -1841,3 +1882,3 @@ VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, + } +- free(s); ++ free(s); + } +@@ -1868,10 +1909,9 @@ static char * + VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, +- const char *str, VarSelectWords_t *seldata) +-{ +- Buffer buf; /* Buffer for the new string */ +- Boolean addSpace; /* TRUE if need to add a space to the ++ const char *str, VarSelectWords_t *seldata) { ++ Buffer buf; /* Buffer for the new string */ ++ Boolean addSpace; /* TRUE if need to add a space to the + * buffer before adding the trimmed + * word */ +- char **av; /* word list */ +- char *as; /* word list memory */ ++ char **av; /* word list */ ++ char *as; /* word list memory */ + int ac, i; +@@ -1883,10 +1923,10 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + if (vpstate->oneBigWord) { +- /* fake what brk_string() would do if there were only one word */ +- ac = 1; +- av = bmake_malloc((ac + 1) * sizeof(char *)); +- as = bmake_strdup(str); +- av[0] = as; +- av[1] = NULL; ++ /* fake what brk_string() would do if there were only one word */ ++ ac = 1; ++ av = bmake_malloc((ac + 1) * sizeof(char *)); ++ as = bmake_strdup(str); ++ av[0] = as; ++ av[1] = NULL; + } else { +- av = brk_string(str, &ac, FALSE, &as); ++ av = brk_string(str, &ac, FALSE, &as); + } +@@ -1900,5 +1940,5 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + if (seldata->start < 0) +- seldata->start = ac + seldata->start + 1; ++ seldata->start = ac + seldata->start + 1; + if (seldata->end < 0) +- seldata->end = ac + seldata->end + 1; ++ seldata->end = ac + seldata->end + 1; + +@@ -1908,9 +1948,9 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + if (seldata->start > seldata->end) { +- start = MIN(ac, seldata->start) - 1; +- end = MAX(0, seldata->end - 1); +- step = -1; ++ start = MIN(ac, seldata->start) - 1; ++ end = MAX(0, seldata->end - 1); ++ step = -1; + } else { +- start = MAX(0, seldata->start - 1); +- end = MIN(ac, seldata->end); +- step = 1; ++ start = MAX(0, seldata->start - 1); ++ end = MIN(ac, seldata->end); ++ step = 1; + } +@@ -1918,11 +1958,11 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, + for (i = start; +- (step < 0 && i >= end) || (step > 0 && i < end); +- i += step) { +- if (av[i] && *av[i]) { +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(&buf, vpstate->varSpace); +- } +- Buf_AddBytes(&buf, strlen(av[i]), av[i]); +- addSpace = TRUE; +- } ++ (step < 0 && i >= end) || (step > 0 && i < end); ++ i += step) { ++ if (av[i] && *av[i]) { ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(&buf, vpstate->varSpace); ++ } ++ Buf_AddBytes(&buf, strlen(av[i]), av[i]); ++ addSpace = TRUE; ++ } + } +@@ -1943,19 +1983,18 @@ static Boolean + VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, +- char *word, Boolean addSpace, Buffer *buf, +- void *patternp MAKE_ATTR_UNUSED) +-{ +- struct stat st; +- char rbuf[MAXPATHLEN]; +- char *rp; +- +- if (addSpace && vpstate->varSpace) { +- Buf_AddByte(buf, vpstate->varSpace); +- } +- addSpace = TRUE; +- rp = cached_realpath(word, rbuf); +- if (rp && *rp == '/' && stat(rp, &st) == 0) +- word = rp; +- +- Buf_AddBytes(buf, strlen(word), word); +- return(addSpace); ++ char *word, Boolean addSpace, Buffer *buf, ++ void *patternp MAKE_ATTR_UNUSED) { ++ struct stat st; ++ char rbuf[MAXPATHLEN]; ++ char *rp; ++ ++ if (addSpace && vpstate->varSpace) { ++ Buf_AddByte(buf, vpstate->varSpace); ++ } ++ addSpace = TRUE; ++ rp = cached_realpath(word, rbuf); ++ if (rp && *rp == '/' && stat(rp, &st) == 0) ++ word = rp; ++ ++ Buf_AddBytes(buf, strlen(word), word); ++ return (addSpace); + } +@@ -1983,13 +2022,12 @@ static char * + VarModify(GNode *ctx, Var_Parse_State *vpstate, +- const char *str, +- Boolean (*modProc)(GNode *, Var_Parse_State *, char *, +- Boolean, Buffer *, void *), +- void *datum) +-{ +- Buffer buf; /* Buffer for the new string */ +- Boolean addSpace; /* TRUE if need to add a space to the ++ const char *str, ++ Boolean (*modProc)(GNode *, Var_Parse_State *, char *, ++ Boolean, Buffer *, void *), ++ void *datum) { ++ Buffer buf; /* Buffer for the new string */ ++ Boolean addSpace; /* TRUE if need to add a space to the + * buffer before adding the trimmed + * word */ +- char **av; /* word list */ +- char *as; /* word list memory */ ++ char **av; /* word list */ ++ char *as; /* word list memory */ + int ac, i; +@@ -2000,10 +2038,10 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate, + if (vpstate->oneBigWord) { +- /* fake what brk_string() would do if there were only one word */ +- ac = 1; +- av = bmake_malloc((ac + 1) * sizeof(char *)); +- as = bmake_strdup(str); +- av[0] = as; +- av[1] = NULL; ++ /* fake what brk_string() would do if there were only one word */ ++ ac = 1; ++ av = bmake_malloc((ac + 1) * sizeof(char *)); ++ as = bmake_strdup(str); ++ av[0] = as; ++ av[1] = NULL; + } else { +- av = brk_string(str, &ac, FALSE, &as); ++ av = brk_string(str, &ac, FALSE, &as); + } +@@ -2011,3 +2049,3 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate, + for (i = 0; i < ac; i++) { +- addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, &buf, datum); ++ addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, &buf, datum); + } +@@ -2022,6 +2060,5 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate, + static int +-VarWordCompare(const void *a, const void *b) +-{ +- int r = strcmp(*(const char * const *)a, *(const char * const *)b); +- return r; ++VarWordCompare(const void *a, const void *b) { ++ int r = strcmp(*(const char *const *) a, *(const char *const *) b); ++ return r; + } +@@ -2046,7 +2083,6 @@ VarWordCompare(const void *a, const void *b) + static char * +-VarOrder(const char *str, const char otype) +-{ +- Buffer buf; /* Buffer for the new string */ +- char **av; /* word list [first word does not count] */ +- char *as; /* word list memory */ ++VarOrder(const char *str, const char otype) { ++ Buffer buf; /* Buffer for the new string */ ++ char **av; /* word list [first word does not count] */ ++ char *as; /* word list memory */ + int ac, i; +@@ -2058,12 +2094,12 @@ VarOrder(const char *str, const char otype) + if (ac > 0) +- switch (otype) { +- case 's': /* sort alphabetically */ +- qsort(av, ac, sizeof(char *), VarWordCompare); +- break; +- case 'x': /* randomize */ +- { +- int rndidx; +- char *t; +- +- /* ++ switch (otype) { ++ case 's': /* sort alphabetically */ ++ qsort(av, ac, sizeof(char *), VarWordCompare); ++ break; ++ case 'x': /* randomize */ ++ { ++ int rndidx; ++ char *t; ++ ++ /* + * We will use [ac..2] range for mod factors. This will produce +@@ -2073,17 +2109,17 @@ VarOrder(const char *str, const char otype) + */ +- for (i = ac-1; i > 0; i--) { +- rndidx = random() % (i + 1); +- if (i != rndidx) { +- t = av[i]; +- av[i] = av[rndidx]; +- av[rndidx] = t; +- } +- } +- } +- } /* end of switch */ ++ for (i = ac - 1; i > 0; i--) { ++ rndidx = random() % (i + 1); ++ if (i != rndidx) { ++ t = av[i]; ++ av[i] = av[rndidx]; ++ av[rndidx] = t; ++ } ++ } ++ } ++ } /* end of switch */ + + for (i = 0; i < ac; i++) { +- Buf_AddBytes(&buf, strlen(av[i]), av[i]); +- if (i != ac - 1) +- Buf_AddByte(&buf, ' '); ++ Buf_AddBytes(&buf, strlen(av[i]), av[i]); ++ if (i != ac - 1) ++ Buf_AddByte(&buf, ' '); + } +@@ -2114,8 +2150,7 @@ VarOrder(const char *str, const char otype) + static char * +-VarUniq(const char *str) +-{ +- Buffer buf; /* Buffer for new string */ +- char **av; /* List of words to affect */ +- char *as; /* Word list memory */ +- int ac, i, j; ++VarUniq(const char *str) { ++ Buffer buf; /* Buffer for new string */ ++ char **av; /* List of words to affect */ ++ char *as; /* Word list memory */ ++ int ac, i, j; + +@@ -2125,6 +2160,6 @@ VarUniq(const char *str) + if (ac > 1) { +- for (j = 0, i = 1; i < ac; i++) +- if (strcmp(av[i], av[j]) != 0 && (++j != i)) +- av[j] = av[i]; +- ac = j + 1; ++ for (j = 0, i = 1; i < ac; i++) ++ if (strcmp(av[i], av[j]) != 0 && (++j != i)) ++ av[j] = av[i]; ++ ac = j + 1; + } +@@ -2132,5 +2167,5 @@ VarUniq(const char *str) + for (i = 0; i < ac; i++) { +- Buf_AddBytes(&buf, strlen(av[i]), av[i]); +- if (i != ac - 1) +- Buf_AddByte(&buf, ' '); ++ Buf_AddBytes(&buf, strlen(av[i]), av[i]); ++ if (i != ac - 1) ++ Buf_AddByte(&buf, ' '); + } +@@ -2158,9 +2193,8 @@ VarUniq(const char *str) + static char * +-VarRange(const char *str, int ac) +-{ +- Buffer buf; /* Buffer for new string */ +- char tmp[32]; /* each element */ +- char **av; /* List of words to affect */ +- char *as; /* Word list memory */ +- int i, n; ++VarRange(const char *str, int ac) { ++ Buffer buf; /* Buffer for new string */ ++ char tmp[32]; /* each element */ ++ char **av; /* List of words to affect */ ++ char *as; /* Word list memory */ ++ int i, n; + +@@ -2168,14 +2202,14 @@ VarRange(const char *str, int ac) + if (ac > 0) { +- as = NULL; +- av = NULL; ++ as = NULL; ++ av = NULL; + } else { +- av = brk_string(str, &ac, FALSE, &as); ++ av = brk_string(str, &ac, FALSE, &as); + } + for (i = 0; i < ac; i++) { +- n = snprintf(tmp, sizeof(tmp), "%d", 1 + i); +- if (n >= (int)sizeof(tmp)) +- break; +- Buf_AddBytes(&buf, n, tmp); +- if (i != ac - 1) +- Buf_AddByte(&buf, ' '); ++ n = snprintf(tmp, sizeof(tmp), "%d", 1 + i); ++ if (n >= (int) sizeof(tmp)) ++ break; ++ Buf_AddBytes(&buf, n, tmp); ++ if (i != ac - 1) ++ Buf_AddByte(&buf, ' '); + } +@@ -2213,5 +2247,4 @@ static char * + VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, +- int flags, const char **tstr, int delim, int *vflags, +- int *length, VarPattern *pattern) +-{ ++ int flags, const char **tstr, int delim, int *vflags, ++ int *length, VarPattern *pattern) { + const char *cp; +@@ -2224,3 +2257,3 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + if (length == NULL) +- length = &junk; ++ length = &junk; + +@@ -2237,11 +2270,11 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + for (cp = *tstr; *cp && (*cp != delim); cp++) { +- if (IS_A_MATCH(cp, delim)) { +- Buf_AddByte(&buf, cp[1]); +- cp++; +- } else if (*cp == '$') { +- if (cp[1] == delim) { +- if (vflags == NULL) +- Buf_AddByte(&buf, *cp); +- else +- /* ++ if (IS_A_MATCH(cp, delim)) { ++ Buf_AddByte(&buf, cp[1]); ++ cp++; ++ } else if (*cp == '$') { ++ if (cp[1] == delim) { ++ if (vflags == NULL) ++ Buf_AddByte(&buf, *cp); ++ else ++ /* + * Unescaped $ at end of pattern => anchor +@@ -2249,10 +2282,10 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + */ +- *vflags |= VAR_MATCH_END; +- } else { +- if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) { +- char *cp2; +- int len; +- void *freeIt; +- +- /* ++ *vflags |= VAR_MATCH_END; ++ } else { ++ if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) { ++ char *cp2; ++ int len; ++ void *freeIt; ++ ++ /* + * If unescaped dollar sign not before the +@@ -2261,12 +2294,12 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + */ +- cp2 = Var_Parse(cp, ctxt, errnum | VARF_WANTRES, &len, +- &freeIt); +- Buf_AddBytes(&buf, strlen(cp2), cp2); +- free(freeIt); +- cp += len - 1; +- } else { +- const char *cp2 = &cp[1]; +- +- if (*cp2 == PROPEN || *cp2 == BROPEN) { +- /* ++ cp2 = Var_Parse(cp, ctxt, errnum | VARF_WANTRES, &len, ++ &freeIt); ++ Buf_AddBytes(&buf, strlen(cp2), cp2); ++ free(freeIt); ++ cp += len - 1; ++ } else { ++ const char *cp2 = &cp[1]; ++ ++ if (*cp2 == PROPEN || *cp2 == BROPEN) { ++ /* + * Find the end of this variable reference +@@ -2275,25 +2308,24 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + */ +- int have = *cp2; +- int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; +- int depth = 1; +- +- for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { +- if (cp2[-1] != '\\') { +- if (*cp2 == have) +- ++depth; +- if (*cp2 == want) +- --depth; +- } +- } +- Buf_AddBytes(&buf, cp2 - cp, cp); +- cp = --cp2; +- } else +- Buf_AddByte(&buf, *cp); +- } +- } +- } +- else if (pattern && *cp == '&') +- Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs); +- else +- Buf_AddByte(&buf, *cp); ++ int have = *cp2; ++ int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; ++ int depth = 1; ++ ++ for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { ++ if (cp2[-1] != '\\') { ++ if (*cp2 == have) ++ ++depth; ++ if (*cp2 == want) ++ --depth; ++ } ++ } ++ Buf_AddBytes(&buf, cp2 - cp, cp); ++ cp = --cp2; ++ } else ++ Buf_AddByte(&buf, *cp); ++ } ++ } ++ } else if (pattern && *cp == '&') ++ Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs); ++ else ++ Buf_AddByte(&buf, *cp); + } +@@ -2301,5 +2333,5 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + if (*cp != delim) { +- *tstr = cp; +- *length = 0; +- return NULL; ++ *tstr = cp; ++ *length = 0; ++ return NULL; + } +@@ -2310,3 +2342,3 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + if (DEBUG(VAR)) +- fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr); ++ fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr); + return rstr; +@@ -2329,7 +2361,6 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + static char * +-VarQuote(char *str, Boolean quoteDollar) +-{ ++VarQuote(char *str, Boolean quoteDollar) { + +- Buffer buf; +- const char *newline; ++ Buffer buf; ++ const char *newline; + size_t nlen; +@@ -2337,3 +2368,3 @@ VarQuote(char *str, Boolean quoteDollar) + if ((newline = Shell_GetNewline()) == NULL) +- newline = "\\\n"; ++ newline = "\\\n"; + nlen = strlen(newline); +@@ -2343,11 +2374,11 @@ VarQuote(char *str, Boolean quoteDollar) + for (; *str != '\0'; str++) { +- if (*str == '\n') { +- Buf_AddBytes(&buf, nlen, newline); +- continue; +- } +- if (isspace((unsigned char)*str) || ismeta((unsigned char)*str)) +- Buf_AddByte(&buf, '\\'); +- Buf_AddByte(&buf, *str); +- if (quoteDollar && *str == '$') +- Buf_AddBytes(&buf, 2, "\\$"); ++ if (*str == '\n') { ++ Buf_AddBytes(&buf, nlen, newline); ++ continue; ++ } ++ if (isspace((unsigned char) *str) || ismeta((unsigned char) *str)) ++ Buf_AddByte(&buf, '\\'); ++ Buf_AddByte(&buf, *str); ++ if (quoteDollar && *str == '$') ++ Buf_AddBytes(&buf, 2, "\\$"); + } +@@ -2356,3 +2387,3 @@ VarQuote(char *str, Boolean quoteDollar) + if (DEBUG(VAR)) +- fprintf(debug_file, "QuoteMeta: [%s]\n", str); ++ fprintf(debug_file, "QuoteMeta: [%s]\n", str); + return str; +@@ -2378,11 +2409,10 @@ VarQuote(char *str, Boolean quoteDollar) + static char * +-VarHash(char *str) +-{ +- static const char hexdigits[16] = "0123456789abcdef"; +- Buffer buf; +- size_t len, len2; +- unsigned char *ustr = (unsigned char *)str; +- unsigned int h, k, c1, c2; ++VarHash(char *str) { ++ static const char hexdigits[16] = "0123456789abcdef"; ++ Buffer buf; ++ size_t len, len2; ++ unsigned char *ustr = (unsigned char *) str; ++ unsigned int h, k, c1, c2; + +- h = 0x971e137bU; ++ h = 0x971e137bU; + c1 = 0x95543787U; +@@ -2391,40 +2421,40 @@ VarHash(char *str) + +- for (len = len2; len; ) { +- k = 0; +- switch (len) { +- default: +- k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0]; +- len -= 4; +- ustr += 4; +- break; +- case 3: +- k |= (ustr[2] << 16); +- case 2: +- k |= (ustr[1] << 8); +- case 1: +- k |= ustr[0]; +- len = 0; +- } +- c1 = c1 * 5 + 0x7b7d159cU; +- c2 = c2 * 5 + 0x6bce6396U; +- k *= c1; +- k = (k << 11) ^ (k >> 21); +- k *= c2; +- h = (h << 13) ^ (h >> 19); +- h = h * 5 + 0x52dce729U; +- h ^= k; +- } +- h ^= len2; +- h *= 0x85ebca6b; +- h ^= h >> 13; +- h *= 0xc2b2ae35; +- h ^= h >> 16; +- +- Buf_Init(&buf, 0); +- for (len = 0; len < 8; ++len) { +- Buf_AddByte(&buf, hexdigits[h & 15]); +- h >>= 4; +- } +- +- return Buf_Destroy(&buf, FALSE); ++ for (len = len2; len;) { ++ k = 0; ++ switch (len) { ++ default: ++ k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0]; ++ len -= 4; ++ ustr += 4; ++ break; ++ case 3: ++ k |= (ustr[2] << 16); ++ case 2: ++ k |= (ustr[1] << 8); ++ case 1: ++ k |= ustr[0]; ++ len = 0; ++ } ++ c1 = c1 * 5 + 0x7b7d159cU; ++ c2 = c2 * 5 + 0x6bce6396U; ++ k *= c1; ++ k = (k << 11) ^ (k >> 21); ++ k *= c2; ++ h = (h << 13) ^ (h >> 19); ++ h = h * 5 + 0x52dce729U; ++ h ^= k; ++ } ++ h ^= len2; ++ h *= 0x85ebca6b; ++ h ^= h >> 13; ++ h *= 0xc2b2ae35; ++ h ^= h >> 16; ++ ++ Buf_Init(&buf, 0); ++ for (len = 0; len < 8; ++len) { ++ Buf_AddByte(&buf, hexdigits[h & 15]); ++ h >>= 4; ++ } ++ ++ return Buf_Destroy(&buf, FALSE); + } +@@ -2432,4 +2462,3 @@ VarHash(char *str) + static char * +-VarStrftime(const char *fmt, int zulu, time_t utc) +-{ ++VarStrftime(const char *fmt, int zulu, time_t utc) { + char buf[BUFSIZ]; +@@ -2437,7 +2466,7 @@ VarStrftime(const char *fmt, int zulu, time_t utc) + if (!utc) +- time(&utc); ++ time(&utc); + if (!*fmt) +- fmt = "%c"; ++ fmt = "%c"; + strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc)); +- ++ + buf[sizeof(buf) - 1] = '\0'; +@@ -2540,18 +2569,29 @@ static char * + ApplyModifiers(char *nstr, const char *tstr, +- int startc, int endc, +- Var *v, GNode *ctxt, int flags, +- int *lengthPtr, void **freePtr) +-{ +- const char *start; +- const char *cp; /* Secondary pointer into str (place marker ++ int startc, int endc, ++ Var *v, GNode *ctxt, int flags, ++ int *lengthPtr, void **freePtr) { ++ const char *start; ++ const char *cp; /* Secondary pointer into str (place marker + * for tstr) */ +- char *newStr; /* New value to return */ +- char *ep; +- char termc; /* Character which terminated scan */ +- int cnt; /* Used to count brace pairs when variable in ++#if (defined _WIN32 && ! defined __CYGWIN__) ++ char *unix_nstr; ++ char *error; ++ if (nstr && strlen(nstr) > 0 && nstr[1] == ':' && (nstr[2] == '/' || nstr[2] == '\\')) { ++ unix_nstr = Cmd_Exec(getUnixPathCmd(nstr), &error); ++ } ++ else { ++ unix_nstr = nstr; ++ } ++#else ++ char *unix_nstr = nstr; ++#endif ++ char *newStr; /* New value to return */ ++ char *ep; ++ char termc; /* Character which terminated scan */ ++ int cnt; /* Used to count brace pairs when variable in + * in parens or braces */ +- char delim; +- int modifier; /* that we are processing */ ++ char delim; ++ int modifier; /* that we are processing */ + Var_Parse_State parsestate; /* Flags passed to helper functions */ +- time_t utc; /* for VarStrftime */ ++ time_t utc; /* for VarStrftime */ + +@@ -2559,3 +2599,3 @@ ApplyModifiers(char *nstr, const char *tstr, + parsestate.oneBigWord = FALSE; +- parsestate.varSpace = ' '; /* word separator */ ++ parsestate.varSpace = ' '; /* word separator */ + +@@ -2565,14 +2605,14 @@ ApplyModifiers(char *nstr, const char *tstr, + +- if (*tstr == '$') { +- /* ++ if (*tstr == '$') { ++ /* + * We may have some complex modifiers in a variable. + */ +- void *freeIt; +- char *rval; +- int rlen; +- int c; ++ void *freeIt; ++ char *rval; ++ int rlen; ++ int c; + +- rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); ++ rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); + +- /* ++ /* + * If we have not parsed up to endc or ':', +@@ -2580,68 +2620,67 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- if (rval != NULL && *rval && +- (c = tstr[rlen]) != '\0' && +- c != ':' && +- c != endc) { +- free(freeIt); +- goto apply_mods; +- } +- +- if (DEBUG(VAR)) { +- fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", +- rval, rlen, tstr, rlen, tstr + rlen); +- } +- +- tstr += rlen; +- +- if (rval != NULL && *rval) { +- int used; +- +- nstr = ApplyModifiers(nstr, rval, +- 0, 0, v, ctxt, flags, &used, freePtr); +- if (nstr == var_Error +- || (nstr == varNoError && (flags & VARF_UNDEFERR) == 0) +- || strlen(rval) != (size_t) used) { +- free(freeIt); +- goto out; /* error already reported */ +- } +- } +- free(freeIt); +- if (*tstr == ':') +- tstr++; +- else if (!*tstr && endc) { +- Error("Unclosed variable specification after complex modifier (expecting '%c') for %s", endc, v->name); +- goto out; +- } +- continue; +- } +- apply_mods: +- if (DEBUG(VAR)) { +- fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", v->name, +- *tstr, nstr); +- } +- newStr = var_Error; +- switch ((modifier = *tstr)) { +- case ':': +- { +- if (tstr[1] == '=' || +- (tstr[2] == '=' && +- (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) { +- /* ++ if (rval != NULL && *rval && ++ (c = tstr[rlen]) != '\0' && ++ c != ':' && ++ c != endc) { ++ free(freeIt); ++ goto apply_mods; ++ } ++ ++ if (DEBUG(VAR)) { ++ fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", ++ rval, rlen, tstr, rlen, tstr + rlen); ++ } ++ ++ tstr += rlen; ++ ++ if (rval != NULL && *rval) { ++ int used; ++ ++ unix_nstr = ApplyModifiers(unix_nstr, rval, ++ 0, 0, v, ctxt, flags, &used, freePtr); ++ if (unix_nstr == var_Error ++ || (unix_nstr == varNoError && (flags & VARF_UNDEFERR) == 0) ++ || strlen(rval) != (size_t) used) { ++ free(freeIt); ++ goto out; /* error already reported */ ++ } ++ } ++ free(freeIt); ++ if (*tstr == ':') ++ tstr++; ++ else if (!*tstr && endc) { ++ Error("Unclosed variable specification after complex modifier (expecting '%c') for %s", endc, v->name); ++ goto out; ++ } ++ continue; ++ } ++ apply_mods: ++ if (DEBUG(VAR)) { ++ fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", v->name, ++ *tstr, unix_nstr); ++ } ++ newStr = var_Error; ++ switch ((modifier = *tstr)) { ++ case ':': { ++ if (tstr[1] == '=' || ++ (tstr[2] == '=' && ++ (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) { ++ /* + * "::=", "::!=", "::+=", or "::?=" + */ +- GNode *v_ctxt; /* context where v belongs */ +- const char *emsg; +- char *sv_name; +- VarPattern pattern; +- int how; +- int vflags; +- +- if (v->name[0] == 0) +- goto bad_modifier; +- +- v_ctxt = ctxt; +- sv_name = NULL; +- ++tstr; +- if (v->flags & VAR_JUNK) { +- /* ++ GNode *v_ctxt; /* context where v belongs */ ++ const char *emsg; ++ char *sv_name; ++ VarPattern pattern; ++ int how; ++ int vflags; ++ ++ if (v->name[0] == 0) ++ goto bad_modifier; ++ ++ v_ctxt = ctxt; ++ sv_name = NULL; ++ ++tstr; ++ if (v->flags & VAR_JUNK) { ++ /* + * We need to bmake_strdup() it incase +@@ -2649,140 +2688,138 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- sv_name = v->name; +- v->name = bmake_strdup(v->name); +- } else if (ctxt != VAR_GLOBAL) { +- Var *gv = VarFind(v->name, ctxt, 0); +- if (gv == NULL) +- v_ctxt = VAR_GLOBAL; +- else +- VarFreeEnv(gv, TRUE); +- } +- +- switch ((how = *tstr)) { +- case '+': +- case '?': +- case '!': +- cp = &tstr[2]; +- break; +- default: +- cp = ++tstr; +- break; +- } +- delim = startc == PROPEN ? PRCLOSE : BRCLOSE; +- pattern.flags = 0; +- +- vflags = (flags & VARF_WANTRES) ? 0 : VAR_NOSUBST; +- pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, +- &cp, delim, &vflags, +- &pattern.rightLen, +- NULL); +- if (v->flags & VAR_JUNK) { +- /* restore original name */ +- free(v->name); +- v->name = sv_name; +- } +- if (pattern.rhs == NULL) +- goto cleanup; +- +- termc = *--cp; +- delim = '\0'; +- +- if (flags & VARF_WANTRES) { +- switch (how) { +- case '+': +- Var_Append(v->name, pattern.rhs, v_ctxt); +- break; +- case '!': +- newStr = Cmd_Exec(pattern.rhs, &emsg); +- if (emsg) +- Error(emsg, nstr); +- else +- Var_Set(v->name, newStr, v_ctxt, 0); +- free(newStr); +- break; +- case '?': +- if ((v->flags & VAR_JUNK) == 0) +- break; +- /* FALLTHROUGH */ +- default: +- Var_Set(v->name, pattern.rhs, v_ctxt, 0); +- break; +- } +- } +- free(UNCONST(pattern.rhs)); +- newStr = varNoError; +- break; +- } +- goto default_case; /* "::" */ +- } +- case '@': +- { +- VarLoop_t loop; +- int vflags = VAR_NOSUBST; +- +- cp = ++tstr; +- delim = '@'; +- if ((loop.tvar = VarGetPattern(ctxt, &parsestate, flags, +- &cp, delim, +- &vflags, &loop.tvarLen, +- NULL)) == NULL) +- goto cleanup; +- +- if ((loop.str = VarGetPattern(ctxt, &parsestate, flags, +- &cp, delim, +- &vflags, &loop.strLen, +- NULL)) == NULL) +- goto cleanup; +- +- termc = *cp; +- delim = '\0'; +- +- loop.errnum = flags & VARF_UNDEFERR; +- loop.ctxt = ctxt; +- newStr = VarModify(ctxt, &parsestate, nstr, VarLoopExpand, +- &loop); +- Var_Delete(loop.tvar, ctxt); +- free(loop.tvar); +- free(loop.str); +- break; +- } +- case '_': /* remember current value */ +- cp = tstr + 1; /* make sure it is set */ +- if (STRMOD_MATCHX(tstr, "_", 1)) { +- if (tstr[1] == '=') { +- char *np; +- int n; +- +- cp++; +- n = strcspn(cp, ":)}"); +- np = bmake_strndup(cp, n+1); +- np[n] = '\0'; +- cp = tstr + 2 + n; +- Var_Set(np, nstr, ctxt, 0); +- free(np); +- } else { +- Var_Set("_", nstr, ctxt, 0); +- } +- newStr = nstr; +- termc = *cp; +- break; +- } +- goto default_case; +- case 'D': +- case 'U': +- { +- Buffer buf; /* Buffer for patterns */ +- int nflags; +- +- if (flags & VARF_WANTRES) { +- int wantres; +- if (*tstr == 'U') +- wantres = ((v->flags & VAR_JUNK) != 0); +- else +- wantres = ((v->flags & VAR_JUNK) == 0); +- nflags = flags & ~VARF_WANTRES; +- if (wantres) +- nflags |= VARF_WANTRES; +- } else +- nflags = flags; +- /* ++ sv_name = v->name; ++ v->name = bmake_strdup(v->name); ++ } else if (ctxt != VAR_GLOBAL) { ++ Var *gv = VarFind(v->name, ctxt, 0); ++ if (gv == NULL) ++ v_ctxt = VAR_GLOBAL; ++ else ++ VarFreeEnv(gv, TRUE); ++ } ++ ++ switch ((how = *tstr)) { ++ case '+': ++ case '?': ++ case '!': ++ cp = &tstr[2]; ++ break; ++ default: ++ cp = ++tstr; ++ break; ++ } ++ delim = startc == PROPEN ? PRCLOSE : BRCLOSE; ++ pattern.flags = 0; ++ ++ vflags = (flags & VARF_WANTRES) ? 0 : VAR_NOSUBST; ++ pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, ++ &cp, delim, &vflags, ++ &pattern.rightLen, ++ NULL); ++ if (v->flags & VAR_JUNK) { ++ /* restore original name */ ++ free(v->name); ++ v->name = sv_name; ++ } ++ if (pattern.rhs == NULL) ++ goto cleanup; ++ ++ termc = *--cp; ++ delim = '\0'; ++ ++ if (flags & VARF_WANTRES) { ++ switch (how) { ++ case '+': ++ Var_Append(v->name, pattern.rhs, v_ctxt); ++ break; ++ case '!': ++ newStr = Cmd_Exec(pattern.rhs, &emsg); ++ if (emsg) ++ Error(emsg, unix_nstr); ++ else ++ Var_Set(v->name, newStr, v_ctxt, 0); ++ free(newStr); ++ break; ++ case '?': ++ if ((v->flags & VAR_JUNK) == 0) ++ break; ++ /* FALLTHROUGH */ ++ default: ++ Var_Set(v->name, pattern.rhs, v_ctxt, 0); ++ break; ++ } ++ } ++ free(UNCONST(pattern.rhs)); ++ newStr = varNoError; ++ break; ++ } ++ goto default_case; /* "::" */ ++ } ++ case '@': { ++ VarLoop_t loop; ++ int vflags = VAR_NOSUBST; ++ ++ cp = ++tstr; ++ delim = '@'; ++ if ((loop.tvar = VarGetPattern(ctxt, &parsestate, flags, ++ &cp, delim, ++ &vflags, &loop.tvarLen, ++ NULL)) == NULL) ++ goto cleanup; ++ ++ if ((loop.str = VarGetPattern(ctxt, &parsestate, flags, ++ &cp, delim, ++ &vflags, &loop.strLen, ++ NULL)) == NULL) ++ goto cleanup; ++ ++ termc = *cp; ++ delim = '\0'; ++ ++ loop.errnum = flags & VARF_UNDEFERR; ++ loop.ctxt = ctxt; ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, VarLoopExpand, ++ &loop); ++ Var_Delete(loop.tvar, ctxt); ++ free(loop.tvar); ++ free(loop.str); ++ break; ++ } ++ case '_': /* remember current value */ ++ cp = tstr + 1; /* make sure it is set */ ++ if (STRMOD_MATCHX(tstr, "_", 1)) { ++ if (tstr[1] == '=') { ++ char *np; ++ int n; ++ ++ cp++; ++ n = strcspn(cp, ":)}"); ++ np = bmake_strndup(cp, n + 1); ++ np[n] = '\0'; ++ cp = tstr + 2 + n; ++ Var_Set(np, unix_nstr, ctxt, 0); ++ free(np); ++ } else { ++ Var_Set("_", unix_nstr, ctxt, 0); ++ } ++ newStr = unix_nstr; ++ termc = *cp; ++ break; ++ } ++ goto default_case; ++ case 'D': ++ case 'U': { ++ Buffer buf; /* Buffer for patterns */ ++ int nflags; ++ ++ if (flags & VARF_WANTRES) { ++ int wantres; ++ if (*tstr == 'U') ++ wantres = ((v->flags & VAR_JUNK) != 0); ++ else ++ wantres = ((v->flags & VAR_JUNK) == 0); ++ nflags = flags & ~VARF_WANTRES; ++ if (wantres) ++ nflags |= VARF_WANTRES; ++ } else ++ nflags = flags; ++ /* + * Pass through tstr looking for 1) escaped delimiters, +@@ -2793,16 +2830,15 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- Buf_Init(&buf, 0); +- for (cp = tstr + 1; +- *cp != endc && *cp != ':' && *cp != '\0'; +- cp++) { +- if ((*cp == '\\') && +- ((cp[1] == ':') || +- (cp[1] == '$') || +- (cp[1] == endc) || +- (cp[1] == '\\'))) +- { +- Buf_AddByte(&buf, cp[1]); +- cp++; +- } else if (*cp == '$') { +- /* ++ Buf_Init(&buf, 0); ++ for (cp = tstr + 1; ++ *cp != endc && *cp != ':' && *cp != '\0'; ++ cp++) { ++ if ((*cp == '\\') && ++ ((cp[1] == ':') || ++ (cp[1] == '$') || ++ (cp[1] == endc) || ++ (cp[1] == '\\'))) { ++ Buf_AddByte(&buf, cp[1]); ++ cp++; ++ } else if (*cp == '$') { ++ /* + * If unescaped dollar sign, assume it's a +@@ -2810,88 +2846,84 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- char *cp2; +- int len; +- void *freeIt; +- +- cp2 = Var_Parse(cp, ctxt, nflags, &len, &freeIt); +- Buf_AddBytes(&buf, strlen(cp2), cp2); +- free(freeIt); +- cp += len - 1; +- } else { +- Buf_AddByte(&buf, *cp); +- } +- } +- +- termc = *cp; +- +- if ((v->flags & VAR_JUNK) != 0) +- v->flags |= VAR_KEEP; +- if (nflags & VARF_WANTRES) { +- newStr = Buf_Destroy(&buf, FALSE); +- } else { +- newStr = nstr; +- Buf_Destroy(&buf, TRUE); +- } +- break; +- } +- case 'L': +- { +- if ((v->flags & VAR_JUNK) != 0) +- v->flags |= VAR_KEEP; +- newStr = bmake_strdup(v->name); +- cp = ++tstr; +- termc = *tstr; +- break; +- } +- case 'P': +- { +- GNode *gn; +- +- if ((v->flags & VAR_JUNK) != 0) +- v->flags |= VAR_KEEP; +- gn = Targ_FindNode(v->name, TARG_NOCREATE); +- if (gn == NULL || gn->type & OP_NOPATH) { +- newStr = NULL; +- } else if (gn->path) { +- newStr = bmake_strdup(gn->path); +- } else { +- newStr = Dir_FindFile(v->name, Suff_FindPath(gn)); +- } +- if (!newStr) { +- newStr = bmake_strdup(v->name); +- } +- cp = ++tstr; +- termc = *tstr; +- break; +- } +- case '!': +- { +- const char *emsg; +- VarPattern pattern; +- pattern.flags = 0; +- +- delim = '!'; +- emsg = NULL; +- cp = ++tstr; +- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, +- &cp, delim, +- NULL, &pattern.rightLen, +- NULL)) == NULL) +- goto cleanup; +- if (flags & VARF_WANTRES) +- newStr = Cmd_Exec(pattern.rhs, &emsg); +- else +- newStr = varNoError; +- free(UNCONST(pattern.rhs)); +- if (emsg) +- Error(emsg, nstr); +- termc = *cp; +- delim = '\0'; +- if (v->flags & VAR_JUNK) { +- v->flags |= VAR_KEEP; +- } +- break; +- } +- case '[': +- { +- /* ++ char *cp2; ++ int len; ++ void *freeIt; ++ ++ cp2 = Var_Parse(cp, ctxt, nflags, &len, &freeIt); ++ Buf_AddBytes(&buf, strlen(cp2), cp2); ++ free(freeIt); ++ cp += len - 1; ++ } else { ++ Buf_AddByte(&buf, *cp); ++ } ++ } ++ ++ termc = *cp; ++ ++ if ((v->flags & VAR_JUNK) != 0) ++ v->flags |= VAR_KEEP; ++ if (nflags & VARF_WANTRES) { ++ newStr = Buf_Destroy(&buf, FALSE); ++ } else { ++ newStr = unix_nstr; ++ Buf_Destroy(&buf, TRUE); ++ } ++ break; ++ } ++ case 'L': { ++ if ((v->flags & VAR_JUNK) != 0) ++ v->flags |= VAR_KEEP; ++ newStr = bmake_strdup(v->name); ++ cp = ++tstr; ++ termc = *tstr; ++ break; ++ } ++ case 'P': { ++ GNode *gn; ++ ++ if ((v->flags & VAR_JUNK) != 0) ++ v->flags |= VAR_KEEP; ++ gn = Targ_FindNode(v->name, TARG_NOCREATE); ++ if (gn == NULL || gn->type & OP_NOPATH) { ++ newStr = NULL; ++ } else if (gn->path) { ++ newStr = bmake_strdup(gn->path); ++ } else { ++ newStr = Dir_FindFile(v->name, Suff_FindPath(gn)); ++ } ++ if (!newStr) { ++ newStr = bmake_strdup(v->name); ++ } ++ cp = ++tstr; ++ termc = *tstr; ++ break; ++ } ++ case '!': { ++ const char *emsg; ++ VarPattern pattern; ++ pattern.flags = 0; ++ ++ delim = '!'; ++ emsg = NULL; ++ cp = ++tstr; ++ if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, ++ &cp, delim, ++ NULL, &pattern.rightLen, ++ NULL)) == NULL) ++ goto cleanup; ++ if (flags & VARF_WANTRES) ++ newStr = Cmd_Exec(pattern.rhs, &emsg); ++ else ++ newStr = varNoError; ++ free(UNCONST(pattern.rhs)); ++ if (emsg) ++ Error(emsg, unix_nstr); ++ termc = *cp; ++ delim = '\0'; ++ if (v->flags & VAR_JUNK) { ++ v->flags |= VAR_KEEP; ++ } ++ break; ++ } ++ case '[': { ++ /* + * Look for the closing ']', recursively +@@ -2902,26 +2934,26 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- char *estr; +- +- cp = tstr+1; /* point to char after '[' */ +- delim = ']'; /* look for closing ']' */ +- estr = VarGetPattern(ctxt, &parsestate, +- flags, &cp, delim, +- NULL, NULL, NULL); +- if (estr == NULL) +- goto cleanup; /* report missing ']' */ +- /* now cp points just after the closing ']' */ +- delim = '\0'; +- if (cp[0] != ':' && cp[0] != endc) { +- /* Found junk after ']' */ +- free(estr); +- goto bad_modifier; +- } +- if (estr[0] == '\0') { +- /* Found empty square brackets in ":[]". */ +- free(estr); +- goto bad_modifier; +- } else if (estr[0] == '#' && estr[1] == '\0') { +- /* Found ":[#]" */ +- +- /* ++ char *estr; ++ ++ cp = tstr + 1; /* point to char after '[' */ ++ delim = ']'; /* look for closing ']' */ ++ estr = VarGetPattern(ctxt, &parsestate, ++ flags, &cp, delim, ++ NULL, NULL, NULL); ++ if (estr == NULL) ++ goto cleanup; /* report missing ']' */ ++ /* now cp points just after the closing ']' */ ++ delim = '\0'; ++ if (cp[0] != ':' && cp[0] != endc) { ++ /* Found junk after ']' */ ++ free(estr); ++ goto bad_modifier; ++ } ++ if (estr[0] == '\0') { ++ /* Found empty square brackets in ":[]". */ ++ free(estr); ++ goto bad_modifier; ++ } else if (estr[0] == '#' && estr[1] == '\0') { ++ /* Found ":[#]" */ ++ ++ /* + * We will need enough space for the decimal +@@ -2933,39 +2965,39 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- int newStrSize = +- (sizeof(int) * CHAR_BIT + 2) / 3 + 2; +- +- newStr = bmake_malloc(newStrSize); +- if (parsestate.oneBigWord) { +- strncpy(newStr, "1", newStrSize); +- } else { +- /* XXX: brk_string() is a rather expensive ++ int newStrSize = ++ (sizeof(int) * CHAR_BIT + 2) / 3 + 2; ++ ++ newStr = bmake_malloc(newStrSize); ++ if (parsestate.oneBigWord) { ++ strncpy(newStr, "1", newStrSize); ++ } else { ++ /* XXX: brk_string() is a rather expensive + * way of counting words. */ +- char **av; +- char *as; +- int ac; +- +- av = brk_string(nstr, &ac, FALSE, &as); +- snprintf(newStr, newStrSize, "%d", ac); +- free(as); +- free(av); +- } +- termc = *cp; +- free(estr); +- break; +- } else if (estr[0] == '*' && estr[1] == '\0') { +- /* Found ":[*]" */ +- parsestate.oneBigWord = TRUE; +- newStr = nstr; +- termc = *cp; +- free(estr); +- break; +- } else if (estr[0] == '@' && estr[1] == '\0') { +- /* Found ":[@]" */ +- parsestate.oneBigWord = FALSE; +- newStr = nstr; +- termc = *cp; +- free(estr); +- break; +- } else { +- /* ++ char **av; ++ char *as; ++ int ac; ++ ++ av = brk_string(unix_nstr, &ac, FALSE, &as); ++ snprintf(newStr, newStrSize, "%d", ac); ++ free(as); ++ free(av); ++ } ++ termc = *cp; ++ free(estr); ++ break; ++ } else if (estr[0] == '*' && estr[1] == '\0') { ++ /* Found ":[*]" */ ++ parsestate.oneBigWord = TRUE; ++ newStr = unix_nstr; ++ termc = *cp; ++ free(estr); ++ break; ++ } else if (estr[0] == '@' && estr[1] == '\0') { ++ /* Found ":[@]" */ ++ parsestate.oneBigWord = FALSE; ++ newStr = unix_nstr; ++ termc = *cp; ++ free(estr); ++ break; ++ } else { ++ /* + * We expect estr to contain a single +@@ -2974,28 +3006,28 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- VarSelectWords_t seldata = { 0, 0 }; +- +- seldata.start = strtol(estr, &ep, 0); +- if (ep == estr) { +- /* Found junk instead of a number */ +- free(estr); +- goto bad_modifier; +- } else if (ep[0] == '\0') { +- /* Found only one integer in :[N] */ +- seldata.end = seldata.start; +- } else if (ep[0] == '.' && ep[1] == '.' && +- ep[2] != '\0') { +- /* Expecting another integer after ".." */ +- ep += 2; +- seldata.end = strtol(ep, &ep, 0); +- if (ep[0] != '\0') { +- /* Found junk after ".." */ +- free(estr); +- goto bad_modifier; +- } +- } else { +- /* Found junk instead of ".." */ +- free(estr); +- goto bad_modifier; +- } +- /* ++ VarSelectWords_t seldata = {0, 0}; ++ ++ seldata.start = strtol(estr, &ep, 0); ++ if (ep == estr) { ++ /* Found junk instead of a number */ ++ free(estr); ++ goto bad_modifier; ++ } else if (ep[0] == '\0') { ++ /* Found only one integer in :[N] */ ++ seldata.end = seldata.start; ++ } else if (ep[0] == '.' && ep[1] == '.' && ++ ep[2] != '\0') { ++ /* Expecting another integer after ".." */ ++ ep += 2; ++ seldata.end = strtol(ep, &ep, 0); ++ if (ep[0] != '\0') { ++ /* Found junk after ".." */ ++ free(estr); ++ goto bad_modifier; ++ } ++ } else { ++ /* Found junk instead of ".." */ ++ free(estr); ++ goto bad_modifier; ++ } ++ /* + * Now seldata is properly filled in, +@@ -3004,16 +3036,16 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- if (seldata.start == 0 && seldata.end == 0) { +- /* ":[0]" or perhaps ":[0..0]" */ +- parsestate.oneBigWord = TRUE; +- newStr = nstr; +- termc = *cp; +- free(estr); +- break; +- } else if (seldata.start == 0 || +- seldata.end == 0) { +- /* ":[0..N]" or ":[N..0]" */ +- free(estr); +- goto bad_modifier; +- } +- /* ++ if (seldata.start == 0 && seldata.end == 0) { ++ /* ":[0]" or perhaps ":[0..0]" */ ++ parsestate.oneBigWord = TRUE; ++ newStr = unix_nstr; ++ termc = *cp; ++ free(estr); ++ break; ++ } else if (seldata.start == 0 || ++ seldata.end == 0) { ++ /* ":[0..N]" or ":[N..0]" */ ++ free(estr); ++ goto bad_modifier; ++ } ++ /* + * Normal case: select the words +@@ -3021,59 +3053,58 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- newStr = VarSelectWords(ctxt, &parsestate, +- nstr, &seldata); +- +- termc = *cp; +- free(estr); +- break; +- } +- +- } +- case 'g': +- cp = tstr + 1; /* make sure it is set */ +- if (STRMOD_MATCHX(tstr, "gmtime", 6)) { +- if (tstr[6] == '=') { +- utc = strtoul(&tstr[7], &ep, 10); +- cp = ep; +- } else { +- utc = 0; +- cp = tstr + 6; +- } +- newStr = VarStrftime(nstr, 1, utc); +- termc = *cp; +- } else { +- goto default_case; +- } +- break; +- case 'h': +- cp = tstr + 1; /* make sure it is set */ +- if (STRMOD_MATCH(tstr, "hash", 4)) { +- newStr = VarHash(nstr); +- cp = tstr + 4; +- termc = *cp; +- } else { +- goto default_case; +- } +- break; +- case 'l': +- cp = tstr + 1; /* make sure it is set */ +- if (STRMOD_MATCHX(tstr, "localtime", 9)) { +- if (tstr[9] == '=') { +- utc = strtoul(&tstr[10], &ep, 10); +- cp = ep; +- } else { +- utc = 0; +- cp = tstr + 9; +- } +- newStr = VarStrftime(nstr, 0, utc); +- termc = *cp; +- } else { +- goto default_case; +- } +- break; +- case 't': +- { +- cp = tstr + 1; /* make sure it is set */ +- if (tstr[1] != endc && tstr[1] != ':') { +- if (tstr[1] == 's') { +- /* ++ newStr = VarSelectWords(ctxt, &parsestate, ++ unix_nstr, &seldata); ++ ++ termc = *cp; ++ free(estr); ++ break; ++ } ++ ++ } ++ case 'g': ++ cp = tstr + 1; /* make sure it is set */ ++ if (STRMOD_MATCHX(tstr, "gmtime", 6)) { ++ if (tstr[6] == '=') { ++ utc = strtoul(&tstr[7], &ep, 10); ++ cp = ep; ++ } else { ++ utc = 0; ++ cp = tstr + 6; ++ } ++ newStr = VarStrftime(unix_nstr, 1, utc); ++ termc = *cp; ++ } else { ++ goto default_case; ++ } ++ break; ++ case 'h': ++ cp = tstr + 1; /* make sure it is set */ ++ if (STRMOD_MATCH(tstr, "hash", 4)) { ++ newStr = VarHash(unix_nstr); ++ cp = tstr + 4; ++ termc = *cp; ++ } else { ++ goto default_case; ++ } ++ break; ++ case 'l': ++ cp = tstr + 1; /* make sure it is set */ ++ if (STRMOD_MATCHX(tstr, "localtime", 9)) { ++ if (tstr[9] == '=') { ++ utc = strtoul(&tstr[10], &ep, 10); ++ cp = ep; ++ } else { ++ utc = 0; ++ cp = tstr + 9; ++ } ++ newStr = VarStrftime(unix_nstr, 0, utc); ++ termc = *cp; ++ } else { ++ goto default_case; ++ } ++ break; ++ case 't': { ++ cp = tstr + 1; /* make sure it is set */ ++ if (tstr[1] != endc && tstr[1] != ':') { ++ if (tstr[1] == 's') { ++ /* + * Use the char (if any) at tstr[2] +@@ -3081,61 +3112,61 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- VarPattern pattern; ++ VarPattern pattern; + +- if (tstr[2] != endc && +- (tstr[3] == endc || tstr[3] == ':')) { +- /* ":ts" or ++ if (tstr[2] != endc && ++ (tstr[3] == endc || tstr[3] == ':')) { ++ /* ":ts" or + * ":ts:" */ +- parsestate.varSpace = tstr[2]; +- cp = tstr + 3; +- } else if (tstr[2] == endc || tstr[2] == ':') { +- /* ":ts" or ":ts:" */ +- parsestate.varSpace = 0; /* no separator */ +- cp = tstr + 2; +- } else if (tstr[2] == '\\') { +- const char *xp = &tstr[3]; +- int base = 8; /* assume octal */ +- +- switch (tstr[3]) { +- case 'n': +- parsestate.varSpace = '\n'; +- cp = tstr + 4; +- break; +- case 't': +- parsestate.varSpace = '\t'; +- cp = tstr + 4; +- break; +- case 'x': +- base = 16; +- xp++; +- goto get_numeric; +- case '0': +- base = 0; +- goto get_numeric; +- default: +- if (isdigit((unsigned char)tstr[3])) { +- +- get_numeric: +- parsestate.varSpace = +- strtoul(xp, &ep, base); +- if (*ep != ':' && *ep != endc) +- goto bad_modifier; +- cp = ep; +- } else { +- /* ++ parsestate.varSpace = tstr[2]; ++ cp = tstr + 3; ++ } else if (tstr[2] == endc || tstr[2] == ':') { ++ /* ":ts" or ":ts:" */ ++ parsestate.varSpace = 0; /* no separator */ ++ cp = tstr + 2; ++ } else if (tstr[2] == '\\') { ++ const char *xp = &tstr[3]; ++ int base = 8; /* assume octal */ ++ ++ switch (tstr[3]) { ++ case 'n': ++ parsestate.varSpace = '\n'; ++ cp = tstr + 4; ++ break; ++ case 't': ++ parsestate.varSpace = '\t'; ++ cp = tstr + 4; ++ break; ++ case 'x': ++ base = 16; ++ xp++; ++ goto get_numeric; ++ case '0': ++ base = 0; ++ goto get_numeric; ++ default: ++ if (isdigit((unsigned char) tstr[3])) { ++ ++ get_numeric: ++ parsestate.varSpace = ++ strtoul(xp, &ep, base); ++ if (*ep != ':' && *ep != endc) ++ goto bad_modifier; ++ cp = ep; ++ } else { ++ /* + * ":ts". + */ +- goto bad_modifier; +- } +- break; +- } +- } else { +- /* ++ goto bad_modifier; ++ } ++ break; ++ } ++ } else { ++ /* + * Found ":ts". + */ +- goto bad_modifier; +- } ++ goto bad_modifier; ++ } + +- termc = *cp; ++ termc = *cp; + +- /* ++ /* + * We cannot be certain that VarModify +@@ -3146,11 +3177,11 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- pattern.flags = VAR_SUB_ONE; +- pattern.lhs = pattern.rhs = "\032"; +- pattern.leftLen = pattern.rightLen = 1; +- +- newStr = VarModify(ctxt, &parsestate, nstr, +- VarSubstitute, +- &pattern); +- } else if (tstr[2] == endc || tstr[2] == ':') { +- /* ++ pattern.flags = VAR_SUB_ONE; ++ pattern.lhs = pattern.rhs = "\032"; ++ pattern.leftLen = pattern.rightLen = 1; ++ ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, ++ VarSubstitute, ++ &pattern); ++ } else if (tstr[2] == endc || tstr[2] == ':') { ++ /* + * Check for two-character options: +@@ -3158,57 +3189,56 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- if (tstr[1] == 'A') { /* absolute path */ +- newStr = VarModify(ctxt, &parsestate, nstr, +- VarRealpath, NULL); +- cp = tstr + 2; +- termc = *cp; +- } else if (tstr[1] == 'u') { +- char *dp = bmake_strdup(nstr); +- for (newStr = dp; *dp; dp++) +- *dp = toupper((unsigned char)*dp); +- cp = tstr + 2; +- termc = *cp; +- } else if (tstr[1] == 'l') { +- char *dp = bmake_strdup(nstr); +- for (newStr = dp; *dp; dp++) +- *dp = tolower((unsigned char)*dp); +- cp = tstr + 2; +- termc = *cp; +- } else if (tstr[1] == 'W' || tstr[1] == 'w') { +- parsestate.oneBigWord = (tstr[1] == 'W'); +- newStr = nstr; +- cp = tstr + 2; +- termc = *cp; +- } else { +- /* Found ":t:" or ++ if (tstr[1] == 'A') { /* absolute path */ ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, ++ VarRealpath, NULL); ++ cp = tstr + 2; ++ termc = *cp; ++ } else if (tstr[1] == 'u') { ++ char *dp = bmake_strdup(unix_nstr); ++ for (newStr = dp; *dp; dp++) ++ *dp = toupper((unsigned char) *dp); ++ cp = tstr + 2; ++ termc = *cp; ++ } else if (tstr[1] == 'l') { ++ char *dp = bmake_strdup(unix_nstr); ++ for (newStr = dp; *dp; dp++) ++ *dp = tolower((unsigned char) *dp); ++ cp = tstr + 2; ++ termc = *cp; ++ } else if (tstr[1] == 'W' || tstr[1] == 'w') { ++ parsestate.oneBigWord = (tstr[1] == 'W'); ++ newStr = unix_nstr; ++ cp = tstr + 2; ++ termc = *cp; ++ } else { ++ /* Found ":t:" or + * ":t". */ +- goto bad_modifier; +- } +- } else { +- /* ++ goto bad_modifier; ++ } ++ } else { ++ /* + * Found ":t". + */ +- goto bad_modifier; +- } +- } else { +- /* ++ goto bad_modifier; ++ } ++ } else { ++ /* + * Found ":t" or ":t:". + */ +- goto bad_modifier; +- } +- break; +- } +- case 'N': +- case 'M': +- { +- char *pattern; +- const char *endpat; /* points just after end of pattern */ +- char *cp2; +- Boolean copy; /* pattern should be, or has been, copied */ +- Boolean needSubst; +- int nest; +- +- copy = FALSE; +- needSubst = FALSE; +- nest = 1; +- /* ++ goto bad_modifier; ++ } ++ break; ++ } ++ case 'N': ++ case 'M': { ++ char *pattern; ++ const char *endpat; /* points just after end of pattern */ ++ char *cp2; ++ Boolean copy; /* pattern should be, or has been, copied */ ++ Boolean needSubst; ++ int nest; ++ ++ copy = FALSE; ++ needSubst = FALSE; ++ nest = 1; ++ /* + * In the loop below, ignore ':' unless we are at +@@ -3218,30 +3248,29 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- for (cp = tstr + 1; +- *cp != '\0' && !(*cp == ':' && nest == 1); +- cp++) +- { +- if (*cp == '\\' && +- (cp[1] == ':' || +- cp[1] == endc || cp[1] == startc)) { +- if (!needSubst) { +- copy = TRUE; +- } +- cp++; +- continue; +- } +- if (*cp == '$') { +- needSubst = TRUE; +- } +- if (*cp == '(' || *cp == '{') +- ++nest; +- if (*cp == ')' || *cp == '}') { +- --nest; +- if (nest == 0) +- break; +- } +- } +- termc = *cp; +- endpat = cp; +- if (copy) { +- /* ++ for (cp = tstr + 1; ++ *cp != '\0' && !(*cp == ':' && nest == 1); ++ cp++) { ++ if (*cp == '\\' && ++ (cp[1] == ':' || ++ cp[1] == endc || cp[1] == startc)) { ++ if (!needSubst) { ++ copy = TRUE; ++ } ++ cp++; ++ continue; ++ } ++ if (*cp == '$') { ++ needSubst = TRUE; ++ } ++ if (*cp == '(' || *cp == '{') ++ ++nest; ++ if (*cp == ')' || *cp == '}') { ++ --nest; ++ if (nest == 0) ++ break; ++ } ++ } ++ termc = *cp; ++ endpat = cp; ++ if (copy) { ++ /* + * Need to compress the \:'s out of the pattern, so +@@ -3252,17 +3281,16 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- pattern = bmake_malloc(cp - tstr); +- for (cp2 = pattern, cp = tstr + 1; +- cp < endpat; +- cp++, cp2++) +- { +- if ((*cp == '\\') && (cp+1 < endpat) && +- (cp[1] == ':' || cp[1] == endc)) { +- cp++; +- } +- *cp2 = *cp; +- } +- *cp2 = '\0'; +- endpat = cp2; +- } else { +- /* ++ pattern = bmake_malloc(cp - tstr); ++ for (cp2 = pattern, cp = tstr + 1; ++ cp < endpat; ++ cp++, cp2++) { ++ if ((*cp == '\\') && (cp + 1 < endpat) && ++ (cp[1] == ':' || cp[1] == endc)) { ++ cp++; ++ } ++ *cp2 = *cp; ++ } ++ *cp2 = '\0'; ++ endpat = cp2; ++ } else { ++ /* + * Either Var_Subst or VarModify will need a +@@ -3270,6 +3298,6 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- pattern = bmake_strndup(tstr+1, endpat - (tstr + 1)); +- } +- if (needSubst) { +- /* ++ pattern = bmake_strndup(tstr + 1, endpat - (tstr + 1)); ++ } ++ if (needSubst) { ++ /* + * pattern contains embedded '$', so use Var_Subst to +@@ -3277,30 +3305,29 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- cp2 = pattern; +- pattern = Var_Subst(NULL, cp2, ctxt, flags | VARF_WANTRES); +- free(cp2); +- } +- if (DEBUG(VAR)) +- fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", +- v->name, nstr, pattern); +- if (*tstr == 'M') { +- newStr = VarModify(ctxt, &parsestate, nstr, VarMatch, +- pattern); +- } else { +- newStr = VarModify(ctxt, &parsestate, nstr, VarNoMatch, +- pattern); +- } +- free(pattern); +- break; +- } +- case 'S': +- { +- VarPattern pattern; +- Var_Parse_State tmpparsestate; +- +- pattern.flags = 0; +- tmpparsestate = parsestate; +- delim = tstr[1]; +- tstr += 2; +- +- /* ++ cp2 = pattern; ++ pattern = Var_Subst(NULL, cp2, ctxt, flags | VARF_WANTRES); ++ free(cp2); ++ } ++ if (DEBUG(VAR)) ++ fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", ++ v->name, unix_nstr, pattern); ++ if (*tstr == 'M') { ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, VarMatch, ++ pattern); ++ } else { ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, VarNoMatch, ++ pattern); ++ } ++ free(pattern); ++ break; ++ } ++ case 'S': { ++ VarPattern pattern; ++ Var_Parse_State tmpparsestate; ++ ++ pattern.flags = 0; ++ tmpparsestate = parsestate; ++ delim = tstr[1]; ++ tstr += 2; ++ ++ /* + * If pattern begins with '^', it is anchored to the +@@ -3308,22 +3335,22 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- if (*tstr == '^') { +- pattern.flags |= VAR_MATCH_START; +- tstr += 1; +- } +- +- cp = tstr; +- if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, +- &cp, delim, +- &pattern.flags, +- &pattern.leftLen, +- NULL)) == NULL) +- goto cleanup; +- +- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, +- &cp, delim, NULL, +- &pattern.rightLen, +- &pattern)) == NULL) +- goto cleanup; +- +- /* ++ if (*tstr == '^') { ++ pattern.flags |= VAR_MATCH_START; ++ tstr += 1; ++ } ++ ++ cp = tstr; ++ if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, ++ &cp, delim, ++ &pattern.flags, ++ &pattern.leftLen, ++ NULL)) == NULL) ++ goto cleanup; ++ ++ if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, ++ &cp, delim, NULL, ++ &pattern.rightLen, ++ &pattern)) == NULL) ++ goto cleanup; ++ ++ /* + * Check for global substitution. If 'g' after the final +@@ -3332,271 +3359,268 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- for (;; cp++) { +- switch (*cp) { +- case 'g': +- pattern.flags |= VAR_SUB_GLOBAL; +- continue; +- case '1': +- pattern.flags |= VAR_SUB_ONE; +- continue; +- case 'W': +- tmpparsestate.oneBigWord = TRUE; +- continue; +- } +- break; +- } +- +- termc = *cp; +- newStr = VarModify(ctxt, &tmpparsestate, nstr, +- VarSubstitute, +- &pattern); +- +- /* ++ for (;; cp++) { ++ switch (*cp) { ++ case 'g': ++ pattern.flags |= VAR_SUB_GLOBAL; ++ continue; ++ case '1': ++ pattern.flags |= VAR_SUB_ONE; ++ continue; ++ case 'W': ++ tmpparsestate.oneBigWord = TRUE; ++ continue; ++ } ++ break; ++ } ++ ++ termc = *cp; ++ newStr = VarModify(ctxt, &tmpparsestate, unix_nstr, ++ VarSubstitute, ++ &pattern); ++ ++ /* + * Free the two strings. + */ +- free(UNCONST(pattern.lhs)); +- free(UNCONST(pattern.rhs)); +- delim = '\0'; +- break; +- } +- case '?': +- { +- VarPattern pattern; +- Boolean value; +- int cond_rc; +- int lhs_flags, rhs_flags; +- +- /* find ':', and then substitute accordingly */ +- if (flags & VARF_WANTRES) { +- cond_rc = Cond_EvalExpression(NULL, v->name, &value, 0, FALSE); +- if (cond_rc == COND_INVALID) { +- lhs_flags = rhs_flags = VAR_NOSUBST; +- } else if (value) { +- lhs_flags = 0; +- rhs_flags = VAR_NOSUBST; +- } else { +- lhs_flags = VAR_NOSUBST; +- rhs_flags = 0; +- } +- } else { +- /* we are just consuming and discarding */ +- cond_rc = value = 0; +- lhs_flags = rhs_flags = VAR_NOSUBST; +- } +- pattern.flags = 0; +- +- cp = ++tstr; +- delim = ':'; +- if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, +- &cp, delim, &lhs_flags, +- &pattern.leftLen, +- NULL)) == NULL) +- goto cleanup; +- +- /* BROPEN or PROPEN */ +- delim = endc; +- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, +- &cp, delim, &rhs_flags, +- &pattern.rightLen, +- NULL)) == NULL) +- goto cleanup; +- +- termc = *--cp; +- delim = '\0'; +- if (cond_rc == COND_INVALID) { +- Error("Bad conditional expression `%s' in %s?%s:%s", +- v->name, v->name, pattern.lhs, pattern.rhs); +- goto cleanup; +- } +- +- if (value) { +- newStr = UNCONST(pattern.lhs); +- free(UNCONST(pattern.rhs)); +- } else { +- newStr = UNCONST(pattern.rhs); +- free(UNCONST(pattern.lhs)); +- } +- if (v->flags & VAR_JUNK) { +- v->flags |= VAR_KEEP; +- } +- break; +- } ++ free(UNCONST(pattern.lhs)); ++ free(UNCONST(pattern.rhs)); ++ delim = '\0'; ++ break; ++ } ++ case '?': { ++ VarPattern pattern; ++ Boolean value; ++ int cond_rc; ++ int lhs_flags, rhs_flags; ++ ++ /* find ':', and then substitute accordingly */ ++ if (flags & VARF_WANTRES) { ++ cond_rc = Cond_EvalExpression(NULL, v->name, &value, 0, FALSE); ++ if (cond_rc == COND_INVALID) { ++ lhs_flags = rhs_flags = VAR_NOSUBST; ++ } else if (value) { ++ lhs_flags = 0; ++ rhs_flags = VAR_NOSUBST; ++ } else { ++ lhs_flags = VAR_NOSUBST; ++ rhs_flags = 0; ++ } ++ } else { ++ /* we are just consuming and discarding */ ++ cond_rc = value = 0; ++ lhs_flags = rhs_flags = VAR_NOSUBST; ++ } ++ pattern.flags = 0; ++ ++ cp = ++tstr; ++ delim = ':'; ++ if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, ++ &cp, delim, &lhs_flags, ++ &pattern.leftLen, ++ NULL)) == NULL) ++ goto cleanup; ++ ++ /* BROPEN or PROPEN */ ++ delim = endc; ++ if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, ++ &cp, delim, &rhs_flags, ++ &pattern.rightLen, ++ NULL)) == NULL) ++ goto cleanup; ++ ++ termc = *--cp; ++ delim = '\0'; ++ if (cond_rc == COND_INVALID) { ++ Error("Bad conditional expression `%s' in %s?%s:%s", ++ v->name, v->name, pattern.lhs, pattern.rhs); ++ goto cleanup; ++ } ++ ++ if (value) { ++ newStr = UNCONST(pattern.lhs); ++ free(UNCONST(pattern.rhs)); ++ } else { ++ newStr = UNCONST(pattern.rhs); ++ free(UNCONST(pattern.lhs)); ++ } ++ if (v->flags & VAR_JUNK) { ++ v->flags |= VAR_KEEP; ++ } ++ break; ++ } + #ifndef NO_REGEX +- case 'C': +- { +- VarREPattern pattern; +- char *re; +- int error; +- Var_Parse_State tmpparsestate; +- +- pattern.flags = 0; +- tmpparsestate = parsestate; +- delim = tstr[1]; +- tstr += 2; +- +- cp = tstr; +- +- if ((re = VarGetPattern(ctxt, &parsestate, flags, &cp, delim, +- NULL, NULL, NULL)) == NULL) +- goto cleanup; +- +- if ((pattern.replace = VarGetPattern(ctxt, &parsestate, +- flags, &cp, delim, NULL, +- NULL, NULL)) == NULL){ +- free(re); +- goto cleanup; +- } +- +- for (;; cp++) { +- switch (*cp) { +- case 'g': +- pattern.flags |= VAR_SUB_GLOBAL; +- continue; +- case '1': +- pattern.flags |= VAR_SUB_ONE; +- continue; +- case 'W': +- tmpparsestate.oneBigWord = TRUE; +- continue; +- } +- break; +- } +- +- termc = *cp; +- +- error = regcomp(&pattern.re, re, REG_EXTENDED); +- free(re); +- if (error) { +- *lengthPtr = cp - start + 1; +- VarREError(error, &pattern.re, "RE substitution error"); +- free(pattern.replace); +- goto cleanup; +- } +- +- pattern.nsub = pattern.re.re_nsub + 1; +- if (pattern.nsub < 1) +- pattern.nsub = 1; +- if (pattern.nsub > 10) +- pattern.nsub = 10; +- pattern.matches = bmake_malloc(pattern.nsub * +- sizeof(regmatch_t)); +- newStr = VarModify(ctxt, &tmpparsestate, nstr, +- VarRESubstitute, +- &pattern); +- regfree(&pattern.re); +- free(pattern.replace); +- free(pattern.matches); +- delim = '\0'; +- break; +- } ++ case 'C': { ++ VarREPattern pattern; ++ char *re; ++ int error; ++ Var_Parse_State tmpparsestate; ++ ++ pattern.flags = 0; ++ tmpparsestate = parsestate; ++ delim = tstr[1]; ++ tstr += 2; ++ ++ cp = tstr; ++ ++ if ((re = VarGetPattern(ctxt, &parsestate, flags, &cp, delim, ++ NULL, NULL, NULL)) == NULL) ++ goto cleanup; ++ ++ if ((pattern.replace = VarGetPattern(ctxt, &parsestate, ++ flags, &cp, delim, NULL, ++ NULL, NULL)) == NULL) { ++ free(re); ++ goto cleanup; ++ } ++ ++ for (;; cp++) { ++ switch (*cp) { ++ case 'g': ++ pattern.flags |= VAR_SUB_GLOBAL; ++ continue; ++ case '1': ++ pattern.flags |= VAR_SUB_ONE; ++ continue; ++ case 'W': ++ tmpparsestate.oneBigWord = TRUE; ++ continue; ++ } ++ break; ++ } ++ ++ termc = *cp; ++ ++ error = regcomp(&pattern.re, re, REG_EXTENDED); ++ free(re); ++ if (error) { ++ *lengthPtr = cp - start + 1; ++ VarREError(error, &pattern.re, "RE substitution error"); ++ free(pattern.replace); ++ goto cleanup; ++ } ++ ++ pattern.nsub = pattern.re.re_nsub + 1; ++ if (pattern.nsub < 1) ++ pattern.nsub = 1; ++ if (pattern.nsub > 10) ++ pattern.nsub = 10; ++ pattern.matches = bmake_malloc(pattern.nsub * ++ sizeof(regmatch_t)); ++ newStr = VarModify(ctxt, &tmpparsestate, unix_nstr, ++ VarRESubstitute, ++ &pattern); ++ regfree(&pattern.re); ++ free(pattern.replace); ++ free(pattern.matches); ++ delim = '\0'; ++ break; ++ } + #endif +- case 'q': +- case 'Q': +- if (tstr[1] == endc || tstr[1] == ':') { +- newStr = VarQuote(nstr, modifier == 'q'); +- cp = tstr + 1; +- termc = *cp; +- break; +- } +- goto default_case; +- case 'T': +- if (tstr[1] == endc || tstr[1] == ':') { +- newStr = VarModify(ctxt, &parsestate, nstr, VarTail, +- NULL); +- cp = tstr + 1; +- termc = *cp; +- break; +- } +- goto default_case; +- case 'H': +- if (tstr[1] == endc || tstr[1] == ':') { +- newStr = VarModify(ctxt, &parsestate, nstr, VarHead, +- NULL); +- cp = tstr + 1; +- termc = *cp; +- break; +- } +- goto default_case; +- case 'E': +- if (tstr[1] == endc || tstr[1] == ':') { +- newStr = VarModify(ctxt, &parsestate, nstr, VarSuffix, +- NULL); +- cp = tstr + 1; +- termc = *cp; +- break; +- } +- goto default_case; +- case 'R': +- if (tstr[1] == endc || tstr[1] == ':') { +- newStr = VarModify(ctxt, &parsestate, nstr, VarRoot, +- NULL); +- cp = tstr + 1; +- termc = *cp; +- break; +- } +- goto default_case; +- case 'r': +- cp = tstr + 1; /* make sure it is set */ +- if (STRMOD_MATCHX(tstr, "range", 5)) { +- int n; +- +- if (tstr[5] == '=') { +- n = strtoul(&tstr[6], &ep, 10); +- cp = ep; +- } else { +- n = 0; +- cp = tstr + 5; +- } +- newStr = VarRange(nstr, n); +- termc = *cp; +- break; +- } +- goto default_case; +- case 'O': +- { +- char otype; +- +- cp = tstr + 1; /* skip to the rest in any case */ +- if (tstr[1] == endc || tstr[1] == ':') { +- otype = 's'; +- termc = *cp; +- } else if ( (tstr[1] == 'x') && +- (tstr[2] == endc || tstr[2] == ':') ) { +- otype = tstr[1]; +- cp = tstr + 2; +- termc = *cp; +- } else { +- goto bad_modifier; +- } +- newStr = VarOrder(nstr, otype); +- break; +- } +- case 'u': +- if (tstr[1] == endc || tstr[1] == ':') { +- newStr = VarUniq(nstr); +- cp = tstr + 1; +- termc = *cp; +- break; +- } +- goto default_case; ++ case 'q': ++ case 'Q': ++ if (tstr[1] == endc || tstr[1] == ':') { ++ newStr = VarQuote(unix_nstr, modifier == 'q'); ++ cp = tstr + 1; ++ termc = *cp; ++ break; ++ } ++ goto default_case; ++ case 'T': ++ if (tstr[1] == endc || tstr[1] == ':') { ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, VarTail, ++ NULL); ++ cp = tstr + 1; ++ termc = *cp; ++ break; ++ } ++ goto default_case; ++ case 'H': ++ if (tstr[1] == endc || tstr[1] == ':') { ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, VarHead, ++ NULL); ++ cp = tstr + 1; ++ termc = *cp; ++ break; ++ } ++ goto default_case; ++ case 'E': ++ if (tstr[1] == endc || tstr[1] == ':') { ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, VarSuffix, ++ NULL); ++ cp = tstr + 1; ++ termc = *cp; ++ break; ++ } ++ goto default_case; ++ case 'R': ++ if (tstr[1] == endc || tstr[1] == ':') { ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, VarRoot, ++ NULL); ++ cp = tstr + 1; ++ termc = *cp; ++ break; ++ } ++ goto default_case; ++ case 'r': ++ cp = tstr + 1; /* make sure it is set */ ++ if (STRMOD_MATCHX(tstr, "range", 5)) { ++ int n; ++ ++ if (tstr[5] == '=') { ++ n = strtoul(&tstr[6], &ep, 10); ++ cp = ep; ++ } else { ++ n = 0; ++ cp = tstr + 5; ++ } ++ newStr = VarRange(unix_nstr, n); ++ termc = *cp; ++ break; ++ } ++ goto default_case; ++ case 'O': { ++ char otype; ++ ++ cp = tstr + 1; /* skip to the rest in any case */ ++ if (tstr[1] == endc || tstr[1] == ':') { ++ otype = 's'; ++ termc = *cp; ++ } else if ((tstr[1] == 'x') && ++ (tstr[2] == endc || tstr[2] == ':')) { ++ otype = tstr[1]; ++ cp = tstr + 2; ++ termc = *cp; ++ } else { ++ goto bad_modifier; ++ } ++ newStr = VarOrder(unix_nstr, otype); ++ break; ++ } ++ case 'u': ++ if (tstr[1] == endc || tstr[1] == ':') { ++ newStr = VarUniq(unix_nstr); ++ cp = tstr + 1; ++ termc = *cp; ++ break; ++ } ++ goto default_case; + #ifdef SUNSHCMD +- case 's': +- if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { +- const char *emsg; +- if (flags & VARF_WANTRES) { +- newStr = Cmd_Exec(nstr, &emsg); +- if (emsg) +- Error(emsg, nstr); +- } else +- newStr = varNoError; +- cp = tstr + 2; +- termc = *cp; +- break; +- } +- goto default_case; ++ case 's': ++ if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { ++ const char *emsg; ++ if (flags & VARF_WANTRES) { ++ newStr = Cmd_Exec(unix_nstr, &emsg); ++ if (emsg) ++ Error(emsg, unix_nstr); ++ } else ++ newStr = varNoError; ++ cp = tstr + 2; ++ termc = *cp; ++ break; ++ } ++ goto default_case; + #endif +- default: +- default_case: +- { ++ default: ++ default_case: ++ { + #ifdef SYSVVARSUB +- /* ++ /* + * This can either be a bogus modifier or a System-V +@@ -3604,8 +3628,8 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- VarPattern pattern; +- Boolean eqFound; ++ VarPattern pattern; ++ Boolean eqFound; + +- pattern.flags = 0; +- eqFound = FALSE; +- /* ++ pattern.flags = 0; ++ eqFound = FALSE; ++ /* + * First we make a pass through the string trying +@@ -3614,19 +3638,18 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- cp = tstr; +- cnt = 1; +- while (*cp != '\0' && cnt) { +- if (*cp == '=') { +- eqFound = TRUE; +- /* continue looking for endc */ +- } +- else if (*cp == endc) +- cnt--; +- else if (*cp == startc) +- cnt++; +- if (cnt) +- cp++; +- } +- if (*cp == endc && eqFound) { +- +- /* ++ cp = tstr; ++ cnt = 1; ++ while (*cp != '\0' && cnt) { ++ if (*cp == '=') { ++ eqFound = TRUE; ++ /* continue looking for endc */ ++ } else if (*cp == endc) ++ cnt--; ++ else if (*cp == startc) ++ cnt++; ++ if (cnt) ++ cp++; ++ } ++ if (*cp == endc && eqFound) { ++ ++ /* + * Now we break this sucker into the lhs and +@@ -3634,15 +3657,15 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- delim='='; +- cp = tstr; +- if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, +- flags, &cp, delim, &pattern.flags, +- &pattern.leftLen, NULL)) == NULL) +- goto cleanup; +- delim = endc; +- if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, +- flags, &cp, delim, NULL, &pattern.rightLen, +- &pattern)) == NULL) +- goto cleanup; +- +- /* ++ delim = '='; ++ cp = tstr; ++ if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, ++ flags, &cp, delim, &pattern.flags, ++ &pattern.leftLen, NULL)) == NULL) ++ goto cleanup; ++ delim = endc; ++ if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, ++ flags, &cp, delim, NULL, &pattern.rightLen, ++ &pattern)) == NULL) ++ goto cleanup; ++ ++ /* + * SYSV modifications happen through the whole +@@ -3650,62 +3673,63 @@ ApplyModifiers(char *nstr, const char *tstr, + */ +- termc = *--cp; +- delim = '\0'; +- if (pattern.leftLen == 0 && *nstr == '\0') { +- newStr = nstr; /* special case */ +- } else { +- newStr = VarModify(ctxt, &parsestate, nstr, +- VarSYSVMatch, +- &pattern); +- } +- free(UNCONST(pattern.lhs)); +- free(UNCONST(pattern.rhs)); +- } else ++ termc = *--cp; ++ delim = '\0'; ++ if (pattern.leftLen == 0 && *unix_nstr == '\0') { ++ newStr = unix_nstr; /* special case */ ++ } else { ++ newStr = VarModify(ctxt, &parsestate, unix_nstr, ++ VarSYSVMatch, ++ &pattern); ++ } ++ free(UNCONST(pattern.lhs)); ++ free(UNCONST(pattern.rhs)); ++ } else + #endif +- { +- Error("Unknown modifier '%c'", *tstr); +- for (cp = tstr+1; +- *cp != ':' && *cp != endc && *cp != '\0'; +- cp++) +- continue; +- termc = *cp; +- newStr = var_Error; +- } +- } +- } +- if (DEBUG(VAR)) { +- fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", +- v->name, modifier, newStr); +- } +- +- if (newStr != nstr) { +- if (*freePtr) { +- free(nstr); +- *freePtr = NULL; +- } +- nstr = newStr; +- if (nstr != var_Error && nstr != varNoError) { +- *freePtr = nstr; +- } +- } +- if (termc == '\0' && endc != '\0') { +- Error("Unclosed variable specification (expecting '%c') for \"%s\" (value \"%s\") modifier %c", endc, v->name, nstr, modifier); +- } else if (termc == ':') { +- cp++; +- } +- tstr = cp; +- } +- out: ++ { ++ Error("Unknown modifier '%c'", *tstr); ++ for (cp = tstr + 1; ++ *cp != ':' && *cp != endc && *cp != '\0'; ++ cp++) ++ continue; ++ termc = *cp; ++ newStr = var_Error; ++ } ++ } ++ } ++ if (DEBUG(VAR)) { ++ fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", ++ v->name, modifier, newStr); ++ } ++ ++ if (newStr != unix_nstr) { ++ if (*freePtr) { ++ free(unix_nstr); ++ *freePtr = NULL; ++ } ++ unix_nstr = newStr; ++ if (unix_nstr != var_Error && unix_nstr != varNoError) { ++ *freePtr = unix_nstr; ++ } ++ } ++ if (termc == '\0' && endc != '\0') { ++ Error("Unclosed variable specification (expecting '%c') for \"%s\" (value \"%s\") modifier %c", endc, ++ v->name, unix_nstr, modifier); ++ } else if (termc == ':') { ++ cp++; ++ } ++ tstr = cp; ++ } ++ out: + *lengthPtr = tstr - start; +- return (nstr); ++ return (unix_nstr); + +- bad_modifier: ++ bad_modifier: + /* "{(" */ +- Error("Bad modifier `:%.*s' for %s", (int)strcspn(tstr, ":)}"), tstr, +- v->name); ++ Error("Bad modifier `:%.*s' for %s", (int) strcspn(tstr, ":)}"), tstr, ++ v->name); + +- cleanup: ++ cleanup: + *lengthPtr = cp - start; + if (delim != '\0') +- Error("Unclosed substitution for %s (%c missing)", +- v->name, delim); ++ Error("Unclosed substitution for %s (%c missing)", ++ v->name, delim); + free(*freePtr); +@@ -3747,15 +3771,14 @@ char * + Var_Parse(const char *str, GNode *ctxt, int flags, +- int *lengthPtr, void **freePtr) +-{ +- const char *tstr; /* Pointer into str */ +- Var *v; /* Variable in invocation */ +- Boolean haveModifier;/* TRUE if have modifiers for the variable */ +- char endc; /* Ending character when variable in parens ++ int *lengthPtr, void **freePtr) { ++ const char *tstr; /* Pointer into str */ ++ Var *v; /* Variable in invocation */ ++ Boolean haveModifier;/* TRUE if have modifiers for the variable */ ++ char endc; /* Ending character when variable in parens + * or braces */ +- char startc; /* Starting character when variable in parens ++ char startc; /* Starting character when variable in parens + * or braces */ +- int vlen; /* Length of variable name */ +- const char *start; /* Points to original start of str */ +- char *nstr; /* New string, used during expansion */ +- Boolean dynamic; /* TRUE if the variable is local and we're ++ int vlen; /* Length of variable name */ ++ const char *start; /* Points to original start of str */ ++ char *nstr; /* New string, used during expansion */ ++ Boolean dynamic; /* TRUE if the variable is local and we're + * expanding it in a non-local context. This +@@ -3763,4 +3786,4 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + * result is just the invocation, unaltered */ +- const char *extramodifiers; /* extra modifiers to apply first */ +- char name[2]; ++ const char *extramodifiers; /* extra modifiers to apply first */ ++ char name[2]; + +@@ -3773,3 +3796,3 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + if (startc != PROPEN && startc != BROPEN) { +- /* ++ /* + * If it's not bounded by braces of some sort, life is much simpler. +@@ -3779,16 +3802,16 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + +- /* Error out some really stupid names */ +- if (startc == '\0' || strchr(")}:$", startc)) { +- *lengthPtr = 1; +- return var_Error; +- } +- name[0] = startc; +- name[1] = '\0'; ++ /* Error out some really stupid names */ ++ if (startc == '\0' || strchr(")}:$", startc)) { ++ *lengthPtr = 1; ++ return var_Error; ++ } ++ name[0] = startc; ++ name[1] = '\0'; + +- v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); +- if (v == NULL) { +- *lengthPtr = 2; ++ v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); ++ if (v == NULL) { ++ *lengthPtr = 2; + +- if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { +- /* ++ if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { ++ /* + * If substituting a local variable in a non-local context, +@@ -3801,69 +3824,67 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + */ +- switch (str[1]) { +- case '@': +- return UNCONST("$(.TARGET)"); +- case '%': +- return UNCONST("$(.MEMBER)"); +- case '*': +- return UNCONST("$(.PREFIX)"); +- case '!': +- return UNCONST("$(.ARCHIVE)"); +- } +- } +- /* ++ switch (str[1]) { ++ case '@': ++ return UNCONST("$(.TARGET)"); ++ case '%': ++ return UNCONST("$(.MEMBER)"); ++ case '*': ++ return UNCONST("$(.PREFIX)"); ++ case '!': ++ return UNCONST("$(.ARCHIVE)"); ++ } ++ } ++ /* + * Error + */ +- return (flags & VARF_UNDEFERR) ? var_Error : varNoError; +- } else { +- haveModifier = FALSE; +- tstr = &str[1]; +- endc = str[1]; +- } ++ return (flags & VARF_UNDEFERR) ? var_Error : varNoError; ++ } else { ++ haveModifier = FALSE; ++ tstr = &str[1]; ++ endc = str[1]; ++ } + } else { +- Buffer buf; /* Holds the variable name */ +- int depth = 1; ++ Buffer buf; /* Holds the variable name */ ++ int depth = 1; + +- endc = startc == PROPEN ? PRCLOSE : BRCLOSE; +- Buf_Init(&buf, 0); ++ endc = startc == PROPEN ? PRCLOSE : BRCLOSE; ++ Buf_Init(&buf, 0); + +- /* ++ /* + * Skip to the end character or a colon, whichever comes first. + */ +- for (tstr = str + 2; *tstr != '\0'; tstr++) +- { +- /* ++ for (tstr = str + 2; *tstr != '\0'; tstr++) { ++ /* + * Track depth so we can spot parse errors. + */ +- if (*tstr == startc) { +- depth++; +- } +- if (*tstr == endc) { +- if (--depth == 0) +- break; +- } +- if (depth == 1 && *tstr == ':') { +- break; +- } +- /* ++ if (*tstr == startc) { ++ depth++; ++ } ++ if (*tstr == endc) { ++ if (--depth == 0) ++ break; ++ } ++ if (depth == 1 && *tstr == ':') { ++ break; ++ } ++ /* + * A variable inside a variable, expand + */ +- if (*tstr == '$') { +- int rlen; +- void *freeIt; +- char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); +- if (rval != NULL) { +- Buf_AddBytes(&buf, strlen(rval), rval); +- } +- free(freeIt); +- tstr += rlen - 1; +- } +- else +- Buf_AddByte(&buf, *tstr); +- } +- if (*tstr == ':') { +- haveModifier = TRUE; +- } else if (*tstr == endc) { +- haveModifier = FALSE; +- } else { +- /* ++ if (*tstr == '$') { ++ int rlen; ++ void *freeIt; ++ char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); ++ if (rval != NULL) { ++ Buf_AddBytes(&buf, strlen(rval), rval); ++ } ++ free(freeIt); ++ tstr += rlen - 1; ++ } else ++ Buf_AddByte(&buf, *tstr); ++ } ++ if (*tstr == ':') { ++ haveModifier = TRUE; ++ } else if (*tstr == endc) { ++ haveModifier = FALSE; ++ } else { ++ /* + * If we never did find the end character, return NULL +@@ -3872,9 +3893,9 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + */ +- *lengthPtr = tstr - str; +- Buf_Destroy(&buf, TRUE); +- return (var_Error); +- } +- str = Buf_GetAll(&buf, &vlen); ++ *lengthPtr = tstr - str; ++ Buf_Destroy(&buf, TRUE); ++ return (var_Error); ++ } ++ str = Buf_GetAll(&buf, &vlen); + +- /* ++ /* + * At this point, str points into newly allocated memory from +@@ -3889,4 +3910,4 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + +- v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); +- /* ++ v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); ++ /* + * Check also for bogus D and F forms of local variables since we're +@@ -3894,28 +3915,26 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + */ +- if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && +- (vlen == 2) && (str[1] == 'F' || str[1] == 'D') && +- strchr("@%?*!<>", str[0]) != NULL) { +- /* ++ if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && ++ (vlen == 2) && (str[1] == 'F' || str[1] == 'D') && ++ strchr("@%?*!<>", str[0]) != NULL) { ++ /* + * Well, it's local -- go look for it. + */ +- name[0] = *str; +- name[1] = '\0'; +- v = VarFind(name, ctxt, 0); +- +- if (v != NULL) { +- if (str[1] == 'D') { +- extramodifiers = "H:"; +- } +- else { /* F */ +- extramodifiers = "T:"; +- } +- } +- } +- +- if (v == NULL) { +- if (((vlen == 1) || +- (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) && +- ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) +- { +- /* ++ name[0] = *str; ++ name[1] = '\0'; ++ v = VarFind(name, ctxt, 0); ++ ++ if (v != NULL) { ++ if (str[1] == 'D') { ++ extramodifiers = "H:"; ++ } else { /* F */ ++ extramodifiers = "T:"; ++ } ++ } ++ } ++ ++ if (v == NULL) { ++ if (((vlen == 1) || ++ (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) && ++ ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) { ++ /* + * If substituting a local variable in a non-local context, +@@ -3928,28 +3947,26 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + */ +- switch (*str) { +- case '@': +- case '%': +- case '*': +- case '!': +- dynamic = TRUE; +- break; +- } +- } else if ((vlen > 2) && (*str == '.') && +- isupper((unsigned char) str[1]) && +- ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) +- { +- int len; +- +- len = vlen - 1; +- if ((strncmp(str, ".TARGET", len) == 0) || +- (strncmp(str, ".ARCHIVE", len) == 0) || +- (strncmp(str, ".PREFIX", len) == 0) || +- (strncmp(str, ".MEMBER", len) == 0)) +- { +- dynamic = TRUE; +- } +- } +- +- if (!haveModifier) { +- /* ++ switch (*str) { ++ case '@': ++ case '%': ++ case '*': ++ case '!': ++ dynamic = TRUE; ++ break; ++ } ++ } else if ((vlen > 2) && (*str == '.') && ++ isupper((unsigned char) str[1]) && ++ ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) { ++ int len; ++ ++ len = vlen - 1; ++ if ((strncmp(str, ".TARGET", len) == 0) || ++ (strncmp(str, ".ARCHIVE", len) == 0) || ++ (strncmp(str, ".PREFIX", len) == 0) || ++ (strncmp(str, ".MEMBER", len) == 0)) { ++ dynamic = TRUE; ++ } ++ } ++ ++ if (!haveModifier) { ++ /* + * No modifiers -- have specification length so we can return +@@ -3957,14 +3974,14 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + */ +- *lengthPtr = tstr - start + 1; +- if (dynamic) { +- char *pstr = bmake_strndup(start, *lengthPtr); +- *freePtr = pstr; +- Buf_Destroy(&buf, TRUE); +- return(pstr); +- } else { +- Buf_Destroy(&buf, TRUE); +- return (flags & VARF_UNDEFERR) ? var_Error : varNoError; +- } +- } else { +- /* ++ *lengthPtr = tstr - start + 1; ++ if (dynamic) { ++ char *pstr = bmake_strndup(start, *lengthPtr); ++ *freePtr = pstr; ++ Buf_Destroy(&buf, TRUE); ++ return (pstr); ++ } else { ++ Buf_Destroy(&buf, TRUE); ++ return (flags & VARF_UNDEFERR) ? var_Error : varNoError; ++ } ++ } else { ++ /* + * Still need to get to the end of the variable specification, +@@ -3972,10 +3989,10 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + */ +- v = bmake_malloc(sizeof(Var)); +- v->name = UNCONST(str); +- Buf_Init(&v->val, 1); +- v->flags = VAR_JUNK; +- Buf_Destroy(&buf, FALSE); +- } +- } else +- Buf_Destroy(&buf, TRUE); ++ v = bmake_malloc(sizeof(Var)); ++ v->name = UNCONST(str); ++ Buf_Init(&v->val, 1); ++ v->flags = VAR_JUNK; ++ Buf_Destroy(&buf, FALSE); ++ } ++ } else ++ Buf_Destroy(&buf, TRUE); + } +@@ -3983,6 +4000,6 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + if (v->flags & VAR_IN_USE) { +- Fatal("Variable %s is recursive.", v->name); +- /*NOTREACHED*/ ++ Fatal("Variable %s is recursive.", v->name); ++ /*NOTREACHED*/ + } else { +- v->flags |= VAR_IN_USE; ++ v->flags |= VAR_IN_USE; + } +@@ -3999,4 +4016,4 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + if (strchr(nstr, '$') != NULL) { +- nstr = Var_Subst(NULL, nstr, ctxt, flags); +- *freePtr = nstr; ++ nstr = Var_Subst(NULL, nstr, ctxt, flags); ++ *freePtr = nstr; + } +@@ -4006,27 +4023,27 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + if ((nstr != NULL) && (haveModifier || extramodifiers != NULL)) { +- void *extraFree; +- int used; +- +- extraFree = NULL; +- if (extramodifiers != NULL) { +- nstr = ApplyModifiers(nstr, extramodifiers, '(', ')', +- v, ctxt, flags, &used, &extraFree); +- } +- +- if (haveModifier) { +- /* Skip initial colon. */ +- tstr++; +- +- nstr = ApplyModifiers(nstr, tstr, startc, endc, +- v, ctxt, flags, &used, freePtr); +- tstr += used; +- free(extraFree); +- } else { +- *freePtr = extraFree; +- } ++ void *extraFree; ++ int used; ++ ++ extraFree = NULL; ++ if (extramodifiers != NULL) { ++ nstr = ApplyModifiers(nstr, extramodifiers, '(', ')', ++ v, ctxt, flags, &used, &extraFree); ++ } ++ ++ if (haveModifier) { ++ /* Skip initial colon. */ ++ tstr++; ++ ++ nstr = ApplyModifiers(nstr, tstr, startc, endc, ++ v, ctxt, flags, &used, freePtr); ++ tstr += used; ++ free(extraFree); ++ } else { ++ *freePtr = extraFree; ++ } + } + if (*tstr) { +- *lengthPtr = tstr - start + 1; ++ *lengthPtr = tstr - start + 1; + } else { +- *lengthPtr = tstr - start; ++ *lengthPtr = tstr - start; + } +@@ -4034,8 +4051,8 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + if (v->flags & VAR_FROM_ENV) { +- Boolean destroy = FALSE; ++ Boolean destroy = FALSE; + +- if (nstr != Buf_GetAll(&v->val, NULL)) { +- destroy = TRUE; +- } else { +- /* ++ if (nstr != Buf_GetAll(&v->val, NULL)) { ++ destroy = TRUE; ++ } else { ++ /* + * Returning the value unmodified, so tell the caller to free +@@ -4043,7 +4060,7 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + */ +- *freePtr = nstr; +- } +- VarFreeEnv(v, destroy); ++ *freePtr = nstr; ++ } ++ VarFreeEnv(v, destroy); + } else if (v->flags & VAR_JUNK) { +- /* ++ /* + * Perform any free'ing needed and set *freePtr to NULL so the caller +@@ -4052,18 +4069,18 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + */ +- if (!(v->flags & VAR_KEEP)) { +- if (*freePtr) { +- free(nstr); +- *freePtr = NULL; +- } +- if (dynamic) { +- nstr = bmake_strndup(start, *lengthPtr); +- *freePtr = nstr; +- } else { +- nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError; +- } +- } +- if (nstr != Buf_GetAll(&v->val, NULL)) +- Buf_Destroy(&v->val, TRUE); +- free(v->name); +- free(v); ++ if (!(v->flags & VAR_KEEP)) { ++ if (*freePtr) { ++ free(nstr); ++ *freePtr = NULL; ++ } ++ if (dynamic) { ++ nstr = bmake_strndup(start, *lengthPtr); ++ *freePtr = nstr; ++ } else { ++ nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError; ++ } ++ } ++ if (nstr != Buf_GetAll(&v->val, NULL)) ++ Buf_Destroy(&v->val, TRUE); ++ free(v->name); ++ free(v); + } +@@ -4095,9 +4112,8 @@ Var_Parse(const char *str, GNode *ctxt, int flags, + char * +-Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) +-{ +- Buffer buf; /* Buffer for forming things */ +- char *val; /* Value to substitute for a variable */ +- int length; /* Length of the variable invocation */ +- Boolean trailingBslash; /* variable ends in \ */ +- void *freeIt = NULL; /* Set if it should be freed */ ++Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) { ++ Buffer buf; /* Buffer for forming things */ ++ char *val; /* Value to substitute for a variable */ ++ int length; /* Length of the variable invocation */ ++ Boolean trailingBslash; /* variable ends in \ */ ++ void *freeIt = NULL; /* Set if it should be freed */ + static Boolean errorReported; /* Set true if an error has already +@@ -4111,6 +4127,6 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + while (*str) { +- if (*str == '\n' && trailingBslash) +- Buf_AddByte(&buf, ' '); +- if (var == NULL && (*str == '$') && (str[1] == '$')) { +- /* ++ if (*str == '\n' && trailingBslash) ++ Buf_AddByte(&buf, ' '); ++ if (var == NULL && (*str == '$') && (str[1] == '$')) { ++ /* + * A dollar sign may be escaped either with another dollar sign. +@@ -4119,9 +4135,9 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + */ +- if (save_dollars && (flags & VARF_ASSIGN)) +- Buf_AddByte(&buf, *str); +- str++; +- Buf_AddByte(&buf, *str); +- str++; +- } else if (*str != '$') { +- /* ++ if (save_dollars && (flags & VARF_ASSIGN)) ++ Buf_AddByte(&buf, *str); ++ str++; ++ Buf_AddByte(&buf, *str); ++ str++; ++ } else if (*str != '$') { ++ /* + * Skip as many characters as possible -- either to the end of +@@ -4129,37 +4145,35 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + */ +- const char *cp; +- +- for (cp = str++; *str != '$' && *str != '\0'; str++) +- continue; +- Buf_AddBytes(&buf, str - cp, cp); +- } else { +- if (var != NULL) { +- int expand; +- for (;;) { +- if (str[1] == '\0') { +- /* A trailing $ is kind of a special case */ +- Buf_AddByte(&buf, str[0]); +- str++; +- expand = FALSE; +- } else if (str[1] != PROPEN && str[1] != BROPEN) { +- if (str[1] != *var || strlen(var) > 1) { +- Buf_AddBytes(&buf, 2, str); +- str += 2; +- expand = FALSE; +- } +- else +- expand = TRUE; +- break; +- } +- else { +- const char *p; +- +- /* ++ const char *cp; ++ ++ for (cp = str++; *str != '$' && *str != '\0'; str++) ++ continue; ++ Buf_AddBytes(&buf, str - cp, cp); ++ } else { ++ if (var != NULL) { ++ int expand; ++ for (;;) { ++ if (str[1] == '\0') { ++ /* A trailing $ is kind of a special case */ ++ Buf_AddByte(&buf, str[0]); ++ str++; ++ expand = FALSE; ++ } else if (str[1] != PROPEN && str[1] != BROPEN) { ++ if (str[1] != *var || strlen(var) > 1) { ++ Buf_AddBytes(&buf, 2, str); ++ str += 2; ++ expand = FALSE; ++ } else ++ expand = TRUE; ++ break; ++ } else { ++ const char *p; ++ ++ /* + * Scan up to the end of the variable name. + */ +- for (p = &str[2]; *p && +- *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++) +- if (*p == '$') +- break; +- /* ++ for (p = &str[2]; *p && ++ *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++) ++ if (*p == '$') ++ break; ++ /* + * A variable inside the variable. We cannot expand +@@ -4168,11 +4182,11 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + */ +- if (*p == '$') { +- Buf_AddBytes(&buf, p - str, str); +- str = p; +- continue; +- } +- +- if (strncmp(var, str + 2, p - str - 2) != 0 || +- var[p - str - 2] != '\0') { +- /* ++ if (*p == '$') { ++ Buf_AddBytes(&buf, p - str, str); ++ str = p; ++ continue; ++ } ++ ++ if (strncmp(var, str + 2, p - str - 2) != 0 || ++ var[p - str - 2] != '\0') { ++ /* + * Not the variable we want to expand, scan +@@ -4180,20 +4194,19 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + */ +- for (;*p != '$' && *p != '\0'; p++) +- continue; +- Buf_AddBytes(&buf, p - str, str); +- str = p; +- expand = FALSE; +- } +- else +- expand = TRUE; +- break; +- } +- } +- if (!expand) +- continue; +- } +- +- val = Var_Parse(str, ctxt, flags, &length, &freeIt); +- +- /* ++ for (; *p != '$' && *p != '\0'; p++) ++ continue; ++ Buf_AddBytes(&buf, p - str, str); ++ str = p; ++ expand = FALSE; ++ } else ++ expand = TRUE; ++ break; ++ } ++ } ++ if (!expand) ++ continue; ++ } ++ ++ val = Var_Parse(str, ctxt, flags, &length, &freeIt); ++ ++ /* + * When we come down here, val should either point to the +@@ -4203,4 +4216,4 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + */ +- if (val == var_Error || val == varNoError) { +- /* ++ if (val == var_Error || val == varNoError) { ++ /* + * If performing old-time variable substitution, skip over +@@ -4210,6 +4223,6 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + */ +- if (oldVars) { +- str += length; +- } else if ((flags & VARF_UNDEFERR) || val == var_Error) { +- /* ++ if (oldVars) { ++ str += length; ++ } else if ((flags & VARF_UNDEFERR) || val == var_Error) { ++ /* + * If variable is undefined, complain and skip the +@@ -4218,14 +4231,14 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + */ +- if (!errorReported) { +- Parse_Error(PARSE_FATAL, +- "Undefined variable \"%.*s\"",length,str); +- } +- str += length; +- errorReported = TRUE; +- } else { +- Buf_AddByte(&buf, *str); +- str += 1; +- } +- } else { +- /* ++ if (!errorReported) { ++ Parse_Error(PARSE_FATAL, ++ "Undefined variable \"%.*s\"", length, str); ++ } ++ str += length; ++ errorReported = TRUE; ++ } else { ++ Buf_AddByte(&buf, *str); ++ str += 1; ++ } ++ } else { ++ /* + * We've now got a variable structure to store in. But first, +@@ -4233,5 +4246,5 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + */ +- str += length; ++ str += length; + +- /* ++ /* + * Copy all the characters from the variable value straight +@@ -4239,9 +4252,9 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + */ +- length = strlen(val); +- Buf_AddBytes(&buf, length, val); +- trailingBslash = length > 0 && val[length - 1] == '\\'; +- } +- free(freeIt); +- freeIt = NULL; +- } ++ length = strlen(val); ++ Buf_AddBytes(&buf, length, val); ++ trailingBslash = length > 0 && val[length - 1] == '\\'; ++ } ++ free(freeIt); ++ freeIt = NULL; ++ } + } +@@ -4269,3 +4282,3 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) + #if 0 +-char * ++ char * + Var_GetTail(char *file) +@@ -4313,4 +4326,3 @@ Var_GetHead(char *file) + void +-Var_Init(void) +-{ ++Var_Init(void) { + VAR_INTERNAL = Targ_NewGN("Internal"); +@@ -4323,4 +4335,3 @@ Var_Init(void) + void +-Var_End(void) +-{ ++Var_End(void) { + } +@@ -4330,5 +4341,4 @@ Var_End(void) + static void +-VarPrintVar(void *vp) +-{ +- Var *v = (Var *)vp; ++VarPrintVar(void *vp) { ++ Var *v = (Var *) vp; + fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL)); +@@ -4343,4 +4353,3 @@ VarPrintVar(void *vp) + void +-Var_Dump(GNode *ctxt) +-{ ++Var_Dump(GNode *ctxt) { + Hash_Search search; +@@ -4349,6 +4358,6888 @@ Var_Dump(GNode *ctxt) + for (h = Hash_EnumFirst(&ctxt->context, &search); +- h != NULL; +- h = Hash_EnumNext(&search)) { +- VarPrintVar(Hash_GetValue(h)); ++ h != NULL; ++ h = Hash_EnumNext(&search)) { ++ VarPrintVar(Hash_GetValue(h)); ++ } ++} ++ ++#if (!defined(HAVE_REGCOMP) || !defined(HAVE_REGERROR) || !defined(HAVE_REGEXEC) || !defined(HAVE_REGFREE)) ++ ++extern char * nl_langinfo(nl_item item); ++ ++/* Extended regular expression matching and search library. ++ Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Isamu Hasegawa . ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++static void re_string_construct_common(const char *str, Idx len, ++ re_string_t *pstr, ++ RE_TRANSLATE_TYPE trans, bool icase, ++ const re_dfa_t *dfa); ++ ++static re_dfastate_t *create_ci_newstate(const re_dfa_t *dfa, ++ const re_node_set *nodes, ++ re_hashval_t hash); ++ ++static re_dfastate_t *create_cd_newstate(const re_dfa_t *dfa, ++ const re_node_set *nodes, ++ unsigned int context, ++ re_hashval_t hash); ++ ++static reg_errcode_t re_string_realloc_buffers(re_string_t *pstr, ++ Idx new_buf_len); ++ ++static void build_upper_buffer(re_string_t *pstr); ++ ++static void re_string_translate_buffer(re_string_t *pstr); ++ ++static unsigned int re_string_context_at(const re_string_t *input, Idx idx, ++ int eflags) __attribute__ ((pure)); ++ ++static reg_errcode_t match_ctx_init(re_match_context_t *cache, int eflags, ++ Idx n); ++ ++static void match_ctx_clean(re_match_context_t *mctx); ++ ++static void match_ctx_free(re_match_context_t *cache); ++ ++static reg_errcode_t match_ctx_add_entry(re_match_context_t *cache, Idx node, ++ Idx str_idx, Idx from, Idx to); ++ ++static Idx search_cur_bkref_entry(const re_match_context_t *mctx, Idx str_idx); ++ ++static reg_errcode_t match_ctx_add_subtop(re_match_context_t *mctx, Idx node, ++ Idx str_idx); ++ ++static re_sub_match_last_t *match_ctx_add_sublast(re_sub_match_top_t *subtop, ++ Idx node, Idx str_idx); ++ ++static void sift_ctx_init(re_sift_context_t *sctx, re_dfastate_t **sifted_sts, ++ re_dfastate_t **limited_sts, Idx last_node, ++ Idx last_str_idx); ++ ++static reg_errcode_t re_search_internal(const regex_t *preg, ++ const char *string, Idx length, ++ Idx start, Idx last_start, Idx stop, ++ size_t nmatch, regmatch_t pmatch[], ++ int eflags); ++ ++static regoff_t re_search_2_stub(struct re_pattern_buffer *bufp, ++ const char *string1, Idx length1, ++ const char *string2, Idx length2, ++ Idx start, regoff_t range, ++ struct re_registers *regs, ++ Idx stop, bool ret_len); ++ ++static regoff_t re_search_stub(struct re_pattern_buffer *bufp, ++ const char *string, Idx length, Idx start, ++ regoff_t range, Idx stop, ++ struct re_registers *regs, ++ bool ret_len); ++ ++static unsigned re_copy_regs(struct re_registers *regs, regmatch_t *pmatch, ++ Idx nregs, int regs_allocated); ++ ++static reg_errcode_t prune_impossible_nodes(re_match_context_t *mctx); ++ ++static Idx check_matching(re_match_context_t *mctx, bool fl_longest_match, ++ Idx *p_match_first); ++ ++static Idx check_halt_state_context(const re_match_context_t *mctx, ++ const re_dfastate_t *state, Idx idx); ++ ++static void update_regs(const re_dfa_t *dfa, regmatch_t *pmatch, ++ regmatch_t *prev_idx_match, Idx cur_node, ++ Idx cur_idx, Idx nmatch); ++ ++static reg_errcode_t push_fail_stack(struct re_fail_stack_t *fs, ++ Idx str_idx, Idx dest_node, Idx nregs, ++ regmatch_t *regs, ++ re_node_set *eps_via_nodes); ++ ++static reg_errcode_t set_regs(const regex_t *preg, ++ const re_match_context_t *mctx, ++ size_t nmatch, regmatch_t *pmatch, ++ bool fl_backtrack); ++ ++static reg_errcode_t free_fail_stack_return(struct re_fail_stack_t *fs); ++ ++static reg_errcode_t sift_states_backward(const re_match_context_t *mctx, ++ re_sift_context_t *sctx); ++ ++static reg_errcode_t build_sifted_states(const re_match_context_t *mctx, ++ re_sift_context_t *sctx, Idx str_idx, ++ re_node_set *cur_dest); ++ ++static reg_errcode_t update_cur_sifted_state(const re_match_context_t *mctx, ++ re_sift_context_t *sctx, ++ Idx str_idx, ++ re_node_set *dest_nodes); ++ ++static reg_errcode_t add_epsilon_src_nodes(const re_dfa_t *dfa, ++ re_node_set *dest_nodes, ++ const re_node_set *candidates); ++ ++static bool check_dst_limits(const re_match_context_t *mctx, ++ const re_node_set *limits, ++ Idx dst_node, Idx dst_idx, Idx src_node, ++ Idx src_idx); ++ ++static int check_dst_limits_calc_pos_1(const re_match_context_t *mctx, ++ int boundaries, Idx subexp_idx, ++ Idx from_node, Idx bkref_idx); ++ ++static int check_dst_limits_calc_pos(const re_match_context_t *mctx, ++ Idx limit, Idx subexp_idx, ++ Idx node, Idx str_idx, ++ Idx bkref_idx); ++ ++static reg_errcode_t check_subexp_limits(const re_dfa_t *dfa, ++ re_node_set *dest_nodes, ++ const re_node_set *candidates, ++ re_node_set *limits, ++ struct re_backref_cache_entry *bkref_ents, ++ Idx str_idx); ++ ++static reg_errcode_t sift_states_bkref(const re_match_context_t *mctx, ++ re_sift_context_t *sctx, ++ Idx str_idx, const re_node_set *candidates); ++ ++static reg_errcode_t merge_state_array(const re_dfa_t *dfa, ++ re_dfastate_t **dst, ++ re_dfastate_t **src, Idx num); ++ ++static re_dfastate_t *find_recover_state(reg_errcode_t *err, ++ re_match_context_t *mctx); ++ ++static re_dfastate_t *transit_state(reg_errcode_t *err, ++ re_match_context_t *mctx, ++ re_dfastate_t *state); ++ ++static re_dfastate_t *merge_state_with_log(reg_errcode_t *err, ++ re_match_context_t *mctx, ++ re_dfastate_t *next_state); ++ ++static reg_errcode_t check_subexp_matching_top(re_match_context_t *mctx, ++ re_node_set *cur_nodes, ++ Idx str_idx); ++ ++static reg_errcode_t transit_state_bkref(re_match_context_t *mctx, ++ const re_node_set *nodes); ++ ++static reg_errcode_t get_subexp(re_match_context_t *mctx, ++ Idx bkref_node, Idx bkref_str_idx); ++ ++static reg_errcode_t get_subexp_sub(re_match_context_t *mctx, ++ const re_sub_match_top_t *sub_top, ++ re_sub_match_last_t *sub_last, ++ Idx bkref_node, Idx bkref_str); ++ ++static Idx find_subexp_node(const re_dfa_t *dfa, const re_node_set *nodes, ++ Idx subexp_idx, int type); ++ ++static reg_errcode_t check_arrival(re_match_context_t *mctx, ++ state_array_t *path, Idx top_node, ++ Idx top_str, Idx last_node, Idx last_str, ++ int type); ++ ++static reg_errcode_t check_arrival_add_next_nodes(re_match_context_t *mctx, ++ Idx str_idx, ++ re_node_set *cur_nodes, ++ re_node_set *next_nodes); ++ ++static reg_errcode_t check_arrival_expand_ecl(const re_dfa_t *dfa, ++ re_node_set *cur_nodes, ++ Idx ex_subexp, int type); ++ ++static reg_errcode_t check_arrival_expand_ecl_sub(const re_dfa_t *dfa, ++ re_node_set *dst_nodes, ++ Idx target, Idx ex_subexp, ++ int type); ++ ++static reg_errcode_t expand_bkref_cache(re_match_context_t *mctx, ++ re_node_set *cur_nodes, Idx cur_str, ++ Idx subexp_num, int type); ++ ++static bool build_trtable(const re_dfa_t *dfa, re_dfastate_t *state); ++ ++static Idx group_nodes_into_DFAstates(const re_dfa_t *dfa, ++ const re_dfastate_t *state, ++ re_node_set *states_node, ++ bitset_t *states_ch); ++ ++static bool check_node_accept(const re_match_context_t *mctx, ++ const re_token_t *node, Idx idx); ++ ++static reg_errcode_t extend_buffers(re_match_context_t *mctx, int min_len); ++ ++/* Check NODE match the current context. */ ++ ++static bool ++check_halt_node_context(const re_dfa_t *dfa, Idx node, unsigned int context) { ++ re_token_type_t type = dfa->nodes[node].type; ++ unsigned int constraint = dfa->nodes[node].constraint; ++ if (type != END_OF_RE) ++ return false; ++ if (!constraint) ++ return true; ++ if (NOT_SATISFY_NEXT_CONSTRAINT(constraint, context)) ++ return false; ++ return true; ++} ++ ++/* Check the halt state STATE match the current context. ++ Return 0 if not match, if the node, STATE has, is a halt node and ++ match the context, return the node. */ ++ ++static Idx ++check_halt_state_context(const re_match_context_t *mctx, ++ const re_dfastate_t *state, Idx idx) { ++ Idx i; ++ unsigned int context; ++ context = re_string_context_at(&mctx->input, idx, mctx->eflags); ++ for (i = 0; i < state->nodes.nelem; ++i) ++ if (check_halt_node_context(mctx->dfa, state->nodes.elems[i], context)) ++ return state->nodes.elems[i]; ++ return 0; ++} ++ ++/* Functions for string operation. */ ++ ++/* This function allocate the buffers. It is necessary to call ++ re_string_reconstruct before using the object. */ ++ ++static reg_errcode_t ++ ++re_string_allocate(re_string_t *pstr, const char *str, Idx len, Idx init_len, ++ RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) { ++ reg_errcode_t ret; ++ Idx init_buf_len; ++ ++/* Ensure at least one character fits into the buffers. */ ++ if (init_len < dfa->mb_cur_max) ++ init_len = dfa->mb_cur_max; ++ init_buf_len = (len + 1 < init_len) ? len + 1 : init_len; ++ re_string_construct_common(str, len, pstr, trans, icase, dfa); ++ ++ ret = re_string_realloc_buffers(pstr, init_buf_len); ++ if ((ret != REG_NOERROR)) ++ return ret; ++ ++ pstr->word_char = dfa->word_char; ++ pstr->word_ops_used = dfa->word_ops_used; ++ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; ++ pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len; ++ pstr->valid_raw_len = pstr->valid_len; ++ return REG_NOERROR; ++} ++ ++/* This function allocate the buffers, and initialize them. */ ++ ++static reg_errcode_t ++ ++re_string_construct(re_string_t *pstr, const char *str, Idx len, ++ RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) { ++ reg_errcode_t ret; ++ memset(pstr, '\0', sizeof(re_string_t)); ++ re_string_construct_common(str, len, pstr, trans, icase, dfa); ++ ++ if (len > 0) { ++ ret = re_string_realloc_buffers(pstr, len + 1); ++ if ((ret != REG_NOERROR)) ++ return ret; ++ } ++ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; ++ ++ if (icase) { ++ ++ build_upper_buffer(pstr); ++ } else { ++ ++ { ++ if (trans != NULL) ++ re_string_translate_buffer(pstr); ++ else { ++ pstr->valid_len = pstr->bufs_len; ++ pstr->valid_raw_len = pstr->bufs_len; ++ } ++ } ++ } ++ ++ return REG_NOERROR; ++} ++ ++/* Helper functions for re_string_allocate, and re_string_construct. */ ++ ++static reg_errcode_t ++ ++re_string_realloc_buffers(re_string_t *pstr, Idx new_buf_len) { ++ ++ if (pstr->mbs_allocated) { ++ unsigned char *new_mbs = re_realloc(pstr->mbs, ++ unsigned char, ++ new_buf_len); ++ if ((new_mbs == NULL)) ++ return REG_ESPACE; ++ pstr->mbs = new_mbs; + } ++ pstr->bufs_len = new_buf_len; ++ return REG_NOERROR; + } ++ ++ ++static void ++re_string_construct_common(const char *str, Idx len, re_string_t *pstr, ++ RE_TRANSLATE_TYPE trans, bool icase, ++ const re_dfa_t *dfa) { ++ pstr->raw_mbs = (const unsigned char *) str; ++ pstr->len = len; ++ pstr->raw_len = len; ++ pstr->trans = trans; ++ pstr->icase = icase; ++ pstr->mbs_allocated = (trans != NULL || icase); ++ pstr->mb_cur_max = dfa->mb_cur_max; ++ pstr->is_utf8 = dfa->is_utf8; ++ pstr->map_notascii = dfa->map_notascii; ++ pstr->stop = pstr->len; ++ pstr->raw_stop = pstr->stop; ++} ++ ++/* Build the buffer PSTR->MBS, and apply the translation if we need. ++ This function is used in case of REG_ICASE. */ ++ ++static void ++build_upper_buffer(re_string_t *pstr) { ++ Idx char_idx, end_idx; ++ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; ++ ++ for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx) { ++ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; ++ if ((pstr->trans != NULL)) ++ ch = pstr->trans[ch]; ++ pstr->mbs[char_idx] = toupper(ch); ++ } ++ pstr->valid_len = char_idx; ++ pstr->valid_raw_len = char_idx; ++} ++ ++/* Apply TRANS to the buffer in PSTR. */ ++ ++static void ++re_string_translate_buffer(re_string_t *pstr) { ++ Idx buf_idx, end_idx; ++ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; ++ ++ for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx) { ++ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; ++ pstr->mbs[buf_idx] = pstr->trans[ch]; ++ } ++ ++ pstr->valid_len = buf_idx; ++ pstr->valid_raw_len = buf_idx; ++} ++ ++/* This function re-construct the buffers. ++ Concretely, convert to wide character in case of pstr->mb_cur_max > 1, ++ convert to upper case in case of REG_ICASE, apply translation. */ ++ ++static reg_errcode_t ++ ++re_string_reconstruct(re_string_t *pstr, Idx idx, int eflags) { ++ Idx offset; ++ ++ if ((pstr->raw_mbs_idx <= idx)) ++ offset = idx - pstr->raw_mbs_idx; ++ else { ++/* Reset buffer. */ ++ ++ pstr->len = pstr->raw_len; ++ pstr->stop = pstr->raw_stop; ++ pstr->valid_len = 0; ++ pstr->raw_mbs_idx = 0; ++ pstr->valid_raw_len = 0; ++ pstr->offsets_needed = 0; ++ pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF ++ : CONTEXT_NEWLINE | CONTEXT_BEGBUF); ++ if (!pstr->mbs_allocated) ++ pstr->mbs = (unsigned char *) pstr->raw_mbs; ++ offset = idx; ++ } ++ ++ if ((offset != 0)) { ++/* Should the already checked characters be kept? */ ++ if ((offset < pstr->valid_raw_len)) { ++/* Yes, move them to the front of the buffer. */ ++ ++ { ++ pstr->tip_context = re_string_context_at(pstr, offset - 1, ++ eflags); ++ ++ if ((pstr->mbs_allocated)) ++ memmove(pstr->mbs, pstr->mbs + offset, ++ pstr->valid_len - offset); ++ pstr->valid_len -= offset; ++ pstr->valid_raw_len -= offset; ++ ++ } ++ } else { ++ ++ pstr->valid_len = 0; ++ ++ { ++ int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; ++ pstr->valid_raw_len = 0; ++ if (pstr->trans) ++ c = pstr->trans[c]; ++ pstr->tip_context = (bitset_contain(pstr->word_char, c) ++ ? CONTEXT_WORD ++ : ((IS_NEWLINE(c) && pstr->newline_anchor) ++ ? CONTEXT_NEWLINE : 0)); ++ } ++ } ++ if (!(pstr->mbs_allocated)) ++ pstr->mbs += offset; ++ } ++ pstr->raw_mbs_idx = idx; ++ pstr->len -= offset; ++ pstr->stop -= offset; ++ ++/* Then build the buffers. */ ++ ++ if ((pstr->mbs_allocated)) { ++ if (pstr->icase) ++ build_upper_buffer(pstr); ++ else if (pstr->trans != NULL) ++ re_string_translate_buffer(pstr); ++ } else ++ pstr->valid_len = pstr->len; ++ ++ pstr->cur_idx = 0; ++ return REG_NOERROR; ++} ++ ++static unsigned char ++__attribute__ ((pure)) ++re_string_peek_byte_case(const re_string_t *pstr, Idx idx) { ++ int ch; ++ Idx off; ++ ++ /* Handle the common (easiest) cases first. */ ++ if ((!pstr->mbs_allocated)) ++ return re_string_peek_byte(pstr, idx); ++ ++ off = pstr->cur_idx + idx; ++ ++ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; ++ ++ return ch; ++} ++ ++static unsigned char ++re_string_fetch_byte_case(re_string_t *pstr) { ++ if ((!pstr->mbs_allocated)) ++ return re_string_fetch_byte(pstr); ++ ++ return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++]; ++} ++ ++static void ++re_string_destruct(re_string_t *pstr) { ++ ++ if (pstr->mbs_allocated) ++ re_free(pstr->mbs); ++} ++ ++/* Return the context at IDX in INPUT. */ ++ ++static unsigned int ++re_string_context_at(const re_string_t *input, Idx idx, int eflags) { ++ int c; ++ if ((idx < 0)) ++ /* In this case, we use the value stored in input->tip_context, ++ since we can't know the character in input->mbs[-1] here. */ ++ return input->tip_context; ++ if ((idx == input->len)) ++ return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF ++ : CONTEXT_NEWLINE | CONTEXT_ENDBUF); ++ ++ { ++ c = re_string_byte_at(input, idx); ++ if (bitset_contain(input->word_char, c)) ++ return CONTEXT_WORD; ++ return IS_NEWLINE(c) && input->newline_anchor ? CONTEXT_NEWLINE : 0; ++ } ++} ++ ++/* Functions for set operation. */ ++ ++static reg_errcode_t ++ ++re_node_set_alloc(re_node_set *set, Idx size) { ++ set->alloc = size; ++ set->nelem = 0; ++ set->elems = re_malloc(Idx, size); ++ if ((set->elems == NULL) ++ && (MALLOC_0_IS_NONNULL || size != 0)) ++ return REG_ESPACE; ++ return REG_NOERROR; ++} ++ ++static reg_errcode_t ++ ++re_node_set_init_1(re_node_set *set, Idx elem) { ++ set->alloc = 1; ++ set->nelem = 1; ++ set->elems = re_malloc(Idx, 1); ++ if ((set->elems == NULL)) { ++ set->alloc = set->nelem = 0; ++ return REG_ESPACE; ++ } ++ set->elems[0] = elem; ++ return REG_NOERROR; ++} ++ ++static reg_errcode_t ++ ++re_node_set_init_2(re_node_set *set, Idx elem1, Idx elem2) { ++ set->alloc = 2; ++ set->elems = re_malloc(Idx, 2); ++ if ((set->elems == NULL)) ++ return REG_ESPACE; ++ if (elem1 == elem2) { ++ set->nelem = 1; ++ set->elems[0] = elem1; ++ } else { ++ set->nelem = 2; ++ if (elem1 < elem2) { ++ set->elems[0] = elem1; ++ set->elems[1] = elem2; ++ } else { ++ set->elems[0] = elem2; ++ set->elems[1] = elem1; ++ } ++ } ++ return REG_NOERROR; ++} ++ ++static reg_errcode_t ++ ++re_node_set_init_copy(re_node_set *dest, const re_node_set *src) { ++ dest->nelem = src->nelem; ++ if (src->nelem > 0) { ++ dest->alloc = dest->nelem; ++ dest->elems = re_malloc(Idx, dest->alloc); ++ if ((dest->elems == NULL)) { ++ dest->alloc = dest->nelem = 0; ++ return REG_ESPACE; ++ } ++ memcpy(dest->elems, src->elems, src->nelem * sizeof(Idx)); ++ } else ++ re_node_set_init_empty(dest); ++ return REG_NOERROR; ++} ++ ++/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to ++ DEST. Return value indicate the error code or REG_NOERROR if succeeded. ++ Note: We assume dest->elems is NULL, when dest->alloc is 0. */ ++ ++static reg_errcode_t ++ ++re_node_set_add_intersect(re_node_set *dest, const re_node_set *src1, ++ const re_node_set *src2) { ++ Idx i1, i2, is, id, delta, sbase; ++ if (src1->nelem == 0 || src2->nelem == 0) ++ return REG_NOERROR; ++ ++/* We need dest->nelem + 2 * elems_in_intersection; this is a ++ conservative estimate. */ ++ if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) { ++ Idx new_alloc = src1->nelem + src2->nelem + dest->alloc; ++ Idx *new_elems = re_realloc(dest->elems, Idx, new_alloc); ++ if ((new_elems == NULL)) ++ return REG_ESPACE; ++ dest->elems = new_elems; ++ dest->alloc = new_alloc; ++ } ++ ++/* Find the items in the intersection of SRC1 and SRC2, and copy ++ into the top of DEST those that are not already in DEST itself. */ ++ sbase = dest->nelem + src1->nelem + src2->nelem; ++ i1 = src1->nelem - 1; ++ i2 = src2->nelem - 1; ++ id = dest->nelem - 1; ++ for (;;) { ++ if (src1->elems[i1] == src2->elems[i2]) { ++/* Try to find the item in DEST. Maybe we could binary search? */ ++ while (id >= 0 && dest->elems[id] > src1->elems[i1]) ++ --id; ++ ++ if (id < 0 || dest->elems[id] != src1->elems[i1]) ++ dest->elems[--sbase] = src1->elems[i1]; ++ ++ if (--i1 < 0 || --i2 < 0) ++ break; ++ } ++ ++/* Lower the highest of the two items. */ ++ else if (src1->elems[i1] < src2->elems[i2]) { ++ if (--i2 < 0) ++ break; ++ } else { ++ if (--i1 < 0) ++ break; ++ } ++ } ++ ++ id = dest->nelem - 1; ++ is = dest->nelem + src1->nelem + src2->nelem - 1; ++ delta = is - sbase + 1; ++ ++/* Now copy. When DELTA becomes zero, the remaining ++ DEST elements are already in place; this is more or ++ less the same loop that is in re_node_set_merge. */ ++ dest->nelem += delta; ++ if (delta > 0 && id >= 0) ++ for (;;) { ++ if (dest->elems[is] > dest->elems[id]) { ++/* Copy from the top. */ ++ dest->elems[id + delta--] = dest->elems[is--]; ++ if (delta == 0) ++ break; ++ } else { ++/* Slide from the bottom. */ ++ dest->elems[id + delta] = dest->elems[id]; ++ if (--id < 0) ++ break; ++ } ++ } ++ ++/* Copy remaining SRC elements. */ ++ memcpy(dest->elems, dest->elems + sbase, delta * sizeof(Idx)); ++ ++ return REG_NOERROR; ++} ++ ++/* Calculate the union set of the sets SRC1 and SRC2. And store it to ++ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ ++ ++static reg_errcode_t ++ ++re_node_set_init_union(re_node_set *dest, const re_node_set *src1, ++ const re_node_set *src2) { ++ Idx i1, i2, id; ++ if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) { ++ dest->alloc = src1->nelem + src2->nelem; ++ dest->elems = re_malloc(Idx, dest->alloc); ++ if ((dest->elems == NULL)) ++ return REG_ESPACE; ++ } else { ++ if (src1 != NULL && src1->nelem > 0) ++ return re_node_set_init_copy(dest, src1); ++ else if (src2 != NULL && src2->nelem > 0) ++ return re_node_set_init_copy(dest, src2); ++ else ++ re_node_set_init_empty(dest); ++ return REG_NOERROR; ++ } ++ for (i1 = i2 = id = 0; i1 < src1->nelem && i2 < src2->nelem;) { ++ if (src1->elems[i1] > src2->elems[i2]) { ++ dest->elems[id++] = src2->elems[i2++]; ++ continue; ++ } ++ if (src1->elems[i1] == src2->elems[i2]) ++ ++i2; ++ dest->elems[id++] = src1->elems[i1++]; ++ } ++ if (i1 < src1->nelem) { ++ memcpy(dest->elems + id, src1->elems + i1, ++ (src1->nelem - i1) * sizeof(Idx)); ++ id += src1->nelem - i1; ++ } else if (i2 < src2->nelem) { ++ memcpy(dest->elems + id, src2->elems + i2, ++ (src2->nelem - i2) * sizeof(Idx)); ++ id += src2->nelem - i2; ++ } ++ dest->nelem = id; ++ return REG_NOERROR; ++} ++ ++/* Calculate the union set of the sets DEST and SRC. And store it to ++ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ ++ ++static reg_errcode_t ++ ++re_node_set_merge(re_node_set *dest, const re_node_set *src) { ++ Idx is, id, sbase, delta; ++ if (src == NULL || src->nelem == 0) ++ return REG_NOERROR; ++ if (dest->alloc < 2 * src->nelem + dest->nelem) { ++ Idx new_alloc = 2 * (src->nelem + dest->alloc); ++ Idx *new_buffer = re_realloc(dest->elems, Idx, new_alloc); ++ if ((new_buffer == NULL)) ++ return REG_ESPACE; ++ dest->elems = new_buffer; ++ dest->alloc = new_alloc; ++ } ++ ++ if ((dest->nelem == 0)) { ++ dest->nelem = src->nelem; ++ memcpy(dest->elems, src->elems, src->nelem * sizeof(Idx)); ++ return REG_NOERROR; ++ } ++ ++/* Copy into the top of DEST the items of SRC that are not ++ found in DEST. Maybe we could binary search in DEST? */ ++ for (sbase = dest->nelem + 2 * src->nelem, ++ is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0;) { ++ if (dest->elems[id] == src->elems[is]) ++ is--, id--; ++ else if (dest->elems[id] < src->elems[is]) ++ dest->elems[--sbase] = src->elems[is--]; ++ else /* if (dest->elems[id] > src->elems[is]) */ ++ --id; ++ } ++ ++ if (is >= 0) { ++/* If DEST is exhausted, the remaining items of SRC must be unique. */ ++ sbase -= is + 1; ++ memcpy(dest->elems + sbase, src->elems, (is + 1) * sizeof(Idx)); ++ } ++ ++ id = dest->nelem - 1; ++ is = dest->nelem + 2 * src->nelem - 1; ++ delta = is - sbase + 1; ++ if (delta == 0) ++ return REG_NOERROR; ++ ++/* Now copy. When DELTA becomes zero, the remaining ++ DEST elements are already in place. */ ++ dest->nelem += delta; ++ for (;;) { ++ if (dest->elems[is] > dest->elems[id]) { ++/* Copy from the top. */ ++ dest->elems[id + delta--] = dest->elems[is--]; ++ if (delta == 0) ++ break; ++ } else { ++/* Slide from the bottom. */ ++ dest->elems[id + delta] = dest->elems[id]; ++ if (--id < 0) { ++/* Copy remaining SRC elements. */ ++ memcpy(dest->elems, dest->elems + sbase, ++ delta * sizeof(Idx)); ++ break; ++ } ++ } ++ } ++ ++ return REG_NOERROR; ++} ++ ++/* Insert the new element ELEM to the re_node_set* SET. ++ SET should not already have ELEM. ++ Return true if successful. */ ++ ++static bool ++ ++re_node_set_insert(re_node_set *set, Idx elem) { ++ Idx idx; ++/* In case the set is empty. */ ++ if (set->alloc == 0) ++ return (re_node_set_init_1(set, elem) == REG_NOERROR); ++ ++ if ((set->nelem) == 0) { ++/* We already guaranteed above that set->alloc != 0. */ ++ set->elems[0] = elem; ++ ++set->nelem; ++ return true; ++ } ++ ++/* Realloc if we need. */ ++ if (set->alloc == set->nelem) { ++ Idx *new_elems; ++ set->alloc = set->alloc * 2; ++ new_elems = re_realloc(set->elems, Idx, set->alloc); ++ if ((new_elems == NULL)) ++ return false; ++ set->elems = new_elems; ++ } ++ ++/* Move the elements which follows the new element. Test the ++ first element separately to skip a check in the inner loop. */ ++ if (elem < set->elems[0]) { ++ idx = 0; ++ for (idx = set->nelem; idx > 0; idx--) ++ set->elems[idx] = set->elems[idx - 1]; ++ } else { ++ for (idx = set->nelem; set->elems[idx - 1] > elem; idx--) ++ set->elems[idx] = set->elems[idx - 1]; ++ } ++ ++/* Insert the new element. */ ++ set->elems[idx] = elem; ++ ++set->nelem; ++ return true; ++} ++ ++/* Insert the new element ELEM to the re_node_set* SET. ++ SET should not already have any element greater than or equal to ELEM. ++ Return true if successful. */ ++ ++static bool ++ ++re_node_set_insert_last(re_node_set *set, Idx elem) { ++/* Realloc if we need. */ ++ if (set->alloc == set->nelem) { ++ Idx *new_elems; ++ set->alloc = (set->alloc + 1) * 2; ++ new_elems = re_realloc(set->elems, Idx, set->alloc); ++ if ((new_elems == NULL)) ++ return false; ++ set->elems = new_elems; ++ } ++ ++/* Insert the new element. */ ++ set->elems[set->nelem++] = elem; ++ return true; ++} ++ ++/* Compare two node sets SET1 and SET2. ++ Return true if SET1 and SET2 are equivalent. */ ++ ++static bool ++__attribute__ ((pure)) ++re_node_set_compare(const re_node_set *set1, const re_node_set *set2) { ++ Idx i; ++ if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) ++ return false; ++ for (i = set1->nelem; --i >= 0;) ++ if (set1->elems[i] != set2->elems[i]) ++ return false; ++ return true; ++} ++ ++/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ ++ ++static Idx ++__attribute__ ((pure)) ++re_node_set_contains(const re_node_set *set, Idx elem) { ++ __re_size_t idx, right, mid; ++ if (set->nelem <= 0) ++ return 0; ++ ++ /* Binary search the element. */ ++ idx = 0; ++ right = set->nelem - 1; ++ while (idx < right) { ++ mid = (idx + right) / 2; ++ if (set->elems[mid] < elem) ++ idx = mid + 1; ++ else ++ right = mid; ++ } ++ return set->elems[idx] == elem ? idx + 1 : 0; ++} ++ ++static void ++re_node_set_remove_at(re_node_set *set, Idx idx) { ++ if (idx < 0 || idx >= set->nelem) ++ return; ++ --set->nelem; ++ for (; idx < set->nelem; idx++) ++ set->elems[idx] = set->elems[idx + 1]; ++} ++ ++ ++/* Add the token TOKEN to dfa->nodes, and return the index of the token. ++ Or return -1 if an error occurred. */ ++ ++static Idx ++re_dfa_add_node(re_dfa_t *dfa, re_token_t token) { ++ if ((dfa->nodes_len >= dfa->nodes_alloc)) { ++ size_t new_nodes_alloc = dfa->nodes_alloc * 2; ++ Idx *new_nexts, *new_indices; ++ re_node_set *new_edests, *new_eclosures; ++ re_token_t *new_nodes; ++ ++ /* Avoid overflows in realloc. */ ++ const size_t max_object_size = MAX (sizeof(re_token_t), ++ MAX(sizeof(re_node_set), ++ sizeof(Idx))); ++ if ((MIN (IDX_MAX, SIZE_MAX / max_object_size) ++ < new_nodes_alloc)) ++ return -1; ++ ++ new_nodes = re_realloc(dfa->nodes, re_token_t, new_nodes_alloc); ++ if ((new_nodes == NULL)) ++ return -1; ++ dfa->nodes = new_nodes; ++ new_nexts = re_realloc(dfa->nexts, Idx, new_nodes_alloc); ++ new_indices = re_realloc(dfa->org_indices, Idx, new_nodes_alloc); ++ new_edests = re_realloc(dfa->edests, re_node_set, new_nodes_alloc); ++ new_eclosures = re_realloc(dfa->eclosures, re_node_set, new_nodes_alloc); ++ if ((new_nexts == NULL || new_indices == NULL ++ || new_edests == NULL || new_eclosures == NULL)) { ++ re_free(new_nexts); ++ re_free(new_indices); ++ re_free(new_edests); ++ re_free(new_eclosures); ++ return -1; ++ } ++ dfa->nexts = new_nexts; ++ dfa->org_indices = new_indices; ++ dfa->edests = new_edests; ++ dfa->eclosures = new_eclosures; ++ dfa->nodes_alloc = new_nodes_alloc; ++ } ++ dfa->nodes[dfa->nodes_len] = token; ++ dfa->nodes[dfa->nodes_len].constraint = 0; ++ dfa->nexts[dfa->nodes_len] = -1; ++ re_node_set_init_empty(dfa->edests + dfa->nodes_len); ++ re_node_set_init_empty(dfa->eclosures + dfa->nodes_len); ++ return dfa->nodes_len++; ++} ++ ++static re_hashval_t ++calc_state_hash(const re_node_set *nodes, unsigned int context) { ++ re_hashval_t hash = nodes->nelem + context; ++ Idx i; ++ for (i = 0; i < nodes->nelem; i++) ++ hash += nodes->elems[i]; ++ return hash; ++} ++ ++/* Search for the state whose node_set is equivalent to NODES. ++ Return the pointer to the state, if we found it in the DFA. ++ Otherwise create the new one and return it. In case of an error ++ return NULL and set the error code in ERR. ++ Note: - We assume NULL as the invalid state, then it is possible that ++ return value is NULL and ERR is REG_NOERROR. ++ - We never return non-NULL value in case of any errors, it is for ++ optimization. */ ++ ++static re_dfastate_t * ++ ++re_acquire_state(reg_errcode_t *err, const re_dfa_t *dfa, ++ const re_node_set *nodes) { ++ re_hashval_t hash; ++ re_dfastate_t *new_state; ++ struct re_state_table_entry *spot; ++ Idx i; ++#if defined GCC_LINT || defined lint ++ /* Suppress bogus uninitialized-variable warnings. */ ++ *err = REG_NOERROR; ++#endif ++ if ((nodes->nelem == 0)) { ++ *err = REG_NOERROR; ++ return NULL; ++ } ++ hash = calc_state_hash(nodes, 0); ++ spot = dfa->state_table + (hash & dfa->state_hash_mask); ++ ++ for (i = 0; i < spot->num; i++) { ++ re_dfastate_t *state = spot->array[i]; ++ if (hash != state->hash) ++ continue; ++ if (re_node_set_compare(&state->nodes, nodes)) ++ return state; ++ } ++ ++/* There are no appropriate state in the dfa, create the new one. */ ++ new_state = create_ci_newstate(dfa, nodes, hash); ++ if ((new_state == NULL)) ++ *err = REG_ESPACE; ++ ++ return new_state; ++} ++ ++/* Search for the state whose node_set is equivalent to NODES and ++ whose context is equivalent to CONTEXT. ++ Return the pointer to the state, if we found it in the DFA. ++ Otherwise create the new one and return it. In case of an error ++ return NULL and set the error code in ERR. ++ Note: - We assume NULL as the invalid state, then it is possible that ++ return value is NULL and ERR is REG_NOERROR. ++ - We never return non-NULL value in case of any errors, it is for ++ optimization. */ ++ ++static re_dfastate_t * ++ ++re_acquire_state_context(reg_errcode_t *err, const re_dfa_t *dfa, ++ const re_node_set *nodes, unsigned int context) { ++ re_hashval_t hash; ++ re_dfastate_t *new_state; ++ struct re_state_table_entry *spot; ++ Idx i; ++#if defined GCC_LINT || defined lint ++ /* Suppress bogus uninitialized-variable warnings. */ ++ *err = REG_NOERROR; ++#endif ++ if (nodes->nelem == 0) { ++ *err = REG_NOERROR; ++ return NULL; ++ } ++ hash = calc_state_hash(nodes, context); ++ spot = dfa->state_table + (hash & dfa->state_hash_mask); ++ ++ for (i = 0; i < spot->num; i++) { ++ re_dfastate_t *state = spot->array[i]; ++ if (state->hash == hash ++ && state->context == context ++ && re_node_set_compare(state->entrance_nodes, nodes)) ++ return state; ++ } ++/* There are no appropriate state in 'dfa', create the new one. */ ++ new_state = create_cd_newstate(dfa, nodes, context, hash); ++ if ((new_state == NULL)) ++ *err = REG_ESPACE; ++ ++ return new_state; ++} ++ ++/* Finish initialization of the new state NEWSTATE, and using its hash value ++ HASH put in the appropriate bucket of DFA's state table. Return value ++ indicates the error code if failed. */ ++ ++static reg_errcode_t ++ ++register_state(const re_dfa_t *dfa, re_dfastate_t *newstate, ++ re_hashval_t hash) { ++ struct re_state_table_entry *spot; ++ reg_errcode_t err; ++ Idx i; ++ ++ newstate->hash = hash; ++ err = re_node_set_alloc(&newstate->non_eps_nodes, newstate->nodes.nelem); ++ if ((err != REG_NOERROR)) ++ return REG_ESPACE; ++ for (i = 0; i < newstate->nodes.nelem; i++) { ++ Idx elem = newstate->nodes.elems[i]; ++ if (!IS_EPSILON_NODE(dfa->nodes[elem].type)) ++ if (!re_node_set_insert_last(&newstate->non_eps_nodes, elem)) ++ return REG_ESPACE; ++ } ++ ++ spot = dfa->state_table + (hash & dfa->state_hash_mask); ++ if ((spot->alloc <= spot->num)) { ++ Idx new_alloc = 2 * spot->num + 2; ++ re_dfastate_t **new_array = re_realloc(spot->array, re_dfastate_t * , ++ new_alloc); ++ if ((new_array == NULL)) ++ return REG_ESPACE; ++ spot->array = new_array; ++ spot->alloc = new_alloc; ++ } ++ spot->array[spot->num++] = newstate; ++ return REG_NOERROR; ++} ++ ++static void ++free_state(re_dfastate_t *state) { ++ re_node_set_free(&state->non_eps_nodes); ++ re_node_set_free(&state->inveclosure); ++ if (state->entrance_nodes != &state->nodes) { ++ re_node_set_free(state->entrance_nodes); ++ re_free(state->entrance_nodes); ++ } ++ re_node_set_free(&state->nodes); ++ re_free(state->word_trtable); ++ re_free(state->trtable); ++ re_free(state); ++} ++ ++/* Create the new state which is independent of contexts. ++ Return the new state if succeeded, otherwise return NULL. */ ++ ++static re_dfastate_t * ++ ++create_ci_newstate(const re_dfa_t *dfa, const re_node_set *nodes, ++ re_hashval_t hash) { ++ Idx i; ++ reg_errcode_t err; ++ re_dfastate_t *newstate; ++ ++ newstate = (re_dfastate_t *) calloc(sizeof(re_dfastate_t), 1); ++ if ((newstate == NULL)) ++ return NULL; ++ err = re_node_set_init_copy(&newstate->nodes, nodes); ++ if ((err != REG_NOERROR)) { ++ re_free(newstate); ++ return NULL; ++ } ++ ++ newstate->entrance_nodes = &newstate->nodes; ++ for (i = 0; i < nodes->nelem; i++) { ++ re_token_t *node = dfa->nodes + nodes->elems[i]; ++ re_token_type_t type = node->type; ++ if (type == CHARACTER && !node->constraint) ++ continue; ++ ++ /* If the state has the halt node, the state is a halt state. */ ++ if (type == END_OF_RE) ++ newstate->halt = 1; ++ else if (type == OP_BACK_REF) ++ newstate->has_backref = 1; ++ else if (type == ANCHOR || node->constraint) ++ newstate->has_constraint = 1; ++ } ++ err = register_state(dfa, newstate, hash); ++ if ((err != REG_NOERROR)) { ++ free_state(newstate); ++ newstate = NULL; ++ } ++ return newstate; ++} ++ ++/* Create the new state which is depend on the context CONTEXT. ++ Return the new state if succeeded, otherwise return NULL. */ ++ ++static re_dfastate_t * ++ ++create_cd_newstate(const re_dfa_t *dfa, const re_node_set *nodes, ++ unsigned int context, re_hashval_t hash) { ++ Idx i, nctx_nodes = 0; ++ reg_errcode_t err; ++ re_dfastate_t *newstate; ++ ++ newstate = (re_dfastate_t *) calloc(sizeof(re_dfastate_t), 1); ++ if ((newstate == NULL)) ++ return NULL; ++ err = re_node_set_init_copy(&newstate->nodes, nodes); ++ if ((err != REG_NOERROR)) { ++ re_free(newstate); ++ return NULL; ++ } ++ ++ newstate->context = context; ++ newstate->entrance_nodes = &newstate->nodes; ++ ++ for (i = 0; i < nodes->nelem; i++) { ++ re_token_t *node = dfa->nodes + nodes->elems[i]; ++ re_token_type_t type = node->type; ++ unsigned int constraint = node->constraint; ++ ++ if (type == CHARACTER && !constraint) ++ continue; ++ ++ /* If the state has the halt node, the state is a halt state. */ ++ if (type == END_OF_RE) ++ newstate->halt = 1; ++ else if (type == OP_BACK_REF) ++ newstate->has_backref = 1; ++ ++ if (constraint) { ++ if (newstate->entrance_nodes == &newstate->nodes) { ++ newstate->entrance_nodes = re_malloc(re_node_set, 1); ++ if ((newstate->entrance_nodes == NULL)) { ++ free_state(newstate); ++ return NULL; ++ } ++ if (re_node_set_init_copy(newstate->entrance_nodes, nodes) ++ != REG_NOERROR) ++ return NULL; ++ nctx_nodes = 0; ++ newstate->has_constraint = 1; ++ } ++ ++ if (NOT_SATISFY_PREV_CONSTRAINT(constraint, context)) { ++ re_node_set_remove_at(&newstate->nodes, i - nctx_nodes); ++ ++nctx_nodes; ++ } ++ } ++ } ++ err = register_state(dfa, newstate, hash); ++ if ((err != REG_NOERROR)) { ++ free_state(newstate); ++ newstate = NULL; ++ } ++ return newstate; ++} ++ ++/* Extended regular expression matching and search library. ++ Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ Contributed by Isamu Hasegawa . ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef RE_TRANSLATE_TYPE ++# define __RE_TRANSLATE_TYPE unsigned char * ++# ifdef __USE_GNU ++# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE ++# endif ++#endif ++ ++# define __REPB_PREFIX(name) name ++ ++ ++static reg_errcode_t re_compile_internal(regex_t *preg, const char *pattern, ++ size_t length, reg_syntax_t syntax); ++ ++static void re_compile_fastmap_iter(regex_t *bufp, ++ const re_dfastate_t *init_state, ++ char *fastmap); ++ ++static reg_errcode_t init_dfa(re_dfa_t *dfa, size_t pat_len); ++ ++static void free_workarea_compile(regex_t *preg); ++ ++static reg_errcode_t create_initial_state(re_dfa_t *dfa); ++ ++static reg_errcode_t analyze(regex_t *preg); ++ ++static reg_errcode_t preorder(bin_tree_t *root, ++ reg_errcode_t (fn(void *, bin_tree_t *)), ++ void *extra); ++ ++static reg_errcode_t postorder(bin_tree_t *root, ++ reg_errcode_t (fn(void *, bin_tree_t *)), ++ void *extra); ++ ++static reg_errcode_t optimize_subexps(void *extra, bin_tree_t *node); ++ ++static reg_errcode_t lower_subexps(void *extra, bin_tree_t *node); ++ ++static bin_tree_t *lower_subexp(reg_errcode_t *err, regex_t *preg, ++ bin_tree_t *node); ++ ++static reg_errcode_t calc_first(void *extra, bin_tree_t *node); ++ ++static reg_errcode_t calc_next(void *extra, bin_tree_t *node); ++ ++static reg_errcode_t link_nfa_nodes(void *extra, bin_tree_t *node); ++ ++static Idx duplicate_node(re_dfa_t *dfa, Idx org_idx, unsigned int constraint); ++ ++static Idx search_duplicated_node(const re_dfa_t *dfa, Idx org_node, ++ unsigned int constraint); ++ ++static reg_errcode_t calc_eclosure(re_dfa_t *dfa); ++ ++static reg_errcode_t calc_eclosure_iter(re_node_set *new_set, re_dfa_t *dfa, ++ Idx node, bool root); ++ ++static reg_errcode_t calc_inveclosure(re_dfa_t *dfa); ++ ++static Idx fetch_number(re_string_t *input, re_token_t *token, ++ reg_syntax_t syntax); ++ ++static int peek_token(re_token_t *token, re_string_t *input, ++ reg_syntax_t syntax); ++ ++static bin_tree_t *parse(re_string_t *regexp, regex_t *preg, ++ reg_syntax_t syntax, reg_errcode_t *err); ++ ++static bin_tree_t *parse_reg_exp(re_string_t *regexp, regex_t *preg, ++ re_token_t *token, reg_syntax_t syntax, ++ Idx nest, reg_errcode_t *err); ++ ++static bin_tree_t *parse_branch(re_string_t *regexp, regex_t *preg, ++ re_token_t *token, reg_syntax_t syntax, ++ Idx nest, reg_errcode_t *err); ++ ++static bin_tree_t *parse_expression(re_string_t *regexp, regex_t *preg, ++ re_token_t *token, reg_syntax_t syntax, ++ Idx nest, reg_errcode_t *err); ++ ++static bin_tree_t *parse_sub_exp(re_string_t *regexp, regex_t *preg, ++ re_token_t *token, reg_syntax_t syntax, ++ Idx nest, reg_errcode_t *err); ++ ++static bin_tree_t *parse_dup_op(bin_tree_t *dup_elem, re_string_t *regexp, ++ re_dfa_t *dfa, re_token_t *token, ++ reg_syntax_t syntax, reg_errcode_t *err); ++ ++static bin_tree_t *parse_bracket_exp(re_string_t *regexp, re_dfa_t *dfa, ++ re_token_t *token, reg_syntax_t syntax, ++ reg_errcode_t *err); ++ ++static reg_errcode_t parse_bracket_element(bracket_elem_t *elem, ++ re_string_t *regexp, ++ re_token_t *token, int token_len, ++ re_dfa_t *dfa, ++ reg_syntax_t syntax, ++ bool accept_hyphen); ++ ++static reg_errcode_t parse_bracket_symbol(bracket_elem_t *elem, ++ re_string_t *regexp, ++ re_token_t *token); ++ ++static reg_errcode_t build_equiv_class(bitset_t sbcset, ++ const unsigned char *name); ++ ++static reg_errcode_t build_charclass(RE_TRANSLATE_TYPE trans, ++ bitset_t sbcset, ++ const char *class_name, ++ reg_syntax_t syntax); ++ ++static bin_tree_t *build_charclass_op(re_dfa_t *dfa, ++ RE_TRANSLATE_TYPE trans, ++ const char *class_name, ++ const char *extra, ++ bool non_match, reg_errcode_t *err); ++ ++static bin_tree_t *create_tree(re_dfa_t *dfa, ++ bin_tree_t *left, bin_tree_t *right, ++ re_token_type_t type); ++ ++static bin_tree_t *create_token_tree(re_dfa_t *dfa, ++ bin_tree_t *left, bin_tree_t *right, ++ const re_token_t *token); ++ ++static bin_tree_t *duplicate_tree(const bin_tree_t *src, re_dfa_t *dfa); ++ ++static void free_token(re_token_t *node); ++ ++static reg_errcode_t free_tree(void *extra, bin_tree_t *node); ++ ++static reg_errcode_t mark_opt_subexp(void *extra, bin_tree_t *node); ++ ++/* This table gives an error message for each of the error codes listed ++ in regex.h. Obviously the order here has to be same as there. ++ POSIX doesn't require that we do anything for REG_NOERROR, ++ but why not be nice? */ ++ ++static const char __re_error_msgid[] = ++ { ++#define REG_NOERROR_IDX 0 ++ gettext_noop("Success") /* REG_NOERROR */ ++ "\0" ++#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") ++ gettext_noop ("No match") /* REG_NOMATCH */ ++ "\0" ++#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") ++ gettext_noop ("Invalid regular expression") /* REG_BADPAT */ ++ "\0" ++#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") ++ gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ ++ "\0" ++#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") ++ gettext_noop ("Invalid character class name") /* REG_ECTYPE */ ++ "\0" ++#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") ++ gettext_noop ("Trailing backslash") /* REG_EESCAPE */ ++ "\0" ++#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") ++ gettext_noop ("Invalid back reference") /* REG_ESUBREG */ ++ "\0" ++#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") ++ gettext_noop ("Unmatched [, [^, [:, [., or [=") /* REG_EBRACK */ ++ "\0" ++#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [, [^, [:, [., or [=") ++ gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ ++ "\0" ++#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") ++ gettext_noop ("Unmatched \\{") /* REG_EBRACE */ ++ "\0" ++#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") ++ gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ ++ "\0" ++#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") ++ gettext_noop ("Invalid range end") /* REG_ERANGE */ ++ "\0" ++#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") ++ gettext_noop ("Memory exhausted") /* REG_ESPACE */ ++ "\0" ++#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") ++ gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ ++ "\0" ++#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") ++ gettext_noop ("Premature end of regular expression") /* REG_EEND */ ++ "\0" ++#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") ++ gettext_noop ("Regular expression too big") /* REG_ESIZE */ ++ "\0" ++#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") ++ gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ ++ }; ++ ++static const size_t __re_error_msgid_idx[] = ++ { ++ REG_NOERROR_IDX, ++ REG_NOMATCH_IDX, ++ REG_BADPAT_IDX, ++ REG_ECOLLATE_IDX, ++ REG_ECTYPE_IDX, ++ REG_EESCAPE_IDX, ++ REG_ESUBREG_IDX, ++ REG_EBRACK_IDX, ++ REG_EPAREN_IDX, ++ REG_EBRACE_IDX, ++ REG_BADBR_IDX, ++ REG_ERANGE_IDX, ++ REG_ESPACE_IDX, ++ REG_BADRPT_IDX, ++ REG_EEND_IDX, ++ REG_ESIZE_IDX, ++ REG_ERPAREN_IDX ++ }; ++ ++/* Entry points for GNU code. */ ++ ++/* re_compile_pattern is the GNU regular expression compiler: it ++ compiles PATTERN (of length LENGTH) and puts the result in BUFP. ++ Returns 0 if the pattern was valid, otherwise an error string. ++ ++ Assumes the 'allocated' (and perhaps 'buffer') and 'translate' fields ++ are set in BUFP on entry. */ ++ ++const char * ++re_compile_pattern(const char *pattern, size_t length, ++ struct re_pattern_buffer *bufp) { ++ reg_errcode_t ret; ++ ++ /* And GNU code determines whether or not to get register information ++ by passing null for the REGS argument to re_match, etc., not by ++ setting no_sub, unless RE_NO_SUB is set. */ ++ bufp->no_sub = !!(re_syntax_options & RE_NO_SUB); ++ ++ /* Match anchors at newline. */ ++ bufp->newline_anchor = 1; ++ ++ ret = re_compile_internal(bufp, pattern, length, re_syntax_options); ++ ++ if (!ret) ++ return NULL; ++ return gettext(__re_error_msgid + __re_error_msgid_idx[(int) ret]); ++} ++ ++ ++/* Set by 're_set_syntax' to the current regexp syntax to recognize. Can ++ also be assigned to arbitrarily: each pattern buffer stores its own ++ syntax, so it can be changed between regex compilations. */ ++/* This has no initializer because initialized variables in Emacs ++ become read-only after dumping. */ ++reg_syntax_t re_syntax_options; ++ ++ ++/* Specify the precise syntax of regexps for compilation. This provides ++ for compatibility for various utilities which historically have ++ different, incompatible syntaxes. ++ ++ The argument SYNTAX is a bit mask comprised of the various bits ++ defined in regex.h. We return the old syntax. */ ++ ++reg_syntax_t ++re_set_syntax(reg_syntax_t syntax) { ++ reg_syntax_t ret = re_syntax_options; ++ ++ re_syntax_options = syntax; ++ return ret; ++} ++ ++int ++re_compile_fastmap(struct re_pattern_buffer *bufp) { ++ re_dfa_t *dfa = bufp->buffer; ++ char *fastmap = bufp->fastmap; ++ ++ memset(fastmap, '\0', sizeof(char) * SBC_MAX); ++ re_compile_fastmap_iter(bufp, dfa->init_state, fastmap); ++ if (dfa->init_state != dfa->init_state_word) ++ re_compile_fastmap_iter(bufp, dfa->init_state_word, fastmap); ++ if (dfa->init_state != dfa->init_state_nl) ++ re_compile_fastmap_iter(bufp, dfa->init_state_nl, fastmap); ++ if (dfa->init_state != dfa->init_state_begbuf) ++ re_compile_fastmap_iter(bufp, dfa->init_state_begbuf, fastmap); ++ bufp->fastmap_accurate = 1; ++ return 0; ++} ++ ++ ++static inline void ++__attribute__ ((always_inline)) ++re_set_fastmap(char *fastmap, bool icase, int ch) { ++ fastmap[ch] = 1; ++ if (icase) ++ fastmap[tolower(ch)] = 1; ++} ++ ++/* Helper function for re_compile_fastmap. ++ Compile fastmap for the initial_state INIT_STATE. */ ++ ++static void ++re_compile_fastmap_iter(regex_t *bufp, const re_dfastate_t *init_state, ++ char *fastmap) { ++ re_dfa_t *dfa = bufp->buffer; ++ Idx node_cnt; ++ bool icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); ++ for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) { ++ Idx node = init_state->nodes.elems[node_cnt]; ++ re_token_type_t type = dfa->nodes[node].type; ++ ++ if (type == CHARACTER) { ++ re_set_fastmap(fastmap, icase, dfa->nodes[node].opr.c); ++ } else if (type == SIMPLE_BRACKET) { ++ int i, ch; ++ for (i = 0, ch = 0; i < BITSET_WORDS; ++i) { ++ int j; ++ bitset_word_t w = dfa->nodes[node].opr.sbcset[i]; ++ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) ++ if (w & ((bitset_word_t) 1 << j)) ++ re_set_fastmap(fastmap, icase, ch); ++ } ++ } else if (type == OP_PERIOD ++ || type == END_OF_RE) { ++ memset(fastmap, '\1', sizeof(char) * SBC_MAX); ++ if (type == END_OF_RE) ++ bufp->can_be_null = 1; ++ return; ++ } ++ } ++} ++ ++/* Entry point for POSIX code. */ ++/* regcomp takes a regular expression as a string and compiles it. ++ ++ PREG is a regex_t *. We do not expect any fields to be initialized, ++ since POSIX says we shouldn't. Thus, we set ++ ++ 'buffer' to the compiled pattern; ++ 'used' to the length of the compiled pattern; ++ 'syntax' to RE_SYNTAX_POSIX_EXTENDED if the ++ REG_EXTENDED bit in CFLAGS is set; otherwise, to ++ RE_SYNTAX_POSIX_BASIC; ++ 'newline_anchor' to REG_NEWLINE being set in CFLAGS; ++ 'fastmap' to an allocated space for the fastmap; ++ 'fastmap_accurate' to zero; ++ 're_nsub' to the number of subexpressions in PATTERN. ++ ++ PATTERN is the address of the pattern string. ++ ++ CFLAGS is a series of bits which affect compilation. ++ ++ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we ++ use POSIX basic syntax. ++ ++ If REG_NEWLINE is set, then . and [^...] don't match newline. ++ Also, regexec will try a match beginning after every newline. ++ ++ If REG_ICASE is set, then we considers upper- and lowercase ++ versions of letters to be equivalent when matching. ++ ++ If REG_NOSUB is set, then when PREG is passed to regexec, that ++ routine will report only success or failure, and nothing about the ++ registers. ++ ++ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for ++ the return codes and their meanings.) */ ++ ++int ++regcomp(regex_t *_Restrict_ preg, const char *_Restrict_ pattern, int cflags) { ++ reg_errcode_t ret; ++ reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED ++ : RE_SYNTAX_POSIX_BASIC); ++ ++ preg->buffer = NULL; ++ preg->allocated = 0; ++ preg->used = 0; ++ ++ /* Try to allocate space for the fastmap. */ ++ preg->fastmap = re_malloc( ++ char, SBC_MAX); ++ if ((preg->fastmap == NULL)) ++ return REG_ESPACE; ++ ++ syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; ++ ++ /* If REG_NEWLINE is set, newlines are treated differently. */ ++ if (cflags & REG_NEWLINE) { /* REG_NEWLINE implies neither . nor [^...] match newline. */ ++ syntax &= ~RE_DOT_NEWLINE; ++ syntax |= RE_HAT_LISTS_NOT_NEWLINE; ++ /* It also changes the matching behavior. */ ++ preg->newline_anchor = 1; ++ } else ++ preg->newline_anchor = 0; ++ preg->no_sub = !!(cflags & REG_NOSUB); ++ preg->translate = NULL; ++ ++ ret = re_compile_internal(preg, pattern, strlen(pattern), syntax); ++ ++ /* POSIX doesn't distinguish between an unmatched open-group and an ++ unmatched close-group: both are REG_EPAREN. */ ++ if (ret == REG_ERPAREN) ++ ret = REG_EPAREN; ++ ++ /* We have already checked preg->fastmap != NULL. */ ++ if ((ret == REG_NOERROR)) ++ /* Compute the fastmap now, since regexec cannot modify the pattern ++ buffer. This function never fails in this implementation. */ ++ (void) re_compile_fastmap(preg); ++ else { ++ /* Some error occurred while compiling the expression. */ ++ re_free(preg->fastmap); ++ preg->fastmap = NULL; ++ } ++ ++ return (int) ret; ++} ++ ++/* Returns a message corresponding to an error code, ERRCODE, returned ++ from either regcomp or regexec. We don't use PREG here. */ ++ ++size_t ++regerror(int errcode, const regex_t *_Restrict_ preg, char *_Restrict_ errbuf, ++ size_t errbuf_size) { ++ const char *msg; ++ size_t msg_size; ++ int nerrcodes = sizeof __re_error_msgid_idx / sizeof __re_error_msgid_idx[0]; ++ ++ if ((errcode < 0 || errcode >= nerrcodes)) ++ /* Only error codes returned by the rest of the code should be passed ++ to this routine. If we are given anything else, or if other regex ++ code generates an invalid error code, then the program has a bug. ++ Dump core so we can fix it. */ ++ abort(); ++ ++ msg = gettext(__re_error_msgid + __re_error_msgid_idx[errcode]); ++ ++ msg_size = strlen(msg) + 1; /* Includes the null. */ ++ ++ if ((errbuf_size != 0)) { ++ size_t cpy_size = msg_size; ++ if ((msg_size > errbuf_size)) { ++ cpy_size = errbuf_size - 1; ++ errbuf[cpy_size] = '\0'; ++ } ++ memcpy(errbuf, msg, cpy_size); ++ } ++ ++ return msg_size; ++} ++ ++static void ++free_dfa_content(re_dfa_t *dfa) { ++ Idx i, j; ++ ++ if (dfa->nodes) ++ for (i = 0; i < dfa->nodes_len; ++i) ++ free_token(dfa->nodes + i); ++ re_free(dfa->nexts); ++ for (i = 0; i < dfa->nodes_len; ++i) { ++ if (dfa->eclosures != NULL) ++ re_node_set_free(dfa->eclosures + i); ++ if (dfa->inveclosures != NULL) ++ re_node_set_free(dfa->inveclosures + i); ++ if (dfa->edests != NULL) ++ re_node_set_free(dfa->edests + i); ++ } ++ re_free(dfa->edests); ++ re_free(dfa->eclosures); ++ re_free(dfa->inveclosures); ++ re_free(dfa->nodes); ++ ++ if (dfa->state_table) ++ for (i = 0; i <= dfa->state_hash_mask; ++i) { ++ struct re_state_table_entry *entry = dfa->state_table + i; ++ for (j = 0; j < entry->num; ++j) { ++ re_dfastate_t *state = entry->array[j]; ++ free_state(state); ++ } ++ re_free(entry->array); ++ } ++ re_free(dfa->state_table); ++ re_free(dfa->subexp_map); ++ re_free(dfa); ++} ++ ++ ++/* Free dynamically allocated space used by PREG. */ ++ ++void ++regfree(regex_t *preg) { ++ re_dfa_t *dfa = preg->buffer; ++ if ((dfa != NULL)) { ++ lock_fini(dfa->lock); ++ free_dfa_content(dfa); ++ } ++ preg->buffer = NULL; ++ preg->allocated = 0; ++ ++ re_free(preg->fastmap); ++ preg->fastmap = NULL; ++ ++ re_free(preg->translate); ++ preg->translate = NULL; ++} ++ ++/* Internal entry point. ++ Compile the regular expression PATTERN, whose length is LENGTH. ++ SYNTAX indicate regular expression's syntax. */ ++ ++static reg_errcode_t ++re_compile_internal(regex_t *preg, const char *pattern, size_t length, ++ reg_syntax_t syntax) { ++ reg_errcode_t err = REG_NOERROR; ++ re_dfa_t *dfa; ++ re_string_t regexp; ++ ++ /* Initialize the pattern buffer. */ ++ preg->fastmap_accurate = 0; ++ preg->syntax = syntax; ++ preg->not_bol = preg->not_eol = 0; ++ preg->used = 0; ++ preg->re_nsub = 0; ++ preg->can_be_null = 0; ++ preg->regs_allocated = REGS_UNALLOCATED; ++ ++ /* Initialize the dfa. */ ++ dfa = preg->buffer; ++ if ((preg->allocated < sizeof(re_dfa_t))) { ++ /* If zero allocated, but buffer is non-null, try to realloc ++ enough space. This loses if buffer's address is bogus, but ++ that is the user's responsibility. If ->buffer is NULL this ++ is a simple allocation. */ ++ dfa = re_realloc(preg->buffer, re_dfa_t, 1); ++ if (dfa == NULL) ++ return REG_ESPACE; ++ preg->allocated = sizeof(re_dfa_t); ++ preg->buffer = dfa; ++ } ++ preg->used = sizeof(re_dfa_t); ++ ++ err = init_dfa(dfa, length); ++ if ((err == REG_NOERROR && lock_init(dfa->lock) != 0)) ++ err = REG_ESPACE; ++ if ((err != REG_NOERROR)) { ++ free_dfa_content(dfa); ++ preg->buffer = NULL; ++ preg->allocated = 0; ++ return err; ++ } ++ err = re_string_construct(®exp, pattern, length, preg->translate, ++ (syntax & RE_ICASE) != 0, dfa); ++ if ((err != REG_NOERROR)) { ++ re_compile_internal_free_return: ++ free_workarea_compile(preg); ++ re_string_destruct(®exp); ++ lock_fini(dfa->lock); ++ free_dfa_content(dfa); ++ preg->buffer = NULL; ++ preg->allocated = 0; ++ return err; ++ } ++ ++ /* Parse the regular expression, and build a structure tree. */ ++ preg->re_nsub = 0; ++ dfa->str_tree = parse(®exp, preg, syntax, &err); ++ if ((dfa->str_tree == NULL)) ++ goto re_compile_internal_free_return; ++ ++ /* Analyze the tree and create the nfa. */ ++ err = analyze(preg); ++ if ((err != REG_NOERROR)) ++ goto re_compile_internal_free_return; ++ ++ /* Then create the initial state of the dfa. */ ++ err = create_initial_state(dfa); ++ ++ /* Release work areas. */ ++ free_workarea_compile(preg); ++ re_string_destruct(®exp); ++ ++ if ((err != REG_NOERROR)) { ++ lock_fini(dfa->lock); ++ free_dfa_content(dfa); ++ preg->buffer = NULL; ++ preg->allocated = 0; ++ } ++ ++ return err; ++} ++ ++/* Initialize DFA. We use the length of the regular expression PAT_LEN ++ as the initial length of some arrays. */ ++ ++static reg_errcode_t ++init_dfa(re_dfa_t *dfa, size_t pat_len) { ++ __re_size_t table_size; ++ const char *codeset_name; ++ ++ size_t max_i18n_object_size = 0; ++ ++ size_t max_object_size = ++ MAX (sizeof(struct re_state_table_entry), ++ MAX(sizeof(re_token_t), ++ MAX(sizeof(re_node_set), ++ MAX(sizeof(regmatch_t), ++ max_i18n_object_size)))); ++ ++ memset(dfa, '\0', sizeof(re_dfa_t)); ++ ++ /* Force allocation of str_tree_storage the first time. */ ++ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; ++ ++ /* Avoid overflows. The extra "/ 2" is for the table_size doubling ++ calculation below, and for similar doubling calculations ++ elsewhere. And it's <= rather than <, because some of the ++ doubling calculations add 1 afterwards. */ ++ if ((MIN (IDX_MAX, SIZE_MAX / max_object_size) / 2 ++ <= pat_len)) ++ return REG_ESPACE; ++ ++ dfa->nodes_alloc = pat_len + 1; ++ dfa->nodes = re_malloc(re_token_t, dfa->nodes_alloc); ++ ++ /* table_size = 2 ^ ceil(log pat_len) */ ++ for (table_size = 1;; table_size <<= 1) ++ if (table_size > pat_len) ++ break; ++ ++ dfa->state_table = calloc(sizeof(struct re_state_table_entry), table_size); ++ dfa->state_hash_mask = table_size - 1; ++ ++ dfa->mb_cur_max = MB_CUR_MAX; ++ codeset_name = nl_langinfo(CODESET); ++ if ((codeset_name[0] == 'U' || codeset_name[0] == 'u') ++ && (codeset_name[1] == 'T' || codeset_name[1] == 't') ++ && (codeset_name[2] == 'F' || codeset_name[2] == 'f') ++ && strcmp(codeset_name + 3 + (codeset_name[3] == '-'), "8") == 0) ++ dfa->is_utf8 = 1; ++ ++ /* We check exhaustively in the loop below if this charset is a ++ superset of ASCII. */ ++ dfa->map_notascii = 0; ++ ++ if ((dfa->nodes == NULL || dfa->state_table == NULL)) ++ return REG_ESPACE; ++ return REG_NOERROR; ++} ++ ++/* Initialize WORD_CHAR table, which indicate which character is ++ "word". In this case "word" means that it is the word construction ++ character used by some operators like "\<", "\>", etc. */ ++ ++static void ++init_word_char(re_dfa_t *dfa) { ++ int i = 0; ++ int j; ++ int ch = 0; ++ dfa->word_ops_used = 1; ++ if ((dfa->map_notascii == 0)) { ++ /* Avoid uint32_t and uint64_t as some non-GCC platforms lack ++ them, an issue when this code is used in Gnulib. */ ++ bitset_word_t bits0 = 0x00000000; ++ bitset_word_t bits1 = 0x03ff0000; ++ bitset_word_t bits2 = 0x87fffffe; ++ bitset_word_t bits3 = 0x07fffffe; ++ if (BITSET_WORD_BITS == 64) { ++ /* Pacify gcc -Woverflow on 32-bit platformns. */ ++ dfa->word_char[0] = bits1 << 31 << 1 | bits0; ++ dfa->word_char[1] = bits3 << 31 << 1 | bits2; ++ i = 2; ++ } else if (BITSET_WORD_BITS == 32) { ++ dfa->word_char[0] = bits0; ++ dfa->word_char[1] = bits1; ++ dfa->word_char[2] = bits2; ++ dfa->word_char[3] = bits3; ++ i = 4; ++ } else ++ goto general_case; ++ ch = 128; ++ ++ if ((dfa->is_utf8)) { ++ memset(&dfa->word_char[i], '\0', (SBC_MAX - ch) / 8); ++ return; ++ } ++ } ++ ++ general_case: ++ for (; i < BITSET_WORDS; ++i) ++ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) ++ if (isalnum(ch) || ch == '_') ++ dfa->word_char[i] |= (bitset_word_t) 1 << j; ++} ++ ++/* Free the work area which are only used while compiling. */ ++ ++static void ++free_workarea_compile(regex_t *preg) { ++ re_dfa_t *dfa = preg->buffer; ++ bin_tree_storage_t *storage, *next; ++ for (storage = dfa->str_tree_storage; storage; storage = next) { ++ next = storage->next; ++ re_free(storage); ++ } ++ dfa->str_tree_storage = NULL; ++ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; ++ dfa->str_tree = NULL; ++ re_free(dfa->org_indices); ++ dfa->org_indices = NULL; ++} ++ ++/* Create initial states for all contexts. */ ++ ++static reg_errcode_t ++create_initial_state(re_dfa_t *dfa) { ++ Idx first, i; ++ reg_errcode_t err; ++ re_node_set init_nodes; ++ ++ /* Initial states have the epsilon closure of the node which is ++ the first node of the regular expression. */ ++ first = dfa->str_tree->first->node_idx; ++ dfa->init_node = first; ++ err = re_node_set_init_copy(&init_nodes, dfa->eclosures + first); ++ if ((err != REG_NOERROR)) ++ return err; ++ ++ /* The back-references which are in initial states can epsilon transit, ++ since in this case all of the subexpressions can be null. ++ Then we add epsilon closures of the nodes which are the next nodes of ++ the back-references. */ ++ if (dfa->nbackref > 0) ++ for (i = 0; i < init_nodes.nelem; ++i) { ++ Idx node_idx = init_nodes.elems[i]; ++ re_token_type_t type = dfa->nodes[node_idx].type; ++ ++ Idx clexp_idx; ++ if (type != OP_BACK_REF) ++ continue; ++ for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) { ++ re_token_t *clexp_node; ++ clexp_node = dfa->nodes + init_nodes.elems[clexp_idx]; ++ if (clexp_node->type == OP_CLOSE_SUBEXP ++ && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx) ++ break; ++ } ++ if (clexp_idx == init_nodes.nelem) ++ continue; ++ ++ if (type == OP_BACK_REF) { ++ Idx dest_idx = dfa->edests[node_idx].elems[0]; ++ if (!re_node_set_contains(&init_nodes, dest_idx)) { ++ reg_errcode_t merge_err ++ = re_node_set_merge(&init_nodes, dfa->eclosures + dest_idx); ++ if (merge_err != REG_NOERROR) ++ return merge_err; ++ i = 0; ++ } ++ } ++ } ++ ++ /* It must be the first time to invoke acquire_state. */ ++ dfa->init_state = re_acquire_state_context(&err, dfa, &init_nodes, 0); ++ /* We don't check ERR here, since the initial state must not be NULL. */ ++ if ((dfa->init_state == NULL)) ++ return err; ++ if (dfa->init_state->has_constraint) { ++ dfa->init_state_word = re_acquire_state_context(&err, dfa, &init_nodes, ++ CONTEXT_WORD); ++ dfa->init_state_nl = re_acquire_state_context(&err, dfa, &init_nodes, ++ CONTEXT_NEWLINE); ++ dfa->init_state_begbuf = re_acquire_state_context(&err, dfa, ++ &init_nodes, ++ CONTEXT_NEWLINE ++ | CONTEXT_BEGBUF); ++ if ((dfa->init_state_word == NULL ++ || dfa->init_state_nl == NULL ++ || dfa->init_state_begbuf == NULL)) ++ return err; ++ } else ++ dfa->init_state_word = dfa->init_state_nl ++ = dfa->init_state_begbuf = dfa->init_state; ++ ++ re_node_set_free(&init_nodes); ++ return REG_NOERROR; ++} ++ ++ ++/* Analyze the structure tree, and calculate "first", "next", "edest", ++ "eclosure", and "inveclosure". */ ++ ++static reg_errcode_t ++analyze(regex_t *preg) { ++ re_dfa_t *dfa = preg->buffer; ++ reg_errcode_t ret; ++ ++ /* Allocate arrays. */ ++ dfa->nexts = re_malloc(Idx, dfa->nodes_alloc); ++ dfa->org_indices = re_malloc(Idx, dfa->nodes_alloc); ++ dfa->edests = re_malloc(re_node_set, dfa->nodes_alloc); ++ dfa->eclosures = re_malloc(re_node_set, dfa->nodes_alloc); ++ if ((dfa->nexts == NULL || dfa->org_indices == NULL ++ || dfa->edests == NULL || dfa->eclosures == NULL)) ++ return REG_ESPACE; ++ ++ dfa->subexp_map = re_malloc(Idx, preg->re_nsub); ++ if (dfa->subexp_map != NULL) { ++ Idx i; ++ for (i = 0; i < preg->re_nsub; i++) ++ dfa->subexp_map[i] = i; ++ preorder(dfa->str_tree, optimize_subexps, dfa); ++ for (i = 0; i < preg->re_nsub; i++) ++ if (dfa->subexp_map[i] != i) ++ break; ++ if (i == preg->re_nsub) { ++ re_free(dfa->subexp_map); ++ dfa->subexp_map = NULL; ++ } ++ } ++ ++ ret = postorder(dfa->str_tree, lower_subexps, preg); ++ if ((ret != REG_NOERROR)) ++ return ret; ++ ret = postorder(dfa->str_tree, calc_first, dfa); ++ if ((ret != REG_NOERROR)) ++ return ret; ++ preorder(dfa->str_tree, calc_next, dfa); ++ ret = preorder(dfa->str_tree, link_nfa_nodes, dfa); ++ if ((ret != REG_NOERROR)) ++ return ret; ++ ret = calc_eclosure(dfa); ++ if ((ret != REG_NOERROR)) ++ return ret; ++ ++ /* We only need this during the prune_impossible_nodes pass in regexec.c; ++ skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */ ++ if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match) ++ || dfa->nbackref) { ++ dfa->inveclosures = re_malloc(re_node_set, dfa->nodes_len); ++ if ((dfa->inveclosures == NULL)) ++ return REG_ESPACE; ++ ret = calc_inveclosure(dfa); ++ } ++ ++ return ret; ++} ++ ++/* Our parse trees are very unbalanced, so we cannot use a stack to ++ implement parse tree visits. Instead, we use parent pointers and ++ some hairy code in these two functions. */ ++static reg_errcode_t ++postorder(bin_tree_t *root, reg_errcode_t (fn(void *, bin_tree_t *)), ++ void *extra) { ++ bin_tree_t *node, *prev; ++ ++ for (node = root;;) { ++ /* Descend down the tree, preferably to the left (or to the right ++ if that's the only child). */ ++ while (node->left || node->right) ++ if (node->left) ++ node = node->left; ++ else ++ node = node->right; ++ ++ do { ++ reg_errcode_t err = fn(extra, node); ++ if ((err != REG_NOERROR)) ++ return err; ++ if (node->parent == NULL) ++ return REG_NOERROR; ++ prev = node; ++ node = node->parent; ++ } ++ /* Go up while we have a node that is reached from the right. */ ++ while (node->right == prev || node->right == NULL); ++ node = node->right; ++ } ++} ++ ++static reg_errcode_t ++preorder(bin_tree_t *root, reg_errcode_t (fn(void *, bin_tree_t *)), ++ void *extra) { ++ bin_tree_t *node; ++ ++ for (node = root;;) { ++ reg_errcode_t err = fn(extra, node); ++ if ((err != REG_NOERROR)) ++ return err; ++ ++ /* Go to the left node, or up and to the right. */ ++ if (node->left) ++ node = node->left; ++ else { ++ bin_tree_t *prev = NULL; ++ while (node->right == prev || node->right == NULL) { ++ prev = node; ++ node = node->parent; ++ if (!node) ++ return REG_NOERROR; ++ } ++ node = node->right; ++ } ++ } ++} ++ ++/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell ++ re_search_internal to map the inner one's opr.idx to this one's. Adjust ++ backreferences as well. Requires a preorder visit. */ ++static reg_errcode_t ++optimize_subexps(void *extra, bin_tree_t *node) { ++ re_dfa_t *dfa = (re_dfa_t *) extra; ++ ++ if (node->token.type == OP_BACK_REF && dfa->subexp_map) { ++ int idx = node->token.opr.idx; ++ node->token.opr.idx = dfa->subexp_map[idx]; ++ dfa->used_bkref_map |= 1 << node->token.opr.idx; ++ } else if (node->token.type == SUBEXP ++ && node->left && node->left->token.type == SUBEXP) { ++ Idx other_idx = node->left->token.opr.idx; ++ ++ node->left = node->left->left; ++ if (node->left) ++ node->left->parent = node; ++ ++ dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx]; ++ if (other_idx < BITSET_WORD_BITS) ++ dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx); ++ } ++ ++ return REG_NOERROR; ++} ++ ++/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation ++ of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */ ++static reg_errcode_t ++lower_subexps(void *extra, bin_tree_t *node) { ++ regex_t *preg = (regex_t *) extra; ++ reg_errcode_t err = REG_NOERROR; ++ ++ if (node->left && node->left->token.type == SUBEXP) { ++ node->left = lower_subexp(&err, preg, node->left); ++ if (node->left) ++ node->left->parent = node; ++ } ++ if (node->right && node->right->token.type == SUBEXP) { ++ node->right = lower_subexp(&err, preg, node->right); ++ if (node->right) ++ node->right->parent = node; ++ } ++ ++ return err; ++} ++ ++static bin_tree_t * ++lower_subexp(reg_errcode_t *err, regex_t *preg, bin_tree_t *node) { ++ re_dfa_t *dfa = preg->buffer; ++ bin_tree_t *body = node->left; ++ bin_tree_t *op, *cls, *tree1, *tree; ++ ++ if (preg->no_sub ++ /* We do not optimize empty subexpressions, because otherwise we may ++ have bad CONCAT nodes with NULL children. This is obviously not ++ very common, so we do not lose much. An example that triggers ++ this case is the sed "script" /\(\)/x. */ ++ && node->left != NULL ++ && (node->token.opr.idx >= BITSET_WORD_BITS ++ || !(dfa->used_bkref_map ++ & ((bitset_word_t) 1 << node->token.opr.idx)))) ++ return node->left; ++ ++ /* Convert the SUBEXP node to the concatenation of an ++ OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */ ++ op = create_tree(dfa, NULL, NULL, OP_OPEN_SUBEXP); ++ cls = create_tree(dfa, NULL, NULL, OP_CLOSE_SUBEXP); ++ tree1 = body ? create_tree(dfa, body, cls, CONCAT) : cls; ++ tree = create_tree(dfa, op, tree1, CONCAT); ++ if ((tree == NULL || tree1 == NULL ++ || op == NULL || cls == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ ++ op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx; ++ op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp; ++ return tree; ++} ++ ++/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton ++ nodes. Requires a postorder visit. */ ++static reg_errcode_t ++calc_first(void *extra, bin_tree_t *node) { ++ re_dfa_t *dfa = (re_dfa_t *) extra; ++ if (node->token.type == CONCAT) { ++ node->first = node->left->first; ++ node->node_idx = node->left->node_idx; ++ } else { ++ node->first = node; ++ node->node_idx = re_dfa_add_node(dfa, node->token); ++ if ((node->node_idx == -1)) ++ return REG_ESPACE; ++ if (node->token.type == ANCHOR) ++ dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type; ++ } ++ return REG_NOERROR; ++} ++ ++/* Pass 2: compute NEXT on the tree. Preorder visit. */ ++static reg_errcode_t ++calc_next(void *extra, bin_tree_t *node) { ++ switch (node->token.type) { ++ case OP_DUP_ASTERISK: ++ node->left->next = node; ++ break; ++ case CONCAT: ++ node->left->next = node->right->first; ++ node->right->next = node->next; ++ break; ++ default: ++ if (node->left) ++ node->left->next = node->next; ++ if (node->right) ++ node->right->next = node->next; ++ break; ++ } ++ return REG_NOERROR; ++} ++ ++/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */ ++static reg_errcode_t ++link_nfa_nodes(void *extra, bin_tree_t *node) { ++ re_dfa_t *dfa = (re_dfa_t *) extra; ++ Idx idx = node->node_idx; ++ reg_errcode_t err = REG_NOERROR; ++ ++ switch (node->token.type) { ++ case CONCAT: ++ break; ++ ++ case END_OF_RE: ++ assert(node->next == NULL); ++ break; ++ ++ case OP_DUP_ASTERISK: ++ case OP_ALT: { ++ Idx left, right; ++ dfa->has_plural_match = 1; ++ if (node->left != NULL) ++ left = node->left->first->node_idx; ++ else ++ left = node->next->node_idx; ++ if (node->right != NULL) ++ right = node->right->first->node_idx; ++ else ++ right = node->next->node_idx; ++ assert(left > -1); ++ assert(right > -1); ++ err = re_node_set_init_2(dfa->edests + idx, left, right); ++ } ++ break; ++ ++ case ANCHOR: ++ case OP_OPEN_SUBEXP: ++ case OP_CLOSE_SUBEXP: ++ err = re_node_set_init_1(dfa->edests + idx, node->next->node_idx); ++ break; ++ ++ case OP_BACK_REF: ++ dfa->nexts[idx] = node->next->node_idx; ++ if (node->token.type == OP_BACK_REF) ++ err = re_node_set_init_1(dfa->edests + idx, dfa->nexts[idx]); ++ break; ++ ++ default: ++ assert(!IS_EPSILON_NODE(node->token.type)); ++ dfa->nexts[idx] = node->next->node_idx; ++ break; ++ } ++ ++ return err; ++} ++ ++/* Duplicate the epsilon closure of the node ROOT_NODE. ++ Note that duplicated nodes have constraint INIT_CONSTRAINT in addition ++ to their own constraint. */ ++ ++static reg_errcode_t ++duplicate_node_closure(re_dfa_t *dfa, Idx top_org_node, Idx top_clone_node, ++ Idx root_node, unsigned int init_constraint) { ++ Idx org_node, clone_node; ++ bool ok; ++ unsigned int constraint = init_constraint; ++ for (org_node = top_org_node, clone_node = top_clone_node;;) { ++ Idx org_dest, clone_dest; ++ if (dfa->nodes[org_node].type == OP_BACK_REF) { ++ /* If the back reference epsilon-transit, its destination must ++ also have the constraint. Then duplicate the epsilon closure ++ of the destination of the back reference, and store it in ++ edests of the back reference. */ ++ org_dest = dfa->nexts[org_node]; ++ re_node_set_empty(dfa->edests + clone_node); ++ clone_dest = duplicate_node(dfa, org_dest, constraint); ++ if ((clone_dest == -1)) ++ return REG_ESPACE; ++ dfa->nexts[clone_node] = dfa->nexts[org_node]; ++ ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); ++ if ((!ok)) ++ return REG_ESPACE; ++ } else if (dfa->edests[org_node].nelem == 0) { ++ /* In case of the node can't epsilon-transit, don't duplicate the ++ destination and store the original destination as the ++ destination of the node. */ ++ dfa->nexts[clone_node] = dfa->nexts[org_node]; ++ break; ++ } else if (dfa->edests[org_node].nelem == 1) { ++ /* In case of the node can epsilon-transit, and it has only one ++ destination. */ ++ org_dest = dfa->edests[org_node].elems[0]; ++ re_node_set_empty(dfa->edests + clone_node); ++ /* If the node is root_node itself, it means the epsilon closure ++ has a loop. Then tie it to the destination of the root_node. */ ++ if (org_node == root_node && clone_node != org_node) { ++ ok = re_node_set_insert(dfa->edests + clone_node, org_dest); ++ if ((!ok)) ++ return REG_ESPACE; ++ break; ++ } ++ /* In case the node has another constraint, append it. */ ++ constraint |= dfa->nodes[org_node].constraint; ++ clone_dest = duplicate_node(dfa, org_dest, constraint); ++ if ((clone_dest == -1)) ++ return REG_ESPACE; ++ ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); ++ if ((!ok)) ++ return REG_ESPACE; ++ } else /* dfa->edests[org_node].nelem == 2 */ ++ { ++ /* In case of the node can epsilon-transit, and it has two ++ destinations. In the bin_tree_t and DFA, that's '|' and '*'. */ ++ org_dest = dfa->edests[org_node].elems[0]; ++ re_node_set_empty(dfa->edests + clone_node); ++ /* Search for a duplicated node which satisfies the constraint. */ ++ clone_dest = search_duplicated_node(dfa, org_dest, constraint); ++ if (clone_dest == -1) { ++ /* There is no such duplicated node, create a new one. */ ++ reg_errcode_t err; ++ clone_dest = duplicate_node(dfa, org_dest, constraint); ++ if ((clone_dest == -1)) ++ return REG_ESPACE; ++ ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); ++ if ((!ok)) ++ return REG_ESPACE; ++ err = duplicate_node_closure(dfa, org_dest, clone_dest, ++ root_node, constraint); ++ if ((err != REG_NOERROR)) ++ return err; ++ } else { ++ /* There is a duplicated node which satisfies the constraint, ++ use it to avoid infinite loop. */ ++ ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); ++ if ((!ok)) ++ return REG_ESPACE; ++ } ++ ++ org_dest = dfa->edests[org_node].elems[1]; ++ clone_dest = duplicate_node(dfa, org_dest, constraint); ++ if ((clone_dest == -1)) ++ return REG_ESPACE; ++ ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); ++ if ((!ok)) ++ return REG_ESPACE; ++ } ++ org_node = org_dest; ++ clone_node = clone_dest; ++ } ++ return REG_NOERROR; ++} ++ ++/* Search for a node which is duplicated from the node ORG_NODE, and ++ satisfies the constraint CONSTRAINT. */ ++ ++static Idx ++search_duplicated_node(const re_dfa_t *dfa, Idx org_node, ++ unsigned int constraint) { ++ Idx idx; ++ for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) { ++ if (org_node == dfa->org_indices[idx] ++ && constraint == dfa->nodes[idx].constraint) ++ return idx; /* Found. */ ++ } ++ return -1; /* Not found. */ ++} ++ ++/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. ++ Return the index of the new node, or -1 if insufficient storage is ++ available. */ ++ ++static Idx ++duplicate_node(re_dfa_t *dfa, Idx org_idx, unsigned int constraint) { ++ Idx dup_idx = re_dfa_add_node(dfa, dfa->nodes[org_idx]); ++ if ((dup_idx != -1)) { ++ dfa->nodes[dup_idx].constraint = constraint; ++ dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint; ++ dfa->nodes[dup_idx].duplicated = 1; ++ ++ /* Store the index of the original node. */ ++ dfa->org_indices[dup_idx] = org_idx; ++ } ++ return dup_idx; ++} ++ ++static reg_errcode_t ++calc_inveclosure(re_dfa_t *dfa) { ++ Idx src, idx; ++ bool ok; ++ for (idx = 0; idx < dfa->nodes_len; ++idx) ++ re_node_set_init_empty(dfa->inveclosures + idx); ++ ++ for (src = 0; src < dfa->nodes_len; ++src) { ++ Idx *elems = dfa->eclosures[src].elems; ++ for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) { ++ ok = re_node_set_insert_last(dfa->inveclosures + elems[idx], src); ++ if ((!ok)) ++ return REG_ESPACE; ++ } ++ } ++ ++ return REG_NOERROR; ++} ++ ++/* Calculate "eclosure" for all the node in DFA. */ ++ ++static reg_errcode_t ++calc_eclosure(re_dfa_t *dfa) { ++ Idx node_idx; ++ bool incomplete; ++ incomplete = false; ++ /* For each nodes, calculate epsilon closure. */ ++ for (node_idx = 0;; ++node_idx) { ++ reg_errcode_t err; ++ re_node_set eclosure_elem; ++ if (node_idx == dfa->nodes_len) { ++ if (!incomplete) ++ break; ++ incomplete = false; ++ node_idx = 0; ++ } ++ ++ /* If we have already calculated, skip it. */ ++ if (dfa->eclosures[node_idx].nelem != 0) ++ continue; ++ /* Calculate epsilon closure of 'node_idx'. */ ++ err = calc_eclosure_iter(&eclosure_elem, dfa, node_idx, true); ++ if ((err != REG_NOERROR)) ++ return err; ++ ++ if (dfa->eclosures[node_idx].nelem == 0) { ++ incomplete = true; ++ re_node_set_free(&eclosure_elem); ++ } ++ } ++ return REG_NOERROR; ++} ++ ++/* Calculate epsilon closure of NODE. */ ++ ++static reg_errcode_t ++calc_eclosure_iter(re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root) { ++ reg_errcode_t err; ++ Idx i; ++ re_node_set eclosure; ++ bool ok; ++ bool incomplete = false; ++ err = re_node_set_alloc(&eclosure, dfa->edests[node].nelem + 1); ++ if ((err != REG_NOERROR)) ++ return err; ++ ++ /* This indicates that we are calculating this node now. ++ We reference this value to avoid infinite loop. */ ++ dfa->eclosures[node].nelem = -1; ++ ++ /* If the current node has constraints, duplicate all nodes ++ since they must inherit the constraints. */ ++ if (dfa->nodes[node].constraint ++ && dfa->edests[node].nelem ++ && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) { ++ err = duplicate_node_closure(dfa, node, node, node, ++ dfa->nodes[node].constraint); ++ if ((err != REG_NOERROR)) ++ return err; ++ } ++ ++ /* Expand each epsilon destination nodes. */ ++ if (IS_EPSILON_NODE(dfa->nodes[node].type)) ++ for (i = 0; i < dfa->edests[node].nelem; ++i) { ++ re_node_set eclosure_elem; ++ Idx edest = dfa->edests[node].elems[i]; ++ /* If calculating the epsilon closure of 'edest' is in progress, ++ return intermediate result. */ ++ if (dfa->eclosures[edest].nelem == -1) { ++ incomplete = true; ++ continue; ++ } ++ /* If we haven't calculated the epsilon closure of 'edest' yet, ++ calculate now. Otherwise use calculated epsilon closure. */ ++ if (dfa->eclosures[edest].nelem == 0) { ++ err = calc_eclosure_iter(&eclosure_elem, dfa, edest, false); ++ if ((err != REG_NOERROR)) ++ return err; ++ } else ++ eclosure_elem = dfa->eclosures[edest]; ++ /* Merge the epsilon closure of 'edest'. */ ++ err = re_node_set_merge(&eclosure, &eclosure_elem); ++ if ((err != REG_NOERROR)) ++ return err; ++ /* If the epsilon closure of 'edest' is incomplete, ++ the epsilon closure of this node is also incomplete. */ ++ if (dfa->eclosures[edest].nelem == 0) { ++ incomplete = true; ++ re_node_set_free(&eclosure_elem); ++ } ++ } ++ ++ /* An epsilon closure includes itself. */ ++ ok = re_node_set_insert(&eclosure, node); ++ if ((!ok)) ++ return REG_ESPACE; ++ if (incomplete && !root) ++ dfa->eclosures[node].nelem = 0; ++ else ++ dfa->eclosures[node] = eclosure; ++ *new_set = eclosure; ++ return REG_NOERROR; ++} ++ ++/* Functions for token which are used in the parser. */ ++ ++/* Fetch a token from INPUT. ++ We must not use this function inside bracket expressions. */ ++ ++static void ++fetch_token(re_token_t *result, re_string_t *input, reg_syntax_t syntax) { ++ re_string_skip_bytes(input, peek_token(result, input, syntax)); ++} ++ ++/* Peek a token from INPUT, and return the length of the token. ++ We must not use this function inside bracket expressions. */ ++ ++static int ++peek_token(re_token_t *token, re_string_t *input, reg_syntax_t syntax) { ++ unsigned char c; ++ ++ if (re_string_eoi(input)) { ++ token->type = END_OF_RE; ++ return 0; ++ } ++ ++ c = re_string_peek_byte(input, 0); ++ token->opr.c = c; ++ ++ token->word_char = 0; ++ ++ if (c == '\\') { ++ unsigned char c2; ++ if (re_string_cur_idx(input) + 1 >= re_string_length(input)) { ++ token->type = BACK_SLASH; ++ return 1; ++ } ++ ++ c2 = re_string_peek_byte_case(input, 1); ++ token->opr.c = c2; ++ token->type = CHARACTER; ++ ++ token->word_char = IS_WORD_CHAR(c2) != 0; ++ ++ switch (c2) { ++ case '|': ++ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) ++ token->type = OP_ALT; ++ break; ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ case '8': ++ case '9': ++ if (!(syntax & RE_NO_BK_REFS)) { ++ token->type = OP_BACK_REF; ++ token->opr.idx = c2 - '1'; ++ } ++ break; ++ case '<': ++ if (!(syntax & RE_NO_GNU_OPS)) { ++ token->type = ANCHOR; ++ token->opr.ctx_type = WORD_FIRST; ++ } ++ break; ++ case '>': ++ if (!(syntax & RE_NO_GNU_OPS)) { ++ token->type = ANCHOR; ++ token->opr.ctx_type = WORD_LAST; ++ } ++ break; ++ case 'b': ++ if (!(syntax & RE_NO_GNU_OPS)) { ++ token->type = ANCHOR; ++ token->opr.ctx_type = WORD_DELIM; ++ } ++ break; ++ case 'B': ++ if (!(syntax & RE_NO_GNU_OPS)) { ++ token->type = ANCHOR; ++ token->opr.ctx_type = NOT_WORD_DELIM; ++ } ++ break; ++ case 'w': ++ if (!(syntax & RE_NO_GNU_OPS)) ++ token->type = OP_WORD; ++ break; ++ case 'W': ++ if (!(syntax & RE_NO_GNU_OPS)) ++ token->type = OP_NOTWORD; ++ break; ++ case 's': ++ if (!(syntax & RE_NO_GNU_OPS)) ++ token->type = OP_SPACE; ++ break; ++ case 'S': ++ if (!(syntax & RE_NO_GNU_OPS)) ++ token->type = OP_NOTSPACE; ++ break; ++ case '`': ++ if (!(syntax & RE_NO_GNU_OPS)) { ++ token->type = ANCHOR; ++ token->opr.ctx_type = BUF_FIRST; ++ } ++ break; ++ case '\'': ++ if (!(syntax & RE_NO_GNU_OPS)) { ++ token->type = ANCHOR; ++ token->opr.ctx_type = BUF_LAST; ++ } ++ break; ++ case '(': ++ if (!(syntax & RE_NO_BK_PARENS)) ++ token->type = OP_OPEN_SUBEXP; ++ break; ++ case ')': ++ if (!(syntax & RE_NO_BK_PARENS)) ++ token->type = OP_CLOSE_SUBEXP; ++ break; ++ case '+': ++ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) ++ token->type = OP_DUP_PLUS; ++ break; ++ case '?': ++ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) ++ token->type = OP_DUP_QUESTION; ++ break; ++ case '{': ++ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) ++ token->type = OP_OPEN_DUP_NUM; ++ break; ++ case '}': ++ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) ++ token->type = OP_CLOSE_DUP_NUM; ++ break; ++ default: ++ break; ++ } ++ return 2; ++ } ++ ++ token->type = CHARACTER; ++ ++ token->word_char = IS_WORD_CHAR(token->opr.c); ++ ++ switch (c) { ++ case '\n': ++ if (syntax & RE_NEWLINE_ALT) ++ token->type = OP_ALT; ++ break; ++ case '|': ++ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) ++ token->type = OP_ALT; ++ break; ++ case '*': ++ token->type = OP_DUP_ASTERISK; ++ break; ++ case '+': ++ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) ++ token->type = OP_DUP_PLUS; ++ break; ++ case '?': ++ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) ++ token->type = OP_DUP_QUESTION; ++ break; ++ case '{': ++ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) ++ token->type = OP_OPEN_DUP_NUM; ++ break; ++ case '}': ++ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) ++ token->type = OP_CLOSE_DUP_NUM; ++ break; ++ case '(': ++ if (syntax & RE_NO_BK_PARENS) ++ token->type = OP_OPEN_SUBEXP; ++ break; ++ case ')': ++ if (syntax & RE_NO_BK_PARENS) ++ token->type = OP_CLOSE_SUBEXP; ++ break; ++ case '[': ++ token->type = OP_OPEN_BRACKET; ++ break; ++ case '.': ++ token->type = OP_PERIOD; ++ break; ++ case '^': ++ if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) && ++ re_string_cur_idx(input) != 0) { ++ char prev = re_string_peek_byte(input, -1); ++ if (!(syntax & RE_NEWLINE_ALT) || prev != '\n') ++ break; ++ } ++ token->type = ANCHOR; ++ token->opr.ctx_type = LINE_FIRST; ++ break; ++ case '$': ++ if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && ++ re_string_cur_idx(input) + 1 != re_string_length(input)) { ++ re_token_t next; ++ re_string_skip_bytes(input, 1); ++ peek_token(&next, input, syntax); ++ re_string_skip_bytes(input, -1); ++ if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP) ++ break; ++ } ++ token->type = ANCHOR; ++ token->opr.ctx_type = LINE_LAST; ++ break; ++ default: ++ break; ++ } ++ return 1; ++} ++ ++/* Peek a token from INPUT, and return the length of the token. ++ We must not use this function out of bracket expressions. */ ++ ++static int ++peek_token_bracket(re_token_t *token, re_string_t *input, reg_syntax_t syntax) { ++ unsigned char c; ++ if (re_string_eoi(input)) { ++ token->type = END_OF_RE; ++ return 0; ++ } ++ c = re_string_peek_byte(input, 0); ++ token->opr.c = c; ++ ++ if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) ++ && re_string_cur_idx(input) + 1 < re_string_length(input)) { ++ /* In this case, '\' escape a character. */ ++ unsigned char c2; ++ re_string_skip_bytes(input, 1); ++ c2 = re_string_peek_byte(input, 0); ++ token->opr.c = c2; ++ token->type = CHARACTER; ++ return 1; ++ } ++ if (c == '[') /* '[' is a special char in a bracket exps. */ ++ { ++ unsigned char c2; ++ int token_len; ++ if (re_string_cur_idx(input) + 1 < re_string_length(input)) ++ c2 = re_string_peek_byte(input, 1); ++ else ++ c2 = 0; ++ token->opr.c = c2; ++ token_len = 2; ++ switch (c2) { ++ case '.': ++ token->type = OP_OPEN_COLL_ELEM; ++ break; ++ ++ case '=': ++ token->type = OP_OPEN_EQUIV_CLASS; ++ break; ++ ++ case ':': ++ if (syntax & RE_CHAR_CLASSES) { ++ token->type = OP_OPEN_CHAR_CLASS; ++ break; ++ } ++ FALLTHROUGH; ++ default: ++ token->type = CHARACTER; ++ token->opr.c = c; ++ token_len = 1; ++ break; ++ } ++ return token_len; ++ } ++ switch (c) { ++ case '-': ++ token->type = OP_CHARSET_RANGE; ++ break; ++ case ']': ++ token->type = OP_CLOSE_BRACKET; ++ break; ++ case '^': ++ token->type = OP_NON_MATCH_LIST; ++ break; ++ default: ++ token->type = CHARACTER; ++ } ++ return 1; ++} ++ ++/* Functions for parser. */ ++ ++/* Entry point of the parser. ++ Parse the regular expression REGEXP and return the structure tree. ++ If an error occurs, ERR is set by error code, and return NULL. ++ This function build the following tree, from regular expression : ++ CAT ++ / \ ++ / \ ++ EOR ++ ++ CAT means concatenation. ++ EOR means end of regular expression. */ ++ ++static bin_tree_t * ++parse(re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, ++ reg_errcode_t *err) { ++ re_dfa_t *dfa = preg->buffer; ++ bin_tree_t *tree, *eor, *root; ++ re_token_t current_token; ++ dfa->syntax = syntax; ++ fetch_token(¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); ++ tree = parse_reg_exp(regexp, preg, ¤t_token, syntax, 0, err); ++ if ((*err != REG_NOERROR && tree == NULL)) ++ return NULL; ++ eor = create_tree(dfa, NULL, NULL, END_OF_RE); ++ if (tree != NULL) ++ root = create_tree(dfa, tree, eor, CONCAT); ++ else ++ root = eor; ++ if ((eor == NULL || root == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ return root; ++} ++ ++/* This function build the following tree, from regular expression ++ |: ++ ALT ++ / \ ++ / \ ++ ++ ++ ALT means alternative, which represents the operator '|'. */ ++ ++static bin_tree_t * ++parse_reg_exp(re_string_t *regexp, regex_t *preg, re_token_t *token, ++ reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { ++ re_dfa_t *dfa = preg->buffer; ++ bin_tree_t *tree, *branch = NULL; ++ bitset_word_t initial_bkref_map = dfa->completed_bkref_map; ++ tree = parse_branch(regexp, preg, token, syntax, nest, err); ++ if ((*err != REG_NOERROR && tree == NULL)) ++ return NULL; ++ ++ while (token->type == OP_ALT) { ++ fetch_token(token, regexp, syntax | RE_CARET_ANCHORS_HERE); ++ if (token->type != OP_ALT && token->type != END_OF_RE ++ && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { ++ bitset_word_t accumulated_bkref_map = dfa->completed_bkref_map; ++ dfa->completed_bkref_map = initial_bkref_map; ++ branch = parse_branch(regexp, preg, token, syntax, nest, err); ++ if ((*err != REG_NOERROR && branch == NULL)) { ++ if (tree != NULL) ++ postorder(tree, free_tree, NULL); ++ return NULL; ++ } ++ dfa->completed_bkref_map |= accumulated_bkref_map; ++ } else ++ branch = NULL; ++ tree = create_tree(dfa, tree, branch, OP_ALT); ++ if ((tree == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ } ++ return tree; ++} ++ ++/* This function build the following tree, from regular expression ++ : ++ CAT ++ / \ ++ / \ ++ ++ ++ CAT means concatenation. */ ++ ++static bin_tree_t * ++parse_branch(re_string_t *regexp, regex_t *preg, re_token_t *token, ++ reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { ++ bin_tree_t *tree, *expr; ++ re_dfa_t *dfa = preg->buffer; ++ tree = parse_expression(regexp, preg, token, syntax, nest, err); ++ if ((*err != REG_NOERROR && tree == NULL)) ++ return NULL; ++ ++ while (token->type != OP_ALT && token->type != END_OF_RE ++ && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { ++ expr = parse_expression(regexp, preg, token, syntax, nest, err); ++ if ((*err != REG_NOERROR && expr == NULL)) { ++ if (tree != NULL) ++ postorder(tree, free_tree, NULL); ++ return NULL; ++ } ++ if (tree != NULL && expr != NULL) { ++ bin_tree_t *newtree = create_tree(dfa, tree, expr, CONCAT); ++ if (newtree == NULL) { ++ postorder(expr, free_tree, NULL); ++ postorder(tree, free_tree, NULL); ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ tree = newtree; ++ } else if (tree == NULL) ++ tree = expr; ++ /* Otherwise expr == NULL, we don't need to create new tree. */ ++ } ++ return tree; ++} ++ ++/* This function build the following tree, from regular expression a*: ++ * ++ | ++ a ++*/ ++ ++static bin_tree_t * ++parse_expression(re_string_t *regexp, regex_t *preg, re_token_t *token, ++ reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { ++ re_dfa_t *dfa = preg->buffer; ++ bin_tree_t *tree; ++ switch (token->type) { ++ case CHARACTER: ++ tree = create_token_tree(dfa, NULL, NULL, token); ++ if ((tree == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ break; ++ ++ case OP_OPEN_SUBEXP: ++ tree = parse_sub_exp(regexp, preg, token, syntax, nest + 1, err); ++ if ((*err != REG_NOERROR && tree == NULL)) ++ return NULL; ++ break; ++ ++ case OP_OPEN_BRACKET: ++ tree = parse_bracket_exp(regexp, dfa, token, syntax, err); ++ if ((*err != REG_NOERROR && tree == NULL)) ++ return NULL; ++ break; ++ ++ case OP_BACK_REF: ++ if (!(dfa->completed_bkref_map & (1 << token->opr.idx))) { ++ *err = REG_ESUBREG; ++ return NULL; ++ } ++ dfa->used_bkref_map |= 1 << token->opr.idx; ++ tree = create_token_tree(dfa, NULL, NULL, token); ++ if ((tree == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ ++dfa->nbackref; ++ dfa->has_mb_node = 1; ++ break; ++ ++ case OP_OPEN_DUP_NUM: ++ if (syntax & RE_CONTEXT_INVALID_DUP) { ++ *err = REG_BADRPT; ++ return NULL; ++ } ++ FALLTHROUGH; ++ case OP_DUP_ASTERISK: ++ case OP_DUP_PLUS: ++ case OP_DUP_QUESTION: ++ if (syntax & RE_CONTEXT_INVALID_OPS) { ++ *err = REG_BADRPT; ++ return NULL; ++ } else if (syntax & RE_CONTEXT_INDEP_OPS) { ++ fetch_token(token, regexp, syntax); ++ return parse_expression(regexp, preg, token, syntax, nest, err); ++ } ++ FALLTHROUGH; ++ case OP_CLOSE_SUBEXP: ++ if ((token->type == OP_CLOSE_SUBEXP) && ++ !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) { ++ *err = REG_ERPAREN; ++ return NULL; ++ } ++ FALLTHROUGH; ++ case OP_CLOSE_DUP_NUM: ++ /* We treat it as a normal character. */ ++ ++ /* Then we can these characters as normal characters. */ ++ token->type = CHARACTER; ++ /* mb_partial and word_char bits should be initialized already ++ by peek_token. */ ++ tree = create_token_tree(dfa, NULL, NULL, token); ++ if ((tree == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ break; ++ ++ case ANCHOR: ++ if ((token->opr.ctx_type ++ & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST)) ++ && dfa->word_ops_used == 0) ++ init_word_char(dfa); ++ if (token->opr.ctx_type == WORD_DELIM ++ || token->opr.ctx_type == NOT_WORD_DELIM) { ++ bin_tree_t *tree_first, *tree_last; ++ if (token->opr.ctx_type == WORD_DELIM) { ++ token->opr.ctx_type = WORD_FIRST; ++ tree_first = create_token_tree(dfa, NULL, NULL, token); ++ token->opr.ctx_type = WORD_LAST; ++ } else { ++ token->opr.ctx_type = INSIDE_WORD; ++ tree_first = create_token_tree(dfa, NULL, NULL, token); ++ token->opr.ctx_type = INSIDE_NOTWORD; ++ } ++ tree_last = create_token_tree(dfa, NULL, NULL, token); ++ tree = create_tree(dfa, tree_first, tree_last, OP_ALT); ++ if ((tree_first == NULL || tree_last == NULL ++ || tree == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ } else { ++ tree = create_token_tree(dfa, NULL, NULL, token); ++ if ((tree == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ } ++ /* We must return here, since ANCHORs can't be followed ++ by repetition operators. ++ eg. RE"^*" is invalid or "", ++ it must not be "". */ ++ fetch_token(token, regexp, syntax); ++ return tree; ++ ++ case OP_PERIOD: ++ tree = create_token_tree(dfa, NULL, NULL, token); ++ if ((tree == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ if (dfa->mb_cur_max > 1) ++ dfa->has_mb_node = 1; ++ break; ++ ++ case OP_WORD: ++ case OP_NOTWORD: ++ tree = build_charclass_op(dfa, regexp->trans, ++ "alnum", ++ "_", ++ token->type == OP_NOTWORD, err); ++ if ((*err != REG_NOERROR && tree == NULL)) ++ return NULL; ++ break; ++ ++ case OP_SPACE: ++ case OP_NOTSPACE: ++ tree = build_charclass_op(dfa, regexp->trans, ++ "space", ++ "", ++ token->type == OP_NOTSPACE, err); ++ if ((*err != REG_NOERROR && tree == NULL)) ++ return NULL; ++ break; ++ ++ case OP_ALT: ++ case END_OF_RE: ++ return NULL; ++ ++ case BACK_SLASH: ++ *err = REG_EESCAPE; ++ return NULL; ++ ++ default: ++ /* Must not happen? */ ++ return NULL; ++ } ++ fetch_token(token, regexp, syntax); ++ ++ while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS ++ || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) { ++ bin_tree_t *dup_tree = parse_dup_op(tree, regexp, dfa, token, ++ syntax, err); ++ if ((*err != REG_NOERROR && dup_tree == NULL)) { ++ if (tree != NULL) ++ postorder(tree, free_tree, NULL); ++ return NULL; ++ } ++ tree = dup_tree; ++ /* In BRE consecutive duplications are not allowed. */ ++ if ((syntax & RE_CONTEXT_INVALID_DUP) ++ && (token->type == OP_DUP_ASTERISK ++ || token->type == OP_OPEN_DUP_NUM)) { ++ if (tree != NULL) ++ postorder(tree, free_tree, NULL); ++ *err = REG_BADRPT; ++ return NULL; ++ } ++ } ++ ++ return tree; ++} ++ ++/* This function build the following tree, from regular expression ++ (): ++ SUBEXP ++ | ++ ++*/ ++ ++static bin_tree_t * ++parse_sub_exp(re_string_t *regexp, regex_t *preg, re_token_t *token, ++ reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { ++ re_dfa_t *dfa = preg->buffer; ++ bin_tree_t *tree; ++ size_t cur_nsub; ++ cur_nsub = preg->re_nsub++; ++ ++ fetch_token(token, regexp, syntax | RE_CARET_ANCHORS_HERE); ++ ++ /* The subexpression may be a null string. */ ++ if (token->type == OP_CLOSE_SUBEXP) ++ tree = NULL; ++ else { ++ tree = parse_reg_exp(regexp, preg, token, syntax, nest, err); ++ if ((*err == REG_NOERROR ++ && token->type != OP_CLOSE_SUBEXP)) { ++ if (tree != NULL) ++ postorder(tree, free_tree, NULL); ++ *err = REG_EPAREN; ++ } ++ if ((*err != REG_NOERROR)) ++ return NULL; ++ } ++ ++ if (cur_nsub <= '9' - '1') ++ dfa->completed_bkref_map |= 1 << cur_nsub; ++ ++ tree = create_tree(dfa, tree, NULL, SUBEXP); ++ if ((tree == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ tree->token.opr.idx = cur_nsub; ++ return tree; ++} ++ ++/* This function parse repetition operators like "*", "+", "{1,3}" etc. */ ++ ++static bin_tree_t * ++parse_dup_op(bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, ++ re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) { ++ bin_tree_t *tree = NULL, *old_tree = NULL; ++ Idx i, start, end, start_idx = re_string_cur_idx(regexp); ++ re_token_t start_token = *token; ++ ++ if (token->type == OP_OPEN_DUP_NUM) { ++ end = 0; ++ start = fetch_number(regexp, token, syntax); ++ if (start == -1) { ++ if (token->type == CHARACTER && token->opr.c == ',') ++ start = 0; /* We treat "{,m}" as "{0,m}". */ ++ else { ++ *err = REG_BADBR; /* {} is invalid. */ ++ return NULL; ++ } ++ } ++ if ((start != -2)) { ++ /* We treat "{n}" as "{n,n}". */ ++ end = ((token->type == OP_CLOSE_DUP_NUM) ? start ++ : ((token->type == CHARACTER && token->opr.c == ',') ++ ? fetch_number(regexp, token, syntax) : -2)); ++ } ++ if ((start == -2 || end == -2)) { ++ /* Invalid sequence. */ ++ if ((!(syntax & RE_INVALID_INTERVAL_ORD))) { ++ if (token->type == END_OF_RE) ++ *err = REG_EBRACE; ++ else ++ *err = REG_BADBR; ++ ++ return NULL; ++ } ++ ++ /* If the syntax bit is set, rollback. */ ++ re_string_set_index(regexp, start_idx); ++ *token = start_token; ++ token->type = CHARACTER; ++ /* mb_partial and word_char bits should be already initialized by ++ peek_token. */ ++ return elem; ++ } ++ ++ if (((end != -1 && start > end) ++ || token->type != OP_CLOSE_DUP_NUM)) { ++ /* First number greater than second. */ ++ *err = REG_BADBR; ++ return NULL; ++ } ++ ++ if ((RE_DUP_MAX < (end == -1 ? start : end))) { ++ *err = REG_ESIZE; ++ return NULL; ++ } ++ } else { ++ start = (token->type == OP_DUP_PLUS) ? 1 : 0; ++ end = (token->type == OP_DUP_QUESTION) ? 1 : -1; ++ } ++ ++ fetch_token(token, regexp, syntax); ++ ++ if ((elem == NULL)) ++ return NULL; ++ if ((start == 0 && end == 0)) { ++ postorder(elem, free_tree, NULL); ++ return NULL; ++ } ++ ++ /* Extract "{n,m}" to "...{0,}". */ ++ if ((start > 0)) { ++ tree = elem; ++ for (i = 2; i <= start; ++i) { ++ elem = duplicate_tree(elem, dfa); ++ tree = create_tree(dfa, tree, elem, CONCAT); ++ if ((elem == NULL || tree == NULL)) ++ goto parse_dup_op_espace; ++ } ++ ++ if (start == end) ++ return tree; ++ ++ /* Duplicate ELEM before it is marked optional. */ ++ elem = duplicate_tree(elem, dfa); ++ if ((elem == NULL)) ++ goto parse_dup_op_espace; ++ old_tree = tree; ++ } else ++ old_tree = NULL; ++ ++ if (elem->token.type == SUBEXP) { ++ uintptr_t subidx = elem->token.opr.idx; ++ postorder(elem, mark_opt_subexp, (void *) subidx); ++ } ++ ++ tree = create_tree(dfa, elem, NULL, ++ (end == -1 ? OP_DUP_ASTERISK : OP_ALT)); ++ if ((tree == NULL)) ++ goto parse_dup_op_espace; ++ ++ /* This loop is actually executed only when end != -1, ++ to rewrite {0,n} as ((...?)?)?... We have ++ already created the start+1-th copy. */ ++ if (TYPE_SIGNED(Idx) || end != -1) ++ for (i = start + 2; i <= end; ++i) { ++ elem = duplicate_tree(elem, dfa); ++ tree = create_tree(dfa, tree, elem, CONCAT); ++ if ((elem == NULL || tree == NULL)) ++ goto parse_dup_op_espace; ++ ++ tree = create_tree(dfa, tree, NULL, OP_ALT); ++ if ((tree == NULL)) ++ goto parse_dup_op_espace; ++ } ++ ++ if (old_tree) ++ tree = create_tree(dfa, old_tree, tree, CONCAT); ++ ++ return tree; ++ ++ parse_dup_op_espace: ++ *err = REG_ESPACE; ++ return NULL; ++} ++ ++/* Size of the names for collating symbol/equivalence_class/character_class. ++ I'm not sure, but maybe enough. */ ++#define BRACKET_NAME_BUF_SIZE 32 ++ ++/* Local function for parse_bracket_exp only used in case of NOT _LIBC. ++ Build the range expression which starts from START_ELEM, and ends ++ at END_ELEM. The result are written to MBCSET and SBCSET. ++ RANGE_ALLOC is the allocated size of mbcset->range_starts, and ++ mbcset->range_ends, is a pointer argument since we may ++ update it. */ ++ ++static reg_errcode_t ++build_range_exp(const reg_syntax_t syntax, ++ bitset_t sbcset, ++ const bracket_elem_t *start_elem, ++ const bracket_elem_t *end_elem) { ++ unsigned int start_ch, end_ch; ++ /* Equivalence Classes and Character Classes can't be a range start/end. */ ++ if ((start_elem->type == EQUIV_CLASS ++ || start_elem->type == CHAR_CLASS ++ || end_elem->type == EQUIV_CLASS ++ || end_elem->type == CHAR_CLASS)) ++ return REG_ERANGE; ++ ++ /* We can handle no multi character collating elements without libc ++ support. */ ++ if (((start_elem->type == COLL_SYM ++ && strlen((char *) start_elem->opr.name) > 1) ++ || (end_elem->type == COLL_SYM ++ && strlen((char *) end_elem->opr.name) > 1))) ++ return REG_ECOLLATE; ++ ++ { ++ unsigned int ch; ++ start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch ++ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] ++ : 0)); ++ end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch ++ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] ++ : 0)); ++ if (start_ch > end_ch) ++ return REG_ERANGE; ++ /* Build the table for single byte characters. */ ++ for (ch = 0; ch < SBC_MAX; ++ch) ++ if (start_ch <= ch && ch <= end_ch) ++ bitset_set(sbcset, ch); ++ } ++ return REG_NOERROR; ++} ++ ++/* Helper function for parse_bracket_exp only used in case of NOT _LIBC.. ++ Build the collating element which is represented by NAME. ++ The result are written to MBCSET and SBCSET. ++ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a ++ pointer argument since we may update it. */ ++ ++static reg_errcode_t ++build_collating_symbol(bitset_t sbcset, const unsigned char *name) { ++ size_t name_len = strlen((const char *) name); ++ if ((name_len != 1)) ++ return REG_ECOLLATE; ++ else { ++ bitset_set(sbcset, name[0]); ++ return REG_NOERROR; ++ } ++} ++ ++ ++/* This function parse bracket expression like "[abc]", "[a-c]", ++ "[[.a-a.]]" etc. */ ++ ++static bin_tree_t * ++parse_bracket_exp(re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, ++ reg_syntax_t syntax, reg_errcode_t *err) { ++ re_token_t br_token; ++ re_bitset_ptr_t sbcset; ++ bool non_match = false; ++ bin_tree_t *work_tree; ++ int token_len; ++ bool first_round = true; ++ sbcset = (re_bitset_ptr_t) calloc(sizeof(bitset_t), 1); ++ if ((sbcset == NULL)) { ++ re_free(sbcset); ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ ++ token_len = peek_token_bracket(token, regexp, syntax); ++ if ((token->type == END_OF_RE)) { ++ *err = REG_BADPAT; ++ goto parse_bracket_exp_free_return; ++ } ++ if (token->type == OP_NON_MATCH_LIST) { ++ non_match = true; ++ if (syntax & RE_HAT_LISTS_NOT_NEWLINE) ++ bitset_set(sbcset, '\n'); ++ re_string_skip_bytes(regexp, token_len); /* Skip a token. */ ++ token_len = peek_token_bracket(token, regexp, syntax); ++ if ((token->type == END_OF_RE)) { ++ *err = REG_BADPAT; ++ goto parse_bracket_exp_free_return; ++ } ++ } ++ ++ /* We treat the first ']' as a normal character. */ ++ if (token->type == OP_CLOSE_BRACKET) ++ token->type = CHARACTER; ++ ++ while (1) { ++ bracket_elem_t start_elem, end_elem; ++ unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; ++ unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; ++ reg_errcode_t ret; ++ int token_len2 = 0; ++ bool is_range_exp = false; ++ re_token_t token2; ++ ++ start_elem.opr.name = start_name_buf; ++ start_elem.type = COLL_SYM; ++ ret = parse_bracket_element(&start_elem, regexp, token, token_len, dfa, ++ syntax, first_round); ++ if ((ret != REG_NOERROR)) { ++ *err = ret; ++ goto parse_bracket_exp_free_return; ++ } ++ first_round = false; ++ ++ /* Get information about the next token. We need it in any case. */ ++ token_len = peek_token_bracket(token, regexp, syntax); ++ ++ /* Do not check for ranges if we know they are not allowed. */ ++ if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS) { ++ if ((token->type == END_OF_RE)) { ++ *err = REG_EBRACK; ++ goto parse_bracket_exp_free_return; ++ } ++ if (token->type == OP_CHARSET_RANGE) { ++ re_string_skip_bytes(regexp, token_len); /* Skip '-'. */ ++ token_len2 = peek_token_bracket(&token2, regexp, syntax); ++ if ((token2.type == END_OF_RE)) { ++ *err = REG_EBRACK; ++ goto parse_bracket_exp_free_return; ++ } ++ if (token2.type == OP_CLOSE_BRACKET) { ++ /* We treat the last '-' as a normal character. */ ++ re_string_skip_bytes(regexp, -token_len); ++ token->type = CHARACTER; ++ } else ++ is_range_exp = true; ++ } ++ } ++ ++ if (is_range_exp == true) { ++ end_elem.opr.name = end_name_buf; ++ end_elem.type = COLL_SYM; ++ ret = parse_bracket_element(&end_elem, regexp, &token2, token_len2, ++ dfa, syntax, true); ++ if ((ret != REG_NOERROR)) { ++ *err = ret; ++ goto parse_bracket_exp_free_return; ++ } ++ ++ token_len = peek_token_bracket(token, regexp, syntax); ++ ++ *err = build_range_exp(syntax, sbcset, &start_elem, &end_elem); ++ ++ if ((*err != REG_NOERROR)) ++ goto parse_bracket_exp_free_return; ++ } else { ++ switch (start_elem.type) { ++ case SB_CHAR: ++ bitset_set(sbcset, start_elem.opr.ch); ++ break; ++ case EQUIV_CLASS: ++ *err = build_equiv_class(sbcset, ++ start_elem.opr.name); ++ if ((*err != REG_NOERROR)) ++ goto parse_bracket_exp_free_return; ++ break; ++ case COLL_SYM: ++ *err = build_collating_symbol(sbcset, ++ start_elem.opr.name); ++ if ((*err != REG_NOERROR)) ++ goto parse_bracket_exp_free_return; ++ break; ++ case CHAR_CLASS: ++ *err = build_charclass(regexp->trans, sbcset, ++ (const char *) start_elem.opr.name, ++ syntax); ++ if ((*err != REG_NOERROR)) ++ goto parse_bracket_exp_free_return; ++ break; ++ default: ++ assert(0); ++ break; ++ } ++ } ++ if ((token->type == END_OF_RE)) { ++ *err = REG_EBRACK; ++ goto parse_bracket_exp_free_return; ++ } ++ if (token->type == OP_CLOSE_BRACKET) ++ break; ++ } ++ ++ re_string_skip_bytes(regexp, token_len); /* Skip a token. */ ++ ++ /* If it is non-matching list. */ ++ if (non_match) ++ bitset_not(sbcset); ++ ++ { ++ /* Build a tree for simple bracket. */ ++ br_token.type = SIMPLE_BRACKET; ++ br_token.opr.sbcset = sbcset; ++ work_tree = create_token_tree(dfa, NULL, NULL, &br_token); ++ if ((work_tree == NULL)) ++ goto parse_bracket_exp_espace; ++ } ++ return work_tree; ++ ++ parse_bracket_exp_espace: ++ *err = REG_ESPACE; ++ parse_bracket_exp_free_return: ++ re_free(sbcset); ++ return NULL; ++} ++ ++/* Parse an element in the bracket expression. */ ++ ++static reg_errcode_t ++parse_bracket_element(bracket_elem_t *elem, re_string_t *regexp, ++ re_token_t *token, int token_len, re_dfa_t *dfa, ++ reg_syntax_t syntax, bool accept_hyphen) { ++ re_string_skip_bytes(regexp, token_len); /* Skip a token. */ ++ if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS ++ || token->type == OP_OPEN_EQUIV_CLASS) ++ return parse_bracket_symbol(elem, regexp, token); ++ if ((token->type == OP_CHARSET_RANGE) && !accept_hyphen) { ++ /* A '-' must only appear as anything but a range indicator before ++ the closing bracket. Everything else is an error. */ ++ re_token_t token2; ++ (void) peek_token_bracket(&token2, regexp, syntax); ++ if (token2.type != OP_CLOSE_BRACKET) ++ /* The actual error value is not standardized since this whole ++ case is undefined. But ERANGE makes good sense. */ ++ return REG_ERANGE; ++ } ++ elem->type = SB_CHAR; ++ elem->opr.ch = token->opr.c; ++ return REG_NOERROR; ++} ++ ++/* Parse a bracket symbol in the bracket expression. Bracket symbols are ++ such as [::], [..], and ++ [==]. */ ++ ++static reg_errcode_t ++parse_bracket_symbol(bracket_elem_t *elem, re_string_t *regexp, ++ re_token_t *token) { ++ unsigned char ch, delim = token->opr.c; ++ int i = 0; ++ if (re_string_eoi(regexp)) ++ return REG_EBRACK; ++ for (;; ++i) { ++ if (i >= BRACKET_NAME_BUF_SIZE) ++ return REG_EBRACK; ++ if (token->type == OP_OPEN_CHAR_CLASS) ++ ch = re_string_fetch_byte_case(regexp); ++ else ++ ch = re_string_fetch_byte(regexp); ++ if (re_string_eoi(regexp)) ++ return REG_EBRACK; ++ if (ch == delim && re_string_peek_byte(regexp, 0) == ']') ++ break; ++ elem->opr.name[i] = ch; ++ } ++ re_string_skip_bytes(regexp, 1); ++ elem->opr.name[i] = '\0'; ++ switch (token->type) { ++ case OP_OPEN_COLL_ELEM: ++ elem->type = COLL_SYM; ++ break; ++ case OP_OPEN_EQUIV_CLASS: ++ elem->type = EQUIV_CLASS; ++ break; ++ case OP_OPEN_CHAR_CLASS: ++ elem->type = CHAR_CLASS; ++ break; ++ default: ++ break; ++ } ++ return REG_NOERROR; ++} ++ ++/* Helper function for parse_bracket_exp. ++ Build the equivalence class which is represented by NAME. ++ The result are written to MBCSET and SBCSET. ++ EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes, ++ is a pointer argument since we may update it. */ ++ ++static reg_errcode_t ++build_equiv_class(bitset_t sbcset, const unsigned char *name) { ++ { ++ if ((strlen((const char *) name) != 1)) ++ return REG_ECOLLATE; ++ bitset_set(sbcset, *name); ++ } ++ return REG_NOERROR; ++} ++ ++/* Helper function for parse_bracket_exp. ++ Build the character class which is represented by NAME. ++ The result are written to MBCSET and SBCSET. ++ CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes, ++ is a pointer argument since we may update it. */ ++ ++static reg_errcode_t ++build_charclass(RE_TRANSLATE_TYPE trans, bitset_t sbcset, ++ const char *class_name, reg_syntax_t syntax) { ++ int i; ++ const char *name = class_name; ++ ++ /* In case of REG_ICASE "upper" and "lower" match the both of ++ upper and lower cases. */ ++ if ((syntax & RE_ICASE) ++ && (strcmp(name, "upper") == 0 || strcmp(name, "lower") == 0)) ++ name = "alpha"; ++ ++#define BUILD_CHARCLASS_LOOP(ctype_func) \ ++ do { \ ++ if ( (trans != NULL)) \ ++ { \ ++ for (i = 0; i < SBC_MAX; ++i) \ ++ if (ctype_func (i)) \ ++ bitset_set (sbcset, trans[i]); \ ++ } \ ++ else \ ++ { \ ++ for (i = 0; i < SBC_MAX; ++i) \ ++ if (ctype_func (i)) \ ++ bitset_set (sbcset, i); \ ++ } \ ++ } while (0) ++ ++ if (strcmp(name, "alnum") == 0) ++ BUILD_CHARCLASS_LOOP (isalnum); ++ else if (strcmp(name, "cntrl") == 0) ++ BUILD_CHARCLASS_LOOP (iscntrl); ++ else if (strcmp(name, "lower") == 0) ++ BUILD_CHARCLASS_LOOP (islower); ++ else if (strcmp(name, "space") == 0) ++ BUILD_CHARCLASS_LOOP (isspace); ++ else if (strcmp(name, "alpha") == 0) ++ BUILD_CHARCLASS_LOOP (isalpha); ++ else if (strcmp(name, "digit") == 0) ++ BUILD_CHARCLASS_LOOP (isdigit); ++ else if (strcmp(name, "print") == 0) ++ BUILD_CHARCLASS_LOOP (isprint); ++ else if (strcmp(name, "upper") == 0) ++ BUILD_CHARCLASS_LOOP (isupper); ++ else if (strcmp(name, "blank") == 0) ++ BUILD_CHARCLASS_LOOP (isblank); ++ else if (strcmp(name, "graph") == 0) ++ BUILD_CHARCLASS_LOOP (isgraph); ++ else if (strcmp(name, "punct") == 0) ++ BUILD_CHARCLASS_LOOP (ispunct); ++ else if (strcmp(name, "xdigit") == 0) ++ BUILD_CHARCLASS_LOOP (isxdigit); ++ else ++ return REG_ECTYPE; ++ ++ return REG_NOERROR; ++} ++ ++static bin_tree_t * ++build_charclass_op(re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, ++ const char *class_name, ++ const char *extra, bool non_match, ++ reg_errcode_t *err) { ++ re_bitset_ptr_t sbcset; ++ reg_errcode_t ret; ++ re_token_t br_token; ++ bin_tree_t *tree; ++ ++ sbcset = (re_bitset_ptr_t) calloc(sizeof(bitset_t), 1); ++ if ((sbcset == NULL)) { ++ *err = REG_ESPACE; ++ return NULL; ++ } ++ ++ /* We don't care the syntax in this case. */ ++ ret = build_charclass(trans, sbcset, ++ class_name, 0); ++ ++ if ((ret != REG_NOERROR)) { ++ re_free(sbcset); ++ *err = ret; ++ return NULL; ++ } ++ /* \w match '_' also. */ ++ for (; *extra; extra++) ++ bitset_set(sbcset, *extra); ++ ++ /* If it is non-matching list. */ ++ if (non_match) ++ bitset_not(sbcset); ++ ++ /* Build a tree for simple bracket. */ ++ br_token.type = SIMPLE_BRACKET; ++ br_token.opr.sbcset = sbcset; ++ tree = create_token_tree(dfa, NULL, NULL, &br_token); ++ if ((tree == NULL)) ++ goto build_word_op_espace; ++ ++ return tree; ++ ++ build_word_op_espace: ++ re_free(sbcset); ++ *err = REG_ESPACE; ++ return NULL; ++} ++ ++/* This is intended for the expressions like "a{1,3}". ++ Fetch a number from 'input', and return the number. ++ Return -1 if the number field is empty like "{,1}". ++ Return RE_DUP_MAX + 1 if the number field is too large. ++ Return -2 if an error occurred. */ ++ ++static Idx ++fetch_number(re_string_t *input, re_token_t *token, reg_syntax_t syntax) { ++ Idx num = -1; ++ unsigned char c; ++ while (1) { ++ fetch_token(token, input, syntax); ++ c = token->opr.c; ++ if ((token->type == END_OF_RE)) ++ return -2; ++ if (token->type == OP_CLOSE_DUP_NUM || c == ',') ++ break; ++ num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2) ++ ? -2 ++ : num == -1 ++ ? c - '0' ++ : MIN (RE_DUP_MAX + 1, num * 10 + c - '0')); ++ } ++ return num; ++} ++ ++/* Functions for binary tree operation. */ ++ ++/* Create a tree node. */ ++ ++static bin_tree_t * ++create_tree(re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, ++ re_token_type_t type) { ++ re_token_t t; ++ t.type = type; ++ return create_token_tree(dfa, left, right, &t); ++} ++ ++static bin_tree_t * ++create_token_tree(re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, ++ const re_token_t *token) { ++ bin_tree_t *tree; ++ if ((dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE)) { ++ bin_tree_storage_t *storage = re_malloc(bin_tree_storage_t, 1); ++ ++ if (storage == NULL) ++ return NULL; ++ storage->next = dfa->str_tree_storage; ++ dfa->str_tree_storage = storage; ++ dfa->str_tree_storage_idx = 0; ++ } ++ tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++]; ++ ++ tree->parent = NULL; ++ tree->left = left; ++ tree->right = right; ++ tree->token = *token; ++ tree->token.duplicated = 0; ++ tree->token.opt_subexp = 0; ++ tree->first = NULL; ++ tree->next = NULL; ++ tree->node_idx = -1; ++ ++ if (left != NULL) ++ left->parent = tree; ++ if (right != NULL) ++ right->parent = tree; ++ return tree; ++} ++ ++/* Mark the tree SRC as an optional subexpression. ++ To be called from preorder or postorder. */ ++ ++static reg_errcode_t ++mark_opt_subexp(void *extra, bin_tree_t *node) { ++ Idx idx = (uintptr_t) extra; ++ if (node->token.type == SUBEXP && node->token.opr.idx == idx) ++ node->token.opt_subexp = 1; ++ ++ return REG_NOERROR; ++} ++ ++/* Free the allocated memory inside NODE. */ ++ ++static void ++free_token(re_token_t *node) { ++ if (node->type == SIMPLE_BRACKET && node->duplicated == 0) ++ re_free(node->opr.sbcset); ++} ++ ++/* Worker function for tree walking. Free the allocated memory inside NODE ++ and its children. */ ++ ++static reg_errcode_t ++free_tree(void *extra, bin_tree_t *node) { ++ free_token(&node->token); ++ return REG_NOERROR; ++} ++ ++ ++/* Duplicate the node SRC, and return new node. This is a preorder ++ visit similar to the one implemented by the generic visitor, but ++ we need more infrastructure to maintain two parallel trees --- so, ++ it's easier to duplicate. */ ++ ++static bin_tree_t * ++duplicate_tree(const bin_tree_t *root, re_dfa_t *dfa) { ++ const bin_tree_t *node; ++ bin_tree_t *dup_root; ++ bin_tree_t **p_new = &dup_root, *dup_node = root->parent; ++ ++ for (node = root;;) { ++ /* Create a new tree and link it back to the current parent. */ ++ *p_new = create_token_tree(dfa, NULL, NULL, &node->token); ++ if (*p_new == NULL) ++ return NULL; ++ (*p_new)->parent = dup_node; ++ (*p_new)->token.duplicated = 1; ++ dup_node = *p_new; ++ ++ /* Go to the left node, or up and to the right. */ ++ if (node->left) { ++ node = node->left; ++ p_new = &dup_node->left; ++ } else { ++ const bin_tree_t *prev = NULL; ++ while (node->right == prev || node->right == NULL) { ++ prev = node; ++ node = node->parent; ++ dup_node = dup_node->parent; ++ if (!node) ++ return dup_root; ++ } ++ node = node->right; ++ p_new = &dup_node->right; ++ } ++ } ++} ++ ++static reg_errcode_t ++prune_impossible_nodes(re_match_context_t *mctx) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ Idx halt_node, match_last; ++ reg_errcode_t ret; ++ re_dfastate_t **sifted_states; ++ re_dfastate_t **lim_states = NULL; ++ re_sift_context_t sctx; ++ match_last = mctx->match_last; ++ halt_node = mctx->last_node; ++ ++/* Avoid overflow. */ ++ if ((MIN (IDX_MAX, SIZE_MAX / sizeof(re_dfastate_t * )) ++ <= match_last)) ++ return REG_ESPACE; ++ ++ sifted_states = re_malloc(re_dfastate_t * , match_last + 1); ++ if ((sifted_states == NULL)) { ++ ret = REG_ESPACE; ++ goto free_return; ++ } ++ if (dfa->nbackref) { ++ lim_states = re_malloc(re_dfastate_t * , match_last + 1); ++ if ((lim_states == NULL)) { ++ ret = REG_ESPACE; ++ goto free_return; ++ } ++ while (1) { ++ memset(lim_states, '\0', ++ sizeof(re_dfastate_t * ) * (match_last + 1)); ++ sift_ctx_init(&sctx, sifted_states, lim_states, halt_node, ++ match_last); ++ ret = sift_states_backward(mctx, &sctx); ++ re_node_set_free(&sctx.limits); ++ if ((ret != REG_NOERROR)) ++ goto free_return; ++ if (sifted_states[0] != NULL || lim_states[0] != NULL) ++ break; ++ do { ++ --match_last; ++ if (match_last < 0) { ++ ret = REG_NOMATCH; ++ goto free_return; ++ } ++ } while (mctx->state_log[match_last] == NULL ++ || !mctx->state_log[match_last]->halt); ++ halt_node = check_halt_state_context(mctx, ++ mctx->state_log[match_last], ++ match_last); ++ } ++ ret = merge_state_array(dfa, sifted_states, lim_states, ++ match_last + 1); ++ re_free(lim_states); ++ lim_states = NULL; ++ if ((ret != REG_NOERROR)) ++ goto free_return; ++ } else { ++ sift_ctx_init(&sctx, sifted_states, lim_states, halt_node, match_last); ++ ret = sift_states_backward(mctx, &sctx); ++ re_node_set_free(&sctx.limits); ++ if ((ret != REG_NOERROR)) ++ goto free_return; ++ if (sifted_states[0] == NULL) { ++ ret = REG_NOMATCH; ++ goto free_return; ++ } ++ } ++ re_free(mctx->state_log); ++ mctx->state_log = sifted_states; ++ sifted_states = NULL; ++ mctx->last_node = halt_node; ++ mctx->match_last = match_last; ++ ret = REG_NOERROR; ++ free_return: ++ re_free(sifted_states); ++ re_free(lim_states); ++ return ret; ++} ++ ++/* Acquire an initial state and return it. ++ We must select appropriate initial state depending on the context, ++ since initial states may have constraints like "\<", "^", etc.. */ ++ ++static inline re_dfastate_t * ++acquire_init_state_context(reg_errcode_t *err, const re_match_context_t *mctx, ++ Idx idx) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ if (dfa->init_state->has_constraint) { ++ unsigned int context; ++ context = re_string_context_at(&mctx->input, idx - 1, mctx->eflags); ++ if (IS_WORD_CONTEXT(context)) ++ return dfa->init_state_word; ++ else if (IS_ORDINARY_CONTEXT(context)) ++ return dfa->init_state; ++ else if (IS_BEGBUF_CONTEXT(context) && IS_NEWLINE_CONTEXT(context)) ++ return dfa->init_state_begbuf; ++ else if (IS_NEWLINE_CONTEXT(context)) ++ return dfa->init_state_nl; ++ else if (IS_BEGBUF_CONTEXT(context)) { ++ /* It is relatively rare case, then calculate on demand. */ ++ return re_acquire_state_context(err, dfa, ++ dfa->init_state->entrance_nodes, ++ context); ++ } else ++ /* Must not happen? */ ++ return dfa->init_state; ++ } else ++ return dfa->init_state; ++} ++ ++/* Check whether the node accepts the byte which is IDX-th ++ byte of the INPUT. */ ++ ++static bool ++check_node_accept(const re_match_context_t *mctx, const re_token_t *node, ++ Idx idx) { ++ unsigned char ch; ++ ch = re_string_byte_at(&mctx->input, idx); ++ switch (node->type) { ++ case CHARACTER: ++ if (node->opr.c != ch) ++ return false; ++ break; ++ ++ case SIMPLE_BRACKET: ++ if (!bitset_contain(node->opr.sbcset, ch)) ++ return false; ++ break; ++ ++ case OP_PERIOD: ++ if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE)) ++ || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL))) ++ return false; ++ break; ++ ++ default: ++ return false; ++ } ++ ++ if (node->constraint) { ++ /* The node has constraints. Check whether the current context ++ satisfies the constraints. */ ++ unsigned int context = re_string_context_at(&mctx->input, idx, ++ mctx->eflags); ++ if (NOT_SATISFY_NEXT_CONSTRAINT(node->constraint, context)) ++ return false; ++ } ++ ++ return true; ++} ++ ++ ++/* Extend the buffers, if the buffers have run out. */ ++ ++static reg_errcode_t ++extend_buffers(re_match_context_t ++ *mctx, ++ int min_len ++) { ++ reg_errcode_t ret; ++ re_string_t *pstr = &mctx->input; ++ ++/* Avoid overflow. */ ++ if ( ++ (MIN (IDX_MAX, SIZE_MAX / sizeof(re_dfastate_t * )) / 2 ++ <= pstr->bufs_len)) ++ return ++ REG_ESPACE; ++ ++/* Double the lengths of the buffers, but allocate at least MIN_LEN. */ ++ ret = re_string_realloc_buffers(pstr, ++ MAX (min_len, ++ MIN(pstr->len, pstr->bufs_len * 2))); ++ if ( ++ (ret ++ != REG_NOERROR)) ++ return ++ ret; ++ ++ if (mctx->state_log != NULL) { ++/* And double the length of state_log. */ ++/* XXX We have no indication of the size of this buffer. If this ++allocation fail we have no indication that the state_log array ++does not have the right size. */ ++ re_dfastate_t **new_array = re_realloc(mctx->state_log, re_dfastate_t * , ++ pstr->bufs_len + 1); ++ if ( ++ (new_array ++ == NULL)) ++ return ++ REG_ESPACE; ++ mctx-> ++ state_log = new_array; ++ } ++ ++/* Then reconstruct the buffers. */ ++ if (pstr->icase) { ++ build_upper_buffer(pstr); ++ } else { ++ { ++ if (pstr->trans != NULL) ++ re_string_translate_buffer(pstr); ++ } ++ } ++ return ++ REG_NOERROR; ++} ++ ++/* Functions for state transition. */ ++ ++/* Helper functions for transit_state. */ ++ ++/* Return the first entry with the same str_idx, or -1 if none is ++ found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ ++ ++static Idx ++search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx) ++{ ++ Idx left, right, mid, last; ++ last = right = mctx->nbkref_ents; ++ for (left = 0; left < right;) ++ { ++ mid = (left + right) / 2; ++ if (mctx->bkref_ents[mid].str_idx < str_idx) ++ left = mid + 1; ++ else ++ right = mid; ++ } ++ if (left < last && mctx->bkref_ents[left].str_idx == str_idx) ++ return left; ++ else ++ return -1; ++} ++ ++/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches ++ at STR_IDX. */ ++ ++static reg_errcode_t ++match_ctx_add_subtop(re_match_context_t *mctx, Idx node, Idx str_idx) { ++ if ((mctx->nsub_tops == mctx->asub_tops)) { ++ Idx new_asub_tops = mctx->asub_tops * 2; ++ re_sub_match_top_t **new_array = re_realloc(mctx->sub_tops, ++ re_sub_match_top_t * , ++ new_asub_tops); ++ if ((new_array == NULL)) ++ return REG_ESPACE; ++ mctx->sub_tops = new_array; ++ mctx->asub_tops = new_asub_tops; ++ } ++ mctx->sub_tops[mctx->nsub_tops] = calloc(1, sizeof(re_sub_match_top_t)); ++ if ((mctx->sub_tops[mctx->nsub_tops] == NULL)) ++ return REG_ESPACE; ++ mctx->sub_tops[mctx->nsub_tops]->node = node; ++ mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx; ++ return REG_NOERROR; ++} ++ ++/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches ++ at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ ++ ++static re_sub_match_last_t * ++match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx) ++{ ++ re_sub_match_last_t *new_entry; ++ if ( (subtop->nlasts == subtop->alasts)) ++ { ++ Idx new_alasts = 2 * subtop->alasts + 1; ++ re_sub_match_last_t **new_array = re_realloc (subtop->lasts, ++ re_sub_match_last_t *, ++ new_alasts); ++ if ( (new_array == NULL)) ++ return NULL; ++ subtop->lasts = new_array; ++ subtop->alasts = new_alasts; ++ } ++ new_entry = calloc (1, sizeof (re_sub_match_last_t)); ++ if ( (new_entry != NULL)) ++ { ++ subtop->lasts[subtop->nlasts] = new_entry; ++ new_entry->node = node; ++ new_entry->str_idx = str_idx; ++ ++subtop->nlasts; ++ } ++ return new_entry; ++} ++ ++ ++/* From the node set CUR_NODES, pick up the nodes whose types are ++ OP_OPEN_SUBEXP and which have corresponding back references in the regular ++ expression. And register them to use them later for evaluating the ++ corresponding back references. */ ++ ++static reg_errcode_t ++check_subexp_matching_top(re_match_context_t *mctx, re_node_set *cur_nodes, ++ Idx str_idx) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ Idx node_idx; ++ reg_errcode_t err; ++ ++ /* TODO: This isn't efficient. ++ Because there might be more than one nodes whose types are ++ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all ++ nodes. ++ E.g. RE: (a){2} */ ++ for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx) { ++ Idx node = cur_nodes->elems[node_idx]; ++ if (dfa->nodes[node].type == OP_OPEN_SUBEXP ++ && dfa->nodes[node].opr.idx < BITSET_WORD_BITS ++ && (dfa->used_bkref_map ++ & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx))) { ++ err = match_ctx_add_subtop(mctx, node, str_idx); ++ if ((err != REG_NOERROR)) ++ return err; ++ } ++ } ++ return REG_NOERROR; ++} ++ ++/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA ++ corresponding to the DFA). ++ Return the destination node, and update EPS_VIA_NODES; ++ return -1 in case of errors. */ ++ ++static Idx ++proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, ++ Idx *pidx, Idx node, re_node_set *eps_via_nodes, ++ struct re_fail_stack_t *fs) ++{ ++ const re_dfa_t *const dfa = mctx->dfa; ++ Idx i; ++ bool ok; ++ if (IS_EPSILON_NODE (dfa->nodes[node].type)) ++ { ++ re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; ++ re_node_set *edests = &dfa->edests[node]; ++ Idx dest_node; ++ ok = re_node_set_insert (eps_via_nodes, node); ++ if ( (! ok)) ++ return -2; ++ /* Pick up a valid destination, or return -1 if none ++ is found. */ ++ for (dest_node = -1, i = 0; i < edests->nelem; ++i) ++ { ++ Idx candidate = edests->elems[i]; ++ if (!re_node_set_contains (cur_nodes, candidate)) ++ continue; ++ if (dest_node == -1) ++ dest_node = candidate; ++ ++ else ++ { ++ /* In order to avoid infinite loop like "(a*)*", return the second ++ epsilon-transition if the first was already considered. */ ++ if (re_node_set_contains (eps_via_nodes, dest_node)) ++ return candidate; ++ ++ /* Otherwise, push the second epsilon-transition on the fail stack. */ ++ else if (fs != NULL ++ && push_fail_stack (fs, *pidx, candidate, nregs, regs, ++ eps_via_nodes)) ++ return -2; ++ ++ /* We know we are going to exit. */ ++ break; ++ } ++ } ++ return dest_node; ++ } ++ else ++ { ++ Idx naccepted = 0; ++ re_token_type_t type = dfa->nodes[node].type; ++ ++ if (type == OP_BACK_REF) ++ { ++ Idx subexp_idx = dfa->nodes[node].opr.idx + 1; ++ naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; ++ if (fs != NULL) ++ { ++ if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) ++ return -1; ++ else if (naccepted) ++ { ++ char *buf = (char *) re_string_get_buffer (&mctx->input); ++ if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, ++ naccepted) != 0) ++ return -1; ++ } ++ } ++ ++ if (naccepted == 0) ++ { ++ Idx dest_node; ++ ok = re_node_set_insert (eps_via_nodes, node); ++ if ( (! ok)) ++ return -2; ++ dest_node = dfa->edests[node].elems[0]; ++ if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, ++ dest_node)) ++ return dest_node; ++ } ++ } ++ ++ if (naccepted != 0 ++ || check_node_accept (mctx, dfa->nodes + node, *pidx)) ++ { ++ Idx dest_node = dfa->nexts[node]; ++ *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; ++ if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL ++ || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, ++ dest_node))) ++ return -1; ++ re_node_set_empty (eps_via_nodes); ++ return dest_node; ++ } ++ } ++ return -1; ++} ++ ++static reg_errcode_t ++ ++push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, ++ Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes) ++{ ++ reg_errcode_t err; ++ Idx num = fs->num++; ++ if (fs->num == fs->alloc) ++ { ++ struct re_fail_stack_ent_t *new_array; ++ new_array = re_realloc (fs->stack, struct re_fail_stack_ent_t, ++ fs->alloc * 2); ++ if (new_array == NULL) ++ return REG_ESPACE; ++ fs->alloc *= 2; ++ fs->stack = new_array; ++ } ++ fs->stack[num].idx = str_idx; ++ fs->stack[num].node = dest_node; ++ fs->stack[num].regs = re_malloc (regmatch_t, nregs); ++ if (fs->stack[num].regs == NULL) ++ return REG_ESPACE; ++ memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); ++ err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); ++ return err; ++} ++ ++static Idx ++pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs, ++ regmatch_t *regs, re_node_set *eps_via_nodes) ++{ ++ Idx num = --fs->num; ++ assert (num >= 0); ++ *pidx = fs->stack[num].idx; ++ memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); ++ re_node_set_free (eps_via_nodes); ++ re_free (fs->stack[num].regs); ++ *eps_via_nodes = fs->stack[num].eps_via_nodes; ++ return fs->stack[num].node; ++} ++ ++/* Set the positions where the subexpressions are starts/ends to registers ++ PMATCH. ++ Note: We assume that pmatch[0] is already set, and ++ pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */ ++ ++static reg_errcode_t ++ ++set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, ++ regmatch_t *pmatch, bool fl_backtrack) ++{ ++ const re_dfa_t *dfa = preg->buffer; ++ Idx idx, cur_node; ++ re_node_set eps_via_nodes; ++ struct re_fail_stack_t *fs; ++ struct re_fail_stack_t fs_body = { 0, 2, NULL }; ++ regmatch_t *prev_idx_match; ++ bool prev_idx_match_malloced = false; ++ if (fl_backtrack) ++ { ++ fs = &fs_body; ++ fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); ++ if (fs->stack == NULL) ++ return REG_ESPACE; ++ } ++ else ++ fs = NULL; ++ ++ cur_node = dfa->init_node; ++ re_node_set_init_empty (&eps_via_nodes); ++ ++ if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) ++ prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); ++ else ++ { ++ prev_idx_match = re_malloc (regmatch_t, nmatch); ++ if (prev_idx_match == NULL) ++ { ++ free_fail_stack_return (fs); ++ return REG_ESPACE; ++ } ++ prev_idx_match_malloced = true; ++ } ++ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); ++ ++ for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) ++ { ++ update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); ++ ++ if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) ++ { ++ Idx reg_idx; ++ if (fs) ++ { ++ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) ++ if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) ++ break; ++ if (reg_idx == nmatch) ++ { ++ re_node_set_free (&eps_via_nodes); ++ if (prev_idx_match_malloced) ++ re_free (prev_idx_match); ++ return free_fail_stack_return (fs); ++ } ++ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, ++ &eps_via_nodes); ++ } ++ else ++ { ++ re_node_set_free (&eps_via_nodes); ++ if (prev_idx_match_malloced) ++ re_free (prev_idx_match); ++ return REG_NOERROR; ++ } ++ } ++ ++ /* Proceed to next node. */ ++ cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node, ++ &eps_via_nodes, fs); ++ ++ if ( (cur_node < 0)) ++ { ++ if ( (cur_node == -2)) ++ { ++ re_node_set_free (&eps_via_nodes); ++ if (prev_idx_match_malloced) ++ re_free (prev_idx_match); ++ free_fail_stack_return (fs); ++ return REG_ESPACE; ++ } ++ if (fs) ++ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, ++ &eps_via_nodes); ++ else ++ { ++ re_node_set_free (&eps_via_nodes); ++ if (prev_idx_match_malloced) ++ re_free (prev_idx_match); ++ return REG_NOMATCH; ++ } ++ } ++ } ++ re_node_set_free (&eps_via_nodes); ++ if (prev_idx_match_malloced) ++ re_free (prev_idx_match); ++ return free_fail_stack_return (fs); ++} ++ ++static reg_errcode_t ++free_fail_stack_return (struct re_fail_stack_t *fs) ++{ ++ if (fs) ++ { ++ Idx fs_idx; ++ for (fs_idx = 0; fs_idx < fs->num; ++fs_idx) ++ { ++ re_node_set_free (&fs->stack[fs_idx].eps_via_nodes); ++ re_free (fs->stack[fs_idx].regs); ++ } ++ re_free (fs->stack); ++ } ++ return REG_NOERROR; ++} ++ ++static void ++update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, ++ regmatch_t *prev_idx_match, Idx cur_node, Idx cur_idx, Idx nmatch) ++{ ++ int type = dfa->nodes[cur_node].type; ++ if (type == OP_OPEN_SUBEXP) ++ { ++ Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; ++ ++ /* We are at the first node of this sub expression. */ ++ if (reg_num < nmatch) ++ { ++ pmatch[reg_num].rm_so = cur_idx; ++ pmatch[reg_num].rm_eo = -1; ++ } ++ } ++ else if (type == OP_CLOSE_SUBEXP) ++ { ++ Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; ++ if (reg_num < nmatch) ++ { ++ /* We are at the last node of this sub expression. */ ++ if (pmatch[reg_num].rm_so < cur_idx) ++ { ++ pmatch[reg_num].rm_eo = cur_idx; ++ /* This is a non-empty match or we are not inside an optional ++ subexpression. Accept this right away. */ ++ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); ++ } ++ else ++ { ++ if (dfa->nodes[cur_node].opt_subexp ++ && prev_idx_match[reg_num].rm_so != -1) ++ /* We transited through an empty match for an optional ++ subexpression, like (a?)*, and this is not the subexp's ++ first match. Copy back the old content of the registers ++ so that matches of an inner subexpression are undone as ++ well, like in ((a?))*. */ ++ memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch); ++ else ++ /* We completed a subexpression, but it may be part of ++ an optional one, so do not update PREV_IDX_MATCH. */ ++ pmatch[reg_num].rm_eo = cur_idx; ++ } ++ } ++ } ++} ++ ++/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 ++ and sift the nodes in each states according to the following rules. ++ Updated state_log will be wrote to STATE_LOG. ++ ++ Rules: We throw away the Node 'a' in the STATE_LOG[STR_IDX] if... ++ 1. When STR_IDX == MATCH_LAST(the last index in the state_log): ++ If 'a' isn't the LAST_NODE and 'a' can't epsilon transit to ++ the LAST_NODE, we throw away the node 'a'. ++ 2. When 0 <= STR_IDX < MATCH_LAST and 'a' accepts ++ string 's' and transit to 'b': ++ i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw ++ away the node 'a'. ++ ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is ++ thrown away, we throw away the node 'a'. ++ 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b': ++ i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the ++ node 'a'. ++ ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away, ++ we throw away the node 'a'. */ ++ ++#define STATE_NODE_CONTAINS(state,node) \ ++ ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) ++ ++static reg_errcode_t ++sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) ++{ ++ reg_errcode_t err; ++ int null_cnt = 0; ++ Idx str_idx = sctx->last_str_idx; ++ re_node_set cur_dest; ++ ++ /* Build sifted state_log[str_idx]. It has the nodes which can epsilon ++ transit to the last_node and the last_node itself. */ ++ err = re_node_set_init_1 (&cur_dest, sctx->last_node); ++ if ( (err != REG_NOERROR)) ++ return err; ++ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); ++ if ( (err != REG_NOERROR)) ++ goto free_return; ++ ++ /* Then check each states in the state_log. */ ++ while (str_idx > 0) ++ { ++ /* Update counters. */ ++ null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; ++ if (null_cnt > mctx->max_mb_elem_len) ++ { ++ memset (sctx->sifted_states, '\0', ++ sizeof (re_dfastate_t *) * str_idx); ++ re_node_set_free (&cur_dest); ++ return REG_NOERROR; ++ } ++ re_node_set_empty (&cur_dest); ++ --str_idx; ++ ++ if (mctx->state_log[str_idx]) ++ { ++ err = build_sifted_states (mctx, sctx, str_idx, &cur_dest); ++ if ( (err != REG_NOERROR)) ++ goto free_return; ++ } ++ ++ /* Add all the nodes which satisfy the following conditions: ++ - It can epsilon transit to a node in CUR_DEST. ++ - It is in CUR_SRC. ++ And update state_log. */ ++ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); ++ if ( (err != REG_NOERROR)) ++ goto free_return; ++ } ++ err = REG_NOERROR; ++ free_return: ++ re_node_set_free (&cur_dest); ++ return err; ++} ++ ++static reg_errcode_t ++build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, ++ Idx str_idx, re_node_set *cur_dest) ++{ ++ const re_dfa_t *const dfa = mctx->dfa; ++ const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; ++ Idx i; ++ ++ /* Then build the next sifted state. ++ We build the next sifted state on 'cur_dest', and update ++ 'sifted_states[str_idx]' with 'cur_dest'. ++ Note: ++ 'cur_dest' is the sifted state from 'state_log[str_idx + 1]'. ++ 'cur_src' points the node_set of the old 'state_log[str_idx]' ++ (with the epsilon nodes pre-filtered out). */ ++ for (i = 0; i < cur_src->nelem; i++) ++ { ++ Idx prev_node = cur_src->elems[i]; ++ int naccepted = 0; ++ bool ok; ++ ++ /* We don't check backreferences here. ++ See update_cur_sifted_state(). */ ++ if (!naccepted ++ && check_node_accept (mctx, dfa->nodes + prev_node, str_idx) ++ && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], ++ dfa->nexts[prev_node])) ++ naccepted = 1; ++ ++ if (naccepted == 0) ++ continue; ++ ++ if (sctx->limits.nelem) ++ { ++ Idx to_idx = str_idx + naccepted; ++ if (check_dst_limits (mctx, &sctx->limits, ++ dfa->nexts[prev_node], to_idx, ++ prev_node, str_idx)) ++ continue; ++ } ++ ok = re_node_set_insert (cur_dest, prev_node); ++ if ( (! ok)) ++ return REG_ESPACE; ++ } ++ ++ return REG_NOERROR; ++} ++ ++static reg_errcode_t ++clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_idx) ++{ ++ Idx top = mctx->state_log_top; ++ ++ if ((next_state_log_idx >= mctx->input.bufs_len ++ && mctx->input.bufs_len < mctx->input.len) ++ || (next_state_log_idx >= mctx->input.valid_len ++ && mctx->input.valid_len < mctx->input.len)) ++ { ++ reg_errcode_t err; ++ err = extend_buffers (mctx, next_state_log_idx + 1); ++ if ( (err != REG_NOERROR)) ++ return err; ++ } ++ ++ if (top < next_state_log_idx) ++ { ++ memset (mctx->state_log + top + 1, '\0', ++ sizeof (re_dfastate_t *) * (next_state_log_idx - top)); ++ mctx->state_log_top = next_state_log_idx; ++ } ++ return REG_NOERROR; ++} ++ ++/* Enumerate all the candidates which the backreference BKREF_NODE can match ++ at BKREF_STR_IDX, and register them by match_ctx_add_entry(). ++ Note that we might collect inappropriate candidates here. ++ However, the cost of checking them strictly here is too high, then we ++ delay these checking for prune_impossible_nodes(). */ ++ ++static reg_errcode_t ++ ++get_subexp(re_match_context_t *mctx, Idx bkref_node, Idx bkref_str_idx) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ Idx subexp_num, sub_top_idx; ++ const char *buf = (const char *) re_string_get_buffer(&mctx->input); ++/* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ ++ Idx cache_idx = search_cur_bkref_entry(mctx, bkref_str_idx); ++ if (cache_idx != -1) { ++ const struct re_backref_cache_entry *entry ++ = mctx->bkref_ents + cache_idx; ++ do ++ if (entry->node == bkref_node) ++ return REG_NOERROR; /* We already checked it. */ ++ while (entry++->more); ++ } ++ ++ subexp_num = dfa->nodes[bkref_node].opr.idx; ++ ++/* For each sub expression */ ++ for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) { ++ reg_errcode_t err; ++ re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx]; ++ re_sub_match_last_t *sub_last; ++ Idx sub_last_idx, sl_str, bkref_str_off; ++ ++ if (dfa->nodes[sub_top->node].opr.idx != subexp_num) ++ continue; /* It isn't related. */ ++ ++ sl_str = sub_top->str_idx; ++ bkref_str_off = bkref_str_idx; ++/* At first, check the last node of sub expressions we already ++evaluated. */ ++ for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx) { ++ regoff_t sl_str_diff; ++ sub_last = sub_top->lasts[sub_last_idx]; ++ sl_str_diff = sub_last->str_idx - sl_str; ++/* The matched string by the sub expression match with the substring ++ at the back reference? */ ++ if (sl_str_diff > 0) { ++ if ((bkref_str_off + sl_str_diff ++ > mctx->input.valid_len)) { ++/* Not enough chars for a successful match. */ ++ if (bkref_str_off + sl_str_diff > mctx->input.len) ++ break; ++ ++ err = clean_state_log_if_needed(mctx, ++ bkref_str_off ++ + sl_str_diff); ++ if ((err != REG_NOERROR)) ++ return err; ++ buf = (const char *) re_string_get_buffer(&mctx->input); ++ } ++ if (memcmp(buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0) ++/* We don't need to search this sub expression any more. */ ++ break; ++ } ++ bkref_str_off += sl_str_diff; ++ sl_str += sl_str_diff; ++ err = get_subexp_sub(mctx, sub_top, sub_last, bkref_node, ++ bkref_str_idx); ++ ++/* Reload buf, since the preceding call might have reallocated ++ the buffer. */ ++ buf = (const char *) re_string_get_buffer(&mctx->input); ++ ++ if (err == REG_NOMATCH) ++ continue; ++ if ((err != REG_NOERROR)) ++ return err; ++ } ++ ++ if (sub_last_idx < sub_top->nlasts) ++ continue; ++ if (sub_last_idx > 0) ++ ++sl_str; ++/* Then, search for the other last nodes of the sub expression. */ ++ for (; sl_str <= bkref_str_idx; ++sl_str) { ++ Idx cls_node; ++ regoff_t sl_str_off; ++ const re_node_set *nodes; ++ sl_str_off = sl_str - sub_top->str_idx; ++/* The matched string by the sub expression match with the substring ++ at the back reference? */ ++ if (sl_str_off > 0) { ++ if ((bkref_str_off >= mctx->input.valid_len)) { ++/* If we are at the end of the input, we cannot match. */ ++ if (bkref_str_off >= mctx->input.len) ++ break; ++ ++ err = extend_buffers(mctx, bkref_str_off + 1); ++ if ((err != REG_NOERROR)) ++ return err; ++ ++ buf = (const char *) re_string_get_buffer(&mctx->input); ++ } ++ if (buf[bkref_str_off++] != buf[sl_str - 1]) ++ break; /* We don't need to search this sub expression ++ any more. */ ++ } ++ if (mctx->state_log[sl_str] == NULL) ++ continue; ++/* Does this state have a ')' of the sub expression? */ ++ nodes = &mctx->state_log[sl_str]->nodes; ++ cls_node = find_subexp_node(dfa, nodes, subexp_num, ++ OP_CLOSE_SUBEXP); ++ if (cls_node == -1) ++ continue; /* No. */ ++ if (sub_top->path == NULL) { ++ sub_top->path = calloc(sizeof(state_array_t), ++ sl_str - sub_top->str_idx + 1); ++ if (sub_top->path == NULL) ++ return REG_ESPACE; ++ } ++/* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node ++ in the current context? */ ++ err = check_arrival(mctx, sub_top->path, sub_top->node, ++ sub_top->str_idx, cls_node, sl_str, ++ OP_CLOSE_SUBEXP); ++ if (err == REG_NOMATCH) ++ continue; ++ if ((err != REG_NOERROR)) ++ return err; ++ sub_last = match_ctx_add_sublast(sub_top, cls_node, sl_str); ++ if ((sub_last == NULL)) ++ return REG_ESPACE; ++ err = get_subexp_sub(mctx, sub_top, sub_last, bkref_node, ++ bkref_str_idx); ++ if (err == REG_NOMATCH) ++ continue; ++ } ++ } ++ return REG_NOERROR; ++} ++ ++/* Helper functions for get_subexp(). */ ++ ++/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR. ++ If it can arrive, register the sub expression expressed with SUB_TOP ++ and SUB_LAST. */ ++ ++static reg_errcode_t ++get_subexp_sub(re_match_context_t *mctx, const re_sub_match_top_t *sub_top, ++ re_sub_match_last_t *sub_last, Idx bkref_node, Idx bkref_str) { ++ reg_errcode_t err; ++ Idx to_idx; ++ /* Can the subexpression arrive the back reference? */ ++ err = check_arrival(mctx, &sub_last->path, sub_last->node, ++ sub_last->str_idx, bkref_node, bkref_str, ++ OP_OPEN_SUBEXP); ++ if (err != REG_NOERROR) ++ return err; ++ err = match_ctx_add_entry(mctx, bkref_node, bkref_str, sub_top->str_idx, ++ sub_last->str_idx); ++ if ((err != REG_NOERROR)) ++ return err; ++ to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx; ++ return clean_state_log_if_needed(mctx, to_idx); ++} ++ ++/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX. ++ Search '(' if FL_OPEN, or search ')' otherwise. ++ TODO: This function isn't efficient... ++ Because there might be more than one nodes whose types are ++ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all ++ nodes. ++ E.g. RE: (a){2} */ ++ ++static Idx ++find_subexp_node(const re_dfa_t *dfa, const re_node_set *nodes, ++ Idx subexp_idx, int type) { ++ Idx cls_idx; ++ for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) { ++ Idx cls_node = nodes->elems[cls_idx]; ++ const re_token_t *node = dfa->nodes + cls_node; ++ if (node->type == type ++ && node->opr.idx == subexp_idx) ++ return cls_node; ++ } ++ return -1; ++} ++ ++/* Check whether the node TOP_NODE at TOP_STR can arrive to the node ++ LAST_NODE at LAST_STR. We record the path onto PATH since it will be ++ heavily reused. ++ Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ ++ ++static reg_errcode_t ++ ++check_arrival(re_match_context_t *mctx, state_array_t *path, Idx top_node, ++ Idx top_str, Idx last_node, Idx last_str, int type) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ reg_errcode_t err = REG_NOERROR; ++ Idx subexp_num, backup_cur_idx, str_idx, null_cnt; ++ re_dfastate_t *cur_state = NULL; ++ re_node_set *cur_nodes, next_nodes; ++ re_dfastate_t **backup_state_log; ++ unsigned int context; ++ ++ subexp_num = dfa->nodes[top_node].opr.idx; ++/* Extend the buffer if we need. */ ++ if ((path->alloc < last_str + mctx->max_mb_elem_len + 1)) { ++ re_dfastate_t **new_array; ++ Idx old_alloc = path->alloc; ++ Idx incr_alloc = last_str + mctx->max_mb_elem_len + 1; ++ Idx new_alloc; ++ if ((IDX_MAX - old_alloc < incr_alloc)) ++ return REG_ESPACE; ++ new_alloc = old_alloc + incr_alloc; ++ if ((SIZE_MAX / sizeof(re_dfastate_t * ) < new_alloc)) ++ return REG_ESPACE; ++ new_array = re_realloc(path->array, re_dfastate_t * , new_alloc); ++ if ((new_array == NULL)) ++ return REG_ESPACE; ++ path->array = new_array; ++ path->alloc = new_alloc; ++ memset(new_array + old_alloc, '\0', ++ sizeof(re_dfastate_t * ) * (path->alloc - old_alloc)); ++ } ++ ++ str_idx = path->next_idx ? path->next_idx : top_str; ++ ++/* Temporary modify MCTX. */ ++ backup_state_log = mctx->state_log; ++ backup_cur_idx = mctx->input.cur_idx; ++ mctx->state_log = path->array; ++ mctx->input.cur_idx = str_idx; ++ ++/* Setup initial node set. */ ++ context = re_string_context_at(&mctx->input, str_idx - 1, mctx->eflags); ++ if (str_idx == top_str) { ++ err = re_node_set_init_1(&next_nodes, top_node); ++ if ((err != REG_NOERROR)) ++ return err; ++ err = check_arrival_expand_ecl(dfa, &next_nodes, subexp_num, type); ++ if ((err != REG_NOERROR)) { ++ re_node_set_free(&next_nodes); ++ return err; ++ } ++ } else { ++ cur_state = mctx->state_log[str_idx]; ++ if (cur_state && cur_state->has_backref) { ++ err = re_node_set_init_copy(&next_nodes, &cur_state->nodes); ++ if ((err != REG_NOERROR)) ++ return err; ++ } else ++ re_node_set_init_empty(&next_nodes); ++ } ++ if (str_idx == top_str || (cur_state && cur_state->has_backref)) { ++ if (next_nodes.nelem) { ++ err = expand_bkref_cache(mctx, &next_nodes, str_idx, ++ subexp_num, type); ++ if ((err != REG_NOERROR)) { ++ re_node_set_free(&next_nodes); ++ return err; ++ } ++ } ++ cur_state = re_acquire_state_context(&err, dfa, &next_nodes, context); ++ if ((cur_state == NULL && err != REG_NOERROR)) { ++ re_node_set_free(&next_nodes); ++ return err; ++ } ++ mctx->state_log[str_idx] = cur_state; ++ } ++ ++ for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;) { ++ re_node_set_empty(&next_nodes); ++ if (mctx->state_log[str_idx + 1]) { ++ err = re_node_set_merge(&next_nodes, ++ &mctx->state_log[str_idx + 1]->nodes); ++ if ((err != REG_NOERROR)) { ++ re_node_set_free(&next_nodes); ++ return err; ++ } ++ } ++ if (cur_state) { ++ err = check_arrival_add_next_nodes(mctx, str_idx, ++ &cur_state->non_eps_nodes, ++ &next_nodes); ++ if ((err != REG_NOERROR)) { ++ re_node_set_free(&next_nodes); ++ return err; ++ } ++ } ++ ++str_idx; ++ if (next_nodes.nelem) { ++ err = check_arrival_expand_ecl(dfa, &next_nodes, subexp_num, type); ++ if ((err != REG_NOERROR)) { ++ re_node_set_free(&next_nodes); ++ return err; ++ } ++ err = expand_bkref_cache(mctx, &next_nodes, str_idx, ++ subexp_num, type); ++ if ((err != REG_NOERROR)) { ++ re_node_set_free(&next_nodes); ++ return err; ++ } ++ } ++ context = re_string_context_at(&mctx->input, str_idx - 1, mctx->eflags); ++ cur_state = re_acquire_state_context(&err, dfa, &next_nodes, context); ++ if ((cur_state == NULL && err != REG_NOERROR)) { ++ re_node_set_free(&next_nodes); ++ return err; ++ } ++ mctx->state_log[str_idx] = cur_state; ++ null_cnt = cur_state == NULL ? null_cnt + 1 : 0; ++ } ++ re_node_set_free(&next_nodes); ++ cur_nodes = (mctx->state_log[last_str] == NULL ? NULL ++ : &mctx->state_log[last_str]->nodes); ++ path->next_idx = str_idx; ++ ++/* Fix MCTX. */ ++ mctx->state_log = backup_state_log; ++ mctx->input.cur_idx = backup_cur_idx; ++ ++/* Then check the current node set has the node LAST_NODE. */ ++ if (cur_nodes != NULL && re_node_set_contains(cur_nodes, last_node)) ++ return REG_NOERROR; ++ ++ return REG_NOMATCH; ++} ++ ++/* Helper functions for check_arrival. */ ++ ++/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them ++ to NEXT_NODES. ++ TODO: This function is similar to the functions transit_state*(), ++ however this function has many additional works. ++ Can't we unify them? */ ++ ++static reg_errcode_t ++ ++check_arrival_add_next_nodes(re_match_context_t *mctx, Idx str_idx, ++ re_node_set *cur_nodes, re_node_set *next_nodes) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ bool ok; ++ Idx cur_idx; ++ re_node_set union_set; ++ re_node_set_init_empty(&union_set); ++ for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) { ++ int naccepted = 0; ++ Idx cur_node = cur_nodes->elems[cur_idx]; ++ if (naccepted ++ || check_node_accept(mctx, dfa->nodes + cur_node, str_idx)) { ++ ok = re_node_set_insert(next_nodes, dfa->nexts[cur_node]); ++ if ((!ok)) { ++ re_node_set_free(&union_set); ++ return REG_ESPACE; ++ } ++ } ++ } ++ re_node_set_free(&union_set); ++ return REG_NOERROR; ++} ++ ++/* For all the nodes in CUR_NODES, add the epsilon closures of them to ++ CUR_NODES, however exclude the nodes which are: ++ - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN. ++ - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN. ++*/ ++ ++static reg_errcode_t ++check_arrival_expand_ecl(const re_dfa_t *dfa, re_node_set *cur_nodes, ++ Idx ex_subexp, int type) { ++ reg_errcode_t err; ++ Idx idx, outside_node; ++ re_node_set new_nodes; ++ err = re_node_set_alloc(&new_nodes, cur_nodes->nelem); ++ if ((err != REG_NOERROR)) ++ return err; ++ /* Create a new node set NEW_NODES with the nodes which are epsilon ++ closures of the node in CUR_NODES. */ ++ ++ for (idx = 0; idx < cur_nodes->nelem; ++idx) { ++ Idx cur_node = cur_nodes->elems[idx]; ++ const re_node_set *eclosure = dfa->eclosures + cur_node; ++ outside_node = find_subexp_node(dfa, eclosure, ex_subexp, type); ++ if (outside_node == -1) { ++ /* There are no problematic nodes, just merge them. */ ++ err = re_node_set_merge(&new_nodes, eclosure); ++ if ((err != REG_NOERROR)) { ++ re_node_set_free(&new_nodes); ++ return err; ++ } ++ } else { ++ /* There are problematic nodes, re-calculate incrementally. */ ++ err = check_arrival_expand_ecl_sub(dfa, &new_nodes, cur_node, ++ ex_subexp, type); ++ if ((err != REG_NOERROR)) { ++ re_node_set_free(&new_nodes); ++ return err; ++ } ++ } ++ } ++ re_node_set_free(cur_nodes); ++ *cur_nodes = new_nodes; ++ return REG_NOERROR; ++} ++ ++/* Helper function for check_arrival_expand_ecl. ++ Check incrementally the epsilon closure of TARGET, and if it isn't ++ problematic append it to DST_NODES. */ ++ ++static reg_errcode_t ++ ++check_arrival_expand_ecl_sub(const re_dfa_t *dfa, re_node_set *dst_nodes, ++ Idx target, Idx ex_subexp, int type) { ++ Idx cur_node; ++ for (cur_node = target; !re_node_set_contains(dst_nodes, cur_node);) { ++ bool ok; ++ ++ if (dfa->nodes[cur_node].type == type ++ && dfa->nodes[cur_node].opr.idx == ex_subexp) { ++ if (type == OP_CLOSE_SUBEXP) { ++ ok = re_node_set_insert(dst_nodes, cur_node); ++ if ((!ok)) ++ return REG_ESPACE; ++ } ++ break; ++ } ++ ok = re_node_set_insert(dst_nodes, cur_node); ++ if ((!ok)) ++ return REG_ESPACE; ++ if (dfa->edests[cur_node].nelem == 0) ++ break; ++ if (dfa->edests[cur_node].nelem == 2) { ++ reg_errcode_t err; ++ err = check_arrival_expand_ecl_sub(dfa, dst_nodes, ++ dfa->edests[cur_node].elems[1], ++ ex_subexp, type); ++ if ((err != REG_NOERROR)) ++ return err; ++ } ++ cur_node = dfa->edests[cur_node].elems[0]; ++ } ++ return REG_NOERROR; ++} ++ ++/* For all the back references in the current state, calculate the ++ destination of the back references by the appropriate entry ++ in MCTX->BKREF_ENTS. */ ++ ++static reg_errcode_t ++expand_bkref_cache(re_match_context_t *mctx, re_node_set *cur_nodes, ++ Idx cur_str, Idx subexp_num, int type) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ reg_errcode_t err; ++ Idx cache_idx_start = search_cur_bkref_entry(mctx, cur_str); ++ struct re_backref_cache_entry *ent; ++ ++ if (cache_idx_start == -1) ++ return REG_NOERROR; ++ ++ restart: ++ ent = mctx->bkref_ents + cache_idx_start; ++ do { ++ Idx to_idx, next_node; ++ ++/* Is this entry ENT is appropriate? */ ++ if (!re_node_set_contains(cur_nodes, ent->node)) ++ continue; /* No. */ ++ ++ to_idx = cur_str + ent->subexp_to - ent->subexp_from; ++/* Calculate the destination of the back reference, and append it ++to MCTX->STATE_LOG. */ ++ if (to_idx == cur_str) { ++/* The backreference did epsilon transit, we must re-check all the ++ node in the current state. */ ++ re_node_set new_dests; ++ reg_errcode_t err2, err3; ++ next_node = dfa->edests[ent->node].elems[0]; ++ if (re_node_set_contains(cur_nodes, next_node)) ++ continue; ++ err = re_node_set_init_1(&new_dests, next_node); ++ err2 = check_arrival_expand_ecl(dfa, &new_dests, subexp_num, type); ++ err3 = re_node_set_merge(cur_nodes, &new_dests); ++ re_node_set_free(&new_dests); ++ if ((err != REG_NOERROR || err2 != REG_NOERROR ++ || err3 != REG_NOERROR)) { ++ err = (err != REG_NOERROR ? err ++ : (err2 != REG_NOERROR ? err2 : err3)); ++ return err; ++ } ++/* TODO: It is still inefficient... */ ++ goto restart; ++ } else { ++ re_node_set union_set; ++ next_node = dfa->nexts[ent->node]; ++ if (mctx->state_log[to_idx]) { ++ bool ok; ++ if (re_node_set_contains(&mctx->state_log[to_idx]->nodes, ++ next_node)) ++ continue; ++ err = re_node_set_init_copy(&union_set, ++ &mctx->state_log[to_idx]->nodes); ++ ok = re_node_set_insert(&union_set, next_node); ++ if ((err != REG_NOERROR || !ok)) { ++ re_node_set_free(&union_set); ++ err = err != REG_NOERROR ? err : REG_ESPACE; ++ return err; ++ } ++ } else { ++ err = re_node_set_init_1(&union_set, next_node); ++ if ((err != REG_NOERROR)) ++ return err; ++ } ++ mctx->state_log[to_idx] = re_acquire_state(&err, dfa, &union_set); ++ re_node_set_free(&union_set); ++ if ((mctx->state_log[to_idx] == NULL ++ && err != REG_NOERROR)) ++ return err; ++ } ++ } while (ent++->more); ++ return REG_NOERROR; ++} ++ ++/* Build transition table for the state. ++ Return true if successful. */ ++ ++static bool ++build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) ++{ ++ reg_errcode_t err; ++ Idx i, j; ++ int ch; ++ bool need_word_trtable = false; ++ bitset_word_t elem, mask; ++ bool dests_node_malloced = false; ++ bool dest_states_malloced = false; ++ Idx ndests; /* Number of the destination states from 'state'. */ ++ re_dfastate_t **trtable; ++ re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; ++ re_node_set follows, *dests_node; ++ bitset_t *dests_ch; ++ bitset_t acceptable; ++ ++ struct dests_alloc ++ { ++ re_node_set dests_node[SBC_MAX]; ++ bitset_t dests_ch[SBC_MAX]; ++ } *dests_alloc; ++ ++ /* We build DFA states which corresponds to the destination nodes ++ from 'state'. 'dests_node[i]' represents the nodes which i-th ++ destination state contains, and 'dests_ch[i]' represents the ++ characters which i-th destination state accepts. */ ++ if (__libc_use_alloca (sizeof (struct dests_alloc))) ++ dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); ++ else ++ { ++ dests_alloc = re_malloc (struct dests_alloc, 1); ++ if ( (dests_alloc == NULL)) ++ return false; ++ dests_node_malloced = true; ++ } ++ dests_node = dests_alloc->dests_node; ++ dests_ch = dests_alloc->dests_ch; ++ ++ /* Initialize transition table. */ ++ state->word_trtable = state->trtable = NULL; ++ ++ /* At first, group all nodes belonging to 'state' into several ++ destinations. */ ++ ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch); ++ if ( (ndests <= 0)) ++ { ++ if (dests_node_malloced) ++ re_free (dests_alloc); ++ /* Return false in case of an error, true otherwise. */ ++ if (ndests == 0) ++ { ++ state->trtable = (re_dfastate_t **) ++ calloc (sizeof (re_dfastate_t *), SBC_MAX); ++ if ( (state->trtable == NULL)) ++ return false; ++ return true; ++ } ++ return false; ++ } ++ ++ err = re_node_set_alloc (&follows, ndests + 1); ++ if ( (err != REG_NOERROR)) ++ goto out_free; ++ ++ /* Avoid arithmetic overflow in size calculation. */ ++ size_t ndests_max ++ = ((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) ++ / (3 * sizeof (re_dfastate_t *))); ++ if ( (ndests_max < ndests)) ++ goto out_free; ++ ++ if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX ++ + ndests * 3 * sizeof (re_dfastate_t *))) ++ dest_states = (re_dfastate_t **) ++ alloca (ndests * 3 * sizeof (re_dfastate_t *)); ++ else ++ { ++ dest_states = re_malloc (re_dfastate_t *, ndests * 3); ++ if ( (dest_states == NULL)) ++ { ++ out_free: ++ if (dest_states_malloced) ++ re_free (dest_states); ++ re_node_set_free (&follows); ++ for (i = 0; i < ndests; ++i) ++ re_node_set_free (dests_node + i); ++ if (dests_node_malloced) ++ re_free (dests_alloc); ++ return false; ++ } ++ dest_states_malloced = true; ++ } ++ dest_states_word = dest_states + ndests; ++ dest_states_nl = dest_states_word + ndests; ++ bitset_empty (acceptable); ++ ++ /* Then build the states for all destinations. */ ++ for (i = 0; i < ndests; ++i) ++ { ++ Idx next_node; ++ re_node_set_empty (&follows); ++ /* Merge the follows of this destination states. */ ++ for (j = 0; j < dests_node[i].nelem; ++j) ++ { ++ next_node = dfa->nexts[dests_node[i].elems[j]]; ++ if (next_node != -1) ++ { ++ err = re_node_set_merge (&follows, dfa->eclosures + next_node); ++ if ( (err != REG_NOERROR)) ++ goto out_free; ++ } ++ } ++ dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); ++ if ( (dest_states[i] == NULL && err != REG_NOERROR)) ++ goto out_free; ++ /* If the new state has context constraint, ++ build appropriate states for these contexts. */ ++ if (dest_states[i]->has_constraint) ++ { ++ dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, ++ CONTEXT_WORD); ++ if ( (dest_states_word[i] == NULL ++ && err != REG_NOERROR)) ++ goto out_free; ++ ++ if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) ++ need_word_trtable = true; ++ ++ dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, ++ CONTEXT_NEWLINE); ++ if ( (dest_states_nl[i] == NULL && err != REG_NOERROR)) ++ goto out_free; ++ } ++ else ++ { ++ dest_states_word[i] = dest_states[i]; ++ dest_states_nl[i] = dest_states[i]; ++ } ++ bitset_merge (acceptable, dests_ch[i]); ++ } ++ ++ if (! (need_word_trtable)) ++ { ++ /* We don't care about whether the following character is a word ++ character, or we are in a single-byte character set so we can ++ discern by looking at the character code: allocate a ++ 256-entry transition table. */ ++ trtable = state->trtable = ++ (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); ++ if ( (trtable == NULL)) ++ goto out_free; ++ ++ /* For all characters ch...: */ ++ for (i = 0; i < BITSET_WORDS; ++i) ++ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; ++ elem; ++ mask <<= 1, elem >>= 1, ++ch) ++ if ( (elem & 1)) ++ { ++ /* There must be exactly one destination which accepts ++ character ch. See group_nodes_into_DFAstates. */ ++ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) ++ ; ++ ++ /* j-th destination accepts the word character ch. */ ++ if (dfa->word_char[i] & mask) ++ trtable[ch] = dest_states_word[j]; ++ else ++ trtable[ch] = dest_states[j]; ++ } ++ } ++ else ++ { ++ /* We care about whether the following character is a word ++ character, and we are in a multi-byte character set: discern ++ by looking at the character code: build two 256-entry ++ transition tables, one starting at trtable[0] and one ++ starting at trtable[SBC_MAX]. */ ++ trtable = state->word_trtable = ++ (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); ++ if ( (trtable == NULL)) ++ goto out_free; ++ ++ /* For all characters ch...: */ ++ for (i = 0; i < BITSET_WORDS; ++i) ++ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; ++ elem; ++ mask <<= 1, elem >>= 1, ++ch) ++ if ( (elem & 1)) ++ { ++ /* There must be exactly one destination which accepts ++ character ch. See group_nodes_into_DFAstates. */ ++ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) ++ ; ++ ++ /* j-th destination accepts the word character ch. */ ++ trtable[ch] = dest_states[j]; ++ trtable[ch + SBC_MAX] = dest_states_word[j]; ++ } ++ } ++ ++ /* new line */ ++ if (bitset_contain (acceptable, NEWLINE_CHAR)) ++ { ++ /* The current state accepts newline character. */ ++ for (j = 0; j < ndests; ++j) ++ if (bitset_contain (dests_ch[j], NEWLINE_CHAR)) ++ { ++ /* k-th destination accepts newline character. */ ++ trtable[NEWLINE_CHAR] = dest_states_nl[j]; ++ if (need_word_trtable) ++ trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j]; ++ /* There must be only one destination which accepts ++ newline. See group_nodes_into_DFAstates. */ ++ break; ++ } ++ } ++ ++ if (dest_states_malloced) ++ re_free (dest_states); ++ ++ re_node_set_free (&follows); ++ for (i = 0; i < ndests; ++i) ++ re_node_set_free (dests_node + i); ++ ++ if (dests_node_malloced) ++ re_free (dests_alloc); ++ ++ return true; ++} ++ ++/* Group all nodes belonging to STATE into several destinations. ++ Then for all destinations, set the nodes belonging to the destination ++ to DESTS_NODE[i] and set the characters accepted by the destination ++ to DEST_CH[i]. This function return the number of destinations. */ ++ ++static Idx ++group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, ++ re_node_set *dests_node, bitset_t *dests_ch) ++{ ++ reg_errcode_t err; ++ bool ok; ++ Idx i, j, k; ++ Idx ndests; /* Number of the destinations from 'state'. */ ++ bitset_t accepts; /* Characters a node can accept. */ ++ const re_node_set *cur_nodes = &state->nodes; ++ bitset_empty (accepts); ++ ndests = 0; ++ ++ /* For all the nodes belonging to 'state', */ ++ for (i = 0; i < cur_nodes->nelem; ++i) ++ { ++ re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; ++ re_token_type_t type = node->type; ++ unsigned int constraint = node->constraint; ++ ++ /* Enumerate all single byte character this node can accept. */ ++ if (type == CHARACTER) ++ bitset_set (accepts, node->opr.c); ++ else if (type == SIMPLE_BRACKET) ++ { ++ bitset_merge (accepts, node->opr.sbcset); ++ } ++ else if (type == OP_PERIOD) ++ { ++ bitset_set_all (accepts); ++ if (!(dfa->syntax & RE_DOT_NEWLINE)) ++ bitset_clear (accepts, '\n'); ++ if (dfa->syntax & RE_DOT_NOT_NULL) ++ bitset_clear (accepts, '\0'); ++ } ++ else ++ continue; ++ ++ /* Check the 'accepts' and sift the characters which are not ++ match it the context. */ ++ if (constraint) ++ { ++ if (constraint & NEXT_NEWLINE_CONSTRAINT) ++ { ++ bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); ++ bitset_empty (accepts); ++ if (accepts_newline) ++ bitset_set (accepts, NEWLINE_CHAR); ++ else ++ continue; ++ } ++ if (constraint & NEXT_ENDBUF_CONSTRAINT) ++ { ++ bitset_empty (accepts); ++ continue; ++ } ++ ++ if (constraint & NEXT_WORD_CONSTRAINT) ++ { ++ bitset_word_t any_set = 0; ++ if (type == CHARACTER && !node->word_char) ++ { ++ bitset_empty (accepts); ++ continue; ++ } ++ for (j = 0; j < BITSET_WORDS; ++j) ++ any_set |= (accepts[j] &= dfa->word_char[j]); ++ if (!any_set) ++ continue; ++ } ++ if (constraint & NEXT_NOTWORD_CONSTRAINT) ++ { ++ bitset_word_t any_set = 0; ++ if (type == CHARACTER && node->word_char) ++ { ++ bitset_empty (accepts); ++ continue; ++ } ++ for (j = 0; j < BITSET_WORDS; ++j) ++ any_set |= (accepts[j] &= ~dfa->word_char[j]); ++ if (!any_set) ++ continue; ++ } ++ } ++ ++ /* Then divide 'accepts' into DFA states, or create a new ++ state. Above, we make sure that accepts is not empty. */ ++ for (j = 0; j < ndests; ++j) ++ { ++ bitset_t intersec; /* Intersection sets, see below. */ ++ bitset_t remains; ++ /* Flags, see below. */ ++ bitset_word_t has_intersec, not_subset, not_consumed; ++ ++ /* Optimization, skip if this state doesn't accept the character. */ ++ if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) ++ continue; ++ ++ /* Enumerate the intersection set of this state and 'accepts'. */ ++ has_intersec = 0; ++ for (k = 0; k < BITSET_WORDS; ++k) ++ has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; ++ /* And skip if the intersection set is empty. */ ++ if (!has_intersec) ++ continue; ++ ++ /* Then check if this state is a subset of 'accepts'. */ ++ not_subset = not_consumed = 0; ++ for (k = 0; k < BITSET_WORDS; ++k) ++ { ++ not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; ++ not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; ++ } ++ ++ /* If this state isn't a subset of 'accepts', create a ++ new group state, which has the 'remains'. */ ++ if (not_subset) ++ { ++ bitset_copy (dests_ch[ndests], remains); ++ bitset_copy (dests_ch[j], intersec); ++ err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); ++ if ( (err != REG_NOERROR)) ++ goto error_return; ++ ++ndests; ++ } ++ ++ /* Put the position in the current group. */ ++ ok = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); ++ if ( (! ok)) ++ goto error_return; ++ ++ /* If all characters are consumed, go to next node. */ ++ if (!not_consumed) ++ break; ++ } ++ /* Some characters remain, create a new group. */ ++ if (j == ndests) ++ { ++ bitset_copy (dests_ch[ndests], accepts); ++ err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); ++ if ( (err != REG_NOERROR)) ++ goto error_return; ++ ++ndests; ++ bitset_empty (accepts); ++ } ++ } ++ return ndests; ++ error_return: ++ for (j = 0; j < ndests; ++j) ++ re_node_set_free (dests_node + j); ++ return -1; ++} ++ ++ ++static reg_errcode_t ++update_cur_sifted_state (const re_match_context_t *mctx, ++ re_sift_context_t *sctx, Idx str_idx, ++ re_node_set *dest_nodes) ++{ ++ const re_dfa_t *const dfa = mctx->dfa; ++ reg_errcode_t err = REG_NOERROR; ++ const re_node_set *candidates; ++ candidates = ((mctx->state_log[str_idx] == NULL) ? NULL ++ : &mctx->state_log[str_idx]->nodes); ++ ++ if (dest_nodes->nelem == 0) ++ sctx->sifted_states[str_idx] = NULL; ++ else ++ { ++ if (candidates) ++ { ++ /* At first, add the nodes which can epsilon transit to a node in ++ DEST_NODE. */ ++ err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); ++ if ( (err != REG_NOERROR)) ++ return err; ++ ++ /* Then, check the limitations in the current sift_context. */ ++ if (sctx->limits.nelem) ++ { ++ err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, ++ mctx->bkref_ents, str_idx); ++ if ( (err != REG_NOERROR)) ++ return err; ++ } ++ } ++ ++ sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); ++ if ( (err != REG_NOERROR)) ++ return err; ++ } ++ ++ if (candidates && mctx->state_log[str_idx]->has_backref) ++ { ++ err = sift_states_bkref (mctx, sctx, str_idx, candidates); ++ if ( (err != REG_NOERROR)) ++ return err; ++ } ++ return REG_NOERROR; ++} ++ ++static reg_errcode_t ++ ++add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, ++ const re_node_set *candidates) ++{ ++ reg_errcode_t err = REG_NOERROR; ++ Idx i; ++ ++ re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes); ++ if ( (err != REG_NOERROR)) ++ return err; ++ ++ if (!state->inveclosure.alloc) ++ { ++ err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem); ++ if ( (err != REG_NOERROR)) ++ return REG_ESPACE; ++ for (i = 0; i < dest_nodes->nelem; i++) ++ { ++ err = re_node_set_merge (&state->inveclosure, ++ dfa->inveclosures + dest_nodes->elems[i]); ++ if ( (err != REG_NOERROR)) ++ return REG_ESPACE; ++ } ++ } ++ return re_node_set_add_intersect (dest_nodes, candidates, ++ &state->inveclosure); ++} ++ ++static reg_errcode_t ++sub_epsilon_src_nodes (const re_dfa_t *dfa, Idx node, re_node_set *dest_nodes, ++ const re_node_set *candidates) ++{ ++ Idx ecl_idx; ++ reg_errcode_t err; ++ re_node_set *inv_eclosure = dfa->inveclosures + node; ++ re_node_set except_nodes; ++ re_node_set_init_empty (&except_nodes); ++ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) ++ { ++ Idx cur_node = inv_eclosure->elems[ecl_idx]; ++ if (cur_node == node) ++ continue; ++ if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) ++ { ++ Idx edst1 = dfa->edests[cur_node].elems[0]; ++ Idx edst2 = ((dfa->edests[cur_node].nelem > 1) ++ ? dfa->edests[cur_node].elems[1] : -1); ++ if ((!re_node_set_contains (inv_eclosure, edst1) ++ && re_node_set_contains (dest_nodes, edst1)) ++ || (edst2 > 0 ++ && !re_node_set_contains (inv_eclosure, edst2) ++ && re_node_set_contains (dest_nodes, edst2))) ++ { ++ err = re_node_set_add_intersect (&except_nodes, candidates, ++ dfa->inveclosures + cur_node); ++ if ( (err != REG_NOERROR)) ++ { ++ re_node_set_free (&except_nodes); ++ return err; ++ } ++ } ++ } ++ } ++ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) ++ { ++ Idx cur_node = inv_eclosure->elems[ecl_idx]; ++ if (!re_node_set_contains (&except_nodes, cur_node)) ++ { ++ Idx idx = re_node_set_contains (dest_nodes, cur_node) - 1; ++ re_node_set_remove_at (dest_nodes, idx); ++ } ++ } ++ re_node_set_free (&except_nodes); ++ return REG_NOERROR; ++} ++ ++static bool ++check_dst_limits (const re_match_context_t *mctx, const re_node_set *limits, ++ Idx dst_node, Idx dst_idx, Idx src_node, Idx src_idx) ++{ ++ const re_dfa_t *const dfa = mctx->dfa; ++ Idx lim_idx, src_pos, dst_pos; ++ ++ Idx dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx); ++ Idx src_bkref_idx = search_cur_bkref_entry (mctx, src_idx); ++ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) ++ { ++ Idx subexp_idx; ++ struct re_backref_cache_entry *ent; ++ ent = mctx->bkref_ents + limits->elems[lim_idx]; ++ subexp_idx = dfa->nodes[ent->node].opr.idx; ++ ++ dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], ++ subexp_idx, dst_node, dst_idx, ++ dst_bkref_idx); ++ src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], ++ subexp_idx, src_node, src_idx, ++ src_bkref_idx); ++ ++ /* In case of: ++ ( ) ++ ( ) ++ ( ) */ ++ if (src_pos == dst_pos) ++ continue; /* This is unrelated limitation. */ ++ else ++ return true; ++ } ++ return false; ++} ++ ++static int ++check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, ++ Idx subexp_idx, Idx from_node, Idx bkref_idx) ++{ ++ const re_dfa_t *const dfa = mctx->dfa; ++ const re_node_set *eclosures = dfa->eclosures + from_node; ++ Idx node_idx; ++ ++ /* Else, we are on the boundary: examine the nodes on the epsilon ++ closure. */ ++ for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) ++ { ++ Idx node = eclosures->elems[node_idx]; ++ switch (dfa->nodes[node].type) ++ { ++ case OP_BACK_REF: ++ if (bkref_idx != -1) ++ { ++ struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx; ++ do ++ { ++ Idx dst; ++ int cpos; ++ ++ if (ent->node != node) ++ continue; ++ ++ if (subexp_idx < BITSET_WORD_BITS ++ && !(ent->eps_reachable_subexps_map ++ & ((bitset_word_t) 1 << subexp_idx))) ++ continue; ++ ++ /* Recurse trying to reach the OP_OPEN_SUBEXP and ++ OP_CLOSE_SUBEXP cases below. But, if the ++ destination node is the same node as the source ++ node, don't recurse because it would cause an ++ infinite loop: a regex that exhibits this behavior ++ is ()\1*\1* */ ++ dst = dfa->edests[node].elems[0]; ++ if (dst == from_node) ++ { ++ if (boundaries & 1) ++ return -1; ++ else /* if (boundaries & 2) */ ++ return 0; ++ } ++ ++ cpos = ++ check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, ++ dst, bkref_idx); ++ if (cpos == -1 /* && (boundaries & 1) */) ++ return -1; ++ if (cpos == 0 && (boundaries & 2)) ++ return 0; ++ ++ if (subexp_idx < BITSET_WORD_BITS) ++ ent->eps_reachable_subexps_map ++ &= ~((bitset_word_t) 1 << subexp_idx); ++ } ++ while (ent++->more); ++ } ++ break; ++ ++ case OP_OPEN_SUBEXP: ++ if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx) ++ return -1; ++ break; ++ ++ case OP_CLOSE_SUBEXP: ++ if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx) ++ return 0; ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ return (boundaries & 2) ? 1 : 0; ++} ++ ++static int ++check_dst_limits_calc_pos (const re_match_context_t *mctx, Idx limit, ++ Idx subexp_idx, Idx from_node, Idx str_idx, ++ Idx bkref_idx) ++{ ++ struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; ++ int boundaries; ++ ++ /* If we are outside the range of the subexpression, return -1 or 1. */ ++ if (str_idx < lim->subexp_from) ++ return -1; ++ ++ if (lim->subexp_to < str_idx) ++ return 1; ++ ++ /* If we are within the subexpression, return 0. */ ++ boundaries = (str_idx == lim->subexp_from); ++ boundaries |= (str_idx == lim->subexp_to) << 1; ++ if (boundaries == 0) ++ return 0; ++ ++ /* Else, examine epsilon closure. */ ++ return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, ++ from_node, bkref_idx); ++} ++ ++/* Check the limitations of sub expressions LIMITS, and remove the nodes ++ which are against limitations from DEST_NODES. */ ++ ++static reg_errcode_t ++check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, ++ const re_node_set *candidates, re_node_set *limits, ++ struct re_backref_cache_entry *bkref_ents, Idx str_idx) ++{ ++ reg_errcode_t err; ++ Idx node_idx, lim_idx; ++ ++ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) ++ { ++ Idx subexp_idx; ++ struct re_backref_cache_entry *ent; ++ ent = bkref_ents + limits->elems[lim_idx]; ++ ++ if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) ++ continue; /* This is unrelated limitation. */ ++ ++ subexp_idx = dfa->nodes[ent->node].opr.idx; ++ if (ent->subexp_to == str_idx) ++ { ++ Idx ops_node = -1; ++ Idx cls_node = -1; ++ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) ++ { ++ Idx node = dest_nodes->elems[node_idx]; ++ re_token_type_t type = dfa->nodes[node].type; ++ if (type == OP_OPEN_SUBEXP ++ && subexp_idx == dfa->nodes[node].opr.idx) ++ ops_node = node; ++ else if (type == OP_CLOSE_SUBEXP ++ && subexp_idx == dfa->nodes[node].opr.idx) ++ cls_node = node; ++ } ++ ++ /* Check the limitation of the open subexpression. */ ++ /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ ++ if (ops_node >= 0) ++ { ++ err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes, ++ candidates); ++ if ( (err != REG_NOERROR)) ++ return err; ++ } ++ ++ /* Check the limitation of the close subexpression. */ ++ if (cls_node >= 0) ++ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) ++ { ++ Idx node = dest_nodes->elems[node_idx]; ++ if (!re_node_set_contains (dfa->inveclosures + node, ++ cls_node) ++ && !re_node_set_contains (dfa->eclosures + node, ++ cls_node)) ++ { ++ /* It is against this limitation. ++ Remove it form the current sifted state. */ ++ err = sub_epsilon_src_nodes (dfa, node, dest_nodes, ++ candidates); ++ if ( (err != REG_NOERROR)) ++ return err; ++ --node_idx; ++ } ++ } ++ } ++ else /* (ent->subexp_to != str_idx) */ ++ { ++ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) ++ { ++ Idx node = dest_nodes->elems[node_idx]; ++ re_token_type_t type = dfa->nodes[node].type; ++ if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) ++ { ++ if (subexp_idx != dfa->nodes[node].opr.idx) ++ continue; ++ /* It is against this limitation. ++ Remove it form the current sifted state. */ ++ err = sub_epsilon_src_nodes (dfa, node, dest_nodes, ++ candidates); ++ if ( (err != REG_NOERROR)) ++ return err; ++ } ++ } ++ } ++ } ++ return REG_NOERROR; ++} ++ ++static reg_errcode_t ++ ++sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, ++ Idx str_idx, const re_node_set *candidates) ++{ ++ const re_dfa_t *const dfa = mctx->dfa; ++ reg_errcode_t err; ++ Idx node_idx, node; ++ re_sift_context_t local_sctx; ++ Idx first_idx = search_cur_bkref_entry (mctx, str_idx); ++ ++ if (first_idx == -1) ++ return REG_NOERROR; ++ ++ local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ ++ ++ for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) ++ { ++ Idx enabled_idx; ++ re_token_type_t type; ++ struct re_backref_cache_entry *entry; ++ node = candidates->elems[node_idx]; ++ type = dfa->nodes[node].type; ++ /* Avoid infinite loop for the REs like "()\1+". */ ++ if (node == sctx->last_node && str_idx == sctx->last_str_idx) ++ continue; ++ if (type != OP_BACK_REF) ++ continue; ++ ++ entry = mctx->bkref_ents + first_idx; ++ enabled_idx = first_idx; ++ do ++ { ++ Idx subexp_len; ++ Idx to_idx; ++ Idx dst_node; ++ bool ok; ++ re_dfastate_t *cur_state; ++ ++ if (entry->node != node) ++ continue; ++ subexp_len = entry->subexp_to - entry->subexp_from; ++ to_idx = str_idx + subexp_len; ++ dst_node = (subexp_len ? dfa->nexts[node] ++ : dfa->edests[node].elems[0]); ++ ++ if (to_idx > sctx->last_str_idx ++ || sctx->sifted_states[to_idx] == NULL ++ || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node) ++ || check_dst_limits (mctx, &sctx->limits, node, ++ str_idx, dst_node, to_idx)) ++ continue; ++ ++ if (local_sctx.sifted_states == NULL) ++ { ++ local_sctx = *sctx; ++ err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); ++ if ( (err != REG_NOERROR)) ++ goto free_return; ++ } ++ local_sctx.last_node = node; ++ local_sctx.last_str_idx = str_idx; ++ ok = re_node_set_insert (&local_sctx.limits, enabled_idx); ++ if ( (! ok)) ++ { ++ err = REG_ESPACE; ++ goto free_return; ++ } ++ cur_state = local_sctx.sifted_states[str_idx]; ++ err = sift_states_backward (mctx, &local_sctx); ++ if ( (err != REG_NOERROR)) ++ goto free_return; ++ if (sctx->limited_states != NULL) ++ { ++ err = merge_state_array (dfa, sctx->limited_states, ++ local_sctx.sifted_states, ++ str_idx + 1); ++ if ( (err != REG_NOERROR)) ++ goto free_return; ++ } ++ local_sctx.sifted_states[str_idx] = cur_state; ++ re_node_set_remove (&local_sctx.limits, enabled_idx); ++ ++ /* mctx->bkref_ents may have changed, reload the pointer. */ ++ entry = mctx->bkref_ents + enabled_idx; ++ } ++ while (enabled_idx++, entry++->more); ++ } ++ err = REG_NOERROR; ++ free_return: ++ if (local_sctx.sifted_states != NULL) ++ { ++ re_node_set_free (&local_sctx.limits); ++ } ++ ++ return err; ++} ++ ++ ++static reg_errcode_t ++transit_state_bkref(re_match_context_t *mctx, const re_node_set *nodes) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ reg_errcode_t err; ++ Idx i; ++ Idx cur_str_idx = re_string_cur_idx(&mctx->input); ++ ++ for (i = 0; i < nodes->nelem; ++i) { ++ Idx dest_str_idx, prev_nelem, bkc_idx; ++ Idx node_idx = nodes->elems[i]; ++ unsigned int context; ++ const re_token_t *node = dfa->nodes + node_idx; ++ re_node_set *new_dest_nodes; ++ ++ /* Check whether 'node' is a backreference or not. */ ++ if (node->type != OP_BACK_REF) ++ continue; ++ ++ if (node->constraint) { ++ context = re_string_context_at(&mctx->input, cur_str_idx, ++ mctx->eflags); ++ if (NOT_SATISFY_NEXT_CONSTRAINT(node->constraint, context)) ++ continue; ++ } ++ ++ /* 'node' is a backreference. ++ Check the substring which the substring matched. */ ++ bkc_idx = mctx->nbkref_ents; ++ err = get_subexp(mctx, node_idx, cur_str_idx); ++ if ((err != REG_NOERROR)) ++ goto free_return; ++ ++ /* And add the epsilon closures (which is 'new_dest_nodes') of ++ the backreference to appropriate state_log. */ ++ ++ for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) { ++ Idx subexp_len; ++ re_dfastate_t *dest_state; ++ struct re_backref_cache_entry *bkref_ent; ++ bkref_ent = mctx->bkref_ents + bkc_idx; ++ if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) ++ continue; ++ subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; ++ new_dest_nodes = (subexp_len == 0 ++ ? dfa->eclosures + dfa->edests[node_idx].elems[0] ++ : dfa->eclosures + dfa->nexts[node_idx]); ++ dest_str_idx = (cur_str_idx + bkref_ent->subexp_to ++ - bkref_ent->subexp_from); ++ context = re_string_context_at(&mctx->input, dest_str_idx - 1, ++ mctx->eflags); ++ dest_state = mctx->state_log[dest_str_idx]; ++ prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 ++ : mctx->state_log[cur_str_idx]->nodes.nelem); ++ /* Add 'new_dest_node' to state_log. */ ++ if (dest_state == NULL) { ++ mctx->state_log[dest_str_idx] ++ = re_acquire_state_context(&err, dfa, new_dest_nodes, ++ context); ++ if ((mctx->state_log[dest_str_idx] == NULL ++ && err != REG_NOERROR)) ++ goto free_return; ++ } else { ++ re_node_set dest_nodes; ++ err = re_node_set_init_union(&dest_nodes, ++ dest_state->entrance_nodes, ++ new_dest_nodes); ++ if ((err != REG_NOERROR)) { ++ re_node_set_free(&dest_nodes); ++ goto free_return; ++ } ++ mctx->state_log[dest_str_idx] ++ = re_acquire_state_context(&err, dfa, &dest_nodes, context); ++ re_node_set_free(&dest_nodes); ++ if ((mctx->state_log[dest_str_idx] == NULL ++ && err != REG_NOERROR)) ++ goto free_return; ++ } ++ /* We need to check recursively if the backreference can epsilon ++ transit. */ ++ if (subexp_len == 0 ++ && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) { ++ err = check_subexp_matching_top(mctx, new_dest_nodes, ++ cur_str_idx); ++ if ((err != REG_NOERROR)) ++ goto free_return; ++ err = transit_state_bkref(mctx, new_dest_nodes); ++ if ((err != REG_NOERROR)) ++ goto free_return; ++ } ++ } ++ } ++ err = REG_NOERROR; ++ free_return: ++ return err; ++} ++ ++/* Return the next state to which the current state STATE will transit by ++ accepting the current input byte, and update STATE_LOG if necessary. ++ If STATE can accept a multibyte char/collating element/back reference ++ update the destination of STATE_LOG. */ ++ ++static re_dfastate_t * ++ ++transit_state(reg_errcode_t ++ *err, ++ re_match_context_t *mctx, ++ re_dfastate_t ++ *state) { ++ re_dfastate_t **trtable; ++ unsigned char ch; ++ ++/* Use transition table */ ++ ch = re_string_fetch_byte(&mctx->input); ++ for (;;) { ++ trtable = state->trtable; ++ if ((trtable != NULL)) ++ return trtable[ch]; ++ ++ trtable = state->word_trtable; ++ if ((trtable != NULL)) { ++ unsigned int context; ++ context ++ = re_string_context_at(&mctx->input, ++ re_string_cur_idx(&mctx->input) - 1, ++ mctx->eflags); ++ if ( ++ IS_WORD_CONTEXT(context) ++ ) ++ return trtable[ch + SBC_MAX]; ++ else ++ return trtable[ch]; ++ } ++ ++ if (! ++ build_trtable(mctx ++ ->dfa, state)) { ++ * ++ err = REG_ESPACE; ++ return ++ NULL; ++ } ++ ++/* Retry, we now have a transition table. */ ++ } ++} ++ ++/* Update the state_log if we need */ ++static re_dfastate_t * ++merge_state_with_log(reg_errcode_t *err, re_match_context_t *mctx, ++ re_dfastate_t *next_state) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ Idx cur_idx = re_string_cur_idx(&mctx->input); ++ ++ if (cur_idx > mctx->state_log_top) { ++ mctx->state_log[cur_idx] = next_state; ++ mctx->state_log_top = cur_idx; ++ } else if (mctx->state_log[cur_idx] == 0) { ++ mctx->state_log[cur_idx] = next_state; ++ } else { ++ re_dfastate_t *pstate; ++ unsigned int context; ++ re_node_set next_nodes, *log_nodes, *table_nodes = NULL; ++ /* If (state_log[cur_idx] != 0), it implies that cur_idx is ++ the destination of a multibyte char/collating element/ ++ back reference. Then the next state is the union set of ++ these destinations and the results of the transition table. */ ++ pstate = mctx->state_log[cur_idx]; ++ log_nodes = pstate->entrance_nodes; ++ if (next_state != NULL) { ++ table_nodes = next_state->entrance_nodes; ++ *err = re_node_set_init_union(&next_nodes, table_nodes, ++ log_nodes); ++ if ((*err != REG_NOERROR)) ++ return NULL; ++ } else ++ next_nodes = *log_nodes; ++ /* Note: We already add the nodes of the initial state, ++ then we don't need to add them here. */ ++ ++ context = re_string_context_at(&mctx->input, ++ re_string_cur_idx(&mctx->input) - 1, ++ mctx->eflags); ++ next_state = mctx->state_log[cur_idx] ++ = re_acquire_state_context(err, dfa, &next_nodes, context); ++ /* We don't need to check errors here, since the return value of ++ this function is next_state and ERR is already set. */ ++ ++ if (table_nodes != NULL) ++ re_node_set_free(&next_nodes); ++ } ++ ++ if ((dfa->nbackref) && next_state != NULL) { ++ /* Check OP_OPEN_SUBEXP in the current state in case that we use them ++ later. We must check them here, since the back references in the ++ next state might use them. */ ++ *err = check_subexp_matching_top(mctx, &next_state->nodes, ++ cur_idx); ++ if ((*err != REG_NOERROR)) ++ return NULL; ++ ++ /* If the next state has back references. */ ++ if (next_state->has_backref) { ++ *err = transit_state_bkref(mctx, &next_state->nodes); ++ if ((*err != REG_NOERROR)) ++ return NULL; ++ next_state = mctx->state_log[cur_idx]; ++ } ++ } ++ ++ return next_state; ++} ++ ++/* Skip bytes in the input that correspond to part of a ++ multi-byte match, then look in the log for a state ++ from which to restart matching. */ ++static re_dfastate_t * ++find_recover_state(reg_errcode_t *err, re_match_context_t *mctx) { ++ re_dfastate_t *cur_state; ++ do { ++ Idx max = mctx->state_log_top; ++ Idx cur_str_idx = re_string_cur_idx(&mctx->input); ++ ++ do { ++ if (++cur_str_idx > max) ++ return NULL; ++ re_string_skip_bytes(&mctx->input, 1); ++ } while (mctx->state_log[cur_str_idx] == NULL); ++ ++ cur_state = merge_state_with_log(err, mctx, NULL); ++ } while (*err == REG_NOERROR && cur_state == NULL); ++ return cur_state; ++} ++ ++/* Functions for matching context. */ ++ ++/* Initialize MCTX. */ ++ ++static reg_errcode_t ++match_ctx_init(re_match_context_t *mctx, int eflags, Idx n) { ++ mctx->eflags = eflags; ++ mctx->match_last = -1; ++ if (n > 0) { ++/* Avoid overflow. */ ++ size_t max_object_size = ++ MAX (sizeof(struct re_backref_cache_entry), ++ sizeof(re_sub_match_top_t * )); ++ if ((MIN (IDX_MAX, SIZE_MAX / max_object_size) < n)) ++ return REG_ESPACE; ++ ++ mctx->bkref_ents = re_malloc( ++ struct re_backref_cache_entry, n); ++ mctx->sub_tops = re_malloc(re_sub_match_top_t * , n); ++ if ((mctx->bkref_ents == NULL || mctx->sub_tops == NULL)) ++ return REG_ESPACE; ++ } ++/* Already zero-ed by the caller. ++ else ++ mctx->bkref_ents = NULL; ++ mctx->nbkref_ents = 0; ++ mctx->nsub_tops = 0; */ ++ mctx->abkref_ents = n; ++ mctx->max_mb_elem_len = 1; ++ mctx->asub_tops = n; ++ return REG_NOERROR; ++} ++ ++/* Clean the entries which depend on the current input in MCTX. ++ This function must be invoked when the matcher changes the start index ++ of the input, or changes the input string. */ ++ ++static void ++match_ctx_clean(re_match_context_t *mctx) { ++ Idx st_idx; ++ for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) { ++ Idx sl_idx; ++ re_sub_match_top_t *top = mctx->sub_tops[st_idx]; ++ for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx) { ++ re_sub_match_last_t *last = top->lasts[sl_idx]; ++ re_free(last->path.array); ++ re_free(last); ++ } ++ re_free(top->lasts); ++ if (top->path) { ++ re_free(top->path->array); ++ re_free(top->path); ++ } ++ re_free(top); ++ } ++ ++ mctx->nsub_tops = 0; ++ mctx->nbkref_ents = 0; ++} ++ ++/* Free all the memory associated with MCTX. */ ++ ++static void ++match_ctx_free(re_match_context_t *mctx) { ++ /* First, free all the memory associated with MCTX->SUB_TOPS. */ ++ match_ctx_clean(mctx); ++ re_free(mctx->sub_tops); ++ re_free(mctx->bkref_ents); ++} ++ ++/* Add a new backreference entry to MCTX. ++ Note that we assume that caller never call this function with duplicate ++ entry, and call with STR_IDX which isn't smaller than any existing entry. ++*/ ++ ++static reg_errcode_t ++ ++match_ctx_add_entry(re_match_context_t *mctx, Idx node, Idx str_idx, Idx from, ++ Idx to) { ++ if (mctx->nbkref_ents >= mctx->abkref_ents) { ++ struct re_backref_cache_entry *new_entry; ++ new_entry = re_realloc(mctx->bkref_ents, ++ struct re_backref_cache_entry, ++ mctx->abkref_ents * 2); ++ if ((new_entry == NULL)) { ++ re_free(mctx->bkref_ents); ++ return REG_ESPACE; ++ } ++ mctx->bkref_ents = new_entry; ++ memset(mctx->bkref_ents + mctx->nbkref_ents, '\0', ++ sizeof(struct re_backref_cache_entry) * mctx->abkref_ents); ++ mctx->abkref_ents *= 2; ++ } ++ if (mctx->nbkref_ents > 0 ++ && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx) ++ mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1; ++ ++ mctx->bkref_ents[mctx->nbkref_ents].node = node; ++ mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; ++ mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; ++ mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; ++ ++/* This is a cache that saves negative results of check_dst_limits_calc_pos. ++ If bit N is clear, means that this entry won't epsilon-transition to ++ an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If ++ it is set, check_dst_limits_calc_pos_1 will recurse and try to find one ++ such node. ++ ++ A backreference does not epsilon-transition unless it is empty, so set ++ to all zeros if FROM != TO. */ ++ mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map ++ = (from == to ? -1 : 0); ++ ++ mctx->bkref_ents[mctx->nbkref_ents++].more = 0; ++ if (mctx->max_mb_elem_len < to - from) ++ mctx->max_mb_elem_len = to - from; ++ return REG_NOERROR; ++} ++ ++/* Check whether the regular expression match input string INPUT or not, ++ and return the index where the matching end. Return -1 if ++ there is no match, and return -2 in case of an error. ++ FL_LONGEST_MATCH means we want the POSIX longest matching. ++ If P_MATCH_FIRST is not NULL, and the match fails, it is set to the ++ next place where we may want to try matching. ++ Note that the matcher assumes that the matching starts from the current ++ index of the buffer. */ ++ ++static Idx ++check_matching(re_match_context_t *mctx, bool fl_longest_match, ++ Idx *p_match_first) { ++ const re_dfa_t *const dfa = mctx->dfa; ++ reg_errcode_t err; ++ Idx match = 0; ++ Idx match_last = -1; ++ Idx cur_str_idx = re_string_cur_idx(&mctx->input); ++ re_dfastate_t *cur_state; ++ bool at_init_state = p_match_first != NULL; ++ Idx next_start_idx = cur_str_idx; ++ ++ err = REG_NOERROR; ++ cur_state = acquire_init_state_context(&err, mctx, cur_str_idx); ++/* An initial state must not be NULL (invalid). */ ++ if ((cur_state == NULL)) { ++ assert(err == REG_ESPACE); ++ return -2; ++ } ++ ++ if (mctx->state_log != NULL) { ++ mctx->state_log[cur_str_idx] = cur_state; ++ ++/* Check OP_OPEN_SUBEXP in the initial state in case that we use them ++later. E.g. Processing back references. */ ++ if ((dfa->nbackref)) { ++ at_init_state = false; ++ err = check_subexp_matching_top(mctx, &cur_state->nodes, 0); ++ if ((err != REG_NOERROR)) ++ return err; ++ ++ if (cur_state->has_backref) { ++ err = transit_state_bkref(mctx, &cur_state->nodes); ++ if ((err != REG_NOERROR)) ++ return err; ++ } ++ } ++ } ++ ++/* If the RE accepts NULL string. */ ++ if ((cur_state->halt)) { ++ if (!cur_state->has_constraint ++ || check_halt_state_context(mctx, cur_state, cur_str_idx)) { ++ if (!fl_longest_match) ++ return cur_str_idx; ++ else { ++ match_last = cur_str_idx; ++ match = 1; ++ } ++ } ++ } ++ ++ while (!re_string_eoi(&mctx->input)) { ++ re_dfastate_t *old_state = cur_state; ++ Idx next_char_idx = re_string_cur_idx(&mctx->input) + 1; ++ ++ if (((next_char_idx >= mctx->input.bufs_len) ++ && mctx->input.bufs_len < mctx->input.len) ++ || ((next_char_idx >= mctx->input.valid_len) ++ && mctx->input.valid_len < mctx->input.len)) { ++ err = extend_buffers(mctx, next_char_idx + 1); ++ if ((err != REG_NOERROR)) { ++ assert(err == REG_ESPACE); ++ return -2; ++ } ++ } ++ ++ cur_state = transit_state(&err, mctx, cur_state); ++ if (mctx->state_log != NULL) ++ cur_state = merge_state_with_log(&err, mctx, cur_state); ++ ++ if (cur_state == NULL) { ++/* Reached the invalid state or an error. Try to recover a valid ++ state using the state log, if available and if we have not ++ already found a valid (even if not the longest) match. */ ++ if ((err != REG_NOERROR)) ++ return -2; ++ ++ if (mctx->state_log == NULL ++ || (match && !fl_longest_match) ++ || (cur_state = find_recover_state(&err, mctx)) == NULL) ++ break; ++ } ++ ++ if ((at_init_state)) { ++ if (old_state == cur_state) ++ next_start_idx = next_char_idx; ++ else ++ at_init_state = false; ++ } ++ ++ if (cur_state->halt) { ++/* Reached a halt state. ++ Check the halt state can satisfy the current context. */ ++ if (!cur_state->has_constraint ++ || check_halt_state_context(mctx, cur_state, ++ re_string_cur_idx(&mctx->input))) { ++/* We found an appropriate halt state. */ ++ match_last = re_string_cur_idx(&mctx->input); ++ match = 1; ++ ++/* We found a match, do not modify match_first below. */ ++ p_match_first = NULL; ++ if (!fl_longest_match) ++ break; ++ } ++ } ++ } ++ ++ if (p_match_first) ++ *p_match_first += next_start_idx; ++ ++ return match_last; ++} ++ ++/* Searches for a compiled pattern PREG in the string STRING, whose ++ length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same ++ meaning as with regexec. LAST_START is START + RANGE, where ++ START and RANGE have the same meaning as with re_search. ++ Return REG_NOERROR if we find a match, and REG_NOMATCH if not, ++ otherwise return the error code. ++ Note: We assume front end functions already check ranges. ++ (0 <= LAST_START && LAST_START <= LENGTH) */ ++ ++static reg_errcode_t ++re_search_internal(const regex_t *preg, const char *string, Idx length, ++ Idx start, Idx last_start, Idx stop, size_t nmatch, ++ regmatch_t pmatch[], int eflags) { ++ reg_errcode_t err; ++ const re_dfa_t *dfa = preg->buffer; ++ Idx left_lim, right_lim; ++ int incr; ++ bool fl_longest_match; ++ int match_kind; ++ Idx match_first; ++ Idx match_last = -1; ++ Idx extra_nmatch; ++ bool sb; ++ int ch; ++ re_match_context_t mctx; ++ char *fastmap = ((preg->fastmap != NULL && preg->fastmap_accurate ++ && start != last_start && !preg->can_be_null) ++ ? preg->fastmap : NULL); ++ RE_TRANSLATE_TYPE t = preg->translate; ++ ++ memset(&mctx, '\0', sizeof(re_match_context_t)); ++ mctx.dfa = dfa; ++ ++ ++ extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0; ++ nmatch -= extra_nmatch; ++ ++ /* Check if the DFA haven't been compiled. */ ++ if ((preg->used == 0 || dfa->init_state == NULL ++ || dfa->init_state_word == NULL ++ || dfa->init_state_nl == NULL ++ || dfa->init_state_begbuf == NULL)) ++ return REG_NOMATCH; ++ ++ /* If initial states with non-begbuf contexts have no elements, ++ the regex must be anchored. If preg->newline_anchor is set, ++ we'll never use init_state_nl, so do not check it. */ ++ if (dfa->init_state->nodes.nelem == 0 ++ && dfa->init_state_word->nodes.nelem == 0 ++ && (dfa->init_state_nl->nodes.nelem == 0 ++ || !preg->newline_anchor)) { ++ if (start != 0 && last_start != 0) ++ return REG_NOMATCH; ++ start = last_start = 0; ++ } ++ ++ /* We must check the longest matching, if nmatch > 0. */ ++ fl_longest_match = (nmatch != 0 || dfa->nbackref); ++ ++ err = re_string_allocate(&mctx.input, string, length, dfa->nodes_len + 1, ++ preg->translate, (preg->syntax & RE_ICASE) != 0, ++ dfa); ++ if ((err != REG_NOERROR)) ++ goto free_return; ++ mctx.input.stop = stop; ++ mctx.input.raw_stop = stop; ++ mctx.input.newline_anchor = preg->newline_anchor; ++ ++ err = match_ctx_init(&mctx, eflags, dfa->nbackref * 2); ++ if ((err != REG_NOERROR)) ++ goto free_return; ++ ++ /* We will log all the DFA states through which the dfa pass, ++ if nmatch > 1, or this dfa has "multibyte node", which is a ++ back-reference or a node which can accept multibyte character or ++ multi character collating element. */ ++ if (nmatch > 1 || dfa->has_mb_node) { ++ /* Avoid overflow. */ ++ if (((MIN (IDX_MAX, SIZE_MAX / sizeof(re_dfastate_t * )) ++ <= mctx.input.bufs_len))) { ++ err = REG_ESPACE; ++ goto free_return; ++ } ++ ++ mctx.state_log = re_malloc(re_dfastate_t * , mctx.input.bufs_len + 1); ++ if ((mctx.state_log == NULL)) { ++ err = REG_ESPACE; ++ goto free_return; ++ } ++ } else ++ mctx.state_log = NULL; ++ ++ match_first = start; ++ mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF ++ : CONTEXT_NEWLINE | CONTEXT_BEGBUF; ++ ++ /* Check incrementally whether the input string matches. */ ++ incr = (last_start < start) ? -1 : 1; ++ left_lim = (last_start < start) ? last_start : start; ++ right_lim = (last_start < start) ? start : last_start; ++ sb = dfa->mb_cur_max == 1; ++ match_kind = ++ (fastmap ++ ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) ++ | (start <= last_start ? 2 : 0) ++ | (t != NULL ? 1 : 0)) ++ : 8); ++ ++ for (;; match_first += incr) { ++ err = REG_NOMATCH; ++ if (match_first < left_lim || right_lim < match_first) ++ goto free_return; ++ ++ /* Advance as rapidly as possible through the string, until we ++ find a plausible place to start matching. This may be done ++ with varying efficiency, so there are various possibilities: ++ only the most common of them are specialized, in order to ++ save on code size. We use a switch statement for speed. */ ++ switch (match_kind) { ++ case 8: ++ /* No fastmap. */ ++ break; ++ ++ case 7: ++ /* Fastmap with single-byte translation, match forward. */ ++ while ((match_first < right_lim) ++ && !fastmap[t[(unsigned char) string[match_first]]]) ++ ++match_first; ++ goto forward_match_found_start_or_reached_end; ++ ++ case 6: ++ /* Fastmap without translation, match forward. */ ++ while ((match_first < right_lim) ++ && !fastmap[(unsigned char) string[match_first]]) ++ ++match_first; ++ ++ forward_match_found_start_or_reached_end: ++ if ((match_first == right_lim)) { ++ ch = match_first >= length ++ ? 0 : (unsigned char) string[match_first]; ++ if (!fastmap[t ? t[ch] : ch]) ++ goto free_return; ++ } ++ break; ++ ++ case 4: ++ case 5: ++ /* Fastmap without multi-byte translation, match backwards. */ ++ while (match_first >= left_lim) { ++ ch = match_first >= length ++ ? 0 : (unsigned char) string[match_first]; ++ if (fastmap[t ? t[ch] : ch]) ++ break; ++ --match_first; ++ } ++ if (match_first < left_lim) ++ goto free_return; ++ break; ++ ++ default: ++ /* In this case, we can't determine easily the current byte, ++ since it might be a component byte of a multibyte ++ character. Then we use the constructed buffer instead. */ ++ for (;;) { ++ /* If MATCH_FIRST is out of the valid range, reconstruct the ++ buffers. */ ++ __re_size_t offset = match_first - mctx.input.raw_mbs_idx; ++ if ((offset ++ >= (__re_size_t) mctx.input.valid_raw_len)) { ++ err = re_string_reconstruct(&mctx.input, match_first, ++ eflags); ++ if ((err != REG_NOERROR)) ++ goto free_return; ++ ++ offset = match_first - mctx.input.raw_mbs_idx; ++ } ++ /* If MATCH_FIRST is out of the buffer, leave it as '\0'. ++ Note that MATCH_FIRST must not be smaller than 0. */ ++ ch = (match_first >= length ++ ? 0 : re_string_byte_at(&mctx.input, offset)); ++ if (fastmap[ch]) ++ break; ++ match_first += incr; ++ if (match_first < left_lim || match_first > right_lim) { ++ err = REG_NOMATCH; ++ goto free_return; ++ } ++ } ++ break; ++ } ++ ++ /* Reconstruct the buffers so that the matcher can assume that ++ the matching starts from the beginning of the buffer. */ ++ err = re_string_reconstruct(&mctx.input, match_first, eflags); ++ if ((err != REG_NOERROR)) ++ goto free_return; ++ ++ /* It seems to be appropriate one, then use the matcher. */ ++ /* We assume that the matching starts from 0. */ ++ mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; ++ match_last = check_matching(&mctx, fl_longest_match, ++ start <= last_start ? &match_first : NULL); ++ if (match_last != -1) { ++ if ((match_last == -2)) { ++ err = REG_ESPACE; ++ goto free_return; ++ } else { ++ mctx.match_last = match_last; ++ if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) { ++ re_dfastate_t *pstate = mctx.state_log[match_last]; ++ mctx.last_node = check_halt_state_context(&mctx, pstate, ++ match_last); ++ } ++ if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) ++ || dfa->nbackref) { ++ err = prune_impossible_nodes(&mctx); ++ if (err == REG_NOERROR) ++ break; ++ if ((err != REG_NOMATCH)) ++ goto free_return; ++ match_last = -1; ++ } else ++ break; /* We found a match. */ ++ } ++ } ++ ++ match_ctx_clean(&mctx); ++ } ++ ++ /* Set pmatch[] if we need. */ ++ if (nmatch > 0) { ++ Idx reg_idx; ++ ++ /* Initialize registers. */ ++ for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) ++ pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; ++ ++ /* Set the points where matching start/end. */ ++ pmatch[0].rm_so = 0; ++ pmatch[0].rm_eo = mctx.match_last; ++ /* FIXME: This function should fail if mctx.match_last exceeds ++ the maximum possible regoff_t value. We need a new error ++ code REG_OVERFLOW. */ ++ ++ if (!preg->no_sub && nmatch > 1) { ++ err = set_regs(preg, &mctx, nmatch, pmatch, ++ dfa->has_plural_match && dfa->nbackref > 0); ++ if ((err != REG_NOERROR)) ++ goto free_return; ++ } ++ ++ /* At last, add the offset to each register, since we slid ++ the buffers so that we could assume that the matching starts ++ from 0. */ ++ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) ++ if (pmatch[reg_idx].rm_so != -1) { ++ pmatch[reg_idx].rm_so += match_first; ++ pmatch[reg_idx].rm_eo += match_first; ++ } ++ for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx) { ++ pmatch[nmatch + reg_idx].rm_so = -1; ++ pmatch[nmatch + reg_idx].rm_eo = -1; ++ } ++ ++ if (dfa->subexp_map) ++ for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++) ++ if (dfa->subexp_map[reg_idx] != reg_idx) { ++ pmatch[reg_idx + 1].rm_so ++ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so; ++ pmatch[reg_idx + 1].rm_eo ++ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo; ++ } ++ } ++ ++ free_return: ++ re_free(mctx.state_log); ++ if (dfa->nbackref) ++ match_ctx_free(&mctx); ++ re_string_destruct(&mctx.input); ++ return err; ++} ++ ++/* Helper functions. */ ++ ++static reg_errcode_t ++merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, ++ re_dfastate_t **src, Idx num) ++{ ++ Idx st_idx; ++ reg_errcode_t err; ++ for (st_idx = 0; st_idx < num; ++st_idx) ++ { ++ if (dst[st_idx] == NULL) ++ dst[st_idx] = src[st_idx]; ++ else if (src[st_idx] != NULL) ++ { ++ re_node_set merged_set; ++ err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, ++ &src[st_idx]->nodes); ++ if ( (err != REG_NOERROR)) ++ return err; ++ dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); ++ re_node_set_free (&merged_set); ++ if ( (err != REG_NOERROR)) ++ return err; ++ } ++ } ++ return REG_NOERROR; ++} ++ ++static void ++sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, ++ re_dfastate_t **limited_sts, Idx last_node, Idx last_str_idx) ++{ ++ sctx->sifted_states = sifted_sts; ++ sctx->limited_states = limited_sts; ++ sctx->last_node = last_node; ++ sctx->last_str_idx = last_str_idx; ++ re_node_set_init_empty (&sctx->limits); ++} ++ ++ ++/* regexec searches for a given pattern, specified by PREG, in the ++ string STRING. ++ ++ If NMATCH is zero or REG_NOSUB was set in the cflags argument to ++ 'regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at ++ least NMATCH elements, and we set them to the offsets of the ++ corresponding matched substrings. ++ ++ EFLAGS specifies "execution flags" which affect matching: if ++ REG_NOTBOL is set, then ^ does not match at the beginning of the ++ string; if REG_NOTEOL is set, then $ does not match at the end. ++ ++ We return 0 if we find a match and REG_NOMATCH if not. */ ++ ++int ++regexec(const regex_t *_Restrict_ preg, const char *_Restrict_ string, ++ size_t nmatch, regmatch_t pmatch[], int eflags) { ++ reg_errcode_t err; ++ Idx start, length; ++ re_dfa_t *dfa = preg->buffer; ++ ++ if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) ++ return REG_BADPAT; ++ ++ if (eflags & REG_STARTEND) { ++ start = pmatch[0].rm_so; ++ length = pmatch[0].rm_eo; ++ } else { ++ start = 0; ++ length = strlen(string); ++ } ++ ++ lock_lock(dfa->lock); ++ if (preg->no_sub) ++ err = re_search_internal(preg, string, length, start, length, ++ length, 0, NULL, eflags); ++ else ++ err = re_search_internal(preg, string, length, start, length, ++ length, nmatch, pmatch, eflags); ++ lock_unlock(dfa->lock); ++ return err != REG_NOERROR; ++} ++ ++#endif +diff --git a/wait.h b/wait.h +index 7408d15..3bea227 100644 +--- a/wait.h ++++ b/wait.h +@@ -26,3 +26,7 @@ + ++#ifdef HAVE_SYS_WAIT_H + #include ++#else ++#include "headers-mingw/sys_wait.h" ++#endif + diff --git a/mingw-w64-bmake/0002-enable-debug-output-on-test.patch b/mingw-w64-bmake/0002-enable-debug-output-on-test.patch new file mode 100644 index 0000000000..2ea8924a70 --- /dev/null +++ b/mingw-w64-bmake/0002-enable-debug-output-on-test.patch @@ -0,0 +1,13 @@ +diff --git a/boot-strap b/boot-strap +index 28d8bf7..6e3aa6c 100644 +--- a/boot-strap ++++ a/boot-strap +@@ -391,7 +391,7 @@ + cd $Mydir && + MAKESYSPATH=$mksrc SRCTOP=$Mydir OBJTOP=$objdir \ + MAKEOBJDIR='${.CURDIR:S,${SRCTOP:tA},${OBJTOP:tA},}' \ +- ${BMAKE:-$objdir/bmake} -f $Mydir/Makefile "$@" ++ ${BMAKE:-$objdir/bmake} -B -f $Mydir/Makefile "$@" + ) + } + diff --git a/mingw-w64-bmake/0003-print-pwd-on-fail-install.patch b/mingw-w64-bmake/0003-print-pwd-on-fail-install.patch new file mode 100644 index 0000000000..4960d4cf0e --- /dev/null +++ b/mingw-w64-bmake/0003-print-pwd-on-fail-install.patch @@ -0,0 +1,22 @@ +diff --git a/install-sh b/install-sh +index 28d8bf7..6e3aa6c 100644 +--- a/install-sh ++++ b/install-sh +@@ -41,6 +41,8 @@ + # This script is compatible with the BSD install script, but was written + # from scratch. + ++dir=`pwd` ++ + tab=' ' + nl=' + ' +@@ -262,6 +264,7 @@ + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 ++ echo "we on $PWD" >&2 + exit 1 + fi + + diff --git a/mingw-w64-bmake/PKGBUILD b/mingw-w64-bmake/PKGBUILD new file mode 100644 index 0000000000..bb2c340f28 --- /dev/null +++ b/mingw-w64-bmake/PKGBUILD @@ -0,0 +1,74 @@ +# Maintainer: Ivy Foster +# Contributor: Alex Szczuczko +# Contributor: Devin Cofer +# Contributor: Imanol Celaya +# Windows port: Timofey Denisov + +_realname=bmake +pkgbase=mingw-w64-${_realname} +pkgname="${MINGW_PACKAGE_PREFIX}-${_realname}" +pkgver=20181221 +pkgrel=1 +pkgdesc='Portable version of the NetBSD make build tool' +arch=('any') +url='http://www.crufty.net/help/sjg/bmake.html' +license=(BSD) + +# upstream recommends using python for improved meta2deps script +depends=("${MINGW_PACKAGE_PREFIX}-binutils" + "${MINGW_PACKAGE_PREFIX}-python" + "${MINGW_PACKAGE_PREFIX}-libiconv") +makedepends=("${MINGW_PACKAGE_PREFIX}-gcc" + "${MINGW_PACKAGE_PREFIX}-make" + "${MINGW_PACKAGE_PREFIX}-libiconv") + +source=("http://www.crufty.net/ftp/pub/sjg/bmake-$pkgver.tar.gz" + 0001-first-version-mingw-patch.patch + 0002-enable-debug-output-on-test.patch + 0003-print-pwd-on-fail-install.patch +) +# checksum source: http://www.crufty.net/ftp/pub/sjg/bmake-$pkgver.tar.gz.sha1 +sha1sums=('ce7db05c68e2fbad41d1dd92ec110406093293bd' + 'SKIP' + 'SKIP' + 'SKIP' +) + +prepare() { + cd "${srcdir}"/bmake + patch -p1 -l -i "${srcdir}"/0001-first-version-mingw-patch.patch + patch -p1 -l -i "${srcdir}"/0002-enable-debug-output-on-test.patch + patch -p1 -l -i "${srcdir}"/0003-print-pwd-on-fail-install.patch +} + +build() { + cd "${srcdir}"/bmake + export SYSROOTWINDOWSPATH=$(cygpath -w /) + aclocal --verbose || die "aclocal failed" + autoreconf --verbose || die "autoreconf failed" + bash -x ./boot-strap --prefix=${MINGW_PREFIX} op=build +} + +# op=build also runs unit tests; thus no check() + +package() { + cd "${srcdir}"/bmake + + export SYSROOTWINDOWSPATH=$(cygpath -w /) + + # Fix directory permissions on install + # install -Dm644 "${pkgdir}${MINGW_PREFIX}/bin" "${pkgdir}${MINGW_PREFIX}/share/licenses/$pkgname" + + bash -x ./boot-strap --install-destdir="${pkgdir}" --prefix=${MINGW_PREFIX} op=install + + rm -rf "${pkgdir}${MINGW_PREFIX}/share/man/cat1" + install -Dm644 bmake.1 "${pkgdir}${MINGW_PREFIX}/share/man/man1/bmake.1" + + mkdir -p "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}" + head -n70 main.c > "${pkgdir}${MINGW_PREFIX}/share/licenses/${_realname}/LICENSE" + + # install profile script + mkdir -p "${pkgdir}${MINGW_PREFIX}"/etc/profile.d + echo "export SYSROOTWINDOWSPATH=$(cygpath -w /)" > "${pkgdir}${MINGW_PREFIX}"/etc/profile.d/bmake.sh + cp "${pkgdir}${MINGW_PREFIX}"/etc/profile.d/bmake.{sh,zsh} +} \ No newline at end of file