blob: e24d6a009131435d4e0195f595509fcfac1cbebd [file] [log] [blame] [edit]
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 <sys/stat.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/sys_stat.h"
+#endif
#include <sys/time.h>
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 <sys/types.h>
#include <sys/stat.h>
+
+#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 <signal.h>
+
+#if (defined _WIN32 && !defined __CYGWIN__)
+#include "headers-mingw/signal.h"
+#endif
+#ifndef SIGQUIT
+#define SIGQUIT SIGTERM
+#endif
+
#include <stdio.h>
@@ -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 <ar.h> 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 <fcntl.h> 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 <inttypes.h> 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 <libgen.h> 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 <memory.h> 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 <paths.h> 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 <poll.h> 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 <ranlib.h> 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 <stdint.h> 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 <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
/* Define to 1 if you have the <sys/select.h> header file. */
@@ -190,5 +472,17 @@
-/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#undef HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <sys/wait.h> 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 <unistd.h> 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 <utime.h> 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 <sys/types.h> 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 </dev/null 6>&1
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&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<library>
- CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
you have headers in a nonstandard directory <include dir>
@@ -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 <stdio.h>
+
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 <stdio.h>
+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 <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+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 <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+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 2>/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 <sys/stat.h>
+#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 <fcntl.h>, 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 <https://www.gnu.org/licenses/>. */
+
+/* written by Paul Eggert */
+
+/* Normal invocation convention. */
+
+#ifndef _GL_FCNTL_H
+#define _GL_FCNTL_H
+
+#ifndef __GLIBC__ /* Avoid namespace pollution on glibc systems. */
+# include <unistd.h>
+#endif
+
+/* Native Windows platforms declare open(), creat() in <io.h>. */
+#if (defined _WIN32 && ! defined __CYGWIN__)
+# include <io.h>
+#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 <https://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+#ifndef _GL_INTPROPS_H
+#define _GL_INTPROPS_H
+
+#include <limits.h>
+
+/* 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
+ <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>. */
+#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_<op>_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_<op>_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
+ <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00401.html>. */
+#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_<op>_OVERFLOW macros return 1 if the corresponding C operators
+ might not yield numerically correct answers due to arithmetic overflow.
+ The INT_<op>_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 <op> 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 <op> 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 <op> 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 <op> 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 <langinfo.h>.
+ 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 <https://www.gnu.org/licenses/>. */
+
+/*
+ * POSIX <langinfo.h> for platforms that lack it or have an incomplete one.
+ * <http://www.opengroup.org/onlinepubs/9699919799/basedefs/langinfo.h.html>
+ */
+
+#ifndef _GL_LANGINFO_H
+#define _GL_LANGINFO_H
+
+
+/* A platform that lacks <langinfo.h>. */
+
+/* Assume that it also lacks <nl_types.h> 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
+ <https://www.gnu.org/licenses/>. */
+
+/* Written by Paul Eggert. */
+
+/* This is intended to be a good-enough substitute for glibc system
+ macros like those defined in <sys/cdefs.h>, so that Gnulib code
+ shared with glibc can do this as the first #include:
+
+ #ifndef _LIBC
+ # include <libc-config.h>
+ #endif
+
+ When compiled as part of glibc this is a no-op; when compiled as
+ part of Gnulib this includes Gnulib's <config.h> and defines macros
+ that glibc library code would normally assume. */
+
+#include <config.h>
+
+/* On glibc this includes <features.h> and <sys/cdefs.h> and #defines
+ _FEATURES_H, __WORDSIZE, and __set_errno. On FreeBSD 11 it
+ includes <sys/cdefs.h> which defines __nonnull. Elsewhere it
+ is harmless. */
+#include <errno.h>
+
+/* From glibc <errno.h>. */
+#ifndef __set_errno
+# define __set_errno(val) (errno = (val))
+#endif
+
+/* From glibc <features.h>. */
+
+#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 <cdefs.h>, which is our copy of glibc
+ <sys/cdefs.h>. */
+
+/* Define _FEATURES_H so that <cdefs.h> does not include <features.h>. */
+#ifndef _FEATURES_H
+# define _FEATURES_H 1
+#endif
+/* Define __WORDSIZE so that <cdefs.h> 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
+ <sys/cdefs.h>, 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 <sys/cdefs.h>. */
+#include "sys_cdefs.h"
+
+/* <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 <libc-symbols.h>, 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 <shlib-compat.h>, 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 <https://www.gnu.org/licenses/>. */
+
+#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 <winsock2.h>
+# 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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _REGEX_H
+#define _REGEX_H 1
+
+#include <sys/types.h>
+
+/* 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 \<digit> matches <digit>.
+ If not set, then \<digit> 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 <isamu@yamato.ibm.com>.
+
+ 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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _REGEX_INTERNAL_H
+#define _REGEX_INTERNAL_H 1
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "langinfo.h"
+#include <locale.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "intprops.h"
+
+#ifdef _LIBC
+# include <libc-lock.h>
+# 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 <pthread.h>
+# 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 <alloca.h>
+#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 <sys/resource.h>.
+ 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 <https://www.gnu.org/licenses/>. */
+
+#ifndef _GL_SYS_RESOURCE_H
+#define _GL_SYS_RESOURCE_H
+
+#if !HAVE_SYS_RESOURCE_H
+/* A platform that lacks <sys/resource.h>. */
+
+/* Get 'struct timeval'. */
+# include <sys/time.h>
+
+/* 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 <sys/resource.h> 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 <signal.h>.
+
+ 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 <https://www.gnu.org/licenses/>. */
+
+
+
+/* Normal invocation convention. */
+
+#ifndef _GL_SIGNAL_H
+#define _GL_SIGNAL_H
+
+/* Get pid_t. */
+#include <sys/types.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. */
+
+/* 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.,
+ <https://lists.gnu.org/r/bug-gnulib/2012-12/msg00023.html>.
+ 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 <stdlib.h>.
+
+ 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 <https://www.gnu.org/licenses/>. */
+
+/* Normal invocation convention. */
+
+#ifndef _GL_STDLIB_H
+
+#define _GL_STDLIB_H
+
+/* Native Windows platforms declare mktemp() in <io.h>. */
+#if (defined _WIN32 && ! defined __CYGWIN__)
+# include <io.h>
+#endif
+
+/* OSF/1 5.1 declares 'struct random_data' in <random.h>, which is included
+ from <stdlib.h> if _REENTRANT is defined. Include it whenever we need
+ 'struct random_data'. */
+#if HAVE_RANDOM_H
+# include <random.h>
+#endif
+
+#if !HAVE_RANDOM_R
+# include <stdint.h>
+#endif
+
+/* Define 'struct random_data'.
+ But allow multiple gnulib generated <stdlib.h> 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 <fcntl.h>)
+ 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 <fcntl.h>)
+ 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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _SYS_CDEFS_H
+#define _SYS_CDEFS_H 1
+
+/* We are almost always included from features.h. */
+#ifndef _FEATURES_H
+# include <features.h>
+#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 <bits/wordsize.h>
+# include <bits/long-double.h>
+#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 <sys/ioctl.h>.
+ 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 <https://www.gnu.org/licenses/>. */
+
+#ifndef _GL_SYS_IOCTL_H
+
+#define _GL_SYS_IOCTL_H
+
+/* AIX 5.1 and Solaris 10 declare ioctl() in <unistd.h> and in <stropts.h>,
+ but not in <sys/ioctl.h>.
+ Haiku declares ioctl() in <unistd.h>, but not in <sys/ioctl.h>.
+ But avoid namespace pollution on glibc systems. */
+#ifndef __GLIBC__
+# include <unistd.h>
+#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 <https://www.gnu.org/licenses/>. */
+
+/* Written by Eric Blake, Paul Eggert, and Jim Meyering. */
+
+/* This file is supposed to be used on platforms where <sys/stat.h> 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 <sys/types.h>
+
+/* Get struct timespec. */
+#include <time.h>
+
+#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 <io.h> and/or <direct.h>, not in <unistd.h>. */
+#if defined _WIN32 && ! defined __CYGWIN__
+# include <io.h> /* mingw32, mingw64 */
+# include <direct.h> /* 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 <direct.h> and <io.h>,
+// 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 <sys/utsname.h>.
+ 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 <https://www.gnu.org/licenses/>. */
+
+#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 <sys/wait.h>.
+ 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 <https://www.gnu.org/licenses/>. */
+
+#ifndef _GL_SYS_WAIT_H
+#define _GL_SYS_WAIT_H
+
+/* Get pid_t. */
+#include <sys/types.h>
+
+
+/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
+
+/* The definition of _GL_WARN_ON_USE is copied here. */
+
+/* Native Windows API. */
+
+#include <signal.h> /* 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 <unistd.h>.
+ 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 <https://www.gnu.org/licenses/>. */
+
+#ifndef _GL_UNISTD_H
+
+/* NetBSD 5.0 mis-defines NULL. Also get size_t. */
+#include <stddef.h>
+
+/* mingw doesn't define the SEEK_* or *_FILENO macros in <unistd.h>. */
+/* MSVC declares 'unlink' in <stdio.h>, not in <unistd.h>. We must include
+ it before we #define unlink rpl_unlink. */
+/* Cygwin 1.7.1 declares symlinkat in <stdio.h>, not in <unistd.h>. */
+/* 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 <stdio.h>
+#endif
+
+/* Cygwin 1.7.1 declares unlinkat in <fcntl.h>, not in <unistd.h>. */
+/* But avoid namespace pollution on glibc systems. */
+#if defined __CYGWIN__ \
+ && ! defined __GLIBC__
+# include <fcntl.h>
+#endif
+
+/* mingw fails to declare _exit in <unistd.h>. */
+/* mingw, MSVC, BeOS, Haiku declare environ in <stdlib.h>, not in
+ <unistd.h>. */
+/* Solaris declares getcwd not only in <unistd.h> but also in <stdlib.h>. */
+/* OSF Tru64 Unix cannot see gnulib rpl_strtod when system <stdlib.h> is
+ included here. */
+/* But avoid namespace pollution on glibc systems. */
+#if !defined __GLIBC__ && !defined __osf__
+# define __need_system_stdlib_h
+# include <stdlib.h>
+# undef __need_system_stdlib_h
+#endif
+
+/* Native Windows platforms declare chdir, getcwd, rmdir in
+ <io.h> and/or <direct.h>, not in <unistd.h>.
+ They also declare access(), chmod(), close(), dup(), dup2(), isatty(),
+ lseek(), read(), unlink(), write() in <io.h>. */
+#if (defined _WIN32 && ! defined __CYGWIN__)
+# include <io.h> /* mingw32, mingw64 */
+# include <direct.h> /* mingw64, MSVC 9 */
+#endif
+
+/* AIX and OSF/1 5.1 declare getdomainname in <netdb.h>, not in <unistd.h>.
+ NonStop Kernel declares gethostname in <netdb.h>, not in <unistd.h>. */
+/* But avoid namespace pollution on glibc systems. */
+#if ((defined _AIX || defined __osf__) \
+ || defined __TANDEM) \
+ && !defined __GLIBC__
+# include <netdb.h>
+#endif
+
+/* MSVC defines off_t in <sys/types.h>.
+ May also define off_t to a 64-bit type on native Windows. */
+/* Get off_t. */
+# include <sys/types.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. */
+
+
+///* Get getopt(), optarg, optind, opterr, optopt. */
+//#if @GNULIB_UNISTD_H_GETOPT@ && !defined _GL_SYSTEM_GETOPT
+//# include <getopt-cdefs.h>
+//# include <getopt-pfx-core.h>
+//#endif
+
+#ifndef _GL_UNISTD_INLINE
+# define _GL_UNISTD_INLINE _GL_INLINE
+#endif
+
+///* Hide some function declarations from <winsock2.h>. */
+//
+//#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 <sys/socket.h>");
+// _GL_WARN_ON_USE (connect,
+// "connect() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (accept,
+// "accept() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (bind,
+// "bind() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (getpeername,
+// "getpeername() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (getsockname,
+// "getsockname() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (getsockopt,
+// "getsockopt() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (listen,
+// "listen() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (recv,
+// "recv() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (send,
+// "send() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (recvfrom,
+// "recvfrom() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (sendto,
+// "sendto() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (setsockopt,
+// "setsockopt() used without including <sys/socket.h>");
+// _GL_WARN_ON_USE (shutdown,
+// "shutdown() used without including <sys/socket.h>");
+//# 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 <sys/select.h>");
+//# 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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html. */
+# if !HAVE_CHOWN
+extern int chown(const char *file, int uid, int gid);
+# endif
+
+
+/* Copy the file descriptor OLDFD into file descriptor NEWFD. Do nothing if
+ NEWFD = OLDFD, otherwise close NEWFD first if it is open.
+ Return newfd if successful, otherwise -1 and errno set.
+ See the POSIX:2008 specification
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup2.html>. */
+#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 <fcntl.h>)
+ 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
+ <https://www.kernel.org/doc/man-pages/online/pages/man2/dup3.2.html>. */
+#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 <unistd.h> 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 <TargetConditionals.h>
+//# if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
+//# define _GL_USE_CRT_EXTERNS
+//# endif
+//# endif
+//# ifdef _GL_USE_CRT_EXTERNS
+//# include <crt_externs.h>
+//# 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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html>. */
+#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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html>. */
+#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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html>. */
+#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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html>. */
+#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 <http://www.opengroup.org/susv3xsh/getlogin.html>.
+
+ 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 <http://www.opengroup.org/susv3xsh/getlogin.html>.
+
+ 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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/lchown.html>. */
+#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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html>. */
+#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 <fcntl.h>)
+ 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
+ <https://www.kernel.org/doc/man-pages/online/pages/man2/pipe2.2.html>. */
+#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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html>. */
+#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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html>. */
+#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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html>. */
+#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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/sleep.html>. */
+#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
+ <http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html>. */
+#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
+ <http://www.opengroup.org/susv3xsh/usleep.html>. */
+#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 <sjg@quick.com.au>
+# 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 <sys/stat.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/sys_stat.h"
+#endif
#include <sys/file.h>
@@ -146,13 +149,23 @@ __RCSID("$NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $");
#include <errno.h>
-#if !defined(USE_SELECT) && defined(HAVE_POLL_H)
-#include <poll.h>
+#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 <poll.h>
+# else
+# ifndef USE_SELECT /* no poll.h */
+# define USE_SELECT
+# endif
+# endif
+# if defined(HAVE_SYS_SELECT_H)
+# include <sys/select.h>
+# endif
#endif
-#if defined(HAVE_SYS_SELECT_H)
-# include <sys/select.h>
+#include <signal.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/signal.h"
#endif
+#ifndef SIGQUIT
+#define SIGQUIT SIGTERM
#endif
-#include <signal.h>
#include <stdio.h>
@@ -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 <sys/param.h>
+#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
+#else
+#include "headers-mingw/resource.h"
+#endif
#include <sys/stat.h>
+#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 <sys/utsname.h>
+#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 <signal.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/signal.h"
+#endif
+#ifndef SIGQUIT
+#define SIGQUIT SIGTERM
+#endif
#include <stdarg.h>
@@ -131,2 +149,5 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $");
#include <stdlib.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/stdlib.h"
+#endif
#include <time.h>
@@ -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 <process.h>
+#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 <fcntl.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/fcntl.h"
+#endif
#include <stdio.h>
#include <stdlib.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/stdlib.h"
+#endif
#ifdef HAVE_STRING_H
@@ -99,2 +105,5 @@
#include <unistd.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/unistd.h"
+#endif
#include <sys/cdefs.h>
@@ -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 <sys/stat.h>
+#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 <sys/ioctl.h>
+#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 <sys/stat.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/sys_stat.h"
+#endif
#include <assert.h>
@@ -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 <sys/stat.h>
-
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/sys_stat.h"
+#endif
#include <errno.h>
@@ -51,3 +53,6 @@
#ifdef HAVE_UNISTD_H
-# include <unistd.h>
+#include <unistd.h>
+#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 <signal.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/signal.h"
+#endif
+#ifndef SIGQUIT
+#define SIGQUIT SIGTERM
+#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#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 <unistd.h>
+#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 <obj.mk>
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 <signal.h>
+#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 <signal.h>
+#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 <sys/types.h>
+
+# if (defined _WIN32 && !defined __CYGWIN__)
+#include "headers-mingw/regex.h"
+#include "headers-mingw/regex_internal.h"
+# else
+
+#include <regex.h>
+
+# 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 <https://www.gnu.org/licenses/>. */
+
+/* Specification. */
+#include <unistd.h>
+#include "headers-mingw/unistd.h"
+/* Native Windows API. */
+
+/* Get _pipe(). */
+#include <io.h>
+
+/* Get _O_BINARY. */
+#include <fcntl.h>
+#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 <bruno@clisp.org>, 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 <https://www.gnu.org/licenses/>. */
+
+/* Specification. */
+#include <unistd.h>
+#include "headers-mingw/unistd.h"
+
+# include <stdio.h>
+
+# 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 <https://www.gnu.org/licenses/>. */
+
+/* Written by Eric Blake <ebb9@byu.net>. */
+
+/* Specification. */
+#include "headers-mingw/fcntl.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+/* Get declarations of the native Windows API functions. */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+/* Get _get_osfhandle. */
+# if GNULIB_MSVC_NOTHROW
+# include "msvc-nothrow.h"
+# else
+# include <io.h>
+# 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 <nenolod@dereferenced.org>
+ *
+ * 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 <windows.h>
+#include <winnt.h>
+#include <winternl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <process.h>
+
+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 <sys/stat.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/sys_stat.h"
+#endif
#include <dirent.h>
@@ -224,2 +703,5 @@ char *sys_siglist[] = {
#include <unistd.h>
+#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
+ <http://www.gnu.org/licenses/>. */
+
+/*
+ * 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 <stdlib.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/stdlib.h"
+#endif
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#ifdef _LIBC
+# include <libc-lock.h>
+#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 <windows.h>
- 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 <https://www.gnu.org/licenses/>. */
+
+/* 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 <alloca.h>
+
+#include <sys/types.h>
+
+/* Specification. */
+#include "headers-mingw/poll.h"
+
+#include <errno.h>
+#include <limits.h>
+
+#include <winsock2.h>
+#include <windows.h>
+#include <io.h>
+#include <stdio.h>
+#include <conio.h>
+#if GNULIB_MSVC_NOTHROW
+# include "msvc-nothrow.h"
+#else
+# include <io.h>
+#endif
+
+//#include <sys/select.h>
+//#include <sys/socket.h>
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#include <time.h>
+
+//#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 <bruno@clisp.org>, 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 <https://www.gnu.org/licenses/>. */
+
+/* Specification. */
+#include <signal.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/signal.h"
+#endif
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#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 <https://www.gnu.org/licenses/>. */
+
+/* Specification. */
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/sys_utsname.h"
+#else
+#include <sys/utsname.h>
+#endif
+
+
+/* This file provides an implementation only for the native Windows API. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/stdlib.h"
+#endif
+#include <string.h>
+#include <unistd.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/unistd.h"
+#endif
+#include <windows.h>
+
+/* 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 <https://www.gnu.org/licenses/>. */
+
+/* Specification. */
+#include "wait.h"
+
+/* Implementation for native Windows systems. */
+
+#include <process.h> /* 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 <stdint.h>
+#include <stdlib.h>
+#if (defined _WIN32 && ! defined __CYGWIN__)
+#include "headers-mingw/stdlib.h"
+#endif
+#include <string.h>
+
+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 <windows.h>
+//#include <stdio.h>
+//#include <malloc.h>
+
+#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 <windows.h>
+#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 <time.h>
+
+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 <sys/cdefs.h>
+ #include <sys/cdefs.h>
#ifndef lint
@@ -126,6 +126,20 @@ __RCSID("$NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $");
#include <sys/stat.h>
+
+#if (defined _WIN32 && !defined __CYGWIN__)
+#include "headers-mingw/sys_stat.h"
+#endif
#ifndef NO_REGEX
+
#include <sys/types.h>
+
+# if (defined _WIN32 && !defined __CYGWIN__)
+ #include "headers-mingw/regex.h"
+#include "headers-mingw/regex_internal.h"
+# else
+
#include <regex.h>
+
+# endif
#endif
+
#include <ctype.h>
@@ -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; /* "::<unrecognised>" */
- }
- 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; /* "::<unrecognised>" */
+ }
+ 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<unrecognised><endc>" or
+ if (tstr[2] != endc &&
+ (tstr[3] == endc || tstr[3] == ':')) {
+ /* ":ts<unrecognised><endc>" or
* ":ts<unrecognised>:" */
- parsestate.varSpace = tstr[2];
- cp = tstr + 3;
- } else if (tstr[2] == endc || tstr[2] == ':') {
- /* ":ts<endc>" 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<endc>" 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<backslash><unrecognised>".
*/
- goto bad_modifier;
- }
- break;
- }
- } else {
- /*
+ goto bad_modifier;
+ }
+ break;
+ }
+ } else {
+ /*
* Found ":ts<unrecognised><unrecognised>".
*/
- 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<unrecognised>:" 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<unrecognised>:" or
* ":t<unrecognised><endc>". */
- goto bad_modifier;
- }
- } else {
- /*
+ goto bad_modifier;
+ }
+ } else {
+ /*
* Found ":t<unrecognised><unrecognised>".
*/
- goto bad_modifier;
- }
- } else {
- /*
+ goto bad_modifier;
+ }
+ } else {
+ /*
* Found ":t<endc>" 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 <isamu@yamato.ibm.com>.
+
+ 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
+ <https://www.gnu.org/licenses/>. */
+
+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 <isamu@yamato.ibm.com>.
+
+ 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
+ <https://www.gnu.org/licenses/>. */
+
+#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(&regexp, 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(&regexp);
+ 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(&regexp, 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(&regexp);
+
+ 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 <reg_exp>:
+ CAT
+ / \
+ / \
+ <reg_exp> 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(&current_token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+ tree = parse_reg_exp(regexp, preg, &current_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
+ <branch1>|<branch2>:
+ ALT
+ / \
+ / \
+ <branch1> <branch2>
+
+ 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
+ <exp1><exp2>:
+ CAT
+ / \
+ / \
+ <exp1> <exp2>
+
+ 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 "<ANCHOR(^)><CHAR(*)>",
+ it must not be "<ANCHOR(^)><REPEAT(*)>". */
+ 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
+ (<reg_exp>):
+ SUBEXP
+ |
+ <reg_exp>
+*/
+
+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; /* <re>{} 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 "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */
+ 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 <re>{0,n} as (<re>(<re>...<re>?)?)?... 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 [:<character_class>:], [.<collating_element>.], and
+ [=<equivalent_class>=]. */
+
+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:
+ <src> <dst> ( <subexp> )
+ ( <subexp> ) <src> <dst>
+ ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */
+ 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 <sys/wait.h>
+#else
+#include "headers-mingw/sys_wait.h"
+#endif