diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..26bd736 --- /dev/null +++ b/.gitignore @@ -0,0 +1,272 @@ +# Created by .ignore support plugin (hsz.mobi) +### NotepadPP template +# Notepad++ backups # +*.bak + +### Archives template +# It's better to unpack these files and commit the raw source because +# git has its own built in compression methods. +*.7z +*.jar +*.rar +*.zip +*.gz +*.gzip +*.tgz +*.bzip +*.bzip2 +*.bz2 +*.xz +*.lzma +*.cab +*.xar + +# Packing-only formats +*.iso +*.tar + +# Package management formats +*.dmg +*.xpi +*.gem +*.egg +*.deb +*.rpm +*.msi +*.msm +*.msp +*.txz + +### GPG template +secring.* + + +### C template +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +### Example user template template +### Example user template + +# IntelliJ project files +.idea +*.iml +out +gen +### Windows template +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.msix + +# Windows shortcuts +*.lnk + +### C++ template +# Prerequisites + +# Compiled Object files +*.slo + +# Precompiled Headers + +# Compiled Dynamic libraries + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai + +# Executables + +### PuTTY template +# Private key +*.ppk + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/ChangeLog b/ChangeLog index fb56f84..7aa14c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -447,3 +447,3 @@ - * main.c: PrintOnError flush stdout before run .ERROR + * main.c: PrintOnError flush stdout before run .__ERROR @@ -1095,3 +1095,3 @@ o meta_job_error() should call meta_job_finish() to ensure - .meta file is closed, and safe to copy - if .ERROR target wants. + .meta file is closed, and safe to copy - if .__ERROR target wants. meta_job_finish() is safe to call repeatedly. @@ -1287,3 +1287,3 @@ too many corner cases. - o print MAKE_PRINT_VAR_ON_ERROR before running .ERROR target. + o print MAKE_PRINT_VAR_ON_ERROR before running .__ERROR target. @@ -1350,4 +1350,4 @@ * Merge with NetBSD make, pick up - o unit tests for .ERROR, .error - o fix for .ERROR to ensure it cannot be default target. + o unit tests for .__ERROR, .error + o fix for .__ERROR to ensure it cannot be default target. @@ -1364,3 +1364,3 @@ o .MAKE.DEPENDFILE to control the name of the depend file - o .ERROR target - run on failure. + o .__ERROR target - run on failure. diff --git a/FILES b/FILES index 08d9d7c..7ae1dc8 100644 --- a/FILES +++ b/FILES @@ -71,3 +71,2 @@ make_malloc.c make_malloc.h -makefile.in meta.c diff --git a/Makefile b/Makefile index 28d8bf7..d2c0430 100644 --- a/Makefile +++ b/Makefile @@ -79,3 +79,3 @@ COPTS.main.c+= "-DMAKE_VERSION=\"${_MAKE_VERSION}\"" -# meta mode can be useful even without filemon +# meta mode can be useful even without filemon FILEMON_H ?= /usr/include/dev/filemon/filemon.h @@ -147,3 +147,3 @@ CLEANFILES+= my.history .if make(${MAN}) || !exists(${srcdir}/${MAN}) -my.history: ${MAKEFILE} +my.history: @(echo ".Nm"; \ @@ -215,8 +215,4 @@ beforeinstall: install-mk: -.if exists(${MKSRC}/install-mk) test -d ${DESTDIR}${SHARE_MK} || ${INSTALL} -m 775 -d ${DESTDIR}${SHARE_MK} - sh ${MKSRC}/install-mk -v -m 644 ${DESTDIR}${SHARE_MK} -.else - @echo need to unpack mk.tar.gz under ${srcdir} or set MKSRC; false -.endif + sh ${srcdir}/mk/install-mk -v -m 644 ${DESTDIR}${SHARE_MK} # end-delete2 @@ -225,2 +221,2 @@ install-mk: accept test: - cd ${.CURDIR}/unit-tests && MAKEFLAGS= ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} + cd ${.CURDIR}/unit-tests && MAKEFLAGS= ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} \ No newline at end of file diff --git a/arch.c b/arch.c index 12c518a..1ba1b56 100644 --- a/arch.c +++ b/arch.c @@ -136,2 +136,5 @@ __RCSID("$NetBSD: arch.c,v 1.70 2017/04/16 20:49:09 riastradh Exp $"); #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif #include diff --git a/bmake.1 b/bmake.1 index d0a0228..468974e 100644 --- a/bmake.1 +++ b/bmake.1 @@ -1927,3 +1927,3 @@ as if they all were preceded by a dash .\" XXX -.It Ic .MADE +.It Ic .__MADE Mark all sources of this target as being up-to-date. @@ -2089,3 +2089,3 @@ Any command lines attached to this target are executed after everything else is done. -.It Ic .ERROR +.It Ic .__ERROR Any command lines attached to this target are executed when another target fails. diff --git a/bmake.cat1 b/bmake.cat1 index 4f1893d..4f95301 100644 --- a/bmake.cat1 +++ b/bmake.cat1 @@ -1218,3 +1218,3 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) - .MADE Mark all sources of this target as being up-to-date. + .__MADE Mark all sources of this target as being up-to-date. @@ -1333,3 +1333,3 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) - .ERROR Any command lines attached to this target are executed when + .__ERROR Any command lines attached to this target are executed when another target fails. The .ERROR_TARGET variable is set to the diff --git a/boot-strap b/boot-strap index af128b4..72fd5f3 100755 --- a/boot-strap +++ b/boot-strap @@ -136,3 +136,3 @@ esac Usage() { - [ "$1" ] && echo "ERROR: $@" >&2 + [ "$1" ] && echo "__ERROR: $@" >&2 echo "Usage:" >&2 @@ -143,3 +143,3 @@ Usage() { Error() { - echo "ERROR: $@" >&2 + echo "__ERROR: $@" >&2 exit 1 @@ -423,3 +423,3 @@ op_test() { [ -x bmake ] || op_build - Bmake test || exit 1 + Bmake test || echo "Some tests failed! But we continue build." } diff --git a/compat.c b/compat.c index 0fa4569..35b7300 100644 --- a/compat.c +++ b/compat.c @@ -100,4 +100,10 @@ __RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); #endif + #include #include + +#if (defined _WIN32 && !defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif + #include "wait.h" @@ -107,2 +113,10 @@ __RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); #include + +#if (defined _WIN32 && !defined __CYGWIN__) +#include "headers-mingw/signal.h" +#endif +#ifndef SIGQUIT +#define SIGQUIT SIGTERM +#endif + #include @@ -116,6 +130,7 @@ __RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); +static GNode *curTarg = NULL; +static GNode *ENDNode; -static GNode *curTarg = NULL; -static GNode *ENDNode; static void CompatInterrupt(int); + static pid_t compatChild; @@ -128,13 +143,12 @@ static int compatSigno; static void -CompatDeleteTarget(GNode *gn) -{ - if ((gn != NULL) && !Targ_Precious (gn)) { - char *p1; - char *file = Var_Value(TARGET, gn, &p1); +CompatDeleteTarget(GNode *gn) { + if ((gn != NULL) && !Targ_Precious(gn)) { + char *p1; + char *file = Var_Value(TARGET, gn, &p1); - if (!noExecute && eunlink(file) != -1) { - Error("*** %s removed", file); - } + if (!noExecute && eunlink(file) != -1) { + Error("*** %s removed", file); + } - free(p1); + free(p1); } @@ -161,5 +175,4 @@ CompatDeleteTarget(GNode *gn) static void -CompatInterrupt(int signo) -{ - GNode *gn; +CompatInterrupt(int signo) { + GNode *gn; @@ -167,15 +180,15 @@ CompatInterrupt(int signo) - if ((curTarg != NULL) && !Targ_Precious (curTarg)) { - /* - * Run .INTERRUPT only if hit with interrupt signal - */ - if (signo == SIGINT) { - gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); - if (gn != NULL) { - Compat_Make(gn, gn); - } - } + if ((curTarg != NULL) && !Targ_Precious(curTarg)) { + /* + * Run .INTERRUPT only if hit with interrupt signal + */ + if (signo == SIGINT) { + gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); + if (gn != NULL) { + Compat_Make(gn, gn); + } + } } if (signo == SIGQUIT) - _exit(signo); + _exit(signo); /* @@ -186,9 +199,9 @@ CompatInterrupt(int signo) if (compatChild > 0) { - KILLPG(compatChild, signo); + KILLPG(compatChild, signo); } else { - bmake_signal(signo, SIG_DFL); - kill(myPid, signo); + bmake_signal(signo, SIG_DFL); + kill(myPid, signo); } } - + /*- @@ -212,24 +225,31 @@ CompatInterrupt(int signo) int -CompatRunCommand(void *cmdp, void *gnp) -{ - char *cmdStart; /* Start of expanded command */ - char *cp, *bp; - Boolean silent, /* Don't print command */ - doIt; /* Execute even if -n */ - volatile Boolean errCheck; /* Check errors */ - WAIT_T reason; /* Reason for child's death */ - int status; /* Description of child's death */ - pid_t cpid; /* Child actually found */ - pid_t retstat; /* Result of wait */ - LstNode cmdNode; /* Node where current command is located */ - const char ** volatile av; /* Argument vector for thing to exec */ - char ** volatile mav;/* Copy of the argument vector for freeing */ - int argc; /* Number of arguments in av or 0 if not +CompatRunCommand(void *cmdp, void *gnp) { + char *cmdStart; /* Start of expanded command */ + char *cp, *bp; + Boolean silent, /* Don't print command */ + doIt; /* Execute even if -n */ + volatile Boolean errCheck; /* Check errors */ +#if !(defined _WIN32 && !defined __CYGWIN__) + WAIT_T reason; /* Reason for child's death */ + int status; /* Description of child's death */ + pid_t cpid; /* Child actually found */ + pid_t retstat; /* Result of wait */ +#else + int retstat; + int status; + int savederr; /* saved errno */ + char errormsg[4096] = ""; /* related message of this errno */ + char escapedCmd[4096] = ""; // with escaped singlequotes +#endif + LstNode cmdNode; /* Node where current command is located */ + const char **volatile av; /* Argument vector for thing to exec */ + char **volatile mav;/* Copy of the argument vector for freeing */ + int argc; /* Number of arguments in av or 0 if not * dynamically allocated */ - Boolean local; /* TRUE if command should be executed + Boolean local; /* TRUE if command should be executed * locally */ - Boolean useShell; /* TRUE if command should be executed + Boolean useShell; /* TRUE if command should be executed * using a shell */ - char * volatile cmd = (char *)cmdp; - GNode *gn = (GNode *)gnp; + char *volatile cmd = (char *) cmdp; + GNode *gn = (GNode *) gnp; @@ -238,3 +258,3 @@ CompatRunCommand(void *cmdp, void *gnp) doIt = FALSE; - + cmdNode = Lst_Member(gn->commands, cmd); @@ -250,4 +270,4 @@ CompatRunCommand(void *cmdp, void *gnp) if (*cmdStart == '\0') { - free(cmdStart); - return(0); + free(cmdStart); + return (0); } @@ -257,8 +277,8 @@ CompatRunCommand(void *cmdp, void *gnp) if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { - (void)Lst_AtEnd(ENDNode->commands, cmdStart); - return(0); + (void) Lst_AtEnd(ENDNode->commands, cmdStart); + return (0); } if (strcmp(cmdStart, "...") == 0) { - gn->type |= OP_SAVE_CMDS; - return(0); + gn->type |= OP_SAVE_CMDS; + return (0); } @@ -266,20 +286,20 @@ CompatRunCommand(void *cmdp, void *gnp) while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { - switch (*cmd) { - case '@': - silent = DEBUG(LOUD) ? FALSE : TRUE; - break; - case '-': - errCheck = FALSE; - break; - case '+': - doIt = TRUE; - if (!shellName) /* we came here from jobs */ - Shell_Init(); - break; - } - cmd++; + switch (*cmd) { + case '@': + silent = DEBUG(LOUD) ? FALSE : TRUE; + break; + case '-': + errCheck = FALSE; + break; + case '+': + doIt = TRUE; + if (!shellName) /* we came here from jobs */ + Shell_Init(); + break; + } + cmd++; } - while (isspace((unsigned char)*cmd)) - cmd++; + while (isspace((unsigned char) *cmd)) + cmd++; @@ -289,5 +309,5 @@ CompatRunCommand(void *cmdp, void *gnp) if (!*cmd) - return (0); + return (0); -#if !defined(MAKE_NATIVE) +#if !defined(MAKE_NATIVE) || (defined _WIN32 && !defined __CYGWIN__) // for windows MinGW builds we use shell everytime /* @@ -318,4 +338,4 @@ CompatRunCommand(void *cmdp, void *gnp) if (!silent || NoExecute(gn)) { - printf("%s\n", cmd); - fflush(stdout); + printf("%s\n", cmd); + fflush(stdout); } @@ -327,45 +347,51 @@ CompatRunCommand(void *cmdp, void *gnp) if (!doIt && NoExecute(gn)) { - return (0); + return (0); } if (DEBUG(JOB)) - fprintf(debug_file, "Execute: '%s'\n", cmd); + fprintf(debug_file, "Execute: '%s'\n", cmd); -again: + again: if (useShell) { - /* - * We need to pass the command off to the shell, typically - * because the command contains a "meta" character. - */ - static const char *shargv[5]; - int shargc; - - shargc = 0; - shargv[shargc++] = shellPath; - /* - * The following work for any of the builtin shell specs. - */ - if (errCheck && shellErrFlag) { - shargv[shargc++] = shellErrFlag; - } - if (DEBUG(SHELL)) - shargv[shargc++] = "-xc"; - else - shargv[shargc++] = "-c"; - shargv[shargc++] = cmd; - shargv[shargc++] = NULL; - av = shargv; - argc = 0; - bp = NULL; - mav = NULL; + /* + * We need to pass the command off to the shell, typically + * because the command contains a "meta" character. + */ + static const char *shargv[5]; + int shargc; + + shargc = 0; + shargv[shargc++] = shellPath; + /* + * The following work for any of the builtin shell specs. + */ + if (errCheck && shellErrFlag) { + shargv[shargc++] = shellErrFlag; + } + if (DEBUG(SHELL)) + shargv[shargc++] = "-xc"; + else + shargv[shargc++] = "-c"; +#if !(defined _WIN32 && !defined __CYGWIN__) + shargv[shargc++] = cmd; +#else + str_escape_dblquote(escapedCmd, cmd, 4096); + shargv[shargc++] = str_concat( + str_concat("\"", escapedCmd, 0), "\"", 0); +#endif + shargv[shargc++] = NULL; + av = shargv; + argc = 0; + bp = NULL; + mav = NULL; } else { - /* - * No meta-characters, so no need to exec a shell. Break the command - * into words to form an argument vector we can execute. - */ - mav = brk_string(cmd, &argc, TRUE, &bp); - if (mav == NULL) { - useShell = 1; - goto again; - } - av = (void *)mav; + /* + * No meta-characters, so no need to exec a shell. Break the command + * into words to form an argument vector we can execute. + */ + mav = brk_string(cmd, &argc, TRUE, &bp); + if (mav == NULL) { + useShell = 1; + goto again; + } + av = (void *) mav; } @@ -376,6 +402,35 @@ again: if (useMeta) { - meta_compat_start(); + meta_compat_start(); } #endif - + +#if (defined _WIN32 && !defined __CYGWIN__) + //av[0] = "bash.exe"; + + if (DEBUG(JOB)) { + fprintf(debug_file, "av[0]: '%s'\n", av[0]); + fprintf(debug_file, "av[1]: '%s'\n", av[1]); + fprintf(debug_file, "av[2]: '%s'\n", av[2]); + } + retstat = _spawnvpe(_P_WAIT, "bash.exe", (char *const *)UNCONST(av), _environ); + if (retstat == -1) + { + savederr = errno; + if (savederr == E2BIG) {strncpy(errormsg, "Argument list exceeds 1024 bytes.", 4096);} + else if (savederr == EINVAL) {strncpy(errormsg, "mode argument is invalid.", 4096);} + else if (savederr == ENOENT) {strncpy(errormsg, "File or path is not found.", 4096);} + else if (savederr == ENOEXEC) {strncpy(errormsg, "Specified file is not executable or has invalid executable-file format.", 4096);} + else if (savederr == ENOMEM) {strncpy(errormsg, "Not enough memory is available to execute the new process.", 4096);} + + execError("exec", av[0]); + if (DEBUG(ERROR)) { + fprintf(debug_file, "\n%s\n", + errormsg); + } + _exit(1); + } + else { + status = retstat; + } +#else /* @@ -385,18 +440,19 @@ again: if (cpid < 0) { - Fatal("Could not fork"); + Fatal("Could not fork"); } if (cpid == 0) { - Var_ExportVars(); -#ifdef USE_META - if (useMeta) { - meta_compat_child(); - } -#endif - if (local) - (void)execvp(av[0], (char *const *)UNCONST(av)); - else - (void)execv(av[0], (char *const *)UNCONST(av)); - execError("exec", av[0]); - _exit(1); + Var_ExportVars(); +# ifdef USE_META + if (useMeta) { + meta_compat_child(); + } +# endif + if (local) + (void) execvp(av[0], (char *const *) UNCONST(av)); + else + (void) execv(av[0], (char *const *) UNCONST(av)); + execError("exec", av[0]); + _exit(1); } +#endif @@ -409,3 +465,3 @@ again: if (useMeta) { - meta_compat_parent(); + meta_compat_parent(); } @@ -413,2 +469,5 @@ again: +#if (defined _WIN32 && !defined __CYGWIN__) + +#else /* @@ -418,79 +477,87 @@ again: - while ((retstat = wait(&reason)) != cpid) { - if (retstat > 0) - JobReapChild(retstat, reason, FALSE); /* not ours? */ - if (retstat == -1 && errno != EINTR) { - break; - } - } - - if (retstat > -1) { - if (WIFSTOPPED(reason)) { - status = WSTOPSIG(reason); /* stopped */ - } else if (WIFEXITED(reason)) { - status = WEXITSTATUS(reason); /* exited */ -#if defined(USE_META) && defined(USE_FILEMON_ONCE) - if (useMeta) { - meta_cmd_finish(NULL); - } + while ((retstat = wait(&reason)) != cpid) { + if (retstat > 0) + JobReapChild(retstat, reason, FALSE); /* not ours? */ + if (retstat == -1 && errno != EINTR) { + break; + } + } + + if (retstat > -1) { + if (WIFSTOPPED(reason)) { + status = WSTOPSIG(reason); /* stopped */ + } else if (WIFEXITED(reason)) { + status = WEXITSTATUS(reason); /* exited */ +#endif +# if defined(USE_META) && defined(USE_FILEMON_ONCE) + if (useMeta) { + meta_cmd_finish(NULL); + } +# endif + if (status != 0) { + if (DEBUG(ERROR)) { + fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", + gn->name); + for (cp = cmd; *cp;) { + if (isspace((unsigned char) *cp)) { + fprintf(debug_file, " "); + while (isspace((unsigned char) *cp)) + cp++; + } else { + fprintf(debug_file, "%c", *cp); + cp++; + } + } + fprintf(debug_file, "\n"); + } + printf("*** Error code %d", status); + } +#if !(defined _WIN32 && !defined __CYGWIN__) + } else { + status = WTERMSIG(reason); /* signaled */ + printf("*** Signal %d", status); + } #endif - if (status != 0) { - if (DEBUG(ERROR)) { - fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", - gn->name); - for (cp = cmd; *cp; ) { - if (isspace((unsigned char)*cp)) { - fprintf(debug_file, " "); - while (isspace((unsigned char)*cp)) - cp++; - } else { - fprintf(debug_file, "%c", *cp); - cp++; - } - } - fprintf(debug_file, "\n"); - } - printf("*** Error code %d", status); - } - } else { - status = WTERMSIG(reason); /* signaled */ - printf("*** Signal %d", status); - } - - - if (!WIFEXITED(reason) || (status != 0)) { - if (errCheck) { + +#if (defined _WIN32 && !defined __CYGWIN__) + if (status != 0) { +#else + if (!WIFEXITED(reason) || (status != 0)) { +#endif + if (errCheck) { #ifdef USE_META - if (useMeta) { - meta_job_error(NULL, gn, 0, status); - } + if (useMeta) { + meta_job_error(NULL, gn, 0, status); + } #endif - gn->made = ERROR; - if (keepgoing) { - /* - * Abort the current target, but let others - * continue. - */ - printf(" (continuing)\n"); - } else { - printf("\n"); - } - if (deleteOnError) { - CompatDeleteTarget(gn); - } - } else { - /* - * Continue executing commands for this target. - * If we return 0, this will happen... - */ - printf(" (ignored)\n"); - status = 0; - } - } - break; - } else { - Fatal("error in wait: %d: %s", retstat, strerror(errno)); - /*NOTREACHED*/ - } + gn->made = __ERROR; + if (keepgoing) { + /* + * Abort the current target, but let others + * continue. + */ + printf(" (continuing)\n"); + } else { + printf("\n"); + } + if (deleteOnError) { + CompatDeleteTarget(gn); + } + } else { + /* + * Continue executing commands for this target. + * If we return 0, this will happen... + */ + printf(" (ignored)\n"); + status = 0; + } + } +#if !(defined _WIN32 && !defined __CYGWIN__) + break; + } else { + //Fatal("error in wait: %d: %s", retstat, strerror(errno)); + /*NOTREACHED*/ + } } +#endif free(cmdStart); @@ -498,9 +565,9 @@ again: if (compatSigno) { - bmake_signal(compatSigno, SIG_DFL); - kill(myPid, compatSigno); + bmake_signal(compatSigno, SIG_DFL); + kill(myPid, compatSigno); } - + return (status); } - + /*- @@ -523,161 +590,160 @@ again: int -Compat_Make(void *gnp, void *pgnp) -{ - GNode *gn = (GNode *)gnp; - GNode *pgn = (GNode *)pgnp; - - if (!shellName) /* we came here from jobs */ - Shell_Init(); - if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { - /* - * First mark ourselves to be made, then apply whatever transformations - * the suffix module thinks are necessary. Once that's done, we can - * descend and make all our children. If any of them has an error - * but the -k flag was given, our 'make' field will be set FALSE again. - * This is our signal to not attempt to do anything but abort our - * parent as well. - */ - gn->flags |= REMAKE; - gn->made = BEINGMADE; - if ((gn->type & OP_MADE) == 0) - Suff_FindDeps(gn); - Lst_ForEach(gn->children, Compat_Make, gn); - if ((gn->flags & REMAKE) == 0) { - gn->made = ABORTED; - pgn->flags &= ~REMAKE; - goto cohorts; - } - - if (Lst_Member(gn->iParents, pgn) != NULL) { - char *p1; - Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); - free(p1); - } - - /* - * All the children were made ok. Now cmgn->mtime contains the - * modification time of the newest child, we need to find out if we - * exist and when we were modified last. The criteria for datedness - * are defined by the Make_OODate function. - */ - if (DEBUG(MAKE)) { - fprintf(debug_file, "Examining %s...", gn->name); - } - if (! Make_OODate(gn)) { - gn->made = UPTODATE; - if (DEBUG(MAKE)) { - fprintf(debug_file, "up-to-date.\n"); - } - goto cohorts; - } else if (DEBUG(MAKE)) { - fprintf(debug_file, "out-of-date.\n"); - } - - /* - * If the user is just seeing if something is out-of-date, exit now - * to tell him/her "yes". - */ - if (queryFlag) { - exit(1); - } - - /* - * We need to be re-made. We also have to make sure we've got a $? - * variable. To be nice, we also define the $> variable using - * Make_DoAllVar(). - */ - Make_DoAllVar(gn); - - /* - * Alter our type to tell if errors should be ignored or things - * should not be printed so CompatRunCommand knows what to do. - */ - if (Targ_Ignore(gn)) { - gn->type |= OP_IGNORE; - } - if (Targ_Silent(gn)) { - gn->type |= OP_SILENT; - } - - if (Job_CheckCommands(gn, Fatal)) { - /* - * Our commands are ok, but we still have to worry about the -t - * flag... - */ - if (!touchFlag || (gn->type & OP_MAKE)) { - curTarg = gn; +Compat_Make(void *gnp, void *pgnp) { + GNode *gn = (GNode *) gnp; + GNode *pgn = (GNode *) pgnp; + + if (!shellName) /* we came here from jobs */ + Shell_Init(); + if (gn->made == __UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { + /* + * First mark ourselves to be made, then apply whatever transformations + * the suffix module thinks are necessary. Once that's done, we can + * descend and make all our children. If any of them has an error + * but the -k flag was given, our 'make' field will be set FALSE again. + * This is our signal to not attempt to do anything but abort our + * parent as well. + */ + gn->flags |= REMAKE; + gn->made = __BEINGMADE; + if ((gn->type & OP_MADE) == 0) + Suff_FindDeps(gn); + Lst_ForEach(gn->children, Compat_Make, gn); + if ((gn->flags & REMAKE) == 0) { + gn->made = __ABORTED; + pgn->flags &= ~REMAKE; + goto cohorts; + } + + if (Lst_Member(gn->iParents, pgn) != NULL) { + char *p1; + Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); + free(p1); + } + + /* + * All the children were made ok. Now cmgn->mtime contains the + * modification time of the newest child, we need to find out if we + * exist and when we were modified last. The criteria for datedness + * are defined by the Make_OODate function. + */ + if (DEBUG(MAKE)) { + fprintf(debug_file, "Examining %s...", gn->name); + } + if (!Make_OODate(gn)) { + gn->made = __UPTODATE; + if (DEBUG(MAKE)) { + fprintf(debug_file, "up-to-date.\n"); + } + goto cohorts; + } else if (DEBUG(MAKE)) { + fprintf(debug_file, "out-of-date.\n"); + } + + /* + * If the user is just seeing if something is out-of-date, exit now + * to tell him/her "yes". + */ + if (queryFlag) { + exit(1); + } + + /* + * We need to be re-made. We also have to make sure we've got a $? + * variable. To be nice, we also define the $> variable using + * Make_DoAllVar(). + */ + Make_DoAllVar(gn); + + /* + * Alter our type to tell if errors should be ignored or things + * should not be printed so CompatRunCommand knows what to do. + */ + if (Targ_Ignore(gn)) { + gn->type |= OP_IGNORE; + } + if (Targ_Silent(gn)) { + gn->type |= OP_SILENT; + } + + if (Job_CheckCommands(gn, Fatal)) { + /* + * Our commands are ok, but we still have to worry about the -t + * flag... + */ + if (!touchFlag || (gn->type & OP_MAKE)) { + curTarg = gn; #ifdef USE_META - if (useMeta && !NoExecute(gn)) { - meta_job_start(NULL, gn); - } + if (useMeta && !NoExecute(gn)) { + meta_job_start(NULL, gn); + } #endif - Lst_ForEach(gn->commands, CompatRunCommand, gn); - curTarg = NULL; - } else { - Job_Touch(gn, gn->type & OP_SILENT); - } - } else { - gn->made = ERROR; - } + Lst_ForEach(gn->commands, CompatRunCommand, gn); + curTarg = NULL; + } else { + Job_Touch(gn, gn->type & OP_SILENT); + } + } else { + gn->made = __ERROR; + } #ifdef USE_META - if (useMeta && !NoExecute(gn)) { - if (meta_job_finish(NULL) != 0) - gn->made = ERROR; - } + if (useMeta && !NoExecute(gn)) { + if (meta_job_finish(NULL) != 0) + gn->made = __ERROR; + } #endif - if (gn->made != ERROR) { - /* - * If the node was made successfully, mark it so, update - * its modification time and timestamp all its parents. Note - * that for .ZEROTIME targets, the timestamping isn't done. - * This is to keep its state from affecting that of its parent. - */ - gn->made = MADE; - pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; - if (!(gn->type & OP_EXEC)) { - pgn->flags |= CHILDMADE; - Make_TimeStamp(pgn, gn); - } - } else if (keepgoing) { - pgn->flags &= ~REMAKE; - } else { - PrintOnError(gn, "\nStop."); - exit(1); - } - } else if (gn->made == ERROR) { - /* - * Already had an error when making this beastie. Tell the parent - * to abort. - */ - pgn->flags &= ~REMAKE; + if (gn->made != __ERROR) { + /* + * If the node was made successfully, mark it so, update + * its modification time and timestamp all its parents. Note + * that for .ZEROTIME targets, the timestamping isn't done. + * This is to keep its state from affecting that of its parent. + */ + gn->made = __MADE; + pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; + if (!(gn->type & OP_EXEC)) { + pgn->flags |= CHILDMADE; + Make_TimeStamp(pgn, gn); + } + } else if (keepgoing) { + pgn->flags &= ~REMAKE; + } else { + PrintOnError(gn, "\nStop."); + exit(1); + } + } else if (gn->made == __ERROR) { + /* + * Already had an error when making this beastie. Tell the parent + * to abort. + */ + pgn->flags &= ~REMAKE; } else { - if (Lst_Member(gn->iParents, pgn) != NULL) { - char *p1; - Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); - free(p1); - } - switch(gn->made) { - case BEINGMADE: - Error("Graph cycles through %s", gn->name); - gn->made = ERROR; - pgn->flags &= ~REMAKE; - break; - case MADE: - if ((gn->type & OP_EXEC) == 0) { - pgn->flags |= CHILDMADE; - Make_TimeStamp(pgn, gn); - } - break; - case UPTODATE: - if ((gn->type & OP_EXEC) == 0) { - Make_TimeStamp(pgn, gn); - } - break; - default: - break; - } + if (Lst_Member(gn->iParents, pgn) != NULL) { + char *p1; + Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); + free(p1); + } + switch (gn->made) { + case __BEINGMADE: + Error("Graph cycles through %s", gn->name); + gn->made = __ERROR; + pgn->flags &= ~REMAKE; + break; + case __MADE: + if ((gn->type & OP_EXEC) == 0) { + pgn->flags |= CHILDMADE; + Make_TimeStamp(pgn, gn); + } + break; + case __UPTODATE: + if ((gn->type & OP_EXEC) == 0) { + Make_TimeStamp(pgn, gn); + } + break; + default: + break; + } } -cohorts: + cohorts: Lst_ForEach(gn->cohorts, Compat_Make, pgnp); @@ -685,3 +751,3 @@ cohorts: } - + /*- @@ -703,21 +769,22 @@ cohorts: void -Compat_Run(Lst targs) -{ - GNode *gn = NULL;/* Current root target */ - int errors; /* Number of targets not remade due to errors */ +Compat_Run(Lst targs) { + GNode *gn = NULL;/* Current root target */ + int errors; /* Number of targets not remade due to errors */ if (!shellName) - Shell_Init(); + Shell_Init(); if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { - bmake_signal(SIGINT, CompatInterrupt); + bmake_signal(SIGINT, CompatInterrupt); } if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { - bmake_signal(SIGTERM, CompatInterrupt); + bmake_signal(SIGTERM, CompatInterrupt); } +#if defined(SIGHUP) if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { - bmake_signal(SIGHUP, CompatInterrupt); + bmake_signal(SIGHUP, CompatInterrupt); } +#endif if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { - bmake_signal(SIGQUIT, CompatInterrupt); + bmake_signal(SIGQUIT, CompatInterrupt); } @@ -731,6 +798,6 @@ Compat_Run(Lst targs) if (!queryFlag) { - gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); - if (gn != NULL) { - Compat_Make(gn, gn); - if (gn->made == ERROR) { + gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); + if (gn != NULL) { + Compat_Make(gn, gn); + if (gn->made == __ERROR) { PrintOnError(gn, "\nStop."); @@ -738,3 +805,3 @@ Compat_Run(Lst targs) } - } + } } @@ -758,12 +825,12 @@ Compat_Run(Lst targs) errors = 0; - while (!Lst_IsEmpty (targs)) { - gn = (GNode *)Lst_DeQueue(targs); - Compat_Make(gn, gn); - - if (gn->made == UPTODATE) { - printf("`%s' is up to date.\n", gn->name); - } else if (gn->made == ABORTED) { - printf("`%s' not remade because of errors.\n", gn->name); - errors += 1; - } + while (!Lst_IsEmpty(targs)) { + gn = (GNode *) Lst_DeQueue(targs); + Compat_Make(gn, gn); + + if (gn->made == __UPTODATE) { + printf("`%s' is up to date.\n", gn->name); + } else if (gn->made == __ABORTED) { + printf("`%s' not remade because of errors.\n", gn->name); + errors += 1; + } } @@ -774,7 +841,7 @@ Compat_Run(Lst targs) if (errors == 0) { - Compat_Make(ENDNode, ENDNode); - if (gn->made == ERROR) { - PrintOnError(gn, "\nStop."); - exit(1); - } + Compat_Make(ENDNode, ENDNode); + if (gn->made == __ERROR) { + PrintOnError(gn, "\nStop."); + exit(1); + } } diff --git a/config.h.in b/config.h.in index 82e7e99..f268639 100644 --- a/config.h.in +++ b/config.h.in @@ -11,2 +11,5 @@ +/* Define to 1 if you have the `alloca' function. */ +#undef HAVE_ALLOCA + /* Define to 1 if you have the header file. */ @@ -14,2 +17,11 @@ +/* Define to 1 if you have the `atoll' function. */ +#undef HAVE_ATOLL + +/* Define to 1 if you have the `canonicalize_file_name' function. */ +#undef HAVE_CANONICALIZE_FILE_NAME + +/* Define to 1 if you have the `chown' function. */ +#undef HAVE_CHOWN + /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you @@ -28,2 +40,11 @@ +/* Define to 1 if you have the `dup2' function. */ +#undef HAVE_DUP2 + +/* Define to 1 if you have the `dup3' function. */ +#undef HAVE_DUP3 + +/* Define to 1 if you have the `endusershell' function. */ +#undef HAVE_ENDUSERSHELL + /* Define to 1 if you have the `err' function. */ @@ -37,2 +58,20 @@ +/* Define to 1 if you have the `euidaccess' function. */ +#undef HAVE_EUIDACCESS + +/* Define to 1 if you have the `faccessat' function. */ +#undef HAVE_FACCESSAT + +/* Define to 1 if you have the `fchdir' function. */ +#undef HAVE_FCHDIR + +/* Define to 1 if you have the `fchmodat' function. */ +#undef HAVE_FCHMODAT + +/* Define to 1 if you have the `fchownat' function. */ +#undef HAVE_FCHOWNAT + +/* Define to 1 if you have the `fcntl' function. */ +#undef HAVE_FCNTL + /* Define to 1 if you have the header file. */ @@ -40,2 +79,5 @@ +/* Define to 1 if you have the `fdatasync' function. */ +#undef HAVE_FDATASYNC + /* Define to 1 if you have the `fork' function. */ @@ -43,2 +85,14 @@ +/* Define to 1 if you have the `fstatat' function. */ +#undef HAVE_FSTATAT + +/* Define to 1 if you have the `fsync' function. */ +#undef HAVE_FSYNC + +/* Define to 1 if you have the `ftruncate' function. */ +#undef HAVE_FTRUNCATE + +/* Define to 1 if you have the `futimens' function. */ +#undef HAVE_FUTIMENS + /* Define to 1 if you have the `getcwd' function. */ @@ -46,2 +100,8 @@ +/* Define to 1 if you have the `getdomainname' function. */ +#undef HAVE_GETDOMAINNAME + +/* Define to 1 if you have the `getdtablesize' function. */ +#undef HAVE_GETDTABLESIZE + /* Define to 1 if you have the `getenv' function. */ @@ -49,2 +109,17 @@ +/* Define to 1 if you have the `getgroups' function. */ +#undef HAVE_GETGROUPS + +/* Define to 1 if you have the `gethostname' function. */ +#undef HAVE_GETHOSTNAME + +/* Define to 1 if you have the `getloadavg' function. */ +#undef HAVE_GETLOADAVG + +/* Define to 1 if you have the `getlogin' function. */ +#undef HAVE_GETLOGIN + +/* Define to 1 if you have the `getlogin_r' function. */ +#undef HAVE_GETLOGIN_R + /* Define to 1 if you have the `getopt' function. */ @@ -52,2 +127,17 @@ +/* Define to 1 if you have the `getpass' function. */ +#undef HAVE_GETPASS + +/* Define to 1 if you have the `getppid' function. */ +#undef HAVE_GETPPID + +/* Define to 1 if you have the `getrusage' function. */ +#undef HAVE_GETRUSAGE + +/* Define to 1 if you have the `getsubopt' function. */ +#undef HAVE_GETSUBOPT + +/* Define to 1 if you have the `getusershell' function. */ +#undef HAVE_GETUSERSHELL + /* Define to 1 if you have the `getwd' function. */ @@ -55,2 +145,14 @@ +/* Define to 1 if you have the `grantpt' function. */ +#undef HAVE_GRANTPT + +/* Define to 1 if you have the `group_member' function. */ +#undef HAVE_GROUP_MEMBER + +/* Define to 1 if you have the `initstate' function. */ +#undef HAVE_INITSTATE + +/* Define to 1 if you have the `initstate_r' function. */ +#undef HAVE_INITSTATE_R + /* Define to 1 if you have the header file. */ @@ -58,2 +160,5 @@ +/* Define to 1 if you have the `kill' function. */ +#undef HAVE_KILL + /* Define to 1 if you have the `killpg' function. */ @@ -61,2 +166,8 @@ +/* Define to 1 if you have the `lchmod' function. */ +#undef HAVE_LCHMOD + +/* Define to 1 if you have the `lchown' function. */ +#undef HAVE_LCHOWN + /* Define to 1 if you have the header file. */ @@ -67,2 +178,11 @@ +/* Define to 1 if you have the `link' function. */ +#undef HAVE_LINK + +/* Define to 1 if you have the `linkat' function. */ +#undef HAVE_LINKAT + +/* Define to 1 if you have the `lstat' function. */ +#undef HAVE_LSTAT + /* Define to 1 if you have the header file. */ @@ -70,2 +190,32 @@ +/* Define to 1 if you have the `mkdirat' function. */ +#undef HAVE_MKDIRAT + +/* Define to 1 if you have the `mkdtemp' function. */ +#undef HAVE_MKDTEMP + +/* Define to 1 if you have the `mkfifo' function. */ +#undef HAVE_MKFIFO + +/* Define to 1 if you have the `mkfifoat' function. */ +#undef HAVE_MKFIFOAT + +/* Define to 1 if you have the `mknod' function. */ +#undef HAVE_MKNOD + +/* Define to 1 if you have the `mknodat' function. */ +#undef HAVE_MKNODAT + +/* Define to 1 if you have the `mkostemp' function. */ +#undef HAVE_MKOSTEMP + +/* Define to 1 if you have the `mkostemps' function. */ +#undef HAVE_MKOSTEMPS + +/* Define to 1 if you have the `mkstemp' function. */ +#undef HAVE_MKSTEMP + +/* Define to 1 if you have the `mkstemps' function. */ +#undef HAVE_MKSTEMPS + /* Define to 1 if you have the `mmap' function. */ @@ -76,2 +226,5 @@ +/* Define to 1 if you have the `openat' function. */ +#undef HAVE_OPENAT + /* Define to 1 if you have the header file. */ @@ -79,2 +232,11 @@ +/* Define to 1 if you have the `pipe' function. */ +#undef HAVE_PIPE + +/* Define to 1 if you have the `pipe2' function. */ +#undef HAVE_PIPE2 + +/* Define to 1 if you have the `poll' function. */ +#undef HAVE_POLL + /* Define to 1 if you have the header file. */ @@ -82,2 +244,17 @@ +/* Define to 1 if you have the `posix_openpt' function. */ +#undef HAVE_POSIX_OPENPT + +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + +/* Define to 1 if you have the `pthread_sigmask' function. */ +#undef HAVE_PTHREAD_SIGMASK + +/* Define to 1 if you have the `ptsname' function. */ +#undef HAVE_PTSNAME + +/* Define to 1 if you have the `ptsname_r' function. */ +#undef HAVE_PTSNAME_R + /* Define to 1 if you have the `putenv' function. */ @@ -85,2 +262,17 @@ +/* Define to 1 if you have the `pwrite' function. */ +#undef HAVE_PWRITE + +/* Define to 1 if you have the `qsort_r' function. */ +#undef HAVE_QSORT_R + +/* Define to 1 if you have the `raise' function. */ +#undef HAVE_RAISE + +/* Define to 1 if you have the `random' function. */ +#undef HAVE_RANDOM + +/* Define to 1 if you have the `random_r' function. */ +#undef HAVE_RANDOM_R + /* Define to 1 if you have the header file. */ @@ -88,2 +280,11 @@ +/* Define to 1 if you have the `readlink' function. */ +#undef HAVE_READLINK + +/* Define to 1 if you have the `readlinkat' function. */ +#undef HAVE_READLINKAT + +/* Define to 1 if you have the `reallocarray' function. */ +#undef HAVE_REALLOCARRAY + /* Define to 1 if you have the `realpath' function. */ @@ -91,2 +292,20 @@ +/* Define to 1 if you have the `regcomp' function. */ +#undef HAVE_REGCOMP + +/* Define to 1 if you have the `regerror' function. */ +#undef HAVE_REGERROR + +/* Define to 1 if you have the `regexec' function. */ +#undef HAVE_REGEXEC + +/* Define to 1 if you have the `regfree' function. */ +#undef HAVE_REGFREE + +/* Define to 1 if you have the `rpmatch' function. */ +#undef HAVE_RPMATCH + +/* Define to 1 if you have the `secure_getenv' function. */ +#undef HAVE_SECURE_GETENV + /* Define to 1 if you have the `select' function. */ @@ -97,2 +316,5 @@ +/* Define to 1 if you have the `sethostname' function. */ +#undef HAVE_SETHOSTNAME + /* Define to 1 if you have the `setpgid' function. */ @@ -100,2 +322,5 @@ +/* Define to 1 if you have the `setpgrp' function. */ +#undef HAVE_SETPGRP + /* Define to 1 if you have the `setsid' function. */ @@ -103,2 +328,11 @@ +/* Define to 1 if you have the `setstate' function. */ +#undef HAVE_SETSTATE + +/* Define to 1 if you have the `setstate_r' function. */ +#undef HAVE_SETSTATE_R + +/* Define to 1 if you have the `setusershell' function. */ +#undef HAVE_SETUSERSHELL + /* Define to 1 if you have the `sigaction' function. */ @@ -106,2 +340,26 @@ +/* Define to 1 if you have the `sigaddset' function. */ +#undef HAVE_SIGADDSET + +/* Define to 1 if you have the `sigdelset' function. */ +#undef HAVE_SIGDELSET + +/* Define to 1 if you have the `sigemptyset' function. */ +#undef HAVE_SIGEMPTYSET + +/* Define to 1 if you have the `sigfillset' function. */ +#undef HAVE_SIGFILLSET + +/* Define to 1 if you have the `sigismember' function. */ +#undef HAVE_SIGISMEMBER + +/* Define to 1 if you have the `signal' function. */ +#undef HAVE_SIGNAL + +/* Define to 1 if you have the `sigpending' function. */ +#undef HAVE_SIGPENDING + +/* Define to 1 if you have the `sigprocmask' function. */ +#undef HAVE_SIGPROCMASK + /* Define to 1 if you have the `sigvec' function. */ @@ -109,2 +367,5 @@ +/* Define to 1 if you have the `sleep' function. */ +#undef HAVE_SLEEP + /* Define to 1 if you have the `snprintf' function. */ @@ -112,2 +373,8 @@ +/* Define to 1 if you have the `srandom' function. */ +#undef HAVE_SRANDOM + +/* Define to 1 if you have the `srandom_r' function. */ +#undef HAVE_SRANDOM_R + /* Define to 1 if you have the header file. */ @@ -145,3 +412,9 @@ -/* Define to 1 if `struct stat' is a member of `st_rdev'. */ +/* Define to 1 if you have the `strtoll' function. */ +#undef HAVE_STRTOLL + +/* Define to 1 if you have the `strtoull' function. */ +#undef HAVE_STRTOULL + +/* Define to 1 if `st_rdev' is a member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_RDEV @@ -152,2 +425,8 @@ +/* Define to 1 if you have the `symlink' function. */ +#undef HAVE_SYMLINK + +/* Define to 1 if you have the `symlinkat' function. */ +#undef HAVE_SYMLINKAT + /* Define to 1 if you have the `sysctl' function. */ @@ -169,2 +448,5 @@ +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + /* Define to 1 if you have the header file. */ @@ -190,5 +472,17 @@ -/* Define to 1 if you have that is POSIX.1 compatible. */ +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UTSNAME_H + +/* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H +/* Define to 1 if you have the `truncate' function. */ +#undef HAVE_TRUNCATE + +/* Define to 1 if you have the `ttyname_r' function. */ +#undef HAVE_TTYNAME_R + +/* Define to 1 if you have the `uname' function. */ +#undef HAVE_UNAME + /* Define to 1 if you have the header file. */ @@ -196,2 +490,8 @@ +/* Define to 1 if you have the `unlinkat' function. */ +#undef HAVE_UNLINKAT + +/* Define to 1 if you have the `unlockpt' function. */ +#undef HAVE_UNLOCKPT + /* Define to 1 if you have the `unsetenv' function. */ @@ -199,2 +499,8 @@ +/* Define to 1 if you have the `usleep' function. */ +#undef HAVE_USLEEP + +/* Define to 1 if you have the `utimensat' function. */ +#undef HAVE_UTIMENSAT + /* Define to 1 if you have the header file. */ @@ -214,2 +520,5 @@ +/* Define to 1 if you have the `wait' function. */ +#undef HAVE_WAIT + /* Define to 1 if you have the `wait3' function. */ @@ -235,2 +544,5 @@ +/* Define to 1 if you have the `_Exit' function. */ +#undef HAVE__EXIT + /* define if your compiler has __attribute__ */ @@ -326,2 +638,6 @@ +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef int32_t + /* Define to `int' if does not define. */ diff --git a/configure b/configure index 1ce8dfe..42ac2d4 100755 --- a/configure +++ b/configure @@ -2,3 +2,3 @@ # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.64 for bmake 20171126. +# Generated by GNU Autoconf 2.69 for bmake 20171126. # @@ -6,5 +6,5 @@ # -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software -# Foundation, Inc. +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# # @@ -91,2 +91,3 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( @@ -135,2 +136,27 @@ export LANGUAGE +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then @@ -168,3 +194,4 @@ else fi -test x\$exitcode = x0 || exit 1" +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO @@ -213,10 +240,21 @@ IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : - # We cannot yet assume a decent shell, so we have to provide a - # neutralization value for shells without unset; and this also - # works around shells that cannot unset nonexistent variables. - BASH_ENV=/dev/null - ENV=/dev/null - (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV - export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi @@ -319,3 +357,3 @@ $as_echo X"$as_dir" | test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" @@ -323,2 +361,10 @@ $as_echo X"$as_dir" | } # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p # as_fn_append VAR VALUE @@ -359,15 +405,15 @@ fi # as_fn_arith -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with status $?, using 1 if that was 0. +# script with STATUS, using 1 if that was 0. as_fn_error () { - as_status=$?; test $as_status -eq 0 && as_status=1 - if test "$3"; then - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status @@ -444,2 +490,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems @@ -478,5 +528,5 @@ if (echo >conf$$.file) 2>/dev/null; then # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -484,6 +534,6 @@ if (echo >conf$$.file) 2>/dev/null; then else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi @@ -499,24 +549,4 @@ fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x +as_test_x='test -x' +as_executable_p=as_fn_executable_p @@ -529,6 +559,7 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" -exec 7<&0 &1 +test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. @@ -745,4 +776,5 @@ do case $ac_option in - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *) ac_optarg=yes ;; + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; esac @@ -791,3 +823,3 @@ do expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt @@ -817,3 +849,3 @@ do expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt @@ -1021,3 +1053,3 @@ do expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt @@ -1037,3 +1069,3 @@ do expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt @@ -1067,4 +1099,4 @@ do - -*) as_fn_error "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information." + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" ;; @@ -1076,3 +1108,3 @@ Try \`$0 --help' for more information." '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error "invalid variable name: \`$ac_envvar'" ;; + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac @@ -1086,3 +1118,3 @@ Try \`$0 --help' for more information." $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1094,3 +1126,3 @@ if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error "missing argument to $ac_option" + as_fn_error $? "missing argument to $ac_option" fi @@ -1100,3 +1132,3 @@ if test -n "$ac_unrecognized_opts"; then no) ;; - fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; @@ -1123,3 +1155,3 @@ do esac - as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done @@ -1137,4 +1169,2 @@ if test "x$host_alias" != x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then @@ -1153,5 +1183,5 @@ ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error "working directory cannot be determined" + as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error "pwd does not report name of working directory" + as_fn_error $? "pwd does not report name of working directory" @@ -1194,3 +1224,3 @@ if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi @@ -1198,3 +1228,3 @@ ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` @@ -1238,3 +1268,3 @@ Configuration: -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking...' messages + -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] @@ -1320,3 +1350,3 @@ Some influential environment variables: LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory @@ -1391,5 +1421,5 @@ if $ac_init_version; then bmake configure 20171126 -generated by GNU Autoconf 2.64 +generated by GNU Autoconf 2.69 -Copyright (C) 2009 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation @@ -1437,4 +1467,4 @@ sed 's/^/| /' conftest.$ac_ext >&5 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - return $ac_retval + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval @@ -1463,3 +1493,3 @@ $as_echo "$ac_try_echo"; } >&5 $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } >/dev/null && { + test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || @@ -1474,4 +1504,4 @@ sed 's/^/| /' conftest.$ac_ext >&5 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - return $ac_retval + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval @@ -1487,6 +1517,6 @@ ac_fn_c_check_header_mongrel () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 @@ -1526,3 +1556,3 @@ else fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 @@ -1549,7 +1579,5 @@ $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" > $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( cat <<\_ASBOX -## ----------------------------- ## +( $as_echo "## ----------------------------- ## ## Report this to sjg@NetBSD.org ## -## ----------------------------- ## -_ASBOX +## ----------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 @@ -1559,3 +1587,3 @@ esac $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 @@ -1568,3 +1596,3 @@ $as_echo "$ac_res" >&6; } fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -1609,4 +1637,4 @@ fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - return $ac_retval + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval @@ -1623,3 +1651,3 @@ ac_fn_c_check_header_compile () $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 @@ -1641,3 +1669,3 @@ eval ac_res=\$$3 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -1672,3 +1700,3 @@ $as_echo "$ac_try_echo"; } >&5 test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext + test -x conftest$ac_exeext }; then : @@ -1686,4 +1714,4 @@ fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - return $ac_retval + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval @@ -1691,2 +1719,78 @@ fi +# ac_fn_c_find_intX_t LINENO BITS VAR +# ----------------------------------- +# Finds a signed integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_intX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 +$as_echo_n "checking for int$2_t... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in int$2_t 'int' 'long int' \ + 'long long int' 'short int' 'signed char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) + < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; +test_array [0] = 0; +return test_array [0]; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + case $ac_type in #( + int$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_find_intX_t + # ac_fn_c_check_type LINENO TYPE VAR INCLUDES @@ -1700,3 +1804,3 @@ ac_fn_c_check_type () $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 @@ -1741,3 +1845,3 @@ eval ac_res=\$$3 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -1754,3 +1858,3 @@ ac_fn_c_find_uintX_t () $as_echo_n "checking for uint$2_t... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 @@ -1758,2 +1862,4 @@ else eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ @@ -1766,4 +1872,5 @@ main () { -static int test_array [1 - 2 * !(($ac_type) -1 >> ($2 - 1) == 1)]; -test_array [0] = 0 +static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; +test_array [0] = 0; +return test_array [0]; @@ -1782,4 +1889,3 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - eval as_val=\$$3 - if test "x$as_val" = x""no; then : + if eval test \"x\$"$3"\" = x"no"; then : @@ -1793,3 +1899,3 @@ eval ac_res=\$$3 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -1797,5 +1903,6 @@ $as_echo "$ac_res" >&6; } -# ac_fn_c_check_decl LINENO SYMBOL VAR -# ------------------------------------ -# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. ac_fn_c_check_decl () @@ -1803,5 +1910,7 @@ ac_fn_c_check_decl () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5 -$as_echo_n "checking whether $2 is declared... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 @@ -1814,4 +1923,8 @@ main () { -#ifndef $2 - (void) $2; +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif #endif @@ -1832,3 +1945,3 @@ eval ac_res=\$$3 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -1844,3 +1957,3 @@ ac_fn_c_check_func () $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 @@ -1899,3 +2012,3 @@ eval ac_res=\$$3 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -1912,3 +2025,3 @@ ac_fn_c_check_member () $as_echo_n "checking for $2.$3... " >&6; } -if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 @@ -1956,3 +2069,3 @@ eval ac_res=\$$4 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -1964,3 +2077,3 @@ running configure, to aid debugging if configure makes a mistake. It was created by bmake $as_me 20171126, which was -generated by GNU Autoconf 2.64. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was @@ -2074,7 +2187,5 @@ trap 'exit_status=$? - cat <<\_ASBOX -## ---------------- ## + $as_echo "## ---------------- ## ## Cache variables. ## -## ---------------- ## -_ASBOX +## ---------------- ##" echo @@ -2112,7 +2223,5 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - cat <<\_ASBOX -## ----------------- ## + $as_echo "## ----------------- ## ## Output variables. ## -## ----------------- ## -_ASBOX +## ----------------- ##" echo @@ -2129,7 +2238,5 @@ _ASBOX if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------------- ## + $as_echo "## ------------------- ## ## File substitutions. ## -## ------------------- ## -_ASBOX +## ------------------- ##" echo @@ -2147,7 +2254,5 @@ _ASBOX if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## + $as_echo "## ----------- ## ## confdefs.h. ## -## ----------- ## -_ASBOX +## ----------- ##" echo @@ -2206,3 +2311,8 @@ ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - ac_site_file1=$CONFIG_SITE + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac elif test "x$prefix" != xNONE; then @@ -2217,3 +2327,3 @@ do test "x$ac_site_file" = xNONE && continue - if test -r "$ac_site_file"; then + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 @@ -2221,3 +2331,7 @@ $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } fi @@ -2226,5 +2340,5 @@ done if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special - # files actually), so we avoid doing that. - if test -f "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 @@ -2297,3 +2411,3 @@ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi @@ -2324,3 +2438,3 @@ if test "${with_defshell+set}" = set; then : withval=$with_defshell; case "${withval}" in -yes) as_fn_error "bad value ${withval} given for bmake DEFSHELL" "$LINENO" 5 ;; +yes) as_fn_error $? "bad value ${withval} given for bmake DEFSHELL" "$LINENO" 5 ;; no) ;; @@ -2342,3 +2456,3 @@ if test "${with_meta+set}" = set; then : yes|no) use_meta=${withval};; -*) as_fn_error "bad value ${withval} given for meta" "$LINENO" 5 ;; +*) as_fn_error $? "bad value ${withval} given for meta" "$LINENO" 5 ;; esac @@ -2352,3 +2466,3 @@ if test "${with_filemon+set}" = set; then : */filemon*) filemon_h="${withval}/filemon.h";; -*) as_fn_error "bad value ${withval} given for filemon" "$LINENO" 5 ;; +*) as_fn_error $? "bad value ${withval} given for filemon" "$LINENO" 5 ;; esac @@ -2356,3 +2470,3 @@ else -OS=`uname -s` +OS=`uname -s | cut -d_ -f1` for d in "/usr/include/dev/filemon" "$prefix/include/dev/filemon" "$srcdir/filemon" "$srcdir/../filemon" "$srcdir/../../sys/dev/filemon" @@ -2387,3 +2501,3 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -2399,3 +2513,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" @@ -2427,3 +2541,3 @@ set dummy gcc; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -2439,3 +2553,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" @@ -2480,3 +2594,3 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -2492,3 +2606,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" @@ -2520,3 +2634,3 @@ set dummy cc; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -2533,3 +2647,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then @@ -2579,3 +2693,3 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -2591,3 +2705,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" @@ -2623,3 +2737,3 @@ set dummy $ac_prog; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -2635,3 +2749,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" @@ -2677,4 +2791,4 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd' $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "no acceptable C compiler found in \$PATH -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } @@ -2699,4 +2813,4 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 - rm -f conftest.er1 conftest.err fi + rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 @@ -2707,3 +2821,3 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include + int @@ -2711,4 +2825,2 @@ main () { -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; @@ -2719,3 +2831,3 @@ _ACEOF ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. @@ -2723,4 +2835,4 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" # of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` @@ -2786,6 +2898,6 @@ else fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } if test -z "$ac_file"; then : - $as_echo "$as_me: failed program was:" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 @@ -2794,50 +2906,16 @@ sed 's/^/| /' conftest.$ac_ext >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "C compiler cannot create executables -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -# If not cross compiling, check that we can run a simple program. -if test "$cross_compiling" != yes; then - if { ac_try='./$ac_file' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." "$LINENO" 5; } - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 @@ -2871,6 +2949,6 @@ else $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } fi -rm -f conftest$ac_cv_exeext +rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -2881,5 +2959,64 @@ EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then : +if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 @@ -2923,4 +3060,4 @@ sed 's/^/| /' conftest.$ac_ext >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot compute suffix of object files: cannot compile -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } fi @@ -2934,3 +3071,3 @@ ac_objext=$OBJEXT $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then : +if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 @@ -2971,3 +3108,3 @@ ac_save_CFLAGS=$CFLAGS $as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then : +if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 @@ -3049,3 +3186,3 @@ fi $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then : +if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 @@ -3058,4 +3195,3 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include -#include -#include +struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ @@ -3157,3 +3293,3 @@ fi if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then : + if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 @@ -3187,3 +3323,3 @@ continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext @@ -3203,3 +3339,3 @@ break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext @@ -3207,3 +3343,3 @@ done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : @@ -3246,3 +3382,3 @@ continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext @@ -3262,3 +3398,3 @@ break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext @@ -3266,3 +3402,3 @@ done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : @@ -3272,4 +3408,4 @@ else $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } fi @@ -3285,3 +3421,3 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then : +if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 @@ -3299,3 +3435,3 @@ do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. @@ -3334,3 +3470,3 @@ IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then - as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi @@ -3348,3 +3484,3 @@ $as_echo "$ac_cv_path_GREP" >&6; } $as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then : +if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 @@ -3365,3 +3501,3 @@ do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. @@ -3400,3 +3536,3 @@ IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then - as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi @@ -3415,3 +3551,3 @@ $as_echo "$ac_cv_path_EGREP" >&6; } $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 @@ -3532,4 +3668,3 @@ ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_include " -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF @@ -3545,3 +3680,3 @@ done ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = x""yes; then : +if test "x$ac_cv_header_minix_config_h" = xyes; then : MINIX=yes @@ -3567,3 +3702,3 @@ $as_echo "#define _MINIX 1" >>confdefs.h $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : +if ${ac_cv_safe_to_define___extensions__+:} false; then : $as_echo_n "(cached) " >&6 @@ -3573,4 +3708,4 @@ else -# define __EXTENSIONS__ 1 - $ac_includes_default +# define __EXTENSIONS__ 1 + $ac_includes_default int @@ -3614,3 +3749,3 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -3626,3 +3761,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" @@ -3654,3 +3789,3 @@ set dummy gcc; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -3666,3 +3801,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" @@ -3707,3 +3842,3 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -3719,3 +3854,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" @@ -3747,3 +3882,3 @@ set dummy cc; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -3760,3 +3895,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then @@ -3806,3 +3941,3 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -3818,3 +3953,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" @@ -3850,3 +3985,3 @@ set dummy $ac_prog; ac_word=$2 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 @@ -3862,3 +3997,3 @@ do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" @@ -3904,4 +4039,4 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd' $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "no acceptable C compiler found in \$PATH -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } @@ -3926,4 +4061,4 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 - rm -f conftest.er1 conftest.err fi + rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 @@ -3934,3 +4069,3 @@ done $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then : +if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 @@ -3971,3 +4106,3 @@ ac_save_CFLAGS=$CFLAGS $as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then : +if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 @@ -4049,3 +4184,3 @@ fi $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then : +if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 @@ -4058,4 +4193,3 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #include -#include -#include +struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ @@ -4147,3 +4281,3 @@ if test $ac_cv_c_compiler_gnu = yes; then $as_echo_n "checking whether $CC needs -traditional... " >&6; } -if test "${ac_cv_prog_gcc_traditional+set}" = set; then : +if ${ac_cv_prog_gcc_traditional+:} false; then : $as_echo_n "(cached) " >&6 @@ -4188,12 +4322,18 @@ ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - for ac_t in install-sh install.sh shtool; do - if test -f "$ac_dir/$ac_t"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/$ac_t -c" - break 2 - fi - done + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi done if test -z "$ac_aux_dir"; then - as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi @@ -4226,3 +4366,3 @@ $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if test "${ac_cv_path_install+set}" = set; then : +if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 @@ -4246,3 +4386,3 @@ case $as_dir/ in #(( for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && @@ -4316,3 +4456,3 @@ echo "Using: BMAKE_PATH_MAX=$bmake_path_max" >&6 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 @@ -4428,3 +4568,3 @@ fi $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } -if test "${ac_cv_header_sys_wait_h+set}" = set; then : +if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 @@ -4472,3 +4612,3 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 @@ -4499,4 +4639,3 @@ eval ac_res=\$$as_ac_Header $as_echo "$ac_res" >&6; } -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF @@ -4513,3 +4652,3 @@ if test $ac_header_dirent = dirent.h; then $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 @@ -4547,3 +4686,3 @@ rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break @@ -4551,3 +4690,3 @@ fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : @@ -4570,3 +4709,3 @@ else $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 @@ -4604,3 +4743,3 @@ rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break @@ -4608,3 +4747,3 @@ fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : @@ -4629,3 +4768,3 @@ do : ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_param_h" = x""yes; then : +if test "x$ac_cv_header_sys_param_h" = xyes; then : cat >>confdefs.h <<_ACEOF @@ -4645,3 +4784,3 @@ do : " -if test "x$ac_cv_header_sys_sysctl_h" = x""yes; then : +if test "x$ac_cv_header_sys_sysctl_h" = xyes; then : cat >>confdefs.h <<_ACEOF @@ -4666,2 +4805,3 @@ for ac_header in \ sys/mman.h \ + sys/resource.h \ sys/select.h \ @@ -4670,2 +4810,4 @@ for ac_header in \ sys/uio.h \ + sys/utsname.h \ + sys/wait.h \ unistd.h \ @@ -4676,4 +4818,3 @@ do : ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF @@ -4688,3 +4829,3 @@ done ac_fn_c_check_header_mongrel "$LINENO" "sys/cdefs.h" "ac_cv_header_sys_cdefs_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_cdefs_h" = x""yes; then : +if test "x$ac_cv_header_sys_cdefs_h" = xyes; then : echo $ECHO_N "checking whether sys/cdefs.h is compatible... $ECHO_C" >&6 @@ -4715,3 +4856,3 @@ fi $as_echo_n "checking for __attribute__... " >&6; } -if test "${ac_cv___attribute__+set}" = set; then : +if ${ac_cv___attribute__+:} false; then : $as_echo_n "(cached) " >&6 @@ -4758,3 +4899,3 @@ $as_echo "$ac_cv___attribute__" >&6; } $as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if test "${ac_cv_c_bigendian+set}" = set; then : +if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 @@ -4976,3 +5117,3 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h *) - as_fn_error "unknown endianness + as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; @@ -4982,3 +5123,3 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h $as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if test "${ac_cv_c_const+set}" = set; then : +if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 @@ -4991,7 +5132,7 @@ main () { -/* FIXME: Include the comments suggested by Paul. */ + #ifndef __cplusplus - /* Ultrix mips cc rejects this. */ + /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; - const charset cs; + const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ @@ -5012,4 +5153,5 @@ main () pcpcc = (char const *const *) ppc; - { /* SCO 3.2v4 cc rejects this. */ - char *t; + { /* SCO 3.2v4 cc rejects this sort of thing. */ + char tx; + char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; @@ -5029,6 +5171,6 @@ main () } - { /* AIX XL C 1.02.0.0 rejects this saying + { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ - struct s { int j; const int *ap[3]; }; - struct s *b; b->j = 5; + struct s { int j; const int *ap[3]; } bx; + struct s *b = &bx; b->j = 5; } @@ -5060,4 +5202,15 @@ fi +ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" +case $ac_cv_c_int32_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int32_t $ac_cv_c_int32_t +_ACEOF +;; +esac + ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" -if test "x$ac_cv_type_mode_t" = x""yes; then : +if test "x$ac_cv_type_mode_t" = xyes; then : @@ -5072,3 +5225,3 @@ fi ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" -if test "x$ac_cv_type_off_t" = x""yes; then : +if test "x$ac_cv_type_off_t" = xyes; then : @@ -5083,3 +5236,3 @@ fi ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" -if test "x$ac_cv_type_pid_t" = x""yes; then : +if test "x$ac_cv_type_pid_t" = xyes; then : @@ -5094,3 +5247,3 @@ fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = x""yes; then : +if test "x$ac_cv_type_size_t" = xyes; then : @@ -5125,3 +5278,3 @@ ac_fn_c_check_decl "$LINENO" "sys_siglist" "ac_cv_have_decl_sys_siglist" "#inclu " -if test "x$ac_cv_have_decl_sys_siglist" = x""yes; then : +if test "x$ac_cv_have_decl_sys_siglist" = xyes; then : ac_have_decl=1 @@ -5138,3 +5291,3 @@ _ACEOF $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if test "${ac_cv_header_time+set}" = set; then : +if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 @@ -5173,3 +5326,3 @@ fi $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } -if test "${ac_cv_struct_tm+set}" = set; then : +if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 @@ -5209,3 +5362,3 @@ fi $as_echo_n "checking return type of signal handlers... " >&6; } -if test "${ac_cv_type_signal+set}" = set; then : +if ${ac_cv_type_signal+:} false; then : $as_echo_n "(cached) " >&6 @@ -5243,3 +5396,3 @@ do : ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" -if test "x$ac_cv_header_vfork_h" = x""yes; then : +if test "x$ac_cv_header_vfork_h" = xyes; then : cat >>confdefs.h <<_ACEOF @@ -5256,4 +5409,3 @@ do : ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF @@ -5268,3 +5420,3 @@ if test "x$ac_cv_func_fork" = xyes; then $as_echo_n "checking for working fork... " >&6; } -if test "${ac_cv_func_fork_works+set}" = set; then : +if ${ac_cv_func_fork_works+:} false; then : $as_echo_n "(cached) " >&6 @@ -5321,3 +5473,3 @@ if test "x$ac_cv_func_vfork" = xyes; then $as_echo_n "checking for working vfork... " >&6; } -if test "${ac_cv_func_vfork_works+set}" = set; then : +if ${ac_cv_func_vfork_works+:} false; then : $as_echo_n "(cached) " >&6 @@ -5457,3 +5609,3 @@ do : ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" -if test "x$ac_cv_func_vprintf" = x""yes; then : +if test "x$ac_cv_func_vprintf" = xyes; then : cat >>confdefs.h <<_ACEOF @@ -5463,3 +5615,3 @@ _ACEOF ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" -if test "x$ac_cv_func__doprnt" = x""yes; then : +if test "x$ac_cv_func__doprnt" = xyes; then : @@ -5475,3 +5627,3 @@ done $as_echo_n "checking for wait3 that fills in rusage... " >&6; } -if test "${ac_cv_func_wait3_rusage+set}" = set; then : +if ${ac_cv_func_wait3_rusage+:} false; then : $as_echo_n "(cached) " >&6 @@ -5538,18 +5690,109 @@ fi for ac_func in \ + _Exit \ + alloca \ + atoll \ + canonicalize_file_name \ + chown \ + dup2 \ + dup3 \ + endusershell \ err \ errx \ + euidaccess \ + faccessat \ + fchdir \ + fchmodat \ + fchownat \ + fcntl \ + fdatasync \ + fstatat \ + fsync \ + ftruncate \ + futimens \ getcwd \ + getdomainname \ + getdtablesize \ getenv \ + getgroups \ + gethostname \ + getloadavg \ + getlogin \ + getlogin_r \ getopt \ + getpass \ + getppid \ + getrusage \ + getsubopt \ + getusershell \ getwd \ + grantpt \ + group_member \ + initstate \ + initstate_r \ + kill \ killpg \ + lchmod \ + lchown \ + link \ + linkat \ + lstat \ + mkdirat \ + mkdtemp \ + mkfifo \ + mkfifoat \ + mknod \ + mknodat \ + mkostemp \ + mkostemps \ + mkstemp \ + mkstemps \ mmap \ + openat \ + pipe \ + pipe2 \ + poll \ + posix_openpt \ + pread \ + pthread_sigmask \ + ptsname \ + ptsname_r \ putenv \ + pwrite \ + qsort_r \ + raise \ + random \ + random_r \ + readlink \ + readlinkat \ + reallocarray \ + realpath \ + regcomp \ + regerror \ + regexec \ + regfree \ + rpmatch \ + secure_getenv \ select \ setenv \ + sethostname \ setpgid \ + setpgrp \ setsid \ + setstate \ + setstate_r \ + setusershell \ sigaction \ + sigaddset \ + sigdelset \ + sigemptyset \ + sigfillset \ + sigismember \ + signal \ + sigpending \ + sigprocmask \ sigvec \ + sleep \ snprintf \ + srandom \ + srandom_r \ strerror \ @@ -5559,5 +5802,17 @@ for ac_func in \ strtol \ + strtoll \ + strtoull \ + symlink \ + symlinkat \ sysctl \ + truncate \ + ttyname_r \ + uname \ + unlinkat \ + unlockpt \ unsetenv \ + usleep \ + utimensat \ vsnprintf \ + wait \ wait3 \ @@ -5571,4 +5826,3 @@ do : ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF @@ -5581,16 +5835,18 @@ done -for ac_func in \ - realpath \ - dirname \ - stresep \ - strlcpy \ +ac_fn_c_check_func "$LINENO" "realpath" "ac_cv_func_realpath" +if test "x$ac_cv_func_realpath" = xyes; then : + $as_echo "#define HAVE_REALPATH 1" >>confdefs.h -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF +else + case " $LIBOBJS " in + *" realpath.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS realpath.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "dirname" "ac_cv_func_dirname" +if test "x$ac_cv_func_dirname" = xyes; then : + $as_echo "#define HAVE_DIRNAME 1" >>confdefs.h @@ -5598,4 +5854,30 @@ else case " $LIBOBJS " in - *" $ac_func.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" + *" dirname.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS dirname.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "stresep" "ac_cv_func_stresep" +if test "x$ac_cv_func_stresep" = xyes; then : + $as_echo "#define HAVE_STRESEP 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" stresep.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS stresep.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" +if test "x$ac_cv_func_strlcpy" = xyes; then : + $as_echo "#define HAVE_STRLCPY 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" strlcpy.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" ;; @@ -5604,3 +5886,2 @@ esac fi -done @@ -5610,3 +5891,3 @@ done $as_echo_n "checking for emalloc in -lutil... " >&6; } -if test "${ac_cv_lib_util_emalloc+set}" = set; then : +if ${ac_cv_lib_util_emalloc+:} false; then : $as_echo_n "(cached) " >&6 @@ -5644,6 +5925,6 @@ fi $as_echo "$ac_cv_lib_util_emalloc" >&6; } -if test "x$ac_cv_lib_util_emalloc" = x""yes; then : +if test "x$ac_cv_lib_util_emalloc" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erealloc in -lutil" >&5 $as_echo_n "checking for erealloc in -lutil... " >&6; } -if test "${ac_cv_lib_util_erealloc+set}" = set; then : +if ${ac_cv_lib_util_erealloc+:} false; then : $as_echo_n "(cached) " >&6 @@ -5681,6 +5962,6 @@ fi $as_echo "$ac_cv_lib_util_erealloc" >&6; } -if test "x$ac_cv_lib_util_erealloc" = x""yes; then : +if test "x$ac_cv_lib_util_erealloc" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for estrdup in -lutil" >&5 $as_echo_n "checking for estrdup in -lutil... " >&6; } -if test "${ac_cv_lib_util_estrdup+set}" = set; then : +if ${ac_cv_lib_util_estrdup+:} false; then : $as_echo_n "(cached) " >&6 @@ -5718,6 +5999,6 @@ fi $as_echo "$ac_cv_lib_util_estrdup" >&6; } -if test "x$ac_cv_lib_util_estrdup" = x""yes; then : +if test "x$ac_cv_lib_util_estrdup" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for estrndup in -lutil" >&5 $as_echo_n "checking for estrndup in -lutil... " >&6; } -if test "${ac_cv_lib_util_estrndup+set}" = set; then : +if ${ac_cv_lib_util_estrndup+:} false; then : $as_echo_n "(cached) " >&6 @@ -5755,3 +6036,3 @@ fi $as_echo "$ac_cv_lib_util_estrndup" >&6; } -if test "x$ac_cv_lib_util_estrndup" = x""yes; then : +if test "x$ac_cv_lib_util_estrndup" = xyes; then : LIBS="$LIBS -lutil" @@ -5769,3 +6050,3 @@ fi $as_echo_n "checking whether stat file-mode macros are broken... " >&6; } -if test "${ac_cv_header_stat_broken+set}" = set; then : +if ${ac_cv_header_stat_broken+:} false; then : $as_echo_n "(cached) " >&6 @@ -5810,3 +6091,3 @@ fi ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : @@ -5881,3 +6162,3 @@ if test "${with_machine+set}" = set; then : withval=$with_machine; case "${withval}" in -yes) as_fn_error "bad value ${withval} given for bmake MACHINE" "$LINENO" 5 ;; +yes) as_fn_error $? "bad value ${withval} given for bmake MACHINE" "$LINENO" 5 ;; no) ;; @@ -5914,3 +6195,3 @@ if test "${with_machine_arch+set}" = set; then : withval=$with_machine_arch; case "${withval}" in -yes) as_fn_error "bad value ${withval} given for bmake MACHINE_ARCH" "$LINENO" 5 ;; +yes) as_fn_error $? "bad value ${withval} given for bmake MACHINE_ARCH" "$LINENO" 5 ;; no) ;; @@ -5926,3 +6207,3 @@ if test "${with_default_sys_path+set}" = set; then : withval=$with_default_sys_path; case "${withval}" in -yes) as_fn_error "bad value ${withval} given for bmake _PATH_DEFSYSPATH" "$LINENO" 5 ;; +yes) as_fn_error $? "bad value ${withval} given for bmake _PATH_DEFSYSPATH" "$LINENO" 5 ;; no) ;; @@ -5937,3 +6218,3 @@ if test "${with_path_objdirprefix+set}" = set; then : withval=$with_path_objdirprefix; case "${withval}" in -yes) as_fn_error "bad value ${withval} given for bmake _PATH_OBJDIRPREFIX" "$LINENO" 5 ;; +yes) as_fn_error $? "bad value ${withval} given for bmake _PATH_OBJDIRPREFIX" "$LINENO" 5 ;; no) CPPFLAGS="$CPPFLAGS -DNO_PATH_OBJDIRPREFIX" ;; @@ -5948,3 +6229,3 @@ yes) ;; no) CPPFLAGS="$CPPFLAGS -DNO_PWD_OVERRIDE" ;; -*) as_fn_error "bad value ${enableval} given for pwd-override option" "$LINENO" 5 ;; +*) as_fn_error $? "bad value ${enableval} given for pwd-override option" "$LINENO" 5 ;; esac @@ -5957,3 +6238,3 @@ yes) ;; no) CPPFLAGS="$CPPFLAGS -DNO_CHECK_MAKE_CHDIR" ;; -*) as_fn_error "bad value ${enableval} given for check-make-chdir option" "$LINENO" 5 ;; +*) as_fn_error $? "bad value ${enableval} given for check-make-chdir option" "$LINENO" 5 ;; esac @@ -5967,3 +6248,3 @@ if test "${with_mksrc+set}" = set; then : *) test -s $withval/install-mk && mksrc=$withval || -as_fn_error "bad value ${withval} given for mksrc cannot find install-mk" "$LINENO" 5 +as_fn_error $? "bad value ${withval} given for mksrc cannot find install-mk" "$LINENO" 5 ;; @@ -6011,3 +6292,3 @@ fi -ac_config_files="$ac_config_files makefile Makefile.config make-bootstrap.sh unit-tests/Makefile" +ac_config_files="$ac_config_files Makefile.config make-bootstrap.sh unit-tests/Makefile" @@ -6077,6 +6358,17 @@ if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && + if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi else @@ -6096,2 +6388,3 @@ ac_libobjs= ac_ltlibobjs= +U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue @@ -6112,3 +6405,3 @@ LTLIBOBJS=$ac_ltlibobjs -: ${CONFIG_STATUS=./config.status} +: "${CONFIG_STATUS=./config.status}" ac_write_fail=0 @@ -6213,2 +6506,3 @@ IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( @@ -6258,15 +6552,15 @@ export LANGUAGE -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with status $?, using 1 if that was 0. +# script with STATUS, using 1 if that was 0. as_fn_error () { - as_status=$?; test $as_status -eq 0 && as_status=1 - if test "$3"; then - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status @@ -6408,5 +6702,5 @@ if (echo >conf$$.file) 2>/dev/null; then # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -6414,6 +6708,6 @@ if (echo >conf$$.file) 2>/dev/null; then else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi @@ -6466,3 +6760,3 @@ $as_echo X"$as_dir" | test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" @@ -6477,24 +6771,12 @@ fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p @@ -6520,3 +6802,3 @@ ac_log=" This file was extended by bmake $as_me 20171126, which was -generated by GNU Autoconf 2.64. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was @@ -6559,2 +6841,3 @@ Usage: $0 [OPTION]... [TAG]... -V, --version print version number and configuration settings, then exit + --config print configuration, then exit -q, --quiet, --silent @@ -6578,8 +6861,9 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ bmake config.status 20171126 -configured by $0, generated by GNU Autoconf 2.64, - with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" -Copyright (C) 2009 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation @@ -6599,3 +6883,3 @@ do case $1 in - --*=*) + --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` @@ -6604,2 +6888,7 @@ do ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; *) @@ -6617,2 +6906,4 @@ do $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) @@ -6623,2 +6914,3 @@ do *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; esac @@ -6635,3 +6927,3 @@ do # Conflict between --help and --header - as_fn_error "ambiguous option: \`$1' + as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; @@ -6644,3 +6936,3 @@ Try \`$0 --help' for more information.";; # This is an error. - -*) as_fn_error "unrecognized option: \`$1' + -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; @@ -6664,3 +6956,3 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift @@ -6694,3 +6986,2 @@ do "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "makefile") CONFIG_FILES="$CONFIG_FILES makefile" ;; "Makefile.config") CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; @@ -6699,3 +6990,3 @@ do - *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac @@ -6721,5 +7012,6 @@ $debug || { - tmp= + tmp= ac_tmp= trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 @@ -6731,3 +7023,3 @@ $debug || tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" + test -d "$tmp" } || @@ -6736,3 +7028,4 @@ $debug || (umask 077 && mkdir "$tmp") -} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp @@ -6753,3 +7046,3 @@ ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\r' + ac_cs_awk_cr='\\r' else @@ -6758,3 +7051,3 @@ fi -echo 'BEGIN {' >"$tmp/subs1.awk" && +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF @@ -6767,4 +7060,4 @@ _ACEOF } >conf$$subs.sh || - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' @@ -6772,3 +7065,3 @@ for ac_last_try in false false false false false :; do . ./conf$$subs.sh || - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 @@ -6778,3 +7071,3 @@ for ac_last_try in false false false false false :; do elif $ac_last_try; then - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else @@ -6786,3 +7079,3 @@ rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF @@ -6800,3 +7093,3 @@ t delim h -s/\(.\{148\}\).*/\1/ +s/\(.\{148\}\)..*/\1/ t more1 @@ -6814,3 +7107,3 @@ t nl h -s/\(.\{148\}\).*/\1/ +s/\(.\{148\}\)..*/\1/ t more2 @@ -6834,3 +7127,3 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$tmp/subs1.awk" <<_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 @@ -6866,8 +7159,8 @@ else cat -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ - || as_fn_error "could not setup config files machinery" "$LINENO" 5 +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty @@ -6875,8 +7168,16 @@ _ACEOF if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=/{ -s/:*\$(srcdir):*/:/ -s/:*\${srcdir}:*/:/ -s/:*@srcdir@:*/:/ -s/^\([^=]*=[ ]*\):*/\1/ + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// s/^[^=]*=[ ]*$// @@ -6892,3 +7193,3 @@ fi # test -n "$CONFIG_FILES" if test -n "$CONFIG_HEADERS"; then -cat >"$tmp/defines.awk" <<\_ACAWK || +cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { @@ -6904,7 +7205,7 @@ ac_delim='%!_!# ' for ac_last_try in false false :; do - ac_t=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_t"; then + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then break elif $ac_last_try; then - as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else @@ -6993,3 +7294,3 @@ _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error "could not setup config headers machinery" "$LINENO" 5 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" @@ -7006,3 +7307,3 @@ do :[FHL]*:*);; - :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; @@ -7025,3 +7326,3 @@ do case $ac_f in - -) ac_f="$tmp/stdin";; + -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree @@ -7034,3 +7335,3 @@ do esac || - as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac @@ -7060,4 +7361,4 @@ $as_echo "$as_me: creating $ac_file" >&6;} case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac @@ -7191,19 +7492,20 @@ $ac_datarootdir_hack " -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&5 +which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&2;} +which seems to be undefined. Please make sure it is defined" >&2;} - rm -f "$tmp/stdin" + rm -f "$ac_tmp/stdin" case $ac_file in - -) cat "$tmp/out" && rm -f "$tmp/out";; - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; @@ -7216,6 +7518,6 @@ which seems to be undefined. Please make sure it is defined." >&2;} $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" - } >"$tmp/config.h" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 @@ -7224,4 +7526,4 @@ $as_echo "$as_me: $ac_file is unchanged" >&6;} rm -f "$ac_file" - mv "$tmp/config.h" "$ac_file" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi @@ -7229,4 +7531,4 @@ $as_echo "$as_me: $ac_file is unchanged" >&6;} $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error "could not create -" "$LINENO" 5 + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 fi @@ -7245,3 +7547,3 @@ ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || - as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 @@ -7266,3 +7568,3 @@ if test "$no_create" != yes; then # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit $? + $ac_cs_success || as_fn_exit 1 fi diff --git a/configure.in b/configure.in index ccd4262..81231ca 100644 --- a/configure.in +++ b/configure.in @@ -50,3 +50,3 @@ esac], [ -OS=`uname -s` +OS=`uname -s | cut -d_ -f1` for d in "/usr/include/dev/filemon" "$prefix/include/dev/filemon" "$srcdir/filemon" "$srcdir/../filemon" "$srcdir/../../sys/dev/filemon" @@ -125,2 +125,3 @@ AC_CHECK_HEADERS( \ sys/mman.h \ + sys/resource.h \ sys/select.h \ @@ -129,2 +130,4 @@ AC_CHECK_HEADERS( \ sys/uio.h \ + sys/utsname.h \ + sys/wait.h \ unistd.h \ @@ -153,2 +156,3 @@ AC_C_BIGENDIAN AC_C_CONST +AC_TYPE_INT32_T AC_TYPE_MODE_T @@ -169,18 +173,109 @@ dnl Keep this list sorted AC_CHECK_FUNCS( \ + _Exit \ + alloca \ + atoll \ + canonicalize_file_name \ + chown \ + dup2 \ + dup3 \ + endusershell \ err \ errx \ + euidaccess \ + faccessat \ + fchdir \ + fchmodat \ + fchownat \ + fcntl \ + fdatasync \ + fstatat \ + fsync \ + ftruncate \ + futimens \ getcwd \ + getdomainname \ + getdtablesize \ getenv \ + getgroups \ + gethostname \ + getloadavg \ + getlogin \ + getlogin_r \ getopt \ + getpass \ + getppid \ + getrusage \ + getsubopt \ + getusershell \ getwd \ + grantpt \ + group_member \ + initstate \ + initstate_r \ + kill \ killpg \ + lchmod \ + lchown \ + link \ + linkat \ + lstat \ + mkdirat \ + mkdtemp \ + mkfifo \ + mkfifoat \ + mknod \ + mknodat \ + mkostemp \ + mkostemps \ + mkstemp \ + mkstemps \ mmap \ + openat \ + pipe \ + pipe2 \ + poll \ + posix_openpt \ + pread \ + pthread_sigmask \ + ptsname \ + ptsname_r \ putenv \ + pwrite \ + qsort_r \ + raise \ + random \ + random_r \ + readlink \ + readlinkat \ + reallocarray \ + realpath \ + regcomp \ + regerror \ + regexec \ + regfree \ + rpmatch \ + secure_getenv \ select \ setenv \ + sethostname \ setpgid \ + setpgrp \ setsid \ + setstate \ + setstate_r \ + setusershell \ sigaction \ + sigaddset \ + sigdelset \ + sigemptyset \ + sigfillset \ + sigismember \ + signal \ + sigpending \ + sigprocmask \ sigvec \ + sleep \ snprintf \ + srandom \ + srandom_r \ strerror \ @@ -190,5 +285,17 @@ AC_CHECK_FUNCS( \ strtol \ + strtoll \ + strtoull \ + symlink \ + symlinkat \ sysctl \ + truncate \ + ttyname_r \ + uname \ + unlinkat \ + unlockpt \ unsetenv \ + usleep \ + utimensat \ vsnprintf \ + wait \ wait3 \ @@ -392,3 +499,3 @@ AC_SUBST(filemon_h) AC_SUBST(_MAKE_VERSION) -AC_OUTPUT(makefile Makefile.config make-bootstrap.sh unit-tests/Makefile) +AC_OUTPUT(Makefile.config make-bootstrap.sh unit-tests/Makefile) diff --git a/dir.c b/dir.c index 0062ac0..8ff040b 100644 --- a/dir.c +++ b/dir.c @@ -139,2 +139,5 @@ __RCSID("$NetBSD: dir.c,v 1.73 2018/07/12 18:03:31 christos Exp $"); #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif diff --git a/headers-mingw/fcntl.h b/headers-mingw/fcntl.h new file mode 100644 index 0000000..b63a9d3 --- /dev/null +++ b/headers-mingw/fcntl.h @@ -0,0 +1,244 @@ +/* Like , but with non-working flags defined to 0. + + Copyright (C) 2006-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* written by Paul Eggert */ + +/* Normal invocation convention. */ + +#ifndef _GL_FCNTL_H +#define _GL_FCNTL_H + +#ifndef __GLIBC__ /* Avoid namespace pollution on glibc systems. */ +# include +#endif + +/* Native Windows platforms declare open(), creat() in . */ +#if (defined _WIN32 && ! defined __CYGWIN__) +# include +#endif + + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + + +/* Declare overridden functions. */ + + + +#if !HAVE_FCNTL +extern int fcntl (int fd, int action, ...); +#endif + +#if !HAVE_OPENAT +extern int openat (int fd, char const *file, int flags, /* mode_t mode */ ...); +# endif + + + +/* Fix up the FD_* macros, only known to be missing on mingw. */ + +#ifndef FD_CLOEXEC +# define FD_CLOEXEC 1 +#endif + +/* Fix up the supported F_* macros. Intentionally leave other F_* + macros undefined. Only known to be missing on mingw. */ + +#ifndef F_DUPFD_CLOEXEC +# define F_DUPFD_CLOEXEC 0x40000000 +/* Witness variable: 1 if gnulib defined F_DUPFD_CLOEXEC, 0 otherwise. */ +# define GNULIB_defined_F_DUPFD_CLOEXEC 1 +#else +# define GNULIB_defined_F_DUPFD_CLOEXEC 0 +#endif + +#ifndef F_DUPFD +# define F_DUPFD 1 +#endif + +#ifndef F_GETFD +# define F_GETFD 2 +#endif + +/* Fix up the O_* macros. */ + +#if !defined O_DIRECT && defined O_DIRECTIO +/* Tru64 spells it 'O_DIRECTIO'. */ +# define O_DIRECT O_DIRECTIO +#endif + +#if !defined O_CLOEXEC && defined O_NOINHERIT +/* Mingw spells it 'O_NOINHERIT'. */ +# define O_CLOEXEC O_NOINHERIT +#endif + +#ifndef O_CLOEXEC +# define O_CLOEXEC 0x40000000 /* Try to not collide with system O_* flags. */ +# define GNULIB_defined_O_CLOEXEC 1 +#else +# define GNULIB_defined_O_CLOEXEC 0 +#endif + +#ifndef O_DIRECT +# define O_DIRECT 0 +#endif + +#ifndef O_DIRECTORY +# define O_DIRECTORY 0 +#endif + +#ifndef O_DSYNC +# define O_DSYNC 0 +#endif + +#ifndef O_EXEC +# define O_EXEC O_RDONLY /* This is often close enough in older systems. */ +#endif + +#ifndef O_IGNORE_CTTY +# define O_IGNORE_CTTY 0 +#endif + +#ifndef O_NDELAY +# define O_NDELAY 0 +#endif + +#ifndef O_NOATIME +# define O_NOATIME 0 +#endif + +#ifndef O_NONBLOCK +# define O_NONBLOCK O_NDELAY +#endif + +///* If the gnulib module 'nonblocking' is in use, guarantee a working non-zero +// value of O_NONBLOCK. Otherwise, O_NONBLOCK is defined (above) to O_NDELAY +// or to 0 as fallback. */ +//#if @GNULIB_NONBLOCKING@ +//# if O_NONBLOCK +//# define GNULIB_defined_O_NONBLOCK 0 +//# else +//# define GNULIB_defined_O_NONBLOCK 1 +//# undef O_NONBLOCK +//# define O_NONBLOCK 0x40000000 +//# endif +//#endif + +#ifndef O_NOCTTY +# define O_NOCTTY 0 +#endif + +#ifndef O_NOFOLLOW +# define O_NOFOLLOW 0 +#endif + +#ifndef O_NOLINK +# define O_NOLINK 0 +#endif + +#ifndef O_NOLINKS +# define O_NOLINKS 0 +#endif + +#ifndef O_NOTRANS +# define O_NOTRANS 0 +#endif + +#ifndef O_RSYNC +# define O_RSYNC 0 +#endif + +#ifndef O_SEARCH +# define O_SEARCH O_RDONLY /* This is often close enough in older systems. */ +#endif + +#ifndef O_SYNC +# define O_SYNC 0 +#endif + +#ifndef O_TTY_INIT +# define O_TTY_INIT 0 +#endif + +#if ~O_ACCMODE & (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) +# undef O_ACCMODE +# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) +#endif + +/* For systems that distinguish between text and binary I/O. + O_BINARY is usually declared in fcntl.h */ +#if !defined O_BINARY && defined _O_BINARY + /* For MSC-compatible compilers. */ +# define O_BINARY _O_BINARY +# define O_TEXT _O_TEXT +#endif + +#if defined __BEOS__ || defined __HAIKU__ + /* BeOS 5 and Haiku have O_BINARY and O_TEXT, but they have no effect. */ +# undef O_BINARY +# undef O_TEXT +#endif + +#ifndef O_BINARY +# define O_BINARY 0 +# define O_TEXT 0 +#endif + +/* Fix up the AT_* macros. */ + +/* Work around a bug in Solaris 9 and 10: AT_FDCWD is positive. Its + value exceeds INT_MAX, so its use as an int doesn't conform to the + C standard, and GCC and Sun C complain in some cases. If the bug + is present, undef AT_FDCWD here, so it can be redefined below. */ +#if 0 < AT_FDCWD && AT_FDCWD == 0xffd19553 +# undef AT_FDCWD +#endif + +/* Use the same bit pattern as Solaris 9, but with the proper + signedness. The bit pattern is important, in case this actually is + Solaris with the above workaround. */ +#ifndef AT_FDCWD +# define AT_FDCWD (-3041965) +#endif + +/* Use the same values as Solaris 9. This shouldn't matter, but + there's no real reason to differ. */ +#ifndef AT_SYMLINK_NOFOLLOW +# define AT_SYMLINK_NOFOLLOW 4096 +#endif + +#ifndef AT_REMOVEDIR +# define AT_REMOVEDIR 1 +#endif + +/* Solaris 9 lacks these two, so just pick unique values. */ +#ifndef AT_SYMLINK_FOLLOW +# define AT_SYMLINK_FOLLOW 2 +#endif + +#ifndef AT_EACCESS +# define AT_EACCESS 4 +#endif + + +#endif /* _@GUARD_PREFIX@_FCNTL_H */ + + diff --git a/headers-mingw/intprops.h b/headers-mingw/intprops.h new file mode 100644 index 0000000..9702aec --- /dev/null +++ b/headers-mingw/intprops.h @@ -0,0 +1,455 @@ +/* intprops.h -- properties of integer types + + Copyright (C) 2001-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert. */ + +#ifndef _GL_INTPROPS_H +#define _GL_INTPROPS_H + +#include + +/* Return a value with the common real type of E and V and the value of V. + Do not evaluate E. */ +#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v)) + +/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see + . */ +#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v)) + +/* The extra casts in the following macros work around compiler bugs, + e.g., in Cray C 5.0.3.0. */ + +/* True if the arithmetic type T is an integer type. bool counts as + an integer. */ +#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) + +/* True if the real type T is signed. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + +/* Return 1 if the real expression E, after promotion, has a + signed or floating type. Do not evaluate E. */ +#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0) + + +/* Minimum and maximum values for integer types and expressions. */ + +/* The width in bits of the integer type or expression T. + Do not evaluate T. + Padding bits are not supported; this is checked at compile-time below. */ +#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) + +/* The maximum and minimum values for the integer type T. */ +#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) +#define TYPE_MAXIMUM(t) \ + ((t) (! TYPE_SIGNED (t) \ + ? (t) -1 \ + : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) + +/* The maximum and minimum values for the type of the expression E, + after integer promotion. E is not evaluated. */ +#define _GL_INT_MINIMUM(e) \ + (EXPR_SIGNED (e) \ + ? ~ _GL_SIGNED_INT_MAXIMUM (e) \ + : _GL_INT_CONVERT (e, 0)) +#define _GL_INT_MAXIMUM(e) \ + (EXPR_SIGNED (e) \ + ? _GL_SIGNED_INT_MAXIMUM (e) \ + : _GL_INT_NEGATE_CONVERT (e, 1)) +#define _GL_SIGNED_INT_MAXIMUM(e) \ + (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1) + +/* Work around OpenVMS incompatibility with C99. */ +#if !defined LLONG_MAX && defined __INT64_MAX +# define LLONG_MAX __INT64_MAX +# define LLONG_MIN __INT64_MIN +#endif + +/* This include file assumes that signed types are two's complement without + padding bits; the above macros have undefined behavior otherwise. + If this is a problem for you, please let us know how to fix it for your host. + This assumption is tested by the intprops-tests module. */ + +/* Does the __typeof__ keyword work? This could be done by + 'configure', but for now it's easier to do it by hand. */ +#if (2 <= __GNUC__ \ + || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ + || (0x5110 <= __SUNPRO_C && !__STDC__)) +# define _GL_HAVE___TYPEOF__ 1 +#else +# define _GL_HAVE___TYPEOF__ 0 +#endif + +/* Return 1 if the integer type or expression T might be signed. Return 0 + if it is definitely unsigned. This macro does not evaluate its argument, + and expands to an integer constant expression. */ +#if _GL_HAVE___TYPEOF__ +# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t)) +#else +# define _GL_SIGNED_TYPE_OR_EXPR(t) 1 +#endif + +/* Bound on length of the string representing an unsigned integer + value representable in B bits. log10 (2.0) < 146/485. The + smallest value of B where this bound is not tight is 2621. */ +#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485) + +/* Bound on length of the string representing an integer type or expression T. + Subtract 1 for the sign bit if T is signed, and then add 1 more for + a minus sign if needed. + + Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 0 when its argument is + signed, this macro may overestimate the true bound by one byte when + applied to unsigned types of size 2, 4, 16, ... bytes. */ +#define INT_STRLEN_BOUND(t) \ + (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \ + + _GL_SIGNED_TYPE_OR_EXPR (t)) + +/* Bound on buffer size needed to represent an integer type or expression T, + including the terminating null. */ +#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) + + +/* Range overflow checks. + + The INT__RANGE_OVERFLOW macros return 1 if the corresponding C + operators might not yield numerically correct answers due to + arithmetic overflow. They do not rely on undefined or + implementation-defined behavior. Their implementations are simple + and straightforward, but they are a bit harder to use than the + INT__OVERFLOW macros described below. + + Example usage: + + long int i = ...; + long int j = ...; + if (INT_MULTIPLY_RANGE_OVERFLOW (i, j, LONG_MIN, LONG_MAX)) + printf ("multiply would overflow"); + else + printf ("product is %ld", i * j); + + Restrictions on *_RANGE_OVERFLOW macros: + + These macros do not check for all possible numerical problems or + undefined or unspecified behavior: they do not check for division + by zero, for bad shift counts, or for shifting negative numbers. + + These macros may evaluate their arguments zero or multiple times, + so the arguments should not have side effects. The arithmetic + arguments (including the MIN and MAX arguments) must be of the same + integer type after the usual arithmetic conversions, and the type + must have minimum value MIN and maximum MAX. Unsigned types should + use a zero MIN of the proper type. + + These macros are tuned for constant MIN and MAX. For commutative + operations such as A + B, they are also tuned for constant B. */ + +/* Return 1 if A + B would overflow in [MIN,MAX] arithmetic. + See above for restrictions. */ +#define INT_ADD_RANGE_OVERFLOW(a, b, min, max) \ + ((b) < 0 \ + ? (a) < (min) - (b) \ + : (max) - (b) < (a)) + +/* Return 1 if A - B would overflow in [MIN,MAX] arithmetic. + See above for restrictions. */ +#define INT_SUBTRACT_RANGE_OVERFLOW(a, b, min, max) \ + ((b) < 0 \ + ? (max) + (b) < (a) \ + : (a) < (min) + (b)) + +/* Return 1 if - A would overflow in [MIN,MAX] arithmetic. + See above for restrictions. */ +#define INT_NEGATE_RANGE_OVERFLOW(a, min, max) \ + ((min) < 0 \ + ? (a) < - (max) \ + : 0 < (a)) + +/* Return 1 if A * B would overflow in [MIN,MAX] arithmetic. + See above for restrictions. Avoid && and || as they tickle + bugs in Sun C 5.11 2010/08/13 and other compilers; see + . */ +#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \ + ((b) < 0 \ + ? ((a) < 0 \ + ? (a) < (max) / (b) \ + : (b) == -1 \ + ? 0 \ + : (min) / (b) < (a)) \ + : (b) == 0 \ + ? 0 \ + : ((a) < 0 \ + ? (a) < (min) / (b) \ + : (max) / (b) < (a))) + +/* Return 1 if A / B would overflow in [MIN,MAX] arithmetic. + See above for restrictions. Do not check for division by zero. */ +#define INT_DIVIDE_RANGE_OVERFLOW(a, b, min, max) \ + ((min) < 0 && (b) == -1 && (a) < - (max)) + +/* Return 1 if A % B would overflow in [MIN,MAX] arithmetic. + See above for restrictions. Do not check for division by zero. + Mathematically, % should never overflow, but on x86-like hosts + INT_MIN % -1 traps, and the C standard permits this, so treat this + as an overflow too. */ +#define INT_REMAINDER_RANGE_OVERFLOW(a, b, min, max) \ + INT_DIVIDE_RANGE_OVERFLOW (a, b, min, max) + +/* Return 1 if A << B would overflow in [MIN,MAX] arithmetic. + See above for restrictions. Here, MIN and MAX are for A only, and B need + not be of the same type as the other arguments. The C standard says that + behavior is undefined for shifts unless 0 <= B < wordwidth, and that when + A is negative then A << B has undefined behavior and A >> B has + implementation-defined behavior, but do not check these other + restrictions. */ +#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \ + ((a) < 0 \ + ? (a) < (min) >> (b) \ + : (max) >> (b) < (a)) + +/* True if __builtin_add_overflow (A, B, P) works when P is non-null. */ +#if 5 <= __GNUC__ && !defined __ICC +# define _GL_HAS_BUILTIN_OVERFLOW 1 +#else +# define _GL_HAS_BUILTIN_OVERFLOW 0 +#endif + +/* True if __builtin_add_overflow_p (A, B, C) works. */ +#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__) + +/* The _GL*_OVERFLOW macros have the same restrictions as the + *_RANGE_OVERFLOW macros, except that they do not assume that operands + (e.g., A and B) have the same type as MIN and MAX. Instead, they assume + that the result (e.g., A + B) has that type. */ +#if _GL_HAS_BUILTIN_OVERFLOW_P +# define _GL_ADD_OVERFLOW(a, b, min, max) \ + __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0) +# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ + __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0) +# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ + __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0) +#else +# define _GL_ADD_OVERFLOW(a, b, min, max) \ + ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \ + : (a) < 0 ? (b) <= (a) + (b) \ + : (b) < 0 ? (a) <= (a) + (b) \ + : (a) + (b) < (b)) +# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ + ((min) < 0 ? INT_SUBTRACT_RANGE_OVERFLOW (a, b, min, max) \ + : (a) < 0 ? 1 \ + : (b) < 0 ? (a) - (b) <= (a) \ + : (a) < (b)) +# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ + (((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \ + || INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max)) +#endif +#define _GL_DIVIDE_OVERFLOW(a, b, min, max) \ + ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ + : (a) < 0 ? (b) <= (a) + (b) - 1 \ + : (b) < 0 && (a) + (b) <= (a)) +#define _GL_REMAINDER_OVERFLOW(a, b, min, max) \ + ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ + : (a) < 0 ? (a) % (b) != ((max) - (b) + 1) % (b) \ + : (b) < 0 && ! _GL_UNSIGNED_NEG_MULTIPLE (a, b, max)) + +/* Return a nonzero value if A is a mathematical multiple of B, where + A is unsigned, B is negative, and MAX is the maximum value of A's + type. A's type must be the same as (A % B)'s type. Normally (A % + -B == 0) suffices, but things get tricky if -B would overflow. */ +#define _GL_UNSIGNED_NEG_MULTIPLE(a, b, max) \ + (((b) < -_GL_SIGNED_INT_MAXIMUM (b) \ + ? (_GL_SIGNED_INT_MAXIMUM (b) == (max) \ + ? (a) \ + : (a) % (_GL_INT_CONVERT (a, _GL_SIGNED_INT_MAXIMUM (b)) + 1)) \ + : (a) % - (b)) \ + == 0) + +/* Check for integer overflow, and report low order bits of answer. + + The INT__OVERFLOW macros return 1 if the corresponding C operators + might not yield numerically correct answers due to arithmetic overflow. + The INT__WRAPV macros also store the low-order bits of the answer. + These macros work correctly on all known practical hosts, and do not rely + on undefined behavior due to signed arithmetic overflow. + + Example usage, assuming A and B are long int: + + if (INT_MULTIPLY_OVERFLOW (a, b)) + printf ("result would overflow\n"); + else + printf ("result is %ld (no overflow)\n", a * b); + + Example usage with WRAPV flavor: + + long int result; + bool overflow = INT_MULTIPLY_WRAPV (a, b, &result); + printf ("result is %ld (%s)\n", result, + overflow ? "after overflow" : "no overflow"); + + Restrictions on these macros: + + These macros do not check for all possible numerical problems or + undefined or unspecified behavior: they do not check for division + by zero, for bad shift counts, or for shifting negative numbers. + + These macros may evaluate their arguments zero or multiple times, so the + arguments should not have side effects. + + The WRAPV macros are not constant expressions. They support only + +, binary -, and *. The result type must be signed. + + These macros are tuned for their last argument being a constant. + + Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B, + A % B, and A << B would overflow, respectively. */ + +#define INT_ADD_OVERFLOW(a, b) \ + _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW) +#define INT_SUBTRACT_OVERFLOW(a, b) \ + _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW) +#if _GL_HAS_BUILTIN_OVERFLOW_P +# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a) +#else +# define INT_NEGATE_OVERFLOW(a) \ + INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) +#endif +#define INT_MULTIPLY_OVERFLOW(a, b) \ + _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW) +#define INT_DIVIDE_OVERFLOW(a, b) \ + _GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW) +#define INT_REMAINDER_OVERFLOW(a, b) \ + _GL_BINARY_OP_OVERFLOW (a, b, _GL_REMAINDER_OVERFLOW) +#define INT_LEFT_SHIFT_OVERFLOW(a, b) \ + INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \ + _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) + +/* Return 1 if the expression A B would overflow, + where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test, + assuming MIN and MAX are the minimum and maximum for the result type. + Arguments should be free of side effects. */ +#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \ + op_result_overflow (a, b, \ + _GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \ + _GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b))) + +/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R. + Return 1 if the result overflows. See above for restrictions. */ +#define INT_ADD_WRAPV(a, b, r) \ + _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, INT_ADD_OVERFLOW) +#define INT_SUBTRACT_WRAPV(a, b, r) \ + _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, INT_SUBTRACT_OVERFLOW) +#define INT_MULTIPLY_WRAPV(a, b, r) \ + _GL_INT_OP_WRAPV (a, b, r, *, __builtin_mul_overflow, INT_MULTIPLY_OVERFLOW) + +/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See: + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193 + https://llvm.org/bugs/show_bug.cgi?id=25390 + For now, assume all versions of GCC-like compilers generate bogus + warnings for _Generic. This matters only for older compilers that + lack __builtin_add_overflow. */ +#if __GNUC__ +# define _GL__GENERIC_BOGUS 1 +#else +# define _GL__GENERIC_BOGUS 0 +#endif + +/* Store the low-order bits of A B into *R, where OP specifies + the operation. BUILTIN is the builtin operation, and OVERFLOW the + overflow predicate. Return 1 if the result overflows. See above + for restrictions. */ +#if _GL_HAS_BUILTIN_OVERFLOW +# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) builtin (a, b, r) +#elif 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS +# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \ + (_Generic \ + (*(r), \ + signed char: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + signed char, SCHAR_MIN, SCHAR_MAX), \ + short int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + short int, SHRT_MIN, SHRT_MAX), \ + int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + int, INT_MIN, INT_MAX), \ + long int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + long int, LONG_MIN, LONG_MAX), \ + long long int: \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ + long long int, LLONG_MIN, LLONG_MAX))) +#else +# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \ + (sizeof *(r) == sizeof (signed char) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + signed char, SCHAR_MIN, SCHAR_MAX) \ + : sizeof *(r) == sizeof (short int) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + short int, SHRT_MIN, SHRT_MAX) \ + : sizeof *(r) == sizeof (int) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ + int, INT_MIN, INT_MAX) \ + : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow)) +# ifdef LLONG_MAX +# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ + (sizeof *(r) == sizeof (long int) \ + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + long int, LONG_MIN, LONG_MAX) \ + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ + long long int, LLONG_MIN, LLONG_MAX)) +# else +# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ + long int, LONG_MIN, LONG_MAX) +# endif +#endif + +/* Store the low-order bits of A B into *R, where the operation + is given by OP. Use the unsigned type UT for calculation to avoid + overflow problems. *R's type is T, with extrema TMIN and TMAX. + T must be a signed integer type. Return 1 if the result overflows. */ +#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \ + (sizeof ((a) op (b)) < sizeof (t) \ + ? _GL_INT_OP_CALC1 ((t) (a), (t) (b), r, op, overflow, ut, t, tmin, tmax) \ + : _GL_INT_OP_CALC1 (a, b, r, op, overflow, ut, t, tmin, tmax)) +#define _GL_INT_OP_CALC1(a, b, r, op, overflow, ut, t, tmin, tmax) \ + ((overflow (a, b) \ + || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \ + || (tmax) < ((a) op (b))) \ + ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \ + : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0)) + +/* Return the low-order bits of A B, where the operation is given + by OP. Use the unsigned type UT for calculation to avoid undefined + behavior on signed integer overflow, and convert the result to type T. + UT is at least as wide as T and is no narrower than unsigned int, + T is two's complement, and there is no padding or trap representations. + Assume that converting UT to T yields the low-order bits, as is + done in all known two's-complement C compilers. E.g., see: + https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html + + According to the C standard, converting UT to T yields an + implementation-defined result or signal for values outside T's + range. However, code that works around this theoretical problem + runs afoul of a compiler bug in Oracle Studio 12.3 x86. See: + https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html + As the compiler bug is real, don't try to work around the + theoretical problem. */ + +#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \ + ((t) ((ut) (a) op (ut) (b))) + +#endif /* _GL_INTPROPS_H */ diff --git a/headers-mingw/langinfo.h b/headers-mingw/langinfo.h new file mode 100644 index 0000000..43244cd --- /dev/null +++ b/headers-mingw/langinfo.h @@ -0,0 +1,139 @@ +/* Substitute for and wrapper around . + Copyright (C) 2009-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* + * POSIX for platforms that lack it or have an incomplete one. + * + */ + +#ifndef _GL_LANGINFO_H +#define _GL_LANGINFO_H + + +/* A platform that lacks . */ + +/* Assume that it also lacks and the nl_item type. */ +# if !GNULIB_defined_nl_item +typedef int nl_item; +# define GNULIB_defined_nl_item 1 +# endif + +/* nl_langinfo items of the LC_CTYPE category */ +# define CODESET 10000 +/* nl_langinfo items of the LC_NUMERIC category */ +# define RADIXCHAR 10001 +# define DECIMAL_POINT RADIXCHAR +# define THOUSEP 10002 +# define THOUSANDS_SEP THOUSEP +# define GROUPING 10114 +/* nl_langinfo items of the LC_TIME category */ +# define D_T_FMT 10003 +# define D_FMT 10004 +# define T_FMT 10005 +# define T_FMT_AMPM 10006 +# define AM_STR 10007 +# define PM_STR 10008 +# define DAY_1 10009 +# define DAY_2 (DAY_1 + 1) +# define DAY_3 (DAY_1 + 2) +# define DAY_4 (DAY_1 + 3) +# define DAY_5 (DAY_1 + 4) +# define DAY_6 (DAY_1 + 5) +# define DAY_7 (DAY_1 + 6) +# define ABDAY_1 10016 +# define ABDAY_2 (ABDAY_1 + 1) +# define ABDAY_3 (ABDAY_1 + 2) +# define ABDAY_4 (ABDAY_1 + 3) +# define ABDAY_5 (ABDAY_1 + 4) +# define ABDAY_6 (ABDAY_1 + 5) +# define ABDAY_7 (ABDAY_1 + 6) +# define MON_1 10023 +# define MON_2 (MON_1 + 1) +# define MON_3 (MON_1 + 2) +# define MON_4 (MON_1 + 3) +# define MON_5 (MON_1 + 4) +# define MON_6 (MON_1 + 5) +# define MON_7 (MON_1 + 6) +# define MON_8 (MON_1 + 7) +# define MON_9 (MON_1 + 8) +# define MON_10 (MON_1 + 9) +# define MON_11 (MON_1 + 10) +# define MON_12 (MON_1 + 11) +# define ALTMON_1 10200 +# define ALTMON_2 (ALTMON_1 + 1) +# define ALTMON_3 (ALTMON_1 + 2) +# define ALTMON_4 (ALTMON_1 + 3) +# define ALTMON_5 (ALTMON_1 + 4) +# define ALTMON_6 (ALTMON_1 + 5) +# define ALTMON_7 (ALTMON_1 + 6) +# define ALTMON_8 (ALTMON_1 + 7) +# define ALTMON_9 (ALTMON_1 + 8) +# define ALTMON_10 (ALTMON_1 + 9) +# define ALTMON_11 (ALTMON_1 + 10) +# define ALTMON_12 (ALTMON_1 + 11) +# define ABMON_1 10035 +# define ABMON_2 (ABMON_1 + 1) +# define ABMON_3 (ABMON_1 + 2) +# define ABMON_4 (ABMON_1 + 3) +# define ABMON_5 (ABMON_1 + 4) +# define ABMON_6 (ABMON_1 + 5) +# define ABMON_7 (ABMON_1 + 6) +# define ABMON_8 (ABMON_1 + 7) +# define ABMON_9 (ABMON_1 + 8) +# define ABMON_10 (ABMON_1 + 9) +# define ABMON_11 (ABMON_1 + 10) +# define ABMON_12 (ABMON_1 + 11) +# define ERA 10047 +# define ERA_D_FMT 10048 +# define ERA_D_T_FMT 10049 +# define ERA_T_FMT 10050 +# define ALT_DIGITS 10051 +/* nl_langinfo items of the LC_MONETARY category */ +# define CRNCYSTR 10052 +# define CURRENCY_SYMBOL CRNCYSTR +# define INT_CURR_SYMBOL 10100 +# define MON_DECIMAL_POINT 10101 +# define MON_THOUSANDS_SEP 10102 +# define MON_GROUPING 10103 +# define POSITIVE_SIGN 10104 +# define NEGATIVE_SIGN 10105 +# define FRAC_DIGITS 10106 +# define INT_FRAC_DIGITS 10107 +# define P_CS_PRECEDES 10108 +# define N_CS_PRECEDES 10109 +# define P_SEP_BY_SPACE 10110 +# define N_SEP_BY_SPACE 10111 +# define P_SIGN_POSN 10112 +# define N_SIGN_POSN 10113 +/* nl_langinfo items of the LC_MESSAGES category */ +# define YESEXPR 10053 +# define NOEXPR 10054 + + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + +/* Declare overridden functions. */ + + +/* Return a piece of locale dependent information. + Note: The difference between nl_langinfo (CODESET) and locale_charset () + is that the latter normalizes the encoding names to GNU conventions. */ + +extern char * nl_langinfo (nl_item item); + +#endif /* _GL_LANGINFO_H */ diff --git a/headers-mingw/libc-config.h b/headers-mingw/libc-config.h new file mode 100644 index 0000000..a352393 --- /dev/null +++ b/headers-mingw/libc-config.h @@ -0,0 +1,174 @@ +/* System definitions for code taken from the GNU C Library + + Copyright 2017-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see + . */ + +/* Written by Paul Eggert. */ + +/* This is intended to be a good-enough substitute for glibc system + macros like those defined in , so that Gnulib code + shared with glibc can do this as the first #include: + + #ifndef _LIBC + # include + #endif + + When compiled as part of glibc this is a no-op; when compiled as + part of Gnulib this includes Gnulib's and defines macros + that glibc library code would normally assume. */ + +#include + +/* On glibc this includes and and #defines + _FEATURES_H, __WORDSIZE, and __set_errno. On FreeBSD 11 it + includes which defines __nonnull. Elsewhere it + is harmless. */ +#include + +/* From glibc . */ +#ifndef __set_errno +# define __set_errno(val) (errno = (val)) +#endif + +/* From glibc . */ + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) ((maj) < __GNUC__ + ((min) <= __GNUC_MINOR__)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#ifndef __glibc_clang_prereq +# if defined __clang_major__ && defined __clang_minor__ +# define __glibc_clang_prereq(maj, min) \ + ((maj) < __clang_major__ + ((min) <= __clang_minor__)) +# else +# define __glibc_clang_prereq(maj, min) 0 +# endif +#endif + + +/* Prepare to include , which is our copy of glibc + . */ + +/* Define _FEATURES_H so that does not include . */ +#ifndef _FEATURES_H +# define _FEATURES_H 1 +#endif +/* Define __WORDSIZE so that does not attempt to include + nonexistent files. Make it a syntax error, since Gnulib does not + use __WORDSIZE now, and if Gnulib uses it later the syntax error + will let us know that __WORDSIZE needs configuring. */ +#ifndef __WORDSIZE +# define __WORDSIZE %%% +#endif +/* Undef the macros unconditionally defined by our copy of glibc + , so that they do not clash with any system-defined + versions. */ +#undef _SYS_CDEFS_H +#undef __ASMNAME +#undef __ASMNAME2 +#undef __BEGIN_DECLS +#undef __CONCAT +#undef __END_DECLS +#undef __HAVE_GENERIC_SELECTION +#undef __LDBL_COMPAT +#undef __LDBL_REDIR +#undef __LDBL_REDIR1 +#undef __LDBL_REDIR1_DECL +#undef __LDBL_REDIR1_NTH +#undef __LDBL_REDIR_DECL +#undef __LDBL_REDIR_NTH +#undef __LEAF +#undef __LEAF_ATTR +#undef __NTH +#undef __NTHNL +#undef __P +#undef __PMT +#undef __REDIRECT +#undef __REDIRECT_LDBL +#undef __REDIRECT_NTH +#undef __REDIRECT_NTHNL +#undef __REDIRECT_NTH_LDBL +#undef __STRING +#undef __THROW +#undef __THROWNL +#undef __always_inline +#undef __attribute__ +#undef __attribute_alloc_size__ +#undef __attribute_artificial__ +#undef __attribute_const__ +#undef __attribute_deprecated__ +#undef __attribute_deprecated_msg__ +#undef __attribute_format_arg__ +#undef __attribute_format_strfmon__ +#undef __attribute_malloc__ +#undef __attribute_noinline__ +#undef __attribute_nonstring__ +#undef __attribute_pure__ +#undef __attribute_used__ +#undef __attribute_warn_unused_result__ +#undef __bos +#undef __bos0 +#undef __errordecl +#undef __extension__ +#undef __extern_always_inline +#undef __extern_inline +#undef __flexarr +#undef __fortify_function +#undef __glibc_c99_flexarr_available +#undef __glibc_clang_has_extension +#undef __glibc_likely +#undef __glibc_macro_warning +#undef __glibc_macro_warning1 +#undef __glibc_unlikely +#undef __inline +#undef __ptr_t +#undef __restrict +#undef __restrict_arr +#undef __va_arg_pack +#undef __va_arg_pack_len +#undef __warnattr +#undef __warndecl + +/* Include our copy of glibc . */ +#include "sys_cdefs.h" + +/* __inline is too pessimistic for non-GCC. */ +#undef __inline +#ifndef HAVE___INLINE +# if 199901 <= __STDC_VERSION__ || defined inline +# define __inline inline +# else +# define __inline +# endif +#endif + + +/* A substitute for glibc , good enough for Gnulib. */ +#define attribute_hidden +#define libc_hidden_proto(name, ...) +#define libc_hidden_def(name) +#define libc_hidden_weak(name) +#define libc_hidden_ver(local, name) +#define strong_alias(name, aliasname) +#define weak_alias(name, aliasname) + +/* A substitute for glibc , good enough for Gnulib. */ +#define SHLIB_COMPAT(lib, introduced, obsoleted) 0 +#define versioned_symbol(lib, local, symbol, version) diff --git a/headers-mingw/poll.h b/headers-mingw/poll.h new file mode 100644 index 0000000..fd3fb64 --- /dev/null +++ b/headers-mingw/poll.h @@ -0,0 +1,76 @@ +/* Header for poll(2) emulation + Contributed by Paolo Bonzini. + + Copyright 2001-2003, 2007, 2009-2018 Free Software Foundation, Inc. + + This file is part of gnulib. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see . */ + +#ifndef _GL_POLL_H + +#define _GL_POLL_H + + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + + +#if !HAVE_POLL_H + +/* fake a poll(2) environment */ +# define POLLIN 0x0001 /* any readable data available */ +# define POLLPRI 0x0002 /* OOB/Urgent readable data */ +# define POLLOUT 0x0004 /* file descriptor is writable */ +# define POLLERR 0x0008 /* some poll error occurred */ +# define POLLHUP 0x0010 /* file descriptor was "hung up" */ +# define POLLNVAL 0x0020 /* requested events "invalid" */ +# define POLLRDNORM 0x0040 +# define POLLRDBAND 0x0080 +# define POLLWRNORM 0x0100 +# define POLLWRBAND 0x0200 + +# if !GNULIB_defined_poll_types +# if !(defined _WIN32 && ! defined __CYGWIN__) +struct pollfd +{ + int fd; /* which file descriptor to poll */ + short events; /* events we are interested in */ + short revents; /* events found on return */ +}; + +# else +#include +# endif + +typedef unsigned long nfds_t; + +# define GNULIB_defined_poll_types 1 +# endif + +/* Define INFTIM only if doing so conforms to POSIX. */ +# if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE) +# define INFTIM (-1) +# endif + +#endif + + +# if !HAVE_POLL +extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout); +#endif + + +#endif /* _@GUARD_PREFIX@_POLL_H */ diff --git a/headers-mingw/regex.h b/headers-mingw/regex.h new file mode 100644 index 0000000..8d8160f --- /dev/null +++ b/headers-mingw/regex.h @@ -0,0 +1,635 @@ +/* Definitions for data structures and routines for the regular + expression library. + Copyright (C) 1985, 1989-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _REGEX_H +#define _REGEX_H 1 + +#include + +/* Allow the use in C++ code. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Define __USE_GNU to declare GNU extensions that violate the + POSIX name space rules. */ +#ifdef _GNU_SOURCE +# define __USE_GNU 1 +#endif + +#ifdef _REGEX_LARGE_OFFSETS + +/* Use types and values that are wide enough to represent signed and + unsigned byte offsets in memory. This currently works only when + the regex code is used outside of the GNU C library; it is not yet + supported within glibc itself, and glibc users should not define + _REGEX_LARGE_OFFSETS. */ + +/* The type of object sizes. */ +typedef size_t __re_size_t; + +/* The type of object sizes, in places where the traditional code + uses unsigned long int. */ +typedef size_t __re_long_size_t; + +#else + +/* The traditional GNU regex implementation mishandles strings longer + than INT_MAX. */ +typedef unsigned int __re_size_t; +typedef unsigned long int __re_long_size_t; + +#endif + +/* The following two types have to be signed and unsigned integer type + wide enough to hold a value of a pointer. For most ANSI compilers + ptrdiff_t and size_t should be likely OK. Still size of these two + types is 2 for Microsoft C. Ugh... */ +typedef long int s_reg_t; +typedef unsigned long int active_reg_t; + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned long int reg_syntax_t; + +/* If this bit is not set, then \ inside a bracket expression is literal. + If set, then such a \ quotes the following character. */ +# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) + +/* If this bit is not set, then + and ? are operators, and \+ and \? are + literals. + If set, then \+ and \? are operators and + and ? are literals. */ +# define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) + +/* If this bit is set, then character classes are supported. They are: + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. + If not set, then character classes are not supported. */ +# define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) + +/* If this bit is set, then ^ and $ are always anchors (outside bracket + expressions, of course). + If this bit is not set, then it depends: + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. + + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because + POSIX draft 11.2 says that * etc. in leading positions is undefined. + We already implemented a previous draft which made those constructs + invalid, though, so we haven't changed the code back. */ +# define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) + +/* If this bit is set, then special characters are always special + regardless of where they are in the pattern. + If this bit is not set, then special characters are special only in + some contexts; otherwise they are ordinary. Specifically, + * + ? and intervals are only special when not after the beginning, + open-group, or alternation operator. */ +# define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) + +/* If this bit is set, then *, +, ?, and { cannot be first in an re or + immediately after an alternation or begin-group operator. */ +# define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) + +/* If this bit is set, then . matches newline. + If not set, then it doesn't. */ +# define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) + +/* If this bit is set, then . doesn't match NUL. + If not set, then it does. */ +# define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) + +/* If this bit is set, nonmatching lists [^...] do not match newline. + If not set, they do. */ +# define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) + +/* If this bit is set, either \{...\} or {...} defines an + interval, depending on RE_NO_BK_BRACES. + If not set, \{, \}, {, and } are literals. */ +# define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) + +/* If this bit is set, +, ? and | aren't recognized as operators. + If not set, they are. */ +# define RE_LIMITED_OPS (RE_INTERVALS << 1) + +/* If this bit is set, newline is an alternation operator. + If not set, newline is literal. */ +# define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) + +/* If this bit is set, then '{...}' defines an interval, and \{ and \} + are literals. + If not set, then '\{...\}' defines an interval. */ +# define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) + +/* If this bit is set, (...) defines a group, and \( and \) are literals. + If not set, \(...\) defines a group, and ( and ) are literals. */ +# define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) + +/* If this bit is set, then \ matches . + If not set, then \ is a back-reference. */ +# define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) + +/* If this bit is set, then | is an alternation operator, and \| is literal. + If not set, then \| is an alternation operator, and | is literal. */ +# define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) + +/* If this bit is set, then an ending range point collating higher + than the starting range point, as in [z-a], is invalid. + If not set, then when ending range point collates higher than the + starting range point, the range is ignored. */ +# define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) + +/* If this bit is set, then an unmatched ) is ordinary. + If not set, then an unmatched ) is invalid. */ +# define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) + +/* If this bit is set, succeed as soon as we match the whole pattern, + without further backtracking. */ +# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) + +/* If this bit is set, do not process the GNU regex operators. + If not set, then the GNU regex operators are recognized. */ +# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) + +/* If this bit is set, turn on internal regex debugging. + If not set, and debugging was on, turn it off. + This only works if regex.c is compiled -DDEBUG. + We define this bit always, so that all that's needed to turn on + debugging is to recompile regex.c; the calling code can always have + this bit set, and it won't affect anything in the normal case. */ +# define RE_DEBUG (RE_NO_GNU_OPS << 1) + +/* If this bit is set, a syntactically invalid interval is treated as + a string of ordinary characters. For example, the ERE 'a{1' is + treated as 'a\{1'. */ +# define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) + +/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only + for ^, because it is difficult to scan the regex backwards to find + whether ^ should be special. */ +# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) + +/* If this bit is set, then \{ cannot be first in a regex or + immediately after an alternation, open-group or \} operator. */ +# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) + +/* If this bit is set, then no_sub will be set to 1 during + re_compile_pattern. */ +# define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) + + +/* This global variable defines the particular regexp syntax to use (for + some interfaces). When a regexp is compiled, the syntax used is + stored in the pattern buffer, so changing this does not affect + already-compiled regexps. */ +extern reg_syntax_t re_syntax_options; + + +/* Define combinations of the above bits for the standard possibilities. + (The [[[ comments delimit what gets put into the Texinfo file, so + don't delete them!) */ +/* [[[begin syntaxes]]] */ +# define RE_SYNTAX_EMACS 0 + +# define RE_SYNTAX_AWK \ + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ + | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CHAR_CLASSES \ + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) + +# define RE_SYNTAX_GNU_AWK \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INVALID_INTERVAL_ORD) \ + & ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \ + | RE_CONTEXT_INVALID_OPS )) + +# define RE_SYNTAX_POSIX_AWK \ + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ + | RE_INTERVALS | RE_NO_GNU_OPS \ + | RE_INVALID_INTERVAL_ORD) + +# define RE_SYNTAX_GREP \ + ((RE_SYNTAX_POSIX_BASIC | RE_NEWLINE_ALT) \ + & ~(RE_CONTEXT_INVALID_DUP | RE_DOT_NOT_NULL)) + +# define RE_SYNTAX_EGREP \ + ((RE_SYNTAX_POSIX_EXTENDED | RE_INVALID_INTERVAL_ORD | RE_NEWLINE_ALT) \ + & ~(RE_CONTEXT_INVALID_OPS | RE_DOT_NOT_NULL)) + +/* POSIX grep -E behavior is no longer incompatible with GNU. */ +# define RE_SYNTAX_POSIX_EGREP \ + RE_SYNTAX_EGREP + +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ +# define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + +# define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + +/* Syntax bits common to both basic and extended POSIX regex syntax. */ +# define _RE_SYNTAX_POSIX_COMMON \ + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ + | RE_INTERVALS | RE_NO_EMPTY_RANGES) + +# define RE_SYNTAX_POSIX_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) + +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this + isn't minimal, since other operators, such as \`, aren't disabled. */ +# define RE_SYNTAX_POSIX_MINIMAL_BASIC \ + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) + +# define RE_SYNTAX_POSIX_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ + | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) + +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is + removed and RE_NO_BK_REFS is added. */ +# define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) +/* [[[end syntaxes]]] */ + + +/* RE_DUP_MAX is 2**15 - 1 because an earlier implementation stored + the counter as a 2-byte signed integer. This is no longer true, so + RE_DUP_MAX could be increased to (INT_MAX / 10 - 1), or to + ((SIZE_MAX - 9) / 10) if _REGEX_LARGE_OFFSETS is defined. + However, there would be a huge performance problem if someone + actually used a pattern like a\{214748363\}, so RE_DUP_MAX retains + its historical value. */ +# define RE_DUP_MAX (0x7fff) + + + +/* POSIX 'cflags' bits (i.e., information for 'regcomp'). */ + +/* If this bit is set, then use extended regular expression syntax. + If not set, then use basic regular expression syntax. */ +#define REG_EXTENDED 1 + +/* If this bit is set, then ignore case when matching. + If not set, then case is significant. */ +#define REG_ICASE (1 << 1) + +/* If this bit is set, then anchors do not match at newline + characters in the string. + If not set, then anchors do match at newlines. */ +#define REG_NEWLINE (1 << 2) + +/* If this bit is set, then report only success or fail in regexec. + If not set, then returns differ between not matching and errors. */ +#define REG_NOSUB (1 << 3) + + +/* POSIX 'eflags' bits (i.e., information for regexec). */ + +/* If this bit is set, then the beginning-of-line operator doesn't match + the beginning of the string (presumably because it's not the + beginning of a line). + If not set, then the beginning-of-line operator does match the + beginning of the string. */ +#define REG_NOTBOL 1 + +/* Like REG_NOTBOL, except for the end-of-line. */ +#define REG_NOTEOL (1 << 1) + +/* Use PMATCH[0] to delimit the start and end of the search in the + buffer. */ +#define REG_STARTEND (1 << 2) + + +/* If any error codes are removed, changed, or added, update the + '__re_error_msgid' table in regcomp.c. */ + +typedef enum +{ + _REG_ENOSYS = -1, /* This will never happen for this implementation. */ + _REG_NOERROR = 0, /* Success. */ + _REG_NOMATCH, /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ + _REG_BADPAT, /* Invalid pattern. */ + _REG_ECOLLATE, /* Invalid collating element. */ + _REG_ECTYPE, /* Invalid character class name. */ + _REG_EESCAPE, /* Trailing backslash. */ + _REG_ESUBREG, /* Invalid back reference. */ + _REG_EBRACK, /* Unmatched left bracket. */ + _REG_EPAREN, /* Parenthesis imbalance. */ + _REG_EBRACE, /* Unmatched \{. */ + _REG_BADBR, /* Invalid contents of \{\}. */ + _REG_ERANGE, /* Invalid range end. */ + _REG_ESPACE, /* Ran out of memory. */ + _REG_BADRPT, /* No preceding re for repetition op. */ + + /* Error codes we've added. */ + _REG_EEND, /* Premature end. */ + _REG_ESIZE, /* Too large (e.g., repeat count too large). */ + _REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ +} reg_errcode_t; + +#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K +# define REG_ENOSYS _REG_ENOSYS +#endif +#define REG_NOERROR _REG_NOERROR +#define REG_NOMATCH _REG_NOMATCH +#define REG_BADPAT _REG_BADPAT +#define REG_ECOLLATE _REG_ECOLLATE +#define REG_ECTYPE _REG_ECTYPE +#define REG_EESCAPE _REG_EESCAPE +#define REG_ESUBREG _REG_ESUBREG +#define REG_EBRACK _REG_EBRACK +#define REG_EPAREN _REG_EPAREN +#define REG_EBRACE _REG_EBRACE +#define REG_BADBR _REG_BADBR +#define REG_ERANGE _REG_ERANGE +#define REG_ESPACE _REG_ESPACE +#define REG_BADRPT _REG_BADRPT +#define REG_EEND _REG_EEND +#define REG_ESIZE _REG_ESIZE +#define REG_ERPAREN _REG_ERPAREN + +/* This data structure represents a compiled pattern. Before calling + the pattern compiler, the fields 'buffer', 'allocated', 'fastmap', + and 'translate' can be set. After the pattern has been compiled, + the fields 're_nsub', 'not_bol' and 'not_eol' are available. All + other fields are private to the regex routines. */ + +#ifndef RE_TRANSLATE_TYPE +# define __RE_TRANSLATE_TYPE unsigned char * + +# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE + +#endif + +# define __REPB_PREFIX(name) name + +struct re_pattern_buffer +{ + /* Space that holds the compiled pattern. The type + 'struct re_dfa_t' is private and is not declared here. */ + struct re_dfa_t *__REPB_PREFIX(buffer); + + /* Number of bytes to which 'buffer' points. */ + __re_long_size_t __REPB_PREFIX(allocated); + + /* Number of bytes actually used in 'buffer'. */ + __re_long_size_t __REPB_PREFIX(used); + + /* Syntax setting with which the pattern was compiled. */ + reg_syntax_t __REPB_PREFIX(syntax); + + /* Pointer to a fastmap, if any, otherwise zero. re_search uses the + fastmap, if there is one, to skip over impossible starting points + for matches. */ + char *__REPB_PREFIX(fastmap); + + /* Either a translate table to apply to all characters before + comparing them, or zero for no translation. The translation is + applied to a pattern when it is compiled and to a string when it + is matched. */ + __RE_TRANSLATE_TYPE __REPB_PREFIX(translate); + + /* Number of subexpressions found by the compiler. */ + size_t re_nsub; + + /* Zero if this pattern cannot match the empty string, one else. + Well, in truth it's used only in 're_search_2', to see whether or + not we should use the fastmap, so we don't set this absolutely + perfectly; see 're_compile_fastmap' (the "duplicate" case). */ + unsigned __REPB_PREFIX(can_be_null) : 1; + + /* If REGS_UNALLOCATED, allocate space in the 'regs' structure + for 'max (RE_NREGS, re_nsub + 1)' groups. + If REGS_REALLOCATE, reallocate space if necessary. + If REGS_FIXED, use what's there. */ + +# define REGS_UNALLOCATED 0 +# define REGS_REALLOCATE 1 +# define REGS_FIXED 2 + + unsigned __REPB_PREFIX(regs_allocated) : 2; + + /* Set to zero when 're_compile_pattern' compiles a pattern; set to + one by 're_compile_fastmap' if it updates the fastmap. */ + unsigned __REPB_PREFIX(fastmap_accurate) : 1; + + /* If set, 're_match_2' does not return information about + subexpressions. */ + unsigned __REPB_PREFIX(no_sub) : 1; + + /* If set, a beginning-of-line anchor doesn't match at the beginning + of the string. */ + unsigned __REPB_PREFIX(not_bol) : 1; + + /* Similarly for an end-of-line anchor. */ + unsigned __REPB_PREFIX(not_eol) : 1; + + /* If true, an anchor at a newline matches. */ + unsigned __REPB_PREFIX(newline_anchor) : 1; +}; + +typedef struct re_pattern_buffer regex_t; + +/* Type for byte offsets within the string. POSIX mandates this. */ +#ifdef _REGEX_LARGE_OFFSETS +/* POSIX 1003.1-2008 requires that regoff_t be at least as wide as + ptrdiff_t and ssize_t. We don't know of any hosts where ptrdiff_t + is wider than ssize_t, so ssize_t is safe. ptrdiff_t is not + visible here, so use ssize_t. */ +typedef ssize_t regoff_t; +#else +/* The traditional GNU regex implementation mishandles strings longer + than INT_MAX. */ +typedef int regoff_t; +#endif + + + +/* This is the structure we store register match data in. See + regex.texinfo for a full description of what registers match. */ +struct re_registers +{ + __re_size_t num_regs; + regoff_t *start; + regoff_t *end; +}; + + +/* If 'regs_allocated' is REGS_UNALLOCATED in the pattern buffer, + 're_match_2' returns information about at least this many registers + the first time a 'regs' structure is passed. */ +# ifndef RE_NREGS +# define RE_NREGS 30 +# endif + + + +/* POSIX specification for registers. Aside from the different names than + 're_registers', POSIX uses an array of structures, instead of a + structure of arrays. */ +typedef struct +{ + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ +} regmatch_t; + +/* Declarations for routines. */ + + +/* Sets the current default syntax to SYNTAX, and return the old syntax. + You can also simply assign to the 're_syntax_options' variable. */ +extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); + +/* Compile the regular expression PATTERN, with length LENGTH + and syntax given by the global 're_syntax_options', into the buffer + BUFFER. Return NULL if successful, and an error string if not. + + To free the allocated storage, you must call 'regfree' on BUFFER. + Note that the translate table must either have been initialized by + 'regcomp', with a malloc'ed value, or set to NULL before calling + 'regfree'. */ +extern const char *re_compile_pattern (const char *__pattern, size_t __length, + struct re_pattern_buffer *__buffer); + + +/* Compile a fastmap for the compiled pattern in BUFFER; used to + accelerate searches. Return 0 if successful and -2 if was an + internal error. */ +extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); + + +/* Search in the string STRING (with length LENGTH) for the pattern + compiled into BUFFER. Start searching at position START, for RANGE + characters. Return the starting position of the match, -1 for no + match, or -2 for an internal error. Also return register + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ +extern regoff_t re_search (struct re_pattern_buffer *__buffer, + const char *__String, regoff_t __length, + regoff_t __start, regoff_t __range, + struct re_registers *__regs); + + +/* Like 're_search', but search in the concatenation of STRING1 and + STRING2. Also, stop searching at index START + STOP. */ +extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer, + const char *__string1, regoff_t __length1, + const char *__string2, regoff_t __length2, + regoff_t __start, regoff_t __range, + struct re_registers *__regs, + regoff_t __stop); + + +/* Like 're_search', but return how many characters in STRING the regexp + in BUFFER matched, starting at position START. */ +extern regoff_t re_match (struct re_pattern_buffer *__buffer, + const char *__String, regoff_t __length, + regoff_t __start, struct re_registers *__regs); + + +/* Relates to 're_match' as 're_search_2' relates to 're_search'. */ +extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer, + const char *__string1, regoff_t __length1, + const char *__string2, regoff_t __length2, + regoff_t __start, struct re_registers *__regs, + regoff_t __stop); + + +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and + ENDS. Subsequent matches using BUFFER and REGS will use this memory + for recording register information. STARTS and ENDS must be + allocated with malloc, and must each be at least 'NUM_REGS * sizeof + (regoff_t)' bytes long. + + If NUM_REGS == 0, then subsequent matches should allocate their own + register data. + + Unless this function is called, the first search or match using + BUFFER will allocate its own register data, without + freeing the old data. */ +extern void re_set_registers (struct re_pattern_buffer *__buffer, + struct re_registers *__regs, + __re_size_t __num_regs, + regoff_t *__starts, regoff_t *__ends); + +/* For plain 'restrict', use glibc's __restrict if defined. + Otherwise, GCC 2.95 and later have "__restrict"; C99 compilers have + "restrict", and "configure" may have defined "restrict". + Other compilers use __restrict, __restrict__, and _Restrict, and + 'configure' might #define 'restrict' to those words, so pick a + different name. */ +#ifndef _Restrict_ +# if defined __restrict || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) +# define _Restrict_ __restrict +# elif 199901L <= __STDC_VERSION__ || defined restrict +# define _Restrict_ restrict +# else +# define _Restrict_ +# endif +#endif +/* For [restrict], use glibc's __restrict_arr if available. + Otherwise, GCC 3.1 (not in C++ mode) and C99 support [restrict]. */ +#ifndef _Restrict_arr_ +# ifdef __restrict_arr +# define _Restrict_arr_ __restrict_arr +# elif ((199901L <= __STDC_VERSION__ || 3 < __GNUC__ + (1 <= __GNUC_MINOR__)) \ + && !defined __GNUG__) +# define _Restrict_arr_ _Restrict_ +# else +# define _Restrict_arr_ +# endif +#endif + +/* POSIX compatibility. */ +extern int regcomp (regex_t *_Restrict_ __preg, + const char *_Restrict_ __pattern, + int __cflags); + +extern int regexec (const regex_t *_Restrict_ __preg, + const char *_Restrict_ __String, size_t __nmatch, + regmatch_t __pmatch[_Restrict_arr_], + int __eflags); + +extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg, + char *_Restrict_ __errbuf, size_t __errbuf_size); + +extern void regfree (regex_t *__preg); + + +#ifdef __cplusplus +} +#endif /* C++ */ + +#endif /* regex.h */ diff --git a/headers-mingw/regex_internal.h b/headers-mingw/regex_internal.h new file mode 100644 index 0000000..b4ae872 --- /dev/null +++ b/headers-mingw/regex_internal.h @@ -0,0 +1,780 @@ +/* Extended regular expression matching and search library. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _REGEX_INTERNAL_H +#define _REGEX_INTERNAL_H 1 + +#include +#include +#include +#include +#include + +#include "langinfo.h" +#include +#include +#include +#include +#include + +#include "intprops.h" + +#ifdef _LIBC +# include +# define lock_define(name) __libc_lock_define (, name) +# define lock_init(lock) (__libc_lock_init (lock), 0) +# define lock_fini(lock) ((void) 0) +# define lock_lock(lock) __libc_lock_lock (lock) +# define lock_unlock(lock) __libc_lock_unlock (lock) +#elif defined GNULIB_LOCK && !defined USE_UNLOCKED_IO +# include "glthread/lock.h" + /* Use gl_lock_define if empty macro arguments are known to work. + Otherwise, fall back on less-portable substitutes. */ +# if ((defined __GNUC__ && !defined __STRICT_ANSI__) \ + || (defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__)) +# define lock_define(name) gl_lock_define (, name) +# elif USE_POSIX_THREADS +# define lock_define(name) pthread_mutex_t name; +# elif USE_PTH_THREADS +# define lock_define(name) pth_mutex_t name; +# elif USE_SOLARIS_THREADS +# define lock_define(name) mutex_t name; +# elif USE_WINDOWS_THREADS +# define lock_define(name) gl_lock_t name; +# else +# define lock_define(name) +# endif +# define lock_init(lock) glthread_lock_init (&(lock)) +# define lock_fini(lock) glthread_lock_destroy (&(lock)) +# define lock_lock(lock) glthread_lock_lock (&(lock)) +# define lock_unlock(lock) glthread_lock_unlock (&(lock)) +#elif defined GNULIB_PTHREAD && !defined USE_UNLOCKED_IO +# include +# define lock_define(name) pthread_mutex_t name; +# define lock_init(lock) pthread_mutex_init (&(lock), 0) +# define lock_fini(lock) pthread_mutex_destroy (&(lock)) +# define lock_lock(lock) pthread_mutex_lock (&(lock)) +# define lock_unlock(lock) pthread_mutex_unlock (&(lock)) +#else +# define lock_define(name) +# define lock_init(lock) 0 +# define lock_fini(lock) ((void) 0) + /* The 'dfa' avoids an "unused variable 'dfa'" warning from GCC. */ +# define lock_lock(lock) ((void) dfa) +# define lock_unlock(lock) ((void) 0) +#endif + +/* In case that the system doesn't have isblank(). */ +#if !defined _LIBC && ! (defined isblank || (HAVE_ISBLANK && HAVE_DECL_ISBLANK)) +# define isblank(ch) ((ch) == ' ' || (ch) == '\t') +#endif + + +# undef gettext +# define gettext(msgid) (msgid) + + +#ifndef gettext_noop +/* This define is so xgettext can find the internationalizable + strings. */ +# define gettext_noop(String) String +#endif + +/* Number of ASCII characters. */ +#define ASCII_CHARS 0x80 + +/* Number of single byte characters. */ +#define SBC_MAX (UCHAR_MAX + 1) + +#define COLL_ELEM_LEN_MAX 8 + +/* The character which represents newline. */ +#define NEWLINE_CHAR '\n' +#define WIDE_NEWLINE_CHAR L'\n' + +/* Rename to standard API for using out of glibc. */ +#ifndef _LIBC +# undef __wctype +# undef __iswalnum +# undef __iswctype +# undef __towlower +# undef __towupper +# define __wctype wctype +# define __iswalnum iswalnum +# define __iswctype iswctype +# define __towlower towlower +# define __towupper towupper +# define __btowc btowc +# define __mbrtowc mbrtowc +# define __wcrtomb wcrtomb +# define __regfree regfree +# define attribute_hidden +#endif /* not _LIBC */ + +#if __GNUC__ < 3 + (__GNUC_MINOR__ < 1) +# define __attribute__(arg) +#endif + +#ifndef SSIZE_MAX +# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) +#endif + +/* The type of indexes into strings. This is signed, not size_t, + since the API requires indexes to fit in regoff_t anyway, and using + signed integers makes the code a bit smaller and presumably faster. + The traditional GNU regex implementation uses int for indexes. + The POSIX-compatible implementation uses a possibly-wider type. + The name 'Idx' is three letters to minimize the hassle of + reindenting a lot of regex code that formerly used 'int'. */ +typedef regoff_t Idx; +#ifdef _REGEX_LARGE_OFFSETS +# define IDX_MAX SSIZE_MAX +#else +# define IDX_MAX INT_MAX +#endif + +#ifdef _REGEX_LARGE_OFFSETS + +/* Use types and values that are wide enough to represent signed and + unsigned byte offsets in memory. This currently works only when + the regex code is used outside of the GNU C library; it is not yet + supported within glibc itself, and glibc users should not define + _REGEX_LARGE_OFFSETS. */ + +/* The type of object sizes. */ +typedef size_t __re_size_t; + +/* The type of object sizes, in places where the traditional code + uses unsigned long int. */ +typedef size_t __re_long_size_t; + +#else + +/* The traditional GNU regex implementation mishandles strings longer + than INT_MAX. */ +typedef unsigned int __re_size_t; +typedef unsigned long int __re_long_size_t; + +#endif + +#ifndef RE_TRANSLATE_TYPE +# define __RE_TRANSLATE_TYPE unsigned char * +# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE +#endif + +/* The following bits are used to determine the regexp syntax we + recognize. The set/not-set meanings are chosen so that Emacs syntax + remains the value 0. The bits are given in alphabetical order, and + the definitions shifted by one from the previous bit; thus, when we + add or remove a bit, only one other definition need change. */ +typedef unsigned long int reg_syntax_t; + +/* A hash value, suitable for computing hash tables. */ +typedef __re_size_t re_hashval_t; + +/* An integer used to represent a set of bits. It must be unsigned, + and must be at least as wide as unsigned int. */ +typedef unsigned long int bitset_word_t; +/* All bits set in a bitset_word_t. */ +#define BITSET_WORD_MAX ULONG_MAX + +/* Number of bits in a bitset_word_t. For portability to hosts with + padding bits, do not use '(sizeof (bitset_word_t) * CHAR_BIT)'; + instead, deduce it directly from BITSET_WORD_MAX. Avoid + greater-than-32-bit integers and unconditional shifts by more than + 31 bits, as they're not portable. */ +#if BITSET_WORD_MAX == 0xffffffffUL +# define BITSET_WORD_BITS 32 +#elif BITSET_WORD_MAX >> 31 >> 4 == 1 +# define BITSET_WORD_BITS 36 +#elif BITSET_WORD_MAX >> 31 >> 16 == 1 +# define BITSET_WORD_BITS 48 +#elif BITSET_WORD_MAX >> 31 >> 28 == 1 +# define BITSET_WORD_BITS 60 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 1 == 1 +# define BITSET_WORD_BITS 64 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 9 == 1 +# define BITSET_WORD_BITS 72 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 3 == 1 +# define BITSET_WORD_BITS 128 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 == 1 +# define BITSET_WORD_BITS 256 +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 > 1 +# define BITSET_WORD_BITS 257 /* any value > SBC_MAX will do here */ +# if BITSET_WORD_BITS <= SBC_MAX +# error "Invalid SBC_MAX" +# endif +#else +# error "Add case for new bitset_word_t size" +#endif + +/* Number of bitset_word_t values in a bitset_t. */ +#define BITSET_WORDS ((SBC_MAX + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS) + +typedef bitset_word_t bitset_t[BITSET_WORDS]; +typedef bitset_word_t *re_bitset_ptr_t; +typedef const bitset_word_t *re_const_bitset_ptr_t; + +#define PREV_WORD_CONSTRAINT 0x0001 +#define PREV_NOTWORD_CONSTRAINT 0x0002 +#define NEXT_WORD_CONSTRAINT 0x0004 +#define NEXT_NOTWORD_CONSTRAINT 0x0008 +#define PREV_NEWLINE_CONSTRAINT 0x0010 +#define NEXT_NEWLINE_CONSTRAINT 0x0020 +#define PREV_BEGBUF_CONSTRAINT 0x0040 +#define NEXT_ENDBUF_CONSTRAINT 0x0080 +#define WORD_DELIM_CONSTRAINT 0x0100 +#define NOT_WORD_DELIM_CONSTRAINT 0x0200 + +typedef enum +{ + INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, + WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, + WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, + INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, + LINE_FIRST = PREV_NEWLINE_CONSTRAINT, + LINE_LAST = NEXT_NEWLINE_CONSTRAINT, + BUF_FIRST = PREV_BEGBUF_CONSTRAINT, + BUF_LAST = NEXT_ENDBUF_CONSTRAINT, + WORD_DELIM = WORD_DELIM_CONSTRAINT, + NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT +} re_context_type; + +typedef struct +{ + Idx alloc; + Idx nelem; + Idx *elems; +} re_node_set; + +typedef enum +{ + NON_TYPE = 0, + + /* Node type, These are used by token, node, tree. */ + CHARACTER = 1, + END_OF_RE = 2, + SIMPLE_BRACKET = 3, + OP_BACK_REF = 4, + OP_PERIOD = 5, + + /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used + when the debugger shows values of this enum type. */ +#define EPSILON_BIT 8 + OP_OPEN_SUBEXP = EPSILON_BIT | 0, + OP_CLOSE_SUBEXP = EPSILON_BIT | 1, + OP_ALT = EPSILON_BIT | 2, + OP_DUP_ASTERISK = EPSILON_BIT | 3, + ANCHOR = EPSILON_BIT | 4, + + /* Tree type, these are used only by tree. */ + CONCAT = 16, + SUBEXP = 17, + + /* Token type, these are used only by token. */ + OP_DUP_PLUS = 18, + OP_DUP_QUESTION, + OP_OPEN_BRACKET, + OP_CLOSE_BRACKET, + OP_CHARSET_RANGE, + OP_OPEN_DUP_NUM, + OP_CLOSE_DUP_NUM, + OP_NON_MATCH_LIST, + OP_OPEN_COLL_ELEM, + OP_CLOSE_COLL_ELEM, + OP_OPEN_EQUIV_CLASS, + OP_CLOSE_EQUIV_CLASS, + OP_OPEN_CHAR_CLASS, + OP_CLOSE_CHAR_CLASS, + OP_WORD, + OP_NOTWORD, + OP_SPACE, + OP_NOTSPACE, + BACK_SLASH + +} re_token_type_t; + +typedef struct +{ + union + { + unsigned char c; /* for CHARACTER */ + re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ + Idx idx; /* for BACK_REF */ + re_context_type ctx_type; /* for ANCHOR */ + } opr; +#if __GNUC__ >= 2 && !defined __STRICT_ANSI__ + re_token_type_t type : 8; +#else + re_token_type_t type; +#endif + unsigned int constraint : 10; /* context constraint */ + unsigned int duplicated : 1; + unsigned int opt_subexp : 1; + unsigned int word_char : 1; +} re_token_t; + +#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT) + +struct re_string_t +{ + /* Indicate the raw buffer which is the original string passed as an + argument of regexec(), re_search(), etc.. */ + const unsigned char *raw_mbs; + /* Store the multibyte string. In case of "case insensitive mode" like + REG_ICASE, upper cases of the string are stored, otherwise MBS points + the same address that RAW_MBS points. */ + unsigned char *mbs; + /* Index in RAW_MBS. Each character mbs[i] corresponds to + raw_mbs[raw_mbs_idx + i]. */ + Idx raw_mbs_idx; + /* The length of the valid characters in the buffers. */ + Idx valid_len; + /* The corresponding number of bytes in raw_mbs array. */ + Idx valid_raw_len; + /* The length of the buffers MBS and WCS. */ + Idx bufs_len; + /* The index in MBS, which is updated by re_string_fetch_byte. */ + Idx cur_idx; + /* length of RAW_MBS array. */ + Idx raw_len; + /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */ + Idx len; + /* End of the buffer may be shorter than its length in the cases such + as re_match_2, re_search_2. Then, we use STOP for end of the buffer + instead of LEN. */ + Idx raw_stop; + /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */ + Idx stop; + + /* The context of mbs[0]. We store the context independently, since + the context of mbs[0] may be different from raw_mbs[0], which is + the beginning of the input string. */ + unsigned int tip_context; + /* The translation passed as a part of an argument of re_compile_pattern. */ + RE_TRANSLATE_TYPE trans; + /* Copy of re_dfa_t's word_char. */ + re_const_bitset_ptr_t word_char; + /* true if REG_ICASE. */ + unsigned char icase; + unsigned char is_utf8; + unsigned char map_notascii; + unsigned char mbs_allocated; + unsigned char offsets_needed; + unsigned char newline_anchor; + unsigned char word_ops_used; + int mb_cur_max; +}; +typedef struct re_string_t re_string_t; + + +struct re_dfa_t; +typedef struct re_dfa_t re_dfa_t; + +# define IS_IN(libc) false + + +#define re_string_peek_byte(pstr, offset) \ + ((pstr)->mbs[(pstr)->cur_idx + offset]) +#define re_string_fetch_byte(pstr) \ + ((pstr)->mbs[(pstr)->cur_idx++]) +#define re_string_first_byte(pstr, idx) \ + ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF) +#define re_string_is_single_byte_char(pstr, idx) \ + ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \ + || (pstr)->wcs[(idx) + 1] != WEOF)) +#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) +#define re_string_cur_idx(pstr) ((pstr)->cur_idx) +#define re_string_get_buffer(pstr) ((pstr)->mbs) +#define re_string_length(pstr) ((pstr)->len) +#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) +#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) +#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) + +#if HAVE_ALLOCA +# include +#endif + +# if HAVE_ALLOCA +/* The OS usually guarantees only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + allocate anything larger than 4096 bytes. Also care for the possibility + of a few compiler-allocated temporary stack slots. */ +# define __libc_use_alloca(n) ((n) < 4032) +# else +/* alloca is implemented with malloc, so just use malloc. */ +# define __libc_use_alloca(n) 0 +# undef alloca +# define alloca(n) malloc (n) +# endif + + +#if !defined MALLOC_0_IS_NONNULL +# define MALLOC_0_IS_NONNULL 0 +#endif + +#ifndef MAX +# define MAX(a,b) ((a) < (b) ? (b) : (a)) +#endif +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) +#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) +#define re_free(p) free (p) + +struct bin_tree_t +{ + struct bin_tree_t *parent; + struct bin_tree_t *left; + struct bin_tree_t *right; + struct bin_tree_t *first; + struct bin_tree_t *next; + + re_token_t token; + + /* 'node_idx' is the index in dfa->nodes, if 'type' == 0. + Otherwise 'type' indicate the type of this node. */ + Idx node_idx; +}; +typedef struct bin_tree_t bin_tree_t; + +#define BIN_TREE_STORAGE_SIZE \ + ((1024 - sizeof (void *)) / sizeof (bin_tree_t)) + +struct bin_tree_storage_t +{ + struct bin_tree_storage_t *next; + bin_tree_t data[BIN_TREE_STORAGE_SIZE]; +}; +typedef struct bin_tree_storage_t bin_tree_storage_t; + +#define CONTEXT_WORD 1 +#define CONTEXT_NEWLINE (CONTEXT_WORD << 1) +#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) +#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) + +#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) +#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) +#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) +#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) +#define IS_ORDINARY_CONTEXT(c) ((c) == 0) + +#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') +#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) +#define IS_WIDE_WORD_CHAR(ch) (__iswalnum (ch) || (ch) == L'_') +#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR) + +#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ + ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ + || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ + || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ + || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) + +#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ + ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ + || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ + || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ + || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) + +struct re_dfastate_t +{ + re_hashval_t hash; + re_node_set nodes; + re_node_set non_eps_nodes; + re_node_set inveclosure; + re_node_set *entrance_nodes; + struct re_dfastate_t **trtable, **word_trtable; + unsigned int context : 4; + unsigned int halt : 1; + /* If this state can accept "multi byte". + Note that we refer to multibyte characters, and multi character + collating elements as "multi byte". */ + unsigned int accept_mb : 1; + /* If this state has backreference node(s). */ + unsigned int has_backref : 1; + unsigned int has_constraint : 1; +}; +typedef struct re_dfastate_t re_dfastate_t; + +struct re_state_table_entry +{ + Idx num; + Idx alloc; + re_dfastate_t **array; +}; + +/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ + +typedef struct +{ + Idx next_idx; + Idx alloc; + re_dfastate_t **array; +} state_array_t; + +/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */ + +typedef struct +{ + Idx node; + Idx str_idx; /* The position NODE match at. */ + state_array_t path; +} re_sub_match_last_t; + +/* Store information about the node NODE whose type is OP_OPEN_SUBEXP. + And information about the node, whose type is OP_CLOSE_SUBEXP, + corresponding to NODE is stored in LASTS. */ + +typedef struct +{ + Idx str_idx; + Idx node; + state_array_t *path; + Idx alasts; /* Allocation size of LASTS. */ + Idx nlasts; /* The number of LASTS. */ + re_sub_match_last_t **lasts; +} re_sub_match_top_t; + +struct re_backref_cache_entry +{ + Idx node; + Idx str_idx; + Idx subexp_from; + Idx subexp_to; + char more; + char unused; + unsigned short int eps_reachable_subexps_map; +}; + +typedef struct +{ + /* The string object corresponding to the input string. */ + re_string_t input; + const re_dfa_t *dfa; + /* EFLAGS of the argument of regexec. */ + int eflags; + /* Where the matching ends. */ + Idx match_last; + Idx last_node; + /* The state log used by the matcher. */ + re_dfastate_t **state_log; + Idx state_log_top; + /* Back reference cache. */ + Idx nbkref_ents; + Idx abkref_ents; + struct re_backref_cache_entry *bkref_ents; + int max_mb_elem_len; + Idx nsub_tops; + Idx asub_tops; + re_sub_match_top_t **sub_tops; +} re_match_context_t; + +typedef struct +{ + re_dfastate_t **sifted_states; + re_dfastate_t **limited_states; + Idx last_node; + Idx last_str_idx; + re_node_set limits; +} re_sift_context_t; + +struct re_fail_stack_ent_t +{ + Idx idx; + Idx node; + regmatch_t *regs; + re_node_set eps_via_nodes; +}; + +struct re_fail_stack_t +{ + Idx num; + Idx alloc; + struct re_fail_stack_ent_t *stack; +}; + +struct re_dfa_t +{ + re_token_t *nodes; + size_t nodes_alloc; + size_t nodes_len; + Idx *nexts; + Idx *org_indices; + re_node_set *edests; + re_node_set *eclosures; + re_node_set *inveclosures; + struct re_state_table_entry *state_table; + re_dfastate_t *init_state; + re_dfastate_t *init_state_word; + re_dfastate_t *init_state_nl; + re_dfastate_t *init_state_begbuf; + bin_tree_t *str_tree; + bin_tree_storage_t *str_tree_storage; + re_bitset_ptr_t sb_char; + int str_tree_storage_idx; + + /* number of subexpressions 're_nsub' is in regex_t. */ + re_hashval_t state_hash_mask; + Idx init_node; + Idx nbackref; /* The number of backreference in this dfa. */ + + /* Bitmap expressing which backreference is used. */ + bitset_word_t used_bkref_map; + bitset_word_t completed_bkref_map; + + unsigned int has_plural_match : 1; + /* If this dfa has "multibyte node", which is a backreference or + a node which can accept multibyte character or multi character + collating element. */ + unsigned int has_mb_node : 1; + unsigned int is_utf8 : 1; + unsigned int map_notascii : 1; + unsigned int word_ops_used : 1; + int mb_cur_max; + bitset_t word_char; + reg_syntax_t syntax; + Idx *subexp_map; + lock_define (lock) +}; + +#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) +#define re_node_set_remove(set,id) \ + (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) +#define re_node_set_empty(p) ((p)->nelem = 0) +#define re_node_set_free(set) re_free ((set)->elems) + + +typedef enum +{ + SB_CHAR, + MB_CHAR, + EQUIV_CLASS, + COLL_SYM, + CHAR_CLASS +} bracket_elem_type; + +typedef struct +{ + bracket_elem_type type; + union + { + unsigned char ch; + unsigned char *name; + wchar_t wch; + } opr; +} bracket_elem_t; + + +/* Functions for bitset_t operation. */ + +static inline void +bitset_set (bitset_t set, Idx i) +{ + set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS; +} + +static inline void +bitset_clear (bitset_t set, Idx i) +{ + set[i / BITSET_WORD_BITS] &= ~ ((bitset_word_t) 1 << i % BITSET_WORD_BITS); +} + +static inline bool +bitset_contain (const bitset_t set, Idx i) +{ + return (set[i / BITSET_WORD_BITS] >> i % BITSET_WORD_BITS) & 1; +} + +static inline void +bitset_empty (bitset_t set) +{ + memset (set, '\0', sizeof (bitset_t)); +} + +static inline void +bitset_set_all (bitset_t set) +{ + memset (set, -1, sizeof (bitset_word_t) * (SBC_MAX / BITSET_WORD_BITS)); + if (SBC_MAX % BITSET_WORD_BITS != 0) + set[BITSET_WORDS - 1] = + ((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1; +} + +static inline void +bitset_copy (bitset_t dest, const bitset_t src) +{ + memcpy (dest, src, sizeof (bitset_t)); +} + +static inline void +bitset_not (bitset_t set) +{ + int bitset_i; + for (bitset_i = 0; bitset_i < SBC_MAX / BITSET_WORD_BITS; ++bitset_i) + set[bitset_i] = ~set[bitset_i]; + if (SBC_MAX % BITSET_WORD_BITS != 0) + set[BITSET_WORDS - 1] = + ((((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1) + & ~set[BITSET_WORDS - 1]); +} + +static inline void +bitset_merge (bitset_t dest, const bitset_t src) +{ + int bitset_i; + for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) + dest[bitset_i] |= src[bitset_i]; +} + +static inline void +bitset_mask (bitset_t dest, const bitset_t src) +{ + int bitset_i; + for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) + dest[bitset_i] &= src[bitset_i]; +} + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +#if __GNUC_PREREQ (3,4) +# undef __attribute_warn_unused_result__ +# define __attribute_warn_unused_result__ \ + __attribute__ ((__warn_unused_result__)) +#else +# define __attribute_warn_unused_result__ /* empty */ +#endif + +#ifndef FALLTHROUGH +# if __GNUC__ < 7 +# define FALLTHROUGH ((void) 0) +# else +# define FALLTHROUGH __attribute__ ((__fallthrough__)) +# endif +#endif + +#endif /* _REGEX_INTERNAL_H */ diff --git a/headers-mingw/resource.h b/headers-mingw/resource.h new file mode 100644 index 0000000..160aad2 --- /dev/null +++ b/headers-mingw/resource.h @@ -0,0 +1,79 @@ +/* Substitute for . + Copyright (C) 2012-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#ifndef _GL_SYS_RESOURCE_H +#define _GL_SYS_RESOURCE_H + +#if !HAVE_SYS_RESOURCE_H +/* A platform that lacks . */ + +/* Get 'struct timeval'. */ +# include + +/* Define the RUSAGE_* constants. */ +# define RUSAGE_SELF 0 +# define RUSAGE_CHILDREN -1 + +# ifdef __cplusplus +extern "C" { +# endif + +# if !GNULIB_defined_struct_rusage +/* All known platforms that lack also lack any declaration + of struct rusage in any other header. */ +struct rusage +{ + struct timeval ru_utime; /* CPU time used in user mode */ + struct timeval ru_stime; /* CPU time used in system mode (kernel) */ + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; +# define GNULIB_defined_struct_rusage 1 +# endif + +# ifdef __cplusplus +} +# endif + +#endif + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + + +/* Declare overridden functions. */ + + +#if !HAVE_GETRUSAGE +extern int getrusage (int who, struct rusage *usage_p); +#endif + +#endif /* _@GUARD_PREFIX@_SYS_RESOURCE_H */ diff --git a/headers-mingw/signal.h b/headers-mingw/signal.h new file mode 100644 index 0000000..63539a2 --- /dev/null +++ b/headers-mingw/signal.h @@ -0,0 +1,264 @@ +/* A GNU-like . + + Copyright (C) 2006-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + + +/* Normal invocation convention. */ + +#ifndef _GL_SIGNAL_H +#define _GL_SIGNAL_H + +/* Get pid_t. */ +#include + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + +/* A set or mask of signals. */ +#if !GNULIB_defined_sigset_t +typedef unsigned int sigset_t; +# define GNULIB_defined_sigset_t 1 +#endif + + +/* Define sighandler_t, the type of signal handlers. A GNU extension. */ +#ifdef __cplusplus +extern "C" { +#endif +#if !GNULIB_defined_sighandler_t +typedef void (*sighandler_t) (int); +# define GNULIB_defined_sighandler_t 1 +#endif +#ifdef __cplusplus +} +#endif + + + +#ifndef SIGPIPE +/* Define SIGPIPE to a value that does not overlap with other signals. */ +# define SIGPIPE 13 +# define GNULIB_defined_SIGPIPE 1 +/* To actually use SIGPIPE, you also need the gnulib modules 'sigprocmask', + 'write', 'stdio'. */ +#endif + + + +/* Maximum signal number + 1. */ +#ifndef NSIG +# if defined __TANDEM +# define NSIG 32 +# endif +#endif + + +#if !(HAVE_PTHREAD_SIGMASK || defined pthread_sigmask) +extern int pthread_sigmask(int how, const sigset_t *new_mask, sigset_t *old_mask); +#endif + + +#if !HAVE_RAISE +extern int raise(int sig); +#endif + + +#ifndef GNULIB_defined_signal_blocking +# define GNULIB_defined_signal_blocking 1 +#endif + +/* Maximum signal number + 1. */ +#ifndef NSIG +# define NSIG 32 +#endif + +/* This code supports only 32 signals. */ +#if !GNULIB_defined_verify_NSIG_constraint +typedef int verify_NSIG_constraint[NSIG <= 32 ? 1 : -1]; +# define GNULIB_defined_verify_NSIG_constraint 1 +#endif + + +/* When also using extern inline, suppress the use of static inline in + standard headers of problematic Apple configurations, as Libc at + least through Libc-825.26 (2013-04-09) mishandles it; see, e.g., + . + Perhaps Apple will fix this some day. */ +#if (defined _GL_EXTERN_INLINE_IN_USE && defined __APPLE__ \ + && (defined __i386__ || defined __x86_64__)) +# undef sigaddset +# undef sigdelset +# undef sigemptyset +# undef sigfillset +# undef sigismember +#endif + +/* Test whether a given signal is contained in a signal set. */ +#if !HAVE_SIGISMEMBER +extern int sigismember(const sigset_t *set, int sig); +# endif + +/* Initialize a signal set to the empty set. */ +#if !HAVE_SIGEMPTYSET +extern int sigemptyset(sigset_t *set); +#endif + + +/* Add a signal to a signal set. */ +#if !HAVE_SIGADDSET +extern int sigaddset(sigset_t *set, int sig); +#endif + + +/* Remove a signal from a signal set. */ +#if !HAVE_SIGDELSET +extern int sigdelset(sigset_t *set, int sig); +# endif + +/* Fill a signal set with all possible signals. */ +#if !HAVE_SIGFILLSET +extern int sigfillset(sigset_t *set); +#endif + + +/* Return the set of those blocked signals that are pending. */ +#if !HAVE_SIGPENDING +extern int sigpending(sigset_t *set); +#endif + +/* If OLD_SET is not NULL, put the current set of blocked signals in *OLD_SET. + Then, if SET is not NULL, affect the current set of blocked signals by + combining it with *SET as indicated in OPERATION. + In this implementation, you are not allowed to change a signal handler + while the signal is blocked. */ +#ifndef SIG_BLOCK +# define SIG_BLOCK 0 /* blocked_set = blocked_set | *set; */ +#endif +#ifndef SIG_SETMASK +# define SIG_SETMASK 1 /* blocked_set = *set; */ +#endif +#ifndef SIG_UNBLOCK +# define SIG_UNBLOCK 2 /* blocked_set = blocked_set & ~*set; */ +#endif +#if !HAVE_SIGPROCMASK +extern int sigprocmask(int operation, const sigset_t *set, sigset_t *old_set); +# endif + +/* Install the handler FUNC for signal SIG, and return the previous + handler. */ +#ifdef __cplusplus +extern "C" { +#endif +#if !GNULIB_defined_function_taking_int_returning_void_t +typedef void (*_gl_function_taking_int_returning_void_t) (int); +# define GNULIB_defined_function_taking_int_returning_void_t 1 +#endif +#ifdef __cplusplus +} +#endif +#if !HAVE_SIGNAL +extern _gl_function_taking_int_returning_void_t signal(int sig, _gl_function_taking_int_returning_void_t func); +#endif + + +extern int _gl_raise_SIGPIPE (void); + +#if !HAVE_SIGACTION +# if !GNULIB_defined_siginfo_types + +/* Present to allow compilation, but unsupported by gnulib. */ +union sigval +{ + int sival_int; + void *sival_ptr; +}; + +/* Present to allow compilation, but unsupported by gnulib. */ +struct siginfo_t +{ + int si_signo; + int si_code; + int si_errno; + pid_t si_pid; + int si_uid; + void *si_addr; + int si_status; + long si_band; + union sigval si_value; +}; +typedef struct siginfo_t siginfo_t; + +# define GNULIB_defined_siginfo_types 1 +# endif + + +/* We assume that platforms which lack the sigaction() function also lack + the 'struct sigaction' type, and vice versa. */ + +# if !GNULIB_defined_struct_sigaction + +struct sigaction +{ + union + { + void (*_sa_handler) (int); + /* Present to allow compilation, but unsupported by gnulib. POSIX + says that implementations may, but not must, make sa_sigaction + overlap with sa_handler, but we know of no implementation where + they do not overlap. */ + void (*_sa_sigaction) (int, siginfo_t *, void *); + } _sa_func; + sigset_t sa_mask; + /* Not all POSIX flags are supported. */ + int sa_flags; +}; +# define sa_handler _sa_func._sa_handler +# define sa_sigaction _sa_func._sa_sigaction +/* Unsupported flags are not present. */ +# define SA_RESETHAND 1 +# define SA_NODEFER 2 +# define SA_RESTART 4 + +# define GNULIB_defined_struct_sigaction 1 +# endif + +extern int sigaction(int, const struct sigaction *restrict, + struct sigaction *restrict); +#endif + +/* Some systems don't have SA_NODEFER. */ +#ifndef SA_NODEFER +# define SA_NODEFER 0 +#endif + +/* Out-of-range substitutes make a good fallback for uncatchable + signals. */ +#ifndef SIGKILL +# define SIGKILL (-1) +#endif +#ifndef SIGSTOP +# define SIGSTOP (-1) +#endif + +#if !defined(HAVE_KILL) +extern int kill(pid_t pid, int sig); +#endif + +#endif /* _@GUARD_PREFIX@_SIGNAL_H */ diff --git a/headers-mingw/stdlib.h b/headers-mingw/stdlib.h new file mode 100644 index 0000000..55a0e5b --- /dev/null +++ b/headers-mingw/stdlib.h @@ -0,0 +1,344 @@ +/* A GNU-like . + + Copyright (C) 1995, 2001-2004, 2006-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Normal invocation convention. */ + +#ifndef _GL_STDLIB_H + +#define _GL_STDLIB_H + +/* Native Windows platforms declare mktemp() in . */ +#if (defined _WIN32 && ! defined __CYGWIN__) +# include +#endif + +/* OSF/1 5.1 declares 'struct random_data' in , which is included + from if _REENTRANT is defined. Include it whenever we need + 'struct random_data'. */ +#if HAVE_RANDOM_H +# include +#endif + +#if !HAVE_RANDOM_R +# include +#endif + +/* Define 'struct random_data'. + But allow multiple gnulib generated replacements to coexist. */ +#if !GNULIB_defined_struct_random_data +typedef struct random_data +{ + int *fptr; /* Front pointer. */ + int *rptr; /* Rear pointer. */ + int *state; /* Array of state values. */ + int rand_type; /* Type of random number generator. */ + int rand_deg; /* Degree of random number generator. */ + int rand_sep; /* Distance between front and rear. */ + int *end_ptr; /* Pointer behind state table. */ +}; +# define GNULIB_defined_struct_random_data 1 +#endif + +/* The __attribute__ feature is available in gcc versions 2.5 and later. + The attribute __pure__ was added in gcc 2.96. */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) +#else +# define _GL_ATTRIBUTE_PURE /* empty */ +#endif + +/* The definition of _Noreturn is copied here. */ + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + + +/* Some systems do not define EXIT_*, despite otherwise supporting C89. */ +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif +/* Tandem/NSK and other platforms that define EXIT_FAILURE as -1 interfere + with proper operation of xargs. */ +#ifndef EXIT_FAILURE +# define EXIT_FAILURE 1 +#elif EXIT_FAILURE != 1 +# undef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif + + +/* Terminate the current process with the given return code, without running + the 'atexit' handlers. */ +#if !HAVE__EXIT +extern void _Exit(int status); +#endif + +/* Parse a signed decimal integer. + Returns the value of the integer. Errors are not detected. */ +#if !HAVE_ATOLL +extern long long atoll(const char *string); +#endif + +#if !HAVE_CANONICALIZE_FILE_NAME +extern char * canonicalize_file_name(const char *name); +#endif + +/* Store max(NELEM,3) load average numbers in LOADAVG[]. + The three numbers are the load average of the last 1 minute, the last 5 + minutes, and the last 15 minutes, respectively. + LOADAVG is an array of NELEM numbers. */ +#if !HAVE_GETLOADAVG +extern int getloadavg(double loadavg[], int nelem); +#endif + + +/* Assuming *OPTIONP is a comma separated list of elements of the form + "token" or "token=value", getsubopt parses the first of these elements. + If the first element refers to a "token" that is member of the given + NULL-terminated array of tokens: + - It replaces the comma with a NUL byte, updates *OPTIONP to point past + the first option and the comma, sets *VALUEP to the value of the + element (or NULL if it doesn't contain an "=" sign), + - It returns the index of the "token" in the given array of tokens. + Otherwise it returns -1, and *OPTIONP and *VALUEP are undefined. + For more details see the POSIX:2001 specification. + http://www.opengroup.org/susv3xsh/getsubopt.html */ +#if !HAVE_GETSUBOPT +extern int getsubopt(char **optionp, char *const *tokens, char **valuep); +#endif + + +/* Change the ownership and access permission of the slave side of the + pseudo-terminal whose master side is specified by FD. */ +#if !HAVE_GRANTPT +extern int grantpt(int fd); +#endif + + +/* Create a unique temporary directory from TEMPLATE. + The last six characters of TEMPLATE must be "XXXXXX"; + they are replaced with a string that makes the directory name unique. + Returns TEMPLATE, or a null pointer if it cannot get a unique name. + The directory is created mode 700. */ +#if !HAVE_MKDTEMP +extern char * mkdtemp(char *template); +#endif + +/* Create a unique temporary file from TEMPLATE. + The last six characters of TEMPLATE must be "XXXXXX"; + they are replaced with a string that makes the file name unique. + The flags are a bitmask, possibly including O_CLOEXEC (defined in ) + and O_TEXT, O_BINARY (defined in "binary-io.h"). + The file is then created, with the specified flags, ensuring it didn't exist + before. + The file is created read-write (mask at least 0600 & ~umask), but it may be + world-readable and world-writable (mask 0666 & ~umask), depending on the + implementation. + Returns the open file descriptor if successful, otherwise -1 and errno + set. */ +#if !HAVE_MKOSTEMP +extern int mkostemp(char *template, int flags); +#endif + +/* Create a unique temporary file from TEMPLATE. + The last six characters of TEMPLATE before a suffix of length + SUFFIXLEN must be "XXXXXX"; + they are replaced with a string that makes the file name unique. + The flags are a bitmask, possibly including O_CLOEXEC (defined in ) + and O_TEXT, O_BINARY (defined in "binary-io.h"). + The file is then created, with the specified flags, ensuring it didn't exist + before. + The file is created read-write (mask at least 0600 & ~umask), but it may be + world-readable and world-writable (mask 0666 & ~umask), depending on the + implementation. + Returns the open file descriptor if successful, otherwise -1 and errno + set. */ +#if !HAVE_MKOSTEMPS +extern int mkostemps(char * template, int suffixlen, int flags); +#endif + + +/* Create a unique temporary file from TEMPLATE. + The last six characters of TEMPLATE must be "XXXXXX"; + they are replaced with a string that makes the file name unique. + The file is then created, ensuring it didn't exist before. + The file is created read-write (mask at least 0600 & ~umask), but it may be + world-readable and world-writable (mask 0666 & ~umask), depending on the + implementation. + Returns the open file descriptor if successful, otherwise -1 and errno + set. */ +#if !HAVE_MKSTEMP +extern int mkstemp(char * template); +#endif + + +/* Create a unique temporary file from TEMPLATE. + The last six characters of TEMPLATE prior to a suffix of length + SUFFIXLEN must be "XXXXXX"; + they are replaced with a string that makes the file name unique. + The file is then created, ensuring it didn't exist before. + The file is created read-write (mask at least 0600 & ~umask), but it may be + world-readable and world-writable (mask 0666 & ~umask), depending on the + implementation. + Returns the open file descriptor if successful, otherwise -1 and errno + set. */ +#if !HAVE_MKSTEMPS +extern int mkstemps(char * template, int suffixlen); +#endif + + +/* Return an FD open to the master side of a pseudo-terminal. Flags should + include O_RDWR, and may also include O_NOCTTY. */ +# if !HAVE_POSIX_OPENPT +extern int posix_openpt(int flags); +#endif + +/* Return the pathname of the pseudo-terminal slave associated with + the master FD is open on, or NULL on errors. */ +#if !HAVE_PTSNAME +extern char * ptsname(int fd); +#endif + + +/* Set the pathname of the pseudo-terminal slave associated with + the master FD is open on and return 0, or set errno and return + non-zero on errors. */ +#if !HAVE_PTSNAME_R +extern int ptsname_r(int fd, char *buf, size_t len); +#endif + +/* Sort an array of NMEMB elements, starting at address BASE, each element + occupying SIZE bytes, in ascending order according to the comparison + function COMPARE. */ +#if !HAVE_QSORT_R +extern void qsort_r(void *base, size_t nmemb, size_t size, + int (*compare) (void const *, void const *, + void *), + void *arg); +#endif + +#ifndef RAND_MAX +# define RAND_MAX 2147483647 +#endif + +#if !HAVE_RANDOM +extern long random(void); +#endif + +#if !HAVE_SRANDOM +extern void srandom(unsigned int seed); +#endif + + +#if !HAVE_INITSTATE +extern char * initstate(unsigned int seed, char *buf, size_t buf_size); +#endif + +#if !HAVE_SETSTATE +extern char * setstate(char *arg_state); +#endif + + +#if !HAVE_RANDOM_R +extern int random_r(struct random_data *buf, int *result); +#endif + +# if !HAVE_SRANDOM_R +extern int srandom_r(unsigned int seed, struct random_data *rand_state); +#endif + +#if !HAVE_INITSTATE_R +extern int initstate_r(unsigned int seed, char *buf, size_t buf_size, + struct random_data *rand_state); +#endif + +#if !HAVE_SETSTATE_R +extern int setstate_r(char *arg_state, struct random_data *rand_state); +#endif + +#if !HAVE_REALLOCARRAY +extern void * reallocarray(void *ptr, size_t nmemb, size_t size); +#endif + +#if !HAVE_REALPATH +extern char * realpath(const char *name, char *resolved); +#endif + +/* Test a user response to a question. + Return 1 if it is affirmative, 0 if it is negative, or -1 if not clear. */ +#if !HAVE_RPMATCH +extern int rpmatch(const char *response); +#endif + +/* Look up NAME in the environment, returning 0 in insecure situations. */ +#if !HAVE_SECURE_GETENV +extern char * secure_getenv(char const *name); +#endif + + +/* Set NAME to VALUE in the environment. + If REPLACE is nonzero, overwrite an existing value. */ +#if !HAVE_SETENV +extern int setenv(const char *name, const char *value, int replace); +#endif + +/* Parse a double from STRING, updating ENDP if appropriate. */ +#if !HAVE_STRTOD +extern double strtod(const char *str, char **endp); +#endif + +/* Parse a signed integer whose textual representation starts at STRING. + The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0, + it may be decimal or octal (with prefix "0") or hexadecimal (with prefix + "0x"). + If ENDPTR is not NULL, the address of the first byte after the integer is + stored in *ENDPTR. + Upon overflow, the return value is LLONG_MAX or LLONG_MIN, and errno is set + to ERANGE. */ +#if !HAVE_STRTOLL +extern long long strtoll(const char *string, char **endptr, int base); +#endif + +/* Parse an unsigned integer whose textual representation starts at STRING. + The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0, + it may be decimal or octal (with prefix "0") or hexadecimal (with prefix + "0x"). + If ENDPTR is not NULL, the address of the first byte after the integer is + stored in *ENDPTR. + Upon overflow, the return value is ULLONG_MAX, and errno is set to + ERANGE. */ +#if !HAVE_STRTOULL +extern unsigned long long strtoull(const char *string, char **endptr, int base); +#endif + + +/* Unlock the slave side of the pseudo-terminal whose master side is specified + by FD, so that it can be opened. */ +#if !HAVE_UNLOCKPT +extern int unlockpt(int fd); +#endif + +/* Remove the variable NAME from the environment. */ +#if !HAVE_UNSETENV +extern int unsetenv(const char *name); +#endif + +#endif /* _@GUARD_PREFIX@_STDLIB_H */ + diff --git a/headers-mingw/sys_cdefs.h b/headers-mingw/sys_cdefs.h new file mode 100644 index 0000000..98cf749 --- /dev/null +++ b/headers-mingw/sys_cdefs.h @@ -0,0 +1,514 @@ +/* Copyright (C) 1992-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _SYS_CDEFS_H +#define _SYS_CDEFS_H 1 + +/* We are almost always included from features.h. */ +#ifndef _FEATURES_H +# include +#endif + +/* The GNU libc does not support any K&R compilers or the traditional mode + of ISO C compilers anymore. Check for some of the combinations not + anymore supported. */ +#if defined __GNUC__ && !defined __STDC__ +# error "You need a ISO C conforming compiler to use the glibc headers" +#endif + +/* Some user header file might have defined this before. */ +#undef __P +#undef __PMT + +#ifdef __GNUC__ + +/* All functions, except those with callbacks or those that + synchronize memory, are leaf functions. */ +# if __GNUC_PREREQ (4, 6) && !defined _LIBC +# define __LEAF , __leaf__ +# define __LEAF_ATTR __attribute__ ((__leaf__)) +# else +# define __LEAF +# define __LEAF_ATTR +# endif + +/* GCC can always grok prototypes. For C++ programs we add throw() + to help it optimize the function calls. But this works only with + gcc 2.8.x and egcs. For gcc 3.2 and up we even mark C functions + as non-throwing using a function attribute since programs can use + the -fexceptions options for C code as well. */ +# if !defined __cplusplus && __GNUC_PREREQ (3, 3) +# define __THROW __attribute__ ((__nothrow__ __LEAF)) +# define __THROWNL __attribute__ ((__nothrow__)) +# define __NTH(fct) __attribute__ ((__nothrow__ __LEAF)) fct +# define __NTHNL(fct) __attribute__ ((__nothrow__)) fct +# else +# if defined __cplusplus && __GNUC_PREREQ (2,8) +# define __THROW throw () +# define __THROWNL throw () +# define __NTH(fct) __LEAF_ATTR fct throw () +# define __NTHNL(fct) fct throw () +# else +# define __THROW +# define __THROWNL +# define __NTH(fct) fct +# define __NTHNL(fct) fct +# endif +# endif + +#else /* Not GCC. */ + +# if (defined __cplusplus \ + || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) +# define __inline inline +# else +# define __inline /* No inline functions. */ +# endif + +# define __THROW +# define __THROWNL +# define __NTH(fct) fct + +#endif /* GCC. */ + +/* Compilers that are not clang may object to + #if defined __clang__ && __has_extension(...) + even though they do not need to evaluate the right-hand side of the &&. */ +#if defined __clang__ && defined __has_extension +# define __glibc_clang_has_extension(ext) __has_extension (ext) +#else +# define __glibc_clang_has_extension(ext) 0 +#endif + +/* These two macros are not used in glibc anymore. They are kept here + only because some other projects expect the macros to be defined. */ +#define __P(args) args +#define __PMT(args) args + +/* For these things, GCC behaves the ANSI way normally, + and the non-ANSI way under -traditional. */ + +#define __CONCAT(x,y) x ## y +#define __STRING(x) #x + +/* This is not a typedef so `const __ptr_t' does the right thing. */ +#define __ptr_t void * + + +/* C++ needs to know that types and declarations are C, not C++. */ +#ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +#else +# define __BEGIN_DECLS +# define __END_DECLS +#endif + + +/* Fortify support. */ +#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1) +#define __bos0(ptr) __builtin_object_size (ptr, 0) + +#if __GNUC_PREREQ (4,3) +# define __warndecl(name, msg) \ + extern void name (void) __attribute__((__warning__ (msg))) +# define __warnattr(msg) __attribute__((__warning__ (msg))) +# define __errordecl(name, msg) \ + extern void name (void) __attribute__((__error__ (msg))) +#else +# define __warndecl(name, msg) extern void name (void) +# define __warnattr(msg) +# define __errordecl(name, msg) extern void name (void) +#endif + +/* Support for flexible arrays. + Headers that should use flexible arrays only if they're "real" + (e.g. only if they won't affect sizeof()) should test + #if __glibc_c99_flexarr_available. */ +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +# define __flexarr [] +# define __glibc_c99_flexarr_available 1 +#elif __GNUC_PREREQ (2,97) +/* GCC 2.97 supports C99 flexible array members as an extension, + even when in C89 mode or compiling C++ (any version). */ +# define __flexarr [] +# define __glibc_c99_flexarr_available 1 +#elif defined __GNUC__ +/* Pre-2.97 GCC did not support C99 flexible arrays but did have + an equivalent extension with slightly different notation. */ +# define __flexarr [0] +# define __glibc_c99_flexarr_available 1 +#else +/* Some other non-C99 compiler. Approximate with [1]. */ +# define __flexarr [1] +# define __glibc_c99_flexarr_available 0 +#endif + + +/* __asm__ ("xyz") is used throughout the headers to rename functions + at the assembly language level. This is wrapped by the __REDIRECT + macro, in order to support compilers that can do this some other + way. When compilers don't support asm-names at all, we have to do + preprocessor tricks instead (which don't have exactly the right + semantics, but it's the best we can do). + + Example: + int __REDIRECT(setpgrp, (__pid_t pid, __pid_t pgrp), setpgid); */ + +#if defined __GNUC__ && __GNUC__ >= 2 + +# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias)) +# ifdef __cplusplus +# define __REDIRECT_NTH(name, proto, alias) \ + name proto __THROW __asm__ (__ASMNAME (#alias)) +# define __REDIRECT_NTHNL(name, proto, alias) \ + name proto __THROWNL __asm__ (__ASMNAME (#alias)) +# else +# define __REDIRECT_NTH(name, proto, alias) \ + name proto __asm__ (__ASMNAME (#alias)) __THROW +# define __REDIRECT_NTHNL(name, proto, alias) \ + name proto __asm__ (__ASMNAME (#alias)) __THROWNL +# endif +# define __ASMNAME(cname) __ASMNAME2 (__USER_LABEL_PREFIX__, cname) +# define __ASMNAME2(prefix, cname) __STRING (prefix) cname + +/* +#elif __SOME_OTHER_COMPILER__ + +# define __REDIRECT(name, proto, alias) name proto; \ + _Pragma("let " #name " = " #alias) +*/ +#endif + +/* GCC has various useful declarations that can be made with the + `__attribute__' syntax. All of the ways we use this do fine if + they are omitted for compilers that don't understand it. */ +#if !defined __GNUC__ || __GNUC__ < 2 +# define __attribute__(xyz) /* Ignore */ +#endif + +/* At some point during the gcc 2.96 development the `malloc' attribute + for functions was introduced. We don't want to use it unconditionally + (although this would be possible) since it generates warnings. */ +#if __GNUC_PREREQ (2,96) +# define __attribute_malloc__ __attribute__ ((__malloc__)) +#else +# define __attribute_malloc__ /* Ignore */ +#endif + +/* Tell the compiler which arguments to an allocation function + indicate the size of the allocation. */ +#if __GNUC_PREREQ (4, 3) +# define __attribute_alloc_size__(params) \ + __attribute__ ((__alloc_size__ params)) +#else +# define __attribute_alloc_size__(params) /* Ignore. */ +#endif + +/* At some point during the gcc 2.96 development the `pure' attribute + for functions was introduced. We don't want to use it unconditionally + (although this would be possible) since it generates warnings. */ +#if __GNUC_PREREQ (2,96) +# define __attribute_pure__ __attribute__ ((__pure__)) +#else +# define __attribute_pure__ /* Ignore */ +#endif + +/* This declaration tells the compiler that the value is constant. */ +#if __GNUC_PREREQ (2,5) +# define __attribute_const__ __attribute__ ((__const__)) +#else +# define __attribute_const__ /* Ignore */ +#endif + +/* At some point during the gcc 3.1 development the `used' attribute + for functions was introduced. We don't want to use it unconditionally + (although this would be possible) since it generates warnings. */ +#if __GNUC_PREREQ (3,1) +# define __attribute_used__ __attribute__ ((__used__)) +# define __attribute_noinline__ __attribute__ ((__noinline__)) +#else +# define __attribute_used__ __attribute__ ((__unused__)) +# define __attribute_noinline__ /* Ignore */ +#endif + +/* Since version 3.2, gcc allows marking deprecated functions. */ +#if __GNUC_PREREQ (3,2) +# define __attribute_deprecated__ __attribute__ ((__deprecated__)) +#else +# define __attribute_deprecated__ /* Ignore */ +#endif + +/* Since version 4.5, gcc also allows one to specify the message printed + when a deprecated function is used. clang claims to be gcc 4.2, but + may also support this feature. */ +#if __GNUC_PREREQ (4,5) || \ + __glibc_clang_has_extension (__attribute_deprecated_with_message__) +# define __attribute_deprecated_msg__(msg) \ + __attribute__ ((__deprecated__ (msg))) +#else +# define __attribute_deprecated_msg__(msg) __attribute_deprecated__ +#endif + +/* At some point during the gcc 2.8 development the `format_arg' attribute + for functions was introduced. We don't want to use it unconditionally + (although this would be possible) since it generates warnings. + If several `format_arg' attributes are given for the same function, in + gcc-3.0 and older, all but the last one are ignored. In newer gccs, + all designated arguments are considered. */ +#if __GNUC_PREREQ (2,8) +# define __attribute_format_arg__(x) __attribute__ ((__format_arg__ (x))) +#else +# define __attribute_format_arg__(x) /* Ignore */ +#endif + +/* At some point during the gcc 2.97 development the `strfmon' format + attribute for functions was introduced. We don't want to use it + unconditionally (although this would be possible) since it + generates warnings. */ +#if __GNUC_PREREQ (2,97) +# define __attribute_format_strfmon__(a,b) \ + __attribute__ ((__format__ (__strfmon__, a, b))) +#else +# define __attribute_format_strfmon__(a,b) /* Ignore */ +#endif + +/* The nonnull function attribute marks pointer parameters that + must not be NULL. Do not define __nonnull if it is already defined, + for portability when this file is used in Gnulib. */ +#ifndef __nonnull +# if __GNUC_PREREQ (3,3) +# define __nonnull(params) __attribute__ ((__nonnull__ params)) +# else +# define __nonnull(params) +# endif +#endif + +/* If fortification mode, we warn about unused results of certain + function calls which can lead to problems. */ +#if __GNUC_PREREQ (3,4) +# define __attribute_warn_unused_result__ \ + __attribute__ ((__warn_unused_result__)) +# if defined __USE_FORTIFY_LEVEL && __USE_FORTIFY_LEVEL > 0 +# define __wur __attribute_warn_unused_result__ +# endif +#else +# define __attribute_warn_unused_result__ /* empty */ +#endif +#ifndef __wur +# define __wur /* Ignore */ +#endif + +/* Forces a function to be always inlined. */ +#if __GNUC_PREREQ (3,2) +/* The Linux kernel defines __always_inline in stddef.h (283d7573), and + it conflicts with this definition. Therefore undefine it first to + allow either header to be included first. */ +# undef __always_inline +# define __always_inline __inline __attribute__ ((__always_inline__)) +#else +# undef __always_inline +# define __always_inline __inline +#endif + +/* Associate error messages with the source location of the call site rather + than with the source location inside the function. */ +#if __GNUC_PREREQ (4,3) +# define __attribute_artificial__ __attribute__ ((__artificial__)) +#else +# define __attribute_artificial__ /* Ignore */ +#endif + +/* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 + inline semantics, unless -fgnu89-inline is used. Using __GNUC_STDC_INLINE__ + or __GNUC_GNU_INLINE is not a good enough check for gcc because gcc versions + older than 4.3 may define these macros and still not guarantee GNU inlining + semantics. + + clang++ identifies itself as gcc-4.2, but has support for GNU inlining + semantics, that can be checked fot by using the __GNUC_STDC_INLINE_ and + __GNUC_GNU_INLINE__ macro definitions. */ +#if (!defined __cplusplus || __GNUC_PREREQ (4,3) \ + || (defined __clang__ && (defined __GNUC_STDC_INLINE__ \ + || defined __GNUC_GNU_INLINE__))) +# if defined __GNUC_STDC_INLINE__ || defined __cplusplus +# define __extern_inline extern __inline __attribute__ ((__gnu_inline__)) +# define __extern_always_inline \ + extern __always_inline __attribute__ ((__gnu_inline__)) +# else +# define __extern_inline extern __inline +# define __extern_always_inline extern __always_inline +# endif +#endif + +#ifdef __extern_always_inline +# define __fortify_function __extern_always_inline __attribute_artificial__ +#endif + +/* GCC 4.3 and above allow passing all anonymous arguments of an + __extern_always_inline function to some other vararg function. */ +#if __GNUC_PREREQ (4,3) +# define __va_arg_pack() __builtin_va_arg_pack () +# define __va_arg_pack_len() __builtin_va_arg_pack_len () +#endif + +/* It is possible to compile containing GCC extensions even if GCC is + run in pedantic mode if the uses are carefully marked using the + `__extension__' keyword. But this is not generally available before + version 2.8. */ +#if !__GNUC_PREREQ (2,8) +# define __extension__ /* Ignore */ +#endif + +/* __restrict is known in EGCS 1.2 and above. */ +#if !__GNUC_PREREQ (2,92) +# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +# define __restrict restrict +# else +# define __restrict /* Ignore */ +# endif +#endif + +/* ISO C99 also allows to declare arrays as non-overlapping. The syntax is + array_name[restrict] + GCC 3.1 supports this. */ +#if __GNUC_PREREQ (3,1) && !defined __GNUG__ +# define __restrict_arr __restrict +#else +# ifdef __GNUC__ +# define __restrict_arr /* Not supported in old GCC. */ +# else +# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +# define __restrict_arr restrict +# else +/* Some other non-C99 compiler. */ +# define __restrict_arr /* Not supported. */ +# endif +# endif +#endif + +#if __GNUC__ >= 3 +# define __glibc_unlikely(cond) __builtin_expect ((cond), 0) +# define __glibc_likely(cond) __builtin_expect ((cond), 1) +#else +# define __glibc_unlikely(cond) (cond) +# define __glibc_likely(cond) (cond) +#endif + +#ifdef __has_attribute +# define __glibc_has_attribute(attr) __has_attribute (attr) +#else +# define __glibc_has_attribute(attr) 0 +#endif + +#if (!defined _Noreturn \ + && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ + && !__GNUC_PREREQ (4,7)) +# if __GNUC_PREREQ (2,8) +# define _Noreturn __attribute__ ((__noreturn__)) +# else +# define _Noreturn +# endif +#endif + +#if __GNUC_PREREQ (8, 0) +/* Describes a char array whose address can safely be passed as the first + argument to strncpy and strncat, as the char array is not necessarily + a NUL-terminated string. */ +# define __attribute_nonstring__ __attribute__ ((__nonstring__)) +#else +# define __attribute_nonstring__ +#endif + +#if (!defined _Static_assert && !defined __cplusplus \ + && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ + && (!__GNUC_PREREQ (4, 6) || defined __STRICT_ANSI__)) +# define _Static_assert(expr, diagnostic) \ + extern int (*__Static_assert_function (void)) \ + [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })] +#endif + +/* The #ifndef lets Gnulib avoid including these on non-glibc + platforms, where the includes typically do not exist. */ +#ifndef __WORDSIZE +# include +# include +#endif + +#if defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH +# define __LDBL_COMPAT 1 +# ifdef __REDIRECT +# define __LDBL_REDIR1(name, proto, alias) __REDIRECT (name, proto, alias) +# define __LDBL_REDIR(name, proto) \ + __LDBL_REDIR1 (name, proto, __nldbl_##name) +# define __LDBL_REDIR1_NTH(name, proto, alias) __REDIRECT_NTH (name, proto, alias) +# define __LDBL_REDIR_NTH(name, proto) \ + __LDBL_REDIR1_NTH (name, proto, __nldbl_##name) +# define __LDBL_REDIR1_DECL(name, alias) \ + extern __typeof (name) name __asm (__ASMNAME (#alias)); +# define __LDBL_REDIR_DECL(name) \ + extern __typeof (name) name __asm (__ASMNAME ("__nldbl_" #name)); +# define __REDIRECT_LDBL(name, proto, alias) \ + __LDBL_REDIR1 (name, proto, __nldbl_##alias) +# define __REDIRECT_NTH_LDBL(name, proto, alias) \ + __LDBL_REDIR1_NTH (name, proto, __nldbl_##alias) +# endif +#endif +#if !defined __LDBL_COMPAT || !defined __REDIRECT +# define __LDBL_REDIR1(name, proto, alias) name proto +# define __LDBL_REDIR(name, proto) name proto +# define __LDBL_REDIR1_NTH(name, proto, alias) name proto __THROW +# define __LDBL_REDIR_NTH(name, proto) name proto __THROW +# define __LDBL_REDIR_DECL(name) +# ifdef __REDIRECT +# define __REDIRECT_LDBL(name, proto, alias) __REDIRECT (name, proto, alias) +# define __REDIRECT_NTH_LDBL(name, proto, alias) \ + __REDIRECT_NTH (name, proto, alias) +# endif +#endif + +/* __glibc_macro_warning (MESSAGE) issues warning MESSAGE. This is + intended for use in preprocessor macros. + + Note: MESSAGE must be a _single_ string; concatenation of string + literals is not supported. */ +#if __GNUC_PREREQ (4,8) || __glibc_clang_prereq (3,5) +# define __glibc_macro_warning1(message) _Pragma (#message) +# define __glibc_macro_warning(message) \ + __glibc_macro_warning1 (GCC warning message) +#else +# define __glibc_macro_warning(msg) +#endif + +/* Generic selection (ISO C11) is a C-only feature, available in GCC + since version 4.9. Previous versions do not provide generic + selection, even though they might set __STDC_VERSION__ to 201112L, + when in -std=c11 mode. Thus, we must check for !defined __GNUC__ + when testing __STDC_VERSION__ for generic selection support. + On the other hand, Clang also defines __GNUC__, so a clang-specific + check is required to enable the use of generic selection. */ +#if !defined __cplusplus \ + && (__GNUC_PREREQ (4, 9) \ + || __glibc_clang_has_extension (c_generic_selections) \ + || (!defined __GNUC__ && defined __STDC_VERSION__ \ + && __STDC_VERSION__ >= 201112L)) +# define __HAVE_GENERIC_SELECTION 1 +#else +# define __HAVE_GENERIC_SELECTION 0 +#endif + +#endif /* sys/cdefs.h */ diff --git a/headers-mingw/sys_ioctl.h b/headers-mingw/sys_ioctl.h new file mode 100644 index 0000000..80e9d7b --- /dev/null +++ b/headers-mingw/sys_ioctl.h @@ -0,0 +1,36 @@ +/* Substitute for and wrapper around . + Copyright (C) 2008-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#ifndef _GL_SYS_IOCTL_H + +#define _GL_SYS_IOCTL_H + +/* AIX 5.1 and Solaris 10 declare ioctl() in and in , + but not in . + Haiku declares ioctl() in , but not in . + But avoid namespace pollution on glibc systems. */ +#ifndef __GLIBC__ +# include +#endif + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + + +/* Declare overridden functions. */ + +#endif /* _@GUARD_PREFIX@_SYS_IOCTL_H */ diff --git a/headers-mingw/sys_stat.h b/headers-mingw/sys_stat.h new file mode 100644 index 0000000..2b06b15 --- /dev/null +++ b/headers-mingw/sys_stat.h @@ -0,0 +1,506 @@ +/* Provide a more complete sys/stat.h header file. + Copyright (C) 2005-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* Written by Eric Blake, Paul Eggert, and Jim Meyering. */ + +/* This file is supposed to be used on platforms where is + incomplete. It is intended to provide definitions and prototypes + needed by an application. Start with what the system provides. */ + +/* Normal invocation convention. */ + +#ifndef _GL_SYS_STAT_H + +/* Get nlink_t. + May also define off_t to a 64-bit type on native Windows. */ +#include + +/* Get struct timespec. */ +#include + +#define _GL_SYS_STAT_H + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + +/* Before doing "#define mkdir rpl_mkdir" below, we need to include all + headers that may declare mkdir(). Native Windows platforms declare mkdir + in and/or , not in . */ +#if defined _WIN32 && ! defined __CYGWIN__ +# include /* mingw32, mingw64 */ +# include /* mingw64, MSVC 9 */ +#endif + +//# if !GNULIB_defined_struct_stat +//struct stat +//{ +// dev_t st_dev; +// ino_t st_ino; +// mode_t st_mode; +// nlink_t st_nlink; +//# if 0 +// uid_t st_uid; +//# else /* uid_t is not defined by default on native Windows. */ +// int st_uid; +//# endif +//# if 0 +// gid_t st_gid; +//# else /* gid_t is not defined by default on native Windows. */ +// int st_gid; +//# endif +// dev_t st_rdev; +// off_t st_size; +//# if 0 +// blksize_t st_blksize; +// blkcnt_t st_blocks; +//# endif +// +////# if @WINDOWS_STAT_TIMESPEC@ +// struct timespec st_atim; +// struct timespec st_mtim; +// struct timespec st_ctim; +////# else +//// time_t st_atime; +//// time_t st_mtime; +//// time_t st_ctime; +////# endif +//}; +////# if @WINDOWS_STAT_TIMESPEC@ +//# define st_atime st_atim.tv_sec +//# define st_mtime st_mtim.tv_sec +//# define st_ctime st_ctim.tv_sec +// /* Indicator, for gnulib internal purposes. */ +//# define _GL_WINDOWS_STAT_TIMESPEC 1 +////# endif +//# define GNULIB_defined_struct_stat 1 +//# endif + +#ifndef S_IFIFO +# ifdef _S_IFIFO +# define S_IFIFO _S_IFIFO +# endif +#endif + +#ifndef S_IFMT +# define S_IFMT 0170000 +#endif + +#if STAT_MACROS_BROKEN +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISLNK +# undef S_ISNAM +# undef S_ISMPB +# undef S_ISMPC +# undef S_ISNWK +# undef S_ISREG +# undef S_ISSOCK +#endif + +#ifndef S_ISBLK +# ifdef S_IFBLK +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +# else +# define S_ISBLK(m) 0 +# endif +#endif + +#ifndef S_ISCHR +# ifdef S_IFCHR +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# else +# define S_ISCHR(m) 0 +# endif +#endif + +#ifndef S_ISDIR +# ifdef S_IFDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# else +# define S_ISDIR(m) 0 +# endif +#endif + +#ifndef S_ISDOOR /* Solaris 2.5 and up */ +# define S_ISDOOR(m) 0 +#endif + +#ifndef S_ISFIFO +# ifdef S_IFIFO +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# else +# define S_ISFIFO(m) 0 +# endif +#endif + +#ifndef S_ISLNK +# ifdef S_IFLNK +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +# else +# define S_ISLNK(m) 0 +# endif +#endif + +#ifndef S_ISMPB /* V7 */ +# ifdef S_IFMPB +# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) +# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) +# else +# define S_ISMPB(m) 0 +# define S_ISMPC(m) 0 +# endif +#endif + +#ifndef S_ISMPX /* AIX */ +# define S_ISMPX(m) 0 +#endif + +#ifndef S_ISNAM /* Xenix */ +# ifdef S_IFNAM +# define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM) +# else +# define S_ISNAM(m) 0 +# endif +#endif + +#ifndef S_ISNWK /* HP/UX */ +# ifdef S_IFNWK +# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) +# else +# define S_ISNWK(m) 0 +# endif +#endif + +#ifndef S_ISPORT /* Solaris 10 and up */ +# define S_ISPORT(m) 0 +#endif + +#ifndef S_ISREG +# ifdef S_IFREG +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +# else +# define S_ISREG(m) 0 +# endif +#endif + +#ifndef S_ISSOCK +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# else +# define S_ISSOCK(m) 0 +# endif +#endif + + +#ifndef S_TYPEISMQ +# define S_TYPEISMQ(p) 0 +#endif + +#ifndef S_TYPEISTMO +# define S_TYPEISTMO(p) 0 +#endif + + +#ifndef S_TYPEISSEM +# ifdef S_INSEM +# define S_TYPEISSEM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSEM) +# else +# define S_TYPEISSEM(p) 0 +# endif +#endif + +#ifndef S_TYPEISSHM +# ifdef S_INSHD +# define S_TYPEISSHM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSHD) +# else +# define S_TYPEISSHM(p) 0 +# endif +#endif + +/* high performance ("contiguous data") */ +#ifndef S_ISCTG +# define S_ISCTG(p) 0 +#endif + +/* Cray DMF (data migration facility): off line, with data */ +#ifndef S_ISOFD +# define S_ISOFD(p) 0 +#endif + +/* Cray DMF (data migration facility): off line, with no data */ +#ifndef S_ISOFL +# define S_ISOFL(p) 0 +#endif + +/* 4.4BSD whiteout */ +#ifndef S_ISWHT +# define S_ISWHT(m) 0 +#endif + +/* If any of the following are undefined, + define them to their de facto standard values. */ +#if !S_ISUID +# define S_ISUID 04000 +#endif +#if !S_ISGID +# define S_ISGID 02000 +#endif + +/* S_ISVTX is a common extension to POSIX. */ +#ifndef S_ISVTX +# define S_ISVTX 01000 +#endif + +#if !S_IRUSR && S_IREAD +# define S_IRUSR S_IREAD +#endif +#if !S_IRUSR +# define S_IRUSR 00400 +#endif +#if !S_IRGRP +# define S_IRGRP (S_IRUSR >> 3) +#endif +#if !S_IROTH +# define S_IROTH (S_IRUSR >> 6) +#endif + +#if !S_IWUSR && S_IWRITE +# define S_IWUSR S_IWRITE +#endif +#if !S_IWUSR +# define S_IWUSR 00200 +#endif +#if !S_IWGRP +# define S_IWGRP (S_IWUSR >> 3) +#endif +#if !S_IWOTH +# define S_IWOTH (S_IWUSR >> 6) +#endif + +#if !S_IXUSR && S_IEXEC +# define S_IXUSR S_IEXEC +#endif +#if !S_IXUSR +# define S_IXUSR 00100 +#endif +#if !S_IXGRP +# define S_IXGRP (S_IXUSR >> 3) +#endif +#if !S_IXOTH +# define S_IXOTH (S_IXUSR >> 6) +#endif + +#if !S_IRWXU +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) +#endif +#if !S_IRWXG +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +#endif +#if !S_IRWXO +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) +#endif + +/* S_IXUGO is a common extension to POSIX. */ +#if !S_IXUGO +# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) +#endif + +#ifndef S_IRWXUGO +# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO) +#endif + +/* Macros for futimens and utimensat. */ +#ifndef UTIME_NOW +# define UTIME_NOW (-1) +# define UTIME_OMIT (-2) +#endif + +#if !HAVE_FCHMODAT +extern int fchmodat(int fd, char const *file, mode_t mode, int flag); +#endif + + +#if !HAVE_FSTATAT +extern int fstatat(int fd, char const *name, struct stat *st, int flags); +#endif + +#if !HAVE_FUTIMENS +extern int futimens(int fd, struct timespec const times[2]); +#endif + +/* Change the mode of FILENAME to MODE, without dereferencing it if FILENAME + denotes a symbolic link. */ +#if !HAVE_LCHMOD +/* The lchmod replacement follows symbolic links. Callers should take + this into account; lchmod should be applied only to arguments that + are known to not be symbolic links. On hosts that lack lchmod, + this can lead to race conditions between the check and the + invocation of lchmod, but we know of no workarounds that are + reliable in general. You might try requesting support for lchmod + from your operating system supplier. */ +#define lchmod chmod +#endif + +#if !HAVE_LSTAT +/* mingw does not support symlinks, therefore it does not have lstat. But + without links, stat does just fine. */ +#define lstat stat +#endif + + +//#if @REPLACE_MKDIR@ +//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +//# undef mkdir +//# define mkdir rpl_mkdir +//# endif +//_GL_FUNCDECL_RPL (mkdir, int, (char const *name, mode_t mode) +// _GL_ARG_NONNULL ((1))); +//_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode)); +//#else +///* mingw's _mkdir() function has 1 argument, but we pass 2 arguments. +// Additionally, it declares _mkdir (and depending on compile flags, an +// alias mkdir), only in the nonstandard includes and , +// which are included above. */ +//# if defined _WIN32 && ! defined __CYGWIN__ +// +//# if !GNULIB_defined_rpl_mkdir +//static int +//rpl_mkdir (char const *name, mode_t mode) +//{ +// return _mkdir (name); +//} +//# define GNULIB_defined_rpl_mkdir 1 +//# endif +// +//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +//# define mkdir rpl_mkdir +//# endif +//_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode)); +//# else +//_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode)); +//# endif +//#endif +//_GL_CXXALIASWARN (mkdir); + + +#if !HAVE_MKDIRAT +extern int mkdirat(int fd, char const *file, mode_t mode); +#endif + +#if !HAVE_MKFIFO +extern int mkfifo(char const *file, mode_t mode); +#endif + +#if !HAVE_MKFIFOAT +extern int mkfifoat(int fd, char const *file, mode_t mode); +#endif + + +#if !HAVE_MKNOD +extern int mknod(char const *file, mode_t mode, dev_t dev); +#endif + +#if !HAVE_MKNODAT +extern int mknodat(int fd, char const *file, mode_t mode, dev_t dev); +#endif + + +//#if @GNULIB_STAT@ +//# if @REPLACE_STAT@ +//# if !@GNULIB_OVERRIDES_STRUCT_STAT@ +// /* We can't use the object-like #define stat rpl_stat, because of +// struct stat. This means that rpl_stat will not be used if the user +// does (stat)(a,b). Oh well. */ +//# if defined _AIX && defined stat && defined _LARGE_FILES +// /* With _LARGE_FILES defined, AIX (only) defines stat to stat64, +// so we have to replace stat64() instead of stat(). */ +//# undef stat64 +//# define stat64(name, st) rpl_stat (name, st) +//# elif @WINDOWS_64_BIT_ST_SIZE@ +// /* Above, we define stat to _stati64. */ +//# if defined __MINGW32__ && defined _stati64 +//# ifndef _USE_32BIT_TIME_T +// /* The system headers define _stati64 to _stat64. */ +//# undef _stat64 +//# define _stat64(name, st) rpl_stat (name, st) +//# endif +//# elif defined _MSC_VER && defined _stati64 +//# ifdef _USE_32BIT_TIME_T +// /* The system headers define _stati64 to _stat32i64. */ +//# undef _stat32i64 +//# define _stat32i64(name, st) rpl_stat (name, st) +//# else +// /* The system headers define _stati64 to _stat64. */ +//# undef _stat64 +//# define _stat64(name, st) rpl_stat (name, st) +//# endif +//# else +//# undef _stati64 +//# define _stati64(name, st) rpl_stat (name, st) +//# endif +//# elif defined __MINGW32__ && defined stat +//# ifdef _USE_32BIT_TIME_T +// /* The system headers define stat to _stat32i64. */ +//# undef _stat32i64 +//# define _stat32i64(name, st) rpl_stat (name, st) +//# else +// /* The system headers define stat to _stat64. */ +//# undef _stat64 +//# define _stat64(name, st) rpl_stat (name, st) +//# endif +//# elif defined _MSC_VER && defined stat +//# ifdef _USE_32BIT_TIME_T +// /* The system headers define stat to _stat32. */ +//# undef _stat32 +//# define _stat32(name, st) rpl_stat (name, st) +//# else +// /* The system headers define stat to _stat64i32. */ +//# undef _stat64i32 +//# define _stat64i32(name, st) rpl_stat (name, st) +//# endif +//# else /* !(_AIX || __MINGW32__ || _MSC_VER) */ +//# undef stat +//# define stat(name, st) rpl_stat (name, st) +//# endif /* !_LARGE_FILES */ +//# endif /* !@GNULIB_OVERRIDES_STRUCT_STAT@ */ +//_GL_EXTERN_C int stat (const char *name, struct stat *buf) +// _GL_ARG_NONNULL ((1, 2)); +//# endif +//#elif @GNULIB_OVERRIDES_STRUCT_STAT@ +///* see above: +// #define stat stat_used_without_requesting_gnulib_module_stat +// */ +//#elif defined GNULIB_POSIXCHECK +//# undef stat +//# if HAVE_RAW_DECL_STAT +//_GL_WARN_ON_USE (stat, "stat is unportable - " +// "use gnulib module stat for portability"); +//# endif +//#endif + +#if !HAVE_UTIMENSAT +extern int utimensat(int fd, char const *name, + struct timespec const times[2], int flag); +#endif + + +#endif /* _@GUARD_PREFIX@_SYS_STAT_H */ + diff --git a/headers-mingw/sys_utsname.h b/headers-mingw/sys_utsname.h new file mode 100644 index 0000000..c9733a7 --- /dev/null +++ b/headers-mingw/sys_utsname.h @@ -0,0 +1,80 @@ +/* Substitute for . + Copyright (C) 2009-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#ifndef _GL_SYS_UTSNAME_H +#define _GL_SYS_UTSNAME_H + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Length of the entries in 'struct utsname' is 256. */ +#define _UTSNAME_LENGTH 256 + +#ifndef _UTSNAME_NODENAME_LENGTH +# define _UTSNAME_NODENAME_LENGTH _UTSNAME_LENGTH +#endif +#ifndef _UTSNAME_SYSNAME_LENGTH +# define _UTSNAME_SYSNAME_LENGTH _UTSNAME_LENGTH +#endif +#ifndef _UTSNAME_RELEASE_LENGTH +# define _UTSNAME_RELEASE_LENGTH _UTSNAME_LENGTH +#endif +#ifndef _UTSNAME_VERSION_LENGTH +# define _UTSNAME_VERSION_LENGTH _UTSNAME_LENGTH +#endif +#ifndef _UTSNAME_MACHINE_LENGTH +# define _UTSNAME_MACHINE_LENGTH _UTSNAME_LENGTH +#endif + +# if !GNULIB_defined_struct_utsname +/* Structure describing the system and machine. */ +struct utsname + { + /* Name of this node on the network. */ + char nodename[_UTSNAME_NODENAME_LENGTH]; + + /* Name of the implementation of the operating system. */ + char sysname[_UTSNAME_SYSNAME_LENGTH]; + /* Current release level of this implementation. */ + char release[_UTSNAME_RELEASE_LENGTH]; + /* Current version level of this release. */ + char version[_UTSNAME_VERSION_LENGTH]; + + /* Name of the hardware type the system is running on. */ + char machine[_UTSNAME_MACHINE_LENGTH]; + }; +# define GNULIB_defined_struct_utsname 1 +# endif + +# if !HAVE_UNAME +extern int uname (struct utsname *buf); +# endif + + + +#ifdef __cplusplus +} +#endif + + +#endif /* _@GUARD_PREFIX@_SYS_UTSNAME_H */ diff --git a/headers-mingw/sys_wait.h b/headers-mingw/sys_wait.h new file mode 100644 index 0000000..c5a90af --- /dev/null +++ b/headers-mingw/sys_wait.h @@ -0,0 +1,65 @@ +/* A POSIX-like . + Copyright (C) 2001-2003, 2005-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#ifndef _GL_SYS_WAIT_H +#define _GL_SYS_WAIT_H + +/* Get pid_t. */ +#include + + +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + +/* Native Windows API. */ + +#include /* for SIGTERM */ + +/* The following macros apply to an argument x, that is a status of a process, + as returned by waitpid() or, equivalently, _cwait() or GetExitCodeProcess(). + This value is simply an 'int', not composed of bit fields. */ + +/* When an unhandled fatal signal terminates a process, the exit code is 3. */ +#define WIFSIGNALED(x) ((x) == 3) +#define WIFEXITED(x) ((x) != 3) +#define WIFSTOPPED(x) 0 + +/* The signal that terminated a process is not known posthum. */ +#define WTERMSIG(x) SIGTERM + +#define WEXITSTATUS(x) (x) + +/* There are no stopping signals. */ +#define WSTOPSIG(x) 0 + +/* There are no core dumps. */ +#define WCOREDUMP(x) 0 + + + + +/* Declarations of functions. */ + +#if !HAVE_WAITPID +/* dummy constants */ +#define WNOHANG (-1) +#define WUNTRACED (-1) +extern pid_t waitpid(pid_t pid, int *statusp, int options); +#endif + + +#endif /* _@GUARD_PREFIX@_SYS_WAIT_H */ diff --git a/headers-mingw/unistd.h b/headers-mingw/unistd.h new file mode 100644 index 0000000..216d3b4 --- /dev/null +++ b/headers-mingw/unistd.h @@ -0,0 +1,566 @@ +/* Substitute for and wrapper around . + Copyright (C) 2003-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +#ifndef _GL_UNISTD_H + +/* NetBSD 5.0 mis-defines NULL. Also get size_t. */ +#include + +/* mingw doesn't define the SEEK_* or *_FILENO macros in . */ +/* MSVC declares 'unlink' in , not in . We must include + it before we #define unlink rpl_unlink. */ +/* Cygwin 1.7.1 declares symlinkat in , not in . */ +/* But avoid namespace pollution on glibc systems. */ +#if (!(defined SEEK_CUR && defined SEEK_END && defined SEEK_SET) \ + || (defined _WIN32 && ! defined __CYGWIN__) \ + || defined __CYGWIN__) \ + && ! defined __GLIBC__ +# include +#endif + +/* Cygwin 1.7.1 declares unlinkat in , not in . */ +/* But avoid namespace pollution on glibc systems. */ +#if defined __CYGWIN__ \ + && ! defined __GLIBC__ +# include +#endif + +/* mingw fails to declare _exit in . */ +/* mingw, MSVC, BeOS, Haiku declare environ in , not in + . */ +/* Solaris declares getcwd not only in but also in . */ +/* OSF Tru64 Unix cannot see gnulib rpl_strtod when system is + included here. */ +/* But avoid namespace pollution on glibc systems. */ +#if !defined __GLIBC__ && !defined __osf__ +# define __need_system_stdlib_h +# include +# undef __need_system_stdlib_h +#endif + +/* Native Windows platforms declare chdir, getcwd, rmdir in + and/or , not in . + They also declare access(), chmod(), close(), dup(), dup2(), isatty(), + lseek(), read(), unlink(), write() in . */ +#if (defined _WIN32 && ! defined __CYGWIN__) +# include /* mingw32, mingw64 */ +# include /* mingw64, MSVC 9 */ +#endif + +/* AIX and OSF/1 5.1 declare getdomainname in , not in . + NonStop Kernel declares gethostname in , not in . */ +/* But avoid namespace pollution on glibc systems. */ +#if ((defined _AIX || defined __osf__) \ + || defined __TANDEM) \ + && !defined __GLIBC__ +# include +#endif + +/* MSVC defines off_t in . + May also define off_t to a 64-bit type on native Windows. */ +/* Get off_t. */ +# include +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ + +/* The definition of _GL_ARG_NONNULL is copied here. */ + +/* The definition of _GL_WARN_ON_USE is copied here. */ + + +///* Get getopt(), optarg, optind, opterr, optopt. */ +//#if @GNULIB_UNISTD_H_GETOPT@ && !defined _GL_SYSTEM_GETOPT +//# include +//# include +//#endif + +#ifndef _GL_UNISTD_INLINE +# define _GL_UNISTD_INLINE _GL_INLINE +#endif + +///* Hide some function declarations from . */ +// +//#if @GNULIB_GETHOSTNAME@ && @UNISTD_H_HAVE_WINSOCK2_H@ +//# if !defined _@GUARD_PREFIX@_SYS_SOCKET_H +//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +//# undef socket +//# define socket socket_used_without_including_sys_socket_h +//# undef connect +//# define connect connect_used_without_including_sys_socket_h +//# undef accept +//# define accept accept_used_without_including_sys_socket_h +//# undef bind +//# define bind bind_used_without_including_sys_socket_h +//# undef getpeername +//# define getpeername getpeername_used_without_including_sys_socket_h +//# undef getsockname +//# define getsockname getsockname_used_without_including_sys_socket_h +//# undef getsockopt +//# define getsockopt getsockopt_used_without_including_sys_socket_h +//# undef listen +//# define listen listen_used_without_including_sys_socket_h +//# undef recv +//# define recv recv_used_without_including_sys_socket_h +//# undef send +//# define send send_used_without_including_sys_socket_h +//# undef recvfrom +//# define recvfrom recvfrom_used_without_including_sys_socket_h +//# undef sendto +//# define sendto sendto_used_without_including_sys_socket_h +//# undef setsockopt +//# define setsockopt setsockopt_used_without_including_sys_socket_h +//# undef shutdown +//# define shutdown shutdown_used_without_including_sys_socket_h +//# else +// _GL_WARN_ON_USE (socket, +// "socket() used without including "); +// _GL_WARN_ON_USE (connect, +// "connect() used without including "); +// _GL_WARN_ON_USE (accept, +// "accept() used without including "); +// _GL_WARN_ON_USE (bind, +// "bind() used without including "); +// _GL_WARN_ON_USE (getpeername, +// "getpeername() used without including "); +// _GL_WARN_ON_USE (getsockname, +// "getsockname() used without including "); +// _GL_WARN_ON_USE (getsockopt, +// "getsockopt() used without including "); +// _GL_WARN_ON_USE (listen, +// "listen() used without including "); +// _GL_WARN_ON_USE (recv, +// "recv() used without including "); +// _GL_WARN_ON_USE (send, +// "send() used without including "); +// _GL_WARN_ON_USE (recvfrom, +// "recvfrom() used without including "); +// _GL_WARN_ON_USE (sendto, +// "sendto() used without including "); +// _GL_WARN_ON_USE (setsockopt, +// "setsockopt() used without including "); +// _GL_WARN_ON_USE (shutdown, +// "shutdown() used without including "); +//# endif +//# endif +//# if !defined _@GUARD_PREFIX@_SYS_SELECT_H +//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +//# undef select +//# define select select_used_without_including_sys_select_h +//# else +// _GL_WARN_ON_USE (select, +// "select() used without including "); +//# endif +//# endif +//#endif + + +/* OS/2 EMX lacks these macros. */ +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +/* Ensure *_OK macros exist. */ +#ifndef F_OK +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +#ifndef MAXSYMLINKS +# ifdef SYMLOOP_MAX +# define MAXSYMLINKS SYMLOOP_MAX +# else +# define MAXSYMLINKS 20 +# endif +#endif + + +/* Declare overridden functions. */ + +/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE + to GID (if GID is not -1). Follow symbolic links. + Return 0 if successful, otherwise -1 and errno set. + See the POSIX:2008 specification + . */ +#if !HAVE_DUP2 +extern int dup2(int oldfd, int newfd); +#endif + +/* Copy the file descriptor OLDFD into file descriptor NEWFD, with the + specified flags. + The flags are a bitmask, possibly including O_CLOEXEC (defined in ) + and O_TEXT, O_BINARY (defined in "binary-io.h"). + Close NEWFD first if it is open. + Return newfd if successful, otherwise -1 and errno set. + See the Linux man page at + . */ +#if !HAVE_DUP3 +extern int dup3(int oldfd, int newfd, int flags); +#endif + + +//#if @GNULIB_ENVIRON@ +//# if defined __CYGWIN__ && !defined __i386__ +///* The 'environ' variable is defined in a DLL. Therefore its declaration needs +// the '__declspec(dllimport)' attribute, but the system's lacks it. +// This leads to a link error on 64-bit Cygwin when the option +// -Wl,--disable-auto-import is in use. */ +//_GL_EXTERN_C __declspec(dllimport) char **environ; +//# endif +//# if !@HAVE_DECL_ENVIRON@ +///* Set of environment variables and values. An array of strings of the form +// "VARIABLE=VALUE", terminated with a NULL. */ +//# if defined __APPLE__ && defined __MACH__ +//# include +//# if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR +//# define _GL_USE_CRT_EXTERNS +//# endif +//# endif +//# ifdef _GL_USE_CRT_EXTERNS +//# include +//# define environ (*_NSGetEnviron ()) +//# else +//# ifdef __cplusplus +//extern "C" { +//# endif +//extern char **environ; +//# ifdef __cplusplus +//} +//# endif +//# endif +//# endif +//#elif defined GNULIB_POSIXCHECK +//# if HAVE_RAW_DECL_ENVIRON +//_GL_UNISTD_INLINE char *** +//_GL_WARN_ON_USE_ATTRIBUTE ("environ is unportable - " +// "use gnulib module environ for portability") +//rpl_environ (void) +//{ +// return &environ; +//} +//# undef environ +//# define environ (*rpl_environ ()) +//# endif +//#endif + + +/* Like access(), except that it uses the effective user id and group id of + the current process. */ +# if !HAVE_EUIDACCESS +extern int euidaccess(const char *filename, int mode); +#endif + + +#if !HAVE_FACCESSAT +extern int faccessat(int fd, char const *file, int mode, int flag); +#endif + + +/* Change the process' current working directory to the directory on which + the given file descriptor is open. + Return 0 if successful, otherwise -1 and errno set. + See the POSIX:2008 specification + . */ +#if !HAVE_FCHDIR +extern int fchdir(int fd); + +/* Gnulib internal hooks needed to maintain the fchdir metadata. */ +extern int _gl_register_fd (int fd, const char *filename); +extern void _gl_unregister_fd (int fd); +extern int _gl_register_dup (int oldfd, int newfd); +extern const char *_gl_directory_name (int fd); +#endif + + +#if !HAVE_FCHOWNAT +extern int fchownat(int fd, char const *file, + int owner, int group, int flag); +#endif + +/* Synchronize changes to a file. + Return 0 if successful, otherwise -1 and errno set. + See POSIX:2008 specification + . */ +#if !HAVE_FDATASYNC +extern int fdatasync(int fd); +#endif + +/* Synchronize changes, including metadata, to a file. + Return 0 if successful, otherwise -1 and errno set. + See POSIX:2008 specification + . */ +#if !HAVE_FSYNC +extern int fsync(int fd); +#endif + +/* Change the size of the file to which FD is opened to become equal to LENGTH. + Return 0 if successful, otherwise -1 and errno set. + See the POSIX:2008 specification + . */ +#if !HAVE_FTRUNCATE +extern int ftruncate(int fd, off_t length); +#endif + +/* Return the NIS domain name of the machine. + WARNING! The NIS domain name is unrelated to the fully qualified host name + of the machine. It is also unrelated to email addresses. + WARNING! The NIS domain name is usually the empty string or "(none)" when + not using NIS. + + Put up to LEN bytes of the NIS domain name into NAME. + Null terminate it if the name is shorter than LEN. + If the NIS domain name is longer than LEN, set errno = EINVAL and return -1. + Return 0 if successful, otherwise set errno and return -1. */ +#if !HAVE_GETDOMAINNAME +extern int getdomainname(char *name, size_t len); +#endif + +/* Return the maximum number of file descriptors in the current process. + In POSIX, this is same as sysconf (_SC_OPEN_MAX). */ +#if !HAVE_GETDTABLESIZE +extern int getdtablesize(void); +#endif + +/* Return the supplemental groups that the current process belongs to. + It is unspecified whether the effective group id is in the list. + If N is 0, return the group count; otherwise, N describes how many + entries are available in GROUPS. Return -1 and set errno if N is + not 0 and not large enough. Fails with ENOSYS on some systems. */ +#if !HAVE_GETGROUPS +extern int getgroups(int n, int *groups); +#endif + +/* Return the standard host name of the machine. + WARNING! The host name may or may not be fully qualified. + + Put up to LEN bytes of the host name into NAME. + Null terminate it if the name is shorter than LEN. + If the host name is longer than LEN, set errno = EINVAL and return -1. + Return 0 if successful, otherwise set errno and return -1. */ +#if !HAVE_GETHOSTNAME && !(defined _WIN32 && ! defined __CYGWIN__) +extern int gethostname(char *name, size_t len); +#endif + +/* Returns the user's login name, or NULL if it cannot be found. Upon error, + returns NULL with errno set. + + See . + + Most programs don't need to use this function, because the information is + available through environment variables: + ${LOGNAME-$USER} on Unix platforms, + $USERNAME on native Windows platforms. + */ +# if !HAVE_GETLOGIN +extern char * getlogin(void); +#endif + +/* Copies the user's login name to NAME. + The array pointed to by NAME has room for SIZE bytes. + + Returns 0 if successful. Upon error, an error number is returned, or -1 in + the case that the login name cannot be found but no specific error is + provided (this case is hopefully rare but is left open by the POSIX spec). + + See . + + Most programs don't need to use this function, because the information is + available through environment variables: + ${LOGNAME-$USER} on Unix platforms, + $USERNAME on native Windows platforms. + */ +#if !HAVE_GETLOGIN_R +extern int getlogin_r(char *name, size_t size); +#endif + + +/* Function getpass() from module 'getpass': + Read a password from /dev/tty or stdin. + Function getpass() from module 'getpass-gnu': + Read a password of arbitrary length from /dev/tty or stdin. */ +#if !HAVE_GETPASS +extern char * getpass(const char *prompt); +#endif + +/* Return the next valid login shell on the system, or NULL when the end of + the list has been reached. */ +#if !HAVE_GETUSERSHELL +extern char * getusershell(void); +#endif + +/* Rewind to pointer that is advanced at each getusershell() call. */ +#if !HAVE_SETUSERSHELL +extern void setusershell(void); +#endif + +/* Free the pointer that is advanced at each getusershell() call and + associated resources. */ +#if !HAVE_ENDUSERSHELL +extern void endusershell(void); +#endif + +/* Determine whether group id is in calling user's group list. */ +#if !HAVE_GROUP_MEMBER +extern int group_member(int gid); +#endif + +/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE + to GID (if GID is not -1). Do not follow symbolic links. + Return 0 if successful, otherwise -1 and errno set. + See the POSIX:2008 specification + . */ +#if !HAVE_LCHOWN +extern int lchown(char const *file, int owner, int group); +#endif + +/* Create a new hard link for an existing file. + Return 0 if successful, otherwise -1 and errno set. + See POSIX:2008 specification + . */ +#if !HAVE_LINK +extern int link(const char *path1, const char *path2); +#endif + +/* Create a new hard link for an existing file, relative to two + directories. FLAG controls whether symlinks are followed. + Return 0 if successful, otherwise -1 and errno set. */ +#if !HAVE_LINKAT +extern int linkat(int fd1, const char *path1, int fd2, const char *path2, + int flag); +#endif + +/* Create a pipe, defaulting to O_BINARY mode. + Store the read-end as fd[0] and the write-end as fd[1]. + Return 0 upon success, or -1 with errno set upon failure. */ +#if !HAVE_PIPE +extern int pipe(int fd[2]); +#endif + +/* Create a pipe, applying the given flags when opening the read-end of the + pipe and the write-end of the pipe. + The flags are a bitmask, possibly including O_CLOEXEC (defined in ) + and O_TEXT, O_BINARY (defined in "binary-io.h"). + Store the read-end as fd[0] and the write-end as fd[1]. + Return 0 upon success, or -1 with errno set upon failure. + See also the Linux man page at + . */ +#if !HAVE_PIPE2 +extern int pipe2(int fd[2], int flags); +#endif + +/* Read at most BUFSIZE bytes from FD into BUF, starting at OFFSET. + Return the number of bytes placed into BUF if successful, otherwise + set errno and return -1. 0 indicates EOF. + See the POSIX:2008 specification + . */ +#if !HAVE_PREAD +extern ssize_t pread(int fd, void *buf, size_t bufsize, off_t offset); +#endif + +/* Write at most BUFSIZE bytes from BUF into FD, starting at OFFSET. + Return the number of bytes written if successful, otherwise + set errno and return -1. 0 indicates nothing written. See the + POSIX:2008 specification + . */ +#if !HAVE_PWRITE +extern ssize_t pwrite(int fd, const void *buf, size_t bufsize, off_t offset); +#endif + +/* Read the contents of the symbolic link FILE and place the first BUFSIZE + bytes of it into BUF. Return the number of bytes placed into BUF if + successful, otherwise -1 and errno set. + See the POSIX:2008 specification + . */ +#if !HAVE_READLINK +extern ssize_t readlink(const char *file, char *buf, size_t bufsize); +#endif + +#if !HAVE_READLINKAT +extern ssize_t readlinkat(int fd, char const *file, char *buf, size_t len); +#endif + +/* Set the host name of the machine. + The host name may or may not be fully qualified. + + Put LEN bytes of NAME into the host name. + Return 0 if successful, otherwise, set errno and return -1. + + Platforms with no ability to set the hostname return -1 and set + errno = ENOSYS. */ +#if !HAVE_SETHOSTNAME +extern int sethostname(const char *name, size_t len); +#endif + +/* Pause the execution of the current thread for N seconds. + Returns the number of seconds left to sleep. + See the POSIX:2008 specification + . */ +#if !HAVE_SLEEP +extern unsigned int sleep(unsigned int n); +#endif + +#if !HAVE_SYMLINK +extern int symlink(char const *contents, char const *file); +#endif + +#if !HAVE_SYMLINKAT +extern int symlinkat(char const *contents, int fd, char const *file); +#endif + +/* Change the size of the file designated by FILENAME to become equal to LENGTH. + Return 0 if successful, otherwise -1 and errno set. + See the POSIX:2008 specification + . */ +#if !HAVE_TRUNCATE +extern int truncate(const char *filename, off_t length); +#endif + +/* Store at most BUFLEN characters of the pathname of the terminal FD is + open on in BUF. Return 0 on success, otherwise an error number. */ +#if !HAVE_TTYNAME_R +extern int ttyname_r(int fd, char *buf, size_t buflen); +#endif + +#if !HAVE_UNLINKAT +extern int unlinkat(int fd, char const *file, int flag); +#endif + +/* Pause the execution of the current thread for N microseconds. + Returns 0 on completion, or -1 on range error. + See the POSIX:2001 specification + . */ +#if !HAVE_USLEEP +extern int usleep(useconds_t n); +#endif + +#endif /* _@GUARD_PREFIX@_UNISTD_H */ + diff --git a/install-sh b/install-sh index a247329..8175c64 100755 --- a/install-sh +++ b/install-sh @@ -1,201 +1,518 @@ -: -# NAME: -# install.sh - portable version of install(1) -# -# SYNOPSIS: -# install [-CNcs] [-f flags] [-i errs] [-o owner] [-g group] [-m mode] file1 file2 ... -# install -d [-i errs] [-o owner] [-g group] [-m mode] directory ... -# -# DESCRIPTION: -# Compatible with BSD install(1). Except that '-c' is always -# true and we always move an already installed target aside as -# this is important on many systems. Recent BSD install(1) -# versions have a '-b' option for this. -# -# -# OPTIONS: -# -b move previous target file aside (always true). +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2018-03-11.20; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. # -# -B "suffix" -# use "suffix" instead of .old for saving existing target. -# -# -c copy rather than move the file into place (always true). +# Copyright (C) 1994 X Consortium # -# -C compare. Only install if target is missing or -# different. +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: # -# -N newer. Only install if target is missing or older. -# -# -s strip target +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. # -# -o "owner" -# make target owned by "owner" +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -# -g "group" -# make target group owned by "group" +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. # -# -m "mode" -# set permissions to "mode" # -# -f "flags" -# Pass "flags" onto chflags(1) -# -# -i "errs" -# Ignore errors from steps indicated by "errs" (``s,o,g,m''). +# FSF changes to this file are in the public domain. # -# BUGS: -# The '-i' option is to save your sanity when 'bsd.prog.mk' -# insists on haveing a '-o' "owner" option which is doomed to -# fail on many systems. We ignore '-b', '-B' and '-c' options. -# -# AUTHOR: -# Simon J. Gerraty +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. # +# This script is compatible with the BSD install script, but was written +# from scratch. -# RCSid: -# $Id: install-sh,v 1.18 2001/03/16 17:33:02 sjg Exp $ -# -# @(#) Copyright (c) 1993 Simon J. Gerraty -# -# This file is provided in the hope that it will -# be of use. There is absolutely NO WARRANTY. -# Permission to copy, redistribute or otherwise -# use this file is hereby granted provided that -# the above copyright notice and this notice are -# left intact. -# -# Please send copies of changes and bug-fixes to: -# sjg@quick.com.au -# +tab=' ' +nl=' +' +IFS=" $tab$nl" -set -- `getopt B:bpxCNcsdo:g:m:i:f: $*` +# Set DOITPROG to "echo" to test this script. -Mydir=`dirname $0` -[ -s $Mydir/.installrc ] && . $Mydir/.installrc +doit=${DOITPROG-} +doit_exec=${doit:-exec} -owner=: -group=: -mode=: -strip=: -mkdirs= -compare=: -newer=: -chflags=: -LS1= -CP_P= +# Put in absolute file names if you don't have them in your path; +# or use environment vars. -while [ $# -gt 1 ] -do - case $1 in - --) shift; break;; - -p) CP_P=-p;; - -x) set -x;; - -B) OLD_EXT=$2; shift;; - -C) compare=Different;; - -N) newer=Newer; - # check if /bin/ls supports -1 - /bin/ls -1 $0 >/dev/null 2>&1 && LS1=1 - ;; - -o) owner="${CHOWN:-chown} $2 "; shift;; - -g) group="${CHGRP:-chgrp} $2 "; shift;; - -m) mode="${CHMOD:-chmod} $2 "; shift;; - -s) strip=${STRIP:-strip};; - -d) mkdirs="mkdir -p";; - -i) ignore_err="$ignore_err$2"; shift;; - -f) chflags="${CHFLAGS:-chflags} $2 "; shift;; - esac - shift +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +is_target_a_directory=possibly + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift done -Newer() { - n=`/bin/ls -t$LS1 $* 2>/dev/null | head -1` - [ $1 = $n ] -} - -Different() { - cmp -s $* - [ $? != 0 ] -} - -Err() { - case "$ignore_err" in - *$1*) ;; - *) exit 1;; - esac -} - -Setem() { - # the order is important - if [ ! -d $1 ]; then - $strip $1 || Err s - fi - $group $1 || Err g - $owner $1 || Err o - $mode $1 || Err m - $chflags $1 || Err f - return 0 -} - -# a bug in HP-UX's /bin/sh, means we need to re-set $* -# after any calls to add_path() -args="$*" - -# all this just for chown! -add_path () { [ -d $1 ] && eval ${2:-PATH}="\$${2:-PATH}:$1"; } -add_path /etc -add_path /usr/etc -add_path /sbin -add_path /usr/sbin - -# restore saved $* -set -- $args - -# make directories if needed -# and ensure mode etc are as desired -if [ "$mkdirs" ]; then - for d in $* - do - [ ! -d $d ] && $mkdirs $d - Setem $d - done - exit 0 # that's all we do +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi fi -# install files -if [ $# -gt 2 ]; then - dest_dir=yes -elif [ $# -eq 1 ]; then - echo "what should I do with $*?" >&2 - exit 1 +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done fi -# get list of files -while [ $# -gt 1 ] -do - files="$files $1" - shift -done -# last one is dest -dest=$1 -shift +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; -if [ "$dest_dir" = yes -a ! -d $dest ]; then - echo "no directory $dest" >&2 - exit 1 + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac fi -for f in $files +for src do - b=`basename $f` - if [ -d $dest ]; then - t=$dest/$b - else - t=$dest - fi - $newer $f $t || continue - $compare $f $t || continue - [ -f $t ] && { mv -f $t $t.old || exit 1; } - { cp $CP_P $f $t && Setem $t; } || exit 1 + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + # Note that $RANDOM variable is not portable (e.g. dash); Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p' feature. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + set +f && + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi done -exit 0 + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/job.c b/job.c index ddf9d40..670798d 100644 --- a/job.c +++ b/job.c @@ -140,2 +140,5 @@ __RCSID("$NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $"); #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif #include @@ -146,13 +149,23 @@ __RCSID("$NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $"); #include -#if !defined(USE_SELECT) && defined(HAVE_POLL_H) -#include +#if (defined _WIN32 && ! defined __CYGWIN__) +# include "headers-mingw/poll.h" #else -#ifndef USE_SELECT /* no poll.h */ -# define USE_SELECT +# if !defined(USE_SELECT) && defined(HAVE_POLL_H) +# include +# else +# ifndef USE_SELECT /* no poll.h */ +# define USE_SELECT +# endif +# endif +# if defined(HAVE_SYS_SELECT_H) +# include +# endif #endif -#if defined(HAVE_SYS_SELECT_H) -# include +#include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/signal.h" #endif +#ifndef SIGQUIT +#define SIGQUIT SIGTERM #endif -#include #include @@ -315,4 +328,8 @@ const char *shellPath = NULL, /* full pathname of char *shellErrFlag = NULL; -static const char *shellArgv = NULL; /* Custom shell args */ +#if (defined _WIN32 && ! defined __CYGWIN__) +const char *shellExecCmd = NULL; +#endif + +static const char *shellArgv = NULL; /* Custom shell args */ @@ -439,2 +456,3 @@ JobCreatePipe(Job *job, int minfd) /* Set close-on-exec flag for both */ +#if defined(F_SETFD) && defined(FD_CLOEXEC) && defined(F_GETFL) && defined(F_SETFL) if (fcntl(job->jobPipe[0], F_SETFD, FD_CLOEXEC) == -1) @@ -456,2 +474,3 @@ JobCreatePipe(Job *job, int minfd) Punt("Cannot set flags: %s", strerror(errno)); +#endif } @@ -1115,3 +1134,3 @@ JobFinish (Job *job, WAIT_T status) } - job->node->made = MADE; + job->node->made = __MADE; if (!(job->flags & JOB_SPECIAL)) @@ -1386,2 +1405,3 @@ JobExec(Job *job, char **argv) } +#if defined(F_SETFD) if (fcntl(0, F_SETFD, 0) == -1) { @@ -1390,2 +1410,3 @@ JobExec(Job *job, char **argv) } +#endif if (lseek(0, (off_t)0, SEEK_SET) == -1) { @@ -1394,3 +1415,3 @@ JobExec(Job *job, char **argv) } - +#if defined(F_SETFD) if (job->node->type & (OP_MAKE | OP_SUBMAKE)) { @@ -1408,2 +1429,3 @@ JobExec(Job *job, char **argv) } +#endif @@ -1423,2 +1445,3 @@ JobExec(Job *job, char **argv) */ +#if defined(F_SETFD) if (fcntl(1, F_SETFD, 0) == -1) { @@ -1427,2 +1450,3 @@ JobExec(Job *job, char **argv) } +#endif if (dup2(1, 2) == -1) { @@ -1439,9 +1463,7 @@ JobExec(Job *job, char **argv) (void)setpgid(0, getpid()); -#else -#if defined(HAVE_SETSID) +#elif defined(HAVE_SETSID) /* XXX: dsl - I'm sure this should be setpgrp()... */ (void)setsid(); -#else +#elif defined(HAVE_SETPGRP) (void)setpgrp(0, getpid()); -#endif #endif @@ -1642,3 +1664,5 @@ JobStart(GNode *gn, int flags) } +#if defined(F_SETFD) (void)fcntl(FILENO(job->cmdFILE), F_SETFD, FD_CLOEXEC); +#endif /* @@ -1734,3 +1758,3 @@ JobStart(GNode *gn, int flags) } - job->node->made = MADE; + job->node->made = __MADE; Make_Update(job->node); @@ -1983,3 +2007,3 @@ JobRun(GNode *targ) Compat_Make(targ, targ); - if (targ->made == ERROR) { + if (targ->made == __ERROR) { PrintOnError(targ, "\n\nStop."); @@ -2063,2 +2087,3 @@ JobReapChild(pid_t pid, WAIT_T status, Boolean isJobs) switch (WSTOPSIG(status)) { +#if defined(SIGTSTP) case SIGTSTP: @@ -2066,2 +2091,3 @@ JobReapChild(pid_t pid, WAIT_T status, Boolean isJobs) break; +#endif case SIGSTOP: @@ -2191,2 +2217,7 @@ Shell_Init(void) } +#if (defined _WIN32 && ! defined __CYGWIN__) + if (shellExecCmd == NULL) { + shellExecCmd = getShellLaunchPrefix(); + } +#endif if (commandShell->exit == NULL) { @@ -2301,2 +2332,3 @@ Job_Init(void) sigemptyset(&caught_signals); +#if defined(SIGCHLD) /* @@ -2306,2 +2338,3 @@ Job_Init(void) sigaddset(&caught_signals, SIGCHLD); +#endif @@ -2318,3 +2351,5 @@ Job_Init(void) ADDSIG(SIGINT, JobPassSig_int) +#if defined(SIGHUP) ADDSIG(SIGHUP, JobPassSig_term) +#endif ADDSIG(SIGTERM, JobPassSig_term) @@ -2328,7 +2363,17 @@ Job_Init(void) */ +#if defined(SIGTSTP) ADDSIG(SIGTSTP, JobPassSig_suspend) +#endif +#if defined(SIGTTOU) ADDSIG(SIGTTOU, JobPassSig_suspend) +#endif +#if defined(SIGTTIN) ADDSIG(SIGTTIN, JobPassSig_suspend) +#endif +#if defined(SIGWINCH) ADDSIG(SIGWINCH, JobCondPassSig) +#endif +#if defined(SIGCONT) ADDSIG(SIGCONT, JobContinueSig) +#endif #undef ADDSIG @@ -2347,12 +2392,26 @@ static void JobSigReset(void) DELSIG(SIGINT) +#if defined(SIGHUP) DELSIG(SIGHUP) +#endif DELSIG(SIGQUIT) DELSIG(SIGTERM) +#if defined(SIGTSTP) DELSIG(SIGTSTP) +#endif +#if defined(SIGTTOU) DELSIG(SIGTTOU) +#endif +#if defined(SIGTTIN) DELSIG(SIGTTIN) +#endif +#if defined(SIGWINCH) DELSIG(SIGWINCH) +#endif +#if defined(SIGCONT) DELSIG(SIGCONT) +#endif #undef DELSIG +#if defined(SIGCHLD) (void)bmake_signal(SIGCHLD, SIG_DFL); +#endif } @@ -2791,2 +2850,3 @@ JobRestartJobs(void) job->job_suspended = 0; +#if defined(SIGCONT) if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) { @@ -2794,2 +2854,3 @@ JobRestartJobs(void) } +#endif } @@ -2888,4 +2949,6 @@ Job_ServerStart(int max_tokens, int jp_0, int jp_1) tokenWaitJob.outPipe = jp_1; +#if defined(F_SETFD) (void)fcntl(jp_0, F_SETFD, FD_CLOEXEC); (void)fcntl(jp_1, F_SETFD, FD_CLOEXEC); +#endif return; @@ -3022,3 +3085,3 @@ Job_RunTarget(const char *target, const char *fname) { JobRun(gn); - if (gn->made == ERROR) { + if (gn->made == __ERROR) { PrintOnError(gn, "\n\nStop."); diff --git a/job.h b/job.h index 91e2c87..ca8e093 100644 --- a/job.h +++ b/job.h @@ -246,2 +246,5 @@ extern const char *shellName; extern char *shellErrFlag; +#if (defined _WIN32 && ! defined __CYGWIN__) +extern const char *shellExecCmd; +#endif diff --git a/main.c b/main.c index 7dd4c50..76e319e 100644 --- a/main.c +++ b/main.c @@ -118,4 +118,11 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); #include +#ifdef HAVE_SYS_RESOURCE_H #include +#else +#include "headers-mingw/resource.h" +#endif #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) @@ -123,3 +130,8 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); #endif + +#ifdef HAVE_SYS_UTSNAME_H #include +#else +#include "headers-mingw/sys_utsname.h" +#endif #include "wait.h" @@ -128,2 +140,8 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/signal.h" +#endif +#ifndef SIGQUIT +#define SIGQUIT SIGTERM +#endif #include @@ -131,2 +149,5 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/stdlib.h" +#endif #include @@ -141,2 +162,6 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); +#if (defined _WIN32 && ! defined __CYGWIN__) +#include +#endif + #ifdef USE_IOVEC @@ -153,2 +178,4 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); +FILE *debug_file; /* Output written here - default stdout */ + Lst create; /* Targets to be made */ @@ -196,2 +223,4 @@ static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ char curdir[MAXPATHLEN + 1]; /* Startup directory */ +char *pcurdir; +char *pobjdir; char *progname; /* the program name */ @@ -764,3 +793,3 @@ Main_SetObjdir(const char *fmt, ...) - if (path[0] != '/') { + if (path[0] != '/' && curdir[0] == '/') { //because directory path could start not from '/' (example: Windows OS family) snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); @@ -776,4 +805,13 @@ Main_SetObjdir(const char *fmt, ...) strncpy(objdir, path, MAXPATHLEN); - Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); - setenv("PWD", objdir, 1); +#if (defined _WIN32 && ! defined __CYGWIN__) + pobjdir = str_replace_char(objdir, '\\', '/'); + if (pobjdir[1] == ':') { // create msys-style windows path + pobjdir[1] = pobjdir[0]; + pobjdir[0] = '/'; + } +#else + pobjdir = objdir; +#endif + Var_Set(".OBJDIR", pobjdir, VAR_GLOBAL, 0); + setenv("PWD", pobjdir, 1); Dir_InitDot(); @@ -990,2 +1028,4 @@ main(int argc, char **argv) char mdpath[MAXPATHLEN]; + const char *error; + #ifdef FORCE_MACHINE @@ -1017,3 +1057,9 @@ main(int argc, char **argv) srandom(rightnow.tv_sec + rightnow.tv_usec); - + +#if (defined _WIN32 && ! defined __CYGWIN__) + if ((progname = strrchr(argv[0], '\\')) != NULL) + progname++; + else + progname = argv[0]; +#else if ((progname = strrchr(argv[0], '/')) != NULL) @@ -1022,3 +1068,4 @@ main(int argc, char **argv) progname = argv[0]; -#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) +#endif +#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) /* @@ -1165,2 +1212,11 @@ main(int argc, char **argv) } + +#if (defined _WIN32 && ! defined __CYGWIN__) +// p1 = str_replace_char(p1, '\\', '/'); +// if (p1[1] == ':') { // create msys-style windows path +// p1[1] = p1[0]; +// p1[0] = '/'; +// } +p1 = Cmd_Exec(getUnixPathCmd(p1), &error); +#endif Var_Set("MAKE", p1, VAR_GLOBAL, 0); @@ -1187,4 +1243,6 @@ main(int argc, char **argv) Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); +#ifdef HAVE_GETPPID snprintf(tmp, sizeof(tmp), "%u", getppid()); Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); +#endif } @@ -1269,3 +1327,13 @@ main(int argc, char **argv) #endif - Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); +#if (defined _WIN32 && ! defined __CYGWIN__) +// pcurdir = str_replace_char(curdir, '\\', '/'); +// if (pcurdir[1] == ':') { // create msys-style windows path +// pcurdir[1] = pcurdir[0]; +// pcurdir[0] = '/'; +// } +pcurdir = Cmd_Exec(getUnixPathCmd(curdir), &error); +#else + pcurdir = curdir; +#endif + Var_Set(".CURDIR", pcurdir, VAR_GLOBAL, 0); @@ -1607,4 +1675,2 @@ found: - - /*- @@ -1625,3 +1691,7 @@ Cmd_Exec(const char *cmd, const char **errnum) const char *args[4]; /* Args for invoking the shell */ +#if !(defined _WIN32 && ! defined __CYGWIN__) int fds[2]; /* Pipe streams */ +#else + FILE * fds[2]; +#endif int cpid; /* Child PID */ @@ -1629,4 +1699,16 @@ Cmd_Exec(const char *cmd, const char **errnum) char *res; /* result */ +#if !(defined _WIN32 && ! defined __CYGWIN__) WAIT_T status; /* command exit status */ Buffer buf; /* buffer to store the result */ +#else + const char *sysRootPath = getenv("SYSROOTWINDOWSPATH"); + int status; + char command[4096] = ""; /* generated cmd string for launch */ + char escapedCmd[4096] = ""; + char escapedCmdLaunchList[4096] = ""; /* temporary string */ + static char stdout_data[16 * 1024 * 1024] = ""; //stdout + static char stderr_data[16 * 1024 * 1024] = ""; + int exit_code = 0; +#endif + char *cp; @@ -1636,2 +1718,3 @@ Cmd_Exec(const char *cmd, const char **errnum) + *errnum = NULL; @@ -1643,4 +1726,10 @@ Cmd_Exec(const char *cmd, const char **errnum) */ +#if !(defined _WIN32 && ! defined __CYGWIN__) args[0] = shellName; args[1] = "-c"; +#else + args[0] = str_concat(sysRootPath, "usr\\bin\\bash.exe", 0); + args[1] = "-lc"; +#endif + args[2] = cmd; @@ -1648,2 +1737,3 @@ Cmd_Exec(const char *cmd, const char **errnum) +#if !(defined _WIN32 && ! defined __CYGWIN__) /* @@ -1656,2 +1746,3 @@ Cmd_Exec(const char *cmd, const char **errnum) + /* @@ -1661,2 +1752,3 @@ Cmd_Exec(const char *cmd, const char **errnum) case 0: + /* @@ -1673,5 +1765,7 @@ Cmd_Exec(const char *cmd, const char **errnum) (void)close(fds[1]); - +#endif Var_ExportVars(); +#if !(defined _WIN32 && ! defined __CYGWIN__) + (void)execv(shellPath, UNCONST(args)); @@ -1685,7 +1779,41 @@ Cmd_Exec(const char *cmd, const char **errnum) default: - /* - * No need for the writing half - */ - (void)close(fds[1]); + /* + * No need for the writing half + */ + (void)close(fds[1]); +#else +// str_escape(escapedCmd, args[2], 4096); +// strncpy(command, str_concat(shellExecCmd, +// str_concat("\"", +// str_concat(str_concat(args[0], +// str_concat(args[1], +// str_concat("'", +// str_concat(escapedCmd, "'", 0), +// 0), +// STR_ADDSPACE), +// STR_ADDSPACE), "\"", 0), +// 0), +// STR_ADDSPACE), 4096); +// fds[0] = _popen(command, "rb"); +// if (fds[0] == NULL) { +// savederr = errno; +// } + str_escape_dblquote(escapedCmd, cmd, 4096); + strncpy(command, +// str_concat("\"", +// str_concat( + str_concat(args[0], + str_concat(args[1], + str_concat("\"", + str_concat(escapedCmd, "\"", 0), + 0), + STR_ADDSPACE), + STR_ADDSPACE), +// , "\"", 0), +// 0), + 4096); + status = system_np(command, 100 * 1000, stdout_data, sizeof(stdout_data), stderr_data, sizeof(stderr_data), &exit_code); +#endif +#if !(defined _WIN32 && ! defined __CYGWIN__) savederr = 0; @@ -1715,2 +1843,3 @@ Cmd_Exec(const char *cmd, const char **errnum) } + cc = Buf_Size(&buf); @@ -1720,7 +1849,16 @@ Cmd_Exec(const char *cmd, const char **errnum) *errnum = "Couldn't read shell's output for \"%s\""; +#else + cc = strlen(stdout_data); + res = bmake_malloc(cc + 1); + strncpy(res, stdout_data, cc); +#endif +#if !(defined _WIN32 && ! defined __CYGWIN__) if (WIFSIGNALED(status)) *errnum = "\"%s\" exited on a signal"; - else if (WEXITSTATUS(status) != 0) + else if (WEXITSTATUS(status) != 0) { + *errnum = "\"%s\" returned non-zero status"; + } +#endif @@ -1745,4 +1883,6 @@ Cmd_Exec(const char *cmd, const char **errnum) } +#if !(defined _WIN32 && ! defined __CYGWIN__) break; } +#endif return res; @@ -2118,3 +2258,4 @@ getTmpdir(void) */ - tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, + tmpdir = Var_Subst(NULL, str_concat( + str_concat("${TMPDIR:tA:U", _PATH_TMP, 0), "}/", 0), VAR_GLOBAL, VARF_WANTRES); diff --git a/make-bootstrap.sh.in b/make-bootstrap.sh.in index a394272..f74bc72 100755 --- a/make-bootstrap.sh.in +++ b/make-bootstrap.sh.in @@ -24,2 +24,13 @@ LDFLAGS="@LDFLAGS@" LIBS="@LIBS@" +MACHINE="@machine@" + +if [ "$(expr substr ${MACHINE} 1 5)" == "mingw" ]; then + LIBS+=" -lws2_32 -lwsock32" + CFLAGS+="" +fi + +if [ "$(expr substr ${MACHINE} 1 7)" == "mingw32" ]; then + LIBS+=" -liconv -lkernel32" + CFLAGS+="" +fi diff --git a/make.1 b/make.1 index 2a2237f..968f006 100644 --- a/make.1 +++ b/make.1 @@ -1927,3 +1927,3 @@ as if they all were preceded by a dash .\" XXX -.It Ic .MADE +.It Ic .__MADE Mark all sources of this target as being up-to-date. @@ -2089,3 +2089,3 @@ Any command lines attached to this target are executed after everything else is done. -.It Ic .ERROR +.It Ic .__ERROR Any command lines attached to this target are executed when another target fails. diff --git a/make.c b/make.c index 8947582..796202c 100644 --- a/make.c +++ b/make.c @@ -703,3 +703,3 @@ Make_Update(GNode *cgn) */ - if (cgn->made != UPTODATE) { + if (cgn->made != __UPTODATE) { mtime = Make_Recheck(cgn); @@ -759,3 +759,3 @@ Make_Update(GNode *cgn) if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) { - if (cgn->made == MADE) + if (cgn->made == __MADE) pgn->flags |= CHILDMADE; @@ -768,3 +768,3 @@ Make_Update(GNode *cgn) */ - if (centurion->unmade_cohorts != 0 || centurion->made < MADE) { + if (centurion->unmade_cohorts != 0 || centurion->made < __MADE) { if (DEBUG(MAKE)) @@ -794,3 +794,3 @@ Make_Update(GNode *cgn) } - if (pgn->made != DEFERRED) { + if (pgn->made != __DEFERRED) { /* @@ -817,3 +817,3 @@ Make_Update(GNode *cgn) /* Ok, we can schedule the parent again */ - pgn->made = REQUESTED; + pgn->made = __REQUESTED; (void)Lst_EnQueue(toBeMade, pgn); @@ -908,3 +908,3 @@ MakeAddAllSrc(void *cgnp, void *pgnp) if (pgn->type & OP_JOIN) { - if (cgn->made == MADE) { + if (cgn->made == __MADE) { Var_Append(OODATE, child, pgn); @@ -912,3 +912,3 @@ MakeAddAllSrc(void *cgnp, void *pgnp) } else if ((pgn->mtime < cgn->mtime) || - (cgn->mtime >= now && cgn->made == MADE)) + (cgn->mtime >= now && cgn->made == __MADE)) { @@ -1005,3 +1005,3 @@ MakeCheckOrder(void *v_bn, void *ignore MAKE_ATTR_UNUSED) - if (bn->made >= MADE || !(bn->flags & REMAKE)) + if (bn->made >= __MADE || !(bn->flags & REMAKE)) return 0; @@ -1021,3 +1021,3 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) cn->name, cn->cohort_num, cn->made, cn->type); - if (cn->made > DEFERRED) + if (cn->made > __DEFERRED) return 0; @@ -1027,3 +1027,3 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) /* Can't build this (or anything else in this child list) yet */ - cn->made = DEFERRED; + cn->made = __DEFERRED; return 0; /* but keep looking */ @@ -1035,3 +1035,3 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) - cn->made = REQUESTED; + cn->made = __REQUESTED; if (toBeMade_next == NULL) @@ -1057,3 +1057,3 @@ MakeBuildParent(void *v_pn, void *toBeMade_next) - if (pn->made != DEFERRED) + if (pn->made != __DEFERRED) return 0; @@ -1085,3 +1085,3 @@ MakeStartJobs(void) - if (gn->made != REQUESTED) { + if (gn->made != __REQUESTED) { if (DEBUG(MAKE)) @@ -1097,3 +1097,3 @@ MakeStartJobs(void) gn->name, gn->cohort_num); - gn->made = DEFERRED; + gn->made = __DEFERRED; continue; @@ -1107,3 +1107,3 @@ MakeStartJobs(void) */ - gn->made = DEFERRED; + gn->made = __DEFERRED; Lst_ForEach(gn->children, MakeBuildChild, Lst_First(toBeMade)); @@ -1115,3 +1115,3 @@ MakeStartJobs(void) - gn->made = BEINGMADE; + gn->made = __BEINGMADE; if (Make_OODate(gn)) { @@ -1130,3 +1130,3 @@ MakeStartJobs(void) } - gn->made = UPTODATE; + gn->made = __UPTODATE; if (gn->type & OP_JOIN) { @@ -1177,3 +1177,3 @@ MakePrintStatusOrder(void *ognp, void *gnp) - if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED) + if (!(ogn->flags & REMAKE) || ogn->made > __REQUESTED) /* not waiting for this one */ @@ -1206,11 +1206,11 @@ MakePrintStatus(void *gnp, void *v_errors) switch (gn->made) { - case UPTODATE: + case __UPTODATE: printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num); break; - case MADE: + case __MADE: break; - case UNMADE: - case DEFERRED: - case REQUESTED: - case BEINGMADE: + case __UNMADE: + case __DEFERRED: + case __REQUESTED: + case __BEINGMADE: (*errors)++; diff --git a/make.h b/make.h index c14b2c6..ea864b4 100644 --- a/make.h +++ b/make.h @@ -91,4 +91,10 @@ #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/fcntl.h" +#endif #include #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/stdlib.h" +#endif #ifdef HAVE_STRING_H @@ -99,2 +105,5 @@ #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/unistd.h" +#endif #include @@ -203,4 +212,4 @@ typedef struct GNode { enum enum_made { - UNMADE, DEFERRED, REQUESTED, BEINGMADE, - MADE, UPTODATE, ERROR, ABORTED + __UNMADE, __DEFERRED, __REQUESTED, __BEINGMADE, + __MADE, __UPTODATE, __ERROR, __ABORTED } made; /* Set to reflect the state of processing @@ -437,2 +446,3 @@ extern Lst defIncPath; /* The default include path. */ extern char curdir[]; /* Startup directory */ +extern char *pcurdir; /* Startup directory */ extern char *progname; /* The program name */ @@ -466,3 +476,3 @@ extern pid_t myPid; */ -FILE *debug_file; /* Output written here - default stdout */ +extern FILE *debug_file; /* Output written here - default stdout */ extern int debug; @@ -552,2 +562,12 @@ int cached_stat(const char *, void *); +size_t str_escape(char *dst, const char *src, size_t dstLen); + +size_t str_escape_dblquote(char *dst, const char *src, size_t dstLen); + +char * str_replace_char(const char *s, const char toReplace, const char replacement); + +extern int system_np(const char* command, int timeout_milliseconds, + char* stdout_data, int stdout_data_size, + char* stderr_data, int stderr_data_size, int* exit_code); + #endif /* _MAKE_H_ */ diff --git a/makefile.in b/makefile.in deleted file mode 100644 index 03b980a..0000000 --- a/makefile.in +++ /dev/null @@ -1,14 +0,0 @@ -# $Id: makefile.in,v 1.1 2012/12/28 21:28:19 sjg Exp $ - -# a simple makefile for those who don't like anything beyond: -# ./configure; make; make install - -prefix= @prefix@ -srcdir= @srcdir@ - -all: build - -build clean install test: - ${srcdir}/boot-strap --prefix=${prefix} -o . op=$@ - - diff --git a/meta.c b/meta.c index a852f3f..cd8c459 100644 --- a/meta.c +++ b/meta.c @@ -38,3 +38,10 @@ #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_ioctl.h" +#else #include +#endif #ifdef HAVE_LIBGEN_H @@ -1613,4 +1620,6 @@ meta_compat_start(void) /* Set close-on-exec flag for both */ +#if defined(F_SETFD) && defined(FD_CLOEXEC) (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC); (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC); +#endif } diff --git a/mk/ChangeLog b/mk/ChangeLog index ce8ac53..460ac78 100644 --- a/mk/ChangeLog +++ b/mk/ChangeLog @@ -946,4 +946,4 @@ read-only manually maintained dependencies. - o meta2deps.py add a clear 'ERROR:' token if an exception is raised. - o gendirdeps.mk if ERROR: from meta2deps.py do not update + o meta2deps.py add a clear '__ERROR:' token if an exception is raised. + o gendirdeps.mk if __ERROR: from meta2deps.py do not update anything. diff --git a/mk/gendirdeps.mk b/mk/gendirdeps.mk index e04f839..5899574 100644 --- a/mk/gendirdeps.mk +++ b/mk/gendirdeps.mk @@ -196,4 +196,4 @@ dir_list != cd ${_OBJDIR} && \ -.if ${dir_list:M*ERROR\:*} != "" -.warning ${dir_list:tW:C,.*(ERROR),\1,} +.if ${dir_list:M*__ERROR\:*} != "" +.warning ${dir_list:tW:C,.*(__ERROR),\1,} .warning Skipping ${_DEPENDFILE:S,${SRCTOP}/,,} diff --git a/mk/host-target.mk b/mk/host-target.mk index f528db9..1ab05b0 100644 --- a/mk/host-target.mk +++ b/mk/host-target.mk @@ -5,3 +5,3 @@ .if !defined(_HOST_OSNAME) -_HOST_OSNAME != uname -s +_HOST_OSNAME != uname -s | cut -d_ -f1 .export _HOST_OSNAME diff --git a/mk/install-mk b/mk/install-mk index 886c264..05f385d 100644 --- a/mk/install-mk +++ b/mk/install-mk @@ -115,3 +115,3 @@ Do() { Error() { - echo "ERROR: $@" >&2 + echo "__ERROR: $@" >&2 exit 1 diff --git a/mk/meta.autodep.mk b/mk/meta.autodep.mk index 9cb3f14..8c84502 100644 --- a/mk/meta.autodep.mk +++ b/mk/meta.autodep.mk @@ -316,3 +316,3 @@ _reldir_failed: .NOMETA .END: _reldir_finish -.ERROR: _reldir_failed +.__ERROR: _reldir_failed .endif diff --git a/mk/meta.stage.mk b/mk/meta.stage.mk index 320ffcc..d4f8a68 100644 --- a/mk/meta.stage.mk +++ b/mk/meta.stage.mk @@ -67,3 +67,3 @@ LN_CP_SCRIPT = LnCp() { \ # a warning is handy when bootstapping different options. -STAGE_CONFLICT?= ERROR +STAGE_CONFLICT?= __ERROR .if ${STAGE_CONFLICT:tl} == "error" diff --git a/mk/meta.sys.mk b/mk/meta.sys.mk index 4dbdd79..de0e3b1 100644 --- a/mk/meta.sys.mk +++ b/mk/meta.sys.mk @@ -20,3 +20,3 @@ .if ${MAKE_VERSION:U0} > 20100901 -.if !target(.ERROR) +.if !target(.__ERROR) @@ -94,3 +94,3 @@ meta_error_log = ${ERROR_LOGDIR}/meta-${.MAKE.PID}.log # we are not interested in make telling us a failure happened elsewhere -.ERROR: _metaError +.__ERROR: _metaError _metaError: .NOMETA .NOTMAIN @@ -100,3 +100,3 @@ _metaError: .NOMETA .NOTMAIN cp ${.ERROR_META_FILE} ${meta_error_log}; \ - echo "ERROR: log ${meta_error_log}" >&2; }; : + echo "__ERROR: log ${meta_error_log}" >&2; }; : @@ -139,3 +139,3 @@ UPDATE_DEPENDFILE= NO .elif !exists(/dev/filemon) -.error ${.newline}ERROR: The filemon module (/dev/filemon) is not loaded. +.error ${.newline}__ERROR: The filemon module (/dev/filemon) is not loaded. .endif diff --git a/mk/own.mk b/mk/own.mk index 4c8425b..37be01b 100644 --- a/mk/own.mk +++ b/mk/own.mk @@ -196,3 +196,3 @@ SHAREMODE?= ${NONBINMODE} COPY?= -c -STRIP_FLAG?= -s +STRIP_FLAG?= diff --git a/mk/prog.mk b/mk/prog.mk index 4bc6260..11bf182 100644 --- a/mk/prog.mk +++ b/mk/prog.mk @@ -26,3 +26,3 @@ CFLAGS+= -mcmodel=medlow LIBCRTBEGIN= ${DESTDIR}/usr/lib/crtbegin.o -.MADE: ${LIBCRTBEGIN} +.__MADE: ${LIBCRTBEGIN} .endif @@ -30,3 +30,3 @@ LIBCRTBEGIN= ${DESTDIR}/usr/lib/crtbegin.o LIBCRTEND= ${DESTDIR}/usr/lib/crtend.o -.MADE: ${LIBCRTEND} +.__MADE: ${LIBCRTEND} .endif @@ -41,3 +41,3 @@ _SHLINKER= ${SHLINKDIR}/ld.so LIBCRT0= ${DESTDIR}/usr/lib/crt0.o -.MADE: ${LIBCRT0} +.__MADE: ${LIBCRT0} .endif @@ -181,3 +181,3 @@ proginstall: ${INSTALL} ${COPY} ${STRIP_FLAG} ${PROG_INSTALL_OWN} -m ${BINMODE} \ - ${PROG} ${DESTDIR}${BINDIR}/${PROG_NAME} + ${OBJTOP:tA}/${PROG} ${DESTDIR}${BINDIR}/${PROG_NAME} .endif diff --git a/mk/sys/MINGW32.mk b/mk/sys/MINGW32.mk new file mode 100644 index 0000000..10da919 --- /dev/null +++ b/mk/sys/MINGW32.mk @@ -0,0 +1,185 @@ +# $Id: Linux.mk,v 1.9 2017/05/05 18:02:16 sjg Exp $ +# $NetBSD: sys.mk,v 1.19.2.1 1994/07/26 19:58:31 cgd Exp $ +# @(#)sys.mk 5.11 (Berkeley) 3/13/91 + +OS?= Windows +unix?= We run ${OS}. + +ROOT_GROUP= + +# would be better to work out where it is... +LIBCRT0= /dev/null + +NEED_SOLINKS=yes + +.SUFFIXES: .out .a .ln .o .c ${CXX_SUFFIXES} .F .f .r .y .l .s .S .cl .p .h .sh .m4 + +.LIBS: .a + +AR= ar +ARFLAGS= rl +RANLIB= ranlib + +AS= as +AFLAGS= +COMPILE.s= ${AS} ${AFLAGS} +LINK.s= ${CC} ${AFLAGS} ${LDFLAGS} +COMPILE.S= ${CC} ${AFLAGS} ${CPPFLAGS} -c +LINK.S= ${CC} ${AFLAGS} ${CPPFLAGS} ${LDFLAGS} + +CC= gcc -pipe +DBG= -O -g +STATIC?= -static + +CFLAGS= ${DBG} +COMPILE.c= ${CC} ${CFLAGS} ${CPPFLAGS} -c +LINK.c= ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} + +CXX= g++ +CXXFLAGS= ${CFLAGS} +COMPILE.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c +LINK.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} + +CPP= cpp +.if defined(DESTDIR) +CPPFLAGS+= -nostdinc -idirafter ${DESTDIR}/usr/include +.endif + +MK_DEP= mkdeps.sh -N +FC= f77 +FFLAGS= -O +RFLAGS= +COMPILE.f= ${FC} ${FFLAGS} -c +LINK.f= ${FC} ${FFLAGS} ${LDFLAGS} +COMPILE.F= ${FC} ${FFLAGS} ${CPPFLAGS} -c +LINK.F= ${FC} ${FFLAGS} ${CPPFLAGS} ${LDFLAGS} +COMPILE.r= ${FC} ${FFLAGS} ${RFLAGS} -c +LINK.r= ${FC} ${FFLAGS} ${RFLAGS} ${LDFLAGS} + +LEX= lex +LFLAGS= +LEX.l= ${LEX} ${LFLAGS} + +LD= ld +LDFLAGS= + +LINT= lint +LINTFLAGS= -chapbx + +PC= pc +PFLAGS= +COMPILE.p= ${PC} ${PFLAGS} ${CPPFLAGS} -c +LINK.p= ${PC} ${PFLAGS} ${CPPFLAGS} ${LDFLAGS} + +SHELL= sh + +YACC= yacc +YFLAGS= -d +YACC.y= ${YACC} ${YFLAGS} + +# C +.c: + ${LINK.c} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.c.o: + ${COMPILE.c} ${.IMPSRC} +.c.a: + ${COMPILE.c} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# C++ +${CXX_SUFFIXES}: + ${LINK.cc} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +${CXX_SUFFIXES:%=%.o}: + ${COMPILE.cc} ${.IMPSRC} +${CXX_SUFFIXES:%=%.a}: + ${COMPILE.cc} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Fortran/Ratfor +.f: + ${LINK.f} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.f.o: + ${COMPILE.f} ${.IMPSRC} +.f.a: + ${COMPILE.f} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +.F: + ${LINK.F} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.F.o: + ${COMPILE.F} ${.IMPSRC} +.F.a: + ${COMPILE.F} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +.r: + ${LINK.r} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.r.o: + ${COMPILE.r} ${.IMPSRC} +.r.a: + ${COMPILE.r} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Pascal +.p: + ${LINK.p} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.p.o: + ${COMPILE.p} ${.IMPSRC} +.p.a: + ${COMPILE.p} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Assembly +.s: + ${LINK.s} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.s.o: + ${COMPILE.s} -o ${.TARGET} ${.IMPSRC} +.s.a: + ${COMPILE.s} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o +.S: + ${LINK.S} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.S.o: + ${COMPILE.S} ${.IMPSRC} +.S.a: + ${COMPILE.S} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Lex +.l: + ${LEX.l} ${.IMPSRC} + ${LINK.c} -o ${.TARGET} lex.yy.c ${LDLIBS} -ll + rm -f lex.yy.c +.l.c: + ${LEX.l} ${.IMPSRC} + mv lex.yy.c ${.TARGET} +.l.o: + ${LEX.l} ${.IMPSRC} + ${COMPILE.c} -o ${.TARGET} lex.yy.c + rm -f lex.yy.c + +# Yacc +.y: + ${YACC.y} ${.IMPSRC} + ${LINK.c} -o ${.TARGET} y.tab.c ${LDLIBS} + rm -f y.tab.c +.y.c: + ${YACC.y} ${.IMPSRC} + mv y.tab.c ${.TARGET} +.y.o: + ${YACC.y} ${.IMPSRC} + ${COMPILE.c} -o ${.TARGET} y.tab.c + rm -f y.tab.c + +# Shell +.sh: + rm -f ${.TARGET} + cp ${.IMPSRC} ${.TARGET} diff --git a/mk/sys/MINGW64.mk b/mk/sys/MINGW64.mk new file mode 100644 index 0000000..10da919 --- /dev/null +++ b/mk/sys/MINGW64.mk @@ -0,0 +1,185 @@ +# $Id: Linux.mk,v 1.9 2017/05/05 18:02:16 sjg Exp $ +# $NetBSD: sys.mk,v 1.19.2.1 1994/07/26 19:58:31 cgd Exp $ +# @(#)sys.mk 5.11 (Berkeley) 3/13/91 + +OS?= Windows +unix?= We run ${OS}. + +ROOT_GROUP= + +# would be better to work out where it is... +LIBCRT0= /dev/null + +NEED_SOLINKS=yes + +.SUFFIXES: .out .a .ln .o .c ${CXX_SUFFIXES} .F .f .r .y .l .s .S .cl .p .h .sh .m4 + +.LIBS: .a + +AR= ar +ARFLAGS= rl +RANLIB= ranlib + +AS= as +AFLAGS= +COMPILE.s= ${AS} ${AFLAGS} +LINK.s= ${CC} ${AFLAGS} ${LDFLAGS} +COMPILE.S= ${CC} ${AFLAGS} ${CPPFLAGS} -c +LINK.S= ${CC} ${AFLAGS} ${CPPFLAGS} ${LDFLAGS} + +CC= gcc -pipe +DBG= -O -g +STATIC?= -static + +CFLAGS= ${DBG} +COMPILE.c= ${CC} ${CFLAGS} ${CPPFLAGS} -c +LINK.c= ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} + +CXX= g++ +CXXFLAGS= ${CFLAGS} +COMPILE.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c +LINK.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} + +CPP= cpp +.if defined(DESTDIR) +CPPFLAGS+= -nostdinc -idirafter ${DESTDIR}/usr/include +.endif + +MK_DEP= mkdeps.sh -N +FC= f77 +FFLAGS= -O +RFLAGS= +COMPILE.f= ${FC} ${FFLAGS} -c +LINK.f= ${FC} ${FFLAGS} ${LDFLAGS} +COMPILE.F= ${FC} ${FFLAGS} ${CPPFLAGS} -c +LINK.F= ${FC} ${FFLAGS} ${CPPFLAGS} ${LDFLAGS} +COMPILE.r= ${FC} ${FFLAGS} ${RFLAGS} -c +LINK.r= ${FC} ${FFLAGS} ${RFLAGS} ${LDFLAGS} + +LEX= lex +LFLAGS= +LEX.l= ${LEX} ${LFLAGS} + +LD= ld +LDFLAGS= + +LINT= lint +LINTFLAGS= -chapbx + +PC= pc +PFLAGS= +COMPILE.p= ${PC} ${PFLAGS} ${CPPFLAGS} -c +LINK.p= ${PC} ${PFLAGS} ${CPPFLAGS} ${LDFLAGS} + +SHELL= sh + +YACC= yacc +YFLAGS= -d +YACC.y= ${YACC} ${YFLAGS} + +# C +.c: + ${LINK.c} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.c.o: + ${COMPILE.c} ${.IMPSRC} +.c.a: + ${COMPILE.c} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# C++ +${CXX_SUFFIXES}: + ${LINK.cc} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +${CXX_SUFFIXES:%=%.o}: + ${COMPILE.cc} ${.IMPSRC} +${CXX_SUFFIXES:%=%.a}: + ${COMPILE.cc} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Fortran/Ratfor +.f: + ${LINK.f} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.f.o: + ${COMPILE.f} ${.IMPSRC} +.f.a: + ${COMPILE.f} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +.F: + ${LINK.F} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.F.o: + ${COMPILE.F} ${.IMPSRC} +.F.a: + ${COMPILE.F} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +.r: + ${LINK.r} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.r.o: + ${COMPILE.r} ${.IMPSRC} +.r.a: + ${COMPILE.r} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Pascal +.p: + ${LINK.p} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.p.o: + ${COMPILE.p} ${.IMPSRC} +.p.a: + ${COMPILE.p} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Assembly +.s: + ${LINK.s} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.s.o: + ${COMPILE.s} -o ${.TARGET} ${.IMPSRC} +.s.a: + ${COMPILE.s} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o +.S: + ${LINK.S} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.S.o: + ${COMPILE.S} ${.IMPSRC} +.S.a: + ${COMPILE.S} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Lex +.l: + ${LEX.l} ${.IMPSRC} + ${LINK.c} -o ${.TARGET} lex.yy.c ${LDLIBS} -ll + rm -f lex.yy.c +.l.c: + ${LEX.l} ${.IMPSRC} + mv lex.yy.c ${.TARGET} +.l.o: + ${LEX.l} ${.IMPSRC} + ${COMPILE.c} -o ${.TARGET} lex.yy.c + rm -f lex.yy.c + +# Yacc +.y: + ${YACC.y} ${.IMPSRC} + ${LINK.c} -o ${.TARGET} y.tab.c ${LDLIBS} + rm -f y.tab.c +.y.c: + ${YACC.y} ${.IMPSRC} + mv y.tab.c ${.TARGET} +.y.o: + ${YACC.y} ${.IMPSRC} + ${COMPILE.c} -o ${.TARGET} y.tab.c + rm -f y.tab.c + +# Shell +.sh: + rm -f ${.TARGET} + cp ${.IMPSRC} ${.TARGET} diff --git a/mk/sys/MSYS.mk b/mk/sys/MSYS.mk new file mode 100644 index 0000000..10da919 --- /dev/null +++ b/mk/sys/MSYS.mk @@ -0,0 +1,185 @@ +# $Id: Linux.mk,v 1.9 2017/05/05 18:02:16 sjg Exp $ +# $NetBSD: sys.mk,v 1.19.2.1 1994/07/26 19:58:31 cgd Exp $ +# @(#)sys.mk 5.11 (Berkeley) 3/13/91 + +OS?= Windows +unix?= We run ${OS}. + +ROOT_GROUP= + +# would be better to work out where it is... +LIBCRT0= /dev/null + +NEED_SOLINKS=yes + +.SUFFIXES: .out .a .ln .o .c ${CXX_SUFFIXES} .F .f .r .y .l .s .S .cl .p .h .sh .m4 + +.LIBS: .a + +AR= ar +ARFLAGS= rl +RANLIB= ranlib + +AS= as +AFLAGS= +COMPILE.s= ${AS} ${AFLAGS} +LINK.s= ${CC} ${AFLAGS} ${LDFLAGS} +COMPILE.S= ${CC} ${AFLAGS} ${CPPFLAGS} -c +LINK.S= ${CC} ${AFLAGS} ${CPPFLAGS} ${LDFLAGS} + +CC= gcc -pipe +DBG= -O -g +STATIC?= -static + +CFLAGS= ${DBG} +COMPILE.c= ${CC} ${CFLAGS} ${CPPFLAGS} -c +LINK.c= ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} + +CXX= g++ +CXXFLAGS= ${CFLAGS} +COMPILE.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c +LINK.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} + +CPP= cpp +.if defined(DESTDIR) +CPPFLAGS+= -nostdinc -idirafter ${DESTDIR}/usr/include +.endif + +MK_DEP= mkdeps.sh -N +FC= f77 +FFLAGS= -O +RFLAGS= +COMPILE.f= ${FC} ${FFLAGS} -c +LINK.f= ${FC} ${FFLAGS} ${LDFLAGS} +COMPILE.F= ${FC} ${FFLAGS} ${CPPFLAGS} -c +LINK.F= ${FC} ${FFLAGS} ${CPPFLAGS} ${LDFLAGS} +COMPILE.r= ${FC} ${FFLAGS} ${RFLAGS} -c +LINK.r= ${FC} ${FFLAGS} ${RFLAGS} ${LDFLAGS} + +LEX= lex +LFLAGS= +LEX.l= ${LEX} ${LFLAGS} + +LD= ld +LDFLAGS= + +LINT= lint +LINTFLAGS= -chapbx + +PC= pc +PFLAGS= +COMPILE.p= ${PC} ${PFLAGS} ${CPPFLAGS} -c +LINK.p= ${PC} ${PFLAGS} ${CPPFLAGS} ${LDFLAGS} + +SHELL= sh + +YACC= yacc +YFLAGS= -d +YACC.y= ${YACC} ${YFLAGS} + +# C +.c: + ${LINK.c} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.c.o: + ${COMPILE.c} ${.IMPSRC} +.c.a: + ${COMPILE.c} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# C++ +${CXX_SUFFIXES}: + ${LINK.cc} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +${CXX_SUFFIXES:%=%.o}: + ${COMPILE.cc} ${.IMPSRC} +${CXX_SUFFIXES:%=%.a}: + ${COMPILE.cc} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Fortran/Ratfor +.f: + ${LINK.f} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.f.o: + ${COMPILE.f} ${.IMPSRC} +.f.a: + ${COMPILE.f} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +.F: + ${LINK.F} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.F.o: + ${COMPILE.F} ${.IMPSRC} +.F.a: + ${COMPILE.F} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +.r: + ${LINK.r} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.r.o: + ${COMPILE.r} ${.IMPSRC} +.r.a: + ${COMPILE.r} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Pascal +.p: + ${LINK.p} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.p.o: + ${COMPILE.p} ${.IMPSRC} +.p.a: + ${COMPILE.p} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Assembly +.s: + ${LINK.s} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.s.o: + ${COMPILE.s} -o ${.TARGET} ${.IMPSRC} +.s.a: + ${COMPILE.s} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o +.S: + ${LINK.S} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} +.S.o: + ${COMPILE.S} ${.IMPSRC} +.S.a: + ${COMPILE.S} ${.IMPSRC} + ${AR} ${ARFLAGS} $@ $*.o + rm -f $*.o + +# Lex +.l: + ${LEX.l} ${.IMPSRC} + ${LINK.c} -o ${.TARGET} lex.yy.c ${LDLIBS} -ll + rm -f lex.yy.c +.l.c: + ${LEX.l} ${.IMPSRC} + mv lex.yy.c ${.TARGET} +.l.o: + ${LEX.l} ${.IMPSRC} + ${COMPILE.c} -o ${.TARGET} lex.yy.c + rm -f lex.yy.c + +# Yacc +.y: + ${YACC.y} ${.IMPSRC} + ${LINK.c} -o ${.TARGET} y.tab.c ${LDLIBS} + rm -f y.tab.c +.y.c: + ${YACC.y} ${.IMPSRC} + mv y.tab.c ${.TARGET} +.y.o: + ${YACC.y} ${.IMPSRC} + ${COMPILE.c} -o ${.TARGET} y.tab.c + rm -f y.tab.c + +# Shell +.sh: + rm -f ${.TARGET} + cp ${.IMPSRC} ${.TARGET} diff --git a/mk/warnings.mk b/mk/warnings.mk index 7fb3ebd..de664fd 100644 --- a/mk/warnings.mk +++ b/mk/warnings.mk @@ -69,4 +69,4 @@ _empty_warnings: .PHONY .endif - @echo "ERROR: Invalid: WARNINGS_SET=${ws}" - @echo "ERROR: Try one of: ${ALL_WARNINGS_SETS:O:u}"; exit 1 + @echo "__ERROR: Invalid: WARNINGS_SET=${ws}" + @echo "__ERROR: Try one of: ${ALL_WARNINGS_SETS:O:u}"; exit 1 diff --git a/parse.c b/parse.c index a7d7a4d..a996c49 100644 --- a/parse.c +++ b/parse.c @@ -127,2 +127,5 @@ __RCSID("$NetBSD: parse.c,v 1.231 2018/12/22 00:36:32 sjg Exp $"); #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif #include @@ -2397,3 +2400,3 @@ ParseSetParseFile(const char *filename) { - char *slash, *dirname; + char *slash, *dirname, *pdirname; const char *pd, *pf; @@ -2403,3 +2406,3 @@ ParseSetParseFile(const char *filename) if (slash == NULL) { - Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0); + Var_Set(".PARSEDIR", pd = pcurdir, VAR_GLOBAL, 0); Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0); @@ -2411,3 +2414,19 @@ ParseSetParseFile(const char *filename) dirname[len] = '\0'; - Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0); +#if (defined _WIN32 && ! defined __CYGWIN__) +// pdirname = str_replace_char(dirname, '\\', '/'); +// if (pdirname[1] == ':') { // create msys-style windows path +// pdirname[1] = pdirname[0]; +// pdirname[0] = '/'; +// } + char *error; + if (dirname && strlen(dirname) > 0 && dirname[1] == ':' && (dirname[2] == '/' || dirname[2] == '\\')) { + pdirname = Cmd_Exec(getUnixPathCmd(dirname), &error); + } + else { + pdirname = dirname; + } +#else + pdirname = dirname; +#endif + Var_Set(".PARSEDIR", pd = pdirname, VAR_GLOBAL, 0); Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0); diff --git a/pathnames.h b/pathnames.h index 9c597b1..e3436a4 100644 --- a/pathnames.h +++ b/pathnames.h @@ -60,3 +60,7 @@ #ifndef _PATH_TMP -#define _PATH_TMP "/tmp/" /* with trailing slash */ +# if (defined _WIN32 && ! defined __CYGWIN__) +# define _PATH_TMP (getenv("TEMP")) +# else +# define _PATH_TMP "/tmp/" /* with trailing slash */ +# endif #endif diff --git a/realpath.c b/realpath.c index fbf0335..9a6ac51 100644 --- a/realpath.c +++ b/realpath.c @@ -42,3 +42,5 @@ #include - +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif #include @@ -51,3 +53,6 @@ #ifdef HAVE_UNISTD_H -# include +#include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/unistd.h" +#endif #endif diff --git a/sigcompat.c b/sigcompat.c index 608538d..9e605e9 100644 --- a/sigcompat.c +++ b/sigcompat.c @@ -91,4 +91,13 @@ #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/signal.h" +#endif +#ifndef SIGQUIT +#define SIGQUIT SIGTERM +#endif #ifdef HAVE_UNISTD_H #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/unistd.h" +#endif #endif diff --git a/str.c b/str.c index b5255bc..cf85b95 100644 --- a/str.c +++ b/str.c @@ -526 +526,30 @@ Str_SYSVSubst(Buffer *buf, char *pat, char *src, int len) } + +char * str_replace_char(const char *s, const char toReplace, const char replacement) +{ + int len; + int count = 0; + char *result; + + + + len = strlen(s); + + /* allocate length plus EOS */ + result = bmake_malloc((unsigned int)(len + 1)); + + /* copy first string into place */ + memcpy(result, s, len + 1); + + count = 0; + while(result[count]!='\0' && count < len) + { + if(result[count]==toReplace) + { + result[count]=replacement; + } + count++; + } + + return result; +} diff --git a/targ.c b/targ.c index 01c3d1c..17b14aa 100644 --- a/targ.c +++ b/targ.c @@ -248,3 +248,3 @@ Targ_NewGN(const char *name) gn->centurion = NULL; - gn->made = UNMADE; + gn->made = __UNMADE; gn->flags = 0; @@ -605,10 +605,10 @@ made_name(enum enum_made made) switch (made) { - case UNMADE: return "unmade"; - case DEFERRED: return "deferred"; - case REQUESTED: return "requested"; - case BEINGMADE: return "being made"; - case MADE: return "made"; - case UPTODATE: return "up-to-date"; - case ERROR: return "error when made"; - case ABORTED: return "aborted"; + case __UNMADE: return "unmade"; + case __DEFERRED: return "deferred"; + case __REQUESTED: return "requested"; + case __BEINGMADE: return "being made"; + case __MADE: return "made"; + case __UPTODATE: return "up-to-date"; + case __ERROR: return "error when made"; + case __ABORTED: return "aborted"; default: return "unknown enum_made value"; @@ -650,3 +650,3 @@ Targ_PrintNode(void *gnp, void *passp) made_name(gn->made)); - } else if (gn->made != UNMADE) { + } else if (gn->made != __UNMADE) { fprintf(debug_file, "# non-existent (maybe): %s\n", diff --git a/trace.c b/trace.c index 267177f..f0f8693 100644 --- a/trace.c +++ b/trace.c @@ -58,2 +58,5 @@ __RCSID("$NetBSD: trace.c,v 1.11 2008/12/28 18:31:51 christos Exp $"); #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/unistd.h" +#endif diff --git a/unit-tests/Makefile b/unit-tests/Makefile new file mode 100644 index 0000000..bd45de7 --- /dev/null +++ b/unit-tests/Makefile @@ -0,0 +1,152 @@ +# $Id: Makefile.in,v 1.49 2018/09/21 21:39:05 sjg Exp $ +# +# $NetBSD: Makefile,v 1.53 2018/05/24 00:25:44 christos Exp $ +# +# Unit tests for make(1) +# The main targets are: +# +# all: run all the tests +# test: run 'all', and compare to expected results +# accept: move generated output to expected results +# +# Adding a test case. +# Each feature should get its own set of tests in its own suitably +# named makefile (*.mk), with its own set of expected results (*.exp), +# and it should be added to the TESTNAMES list. +# + +srcdir= /home/ofry/bmake/unit-tests + +.MAIN: all + +UNIT_TESTS:= ${srcdir} +WIN_UNIT_TESTS != cygpath -m ${srcdir} +.PATH: ${UNIT_TESTS} + +# Each test is in a sub-makefile. +# Keep the list sorted. +TESTNAMES= \ + comment \ + cond1 \ + cond2 \ + error \ + export \ + export-all \ + export-env \ + doterror \ + forloop \ + forsubst \ + hash \ + misc \ + moderrs \ + modmatch \ + modmisc \ + modorder \ + modts \ + modword \ + qequals \ + sunshcmd \ + sysv \ + ternary \ + unexport \ + unexport-env \ + varcmd \ + varmisc \ + varquote \ + varshell + +# these tests were broken by referting POSIX chanegs +STRICT_POSIX_TESTS = \ + escape \ + impsrc \ + phony-end \ + posix1 \ + suffixes + +# Override make flags for certain tests +flags.doterror= +flags.order=-j1 + +OUTFILES= ${TESTNAMES:S/$/.out/} + +all: ${OUTFILES} + +CLEANFILES += *.rawout *.out *.status *.tmp *.core *.tmp +CLEANFILES += obj*.[och] lib*.a # posix1.mk +CLEANFILES += issue* .[ab]* # suffixes.mk +CLEANRECURSIVE += dir dummy # posix1.mk + +clean: + rm -f ${CLEANFILES} +.if !empty(CLEANRECURSIVE) + rm -rf ${CLEANRECURSIVE} +.endif + +TEST_MAKE?= ${.MAKE} +TOOL_SED?= sed +TOOL_TR?= tr +TOOL_DIFF?= diff +DIFF_FLAGS?= -u + +.if defined(.PARSEDIR) +# ensure consistent results from sort(1) +LC_ALL= C +LANG= C +.export LANG LC_ALL +.endif + +# some tests need extra post-processing +SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ + -e '/command/s,No such.*,not found,' + +# the tests are actually done with sub-makes. +.SUFFIXES: .mk .rawout .out +.mk.rawout: + @echo ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} + -@cd ${.OBJDIR} && \ + { ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} \ + 2>&1 ; echo $$? >${.TARGET:R}.status ; } > ${.TARGET}.tmp + @mv ${.TARGET}.tmp ${.TARGET} + +# We always pretend .MAKE was called 'make' +# and strip ${.CURDIR}/ from the output +# and replace anything after 'stopped in' with unit-tests +# so the results can be compared. +.rawout.out: + @echo postprocess ${.TARGET} + @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \ + -e 's,^${TEST_MAKE:T:C/\./\\\./g}\.exe[][0-9]*:,make:,' \ + -e 's,${TEST_MAKE:C/\./\\\./g},make,' \ + -e '/stopped/s, /.*, unit-tests,' \ + -e 's,${.CURDIR:C/\./\\\./g}/,,g' \ + -e 's,${WIN_UNIT_TESTS:C/\./\\\./g},unit-tests,g' \ + -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' ${SED_CMDS.${.TARGET:T:R}} \ + < ${.IMPSRC} > ${.TARGET}.tmp + @echo "exit status `cat ${.TARGET:R}.status`" >> ${.TARGET}.tmp + @mv ${.TARGET}.tmp ${.TARGET} + +# Compare all output files +test: ${OUTFILES} .PHONY + @failed= ; \ + for test in ${TESTNAMES}; do \ + ${TOOL_DIFF} ${DIFF_FLAGS} ${UNIT_TESTS}/$${test}.exp $${test}.out \ + || failed="$${failed}$${failed:+ }$${test}" ; \ + done ; \ + if [ -n "$${failed}" ]; then \ + echo "Failed tests: $${failed}" ; false ; \ + else \ + echo "All tests passed" ; \ + fi + +accept: + @for test in ${TESTNAMES}; do \ + cmp -s ${UNIT_TESTS}/$${test}.exp $${test}.out \ + || { echo "Replacing $${test}.exp" ; \ + cp $${test}.out ${UNIT_TESTS}/$${test}.exp ; } \ + done + +.if exists(${TEST_MAKE}) +${TESTNAMES:S/$/.rawout/}: ${TEST_MAKE} +.endif + +.-include diff --git a/unit-tests/Makefile.in b/unit-tests/Makefile.in index e51d254..c24bc33 100644 --- a/unit-tests/Makefile.in +++ b/unit-tests/Makefile.in @@ -22,2 +22,3 @@ srcdir= @srcdir@ UNIT_TESTS:= ${srcdir} +WIN_UNIT_TESTS != cygpath -m ${srcdir} .PATH: ${UNIT_TESTS} @@ -35,3 +36,2 @@ TESTNAMES= \ doterror \ - dotwait \ forloop \ @@ -46,4 +46,2 @@ TESTNAMES= \ modword \ - order \ - posix \ qequals \ @@ -119,2 +117,3 @@ SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \ + -e 's,^${TEST_MAKE:T:C/\./\\\./g}\.exe[][0-9]*:,make:,' \ -e 's,${TEST_MAKE:C/\./\\\./g},make,' \ @@ -122,2 +121,3 @@ SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ -e 's,${.CURDIR:C/\./\\\./g}/,,g' \ + -e 's,${WIN_UNIT_TESTS:C/\./\\\./g},unit-tests,g' \ -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' ${SED_CMDS.${.TARGET:T:R}} \ diff --git a/unit-tests/doterror.exp b/unit-tests/doterror.exp index 5655644..1c8b971 100644 --- a/unit-tests/doterror.exp +++ b/unit-tests/doterror.exp @@ -7,3 +7,3 @@ Stop. make: stopped in unit-tests -.ERROR: Looks like 'sad' is upset. +.__ERROR: Looks like 'sad' is upset. exit status 1 diff --git a/unit-tests/doterror.mk b/unit-tests/doterror.mk index 9030dce..676e2e6 100644 --- a/unit-tests/doterror.mk +++ b/unit-tests/doterror.mk @@ -9,3 +9,3 @@ -.ERROR: +.__ERROR: @echo "$@: Looks like '${.ERROR_TARGET}' is upset." diff --git a/unit-tests/escape.mk b/unit-tests/escape.mk index bb37c92..3bf1b1f 100644 --- a/unit-tests/escape.mk +++ b/unit-tests/escape.mk @@ -53,3 +53,3 @@ should continue the comment. \ -__printvars: .USE .MADE +__printvars: .USE .__MADE @echo ${.TARGET} diff --git a/util.c b/util.c index c79f645..25f4f5e 100644 --- a/util.c +++ b/util.c @@ -9,2 +9,8 @@ #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/signal.h" +#endif +#ifndef SIGQUIT +#define SIGQUIT SIGTERM +#endif #endif @@ -24,17 +30,487 @@ __RCSID("$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $"); #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/signal.h" +#endif +#ifndef SIGQUIT +#define SIGQUIT SIGTERM +#endif -#if !defined(HAVE_STRERROR) -extern int errno, sys_nerr; -extern char *sys_errlist[]; +#ifndef NO_REGEX -char * -strerror(int e) +#include + +# if (defined _WIN32 && !defined __CYGWIN__) +#include "headers-mingw/regex.h" +#include "headers-mingw/regex_internal.h" +# else + +#include + +# endif +#endif + +#if !defined(HAVE_PIPE) && (defined _WIN32 && ! defined __CYGWIN__) +/* Create a pipe. + Copyright (C) 2009-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see . */ + +/* Specification. */ +#include +#include "headers-mingw/unistd.h" +/* Native Windows API. */ + +/* Get _pipe(). */ +#include + +/* Get _O_BINARY. */ +#include +#include "headers-mingw/fcntl.h" + +int +pipe (int fd[2]) { - static char buf[100]; - if (e < 0 || e >= sys_nerr) { - snprintf(buf, sizeof(buf), "Unknown error %d", e); - return buf; + /* Mingw changes fd to {-1,-1} on failure, but this violates + http://austingroupbugs.net/view.php?id=467 */ + int tmp[2]; + int result = _pipe (tmp, 4096, _O_BINARY); + if (!result) + { + fd[0] = tmp[0]; + fd[1] = tmp[1]; } - else - return sys_errlist[e]; + return result; +} + +#endif + +#if !defined(HAVE_GETDTABLESIZE) && (defined _WIN32 && ! defined __CYGWIN__) +/* getdtablesize() function: Return maximum possible file descriptor value + 1. + Copyright (C) 2008-2018 Free Software Foundation, Inc. + Written by Bruno Haible , 2008. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Specification. */ +#include +#include "headers-mingw/unistd.h" + +# include + +# define _setmaxstdio_nothrow _setmaxstdio + +/* Cache for the previous getdtablesize () result. Safe to cache because + Windows also lacks setrlimit. */ +static int dtablesize; + +int +getdtablesize (void) +{ + if (dtablesize == 0) + { + /* We are looking for the number N such that the valid file descriptors + are 0..N-1. It can be obtained through a loop as follows: + { + int fd; + for (fd = 3; fd < 65536; fd++) + if (dup2 (0, fd) == -1) + break; + return fd; + } + On Windows XP, the result is 2048. + The drawback of this loop is that it allocates memory for a libc + internal array that is never freed. + + The number N can also be obtained as the upper bound for + _getmaxstdio (). _getmaxstdio () returns the maximum number of open + FILE objects. The sanity check in _setmaxstdio reveals the maximum + number of file descriptors. This too allocates memory, but it is + freed when we call _setmaxstdio with the original value. */ + int orig_max_stdio = _getmaxstdio (); + unsigned int bound; + for (bound = 0x10000; _setmaxstdio_nothrow (bound) < 0; bound = bound / 2) + ; + _setmaxstdio_nothrow (orig_max_stdio); + dtablesize = bound; + } + return dtablesize; +} + +#endif + +#if !defined(HAVE_FCNTL) && (defined _WIN32 && ! defined __CYGWIN__) +/* Provide file descriptor control. + + Copyright (C) 2009-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Eric Blake . */ + +/* Specification. */ +#include "headers-mingw/fcntl.h" + +#include +#include +#include +#include + +/* Get declarations of the native Windows API functions. */ +# define WIN32_LEAN_AND_MEAN +# include + +/* Get _get_osfhandle. */ +# if GNULIB_MSVC_NOTHROW +# include "msvc-nothrow.h" +# else +# include +# endif + +/* Upper bound on getdtablesize(). See lib/getdtablesize.c. */ +# define OPEN_MAX_MAX 0x10000 + +/* Duplicate OLDFD into the first available slot of at least NEWFD, + which must be positive, with FLAGS determining whether the duplicate + will be inheritable. */ +static int +dupfd (int oldfd, int newfd, int flags) +{ + /* Mingw has no way to create an arbitrary fd. Iterate until all + file descriptors less than newfd are filled up. */ + HANDLE curr_process = GetCurrentProcess (); + HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd); + unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT]; + unsigned int fds_to_close_bound = 0; + int result; + BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE; + int mode; + + if (newfd < 0 || getdtablesize () <= newfd) + { + errno = EINVAL; + return -1; + } + if (old_handle == INVALID_HANDLE_VALUE + || (mode = setmode (oldfd, O_BINARY)) == -1) + { + /* oldfd is not open, or is an unassigned standard file + descriptor. */ + errno = EBADF; + return -1; + } + setmode (oldfd, mode); + flags |= mode; + + for (;;) + { + HANDLE new_handle; + int duplicated_fd; + unsigned int index; + + if (!DuplicateHandle (curr_process, /* SourceProcessHandle */ + old_handle, /* SourceHandle */ + curr_process, /* TargetProcessHandle */ + (PHANDLE) &new_handle, /* TargetHandle */ + (DWORD) 0, /* DesiredAccess */ + inherit, /* InheritHandle */ + DUPLICATE_SAME_ACCESS)) /* Options */ + { + switch (GetLastError ()) + { + case ERROR_TOO_MANY_OPEN_FILES: + errno = EMFILE; + break; + case ERROR_INVALID_HANDLE: + case ERROR_INVALID_TARGET_HANDLE: + case ERROR_DIRECT_ACCESS_HANDLE: + errno = EBADF; + break; + case ERROR_INVALID_PARAMETER: + case ERROR_INVALID_FUNCTION: + case ERROR_INVALID_ACCESS: + errno = EINVAL; + break; + default: + errno = EACCES; + break; + } + result = -1; + break; + } + duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags); + if (duplicated_fd < 0) + { + CloseHandle (new_handle); + result = -1; + break; + } + if (newfd <= duplicated_fd) + { + result = duplicated_fd; + break; + } + + /* Set the bit duplicated_fd in fds_to_close[]. */ + index = (unsigned int) duplicated_fd / CHAR_BIT; + if (fds_to_close_bound <= index) + { + if (sizeof fds_to_close <= index) + /* Need to increase OPEN_MAX_MAX. */ + abort (); + memset (fds_to_close + fds_to_close_bound, '\0', + index + 1 - fds_to_close_bound); + fds_to_close_bound = index + 1; + } + fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT); + } + + /* Close the previous fds that turned out to be too small. */ + { + int saved_errno = errno; + unsigned int duplicated_fd; + + for (duplicated_fd = 0; + duplicated_fd < fds_to_close_bound * CHAR_BIT; + duplicated_fd++) + if ((fds_to_close[duplicated_fd / CHAR_BIT] + >> (duplicated_fd % CHAR_BIT)) + & 1) + close (duplicated_fd); + + errno = saved_errno; + } + return result; +} + +/* Forward declarations, because we '#undef fcntl' in the middle of this + compilation unit. */ +/* Our implementation of fcntl (fd, F_DUPFD, target). */ +static int rpl_fcntl_DUPFD (int fd, int target); +/* Our implementation of fcntl (fd, F_DUPFD_CLOEXEC, target). */ +static int rpl_fcntl_DUPFD_CLOEXEC (int fd, int target); + +/* Perform the specified ACTION on the file descriptor FD, possibly + using the argument ARG further described below. This replacement + handles the following actions, and forwards all others on to the + native fcntl. An unrecognized ACTION returns -1 with errno set to + EINVAL. + + F_DUPFD - duplicate FD, with int ARG being the minimum target fd. + If successful, return the duplicate, which will be inheritable; + otherwise return -1 and set errno. + + F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum + target fd. If successful, return the duplicate, which will not be + inheritable; otherwise return -1 and set errno. + + F_GETFD - ARG need not be present. If successful, return a + non-negative value containing the descriptor flags of FD (only + FD_CLOEXEC is portable, but other flags may be present); otherwise + return -1 and set errno. */ + +int +fcntl (int fd, int action, /* arg */...) +{ + va_list arg; + int result = -1; + va_start (arg, action); + switch (action) + { + case F_DUPFD: + { + int target = va_arg (arg, int); + result = rpl_fcntl_DUPFD (fd, target); + break; + } + + case F_DUPFD_CLOEXEC: + { + int target = va_arg (arg, int); + result = rpl_fcntl_DUPFD_CLOEXEC (fd, target); + break; + } + + case F_GETFD: + { + HANDLE handle = (HANDLE) _get_osfhandle (fd); + DWORD flags; + if (handle == INVALID_HANDLE_VALUE + || GetHandleInformation (handle, &flags) == 0) + errno = EBADF; + else + result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC; + break; + } /* F_GETFD */ + + /* Implementing F_SETFD on mingw is not trivial - there is no + API for changing the O_NOINHERIT bit on an fd, and merely + changing the HANDLE_FLAG_INHERIT bit on the underlying handle + can lead to odd state. It may be possible by duplicating the + handle, using _open_osfhandle with the right flags, then + using dup2 to move the duplicate onto the original, but that + is not supported for now. */ + + default: + { + errno = EINVAL; + break; + } + } + va_end (arg); + return result; +} + +static int +rpl_fcntl_DUPFD (int fd, int target) +{ + int result; + result = dupfd (fd, target, 0); + return result; +} + +static int +rpl_fcntl_DUPFD_CLOEXEC (int fd, int target) +{ + int result; + result = dupfd (fd, target, O_CLOEXEC); + return result; +} + +#endif + +#if !defined(HAVE_FORK) && (defined _WIN32 && ! defined __CYGWIN__) +/* + * fork.c + * Experimental fork() on Windows. Requires NT 6 subsystem or + * newer. + * + * Copyright (c) 2012 William Pitcock + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include + +typedef struct _SECTION_IMAGE_INFORMATION { + PVOID EntryPoint; + ULONG StackZeroBits; + ULONG StackReserved; + ULONG StackCommit; + ULONG ImageSubsystem; + WORD SubSystemVersionLow; + WORD SubSystemVersionHigh; + ULONG Unknown1; + ULONG ImageCharacteristics; + ULONG ImageMachineType; + ULONG Unknown2[3]; +} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; + +typedef struct _RTL_USER_PROCESS_INFORMATION { + ULONG Size; + HANDLE Process; + HANDLE Thread; + CLIENT_ID ClientId; + SECTION_IMAGE_INFORMATION ImageInformation; +} RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION; + +#define RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED 0x00000001 +#define RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES 0x00000002 +#define RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE 0x00000004 + +#define RTL_CLONE_PARENT 0 +#define RTL_CLONE_CHILD 297 + +typedef NTSTATUS (*RtlCloneUserProcess_f)(ULONG ProcessFlags, + PSECURITY_DESCRIPTOR ProcessSecurityDescriptor /* optional */, + PSECURITY_DESCRIPTOR ThreadSecurityDescriptor /* optional */, + HANDLE DebugPort /* optional */, + PRTL_USER_PROCESS_INFORMATION ProcessInformation); + +pid_t fork(void) +{ + HMODULE mod; + RtlCloneUserProcess_f clone_p; + RTL_USER_PROCESS_INFORMATION process_info; + NTSTATUS result; + + mod = GetModuleHandle("ntdll.dll"); + if (!mod) + return -ENOSYS; + + clone_p = (RtlCloneUserProcess_f)GetProcAddress(mod, "RtlCloneUserProcess"); + if (clone_p == NULL) + return -ENOSYS; + + /* lets do this */ + result = clone_p(RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED | RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES, NULL, NULL, NULL, &process_info); + + if (result == RTL_CLONE_PARENT) + { + HANDLE me, hp, ht, hcp = 0; + DWORD pi, ti, mi; + me = GetCurrentProcess(); + pi = (DWORD)process_info.ClientId.UniqueProcess; + ti = (DWORD)process_info.ClientId.UniqueThread; + + ResumeThread(ht); + CloseHandle(ht); + CloseHandle(hp); + return (pid_t)pi; + } + else if (result == RTL_CLONE_CHILD) + { + /* fix stdio */ + AllocConsole(); + return 0; + } + else + return -1; + + /* NOTREACHED */ + return -1; } @@ -221,2 +697,5 @@ char *sys_siglist[] = { #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif #include @@ -224,2 +703,5 @@ char *sys_siglist[] = { #include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/unistd.h" +#endif @@ -367,2 +849,641 @@ getwd(char *pathname) +#if !defined(HAVE_RANDOM) +/* Copyright (C) 1995-2018 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + * Rewritten to use reentrant functions by Ulrich Drepper, 1995. + */ + +/* + Copyright (C) 1983 Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE.*/ + +#ifndef _LIBC +# include "headers-mingw/libc-config.h" +#endif + +/* Specification. */ +#include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/stdlib.h" +#endif + +#include +#include +#include + +#ifdef _LIBC +# include +#else +/* Allow memory races; that's random enough. */ +# define __libc_lock_define_initialized(class, name) +# define __libc_lock_lock(name) ((void) 0) +# define __libc_lock_unlock(name) ((void) 0) +#endif + +/* An improved random number generation package. In addition to the standard + rand()/srand() like interface, this package also has a special state info + interface. The initstate() routine is called with a seed, an array of + bytes, and a count of how many bytes are being passed in; this array is + then initialized to contain information for random number generation with + that much state information. Good sizes for the amount of state + information are 32, 64, 128, and 256 bytes. The state can be switched by + calling the setstate() function with the same array as was initialized + with initstate(). By default, the package runs with 128 bytes of state + information and generates far better random numbers than a linear + congruential generator. If the amount of state information is less than + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the + state information is treated as an array of longs; the zeroth element of + the array is the type of R.N.G. being used (small integer); the remainder + of the array is the state information for the R.N.G. Thus, 32 bytes of + state information will give 7 longs worth of state information, which will + allow a degree seven polynomial. (Note: The zeroth word of state + information also has some other information stored in it; see setstate + for details). The random number generation technique is a linear feedback + shift register approach, employing trinomials (since there are fewer terms + to sum up that way). In this approach, the least significant bit of all + the numbers in the state table will act as a linear feedback shift register, + and will have period 2^deg - 1 (where deg is the degree of the polynomial + being used, assuming that the polynomial is irreducible and primitive). + The higher order bits will have longer periods, since their values are + also influenced by pseudo-random carries out of the lower bits. The + total period of the generator is approximately deg*(2**deg - 1); thus + doubling the amount of state information has a vast influence on the + period of the generator. Note: The deg*(2**deg - 1) is an approximation + only good for large deg, when the period of the shift register is the + dominant factor. With deg equal to seven, the period is actually much + longer than the 7*(2**7 - 1) predicted by this formula. */ + + + +/* For each of the currently supported random number generators, we have a + break value on the amount of state information (you need at least this many + bytes of state info to support this random number generator), a degree for + the polynomial (actually a trinomial) that the R.N.G. is based on, and + separation between the two lower order coefficients of the trinomial. */ + +/* Linear congruential. */ +#define TYPE_0 0 +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +/* x**7 + x**3 + 1. */ +#define TYPE_1 1 +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +/* x**15 + x + 1. */ +#define TYPE_2 2 +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +/* x**31 + x**3 + 1. */ +#define TYPE_3 3 +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +/* x**63 + x + 1. */ +#define TYPE_4 4 +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +#define MAX_TYPES 5 /* Max number of types above. */ + + +/* Initially, everything is set up as if from: + initstate(1, randtbl, 128); + Note that this initialization takes advantage of the fact that srandom + advances the front and rear pointers 10*rand_deg times, and hence the + rear pointer which starts at 0 will also end up at zero; thus the zeroth + element of the state information, which contains info about the current + position of the rear pointer is just + (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ + +static int32_t randtbl[DEG_3 + 1] = + { + TYPE_3, + + -1726662223, 379960547, 1735697613, 1040273694, 1313901226, + 1627687941, -179304937, -2073333483, 1780058412, -1989503057, + -615974602, 344556628, 939512070, -1249116260, 1507946756, + -812545463, 154635395, 1388815473, -1926676823, 525320961, + -1009028674, 968117788, -123449607, 1284210865, 435012392, + -2017506339, -911064859, -370259173, 1132637927, 1398500161, + -205601318, + }; + + +static struct random_data unsafe_state = + { +/* FPTR and RPTR are two pointers into the state info, a front and a rear + pointer. These two pointers are always rand_sep places apart, as they + cycle through the state information. (Yes, this does mean we could get + away with just one pointer, but the code for random is more efficient + this way). The pointers are left positioned as they would be from the call: + initstate(1, randtbl, 128); + (The position of the rear pointer, rptr, is really 0 (as explained above + in the initialization of randtbl) because the state table pointer is set + to point to randtbl[1] (as explained below).) */ + + .fptr = &randtbl[SEP_3 + 1], + .rptr = &randtbl[1], + +/* The following things are the pointer to the state information table, + the type of the current generator, the degree of the current polynomial + being used, and the separation between the two pointers. + Note that for efficiency of random, we remember the first location of + the state information, not the zeroth. Hence it is valid to access + state[-1], which is used to store the type of the R.N.G. + Also, we remember the last location, since this is more efficient than + indexing every time to find the address of the last element to see if + the front and rear pointers have wrapped. */ + + .state = &randtbl[1], + + .rand_type = TYPE_3, + .rand_deg = DEG_3, + .rand_sep = SEP_3, + + .end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])] + }; + +/* POSIX.1c requires that there is mutual exclusion for the 'rand' and + 'srand' functions to prevent concurrent calls from modifying common + data. */ +__libc_lock_define_initialized (static, lock) + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ +void +__srandom (unsigned int x) +{ + __libc_lock_lock (lock); + (void) __srandom_r (x, &unsafe_state); + __libc_lock_unlock (lock); +} + +inline void +srandom (unsigned int x) +{ + return __srandom(x); +} + +inline void +srand (unsigned int x) +{ + return __srandom(x); +} + +/* Initialize the state information in the given array of N bytes for + future random number generation. Based on the number of bytes we + are given, and the break values for the different R.N.G.'s, we choose + the best (largest) one we can and set things up for it. srandom is + then called to initialize the state information. Note that on return + from srandom, we set state[-1] to be the type multiplexed with the current + value of the rear pointer; this is so successive calls to initstate won't + lose this information and will be able to restart with setstate. + Note: The first thing we do is save the current state, if any, just like + setstate so that it doesn't matter when initstate is called. + Returns a pointer to the old state. */ +char * +__initstate (unsigned int seed, char *arg_state, size_t n) +{ + int32_t *ostate; + int ret; + + __libc_lock_lock (lock); + + ostate = &unsafe_state.state[-1]; + + ret = __initstate_r (seed, arg_state, n, &unsafe_state); + + __libc_lock_unlock (lock); + + return ret == -1 ? NULL : (char *) ostate; +} + +inline char * +initstate (unsigned int seed, char *arg_state, size_t n) +{ + return __initstate(seed, arg_state, n); +} + +/* Restore the state from the given state array. + Note: It is important that we also remember the locations of the pointers + in the current state information, and restore the locations of the pointers + from the old state information. This is done by multiplexing the pointer + location into the zeroth word of the state information. Note that due + to the order in which things are done, it is OK to call setstate with the + same state as the current state + Returns a pointer to the old state information. */ +char * +__setstate (char *arg_state) +{ + int32_t *ostate; + + __libc_lock_lock (lock); + + ostate = &unsafe_state.state[-1]; + + if (__setstate_r (arg_state, &unsafe_state) < 0) + ostate = NULL; + + __libc_lock_unlock (lock); + + return (char *) ostate; +} + +inline char * +setstate (char *arg_state) +{ + return __setstate(arg_state); +} + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all the other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +long int +__random (void) +{ + int32_t retval; + + __libc_lock_lock (lock); + + (void) __random_r (&unsafe_state, &retval); + + __libc_lock_unlock (lock); + + return retval; +} +inline long int random(void) +{ + return __random(); +} + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +struct random_poly_info +{ + int seps[MAX_TYPES]; + int degrees[MAX_TYPES]; +}; + +static const struct random_poly_info random_poly_info = + { + { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }, + { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 } + }; + +static int32_t +get_int32 (void *p) +{ + int32_t v; + memcpy (&v, p, sizeof v); + return v; +} + +static void +set_int32 (void *p, int32_t v) +{ + memcpy (p, &v, sizeof v); +} + + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ +int +__srandom_r (unsigned int seed, struct random_data *buf) +{ + int type; + int32_t *state; + long int i; + int32_t word; + int32_t *dst; + int kc; + + if (buf == NULL) + goto fail; + type = buf->rand_type; + if ((unsigned int) type >= MAX_TYPES) + goto fail; + + state = buf->state; + /* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */ + if (seed == 0) + seed = 1; + set_int32 (&state[0], seed); + if (type == TYPE_0) + goto done; + + dst = state; + word = seed; + kc = buf->rand_deg; + for (i = 1; i < kc; ++i) + { + /* This does: + state[i] = (16807 * state[i - 1]) % 2147483647; + but avoids overflowing 31 bits. */ + long int hi = word / 127773; + long int lo = word % 127773; + word = 16807 * lo - 2836 * hi; + if (word < 0) + word += 2147483647; + set_int32 (++dst, word); + } + + buf->fptr = &state[buf->rand_sep]; + buf->rptr = &state[0]; + kc *= 10; + while (--kc >= 0) + { + int32_t discard; + (void) __random_r (buf, &discard); + } + + done: + return 0; + + fail: + return -1; +} + +inline int +srandom_r (unsigned int seed, struct random_data *buf) +{ + return __srandom_r(seed, buf); +} + +/* Initialize the state information in the given array of N bytes for + future random number generation. Based on the number of bytes we + are given, and the break values for the different R.N.G.'s, we choose + the best (largest) one we can and set things up for it. srandom is + then called to initialize the state information. Note that on return + from srandom, we set state[-1] to be the type multiplexed with the current + value of the rear pointer; this is so successive calls to initstate won't + lose this information and will be able to restart with setstate. + Note: The first thing we do is save the current state, if any, just like + setstate so that it doesn't matter when initstate is called. + Returns 0 on success, non-zero on failure. */ +int +__initstate_r (unsigned int seed, char *arg_state, size_t n, + struct random_data *buf) +{ + if (buf == NULL) + goto fail; + + int32_t *old_state = buf->state; + if (old_state != NULL) + { + int old_type = buf->rand_type; + set_int32 (&old_state[-1], + (old_type == TYPE_0 + ? TYPE_0 + : (MAX_TYPES * (buf->rptr - old_state)) + old_type)); + } + + int type; + if (n >= BREAK_3) + type = n < BREAK_4 ? TYPE_3 : TYPE_4; + else if (n < BREAK_1) + { + if (n < BREAK_0) + goto fail; + + type = TYPE_0; + } + else + type = n < BREAK_2 ? TYPE_1 : TYPE_2; + + int degree = random_poly_info.degrees[type]; + int separation = random_poly_info.seps[type]; + + buf->rand_type = type; + buf->rand_sep = separation; + buf->rand_deg = degree; + int32_t *state = &((int32_t *) arg_state)[1]; /* First location. */ + /* Must set END_PTR before srandom. */ + buf->end_ptr = &state[degree]; + + buf->state = state; + + __srandom_r (seed, buf); + + set_int32 (&state[-1], + type == TYPE_0 ? TYPE_0 : (buf->rptr - state) * MAX_TYPES + type); + + return 0; + + fail: + __set_errno (EINVAL); + return -1; +} + +inline int +initstate_r (unsigned int seed, char *arg_state, size_t n, + struct random_data *buf) +{ + return __initstate_r(seed, arg_state, n, buf); +} + +/* Restore the state from the given state array. + Note: It is important that we also remember the locations of the pointers + in the current state information, and restore the locations of the pointers + from the old state information. This is done by multiplexing the pointer + location into the zeroth word of the state information. Note that due + to the order in which things are done, it is OK to call setstate with the + same state as the current state + Returns 0 on success, non-zero on failure. */ +int +__setstate_r (char *arg_state, struct random_data *buf) +{ + int32_t *new_state = 1 + (int32_t *) arg_state; + int type; + int old_type; + int32_t *old_state; + int degree; + int separation; + + if (arg_state == NULL || buf == NULL) + goto fail; + + old_type = buf->rand_type; + old_state = buf->state; + set_int32 (&old_state[-1], + (old_type == TYPE_0 + ? TYPE_0 + : (MAX_TYPES * (buf->rptr - old_state)) + old_type)); + + type = get_int32 (&new_state[-1]) % MAX_TYPES; + if (type < TYPE_0 || type > TYPE_4) + goto fail; + + buf->rand_deg = degree = random_poly_info.degrees[type]; + buf->rand_sep = separation = random_poly_info.seps[type]; + buf->rand_type = type; + + if (type != TYPE_0) + { + int rear = get_int32 (&new_state[-1]) / MAX_TYPES; + buf->rptr = &new_state[rear]; + buf->fptr = &new_state[(rear + separation) % degree]; + } + buf->state = new_state; + /* Set end_ptr too. */ + buf->end_ptr = &new_state[degree]; + + return 0; + + fail: + __set_errno (EINVAL); + return -1; +} + +inline int setstate_r (char *arg_state, struct random_data *buf) +{ + return __setstate_r(arg_state, buf); +} + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all the other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +int +__random_r (struct random_data *buf, int32_t *result) +{ + int32_t *state; + + if (buf == NULL || result == NULL) + goto fail; + + state = buf->state; + + if (buf->rand_type == TYPE_0) + { + int32_t val = (((get_int32 (&state[0]) * 1103515245U) + 12345U) + & 0x7fffffff); + set_int32 (&state[0], val); + *result = val; + } + else + { + int32_t *fptr = buf->fptr; + int32_t *rptr = buf->rptr; + int32_t *end_ptr = buf->end_ptr; + /* F and R are unsigned int, not uint32_t, to avoid undefined + overflow behavior on platforms where INT_MAX == UINT32_MAX. */ + unsigned int f = get_int32 (fptr); + unsigned int r = get_int32 (rptr); + uint32_t val = f + r; + set_int32 (fptr, val); + /* Chucking least random bit. */ + *result = val >> 1; + ++fptr; + if (fptr >= end_ptr) + { + fptr = state; + ++rptr; + } + else + { + ++rptr; + if (rptr >= end_ptr) + rptr = state; + } + buf->fptr = fptr; + buf->rptr = rptr; + } + return 0; + + fail: + __set_errno (EINVAL); + return -1; +} + +inline int +random_r (struct random_data *buf, int32_t *result) +{ + return __random_r(buf, result); +} + +#endif + #if !defined(HAVE_GETCWD) @@ -526,2 +1647,19 @@ strftime(char *buf, size_t len, const char *fmt, const struct tm *tm) +#if !defined(HAVE_STRERROR) +extern int errno, sys_nerr; +extern char *sys_errlist[]; + +char * +strerror(int e) +{ + static char buf[100]; + if (e < 0 || e >= sys_nerr) { + snprintf(buf, sizeof(buf), "Unknown error %d", e); + return buf; + } + else + return sys_errlist[e]; +} +#endif + #if !defined(HAVE_KILLPG) @@ -599,11 +1737,11 @@ errx(int eval, const char *fmt, ...) -#if !defined(HAVE_WARN) -void -warn(const char *fmt, ...) -{ - va_list ap; +#if !defined(HAVE_KILL) && (defined _WIN32 && ! defined __CYGWIN__) +# define WIN32_LEAN_AND_MEAN +# include - va_start(ap, fmt); - vwarn(fmt, ap); - va_end(ap); +/* The return value of spawnvp() is really a process handle as returned + by CreateProcess(). Therefore we can kill it using TerminateProcess. */ +int kill(pid_t pid, int sig) +{ + return TerminateProcess ((HANDLE) (pid), sig); } @@ -611,9 +1749,1208 @@ warn(const char *fmt, ...) -#if !defined(HAVE_WARNX) -void -warnx(const char *fmt, ...) -{ - va_list ap; +#if (defined _WIN32 && ! defined __CYGWIN__) //poll function +/* Emulation for poll(2) + Contributed by Paolo Bonzini. - va_start(ap, fmt); + Copyright 2001-2003, 2006-2018 Free Software Foundation, Inc. + + This file is part of gnulib. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see . */ + +/* Tell gcc not to warn about the (nfd < 0) tests, below. */ +#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__ +# pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +//#include + +#include + +/* Specification. */ +#include "headers-mingw/poll.h" + +#include +#include + +#include +#include +#include +#include +#include +#if GNULIB_MSVC_NOTHROW +# include "msvc-nothrow.h" +#else +# include +#endif + +//#include +//#include + +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_SYS_FILIO_H +# include +#endif + +#include + +//#include "assure.h" + +#ifndef INFTIM +# define INFTIM (-1) +#endif + +/* BeOS does not have MSG_PEEK. */ +#ifndef MSG_PEEK +# define MSG_PEEK 0 +#endif + +/* Avoid warnings from gcc -Wcast-function-type. */ +# define GetProcAddress \ + (void *) GetProcAddress + +static BOOL IsConsoleHandle (HANDLE h) +{ + DWORD mode; + return GetConsoleMode (h, &mode) != 0; +} + +static BOOL +IsSocketHandle (HANDLE h) +{ + WSANETWORKEVENTS ev; + + if (IsConsoleHandle (h)) + return FALSE; + + /* Under Wine, it seems that getsockopt returns 0 for pipes too. + WSAEnumNetworkEvents instead distinguishes the two correctly. */ + ev.lNetworkEvents = 0xDEADBEEF; + WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); + return ev.lNetworkEvents != 0xDEADBEEF; +} + +typedef DWORD (WINAPI *PNtQueryInformationFile) + (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS); + +# ifndef PIPE_BUF +# define PIPE_BUF 512 +# endif + +/* Compute revents values for file handle H. If some events cannot happen + for the handle, eliminate them from *P_SOUGHT. */ + +static int +windows_compute_revents (HANDLE h, int *p_sought) +{ + int i, ret, happened; + INPUT_RECORD *irbuffer; + DWORD avail, nbuffer; + BOOL bRet; + IO_STATUS_BLOCK iosb; + FILE_PIPE_LOCAL_INFORMATION fpli; + static PNtQueryInformationFile NtQueryInformationFile; + static BOOL once_only; + + switch (GetFileType (h)) + { + case FILE_TYPE_PIPE: + if (!once_only) + { + NtQueryInformationFile = (PNtQueryInformationFile) + GetProcAddress (GetModuleHandle ("ntdll.dll"), + "NtQueryInformationFile"); + once_only = TRUE; + } + + happened = 0; + if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0) + { + if (avail) + happened |= *p_sought & (POLLIN | POLLRDNORM); + } + else if (GetLastError () == ERROR_BROKEN_PIPE) + happened |= POLLHUP; + + else + { + /* It was the write-end of the pipe. Check if it is writable. + If NtQueryInformationFile fails, optimistically assume the pipe is + writable. This could happen on Windows 9x, where + NtQueryInformationFile is not available, or if we inherit a pipe + that doesn't permit FILE_READ_ATTRIBUTES access on the write end + (I think this should not happen since Windows XP SP2; WINE seems + fine too). Otherwise, ensure that enough space is available for + atomic writes. */ + memset (&iosb, 0, sizeof (iosb)); + memset (&fpli, 0, sizeof (fpli)); + + if (!NtQueryInformationFile + || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli), + FilePipeLocalInformation) + || fpli.WriteQuotaAvailable >= PIPE_BUF + || (fpli.OutboundQuota < PIPE_BUF && + fpli.WriteQuotaAvailable == fpli.OutboundQuota)) + happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND); + } + return happened; + + case FILE_TYPE_CHAR: + ret = WaitForSingleObject (h, 0); + if (!IsConsoleHandle (h)) + return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0; + + nbuffer = avail = 0; + bRet = GetNumberOfConsoleInputEvents (h, &nbuffer); + if (bRet) + { + /* Input buffer. */ + *p_sought &= POLLIN | POLLRDNORM; + if (nbuffer == 0) + return POLLHUP; + if (!*p_sought) + return 0; + + irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD)); + bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail); + if (!bRet || avail == 0) + return POLLHUP; + + for (i = 0; i < avail; i++) + if (irbuffer[i].EventType == KEY_EVENT) + return *p_sought; + return 0; + } + else + { + /* Screen buffer. */ + *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND; + return *p_sought; + } + + default: + ret = WaitForSingleObject (h, 0); + if (ret == WAIT_OBJECT_0) + return *p_sought & ~(POLLPRI | POLLRDBAND); + + return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND); + } +} + +/* Convert fd_sets returned by select into revents values. */ + +static int +windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents) +{ + int happened = 0; + + if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT) + happened |= (POLLIN | POLLRDNORM) & sought; + + else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) + { + int r, error; + + char data[64]; + WSASetLastError (0); + r = recv (h, data, sizeof (data), MSG_PEEK); + error = WSAGetLastError (); + WSASetLastError (0); + + if (r > 0 || error == WSAENOTCONN) + happened |= (POLLIN | POLLRDNORM) & sought; + + /* Distinguish hung-up sockets from other errors. */ + else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET + || error == WSAECONNABORTED || error == WSAENETRESET) + happened |= POLLHUP; + + else + happened |= POLLERR; + } + + if (lNetworkEvents & (FD_WRITE | FD_CONNECT)) + happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought; + + if (lNetworkEvents & FD_OOB) + happened |= (POLLPRI | POLLRDBAND) & sought; + + return happened; +} + +int +poll (struct pollfd *pfd, nfds_t nfd, int timeout) +{ + static struct timeval tv0; + static HANDLE hEvent; + WSANETWORKEVENTS ev; + HANDLE h, handle_array[FD_SETSIZE + 2]; + DWORD ret, wait_timeout, nhandles; + fd_set rfds, wfds, xfds; + BOOL poll_again; + MSG msg; + int rc = 0; + nfds_t i; + + if (nfd > INT_MAX || timeout < -1) + { + errno = EINVAL; + return -1; + } + + if (!hEvent) + hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + +restart: + handle_array[0] = hEvent; + nhandles = 1; + FD_ZERO (&rfds); + FD_ZERO (&wfds); + FD_ZERO (&xfds); + + /* Classify socket handles and create fd sets. */ + for (i = 0; i < nfd; i++) + { + int sought = pfd[i].events; + pfd[i].revents = 0; + if (pfd[i].fd < 0) + continue; + if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND + | POLLPRI | POLLRDBAND))) + continue; + + h = (HANDLE) _get_osfhandle (pfd[i].fd); + if (IsSocketHandle (h)) + { + int requested = FD_CLOSE; + + /* see above; socket handles are mapped onto select. */ + if (sought & (POLLIN | POLLRDNORM)) + { + requested |= FD_READ | FD_ACCEPT; + FD_SET ((SOCKET) h, &rfds); + } + if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND)) + { + requested |= FD_WRITE | FD_CONNECT; + FD_SET ((SOCKET) h, &wfds); + } + if (sought & (POLLPRI | POLLRDBAND)) + { + requested |= FD_OOB; + FD_SET ((SOCKET) h, &xfds); + } + + if (requested) + WSAEventSelect ((SOCKET) h, hEvent, requested); + } + else + { + /* Poll now. If we get an event, do not poll again. Also, + screen buffer handles are waitable, and they'll block until + a character is available. windows_compute_revents eliminates + bits for the "wrong" direction. */ + pfd[i].revents = windows_compute_revents (h, &sought); + if (sought) + handle_array[nhandles++] = h; + if (pfd[i].revents) + timeout = 0; + } + } + + if (select (0, &rfds, &wfds, &xfds, &tv0) > 0) + { + /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but + no need to call select again. */ + poll_again = FALSE; + wait_timeout = 0; + } + else + { + poll_again = TRUE; + if (timeout == INFTIM) + wait_timeout = INFINITE; + else + wait_timeout = timeout; + } + + for (;;) + { + ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE, + wait_timeout, QS_ALLINPUT); + + if (ret == WAIT_OBJECT_0 + nhandles) + { + /* new input of some other kind */ + BOOL bRet; + while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + } + else + break; + } + + if (poll_again) + select (0, &rfds, &wfds, &xfds, &tv0); + + /* Place a sentinel at the end of the array. */ + handle_array[nhandles] = NULL; + nhandles = 1; + for (i = 0; i < nfd; i++) + { + int happened; + + if (pfd[i].fd < 0) + continue; + if (!(pfd[i].events & (POLLIN | POLLRDNORM | + POLLOUT | POLLWRNORM | POLLWRBAND))) + continue; + + h = (HANDLE) _get_osfhandle (pfd[i].fd); + if (h != handle_array[nhandles]) + { + /* It's a socket. */ + WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); + WSAEventSelect ((SOCKET) h, 0, 0); + + /* If we're lucky, WSAEnumNetworkEvents already provided a way + to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */ + if (FD_ISSET ((SOCKET) h, &rfds) + && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT))) + ev.lNetworkEvents |= FD_READ | FD_ACCEPT; + if (FD_ISSET ((SOCKET) h, &wfds)) + ev.lNetworkEvents |= FD_WRITE | FD_CONNECT; + if (FD_ISSET ((SOCKET) h, &xfds)) + ev.lNetworkEvents |= FD_OOB; + + happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events, + ev.lNetworkEvents); + } + else + { + /* Not a socket. */ + int sought = pfd[i].events; + happened = windows_compute_revents (h, &sought); + nhandles++; + } + + if ((pfd[i].revents |= happened) != 0) + rc++; + } + + if (!rc && timeout == INFTIM) + { + SleepEx (1, TRUE); + goto restart; + } + + return rc; +} + +#endif //(defined _WIN32 && ! defined __CYGWIN__) (poll function) + +#if !defined(HAVE_SIGEMPTYSET) || !defined(HAVE_SIGISMEMBER) || !defined(HAVE_SIGPROCMASK) || !defined(HAVE_SIGACTION) +/* POSIX compatible signal blocking. + Copyright (C) 2006-2018 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Specification. */ +#include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/signal.h" +#endif + +#include +#include +#include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/stdlib.h" +#endif + +#if HAVE_MSVC_INVALID_PARAMETER_HANDLER +# include "msvc-inval.h" +#endif + +/* We assume that a platform without POSIX signal blocking functions + also does not have the POSIX sigaction() function, only the + signal() function. We also assume signal() has SysV semantics, + where any handler is uninstalled prior to being invoked. This is + true for native Windows platforms. */ + +/* We use raw signal(), but also provide a wrapper rpl_signal() so + that applications can query or change a blocked signal. */ +#undef signal + +/* Provide invalid signal numbers as fallbacks if the uncatchable + signals are not defined. */ +#ifndef SIGKILL +# define SIGKILL (-1) +#endif +#ifndef SIGSTOP +# define SIGSTOP (-1) +#endif + +/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias + for the signal SIGABRT. Only one signal handler is stored for both + SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */ +#if defined _WIN32 && ! defined __CYGWIN__ +# undef SIGABRT_COMPAT +# define SIGABRT_COMPAT 6 +#endif +#ifdef SIGABRT_COMPAT +# define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT) +#else +# define SIGABRT_COMPAT_MASK 0 +#endif + +typedef void (*handler_t) (int); + +#if HAVE_MSVC_INVALID_PARAMETER_HANDLER +static handler_t +signal_nothrow (int sig, handler_t handler) +{ + handler_t result; + + TRY_MSVC_INVAL + { + result = signal (sig, handler); + } + CATCH_MSVC_INVAL + { + result = SIG_ERR; + errno = EINVAL; + } + DONE_MSVC_INVAL; + + return result; +} +# define signal signal_nothrow +#endif + +/* Handling of gnulib defined signals. */ + +#if GNULIB_defined_SIGPIPE +static handler_t SIGPIPE_handler = SIG_DFL; +#endif + +#if GNULIB_defined_SIGPIPE +static handler_t +ext_signal (int sig, handler_t handler) +{ + switch (sig) + { + case SIGPIPE: + { + handler_t old_handler = SIGPIPE_handler; + SIGPIPE_handler = handler; + return old_handler; + } + default: /* System defined signal */ + return signal (sig, handler); + } +} +# undef signal +# define signal ext_signal +#endif + +int +sigismember (const sigset_t *set, int sig) +{ + if (sig >= 0 && sig < NSIG) + { +#ifdef SIGABRT_COMPAT + if (sig == SIGABRT_COMPAT) + sig = SIGABRT; +#endif + + return (*set >> sig) & 1; + } + else + return 0; +} + +int +sigemptyset (sigset_t *set) +{ + *set = 0; + return 0; +} + +int +sigaddset (sigset_t *set, int sig) +{ + if (sig >= 0 && sig < NSIG) + { +#ifdef SIGABRT_COMPAT + if (sig == SIGABRT_COMPAT) + sig = SIGABRT; +#endif + + *set |= 1U << sig; + return 0; + } + else + { + errno = EINVAL; + return -1; + } +} + +int +sigdelset (sigset_t *set, int sig) +{ + if (sig >= 0 && sig < NSIG) + { +#ifdef SIGABRT_COMPAT + if (sig == SIGABRT_COMPAT) + sig = SIGABRT; +#endif + + *set &= ~(1U << sig); + return 0; + } + else + { + errno = EINVAL; + return -1; + } +} + + +int +sigfillset (sigset_t *set) +{ + *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK; + return 0; +} + +/* Set of currently blocked signals. */ +static volatile sigset_t blocked_set /* = 0 */; + +/* Set of currently blocked and pending signals. */ +static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */; + +/* Signal handler that is installed for blocked signals. */ +static void +blocked_handler (int sig) +{ + /* Reinstall the handler, in case the signal occurs multiple times + while blocked. There is an inherent race where an asynchronous + signal in between when the kernel uninstalled the handler and + when we reinstall it will trigger the default handler; oh + well. */ + signal (sig, blocked_handler); + if (sig >= 0 && sig < NSIG) + pending_array[sig] = 1; +} + +int +sigpending (sigset_t *set) +{ + sigset_t pending = 0; + int sig; + + for (sig = 0; sig < NSIG; sig++) + if (pending_array[sig]) + pending |= 1U << sig; + *set = pending; + return 0; +} + +/* The previous signal handlers. + Only the array elements corresponding to blocked signals are relevant. */ +static volatile handler_t old_handlers[NSIG]; + +int +sigprocmask (int operation, const sigset_t *set, sigset_t *old_set) +{ + if (old_set != NULL) + *old_set = blocked_set; + + if (set != NULL) + { + sigset_t new_blocked_set; + sigset_t to_unblock; + sigset_t to_block; + + switch (operation) + { + case SIG_BLOCK: + new_blocked_set = blocked_set | *set; + break; + case SIG_SETMASK: + new_blocked_set = *set; + break; + case SIG_UNBLOCK: + new_blocked_set = blocked_set & ~*set; + break; + default: + errno = EINVAL; + return -1; + } + to_unblock = blocked_set & ~new_blocked_set; + to_block = new_blocked_set & ~blocked_set; + + if (to_block != 0) + { + int sig; + + for (sig = 0; sig < NSIG; sig++) + if ((to_block >> sig) & 1) + { + pending_array[sig] = 0; + if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR) + blocked_set |= 1U << sig; + } + } + + if (to_unblock != 0) + { + sig_atomic_t received[NSIG]; + int sig; + + for (sig = 0; sig < NSIG; sig++) + if ((to_unblock >> sig) & 1) + { +// if (signal (sig, old_handlers[sig]) != blocked_handler) +// /* The application changed a signal handler while the signal +// was blocked, bypassing our rpl_signal replacement. +// We don't support this. */ +// abort (); + received[sig] = pending_array[sig]; + blocked_set &= ~(1U << sig); + pending_array[sig] = 0; + } + else + received[sig] = 0; + + for (sig = 0; sig < NSIG; sig++) + if (received[sig]) + raise (sig); + } + } + return 0; +} + +/* Install the handler FUNC for signal SIG, and return the previous + handler. */ +handler_t +rpl_signal (int sig, handler_t handler) +{ + /* We must provide a wrapper, so that a user can query what handler + they installed even if that signal is currently blocked. */ + if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP + && handler != SIG_ERR) + { +#ifdef SIGABRT_COMPAT + if (sig == SIGABRT_COMPAT) + sig = SIGABRT; +#endif + + if (blocked_set & (1U << sig)) + { + /* POSIX states that sigprocmask and signal are both + async-signal-safe. This is not true of our + implementation - there is a slight data race where an + asynchronous interrupt on signal A can occur after we + install blocked_handler but before we have updated + old_handlers for signal B, such that handler A can see + stale information if it calls signal(B). Oh well - + signal handlers really shouldn't try to manipulate the + installed handlers of unrelated signals. */ + handler_t result = old_handlers[sig]; + old_handlers[sig] = handler; + return result; + } + else + return signal (sig, handler); + } + else + { + errno = EINVAL; + return SIG_ERR; + } +} + +/* This implementation of sigaction is tailored to native Windows behavior: + signal() has SysV semantics (ie. the handler is uninstalled before + it is invoked). This is an inherent data race if an asynchronous + signal is sent twice in a row before we can reinstall our handler, + but there's nothing we can do about it. Meanwhile, sigprocmask() + is not present, and while we can use the gnulib replacement to + provide critical sections, it too suffers from potential data races + in the face of an ill-timed asynchronous signal. And we compound + the situation by reading static storage in a signal handler, which + POSIX warns is not generically async-signal-safe. Oh well. + + Additionally: + - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD + is not defined. + - We don't implement SA_ONSTACK, because sigaltstack() is not present. + - We ignore SA_RESTART, because blocking native Windows API calls are + not interrupted anyway when an asynchronous signal occurs, and the + MSVCRT runtime never sets errno to EINTR. + - We don't implement SA_SIGINFO because it is impossible to do so + portably. + + POSIX states that an application should not mix signal() and + sigaction(). We support the use of signal() within the gnulib + sigprocmask() substitute, but all other application code linked + with this module should stick with only sigaction(). */ + +/* Set of current actions. If sa_handler for an entry is NULL, then + that signal is not currently handled by the sigaction handler. */ +static struct sigaction volatile action_array[NSIG] /* = 0 */; + +/* Signal handler that is installed for signals. */ +static void +sigaction_handler (int sig) +{ + handler_t handler; + sigset_t mask; + sigset_t oldmask; + int saved_errno = errno; + if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler) + { + /* Unexpected situation; be careful to avoid recursive abort. */ + if (sig == SIGABRT) + signal (SIGABRT, SIG_DFL); + abort (); + } + + /* Reinstall the signal handler when required; otherwise update the + bookkeeping so that the user's handler may call sigaction and get + accurate results. We know the signal isn't currently blocked, or + we wouldn't be in its handler, therefore we know that we are not + interrupting a sigaction() call. There is a race where any + asynchronous instance of the same signal occurring before we + reinstall the handler will trigger the default handler; oh + well. */ + handler = action_array[sig].sa_handler; + if ((action_array[sig].sa_flags & SA_RESETHAND) == 0) + signal (sig, sigaction_handler); + else + action_array[sig].sa_handler = NULL; + + /* Block appropriate signals. */ + mask = action_array[sig].sa_mask; + if ((action_array[sig].sa_flags & SA_NODEFER) == 0) + sigaddset (&mask, sig); + sigprocmask (SIG_BLOCK, &mask, &oldmask); + + /* Invoke the user's handler, then restore prior mask. */ + errno = saved_errno; + handler (sig); + saved_errno = errno; + sigprocmask (SIG_SETMASK, &oldmask, NULL); + errno = saved_errno; +} + +/* Change and/or query the action that will be taken on delivery of + signal SIG. If not NULL, ACT describes the new behavior. If not + NULL, OACT is set to the prior behavior. Return 0 on success, or + set errno and return -1 on failure. */ +int +sigaction (int sig, const struct sigaction *restrict act, + struct sigaction *restrict oact) +{ + sigset_t mask; + sigset_t oldmask; + int saved_errno; + + if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP + || (act && act->sa_handler == SIG_ERR)) + { + errno = EINVAL; + return -1; + } + +#ifdef SIGABRT_COMPAT + if (sig == SIGABRT_COMPAT) + sig = SIGABRT; +#endif + + /* POSIX requires sigaction() to be async-signal-safe. In other + words, if an asynchronous signal can occur while we are anywhere + inside this function, the user's handler could then call + sigaction() recursively and expect consistent results. We meet + this rule by using sigprocmask to block all signals before + modifying any data structure that could be read from a signal + handler; this works since we know that the gnulib sigprocmask + replacement does not try to use sigaction() from its handler. */ + if (!act && !oact) + return 0; + sigfillset (&mask); + sigprocmask (SIG_BLOCK, &mask, &oldmask); + if (oact) + { + if (action_array[sig].sa_handler) + *oact = action_array[sig]; + else + { + /* Safe to change the handler at will here, since all + signals are currently blocked. */ + oact->sa_handler = signal (sig, SIG_DFL); + if (oact->sa_handler == SIG_ERR) + goto failure; + signal (sig, oact->sa_handler); + oact->sa_flags = SA_RESETHAND | SA_NODEFER; + sigemptyset (&oact->sa_mask); + } + } + + if (act) + { + /* Safe to install the handler before updating action_array, + since all signals are currently blocked. */ + if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN) + { + if (signal (sig, act->sa_handler) == SIG_ERR) + goto failure; + action_array[sig].sa_handler = NULL; + } + else + { + if (signal (sig, sigaction_handler) == SIG_ERR) + goto failure; + action_array[sig] = *act; + } + } + sigprocmask (SIG_SETMASK, &oldmask, NULL); + return 0; + + failure: + saved_errno = errno; + sigprocmask (SIG_SETMASK, &oldmask, NULL); + errno = saved_errno; + return -1; +} + +#endif + +#if !defined(HAVE_UNAME) +/* uname replacement. + Copyright (C) 2009-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Specification. */ +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/sys_utsname.h" +#else +#include +#endif + + +/* This file provides an implementation only for the native Windows API. */ + +#include +#include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/stdlib.h" +#endif +#include +#include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/unistd.h" +#endif +#include + +/* Mingw headers don't have all the platform codes. */ +#ifndef VER_PLATFORM_WIN32_CE +# define VER_PLATFORM_WIN32_CE 3 +#endif + +/* Some headers don't have all the processor architecture codes. */ +#ifndef PROCESSOR_ARCHITECTURE_AMD64 +# define PROCESSOR_ARCHITECTURE_AMD64 9 +#endif +#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 +# define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 +#endif + +/* Mingw headers don't have the latest processor codes. */ +#ifndef PROCESSOR_AMD_X8664 +# define PROCESSOR_AMD_X8664 8664 +#endif + +int +uname (struct utsname *buf) +{ + OSVERSIONINFO version; + OSVERSIONINFOEX versionex; + BOOL have_versionex; /* indicates whether versionex is filled */ + const char *super_version; + + /* Preparation: Fill version and, if possible, also versionex. + But try to call GetVersionEx only once in the common case. */ + versionex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX); + have_versionex = GetVersionEx ((OSVERSIONINFO *) &versionex); + if (have_versionex) + { + /* We know that OSVERSIONINFO is a subset of OSVERSIONINFOEX. */ + memcpy (&version, &versionex, sizeof (OSVERSIONINFO)); + } + else + { + version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + if (!GetVersionEx (&version)) + abort (); + } + + /* Fill in nodename. */ + if (gethostname (buf->nodename, sizeof (buf->nodename)) < 0) + strcpy (buf->nodename, "localhost"); + + /* Determine major-major Windows version. */ + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + /* Windows NT or newer. */ + super_version = "NT"; + } + else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE) + { + /* Windows CE or Embedded CE. */ + super_version = "CE"; + } + else if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) + { + /* Windows 95/98/ME. */ + switch (version.dwMinorVersion) + { + case 0: + super_version = "95"; + break; + case 10: + super_version = "98"; + break; + case 90: + super_version = "ME"; + break; + default: + super_version = ""; + break; + } + } + else + super_version = ""; + + /* Fill in sysname. */ +#ifdef __MINGW32__ + /* Returns a string compatible with the MSYS uname.exe program, + so that no further changes are needed to GNU config.guess. + For example, + $ ./uname.exe -s => MINGW32_NT-5.1 + */ + sprintf (buf->sysname, "MINGW32_%s-%u.%u", super_version, + (unsigned int) version.dwMajorVersion, + (unsigned int) version.dwMinorVersion); +#else + sprintf (buf->sysname, "Windows%s", super_version); +#endif + + /* Fill in release, version. */ + /* The MSYS uname.exe programs uses strings from a modified Cygwin runtime: + $ ./uname.exe -r => 1.0.11(0.46/3/2) + $ ./uname.exe -v => 2008-08-25 23:40 + There is no point in imitating this behaviour. */ + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + /* Windows NT or newer. */ + struct windows_version + { + int major; + int minor; + unsigned int server_offset; + const char *name; + }; + + /* Storing the workstation and server version names in a single + stream does not waste memory when they are the same. These + macros abstract the representation. VERSION1 is used if + version.wProductType does not matter, VERSION2 if it does. */ + #define VERSION1(major, minor, name) \ + { major, minor, 0, name } + #define VERSION2(major, minor, workstation, server) \ + { major, minor, sizeof workstation, workstation "\0" server } + static const struct windows_version versions[] = + { + VERSION2 (3, -1, "Windows NT Workstation", "Windows NT Server"), + VERSION2 (4, -1, "Windows NT Workstation", "Windows NT Server"), + VERSION1 (5, 0, "Windows 2000"), + VERSION1 (5, 1, "Windows XP"), + VERSION1 (5, 2, "Windows Server 2003"), + VERSION2 (6, 0, "Windows Vista", "Windows Server 2008"), + VERSION2 (6, 1, "Windows 7", "Windows Server 2008 R2"), + VERSION2 (-1, -1, "Windows", "Windows Server") + }; + const char *base; + const struct windows_version *v = versions; + + /* Find a version that matches ours. The last element is a + wildcard that always ends the loop. */ + while ((v->major != version.dwMajorVersion && v->major != -1) + || (v->minor != version.dwMinorVersion && v->minor != -1)) + v++; + + if (have_versionex && versionex.wProductType != VER_NT_WORKSTATION) + base = v->name + v->server_offset; + else + base = v->name; + if (v->major == -1 || v->minor == -1) + sprintf (buf->release, "%s %u.%u", + base, + (unsigned int) version.dwMajorVersion, + (unsigned int) version.dwMinorVersion); + else + strcpy (buf->release, base); + } + else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE) + { + /* Windows CE or Embedded CE. */ + sprintf (buf->release, "Windows CE %u.%u", + (unsigned int) version.dwMajorVersion, + (unsigned int) version.dwMinorVersion); + } + else + { + /* Windows 95/98/ME. */ + sprintf (buf->release, "Windows %s", super_version); + } + strcpy (buf->version, version.szCSDVersion); + + /* Fill in machine. */ + { + SYSTEM_INFO info; + + GetSystemInfo (&info); + /* Check for Windows NT or CE, since the info.wProcessorLevel is + garbage on Windows 95. */ + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT + || version.dwPlatformId == VER_PLATFORM_WIN32_CE) + { + /* Windows NT or newer, or Windows CE or Embedded CE. */ + switch (info.wProcessorArchitecture) + { + case PROCESSOR_ARCHITECTURE_AMD64: + strcpy (buf->machine, "x86_64"); + break; + case PROCESSOR_ARCHITECTURE_IA64: + strcpy (buf->machine, "ia64"); + break; + case PROCESSOR_ARCHITECTURE_INTEL: + strcpy (buf->machine, "i386"); + if (info.wProcessorLevel >= 3) + buf->machine[1] = + '0' + (info.wProcessorLevel <= 6 ? info.wProcessorLevel : 6); + break; + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: + strcpy (buf->machine, "i686"); + break; + case PROCESSOR_ARCHITECTURE_MIPS: + strcpy (buf->machine, "mips"); + break; + case PROCESSOR_ARCHITECTURE_ALPHA: + case PROCESSOR_ARCHITECTURE_ALPHA64: + strcpy (buf->machine, "alpha"); + break; + case PROCESSOR_ARCHITECTURE_PPC: + strcpy (buf->machine, "powerpc"); + break; + case PROCESSOR_ARCHITECTURE_SHX: + strcpy (buf->machine, "sh"); + break; + case PROCESSOR_ARCHITECTURE_ARM: + strcpy (buf->machine, "arm"); + break; + default: + strcpy (buf->machine, "unknown"); + break; + } + } + else + { + /* Windows 95/98/ME. */ + switch (info.dwProcessorType) + { + case PROCESSOR_AMD_X8664: + strcpy (buf->machine, "x86_64"); + break; + case PROCESSOR_INTEL_IA64: + strcpy (buf->machine, "ia64"); + break; + default: + if (info.dwProcessorType % 100 == 86) + sprintf (buf->machine, "i%u", + (unsigned int) info.dwProcessorType); + else + strcpy (buf->machine, "unknown"); + break; + } + } + } + + return 0; +} + +#endif + +#if !defined(HAVE_WARN) +void +warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); +} +#endif + +#if !defined(HAVE_WARNX) +void +warnx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); vwarnx(fmt, ap); @@ -622 +2959,618 @@ warnx(const char *fmt, ...) #endif + +#if !defined(HAVE_WAIT) +/* Specification. */ +#include "wait.h" +pid_t +wait (int *statusp) +{ + return waitpid((pid_t) -1, statusp, WUNTRACED); +} +#endif + +#if !defined(HAVE_WAITPID) +/* Wait for process state change. + Copyright (C) 2001-2003, 2005-2018 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . */ + +/* Specification. */ +#include "wait.h" + +/* Implementation for native Windows systems. */ + +#include /* for _cwait, WAIT_CHILD */ + +pid_t +waitpid (pid_t pid, int *statusp, int options) +{ + return _cwait (statusp, pid, WAIT_CHILD); +} +#endif + +#if (defined _WIN32 && ! defined __CYGWIN__) +char * +getShellLaunchPrefix() +{ + const char *sysRootPath = getenv("SYSROOTWINDOWSPATH"); + const char *msystemPrefix = getenv("MSYSTEM"); + + if (sysRootPath == NULL || msystemPrefix == NULL) { + return NULL; /*we can't find mingw shell installed on this system */ + } + else { + /* we will return something like + * C:\msys64\usr\bin\env MSYSTEM=MINGW64 /usr/bin/bash -lc + */ + return str_concat( + str_concat( + str_concat(sysRootPath, "usr\\bin\\env.exe MSYSTEM=", 0), + msystemPrefix, 0), + "/usr/bin/bash -lc", STR_ADDSPACE); + } +} + +char * getUnixPathCmd(const char *path) +{ + return str_concat( + "cygpath -u", str_concat("\"", + str_concat(path, "\"", 0), + 0), + STR_ADDSPACE); +} + +#endif + +#include +#include +#if (defined _WIN32 && ! defined __CYGWIN__) +#include "headers-mingw/stdlib.h" +#endif +#include + +size_t str_escape(char *dst, const char *src, size_t dstLen) +{ + const char complexCharMap[] = "abtnvfr"; + + size_t i; + size_t srcLen = strlen(src); + size_t dstIdx = 0; + + // If caller wants to determine required length (supplying NULL for dst) + // then we set dstLen to SIZE_MAX and pretend the buffer is the largest + // possible, but we never write to it. Caller can also provide dstLen + // as 0 if no limit is wanted. + if (dst == NULL || dstLen == 0) dstLen = SIZE_MAX; + + for (i = 0; i < srcLen && dstIdx < dstLen; i++) + { + size_t complexIdx = 0; + + switch (src[i]) + { + case '\'': + case '\"': + case '\\': + if (dst && dstIdx <= dstLen - 2) + { + dst[dstIdx++] = '\\'; + dst[dstIdx++] = src[i]; + } + else dstIdx += 2; + break; + + case '\r': complexIdx++; + case '\f': complexIdx++; + case '\v': complexIdx++; + case '\n': complexIdx++; + case '\t': complexIdx++; + case '\b': complexIdx++; + case '\a': + if (dst && dstIdx <= dstLen - 2) + { + dst[dstIdx++] = '\\'; + dst[dstIdx++] = complexCharMap[complexIdx]; + } + else dstIdx += 2; + break; + + default: + if (isprint(src[i])) + { + // simply copy the character + if (dst) + dst[dstIdx++] = src[i]; + else + dstIdx++; + } + else + { + // produce octal escape sequence + if (dst && dstIdx <= dstLen - 4) + { + dst[dstIdx++] = '\\'; + dst[dstIdx++] = ((src[i] & 0300) >> 6) + '0'; + dst[dstIdx++] = ((src[i] & 0070) >> 3) + '0'; + dst[dstIdx++] = ((src[i] & 0007) >> 0) + '0'; + } + else + { + dstIdx += 4; + } + } + } + } + + if (dst && dstIdx <= dstLen) + dst[dstIdx] = '\0'; + + return dstIdx; +} + +size_t str_escape_dblquote(char *dst, const char *src, size_t dstLen) +{ + + size_t i; + size_t srcLen = strlen(src); + size_t dstIdx = 0; + + // If caller wants to determine required length (supplying NULL for dst) + // then we set dstLen to SIZE_MAX and pretend the buffer is the largest + // possible, but we never write to it. Caller can also provide dstLen + // as 0 if no limit is wanted. + if (dst == NULL || dstLen == 0) dstLen = SIZE_MAX; + + for (i = 0; i < srcLen && dstIdx < dstLen; i++) + { + size_t complexIdx = 0; + + switch (src[i]) + { + case '\"': + if (dst && dstIdx <= dstLen - 2) + { + dst[dstIdx++] = '\\'; + dst[dstIdx++] = src[i]; + } + else dstIdx += 2; + break; + case '\\': + if (dst && dstIdx <= dstLen - 2) + { + dst[dstIdx++] = '\\'; + dst[dstIdx++] = src[i]; + } + else dstIdx += 2; + break; + default: +// if (isprint(src[i]) || src[i] == '\n' || src[i] == '\r') +// { + // simply copy the character + if (dst) + dst[dstIdx++] = src[i]; + else + dstIdx++; +// } +// else { +// dst[dstIdx++] = ' '; +// } + } + } + + if (dst && dstIdx <= dstLen) + dst[dstIdx] = '\0'; + + return dstIdx; +} + +#if (defined _WIN32 && ! defined __CYGWIN__) +#include +//#include +//#include + +#define bool _Bool +#define true 1 +#define false 0 + +#define null ((void*)0) + +typedef struct system_np_s { + HANDLE child_stdout_read; + HANDLE child_stderr_read; + HANDLE reader; + PROCESS_INFORMATION pi; + const char* command; + char* stdout_data; + int stdout_data_size; + char* stderr_data; + int stderr_data_size; + int* exit_code; + int timeout; // timeout in milliseconds or -1 for INIFINTE +} system_np_t; + +static int peek_pipe(HANDLE pipe, char* data, int size) { + char buffer[4 * 1024]; + DWORD read = 0; + DWORD available = 0; + bool b = PeekNamedPipe(pipe, null, sizeof(buffer), null, &available, null); + if (!b) { + return -1; + } else if (available > 0) { + int bytes = min(sizeof(buffer), available); + b = ReadFile(pipe, buffer, bytes, &read, null); + if (!b) { + return -1; + } + if (data != null && size > 0) { + int n = min(size - 1, (int)read); + memcpy(data, buffer, n); + data[n + 1] = 0; // always zero terminated + return n; + } + } + return 0; +} + +static DWORD WINAPI read_from_all_pipes_fully(void* p) { + system_np_t* system = (system_np_t*)p; + unsigned long long milliseconds = GetTickCount64(); // since boot time + char* out = system->stdout_data != null && system->stdout_data_size > 0 ? system->stdout_data : null; + char* err = system->stderr_data != null && system->stderr_data_size > 0 ? system->stderr_data : null; + int out_bytes = system->stdout_data != null && system->stdout_data_size > 0 ? system->stdout_data_size - 1 : 0; + int err_bytes = system->stderr_data != null && system->stderr_data_size > 0 ? system->stderr_data_size - 1 : 0; + for (;;) { + int read_stdout = peek_pipe(system->child_stdout_read, out, out_bytes); + if (read_stdout > 0 && out != null) { out += read_stdout; out_bytes -= read_stdout; } + int read_stderr = peek_pipe(system->child_stderr_read, err, err_bytes); + if (read_stderr > 0 && err != null) { err += read_stderr; err_bytes -= read_stderr; } + if (read_stdout < 0 && read_stderr < 0) { break; } // both pipes are closed + unsigned long long time_spent_in_milliseconds = GetTickCount64() - milliseconds; + if (system->timeout > 0 && time_spent_in_milliseconds > system->timeout) { break; } + if (read_stdout == 0 && read_stderr == 0) { // nothing has been read from both pipes + HANDLE handles[2] = {system->child_stdout_read, system->child_stderr_read}; + WaitForMultipleObjects(2, handles, false, 1); // wait for at least 1 millisecond (more likely 16) + } + } + if (out != null) { *out = 0; } + if (err != null) { *err = 0; } + return 0; +} + +static int create_child_process(system_np_t* system) { + SECURITY_ATTRIBUTES sa = {0}; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = true; + sa.lpSecurityDescriptor = null; + HANDLE child_stdout_write = INVALID_HANDLE_VALUE; + HANDLE child_stderr_write = INVALID_HANDLE_VALUE; + if (!CreatePipe(&system->child_stderr_read, &child_stderr_write, &sa, 0) ) { + return GetLastError(); + } + if (!SetHandleInformation(system->child_stderr_read, HANDLE_FLAG_INHERIT, 0) ){ + return GetLastError(); + } + if (!CreatePipe(&system->child_stdout_read, &child_stdout_write, &sa, 0) ) { + return GetLastError(); + } + if (!SetHandleInformation(system->child_stdout_read, HANDLE_FLAG_INHERIT, 0) ){ + return GetLastError(); + } + // Set the text I want to run + STARTUPINFO siStartInfo = {0}; + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = child_stderr_write; + siStartInfo.hStdOutput = child_stdout_write; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.wShowWindow = SW_HIDE; + bool b = CreateProcessA(null, + (char*)system->command, + null, // process security attributes + null, // primary thread security attributes + true, // handles are inherited + CREATE_NO_WINDOW, // creation flags + null, // use parent's environment + null, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &system->pi); // receives PROCESS_INFORMATION + int err = GetLastError(); + CloseHandle(child_stderr_write); + CloseHandle(child_stdout_write); + if (!b) { + CloseHandle(system->child_stdout_read); system->child_stdout_read = INVALID_HANDLE_VALUE; + CloseHandle(system->child_stderr_read); system->child_stderr_read = INVALID_HANDLE_VALUE; + } + return b ? 0 : err; +} + +int system_np(const char* command, int timeout_milliseconds, + char* stdout_data, int stdout_data_size, + char* stderr_data, int stderr_data_size, int* exit_code) { + system_np_t system = {0}; + if (exit_code != null) { *exit_code = 0; } + if (stdout_data != null && stdout_data_size > 0) { stdout_data[0] = 0; } + if (stderr_data != null && stderr_data_size > 0) { stderr_data[0] = 0; } + system.timeout = timeout_milliseconds > 0 ? timeout_milliseconds : -1; + system.command = command; + system.stdout_data = stdout_data; + system.stderr_data = stderr_data; + system.stdout_data_size = stdout_data_size; + system.stderr_data_size = stderr_data_size; + int r = create_child_process(&system); + if (r == 0) { + system.reader = CreateThread(null, 0, read_from_all_pipes_fully, &system, 0, null); + if (system.reader == null) { // in theory should rarely happen only when system super low on resources + r = GetLastError(); + TerminateProcess(system.pi.hProcess, ECANCELED); + } else { + bool thread_done = WaitForSingleObject(system.pi.hThread, timeout_milliseconds) == 0; + bool process_done = WaitForSingleObject(system.pi.hProcess, timeout_milliseconds) == 0; + if (!thread_done || !process_done) { + TerminateProcess(system.pi.hProcess, ETIME); + } + if (exit_code != null) { + GetExitCodeProcess(system.pi.hProcess, (DWORD*)exit_code); + } + CloseHandle(system.pi.hThread); + CloseHandle(system.pi.hProcess); + CloseHandle(system.child_stdout_read); system.child_stdout_read = INVALID_HANDLE_VALUE; + CloseHandle(system.child_stderr_read); system.child_stderr_read = INVALID_HANDLE_VALUE; + WaitForSingleObject(system.reader, INFINITE); // join thread + CloseHandle(system.reader); + } + } + if (stdout_data != null && stdout_data_size > 0) { stdout_data[stdout_data_size - 1] = 0; } + if (stderr_data != null && stderr_data_size > 0) { stderr_data[stderr_data_size - 1] = 0; } + return r; +} +#endif + +#ifndef NO_REGEX +#if (!defined(HAVE_REGCOMP) || !defined(HAVE_REGERROR) || !defined(HAVE_REGEXEC) || !defined(HAVE_REGFREE)) + +#if (defined _WIN32 && ! defined __CYGWIN__) +#include +#endif +/* Return the codeset of the current locale, if this is easily deducible. + Otherwise, return "". */ +static char * +ctype_codeset(void) { + static char buf[2 + 10 + 1]; + char const *locale = setlocale(LC_CTYPE, NULL); + char *codeset = buf; + size_t codesetlen; + codeset[0] = '\0'; + + if (locale && locale[0]) { + /* If the locale name contains an encoding after the dot, return it. */ + char *dot = strchr(locale, '.'); + + if (dot) { + /* Look for the possible @... trailer and remove it, if any. */ + char *codeset_start = dot + 1; + char const *modifier = strchr(codeset_start, '@'); + + if (!modifier) + codeset = codeset_start; + else { + codesetlen = modifier - codeset_start; + if (codesetlen < sizeof buf) { + codeset = memcpy(buf, codeset_start, codesetlen); + codeset[codesetlen] = '\0'; + } + } + } + } + + /* If setlocale is successful, it returns the number of the + codepage, as a string. Otherwise, fall back on Windows API + GetACP, which returns the locale's codepage as a number (although + this doesn't change according to what the 'setlocale' call specified). + Either way, prepend "CP" to make it a valid codeset name. */ + codesetlen = strlen(codeset); + if (0 < codesetlen && codesetlen < sizeof buf - 2) + memmove(buf + 2, codeset, codesetlen + 1); + else + sprintf(buf + 2, "%u", GetACP()); + codeset = memcpy(buf, "CP", 2); + return codeset; +} + +/* Provide nl_langinfo from scratch, either for native MS-Windows, or + for old Unix platforms without locales, such as Linux libc5 or + BeOS. */ + +# include + +char * +nl_langinfo(nl_item item) { + static char nlbuf[100]; + struct tm tmm = {0}; + + switch (item) { + /* nl_langinfo items of the LC_CTYPE category */ + case CODESET: { + char *codeset = ctype_codeset(); + if (*codeset) + return codeset; + } + return (char *) "ISO-8859-1"; + /* nl_langinfo items of the LC_NUMERIC category */ + case RADIXCHAR: + return localeconv()->decimal_point; + case THOUSEP: + return localeconv()->thousands_sep; + /* nl_langinfo items of the LC_TIME category. + TODO: Really use the locale. */ + case D_T_FMT: + case ERA_D_T_FMT: + return (char *) "%a %b %e %H:%M:%S %Y"; + case D_FMT: + case ERA_D_FMT: + return (char *) "%m/%d/%y"; + case T_FMT: + case ERA_T_FMT: + return (char *) "%H:%M:%S"; + case T_FMT_AMPM: + return (char *) "%I:%M:%S %p"; + case AM_STR: + if (!strftime(nlbuf, sizeof nlbuf, "%p", &tmm)) + return (char *) "AM"; + return nlbuf; + case PM_STR: + tmm.tm_hour = 12; + if (!strftime(nlbuf, sizeof nlbuf, "%p", &tmm)) + return (char *) "PM"; + return nlbuf; + case DAY_1: + case DAY_2: + case DAY_3: + case DAY_4: + case DAY_5: + case DAY_6: + case DAY_7: { + static char const days[][sizeof "Wednesday"] = { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday" + }; + tmm.tm_wday = item - DAY_1; + if (!strftime(nlbuf, sizeof nlbuf, "%A", &tmm)) + return (char *) days[item - DAY_1]; + return nlbuf; + } + case ABDAY_1: + case ABDAY_2: + case ABDAY_3: + case ABDAY_4: + case ABDAY_5: + case ABDAY_6: + case ABDAY_7: { + static char const abdays[][sizeof "Sun"] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + tmm.tm_wday = item - ABDAY_1; + if (!strftime(nlbuf, sizeof nlbuf, "%a", &tmm)) + return (char *) abdays[item - ABDAY_1]; + return nlbuf; + } + { + static char const months[][sizeof "September"] = { + "January", "February", "March", "April", "May", "June", "July", + "September", "October", "November", "December" + }; + case MON_1: + case MON_2: + case MON_3: + case MON_4: + case MON_5: + case MON_6: + case MON_7: + case MON_8: + case MON_9: + case MON_10: + case MON_11: + case MON_12: + tmm.tm_mon = item - MON_1; + if (!strftime(nlbuf, sizeof nlbuf, "%B", &tmm)) + return (char *) months[item - MON_1]; + return nlbuf; + case ALTMON_1: + case ALTMON_2: + case ALTMON_3: + case ALTMON_4: + case ALTMON_5: + case ALTMON_6: + case ALTMON_7: + case ALTMON_8: + case ALTMON_9: + case ALTMON_10: + case ALTMON_11: + case ALTMON_12: + tmm.tm_mon = item - ALTMON_1; + /* The platforms without nl_langinfo() don't support strftime with %OB. + We don't even need to try. */ + if (!strftime(nlbuf, sizeof nlbuf, "%B", &tmm)) + return (char *) months[item - ALTMON_1]; + return nlbuf; + } + case ABMON_1: + case ABMON_2: + case ABMON_3: + case ABMON_4: + case ABMON_5: + case ABMON_6: + case ABMON_7: + case ABMON_8: + case ABMON_9: + case ABMON_10: + case ABMON_11: + case ABMON_12: { + static char const abmonths[][sizeof "Jan"] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", + "Sep", "Oct", "Nov", "Dec" + }; + tmm.tm_mon = item - ABMON_1; + if (!strftime(nlbuf, sizeof nlbuf, "%b", &tmm)) + return (char *) abmonths[item - ABMON_1]; + return nlbuf; + } + case ERA: + return (char *) ""; + case ALT_DIGITS: + return (char *) "\0\0\0\0\0\0\0\0\0\0"; + /* nl_langinfo items of the LC_MONETARY category. */ + case CRNCYSTR: + return localeconv()->currency_symbol; +# ifdef INT_CURR_SYMBOL + case INT_CURR_SYMBOL: + return localeconv () ->int_curr_symbol; + case MON_DECIMAL_POINT: + return localeconv () ->mon_decimal_point; + case MON_THOUSANDS_SEP: + return localeconv () ->mon_thousands_sep; + case MON_GROUPING: + return localeconv () ->mon_grouping; + case POSITIVE_SIGN: + return localeconv () ->positive_sign; + case NEGATIVE_SIGN: + return localeconv () ->negative_sign; + case FRAC_DIGITS: + return & localeconv () ->frac_digits; + case INT_FRAC_DIGITS: + return & localeconv () ->int_frac_digits; + case P_CS_PRECEDES: + return & localeconv () ->p_cs_precedes; + case N_CS_PRECEDES: + return & localeconv () ->n_cs_precedes; + case P_SEP_BY_SPACE: + return & localeconv () ->p_sep_by_space; + case N_SEP_BY_SPACE: + return & localeconv () ->n_sep_by_space; + case P_SIGN_POSN: + return & localeconv () ->p_sign_posn; + case N_SIGN_POSN: + return & localeconv () ->n_sign_posn; +# endif + /* nl_langinfo items of the LC_MESSAGES category + TODO: Really use the locale. */ + case YESEXPR: + return (char *) "^[yY]"; + case NOEXPR: + return (char *) "^[nN]"; + default: + return (char *) ""; + } +} + +#endif +#endif \ No newline at end of file diff --git a/var.c b/var.c index 6f8d4c3..5e4e9d2 100644 --- a/var.c +++ b/var.c @@ -73,3 +73,3 @@ static char rcsid[] = "$NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $"; #else -#include + #include #ifndef lint @@ -126,6 +126,20 @@ __RCSID("$NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $"); #include + +#if (defined _WIN32 && !defined __CYGWIN__) +#include "headers-mingw/sys_stat.h" +#endif #ifndef NO_REGEX + #include + +# if (defined _WIN32 && !defined __CYGWIN__) + #include "headers-mingw/regex.h" +#include "headers-mingw/regex_internal.h" +# else + #include + +# endif #endif + #include @@ -153,3 +167,3 @@ char **savedEnv = NULL; */ -char var_Error[] = ""; +char var_Error[] = ""; @@ -160,3 +174,3 @@ char var_Error[] = ""; */ -static char varNoError[] = ""; +static char varNoError[] = ""; @@ -188,18 +202,18 @@ static Boolean save_dollars = FALSE; */ -GNode *VAR_INTERNAL; /* variables from make itself */ -GNode *VAR_GLOBAL; /* variables from the makefile */ -GNode *VAR_CMD; /* variables defined on the command-line */ +GNode *VAR_INTERNAL; /* variables from make itself */ +GNode *VAR_GLOBAL; /* variables from the makefile */ +GNode *VAR_CMD; /* variables defined on the command-line */ -#define FIND_CMD 0x1 /* look in VAR_CMD when searching */ -#define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ -#define FIND_ENV 0x4 /* look in the environment also */ +#define FIND_CMD 0x1 /* look in VAR_CMD when searching */ +#define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ +#define FIND_ENV 0x4 /* look in the environment also */ typedef struct Var { - char *name; /* the variable's name */ - Buffer val; /* its value */ - int flags; /* miscellaneous status flags */ -#define VAR_IN_USE 1 /* Variable's value currently being used. + char *name; /* the variable's name */ + Buffer val; /* its value */ + int flags; /* miscellaneous status flags */ +#define VAR_IN_USE 1 /* Variable's value currently being used. * Used to avoid recursion */ -#define VAR_FROM_ENV 2 /* Variable comes from the environment */ -#define VAR_JUNK 4 /* Variable is a junk variable that +#define VAR_FROM_ENV 2 /* Variable comes from the environment */ +#define VAR_JUNK 4 /* Variable is a junk variable that * should be destroyed when done with @@ -207,11 +221,11 @@ typedef struct Var { * modified variables */ -#define VAR_KEEP 8 /* Variable is VAR_JUNK, but we found +#define VAR_KEEP 8 /* Variable is VAR_JUNK, but we found * a use for it in some modifier and * the value is therefore valid */ -#define VAR_EXPORTED 16 /* Variable is exported */ -#define VAR_REEXPORT 32 /* Indicate if var needs re-export. +#define VAR_EXPORTED 16 /* Variable is exported */ +#define VAR_REEXPORT 32 /* Indicate if var needs re-export. * This would be true if it contains $'s */ -#define VAR_FROM_CMD 64 /* Variable came from command line */ -} Var; +#define VAR_FROM_CMD 64 /* Variable came from command line */ +} Var; @@ -220,5 +234,5 @@ typedef struct Var { */ -#define VAR_EXPORTED_NONE 0 -#define VAR_EXPORTED_YES 1 -#define VAR_EXPORTED_ALL 2 +#define VAR_EXPORTED_NONE 0 +#define VAR_EXPORTED_YES 1 +#define VAR_EXPORTED_ALL 2 static int var_exportedVars = VAR_EXPORTED_NONE; @@ -228,3 +242,3 @@ static int var_exportedVars = VAR_EXPORTED_NONE; */ -#define VAR_EXPORT_PARENT 1 +#define VAR_EXPORT_PARENT 1 /* @@ -232,14 +246,14 @@ static int var_exportedVars = VAR_EXPORTED_NONE; */ -#define VAR_EXPORT_LITERAL 2 +#define VAR_EXPORT_LITERAL 2 /* Var*Pattern flags */ -#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ -#define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ -#define VAR_SUB_MATCHED 0x04 /* There was a match */ -#define VAR_MATCH_START 0x08 /* Match at start of word */ -#define VAR_MATCH_END 0x10 /* Match at end of word */ -#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ +#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ +#define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ +#define VAR_SUB_MATCHED 0x04 /* There was a match */ +#define VAR_MATCH_START 0x08 /* Match at start of word */ +#define VAR_MATCH_END 0x10 /* Match at end of word */ +#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ /* Var_Set flags */ -#define VAR_NO_EXPORT 0x01 /* do not export */ +#define VAR_NO_EXPORT 0x01 /* do not export */ @@ -251,4 +265,4 @@ typedef struct { */ - Byte varSpace; /* Word separator in expansions */ - Boolean oneBigWord; /* TRUE if we will treat the variable as a + Byte varSpace; /* Word separator in expansions */ + Boolean oneBigWord; /* TRUE if we will treat the variable as a * single big word, even if it contains @@ -262,7 +276,7 @@ typedef struct { typedef struct { - const char *lhs; /* String to match */ - int leftLen; /* Length of string */ - const char *rhs; /* Replacement string (w/ &'s removed) */ - int rightLen; /* Length of replacement */ - int flags; + const char *lhs; /* String to match */ + int leftLen; /* Length of string */ + const char *rhs; /* Replacement string (w/ &'s removed) */ + int rightLen; /* Length of replacement */ + int flags; } VarPattern; @@ -271,8 +285,8 @@ typedef struct { typedef struct { - GNode *ctxt; /* variable context */ - char *tvar; /* name of temp var */ - int tvarLen; - char *str; /* string to expand */ - int strLen; - int errnum; /* errnum for not defined */ + GNode *ctxt; /* variable context */ + char *tvar; /* name of temp var */ + int tvarLen; + char *str; /* string to expand */ + int strLen; + int errnum; /* errnum for not defined */ } VarLoop_t; @@ -282,7 +296,7 @@ typedef struct { typedef struct { - regex_t re; - int nsub; - regmatch_t *matches; - char *replace; - int flags; + regex_t re; + int nsub; + regmatch_t *matches; + char *replace; + int flags; } VarREPattern; @@ -292,4 +306,4 @@ typedef struct { typedef struct { - int start; /* first word to select */ - int end; /* last word to select */ + int start; /* first word to select */ + int end; /* last word to select */ } VarSelectWords_t; @@ -297,46 +311,70 @@ typedef struct { static Var *VarFind(const char *, GNode *, int); + static void VarAdd(const char *, const char *, GNode *); + static Boolean VarHead(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + static Boolean VarTail(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + static Boolean VarSuffix(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + static Boolean VarRoot(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + static Boolean VarMatch(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + #ifdef SYSVVARSUB + static Boolean VarSYSVMatch(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + #endif + static Boolean VarNoMatch(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + #ifndef NO_REGEX + static void VarREError(int, regex_t *, const char *); + static Boolean VarRESubstitute(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + #endif + static Boolean VarSubstitute(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + static Boolean VarLoopExpand(GNode *, Var_Parse_State *, - char *, Boolean, Buffer *, void *); + char *, Boolean, Buffer *, void *); + static char *VarGetPattern(GNode *, Var_Parse_State *, - int, const char **, int, int *, int *, - VarPattern *); + int, const char **, int, int *, int *, + VarPattern *); + static char *VarQuote(char *, Boolean); + static char *VarHash(char *); + static char *VarModify(GNode *, Var_Parse_State *, - const char *, - Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), - void *); + const char *, + Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), + void *); + static char *VarOrder(const char *, const char); + static char *VarUniq(const char *); + static int VarWordCompare(const void *, const void *); + static void VarPrintVar(void *); -#define BROPEN '{' -#define BRCLOSE '}' -#define PROPEN '(' -#define PRCLOSE ')' +#define BROPEN '{' +#define BRCLOSE '}' +#define PROPEN '(' +#define PRCLOSE ')' @@ -365,8 +403,7 @@ static void VarPrintVar(void *); static Var * -VarFind(const char *name, GNode *ctxt, int flags) -{ - Hash_Entry *var; - Var *v; +VarFind(const char *name, GNode *ctxt, int flags) { + Hash_Entry *var; + Var *v; - /* + /* * If the variable name begins with a '.', it could very well be one of @@ -376,33 +413,33 @@ VarFind(const char *name, GNode *ctxt, int flags) */ - if (*name == '.' && isupper((unsigned char) name[1])) - switch (name[1]) { - case 'A': - if (!strcmp(name, ".ALLSRC")) - name = ALLSRC; - if (!strcmp(name, ".ARCHIVE")) - name = ARCHIVE; - break; - case 'I': - if (!strcmp(name, ".IMPSRC")) - name = IMPSRC; - break; - case 'M': - if (!strcmp(name, ".MEMBER")) - name = MEMBER; - break; - case 'O': - if (!strcmp(name, ".OODATE")) - name = OODATE; - break; - case 'P': - if (!strcmp(name, ".PREFIX")) - name = PREFIX; - break; - case 'T': - if (!strcmp(name, ".TARGET")) - name = TARGET; - break; - } + if (*name == '.' && isupper((unsigned char) name[1])) + switch (name[1]) { + case 'A': + if (!strcmp(name, ".ALLSRC")) + name = ALLSRC; + if (!strcmp(name, ".ARCHIVE")) + name = ARCHIVE; + break; + case 'I': + if (!strcmp(name, ".IMPSRC")) + name = IMPSRC; + break; + case 'M': + if (!strcmp(name, ".MEMBER")) + name = MEMBER; + break; + case 'O': + if (!strcmp(name, ".OODATE")) + name = OODATE; + break; + case 'P': + if (!strcmp(name, ".PREFIX")) + name = PREFIX; + break; + case 'T': + if (!strcmp(name, ".TARGET")) + name = TARGET; + break; + } #ifdef notyet - /* for compatibility with gmake */ + /* for compatibility with gmake */ if (name[0] == '^' && name[1] == '\0') @@ -419,48 +456,46 @@ VarFind(const char *name, GNode *ctxt, int flags) if ((var == NULL) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) { - var = Hash_FindEntry(&VAR_CMD->context, name); + var = Hash_FindEntry(&VAR_CMD->context, name); } if (!checkEnvFirst && (var == NULL) && (flags & FIND_GLOBAL) && - (ctxt != VAR_GLOBAL)) - { - var = Hash_FindEntry(&VAR_GLOBAL->context, name); - if ((var == NULL) && (ctxt != VAR_INTERNAL)) { - /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ - var = Hash_FindEntry(&VAR_INTERNAL->context, name); - } + (ctxt != VAR_GLOBAL)) { + var = Hash_FindEntry(&VAR_GLOBAL->context, name); + if ((var == NULL) && (ctxt != VAR_INTERNAL)) { + /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ + var = Hash_FindEntry(&VAR_INTERNAL->context, name); + } } if ((var == NULL) && (flags & FIND_ENV)) { - char *env; - - if ((env = getenv(name)) != NULL) { - int len; - - v = bmake_malloc(sizeof(Var)); - v->name = bmake_strdup(name); - - len = strlen(env); - - Buf_Init(&v->val, len + 1); - Buf_AddBytes(&v->val, len, env); - - v->flags = VAR_FROM_ENV; - return (v); - } else if (checkEnvFirst && (flags & FIND_GLOBAL) && - (ctxt != VAR_GLOBAL)) - { - var = Hash_FindEntry(&VAR_GLOBAL->context, name); - if ((var == NULL) && (ctxt != VAR_INTERNAL)) { - var = Hash_FindEntry(&VAR_INTERNAL->context, name); - } - if (var == NULL) { - return NULL; - } else { - return ((Var *)Hash_GetValue(var)); - } - } else { - return NULL; - } + char *env; + + if ((env = getenv(name)) != NULL) { + int len; + + v = bmake_malloc(sizeof(Var)); + v->name = bmake_strdup(name); + + len = strlen(env); + + Buf_Init(&v->val, len + 1); + Buf_AddBytes(&v->val, len, env); + + v->flags = VAR_FROM_ENV; + return (v); + } else if (checkEnvFirst && (flags & FIND_GLOBAL) && + (ctxt != VAR_GLOBAL)) { + var = Hash_FindEntry(&VAR_GLOBAL->context, name); + if ((var == NULL) && (ctxt != VAR_INTERNAL)) { + var = Hash_FindEntry(&VAR_INTERNAL->context, name); + } + if (var == NULL) { + return NULL; + } else { + return ((Var *) Hash_GetValue(var)); + } + } else { + return NULL; + } } else if (var == NULL) { - return NULL; + return NULL; } else { - return ((Var *)Hash_GetValue(var)); + return ((Var *) Hash_GetValue(var)); } @@ -485,6 +520,5 @@ VarFind(const char *name, GNode *ctxt, int flags) static Boolean -VarFreeEnv(Var *v, Boolean destroy) -{ +VarFreeEnv(Var *v, Boolean destroy) { if ((v->flags & VAR_FROM_ENV) == 0) - return FALSE; + return FALSE; free(v->name); @@ -515,7 +549,6 @@ VarFreeEnv(Var *v, Boolean destroy) static void -VarAdd(const char *name, const char *val, GNode *ctxt) -{ - Var *v; - int len; - Hash_Entry *h; +VarAdd(const char *name, const char *val, GNode *ctxt) { + Var *v; + int len; + Hash_Entry *h; @@ -524,3 +557,3 @@ VarAdd(const char *name, const char *val, GNode *ctxt) len = val ? strlen(val) : 0; - Buf_Init(&v->val, len+1); + Buf_Init(&v->val, len + 1); Buf_AddBytes(&v->val, len, val); @@ -533,3 +566,3 @@ VarAdd(const char *name, const char *val, GNode *ctxt) if (DEBUG(VAR) && (ctxt->flags & INTERNAL) == 0) { - fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); + fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); } @@ -551,11 +584,10 @@ VarAdd(const char *name, const char *val, GNode *ctxt) void -Var_Delete(const char *name, GNode *ctxt) -{ - Hash_Entry *ln; +Var_Delete(const char *name, GNode *ctxt) { + Hash_Entry *ln; char *cp; - + if (strchr(name, '$')) { - cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES); + cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES); } else { - cp = (char *)name; + cp = (char *) name; } @@ -563,23 +595,23 @@ Var_Delete(const char *name, GNode *ctxt) if (DEBUG(VAR)) { - fprintf(debug_file, "%s:delete %s%s\n", - ctxt->name, cp, ln ? "" : " (not found)"); + fprintf(debug_file, "%s:delete %s%s\n", + ctxt->name, cp, ln ? "" : " (not found)"); } if (cp != name) { - free(cp); + free(cp); } if (ln != NULL) { - Var *v; + Var *v; - v = (Var *)Hash_GetValue(ln); - if ((v->flags & VAR_EXPORTED)) { - unsetenv(v->name); - } - if (strcmp(MAKE_EXPORTED, v->name) == 0) { - var_exportedVars = VAR_EXPORTED_NONE; - } - if (v->name != ln->name) - free(v->name); - Hash_DeleteEntry(&ctxt->context, ln); - Buf_Destroy(&v->val, TRUE); - free(v); + v = (Var *) Hash_GetValue(ln); + if ((v->flags & VAR_EXPORTED)) { + unsetenv(v->name); + } + if (strcmp(MAKE_EXPORTED, v->name) == 0) { + var_exportedVars = VAR_EXPORTED_NONE; + } + if (v->name != ln->name) + free(v->name); + Hash_DeleteEntry(&ctxt->context, ln); + Buf_Destroy(&v->val, TRUE); + free(v); } @@ -596,4 +628,3 @@ Var_Delete(const char *name, GNode *ctxt) static int -Var_Export1(const char *name, int flags) -{ +Var_Export1(const char *name, int flags) { char tmp[BUFSIZ]; @@ -605,5 +636,5 @@ Var_Export1(const char *name, int flags) if (*name == '.') - return 0; /* skip internals */ + return 0; /* skip internals */ if (!name[1]) { - /* + /* * A single char. @@ -613,9 +644,9 @@ Var_Export1(const char *name, int flags) */ - switch (name[0]) { - case '@': - case '%': - case '*': - case '!': - return 0; - } + switch (name[0]) { + case '@': + case '%': + case '*': + case '!': + return 0; + } } @@ -623,7 +654,7 @@ Var_Export1(const char *name, int flags) if (v == NULL) { - return 0; + return 0; } if (!parent && - (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) { - return 0; /* nothing to do */ + (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) { + return 0; /* nothing to do */ } @@ -631,4 +662,4 @@ Var_Export1(const char *name, int flags) if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) { - if (parent) { - /* + if (parent) { + /* * Flag this as something we need to re-export. @@ -637,7 +668,7 @@ Var_Export1(const char *name, int flags) */ - v->flags |= (VAR_EXPORTED|VAR_REEXPORT); - return 1; - } - if (v->flags & VAR_IN_USE) { - /* + v->flags |= (VAR_EXPORTED | VAR_REEXPORT); + return 1; + } + if (v->flags & VAR_IN_USE) { + /* * We recursed while exporting in a child. @@ -645,17 +676,17 @@ Var_Export1(const char *name, int flags) */ - return 0; - } - n = snprintf(tmp, sizeof(tmp), "${%s}", name); - if (n < (int)sizeof(tmp)) { - val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); - setenv(name, val, 1); - free(val); - } + return 0; + } + n = snprintf(tmp, sizeof(tmp), "${%s}", name); + if (n < (int) sizeof(tmp)) { + val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); + setenv(name, val, 1); + free(val); + } } else { - if (parent) { - v->flags &= ~VAR_REEXPORT; /* once will do */ - } - if (parent || !(v->flags & VAR_EXPORTED)) { - setenv(name, val, 1); - } + if (parent) { + v->flags &= ~VAR_REEXPORT; /* once will do */ + } + if (parent || !(v->flags & VAR_EXPORTED)) { + setenv(name, val, 1); + } } @@ -665,3 +696,3 @@ Var_Export1(const char *name, int flags) if (parent) { - v->flags |= VAR_EXPORTED; + v->flags |= VAR_EXPORTED; } @@ -674,7 +705,6 @@ Var_Export1(const char *name, int flags) void -Var_ExportVars(void) -{ +Var_ExportVars(void) { char tmp[BUFSIZ]; - Hash_Entry *var; - Hash_Search state; + Hash_Entry *var; + Hash_Search state; Var *v; @@ -693,15 +723,15 @@ Var_ExportVars(void) if (VAR_EXPORTED_NONE == var_exportedVars) - return; + return; if (VAR_EXPORTED_ALL == var_exportedVars) { - /* + /* * Ouch! This is crazy... */ - for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state); - var != NULL; - var = Hash_EnumNext(&state)) { - v = (Var *)Hash_GetValue(var); - Var_Export1(v->name, 0); - } - return; + for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state); + var != NULL; + var = Hash_EnumNext(&state)) { + v = (Var *) Hash_GetValue(var); + Var_Export1(v->name, 0); + } + return; } @@ -711,18 +741,18 @@ Var_ExportVars(void) n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); - if (n < (int)sizeof(tmp)) { - char **av; - char *as; - int ac; - int i; - - val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); - if (*val) { - av = brk_string(val, &ac, FALSE, &as); - for (i = 0; i < ac; i++) { - Var_Export1(av[i], 0); - } - free(as); - free(av); - } - free(val); + if (n < (int) sizeof(tmp)) { + char **av; + char *as; + int ac; + int i; + + val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); + if (*val) { + av = brk_string(val, &ac, FALSE, &as); + for (i = 0; i < ac; i++) { + Var_Export1(av[i], 0); + } + free(as); + free(av); + } + free(val); } @@ -736,4 +766,3 @@ Var_ExportVars(void) void -Var_Export(char *str, int isExport) -{ +Var_Export(char *str, int isExport) { char *name; @@ -747,4 +776,4 @@ Var_Export(char *str, int isExport) if (isExport && (!str || !str[0])) { - var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ - return; + var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ + return; } @@ -753,8 +782,8 @@ Var_Export(char *str, int isExport) if (strncmp(str, "-env", 4) == 0) { - str += 4; + str += 4; } else if (strncmp(str, "-literal", 8) == 0) { - str += 8; - flags |= VAR_EXPORT_LITERAL; + str += 8; + flags |= VAR_EXPORT_LITERAL; } else { - flags |= VAR_EXPORT_PARENT; + flags |= VAR_EXPORT_PARENT; } @@ -762,7 +791,7 @@ Var_Export(char *str, int isExport) if (*val) { - av = brk_string(val, &ac, FALSE, &as); - for (i = 0; i < ac; i++) { - name = av[i]; - if (!name[1]) { - /* + av = brk_string(val, &ac, FALSE, &as); + for (i = 0; i < ac; i++) { + name = av[i]; + if (!name[1]) { + /* * A single char. @@ -772,20 +801,20 @@ Var_Export(char *str, int isExport) */ - switch (name[0]) { - case '@': - case '%': - case '*': - case '!': - continue; - } - } - if (Var_Export1(name, flags)) { - if (VAR_EXPORTED_ALL != var_exportedVars) - var_exportedVars = VAR_EXPORTED_YES; - if (isExport && (flags & VAR_EXPORT_PARENT)) { - Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); - } - } - } - free(as); - free(av); + switch (name[0]) { + case '@': + case '%': + case '*': + case '!': + continue; + } + } + if (Var_Export1(name, flags)) { + if (VAR_EXPORTED_ALL != var_exportedVars) + var_exportedVars = VAR_EXPORTED_YES; + if (isExport && (flags & VAR_EXPORT_PARENT)) { + Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); + } + } + } + free(as); + free(av); } @@ -801,4 +830,3 @@ extern char **environ; void -Var_UnExport(char *str) -{ +Var_UnExport(char *str) { char tmp[BUFSIZ]; @@ -810,3 +838,3 @@ Var_UnExport(char *str) if (!str || !str[0]) { - return; /* assert? */ + return; /* assert? */ } @@ -818,29 +846,29 @@ Var_UnExport(char *str) if (unexport_env) { - char **newenv; - - cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ - if (environ == savedEnv) { - /* we have been here before! */ - newenv = bmake_realloc(environ, 2 * sizeof(char *)); - } else { - if (savedEnv) { - free(savedEnv); - savedEnv = NULL; - } - newenv = bmake_malloc(2 * sizeof(char *)); - } - if (!newenv) - return; - /* Note: we cannot safely free() the original environ. */ - environ = savedEnv = newenv; - newenv[0] = NULL; - newenv[1] = NULL; - if (cp && *cp) - setenv(MAKE_LEVEL_ENV, cp, 1); + char **newenv; + + cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ + if (environ == savedEnv) { + /* we have been here before! */ + newenv = bmake_realloc(environ, 2 * sizeof(char *)); + } else { + if (savedEnv) { + free(savedEnv); + savedEnv = NULL; + } + newenv = bmake_malloc(2 * sizeof(char *)); + } + if (!newenv) + return; + /* Note: we cannot safely free() the original environ. */ + environ = savedEnv = newenv; + newenv[0] = NULL; + newenv[1] = NULL; + if (cp && *cp) + setenv(MAKE_LEVEL_ENV, cp, 1); } else { - for (; *str != '\n' && isspace((unsigned char) *str); str++) - continue; - if (str[0] && str[0] != '\n') { - vlist = str; - } + for (; *str != '\n' && isspace((unsigned char) *str); str++) + continue; + if (str[0] && str[0] != '\n') { + vlist = str; + } } @@ -848,26 +876,26 @@ Var_UnExport(char *str) if (!vlist) { - /* Using .MAKE.EXPORTED */ - n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); - if (n < (int)sizeof(tmp)) { - vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); - } + /* Using .MAKE.EXPORTED */ + n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); + if (n < (int) sizeof(tmp)) { + vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); + } } if (vlist) { - Var *v; - char **av; - char *as; - int ac; - int i; - - av = brk_string(vlist, &ac, FALSE, &as); - for (i = 0; i < ac; i++) { - v = VarFind(av[i], VAR_GLOBAL, 0); - if (!v) - continue; - if (!unexport_env && - (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) { - unsetenv(v->name); - } - v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT); - /* + Var *v; + char **av; + char *as; + int ac; + int i; + + av = brk_string(vlist, &ac, FALSE, &as); + for (i = 0; i < ac; i++) { + v = VarFind(av[i], VAR_GLOBAL, 0); + if (!v) + continue; + if (!unexport_env && + (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) { + unsetenv(v->name); + } + v->flags &= ~(VAR_EXPORTED | VAR_REEXPORT); + /* * If we are unexporting a list, @@ -877,18 +905,18 @@ Var_UnExport(char *str) */ - if (vlist == str) { - n = snprintf(tmp, sizeof(tmp), - "${" MAKE_EXPORTED ":N%s}", v->name); - if (n < (int)sizeof(tmp)) { - cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); - Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL, 0); - free(cp); - } - } - } - free(as); - free(av); - if (vlist != str) { - Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); - free(vlist); - } + if (vlist == str) { + n = snprintf(tmp, sizeof(tmp), + "${" MAKE_EXPORTED ":N%s}", v->name); + if (n < (int) sizeof(tmp)) { + cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); + Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL, 0); + free(cp); + } + } + } + free(as); + free(av); + if (vlist != str) { + Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); + free(vlist); + } } @@ -925,7 +953,20 @@ Var_UnExport(char *str) void -Var_Set(const char *name, const char *val, GNode *ctxt, int flags) -{ - Var *v; +Var_Set(const char *name, const char *val, GNode *ctxt, int flags) { + Var *v; char *expanded_name = NULL; + +#if (defined _WIN32 && ! defined __CYGWIN__) + char *unix_val; + char *error; + if (val && strlen(val) > 0 && val[1] == ':' && (val[2] == '/' || val[2] == '\\')) { + unix_val = Cmd_Exec(getUnixPathCmd(val), &error); + } + else { + unix_val = val; + } +#else + const char *unix_val = val; +#endif + /* @@ -936,25 +977,25 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) if (strchr(name, '$') != NULL) { - expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); - if (expanded_name[0] == 0) { - if (DEBUG(VAR)) { - fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " - "name expands to empty string - ignored\n", - name, val); - } - free(expanded_name); - return; - } - name = expanded_name; + expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); + if (expanded_name[0] == 0) { + if (DEBUG(VAR)) { + fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " + "name expands to empty string - ignored\n", + name, unix_val); + } + free(expanded_name); + return; + } + name = expanded_name; } if (ctxt == VAR_GLOBAL) { - v = VarFind(name, VAR_CMD, 0); - if (v != NULL) { - if ((v->flags & VAR_FROM_CMD)) { - if (DEBUG(VAR)) { - fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val); - } - goto out; - } - VarFreeEnv(v, TRUE); - } + v = VarFind(name, VAR_CMD, 0); + if (v != NULL) { + if ((v->flags & VAR_FROM_CMD)) { + if (DEBUG(VAR)) { + fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, unix_val); + } + goto out; + } + VarFreeEnv(v, TRUE); + } } @@ -962,4 +1003,4 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) if (v == NULL) { - if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { - /* + if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { + /* * This var would normally prevent the same name being added @@ -968,16 +1009,16 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) */ - Var_Delete(name, VAR_GLOBAL); - } - VarAdd(name, val, ctxt); + Var_Delete(name, VAR_GLOBAL); + } + VarAdd(name, unix_val, ctxt); } else { - Buf_Empty(&v->val); - if (val) - Buf_AddBytes(&v->val, strlen(val), val); + Buf_Empty(&v->val); + if (unix_val) + Buf_AddBytes(&v->val, strlen(unix_val), unix_val); - if (DEBUG(VAR)) { - fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); - } - if ((v->flags & VAR_EXPORTED)) { - Var_Export1(name, VAR_EXPORT_PARENT); - } + if (DEBUG(VAR)) { + fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, unix_val); + } + if ((v->flags & VAR_EXPORTED)) { + Var_Export1(name, VAR_EXPORT_PARENT); + } } @@ -988,9 +1029,9 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { - if (v == NULL) { - /* we just added it */ - v = VarFind(name, ctxt, 0); - } - if (v != NULL) - v->flags |= VAR_FROM_CMD; - /* + if (v == NULL) { + /* we just added it */ + v = VarFind(name, ctxt, 0); + } + if (v != NULL) + v->flags |= VAR_FROM_CMD; + /* * If requested, don't export these in the environment @@ -1000,16 +1041,16 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) */ - if (varNoExportEnv != TRUE) - setenv(name, val ? val : "", 1); + if (varNoExportEnv != TRUE) + setenv(name, unix_val ? unix_val : "", 1); - Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); + Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); } if (*name == '.') { - if (strcmp(name, SAVE_DOLLARS) == 0) - save_dollars = s2Boolean(val, save_dollars); + if (strcmp(name, SAVE_DOLLARS) == 0) + save_dollars = s2Boolean(unix_val, save_dollars); } - out: + out: free(expanded_name); if (v != NULL) - VarFreeEnv(v, TRUE); + VarFreeEnv(v, TRUE); } @@ -1044,6 +1085,5 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) void -Var_Append(const char *name, const char *val, GNode *ctxt) -{ - Var *v; - Hash_Entry *h; +Var_Append(const char *name, const char *val, GNode *ctxt) { + Var *v; + Hash_Entry *h; char *expanded_name = NULL; @@ -1051,30 +1091,30 @@ Var_Append(const char *name, const char *val, GNode *ctxt) if (strchr(name, '$') != NULL) { - expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); - if (expanded_name[0] == 0) { - if (DEBUG(VAR)) { - fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " - "name expands to empty string - ignored\n", - name, val); - } - free(expanded_name); - return; - } - name = expanded_name; + expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); + if (expanded_name[0] == 0) { + if (DEBUG(VAR)) { + fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " + "name expands to empty string - ignored\n", + name, val); + } + free(expanded_name); + return; + } + name = expanded_name; } - v = VarFind(name, ctxt, (ctxt == VAR_GLOBAL) ? (FIND_CMD|FIND_ENV) : 0); + v = VarFind(name, ctxt, (ctxt == VAR_GLOBAL) ? (FIND_CMD | FIND_ENV) : 0); if (v == NULL) { - Var_Set(name, val, ctxt, 0); + Var_Set(name, val, ctxt, 0); } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) { - Buf_AddByte(&v->val, ' '); - Buf_AddBytes(&v->val, strlen(val), val); + Buf_AddByte(&v->val, ' '); + Buf_AddBytes(&v->val, strlen(val), val); - if (DEBUG(VAR)) { - fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, - Buf_GetAll(&v->val, NULL)); - } + if (DEBUG(VAR)) { + fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, + Buf_GetAll(&v->val, NULL)); + } - if (v->flags & VAR_FROM_ENV) { - /* + if (v->flags & VAR_FROM_ENV) { + /* * If the original variable came from the environment, we @@ -1084,6 +1124,6 @@ Var_Append(const char *name, const char *val, GNode *ctxt) */ - v->flags &= ~VAR_FROM_ENV; - h = Hash_CreateEntry(&ctxt->context, name, NULL); - Hash_SetValue(h, v); - } + v->flags &= ~VAR_FROM_ENV; + h = Hash_CreateEntry(&ctxt->context, name, NULL); + Hash_SetValue(h, v); + } } @@ -1110,18 +1150,17 @@ Var_Append(const char *name, const char *val, GNode *ctxt) Boolean -Var_Exists(const char *name, GNode *ctxt) -{ - Var *v; - char *cp; +Var_Exists(const char *name, GNode *ctxt) { + Var *v; + char *cp; if ((cp = strchr(name, '$')) != NULL) { - cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES); + cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES); } - v = VarFind(cp ? cp : name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV); + v = VarFind(cp ? cp : name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV); free(cp); if (v == NULL) { - return(FALSE); + return (FALSE); } else { - (void)VarFreeEnv(v, TRUE); + (void) VarFreeEnv(v, TRUE); } - return(TRUE); + return (TRUE); } @@ -1145,5 +1184,4 @@ Var_Exists(const char *name, GNode *ctxt) char * -Var_Value(const char *name, GNode *ctxt, char **frp) -{ - Var *v; +Var_Value(const char *name, GNode *ctxt, char **frp) { + Var *v; @@ -1152,8 +1190,20 @@ Var_Value(const char *name, GNode *ctxt, char **frp) if (v != NULL) { - char *p = (Buf_GetAll(&v->val, NULL)); - if (VarFreeEnv(v, FALSE)) - *frp = p; - return p; + char *raw = (Buf_GetAll(&v->val, NULL)); +#if (defined _WIN32 && ! defined __CYGWIN__) + char *p; + const char *error; + if ((raw[1] == ':') && (raw[2] == '/' || raw[2] == '\\')) { // it is windows path + p = Cmd_Exec(getUnixPathCmd(raw), &error); + } + else { + p = raw; + } +#else + char *p = raw; +#endif + if (VarFreeEnv(v, FALSE)) + *frp = p; + return p; } else { - return NULL; + return NULL; } @@ -1184,5 +1234,4 @@ static Boolean VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, - char *word, Boolean addSpace, Buffer *buf, - void *dummy MAKE_ATTR_UNUSED) -{ + char *word, Boolean addSpace, Buffer *buf, + void *dummy MAKE_ATTR_UNUSED) { char *slash; @@ -1191,16 +1240,16 @@ VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, if (slash != NULL) { - if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); - } - *slash = '\0'; - Buf_AddBytes(buf, strlen(word), word); - *slash = '/'; - return (TRUE); + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + *slash = '\0'; + Buf_AddBytes(buf, strlen(word), word); + *slash = '/'; + return (TRUE); } else { - /* + /* * If no directory part, give . (q.v. the POSIX standard) */ - if (addSpace && vpstate->varSpace) - Buf_AddByte(buf, vpstate->varSpace); - Buf_AddByte(buf, '.'); + if (addSpace && vpstate->varSpace) + Buf_AddByte(buf, vpstate->varSpace); + Buf_AddByte(buf, '.'); } @@ -1232,5 +1281,4 @@ static Boolean VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, - char *word, Boolean addSpace, Buffer *buf, - void *dummy MAKE_ATTR_UNUSED) -{ + char *word, Boolean addSpace, Buffer *buf, + void *dummy MAKE_ATTR_UNUSED) { char *slash; @@ -1238,3 +1286,3 @@ VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); + Buf_AddByte(buf, vpstate->varSpace); } @@ -1243,7 +1291,7 @@ VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, if (slash != NULL) { - *slash++ = '\0'; - Buf_AddBytes(buf, strlen(slash), slash); - slash[-1] = '/'; + *slash++ = '\0'; + Buf_AddBytes(buf, strlen(slash), slash); + slash[-1] = '/'; } else { - Buf_AddBytes(buf, strlen(word), word); + Buf_AddBytes(buf, strlen(word), word); } @@ -1274,5 +1322,4 @@ static Boolean VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, - char *word, Boolean addSpace, Buffer *buf, - void *dummy MAKE_ATTR_UNUSED) -{ + char *word, Boolean addSpace, Buffer *buf, + void *dummy MAKE_ATTR_UNUSED) { char *dot; @@ -1281,9 +1328,9 @@ VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, if (dot != NULL) { - if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); - } - *dot++ = '\0'; - Buf_AddBytes(buf, strlen(dot), dot); - dot[-1] = '.'; - addSpace = TRUE; + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + *dot++ = '\0'; + Buf_AddBytes(buf, strlen(dot), dot); + dot[-1] = '.'; + addSpace = TRUE; } @@ -1315,5 +1362,4 @@ static Boolean VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, - char *word, Boolean addSpace, Buffer *buf, - void *dummy MAKE_ATTR_UNUSED) -{ + char *word, Boolean addSpace, Buffer *buf, + void *dummy MAKE_ATTR_UNUSED) { char *dot; @@ -1321,3 +1367,3 @@ VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); + Buf_AddByte(buf, vpstate->varSpace); } @@ -1326,7 +1372,7 @@ VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, if (dot != NULL) { - *dot = '\0'; - Buf_AddBytes(buf, strlen(word), word); - *dot = '.'; + *dot = '\0'; + Buf_AddBytes(buf, strlen(word), word); + *dot = '.'; } else { - Buf_AddBytes(buf, strlen(word), word); + Buf_AddBytes(buf, strlen(word), word); } @@ -1359,15 +1405,14 @@ static Boolean VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, - char *word, Boolean addSpace, Buffer *buf, - void *pattern) -{ + char *word, Boolean addSpace, Buffer *buf, + void *pattern) { if (DEBUG(VAR)) - fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *)pattern); - if (Str_Match(word, (char *)pattern)) { - if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); - } - addSpace = TRUE; - Buf_AddBytes(buf, strlen(word), word); + fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *) pattern); + if (Str_Match(word, (char *) pattern)) { + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + addSpace = TRUE; + Buf_AddBytes(buf, strlen(word), word); } - return(addSpace); + return (addSpace); } @@ -1375,2 +1420,3 @@ VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, #ifdef SYSVVARSUB + /*- @@ -1400,8 +1446,7 @@ static Boolean VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, - char *word, Boolean addSpace, Buffer *buf, - void *patp) -{ + char *word, Boolean addSpace, Buffer *buf, + void *patp) { int len; char *ptr; - VarPattern *pat = (VarPattern *)patp; + VarPattern *pat = (VarPattern *) patp; char *varexp; @@ -1409,3 +1454,3 @@ VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, if (addSpace && vpstate->varSpace) - Buf_AddByte(buf, vpstate->varSpace); + Buf_AddByte(buf, vpstate->varSpace); @@ -1415,10 +1460,11 @@ VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, varexp = Var_Subst(NULL, pat->rhs, ctx, VARF_WANTRES); - Str_SYSVSubst(buf, varexp, ptr, len); - free(varexp); + Str_SYSVSubst(buf, varexp, ptr, len); + free(varexp); } else { - Buf_AddBytes(buf, strlen(word), word); + Buf_AddBytes(buf, strlen(word), word); } - return(addSpace); + return (addSpace); } + #endif @@ -1450,13 +1496,12 @@ static Boolean VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, - char *word, Boolean addSpace, Buffer *buf, - void *pattern) -{ - if (!Str_Match(word, (char *)pattern)) { - if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); - } - addSpace = TRUE; - Buf_AddBytes(buf, strlen(word), word); + char *word, Boolean addSpace, Buffer *buf, + void *pattern) { + if (!Str_Match(word, (char *) pattern)) { + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + addSpace = TRUE; + Buf_AddBytes(buf, strlen(word), word); } - return(addSpace); + return (addSpace); } @@ -1487,13 +1532,12 @@ static Boolean VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, - char *word, Boolean addSpace, Buffer *buf, - void *patternp) -{ - int wordLen; /* Length of word */ - char *cp; /* General pointer */ - VarPattern *pattern = (VarPattern *)patternp; + char *word, Boolean addSpace, Buffer *buf, + void *patternp) { + int wordLen; /* Length of word */ + char *cp; /* General pointer */ + VarPattern *pattern = (VarPattern *) patternp; wordLen = strlen(word); - if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) != - (VAR_SUB_ONE|VAR_SUB_MATCHED)) { - /* + if ((pattern->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) != + (VAR_SUB_ONE | VAR_SUB_MATCHED)) { + /* * Still substituting -- break it down into simple anchored cases @@ -1501,10 +1545,10 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, */ - if ((pattern->flags & VAR_MATCH_START) && - (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { - /* + if ((pattern->flags & VAR_MATCH_START) && + (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { + /* * Anchored at start and beginning of word matches pattern */ - if ((pattern->flags & VAR_MATCH_END) && - (wordLen == pattern->leftLen)) { - /* + if ((pattern->flags & VAR_MATCH_END) && + (wordLen == pattern->leftLen)) { + /* * Also anchored at end and matches to the end (word @@ -1513,37 +1557,37 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, */ - if (pattern->rightLen != 0) { - if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); - } - addSpace = TRUE; - Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); - } - pattern->flags |= VAR_SUB_MATCHED; - } else if (pattern->flags & VAR_MATCH_END) { - /* + if (pattern->rightLen != 0) { + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + addSpace = TRUE; + Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); + } + pattern->flags |= VAR_SUB_MATCHED; + } else if (pattern->flags & VAR_MATCH_END) { + /* * Doesn't match to end -- copy word wholesale */ - goto nosub; - } else { - /* + goto nosub; + } else { + /* * Matches at start but need to copy in trailing characters */ - if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){ - if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); - } - addSpace = TRUE; - } - Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); - Buf_AddBytes(buf, wordLen - pattern->leftLen, - (word + pattern->leftLen)); - pattern->flags |= VAR_SUB_MATCHED; - } - } else if (pattern->flags & VAR_MATCH_START) { - /* + if ((pattern->rightLen + wordLen - pattern->leftLen) != 0) { + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + addSpace = TRUE; + } + Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); + Buf_AddBytes(buf, wordLen - pattern->leftLen, + (word + pattern->leftLen)); + pattern->flags |= VAR_SUB_MATCHED; + } + } else if (pattern->flags & VAR_MATCH_START) { + /* * Had to match at start of word and didn't -- copy whole word. */ - goto nosub; - } else if (pattern->flags & VAR_MATCH_END) { - /* + goto nosub; + } else if (pattern->flags & VAR_MATCH_END) { + /* * Anchored at end, Find only place match could occur (leftLen @@ -1553,6 +1597,6 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, */ - cp = word + (wordLen - pattern->leftLen); - if ((cp >= word) && - (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { - /* + cp = word + (wordLen - pattern->leftLen); + if ((cp >= word) && + (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { + /* * Match found. If we will place characters in the buffer, @@ -1562,19 +1606,19 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, */ - if (((cp - word) + pattern->rightLen) != 0) { - if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); - } - addSpace = TRUE; - } - Buf_AddBytes(buf, cp - word, word); - Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); - pattern->flags |= VAR_SUB_MATCHED; - } else { - /* + if (((cp - word) + pattern->rightLen) != 0) { + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + addSpace = TRUE; + } + Buf_AddBytes(buf, cp - word, word); + Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); + pattern->flags |= VAR_SUB_MATCHED; + } else { + /* * Had to match at end and didn't. Copy entire word. */ - goto nosub; - } - } else { - /* + goto nosub; + } + } else { + /* * Pattern is unanchored: search for the pattern in the word using @@ -1589,36 +1633,36 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, */ - Boolean done; - int origSize; - - done = FALSE; - origSize = Buf_Size(buf); - while (!done) { - cp = Str_FindSubstring(word, pattern->lhs); - if (cp != NULL) { - if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ - Buf_AddByte(buf, vpstate->varSpace); - addSpace = FALSE; - } - Buf_AddBytes(buf, cp-word, word); - Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); - wordLen -= (cp - word) + pattern->leftLen; - word = cp + pattern->leftLen; - if (wordLen == 0) { - done = TRUE; - } - if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { - done = TRUE; - } - pattern->flags |= VAR_SUB_MATCHED; - } else { - done = TRUE; - } - } - if (wordLen != 0) { - if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); - } - Buf_AddBytes(buf, wordLen, word); - } - /* + Boolean done; + int origSize; + + done = FALSE; + origSize = Buf_Size(buf); + while (!done) { + cp = Str_FindSubstring(word, pattern->lhs); + if (cp != NULL) { + if (addSpace && (((cp - word) + pattern->rightLen) != 0)) { + Buf_AddByte(buf, vpstate->varSpace); + addSpace = FALSE; + } + Buf_AddBytes(buf, cp - word, word); + Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); + wordLen -= (cp - word) + pattern->leftLen; + word = cp + pattern->leftLen; + if (wordLen == 0) { + done = TRUE; + } + if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { + done = TRUE; + } + pattern->flags |= VAR_SUB_MATCHED; + } else { + done = TRUE; + } + } + if (wordLen != 0) { + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + Buf_AddBytes(buf, wordLen, word); + } + /* * If added characters to the buffer, need to add a space @@ -1627,12 +1671,12 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, */ - return ((Buf_Size(buf) != origSize) || addSpace); - } - return (addSpace); + return ((Buf_Size(buf) != origSize) || addSpace); + } + return (addSpace); } - nosub: + nosub: if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); + Buf_AddByte(buf, vpstate->varSpace); } Buf_AddBytes(buf, wordLen, word); - return(TRUE); + return (TRUE); } @@ -1640,2 +1684,3 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, #ifndef NO_REGEX + /*- @@ -1654,4 +1699,3 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, static void -VarREError(int reerr, regex_t *pat, const char *str) -{ +VarREError(int reerr, regex_t *pat, const char *str) { char *errbuf; @@ -1683,6 +1727,5 @@ static Boolean VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, - Var_Parse_State *vpstate MAKE_ATTR_UNUSED, - char *word, Boolean addSpace, Buffer *buf, - void *patternp) -{ + Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + char *word, Boolean addSpace, Buffer *buf, + void *patternp) { VarREPattern *pat; @@ -1694,6 +1737,6 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, -#define MAYBE_ADD_SPACE() \ - if (addSpace && !added) \ - Buf_AddByte(buf, ' '); \ - added = 1 +#define MAYBE_ADD_SPACE() \ + if (addSpace && !added) \ + Buf_AddByte(buf, ' '); \ + added = 1 @@ -1703,8 +1746,8 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, - if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) == - (VAR_SUB_ONE|VAR_SUB_MATCHED)) - xrv = REG_NOMATCH; + if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) == + (VAR_SUB_ONE | VAR_SUB_MATCHED)) + xrv = REG_NOMATCH; else { - tryagain: - xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); + tryagain: + xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); } @@ -1712,88 +1755,87 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, switch (xrv) { - case 0: - pat->flags |= VAR_SUB_MATCHED; - if (pat->matches[0].rm_so > 0) { - MAYBE_ADD_SPACE(); - Buf_AddBytes(buf, pat->matches[0].rm_so, wp); - } - - for (rp = pat->replace; *rp; rp++) { - if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { - MAYBE_ADD_SPACE(); - Buf_AddByte(buf,rp[1]); - rp++; - } - else if ((*rp == '&') || - ((*rp == '\\') && isdigit((unsigned char)rp[1]))) { - int n; - const char *subbuf; - int sublen; - char errstr[3]; - - if (*rp == '&') { - n = 0; - errstr[0] = '&'; - errstr[1] = '\0'; - } else { - n = rp[1] - '0'; - errstr[0] = '\\'; - errstr[1] = rp[1]; - errstr[2] = '\0'; - rp++; - } - - if (n > pat->nsub) { - Error("No subexpression %s", &errstr[0]); - subbuf = ""; - sublen = 0; - } else if ((pat->matches[n].rm_so == -1) && - (pat->matches[n].rm_eo == -1)) { - Error("No match for subexpression %s", &errstr[0]); - subbuf = ""; - sublen = 0; - } else { - subbuf = wp + pat->matches[n].rm_so; - sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; - } - - if (sublen > 0) { - MAYBE_ADD_SPACE(); - Buf_AddBytes(buf, sublen, subbuf); - } - } else { - MAYBE_ADD_SPACE(); - Buf_AddByte(buf, *rp); - } - } - wp += pat->matches[0].rm_eo; - if (pat->flags & VAR_SUB_GLOBAL) { - flags |= REG_NOTBOL; - if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { - MAYBE_ADD_SPACE(); - Buf_AddByte(buf, *wp); - wp++; - - } - if (*wp) - goto tryagain; - } - if (*wp) { - MAYBE_ADD_SPACE(); - Buf_AddBytes(buf, strlen(wp), wp); - } - break; - default: - VarREError(xrv, &pat->re, "Unexpected regex error"); - /* fall through */ - case REG_NOMATCH: - if (*wp) { - MAYBE_ADD_SPACE(); - Buf_AddBytes(buf,strlen(wp),wp); - } - break; - } - return(addSpace||added); + case 0: + pat->flags |= VAR_SUB_MATCHED; + if (pat->matches[0].rm_so > 0) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf, pat->matches[0].rm_so, wp); + } + + for (rp = pat->replace; *rp; rp++) { + if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { + MAYBE_ADD_SPACE(); + Buf_AddByte(buf, rp[1]); + rp++; + } else if ((*rp == '&') || + ((*rp == '\\') && isdigit((unsigned char) rp[1]))) { + int n; + const char *subbuf; + int sublen; + char errstr[3]; + + if (*rp == '&') { + n = 0; + errstr[0] = '&'; + errstr[1] = '\0'; + } else { + n = rp[1] - '0'; + errstr[0] = '\\'; + errstr[1] = rp[1]; + errstr[2] = '\0'; + rp++; + } + + if (n > pat->nsub) { + Error("No subexpression %s", &errstr[0]); + subbuf = ""; + sublen = 0; + } else if ((pat->matches[n].rm_so == -1) && + (pat->matches[n].rm_eo == -1)) { + Error("No match for subexpression %s", &errstr[0]); + subbuf = ""; + sublen = 0; + } else { + subbuf = wp + pat->matches[n].rm_so; + sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; + } + + if (sublen > 0) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf, sublen, subbuf); + } + } else { + MAYBE_ADD_SPACE(); + Buf_AddByte(buf, *rp); + } + } + wp += pat->matches[0].rm_eo; + if (pat->flags & VAR_SUB_GLOBAL) { + flags |= REG_NOTBOL; + if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { + MAYBE_ADD_SPACE(); + Buf_AddByte(buf, *wp); + wp++; + + } + if (*wp) + goto tryagain; + } + if (*wp) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf, strlen(wp), wp); + } + break; + default: + VarREError(xrv, &pat->re, "Unexpected regex error"); + /* fall through */ + case REG_NOMATCH: + if (*wp) { + MAYBE_ADD_SPACE(); + Buf_AddBytes(buf, strlen(wp), wp); + } + break; + } + return (addSpace || added); } -#endif +#endif @@ -1824,7 +1866,6 @@ static Boolean VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, - Var_Parse_State *vpstate MAKE_ATTR_UNUSED, - char *word, Boolean addSpace, Buffer *buf, - void *loopp) -{ - VarLoop_t *loop = (VarLoop_t *)loopp; + Var_Parse_State *vpstate MAKE_ATTR_UNUSED, + char *word, Boolean addSpace, Buffer *buf, + void *loopp) { + VarLoop_t *loop = (VarLoop_t *) loopp; char *s; @@ -1841,3 +1882,3 @@ VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, } - free(s); + free(s); } @@ -1868,10 +1909,9 @@ static char * VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, - const char *str, VarSelectWords_t *seldata) -{ - Buffer buf; /* Buffer for the new string */ - Boolean addSpace; /* TRUE if need to add a space to the + const char *str, VarSelectWords_t *seldata) { + Buffer buf; /* Buffer for the new string */ + Boolean addSpace; /* TRUE if need to add a space to the * buffer before adding the trimmed * word */ - char **av; /* word list */ - char *as; /* word list memory */ + char **av; /* word list */ + char *as; /* word list memory */ int ac, i; @@ -1883,10 +1923,10 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, if (vpstate->oneBigWord) { - /* fake what brk_string() would do if there were only one word */ - ac = 1; - av = bmake_malloc((ac + 1) * sizeof(char *)); - as = bmake_strdup(str); - av[0] = as; - av[1] = NULL; + /* fake what brk_string() would do if there were only one word */ + ac = 1; + av = bmake_malloc((ac + 1) * sizeof(char *)); + as = bmake_strdup(str); + av[0] = as; + av[1] = NULL; } else { - av = brk_string(str, &ac, FALSE, &as); + av = brk_string(str, &ac, FALSE, &as); } @@ -1900,5 +1940,5 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, if (seldata->start < 0) - seldata->start = ac + seldata->start + 1; + seldata->start = ac + seldata->start + 1; if (seldata->end < 0) - seldata->end = ac + seldata->end + 1; + seldata->end = ac + seldata->end + 1; @@ -1908,9 +1948,9 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, if (seldata->start > seldata->end) { - start = MIN(ac, seldata->start) - 1; - end = MAX(0, seldata->end - 1); - step = -1; + start = MIN(ac, seldata->start) - 1; + end = MAX(0, seldata->end - 1); + step = -1; } else { - start = MAX(0, seldata->start - 1); - end = MIN(ac, seldata->end); - step = 1; + start = MAX(0, seldata->start - 1); + end = MIN(ac, seldata->end); + step = 1; } @@ -1918,11 +1958,11 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, for (i = start; - (step < 0 && i >= end) || (step > 0 && i < end); - i += step) { - if (av[i] && *av[i]) { - if (addSpace && vpstate->varSpace) { - Buf_AddByte(&buf, vpstate->varSpace); - } - Buf_AddBytes(&buf, strlen(av[i]), av[i]); - addSpace = TRUE; - } + (step < 0 && i >= end) || (step > 0 && i < end); + i += step) { + if (av[i] && *av[i]) { + if (addSpace && vpstate->varSpace) { + Buf_AddByte(&buf, vpstate->varSpace); + } + Buf_AddBytes(&buf, strlen(av[i]), av[i]); + addSpace = TRUE; + } } @@ -1943,19 +1983,18 @@ static Boolean VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, - char *word, Boolean addSpace, Buffer *buf, - void *patternp MAKE_ATTR_UNUSED) -{ - struct stat st; - char rbuf[MAXPATHLEN]; - char *rp; - - if (addSpace && vpstate->varSpace) { - Buf_AddByte(buf, vpstate->varSpace); - } - addSpace = TRUE; - rp = cached_realpath(word, rbuf); - if (rp && *rp == '/' && stat(rp, &st) == 0) - word = rp; - - Buf_AddBytes(buf, strlen(word), word); - return(addSpace); + char *word, Boolean addSpace, Buffer *buf, + void *patternp MAKE_ATTR_UNUSED) { + struct stat st; + char rbuf[MAXPATHLEN]; + char *rp; + + if (addSpace && vpstate->varSpace) { + Buf_AddByte(buf, vpstate->varSpace); + } + addSpace = TRUE; + rp = cached_realpath(word, rbuf); + if (rp && *rp == '/' && stat(rp, &st) == 0) + word = rp; + + Buf_AddBytes(buf, strlen(word), word); + return (addSpace); } @@ -1983,13 +2022,12 @@ static char * VarModify(GNode *ctx, Var_Parse_State *vpstate, - const char *str, - Boolean (*modProc)(GNode *, Var_Parse_State *, char *, - Boolean, Buffer *, void *), - void *datum) -{ - Buffer buf; /* Buffer for the new string */ - Boolean addSpace; /* TRUE if need to add a space to the + const char *str, + Boolean (*modProc)(GNode *, Var_Parse_State *, char *, + Boolean, Buffer *, void *), + void *datum) { + Buffer buf; /* Buffer for the new string */ + Boolean addSpace; /* TRUE if need to add a space to the * buffer before adding the trimmed * word */ - char **av; /* word list */ - char *as; /* word list memory */ + char **av; /* word list */ + char *as; /* word list memory */ int ac, i; @@ -2000,10 +2038,10 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate, if (vpstate->oneBigWord) { - /* fake what brk_string() would do if there were only one word */ - ac = 1; - av = bmake_malloc((ac + 1) * sizeof(char *)); - as = bmake_strdup(str); - av[0] = as; - av[1] = NULL; + /* fake what brk_string() would do if there were only one word */ + ac = 1; + av = bmake_malloc((ac + 1) * sizeof(char *)); + as = bmake_strdup(str); + av[0] = as; + av[1] = NULL; } else { - av = brk_string(str, &ac, FALSE, &as); + av = brk_string(str, &ac, FALSE, &as); } @@ -2011,3 +2049,3 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate, for (i = 0; i < ac; i++) { - addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, &buf, datum); + addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, &buf, datum); } @@ -2022,6 +2060,5 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate, static int -VarWordCompare(const void *a, const void *b) -{ - int r = strcmp(*(const char * const *)a, *(const char * const *)b); - return r; +VarWordCompare(const void *a, const void *b) { + int r = strcmp(*(const char *const *) a, *(const char *const *) b); + return r; } @@ -2046,7 +2083,6 @@ VarWordCompare(const void *a, const void *b) static char * -VarOrder(const char *str, const char otype) -{ - Buffer buf; /* Buffer for the new string */ - char **av; /* word list [first word does not count] */ - char *as; /* word list memory */ +VarOrder(const char *str, const char otype) { + Buffer buf; /* Buffer for the new string */ + char **av; /* word list [first word does not count] */ + char *as; /* word list memory */ int ac, i; @@ -2058,12 +2094,12 @@ VarOrder(const char *str, const char otype) if (ac > 0) - switch (otype) { - case 's': /* sort alphabetically */ - qsort(av, ac, sizeof(char *), VarWordCompare); - break; - case 'x': /* randomize */ - { - int rndidx; - char *t; - - /* + switch (otype) { + case 's': /* sort alphabetically */ + qsort(av, ac, sizeof(char *), VarWordCompare); + break; + case 'x': /* randomize */ + { + int rndidx; + char *t; + + /* * We will use [ac..2] range for mod factors. This will produce @@ -2073,17 +2109,17 @@ VarOrder(const char *str, const char otype) */ - for (i = ac-1; i > 0; i--) { - rndidx = random() % (i + 1); - if (i != rndidx) { - t = av[i]; - av[i] = av[rndidx]; - av[rndidx] = t; - } - } - } - } /* end of switch */ + for (i = ac - 1; i > 0; i--) { + rndidx = random() % (i + 1); + if (i != rndidx) { + t = av[i]; + av[i] = av[rndidx]; + av[rndidx] = t; + } + } + } + } /* end of switch */ for (i = 0; i < ac; i++) { - Buf_AddBytes(&buf, strlen(av[i]), av[i]); - if (i != ac - 1) - Buf_AddByte(&buf, ' '); + Buf_AddBytes(&buf, strlen(av[i]), av[i]); + if (i != ac - 1) + Buf_AddByte(&buf, ' '); } @@ -2114,8 +2150,7 @@ VarOrder(const char *str, const char otype) static char * -VarUniq(const char *str) -{ - Buffer buf; /* Buffer for new string */ - char **av; /* List of words to affect */ - char *as; /* Word list memory */ - int ac, i, j; +VarUniq(const char *str) { + Buffer buf; /* Buffer for new string */ + char **av; /* List of words to affect */ + char *as; /* Word list memory */ + int ac, i, j; @@ -2125,6 +2160,6 @@ VarUniq(const char *str) if (ac > 1) { - for (j = 0, i = 1; i < ac; i++) - if (strcmp(av[i], av[j]) != 0 && (++j != i)) - av[j] = av[i]; - ac = j + 1; + for (j = 0, i = 1; i < ac; i++) + if (strcmp(av[i], av[j]) != 0 && (++j != i)) + av[j] = av[i]; + ac = j + 1; } @@ -2132,5 +2167,5 @@ VarUniq(const char *str) for (i = 0; i < ac; i++) { - Buf_AddBytes(&buf, strlen(av[i]), av[i]); - if (i != ac - 1) - Buf_AddByte(&buf, ' '); + Buf_AddBytes(&buf, strlen(av[i]), av[i]); + if (i != ac - 1) + Buf_AddByte(&buf, ' '); } @@ -2158,9 +2193,8 @@ VarUniq(const char *str) static char * -VarRange(const char *str, int ac) -{ - Buffer buf; /* Buffer for new string */ - char tmp[32]; /* each element */ - char **av; /* List of words to affect */ - char *as; /* Word list memory */ - int i, n; +VarRange(const char *str, int ac) { + Buffer buf; /* Buffer for new string */ + char tmp[32]; /* each element */ + char **av; /* List of words to affect */ + char *as; /* Word list memory */ + int i, n; @@ -2168,14 +2202,14 @@ VarRange(const char *str, int ac) if (ac > 0) { - as = NULL; - av = NULL; + as = NULL; + av = NULL; } else { - av = brk_string(str, &ac, FALSE, &as); + av = brk_string(str, &ac, FALSE, &as); } for (i = 0; i < ac; i++) { - n = snprintf(tmp, sizeof(tmp), "%d", 1 + i); - if (n >= (int)sizeof(tmp)) - break; - Buf_AddBytes(&buf, n, tmp); - if (i != ac - 1) - Buf_AddByte(&buf, ' '); + n = snprintf(tmp, sizeof(tmp), "%d", 1 + i); + if (n >= (int) sizeof(tmp)) + break; + Buf_AddBytes(&buf, n, tmp); + if (i != ac - 1) + Buf_AddByte(&buf, ' '); } @@ -2213,5 +2247,4 @@ static char * VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, - int flags, const char **tstr, int delim, int *vflags, - int *length, VarPattern *pattern) -{ + int flags, const char **tstr, int delim, int *vflags, + int *length, VarPattern *pattern) { const char *cp; @@ -2224,3 +2257,3 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, if (length == NULL) - length = &junk; + length = &junk; @@ -2237,11 +2270,11 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, for (cp = *tstr; *cp && (*cp != delim); cp++) { - if (IS_A_MATCH(cp, delim)) { - Buf_AddByte(&buf, cp[1]); - cp++; - } else if (*cp == '$') { - if (cp[1] == delim) { - if (vflags == NULL) - Buf_AddByte(&buf, *cp); - else - /* + if (IS_A_MATCH(cp, delim)) { + Buf_AddByte(&buf, cp[1]); + cp++; + } else if (*cp == '$') { + if (cp[1] == delim) { + if (vflags == NULL) + Buf_AddByte(&buf, *cp); + else + /* * Unescaped $ at end of pattern => anchor @@ -2249,10 +2282,10 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, */ - *vflags |= VAR_MATCH_END; - } else { - if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) { - char *cp2; - int len; - void *freeIt; - - /* + *vflags |= VAR_MATCH_END; + } else { + if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) { + char *cp2; + int len; + void *freeIt; + + /* * If unescaped dollar sign not before the @@ -2261,12 +2294,12 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, */ - cp2 = Var_Parse(cp, ctxt, errnum | VARF_WANTRES, &len, - &freeIt); - Buf_AddBytes(&buf, strlen(cp2), cp2); - free(freeIt); - cp += len - 1; - } else { - const char *cp2 = &cp[1]; - - if (*cp2 == PROPEN || *cp2 == BROPEN) { - /* + cp2 = Var_Parse(cp, ctxt, errnum | VARF_WANTRES, &len, + &freeIt); + Buf_AddBytes(&buf, strlen(cp2), cp2); + free(freeIt); + cp += len - 1; + } else { + const char *cp2 = &cp[1]; + + if (*cp2 == PROPEN || *cp2 == BROPEN) { + /* * Find the end of this variable reference @@ -2275,25 +2308,24 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, */ - int have = *cp2; - int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; - int depth = 1; - - for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { - if (cp2[-1] != '\\') { - if (*cp2 == have) - ++depth; - if (*cp2 == want) - --depth; - } - } - Buf_AddBytes(&buf, cp2 - cp, cp); - cp = --cp2; - } else - Buf_AddByte(&buf, *cp); - } - } - } - else if (pattern && *cp == '&') - Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs); - else - Buf_AddByte(&buf, *cp); + int have = *cp2; + int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; + int depth = 1; + + for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { + if (cp2[-1] != '\\') { + if (*cp2 == have) + ++depth; + if (*cp2 == want) + --depth; + } + } + Buf_AddBytes(&buf, cp2 - cp, cp); + cp = --cp2; + } else + Buf_AddByte(&buf, *cp); + } + } + } else if (pattern && *cp == '&') + Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs); + else + Buf_AddByte(&buf, *cp); } @@ -2301,5 +2333,5 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, if (*cp != delim) { - *tstr = cp; - *length = 0; - return NULL; + *tstr = cp; + *length = 0; + return NULL; } @@ -2310,3 +2342,3 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, if (DEBUG(VAR)) - fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr); + fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr); return rstr; @@ -2329,7 +2361,6 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, static char * -VarQuote(char *str, Boolean quoteDollar) -{ +VarQuote(char *str, Boolean quoteDollar) { - Buffer buf; - const char *newline; + Buffer buf; + const char *newline; size_t nlen; @@ -2337,3 +2368,3 @@ VarQuote(char *str, Boolean quoteDollar) if ((newline = Shell_GetNewline()) == NULL) - newline = "\\\n"; + newline = "\\\n"; nlen = strlen(newline); @@ -2343,11 +2374,11 @@ VarQuote(char *str, Boolean quoteDollar) for (; *str != '\0'; str++) { - if (*str == '\n') { - Buf_AddBytes(&buf, nlen, newline); - continue; - } - if (isspace((unsigned char)*str) || ismeta((unsigned char)*str)) - Buf_AddByte(&buf, '\\'); - Buf_AddByte(&buf, *str); - if (quoteDollar && *str == '$') - Buf_AddBytes(&buf, 2, "\\$"); + if (*str == '\n') { + Buf_AddBytes(&buf, nlen, newline); + continue; + } + if (isspace((unsigned char) *str) || ismeta((unsigned char) *str)) + Buf_AddByte(&buf, '\\'); + Buf_AddByte(&buf, *str); + if (quoteDollar && *str == '$') + Buf_AddBytes(&buf, 2, "\\$"); } @@ -2356,3 +2387,3 @@ VarQuote(char *str, Boolean quoteDollar) if (DEBUG(VAR)) - fprintf(debug_file, "QuoteMeta: [%s]\n", str); + fprintf(debug_file, "QuoteMeta: [%s]\n", str); return str; @@ -2378,11 +2409,10 @@ VarQuote(char *str, Boolean quoteDollar) static char * -VarHash(char *str) -{ - static const char hexdigits[16] = "0123456789abcdef"; - Buffer buf; - size_t len, len2; - unsigned char *ustr = (unsigned char *)str; - unsigned int h, k, c1, c2; +VarHash(char *str) { + static const char hexdigits[16] = "0123456789abcdef"; + Buffer buf; + size_t len, len2; + unsigned char *ustr = (unsigned char *) str; + unsigned int h, k, c1, c2; - h = 0x971e137bU; + h = 0x971e137bU; c1 = 0x95543787U; @@ -2391,40 +2421,40 @@ VarHash(char *str) - for (len = len2; len; ) { - k = 0; - switch (len) { - default: - k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0]; - len -= 4; - ustr += 4; - break; - case 3: - k |= (ustr[2] << 16); - case 2: - k |= (ustr[1] << 8); - case 1: - k |= ustr[0]; - len = 0; - } - c1 = c1 * 5 + 0x7b7d159cU; - c2 = c2 * 5 + 0x6bce6396U; - k *= c1; - k = (k << 11) ^ (k >> 21); - k *= c2; - h = (h << 13) ^ (h >> 19); - h = h * 5 + 0x52dce729U; - h ^= k; - } - h ^= len2; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - Buf_Init(&buf, 0); - for (len = 0; len < 8; ++len) { - Buf_AddByte(&buf, hexdigits[h & 15]); - h >>= 4; - } - - return Buf_Destroy(&buf, FALSE); + for (len = len2; len;) { + k = 0; + switch (len) { + default: + k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0]; + len -= 4; + ustr += 4; + break; + case 3: + k |= (ustr[2] << 16); + case 2: + k |= (ustr[1] << 8); + case 1: + k |= ustr[0]; + len = 0; + } + c1 = c1 * 5 + 0x7b7d159cU; + c2 = c2 * 5 + 0x6bce6396U; + k *= c1; + k = (k << 11) ^ (k >> 21); + k *= c2; + h = (h << 13) ^ (h >> 19); + h = h * 5 + 0x52dce729U; + h ^= k; + } + h ^= len2; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + Buf_Init(&buf, 0); + for (len = 0; len < 8; ++len) { + Buf_AddByte(&buf, hexdigits[h & 15]); + h >>= 4; + } + + return Buf_Destroy(&buf, FALSE); } @@ -2432,4 +2462,3 @@ VarHash(char *str) static char * -VarStrftime(const char *fmt, int zulu, time_t utc) -{ +VarStrftime(const char *fmt, int zulu, time_t utc) { char buf[BUFSIZ]; @@ -2437,7 +2466,7 @@ VarStrftime(const char *fmt, int zulu, time_t utc) if (!utc) - time(&utc); + time(&utc); if (!*fmt) - fmt = "%c"; + fmt = "%c"; strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc)); - + buf[sizeof(buf) - 1] = '\0'; @@ -2540,18 +2569,29 @@ static char * ApplyModifiers(char *nstr, const char *tstr, - int startc, int endc, - Var *v, GNode *ctxt, int flags, - int *lengthPtr, void **freePtr) -{ - const char *start; - const char *cp; /* Secondary pointer into str (place marker + int startc, int endc, + Var *v, GNode *ctxt, int flags, + int *lengthPtr, void **freePtr) { + const char *start; + const char *cp; /* Secondary pointer into str (place marker * for tstr) */ - char *newStr; /* New value to return */ - char *ep; - char termc; /* Character which terminated scan */ - int cnt; /* Used to count brace pairs when variable in +#if (defined _WIN32 && ! defined __CYGWIN__) + char *unix_nstr; + char *error; + if (nstr && strlen(nstr) > 0 && nstr[1] == ':' && (nstr[2] == '/' || nstr[2] == '\\')) { + unix_nstr = Cmd_Exec(getUnixPathCmd(nstr), &error); + } + else { + unix_nstr = nstr; + } +#else + char *unix_nstr = nstr; +#endif + char *newStr; /* New value to return */ + char *ep; + char termc; /* Character which terminated scan */ + int cnt; /* Used to count brace pairs when variable in * in parens or braces */ - char delim; - int modifier; /* that we are processing */ + char delim; + int modifier; /* that we are processing */ Var_Parse_State parsestate; /* Flags passed to helper functions */ - time_t utc; /* for VarStrftime */ + time_t utc; /* for VarStrftime */ @@ -2559,3 +2599,3 @@ ApplyModifiers(char *nstr, const char *tstr, parsestate.oneBigWord = FALSE; - parsestate.varSpace = ' '; /* word separator */ + parsestate.varSpace = ' '; /* word separator */ @@ -2565,14 +2605,14 @@ ApplyModifiers(char *nstr, const char *tstr, - if (*tstr == '$') { - /* + if (*tstr == '$') { + /* * We may have some complex modifiers in a variable. */ - void *freeIt; - char *rval; - int rlen; - int c; + void *freeIt; + char *rval; + int rlen; + int c; - rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); + rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); - /* + /* * If we have not parsed up to endc or ':', @@ -2580,68 +2620,67 @@ ApplyModifiers(char *nstr, const char *tstr, */ - if (rval != NULL && *rval && - (c = tstr[rlen]) != '\0' && - c != ':' && - c != endc) { - free(freeIt); - goto apply_mods; - } - - if (DEBUG(VAR)) { - fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", - rval, rlen, tstr, rlen, tstr + rlen); - } - - tstr += rlen; - - if (rval != NULL && *rval) { - int used; - - nstr = ApplyModifiers(nstr, rval, - 0, 0, v, ctxt, flags, &used, freePtr); - if (nstr == var_Error - || (nstr == varNoError && (flags & VARF_UNDEFERR) == 0) - || strlen(rval) != (size_t) used) { - free(freeIt); - goto out; /* error already reported */ - } - } - free(freeIt); - if (*tstr == ':') - tstr++; - else if (!*tstr && endc) { - Error("Unclosed variable specification after complex modifier (expecting '%c') for %s", endc, v->name); - goto out; - } - continue; - } - apply_mods: - if (DEBUG(VAR)) { - fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", v->name, - *tstr, nstr); - } - newStr = var_Error; - switch ((modifier = *tstr)) { - case ':': - { - if (tstr[1] == '=' || - (tstr[2] == '=' && - (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) { - /* + if (rval != NULL && *rval && + (c = tstr[rlen]) != '\0' && + c != ':' && + c != endc) { + free(freeIt); + goto apply_mods; + } + + if (DEBUG(VAR)) { + fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", + rval, rlen, tstr, rlen, tstr + rlen); + } + + tstr += rlen; + + if (rval != NULL && *rval) { + int used; + + unix_nstr = ApplyModifiers(unix_nstr, rval, + 0, 0, v, ctxt, flags, &used, freePtr); + if (unix_nstr == var_Error + || (unix_nstr == varNoError && (flags & VARF_UNDEFERR) == 0) + || strlen(rval) != (size_t) used) { + free(freeIt); + goto out; /* error already reported */ + } + } + free(freeIt); + if (*tstr == ':') + tstr++; + else if (!*tstr && endc) { + Error("Unclosed variable specification after complex modifier (expecting '%c') for %s", endc, v->name); + goto out; + } + continue; + } + apply_mods: + if (DEBUG(VAR)) { + fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", v->name, + *tstr, unix_nstr); + } + newStr = var_Error; + switch ((modifier = *tstr)) { + case ':': { + if (tstr[1] == '=' || + (tstr[2] == '=' && + (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) { + /* * "::=", "::!=", "::+=", or "::?=" */ - GNode *v_ctxt; /* context where v belongs */ - const char *emsg; - char *sv_name; - VarPattern pattern; - int how; - int vflags; - - if (v->name[0] == 0) - goto bad_modifier; - - v_ctxt = ctxt; - sv_name = NULL; - ++tstr; - if (v->flags & VAR_JUNK) { - /* + GNode *v_ctxt; /* context where v belongs */ + const char *emsg; + char *sv_name; + VarPattern pattern; + int how; + int vflags; + + if (v->name[0] == 0) + goto bad_modifier; + + v_ctxt = ctxt; + sv_name = NULL; + ++tstr; + if (v->flags & VAR_JUNK) { + /* * We need to bmake_strdup() it incase @@ -2649,140 +2688,138 @@ ApplyModifiers(char *nstr, const char *tstr, */ - sv_name = v->name; - v->name = bmake_strdup(v->name); - } else if (ctxt != VAR_GLOBAL) { - Var *gv = VarFind(v->name, ctxt, 0); - if (gv == NULL) - v_ctxt = VAR_GLOBAL; - else - VarFreeEnv(gv, TRUE); - } - - switch ((how = *tstr)) { - case '+': - case '?': - case '!': - cp = &tstr[2]; - break; - default: - cp = ++tstr; - break; - } - delim = startc == PROPEN ? PRCLOSE : BRCLOSE; - pattern.flags = 0; - - vflags = (flags & VARF_WANTRES) ? 0 : VAR_NOSUBST; - pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, - &cp, delim, &vflags, - &pattern.rightLen, - NULL); - if (v->flags & VAR_JUNK) { - /* restore original name */ - free(v->name); - v->name = sv_name; - } - if (pattern.rhs == NULL) - goto cleanup; - - termc = *--cp; - delim = '\0'; - - if (flags & VARF_WANTRES) { - switch (how) { - case '+': - Var_Append(v->name, pattern.rhs, v_ctxt); - break; - case '!': - newStr = Cmd_Exec(pattern.rhs, &emsg); - if (emsg) - Error(emsg, nstr); - else - Var_Set(v->name, newStr, v_ctxt, 0); - free(newStr); - break; - case '?': - if ((v->flags & VAR_JUNK) == 0) - break; - /* FALLTHROUGH */ - default: - Var_Set(v->name, pattern.rhs, v_ctxt, 0); - break; - } - } - free(UNCONST(pattern.rhs)); - newStr = varNoError; - break; - } - goto default_case; /* "::" */ - } - case '@': - { - VarLoop_t loop; - int vflags = VAR_NOSUBST; - - cp = ++tstr; - delim = '@'; - if ((loop.tvar = VarGetPattern(ctxt, &parsestate, flags, - &cp, delim, - &vflags, &loop.tvarLen, - NULL)) == NULL) - goto cleanup; - - if ((loop.str = VarGetPattern(ctxt, &parsestate, flags, - &cp, delim, - &vflags, &loop.strLen, - NULL)) == NULL) - goto cleanup; - - termc = *cp; - delim = '\0'; - - loop.errnum = flags & VARF_UNDEFERR; - loop.ctxt = ctxt; - newStr = VarModify(ctxt, &parsestate, nstr, VarLoopExpand, - &loop); - Var_Delete(loop.tvar, ctxt); - free(loop.tvar); - free(loop.str); - break; - } - case '_': /* remember current value */ - cp = tstr + 1; /* make sure it is set */ - if (STRMOD_MATCHX(tstr, "_", 1)) { - if (tstr[1] == '=') { - char *np; - int n; - - cp++; - n = strcspn(cp, ":)}"); - np = bmake_strndup(cp, n+1); - np[n] = '\0'; - cp = tstr + 2 + n; - Var_Set(np, nstr, ctxt, 0); - free(np); - } else { - Var_Set("_", nstr, ctxt, 0); - } - newStr = nstr; - termc = *cp; - break; - } - goto default_case; - case 'D': - case 'U': - { - Buffer buf; /* Buffer for patterns */ - int nflags; - - if (flags & VARF_WANTRES) { - int wantres; - if (*tstr == 'U') - wantres = ((v->flags & VAR_JUNK) != 0); - else - wantres = ((v->flags & VAR_JUNK) == 0); - nflags = flags & ~VARF_WANTRES; - if (wantres) - nflags |= VARF_WANTRES; - } else - nflags = flags; - /* + sv_name = v->name; + v->name = bmake_strdup(v->name); + } else if (ctxt != VAR_GLOBAL) { + Var *gv = VarFind(v->name, ctxt, 0); + if (gv == NULL) + v_ctxt = VAR_GLOBAL; + else + VarFreeEnv(gv, TRUE); + } + + switch ((how = *tstr)) { + case '+': + case '?': + case '!': + cp = &tstr[2]; + break; + default: + cp = ++tstr; + break; + } + delim = startc == PROPEN ? PRCLOSE : BRCLOSE; + pattern.flags = 0; + + vflags = (flags & VARF_WANTRES) ? 0 : VAR_NOSUBST; + pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, + &cp, delim, &vflags, + &pattern.rightLen, + NULL); + if (v->flags & VAR_JUNK) { + /* restore original name */ + free(v->name); + v->name = sv_name; + } + if (pattern.rhs == NULL) + goto cleanup; + + termc = *--cp; + delim = '\0'; + + if (flags & VARF_WANTRES) { + switch (how) { + case '+': + Var_Append(v->name, pattern.rhs, v_ctxt); + break; + case '!': + newStr = Cmd_Exec(pattern.rhs, &emsg); + if (emsg) + Error(emsg, unix_nstr); + else + Var_Set(v->name, newStr, v_ctxt, 0); + free(newStr); + break; + case '?': + if ((v->flags & VAR_JUNK) == 0) + break; + /* FALLTHROUGH */ + default: + Var_Set(v->name, pattern.rhs, v_ctxt, 0); + break; + } + } + free(UNCONST(pattern.rhs)); + newStr = varNoError; + break; + } + goto default_case; /* "::" */ + } + case '@': { + VarLoop_t loop; + int vflags = VAR_NOSUBST; + + cp = ++tstr; + delim = '@'; + if ((loop.tvar = VarGetPattern(ctxt, &parsestate, flags, + &cp, delim, + &vflags, &loop.tvarLen, + NULL)) == NULL) + goto cleanup; + + if ((loop.str = VarGetPattern(ctxt, &parsestate, flags, + &cp, delim, + &vflags, &loop.strLen, + NULL)) == NULL) + goto cleanup; + + termc = *cp; + delim = '\0'; + + loop.errnum = flags & VARF_UNDEFERR; + loop.ctxt = ctxt; + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarLoopExpand, + &loop); + Var_Delete(loop.tvar, ctxt); + free(loop.tvar); + free(loop.str); + break; + } + case '_': /* remember current value */ + cp = tstr + 1; /* make sure it is set */ + if (STRMOD_MATCHX(tstr, "_", 1)) { + if (tstr[1] == '=') { + char *np; + int n; + + cp++; + n = strcspn(cp, ":)}"); + np = bmake_strndup(cp, n + 1); + np[n] = '\0'; + cp = tstr + 2 + n; + Var_Set(np, unix_nstr, ctxt, 0); + free(np); + } else { + Var_Set("_", unix_nstr, ctxt, 0); + } + newStr = unix_nstr; + termc = *cp; + break; + } + goto default_case; + case 'D': + case 'U': { + Buffer buf; /* Buffer for patterns */ + int nflags; + + if (flags & VARF_WANTRES) { + int wantres; + if (*tstr == 'U') + wantres = ((v->flags & VAR_JUNK) != 0); + else + wantres = ((v->flags & VAR_JUNK) == 0); + nflags = flags & ~VARF_WANTRES; + if (wantres) + nflags |= VARF_WANTRES; + } else + nflags = flags; + /* * Pass through tstr looking for 1) escaped delimiters, @@ -2793,16 +2830,15 @@ ApplyModifiers(char *nstr, const char *tstr, */ - Buf_Init(&buf, 0); - for (cp = tstr + 1; - *cp != endc && *cp != ':' && *cp != '\0'; - cp++) { - if ((*cp == '\\') && - ((cp[1] == ':') || - (cp[1] == '$') || - (cp[1] == endc) || - (cp[1] == '\\'))) - { - Buf_AddByte(&buf, cp[1]); - cp++; - } else if (*cp == '$') { - /* + Buf_Init(&buf, 0); + for (cp = tstr + 1; + *cp != endc && *cp != ':' && *cp != '\0'; + cp++) { + if ((*cp == '\\') && + ((cp[1] == ':') || + (cp[1] == '$') || + (cp[1] == endc) || + (cp[1] == '\\'))) { + Buf_AddByte(&buf, cp[1]); + cp++; + } else if (*cp == '$') { + /* * If unescaped dollar sign, assume it's a @@ -2810,88 +2846,84 @@ ApplyModifiers(char *nstr, const char *tstr, */ - char *cp2; - int len; - void *freeIt; - - cp2 = Var_Parse(cp, ctxt, nflags, &len, &freeIt); - Buf_AddBytes(&buf, strlen(cp2), cp2); - free(freeIt); - cp += len - 1; - } else { - Buf_AddByte(&buf, *cp); - } - } - - termc = *cp; - - if ((v->flags & VAR_JUNK) != 0) - v->flags |= VAR_KEEP; - if (nflags & VARF_WANTRES) { - newStr = Buf_Destroy(&buf, FALSE); - } else { - newStr = nstr; - Buf_Destroy(&buf, TRUE); - } - break; - } - case 'L': - { - if ((v->flags & VAR_JUNK) != 0) - v->flags |= VAR_KEEP; - newStr = bmake_strdup(v->name); - cp = ++tstr; - termc = *tstr; - break; - } - case 'P': - { - GNode *gn; - - if ((v->flags & VAR_JUNK) != 0) - v->flags |= VAR_KEEP; - gn = Targ_FindNode(v->name, TARG_NOCREATE); - if (gn == NULL || gn->type & OP_NOPATH) { - newStr = NULL; - } else if (gn->path) { - newStr = bmake_strdup(gn->path); - } else { - newStr = Dir_FindFile(v->name, Suff_FindPath(gn)); - } - if (!newStr) { - newStr = bmake_strdup(v->name); - } - cp = ++tstr; - termc = *tstr; - break; - } - case '!': - { - const char *emsg; - VarPattern pattern; - pattern.flags = 0; - - delim = '!'; - emsg = NULL; - cp = ++tstr; - if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, - &cp, delim, - NULL, &pattern.rightLen, - NULL)) == NULL) - goto cleanup; - if (flags & VARF_WANTRES) - newStr = Cmd_Exec(pattern.rhs, &emsg); - else - newStr = varNoError; - free(UNCONST(pattern.rhs)); - if (emsg) - Error(emsg, nstr); - termc = *cp; - delim = '\0'; - if (v->flags & VAR_JUNK) { - v->flags |= VAR_KEEP; - } - break; - } - case '[': - { - /* + char *cp2; + int len; + void *freeIt; + + cp2 = Var_Parse(cp, ctxt, nflags, &len, &freeIt); + Buf_AddBytes(&buf, strlen(cp2), cp2); + free(freeIt); + cp += len - 1; + } else { + Buf_AddByte(&buf, *cp); + } + } + + termc = *cp; + + if ((v->flags & VAR_JUNK) != 0) + v->flags |= VAR_KEEP; + if (nflags & VARF_WANTRES) { + newStr = Buf_Destroy(&buf, FALSE); + } else { + newStr = unix_nstr; + Buf_Destroy(&buf, TRUE); + } + break; + } + case 'L': { + if ((v->flags & VAR_JUNK) != 0) + v->flags |= VAR_KEEP; + newStr = bmake_strdup(v->name); + cp = ++tstr; + termc = *tstr; + break; + } + case 'P': { + GNode *gn; + + if ((v->flags & VAR_JUNK) != 0) + v->flags |= VAR_KEEP; + gn = Targ_FindNode(v->name, TARG_NOCREATE); + if (gn == NULL || gn->type & OP_NOPATH) { + newStr = NULL; + } else if (gn->path) { + newStr = bmake_strdup(gn->path); + } else { + newStr = Dir_FindFile(v->name, Suff_FindPath(gn)); + } + if (!newStr) { + newStr = bmake_strdup(v->name); + } + cp = ++tstr; + termc = *tstr; + break; + } + case '!': { + const char *emsg; + VarPattern pattern; + pattern.flags = 0; + + delim = '!'; + emsg = NULL; + cp = ++tstr; + if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, + &cp, delim, + NULL, &pattern.rightLen, + NULL)) == NULL) + goto cleanup; + if (flags & VARF_WANTRES) + newStr = Cmd_Exec(pattern.rhs, &emsg); + else + newStr = varNoError; + free(UNCONST(pattern.rhs)); + if (emsg) + Error(emsg, unix_nstr); + termc = *cp; + delim = '\0'; + if (v->flags & VAR_JUNK) { + v->flags |= VAR_KEEP; + } + break; + } + case '[': { + /* * Look for the closing ']', recursively @@ -2902,26 +2934,26 @@ ApplyModifiers(char *nstr, const char *tstr, */ - char *estr; - - cp = tstr+1; /* point to char after '[' */ - delim = ']'; /* look for closing ']' */ - estr = VarGetPattern(ctxt, &parsestate, - flags, &cp, delim, - NULL, NULL, NULL); - if (estr == NULL) - goto cleanup; /* report missing ']' */ - /* now cp points just after the closing ']' */ - delim = '\0'; - if (cp[0] != ':' && cp[0] != endc) { - /* Found junk after ']' */ - free(estr); - goto bad_modifier; - } - if (estr[0] == '\0') { - /* Found empty square brackets in ":[]". */ - free(estr); - goto bad_modifier; - } else if (estr[0] == '#' && estr[1] == '\0') { - /* Found ":[#]" */ - - /* + char *estr; + + cp = tstr + 1; /* point to char after '[' */ + delim = ']'; /* look for closing ']' */ + estr = VarGetPattern(ctxt, &parsestate, + flags, &cp, delim, + NULL, NULL, NULL); + if (estr == NULL) + goto cleanup; /* report missing ']' */ + /* now cp points just after the closing ']' */ + delim = '\0'; + if (cp[0] != ':' && cp[0] != endc) { + /* Found junk after ']' */ + free(estr); + goto bad_modifier; + } + if (estr[0] == '\0') { + /* Found empty square brackets in ":[]". */ + free(estr); + goto bad_modifier; + } else if (estr[0] == '#' && estr[1] == '\0') { + /* Found ":[#]" */ + + /* * We will need enough space for the decimal @@ -2933,39 +2965,39 @@ ApplyModifiers(char *nstr, const char *tstr, */ - int newStrSize = - (sizeof(int) * CHAR_BIT + 2) / 3 + 2; - - newStr = bmake_malloc(newStrSize); - if (parsestate.oneBigWord) { - strncpy(newStr, "1", newStrSize); - } else { - /* XXX: brk_string() is a rather expensive + int newStrSize = + (sizeof(int) * CHAR_BIT + 2) / 3 + 2; + + newStr = bmake_malloc(newStrSize); + if (parsestate.oneBigWord) { + strncpy(newStr, "1", newStrSize); + } else { + /* XXX: brk_string() is a rather expensive * way of counting words. */ - char **av; - char *as; - int ac; - - av = brk_string(nstr, &ac, FALSE, &as); - snprintf(newStr, newStrSize, "%d", ac); - free(as); - free(av); - } - termc = *cp; - free(estr); - break; - } else if (estr[0] == '*' && estr[1] == '\0') { - /* Found ":[*]" */ - parsestate.oneBigWord = TRUE; - newStr = nstr; - termc = *cp; - free(estr); - break; - } else if (estr[0] == '@' && estr[1] == '\0') { - /* Found ":[@]" */ - parsestate.oneBigWord = FALSE; - newStr = nstr; - termc = *cp; - free(estr); - break; - } else { - /* + char **av; + char *as; + int ac; + + av = brk_string(unix_nstr, &ac, FALSE, &as); + snprintf(newStr, newStrSize, "%d", ac); + free(as); + free(av); + } + termc = *cp; + free(estr); + break; + } else if (estr[0] == '*' && estr[1] == '\0') { + /* Found ":[*]" */ + parsestate.oneBigWord = TRUE; + newStr = unix_nstr; + termc = *cp; + free(estr); + break; + } else if (estr[0] == '@' && estr[1] == '\0') { + /* Found ":[@]" */ + parsestate.oneBigWord = FALSE; + newStr = unix_nstr; + termc = *cp; + free(estr); + break; + } else { + /* * We expect estr to contain a single @@ -2974,28 +3006,28 @@ ApplyModifiers(char *nstr, const char *tstr, */ - VarSelectWords_t seldata = { 0, 0 }; - - seldata.start = strtol(estr, &ep, 0); - if (ep == estr) { - /* Found junk instead of a number */ - free(estr); - goto bad_modifier; - } else if (ep[0] == '\0') { - /* Found only one integer in :[N] */ - seldata.end = seldata.start; - } else if (ep[0] == '.' && ep[1] == '.' && - ep[2] != '\0') { - /* Expecting another integer after ".." */ - ep += 2; - seldata.end = strtol(ep, &ep, 0); - if (ep[0] != '\0') { - /* Found junk after ".." */ - free(estr); - goto bad_modifier; - } - } else { - /* Found junk instead of ".." */ - free(estr); - goto bad_modifier; - } - /* + VarSelectWords_t seldata = {0, 0}; + + seldata.start = strtol(estr, &ep, 0); + if (ep == estr) { + /* Found junk instead of a number */ + free(estr); + goto bad_modifier; + } else if (ep[0] == '\0') { + /* Found only one integer in :[N] */ + seldata.end = seldata.start; + } else if (ep[0] == '.' && ep[1] == '.' && + ep[2] != '\0') { + /* Expecting another integer after ".." */ + ep += 2; + seldata.end = strtol(ep, &ep, 0); + if (ep[0] != '\0') { + /* Found junk after ".." */ + free(estr); + goto bad_modifier; + } + } else { + /* Found junk instead of ".." */ + free(estr); + goto bad_modifier; + } + /* * Now seldata is properly filled in, @@ -3004,16 +3036,16 @@ ApplyModifiers(char *nstr, const char *tstr, */ - if (seldata.start == 0 && seldata.end == 0) { - /* ":[0]" or perhaps ":[0..0]" */ - parsestate.oneBigWord = TRUE; - newStr = nstr; - termc = *cp; - free(estr); - break; - } else if (seldata.start == 0 || - seldata.end == 0) { - /* ":[0..N]" or ":[N..0]" */ - free(estr); - goto bad_modifier; - } - /* + if (seldata.start == 0 && seldata.end == 0) { + /* ":[0]" or perhaps ":[0..0]" */ + parsestate.oneBigWord = TRUE; + newStr = unix_nstr; + termc = *cp; + free(estr); + break; + } else if (seldata.start == 0 || + seldata.end == 0) { + /* ":[0..N]" or ":[N..0]" */ + free(estr); + goto bad_modifier; + } + /* * Normal case: select the words @@ -3021,59 +3053,58 @@ ApplyModifiers(char *nstr, const char *tstr, */ - newStr = VarSelectWords(ctxt, &parsestate, - nstr, &seldata); - - termc = *cp; - free(estr); - break; - } - - } - case 'g': - cp = tstr + 1; /* make sure it is set */ - if (STRMOD_MATCHX(tstr, "gmtime", 6)) { - if (tstr[6] == '=') { - utc = strtoul(&tstr[7], &ep, 10); - cp = ep; - } else { - utc = 0; - cp = tstr + 6; - } - newStr = VarStrftime(nstr, 1, utc); - termc = *cp; - } else { - goto default_case; - } - break; - case 'h': - cp = tstr + 1; /* make sure it is set */ - if (STRMOD_MATCH(tstr, "hash", 4)) { - newStr = VarHash(nstr); - cp = tstr + 4; - termc = *cp; - } else { - goto default_case; - } - break; - case 'l': - cp = tstr + 1; /* make sure it is set */ - if (STRMOD_MATCHX(tstr, "localtime", 9)) { - if (tstr[9] == '=') { - utc = strtoul(&tstr[10], &ep, 10); - cp = ep; - } else { - utc = 0; - cp = tstr + 9; - } - newStr = VarStrftime(nstr, 0, utc); - termc = *cp; - } else { - goto default_case; - } - break; - case 't': - { - cp = tstr + 1; /* make sure it is set */ - if (tstr[1] != endc && tstr[1] != ':') { - if (tstr[1] == 's') { - /* + newStr = VarSelectWords(ctxt, &parsestate, + unix_nstr, &seldata); + + termc = *cp; + free(estr); + break; + } + + } + case 'g': + cp = tstr + 1; /* make sure it is set */ + if (STRMOD_MATCHX(tstr, "gmtime", 6)) { + if (tstr[6] == '=') { + utc = strtoul(&tstr[7], &ep, 10); + cp = ep; + } else { + utc = 0; + cp = tstr + 6; + } + newStr = VarStrftime(unix_nstr, 1, utc); + termc = *cp; + } else { + goto default_case; + } + break; + case 'h': + cp = tstr + 1; /* make sure it is set */ + if (STRMOD_MATCH(tstr, "hash", 4)) { + newStr = VarHash(unix_nstr); + cp = tstr + 4; + termc = *cp; + } else { + goto default_case; + } + break; + case 'l': + cp = tstr + 1; /* make sure it is set */ + if (STRMOD_MATCHX(tstr, "localtime", 9)) { + if (tstr[9] == '=') { + utc = strtoul(&tstr[10], &ep, 10); + cp = ep; + } else { + utc = 0; + cp = tstr + 9; + } + newStr = VarStrftime(unix_nstr, 0, utc); + termc = *cp; + } else { + goto default_case; + } + break; + case 't': { + cp = tstr + 1; /* make sure it is set */ + if (tstr[1] != endc && tstr[1] != ':') { + if (tstr[1] == 's') { + /* * Use the char (if any) at tstr[2] @@ -3081,61 +3112,61 @@ ApplyModifiers(char *nstr, const char *tstr, */ - VarPattern pattern; + VarPattern pattern; - if (tstr[2] != endc && - (tstr[3] == endc || tstr[3] == ':')) { - /* ":ts" or + if (tstr[2] != endc && + (tstr[3] == endc || tstr[3] == ':')) { + /* ":ts" or * ":ts:" */ - parsestate.varSpace = tstr[2]; - cp = tstr + 3; - } else if (tstr[2] == endc || tstr[2] == ':') { - /* ":ts" or ":ts:" */ - parsestate.varSpace = 0; /* no separator */ - cp = tstr + 2; - } else if (tstr[2] == '\\') { - const char *xp = &tstr[3]; - int base = 8; /* assume octal */ - - switch (tstr[3]) { - case 'n': - parsestate.varSpace = '\n'; - cp = tstr + 4; - break; - case 't': - parsestate.varSpace = '\t'; - cp = tstr + 4; - break; - case 'x': - base = 16; - xp++; - goto get_numeric; - case '0': - base = 0; - goto get_numeric; - default: - if (isdigit((unsigned char)tstr[3])) { - - get_numeric: - parsestate.varSpace = - strtoul(xp, &ep, base); - if (*ep != ':' && *ep != endc) - goto bad_modifier; - cp = ep; - } else { - /* + parsestate.varSpace = tstr[2]; + cp = tstr + 3; + } else if (tstr[2] == endc || tstr[2] == ':') { + /* ":ts" or ":ts:" */ + parsestate.varSpace = 0; /* no separator */ + cp = tstr + 2; + } else if (tstr[2] == '\\') { + const char *xp = &tstr[3]; + int base = 8; /* assume octal */ + + switch (tstr[3]) { + case 'n': + parsestate.varSpace = '\n'; + cp = tstr + 4; + break; + case 't': + parsestate.varSpace = '\t'; + cp = tstr + 4; + break; + case 'x': + base = 16; + xp++; + goto get_numeric; + case '0': + base = 0; + goto get_numeric; + default: + if (isdigit((unsigned char) tstr[3])) { + + get_numeric: + parsestate.varSpace = + strtoul(xp, &ep, base); + if (*ep != ':' && *ep != endc) + goto bad_modifier; + cp = ep; + } else { + /* * ":ts". */ - goto bad_modifier; - } - break; - } - } else { - /* + goto bad_modifier; + } + break; + } + } else { + /* * Found ":ts". */ - goto bad_modifier; - } + goto bad_modifier; + } - termc = *cp; + termc = *cp; - /* + /* * We cannot be certain that VarModify @@ -3146,11 +3177,11 @@ ApplyModifiers(char *nstr, const char *tstr, */ - pattern.flags = VAR_SUB_ONE; - pattern.lhs = pattern.rhs = "\032"; - pattern.leftLen = pattern.rightLen = 1; - - newStr = VarModify(ctxt, &parsestate, nstr, - VarSubstitute, - &pattern); - } else if (tstr[2] == endc || tstr[2] == ':') { - /* + pattern.flags = VAR_SUB_ONE; + pattern.lhs = pattern.rhs = "\032"; + pattern.leftLen = pattern.rightLen = 1; + + newStr = VarModify(ctxt, &parsestate, unix_nstr, + VarSubstitute, + &pattern); + } else if (tstr[2] == endc || tstr[2] == ':') { + /* * Check for two-character options: @@ -3158,57 +3189,56 @@ ApplyModifiers(char *nstr, const char *tstr, */ - if (tstr[1] == 'A') { /* absolute path */ - newStr = VarModify(ctxt, &parsestate, nstr, - VarRealpath, NULL); - cp = tstr + 2; - termc = *cp; - } else if (tstr[1] == 'u') { - char *dp = bmake_strdup(nstr); - for (newStr = dp; *dp; dp++) - *dp = toupper((unsigned char)*dp); - cp = tstr + 2; - termc = *cp; - } else if (tstr[1] == 'l') { - char *dp = bmake_strdup(nstr); - for (newStr = dp; *dp; dp++) - *dp = tolower((unsigned char)*dp); - cp = tstr + 2; - termc = *cp; - } else if (tstr[1] == 'W' || tstr[1] == 'w') { - parsestate.oneBigWord = (tstr[1] == 'W'); - newStr = nstr; - cp = tstr + 2; - termc = *cp; - } else { - /* Found ":t:" or + if (tstr[1] == 'A') { /* absolute path */ + newStr = VarModify(ctxt, &parsestate, unix_nstr, + VarRealpath, NULL); + cp = tstr + 2; + termc = *cp; + } else if (tstr[1] == 'u') { + char *dp = bmake_strdup(unix_nstr); + for (newStr = dp; *dp; dp++) + *dp = toupper((unsigned char) *dp); + cp = tstr + 2; + termc = *cp; + } else if (tstr[1] == 'l') { + char *dp = bmake_strdup(unix_nstr); + for (newStr = dp; *dp; dp++) + *dp = tolower((unsigned char) *dp); + cp = tstr + 2; + termc = *cp; + } else if (tstr[1] == 'W' || tstr[1] == 'w') { + parsestate.oneBigWord = (tstr[1] == 'W'); + newStr = unix_nstr; + cp = tstr + 2; + termc = *cp; + } else { + /* Found ":t:" or * ":t". */ - goto bad_modifier; - } - } else { - /* + goto bad_modifier; + } + } else { + /* * Found ":t". */ - goto bad_modifier; - } - } else { - /* + goto bad_modifier; + } + } else { + /* * Found ":t" or ":t:". */ - goto bad_modifier; - } - break; - } - case 'N': - case 'M': - { - char *pattern; - const char *endpat; /* points just after end of pattern */ - char *cp2; - Boolean copy; /* pattern should be, or has been, copied */ - Boolean needSubst; - int nest; - - copy = FALSE; - needSubst = FALSE; - nest = 1; - /* + goto bad_modifier; + } + break; + } + case 'N': + case 'M': { + char *pattern; + const char *endpat; /* points just after end of pattern */ + char *cp2; + Boolean copy; /* pattern should be, or has been, copied */ + Boolean needSubst; + int nest; + + copy = FALSE; + needSubst = FALSE; + nest = 1; + /* * In the loop below, ignore ':' unless we are at @@ -3218,30 +3248,29 @@ ApplyModifiers(char *nstr, const char *tstr, */ - for (cp = tstr + 1; - *cp != '\0' && !(*cp == ':' && nest == 1); - cp++) - { - if (*cp == '\\' && - (cp[1] == ':' || - cp[1] == endc || cp[1] == startc)) { - if (!needSubst) { - copy = TRUE; - } - cp++; - continue; - } - if (*cp == '$') { - needSubst = TRUE; - } - if (*cp == '(' || *cp == '{') - ++nest; - if (*cp == ')' || *cp == '}') { - --nest; - if (nest == 0) - break; - } - } - termc = *cp; - endpat = cp; - if (copy) { - /* + for (cp = tstr + 1; + *cp != '\0' && !(*cp == ':' && nest == 1); + cp++) { + if (*cp == '\\' && + (cp[1] == ':' || + cp[1] == endc || cp[1] == startc)) { + if (!needSubst) { + copy = TRUE; + } + cp++; + continue; + } + if (*cp == '$') { + needSubst = TRUE; + } + if (*cp == '(' || *cp == '{') + ++nest; + if (*cp == ')' || *cp == '}') { + --nest; + if (nest == 0) + break; + } + } + termc = *cp; + endpat = cp; + if (copy) { + /* * Need to compress the \:'s out of the pattern, so @@ -3252,17 +3281,16 @@ ApplyModifiers(char *nstr, const char *tstr, */ - pattern = bmake_malloc(cp - tstr); - for (cp2 = pattern, cp = tstr + 1; - cp < endpat; - cp++, cp2++) - { - if ((*cp == '\\') && (cp+1 < endpat) && - (cp[1] == ':' || cp[1] == endc)) { - cp++; - } - *cp2 = *cp; - } - *cp2 = '\0'; - endpat = cp2; - } else { - /* + pattern = bmake_malloc(cp - tstr); + for (cp2 = pattern, cp = tstr + 1; + cp < endpat; + cp++, cp2++) { + if ((*cp == '\\') && (cp + 1 < endpat) && + (cp[1] == ':' || cp[1] == endc)) { + cp++; + } + *cp2 = *cp; + } + *cp2 = '\0'; + endpat = cp2; + } else { + /* * Either Var_Subst or VarModify will need a @@ -3270,6 +3298,6 @@ ApplyModifiers(char *nstr, const char *tstr, */ - pattern = bmake_strndup(tstr+1, endpat - (tstr + 1)); - } - if (needSubst) { - /* + pattern = bmake_strndup(tstr + 1, endpat - (tstr + 1)); + } + if (needSubst) { + /* * pattern contains embedded '$', so use Var_Subst to @@ -3277,30 +3305,29 @@ ApplyModifiers(char *nstr, const char *tstr, */ - cp2 = pattern; - pattern = Var_Subst(NULL, cp2, ctxt, flags | VARF_WANTRES); - free(cp2); - } - if (DEBUG(VAR)) - fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", - v->name, nstr, pattern); - if (*tstr == 'M') { - newStr = VarModify(ctxt, &parsestate, nstr, VarMatch, - pattern); - } else { - newStr = VarModify(ctxt, &parsestate, nstr, VarNoMatch, - pattern); - } - free(pattern); - break; - } - case 'S': - { - VarPattern pattern; - Var_Parse_State tmpparsestate; - - pattern.flags = 0; - tmpparsestate = parsestate; - delim = tstr[1]; - tstr += 2; - - /* + cp2 = pattern; + pattern = Var_Subst(NULL, cp2, ctxt, flags | VARF_WANTRES); + free(cp2); + } + if (DEBUG(VAR)) + fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", + v->name, unix_nstr, pattern); + if (*tstr == 'M') { + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarMatch, + pattern); + } else { + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarNoMatch, + pattern); + } + free(pattern); + break; + } + case 'S': { + VarPattern pattern; + Var_Parse_State tmpparsestate; + + pattern.flags = 0; + tmpparsestate = parsestate; + delim = tstr[1]; + tstr += 2; + + /* * If pattern begins with '^', it is anchored to the @@ -3308,22 +3335,22 @@ ApplyModifiers(char *nstr, const char *tstr, */ - if (*tstr == '^') { - pattern.flags |= VAR_MATCH_START; - tstr += 1; - } - - cp = tstr; - if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, - &cp, delim, - &pattern.flags, - &pattern.leftLen, - NULL)) == NULL) - goto cleanup; - - if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, - &cp, delim, NULL, - &pattern.rightLen, - &pattern)) == NULL) - goto cleanup; - - /* + if (*tstr == '^') { + pattern.flags |= VAR_MATCH_START; + tstr += 1; + } + + cp = tstr; + if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, + &cp, delim, + &pattern.flags, + &pattern.leftLen, + NULL)) == NULL) + goto cleanup; + + if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, + &cp, delim, NULL, + &pattern.rightLen, + &pattern)) == NULL) + goto cleanup; + + /* * Check for global substitution. If 'g' after the final @@ -3332,271 +3359,268 @@ ApplyModifiers(char *nstr, const char *tstr, */ - for (;; cp++) { - switch (*cp) { - case 'g': - pattern.flags |= VAR_SUB_GLOBAL; - continue; - case '1': - pattern.flags |= VAR_SUB_ONE; - continue; - case 'W': - tmpparsestate.oneBigWord = TRUE; - continue; - } - break; - } - - termc = *cp; - newStr = VarModify(ctxt, &tmpparsestate, nstr, - VarSubstitute, - &pattern); - - /* + for (;; cp++) { + switch (*cp) { + case 'g': + pattern.flags |= VAR_SUB_GLOBAL; + continue; + case '1': + pattern.flags |= VAR_SUB_ONE; + continue; + case 'W': + tmpparsestate.oneBigWord = TRUE; + continue; + } + break; + } + + termc = *cp; + newStr = VarModify(ctxt, &tmpparsestate, unix_nstr, + VarSubstitute, + &pattern); + + /* * Free the two strings. */ - free(UNCONST(pattern.lhs)); - free(UNCONST(pattern.rhs)); - delim = '\0'; - break; - } - case '?': - { - VarPattern pattern; - Boolean value; - int cond_rc; - int lhs_flags, rhs_flags; - - /* find ':', and then substitute accordingly */ - if (flags & VARF_WANTRES) { - cond_rc = Cond_EvalExpression(NULL, v->name, &value, 0, FALSE); - if (cond_rc == COND_INVALID) { - lhs_flags = rhs_flags = VAR_NOSUBST; - } else if (value) { - lhs_flags = 0; - rhs_flags = VAR_NOSUBST; - } else { - lhs_flags = VAR_NOSUBST; - rhs_flags = 0; - } - } else { - /* we are just consuming and discarding */ - cond_rc = value = 0; - lhs_flags = rhs_flags = VAR_NOSUBST; - } - pattern.flags = 0; - - cp = ++tstr; - delim = ':'; - if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, - &cp, delim, &lhs_flags, - &pattern.leftLen, - NULL)) == NULL) - goto cleanup; - - /* BROPEN or PROPEN */ - delim = endc; - if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, - &cp, delim, &rhs_flags, - &pattern.rightLen, - NULL)) == NULL) - goto cleanup; - - termc = *--cp; - delim = '\0'; - if (cond_rc == COND_INVALID) { - Error("Bad conditional expression `%s' in %s?%s:%s", - v->name, v->name, pattern.lhs, pattern.rhs); - goto cleanup; - } - - if (value) { - newStr = UNCONST(pattern.lhs); - free(UNCONST(pattern.rhs)); - } else { - newStr = UNCONST(pattern.rhs); - free(UNCONST(pattern.lhs)); - } - if (v->flags & VAR_JUNK) { - v->flags |= VAR_KEEP; - } - break; - } + free(UNCONST(pattern.lhs)); + free(UNCONST(pattern.rhs)); + delim = '\0'; + break; + } + case '?': { + VarPattern pattern; + Boolean value; + int cond_rc; + int lhs_flags, rhs_flags; + + /* find ':', and then substitute accordingly */ + if (flags & VARF_WANTRES) { + cond_rc = Cond_EvalExpression(NULL, v->name, &value, 0, FALSE); + if (cond_rc == COND_INVALID) { + lhs_flags = rhs_flags = VAR_NOSUBST; + } else if (value) { + lhs_flags = 0; + rhs_flags = VAR_NOSUBST; + } else { + lhs_flags = VAR_NOSUBST; + rhs_flags = 0; + } + } else { + /* we are just consuming and discarding */ + cond_rc = value = 0; + lhs_flags = rhs_flags = VAR_NOSUBST; + } + pattern.flags = 0; + + cp = ++tstr; + delim = ':'; + if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, + &cp, delim, &lhs_flags, + &pattern.leftLen, + NULL)) == NULL) + goto cleanup; + + /* BROPEN or PROPEN */ + delim = endc; + if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, + &cp, delim, &rhs_flags, + &pattern.rightLen, + NULL)) == NULL) + goto cleanup; + + termc = *--cp; + delim = '\0'; + if (cond_rc == COND_INVALID) { + Error("Bad conditional expression `%s' in %s?%s:%s", + v->name, v->name, pattern.lhs, pattern.rhs); + goto cleanup; + } + + if (value) { + newStr = UNCONST(pattern.lhs); + free(UNCONST(pattern.rhs)); + } else { + newStr = UNCONST(pattern.rhs); + free(UNCONST(pattern.lhs)); + } + if (v->flags & VAR_JUNK) { + v->flags |= VAR_KEEP; + } + break; + } #ifndef NO_REGEX - case 'C': - { - VarREPattern pattern; - char *re; - int error; - Var_Parse_State tmpparsestate; - - pattern.flags = 0; - tmpparsestate = parsestate; - delim = tstr[1]; - tstr += 2; - - cp = tstr; - - if ((re = VarGetPattern(ctxt, &parsestate, flags, &cp, delim, - NULL, NULL, NULL)) == NULL) - goto cleanup; - - if ((pattern.replace = VarGetPattern(ctxt, &parsestate, - flags, &cp, delim, NULL, - NULL, NULL)) == NULL){ - free(re); - goto cleanup; - } - - for (;; cp++) { - switch (*cp) { - case 'g': - pattern.flags |= VAR_SUB_GLOBAL; - continue; - case '1': - pattern.flags |= VAR_SUB_ONE; - continue; - case 'W': - tmpparsestate.oneBigWord = TRUE; - continue; - } - break; - } - - termc = *cp; - - error = regcomp(&pattern.re, re, REG_EXTENDED); - free(re); - if (error) { - *lengthPtr = cp - start + 1; - VarREError(error, &pattern.re, "RE substitution error"); - free(pattern.replace); - goto cleanup; - } - - pattern.nsub = pattern.re.re_nsub + 1; - if (pattern.nsub < 1) - pattern.nsub = 1; - if (pattern.nsub > 10) - pattern.nsub = 10; - pattern.matches = bmake_malloc(pattern.nsub * - sizeof(regmatch_t)); - newStr = VarModify(ctxt, &tmpparsestate, nstr, - VarRESubstitute, - &pattern); - regfree(&pattern.re); - free(pattern.replace); - free(pattern.matches); - delim = '\0'; - break; - } + case 'C': { + VarREPattern pattern; + char *re; + int error; + Var_Parse_State tmpparsestate; + + pattern.flags = 0; + tmpparsestate = parsestate; + delim = tstr[1]; + tstr += 2; + + cp = tstr; + + if ((re = VarGetPattern(ctxt, &parsestate, flags, &cp, delim, + NULL, NULL, NULL)) == NULL) + goto cleanup; + + if ((pattern.replace = VarGetPattern(ctxt, &parsestate, + flags, &cp, delim, NULL, + NULL, NULL)) == NULL) { + free(re); + goto cleanup; + } + + for (;; cp++) { + switch (*cp) { + case 'g': + pattern.flags |= VAR_SUB_GLOBAL; + continue; + case '1': + pattern.flags |= VAR_SUB_ONE; + continue; + case 'W': + tmpparsestate.oneBigWord = TRUE; + continue; + } + break; + } + + termc = *cp; + + error = regcomp(&pattern.re, re, REG_EXTENDED); + free(re); + if (error) { + *lengthPtr = cp - start + 1; + VarREError(error, &pattern.re, "RE substitution error"); + free(pattern.replace); + goto cleanup; + } + + pattern.nsub = pattern.re.re_nsub + 1; + if (pattern.nsub < 1) + pattern.nsub = 1; + if (pattern.nsub > 10) + pattern.nsub = 10; + pattern.matches = bmake_malloc(pattern.nsub * + sizeof(regmatch_t)); + newStr = VarModify(ctxt, &tmpparsestate, unix_nstr, + VarRESubstitute, + &pattern); + regfree(&pattern.re); + free(pattern.replace); + free(pattern.matches); + delim = '\0'; + break; + } #endif - case 'q': - case 'Q': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarQuote(nstr, modifier == 'q'); - cp = tstr + 1; - termc = *cp; - break; - } - goto default_case; - case 'T': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(ctxt, &parsestate, nstr, VarTail, - NULL); - cp = tstr + 1; - termc = *cp; - break; - } - goto default_case; - case 'H': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(ctxt, &parsestate, nstr, VarHead, - NULL); - cp = tstr + 1; - termc = *cp; - break; - } - goto default_case; - case 'E': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(ctxt, &parsestate, nstr, VarSuffix, - NULL); - cp = tstr + 1; - termc = *cp; - break; - } - goto default_case; - case 'R': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarModify(ctxt, &parsestate, nstr, VarRoot, - NULL); - cp = tstr + 1; - termc = *cp; - break; - } - goto default_case; - case 'r': - cp = tstr + 1; /* make sure it is set */ - if (STRMOD_MATCHX(tstr, "range", 5)) { - int n; - - if (tstr[5] == '=') { - n = strtoul(&tstr[6], &ep, 10); - cp = ep; - } else { - n = 0; - cp = tstr + 5; - } - newStr = VarRange(nstr, n); - termc = *cp; - break; - } - goto default_case; - case 'O': - { - char otype; - - cp = tstr + 1; /* skip to the rest in any case */ - if (tstr[1] == endc || tstr[1] == ':') { - otype = 's'; - termc = *cp; - } else if ( (tstr[1] == 'x') && - (tstr[2] == endc || tstr[2] == ':') ) { - otype = tstr[1]; - cp = tstr + 2; - termc = *cp; - } else { - goto bad_modifier; - } - newStr = VarOrder(nstr, otype); - break; - } - case 'u': - if (tstr[1] == endc || tstr[1] == ':') { - newStr = VarUniq(nstr); - cp = tstr + 1; - termc = *cp; - break; - } - goto default_case; + case 'q': + case 'Q': + if (tstr[1] == endc || tstr[1] == ':') { + newStr = VarQuote(unix_nstr, modifier == 'q'); + cp = tstr + 1; + termc = *cp; + break; + } + goto default_case; + case 'T': + if (tstr[1] == endc || tstr[1] == ':') { + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarTail, + NULL); + cp = tstr + 1; + termc = *cp; + break; + } + goto default_case; + case 'H': + if (tstr[1] == endc || tstr[1] == ':') { + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarHead, + NULL); + cp = tstr + 1; + termc = *cp; + break; + } + goto default_case; + case 'E': + if (tstr[1] == endc || tstr[1] == ':') { + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarSuffix, + NULL); + cp = tstr + 1; + termc = *cp; + break; + } + goto default_case; + case 'R': + if (tstr[1] == endc || tstr[1] == ':') { + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarRoot, + NULL); + cp = tstr + 1; + termc = *cp; + break; + } + goto default_case; + case 'r': + cp = tstr + 1; /* make sure it is set */ + if (STRMOD_MATCHX(tstr, "range", 5)) { + int n; + + if (tstr[5] == '=') { + n = strtoul(&tstr[6], &ep, 10); + cp = ep; + } else { + n = 0; + cp = tstr + 5; + } + newStr = VarRange(unix_nstr, n); + termc = *cp; + break; + } + goto default_case; + case 'O': { + char otype; + + cp = tstr + 1; /* skip to the rest in any case */ + if (tstr[1] == endc || tstr[1] == ':') { + otype = 's'; + termc = *cp; + } else if ((tstr[1] == 'x') && + (tstr[2] == endc || tstr[2] == ':')) { + otype = tstr[1]; + cp = tstr + 2; + termc = *cp; + } else { + goto bad_modifier; + } + newStr = VarOrder(unix_nstr, otype); + break; + } + case 'u': + if (tstr[1] == endc || tstr[1] == ':') { + newStr = VarUniq(unix_nstr); + cp = tstr + 1; + termc = *cp; + break; + } + goto default_case; #ifdef SUNSHCMD - case 's': - if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { - const char *emsg; - if (flags & VARF_WANTRES) { - newStr = Cmd_Exec(nstr, &emsg); - if (emsg) - Error(emsg, nstr); - } else - newStr = varNoError; - cp = tstr + 2; - termc = *cp; - break; - } - goto default_case; + case 's': + if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { + const char *emsg; + if (flags & VARF_WANTRES) { + newStr = Cmd_Exec(unix_nstr, &emsg); + if (emsg) + Error(emsg, unix_nstr); + } else + newStr = varNoError; + cp = tstr + 2; + termc = *cp; + break; + } + goto default_case; #endif - default: - default_case: - { + default: + default_case: + { #ifdef SYSVVARSUB - /* + /* * This can either be a bogus modifier or a System-V @@ -3604,8 +3628,8 @@ ApplyModifiers(char *nstr, const char *tstr, */ - VarPattern pattern; - Boolean eqFound; + VarPattern pattern; + Boolean eqFound; - pattern.flags = 0; - eqFound = FALSE; - /* + pattern.flags = 0; + eqFound = FALSE; + /* * First we make a pass through the string trying @@ -3614,19 +3638,18 @@ ApplyModifiers(char *nstr, const char *tstr, */ - cp = tstr; - cnt = 1; - while (*cp != '\0' && cnt) { - if (*cp == '=') { - eqFound = TRUE; - /* continue looking for endc */ - } - else if (*cp == endc) - cnt--; - else if (*cp == startc) - cnt++; - if (cnt) - cp++; - } - if (*cp == endc && eqFound) { - - /* + cp = tstr; + cnt = 1; + while (*cp != '\0' && cnt) { + if (*cp == '=') { + eqFound = TRUE; + /* continue looking for endc */ + } else if (*cp == endc) + cnt--; + else if (*cp == startc) + cnt++; + if (cnt) + cp++; + } + if (*cp == endc && eqFound) { + + /* * Now we break this sucker into the lhs and @@ -3634,15 +3657,15 @@ ApplyModifiers(char *nstr, const char *tstr, */ - delim='='; - cp = tstr; - if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, - flags, &cp, delim, &pattern.flags, - &pattern.leftLen, NULL)) == NULL) - goto cleanup; - delim = endc; - if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, - flags, &cp, delim, NULL, &pattern.rightLen, - &pattern)) == NULL) - goto cleanup; - - /* + delim = '='; + cp = tstr; + if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, + flags, &cp, delim, &pattern.flags, + &pattern.leftLen, NULL)) == NULL) + goto cleanup; + delim = endc; + if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, + flags, &cp, delim, NULL, &pattern.rightLen, + &pattern)) == NULL) + goto cleanup; + + /* * SYSV modifications happen through the whole @@ -3650,62 +3673,63 @@ ApplyModifiers(char *nstr, const char *tstr, */ - termc = *--cp; - delim = '\0'; - if (pattern.leftLen == 0 && *nstr == '\0') { - newStr = nstr; /* special case */ - } else { - newStr = VarModify(ctxt, &parsestate, nstr, - VarSYSVMatch, - &pattern); - } - free(UNCONST(pattern.lhs)); - free(UNCONST(pattern.rhs)); - } else + termc = *--cp; + delim = '\0'; + if (pattern.leftLen == 0 && *unix_nstr == '\0') { + newStr = unix_nstr; /* special case */ + } else { + newStr = VarModify(ctxt, &parsestate, unix_nstr, + VarSYSVMatch, + &pattern); + } + free(UNCONST(pattern.lhs)); + free(UNCONST(pattern.rhs)); + } else #endif - { - Error("Unknown modifier '%c'", *tstr); - for (cp = tstr+1; - *cp != ':' && *cp != endc && *cp != '\0'; - cp++) - continue; - termc = *cp; - newStr = var_Error; - } - } - } - if (DEBUG(VAR)) { - fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", - v->name, modifier, newStr); - } - - if (newStr != nstr) { - if (*freePtr) { - free(nstr); - *freePtr = NULL; - } - nstr = newStr; - if (nstr != var_Error && nstr != varNoError) { - *freePtr = nstr; - } - } - if (termc == '\0' && endc != '\0') { - Error("Unclosed variable specification (expecting '%c') for \"%s\" (value \"%s\") modifier %c", endc, v->name, nstr, modifier); - } else if (termc == ':') { - cp++; - } - tstr = cp; - } - out: + { + Error("Unknown modifier '%c'", *tstr); + for (cp = tstr + 1; + *cp != ':' && *cp != endc && *cp != '\0'; + cp++) + continue; + termc = *cp; + newStr = var_Error; + } + } + } + if (DEBUG(VAR)) { + fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", + v->name, modifier, newStr); + } + + if (newStr != unix_nstr) { + if (*freePtr) { + free(unix_nstr); + *freePtr = NULL; + } + unix_nstr = newStr; + if (unix_nstr != var_Error && unix_nstr != varNoError) { + *freePtr = unix_nstr; + } + } + if (termc == '\0' && endc != '\0') { + Error("Unclosed variable specification (expecting '%c') for \"%s\" (value \"%s\") modifier %c", endc, + v->name, unix_nstr, modifier); + } else if (termc == ':') { + cp++; + } + tstr = cp; + } + out: *lengthPtr = tstr - start; - return (nstr); + return (unix_nstr); - bad_modifier: + bad_modifier: /* "{(" */ - Error("Bad modifier `:%.*s' for %s", (int)strcspn(tstr, ":)}"), tstr, - v->name); + Error("Bad modifier `:%.*s' for %s", (int) strcspn(tstr, ":)}"), tstr, + v->name); - cleanup: + cleanup: *lengthPtr = cp - start; if (delim != '\0') - Error("Unclosed substitution for %s (%c missing)", - v->name, delim); + Error("Unclosed substitution for %s (%c missing)", + v->name, delim); free(*freePtr); @@ -3747,15 +3771,14 @@ char * Var_Parse(const char *str, GNode *ctxt, int flags, - int *lengthPtr, void **freePtr) -{ - const char *tstr; /* Pointer into str */ - Var *v; /* Variable in invocation */ - Boolean haveModifier;/* TRUE if have modifiers for the variable */ - char endc; /* Ending character when variable in parens + int *lengthPtr, void **freePtr) { + const char *tstr; /* Pointer into str */ + Var *v; /* Variable in invocation */ + Boolean haveModifier;/* TRUE if have modifiers for the variable */ + char endc; /* Ending character when variable in parens * or braces */ - char startc; /* Starting character when variable in parens + char startc; /* Starting character when variable in parens * or braces */ - int vlen; /* Length of variable name */ - const char *start; /* Points to original start of str */ - char *nstr; /* New string, used during expansion */ - Boolean dynamic; /* TRUE if the variable is local and we're + int vlen; /* Length of variable name */ + const char *start; /* Points to original start of str */ + char *nstr; /* New string, used during expansion */ + Boolean dynamic; /* TRUE if the variable is local and we're * expanding it in a non-local context. This @@ -3763,4 +3786,4 @@ Var_Parse(const char *str, GNode *ctxt, int flags, * result is just the invocation, unaltered */ - const char *extramodifiers; /* extra modifiers to apply first */ - char name[2]; + const char *extramodifiers; /* extra modifiers to apply first */ + char name[2]; @@ -3773,3 +3796,3 @@ Var_Parse(const char *str, GNode *ctxt, int flags, if (startc != PROPEN && startc != BROPEN) { - /* + /* * If it's not bounded by braces of some sort, life is much simpler. @@ -3779,16 +3802,16 @@ Var_Parse(const char *str, GNode *ctxt, int flags, - /* Error out some really stupid names */ - if (startc == '\0' || strchr(")}:$", startc)) { - *lengthPtr = 1; - return var_Error; - } - name[0] = startc; - name[1] = '\0'; + /* Error out some really stupid names */ + if (startc == '\0' || strchr(")}:$", startc)) { + *lengthPtr = 1; + return var_Error; + } + name[0] = startc; + name[1] = '\0'; - v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); - if (v == NULL) { - *lengthPtr = 2; + v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); + if (v == NULL) { + *lengthPtr = 2; - if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { - /* + if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { + /* * If substituting a local variable in a non-local context, @@ -3801,69 +3824,67 @@ Var_Parse(const char *str, GNode *ctxt, int flags, */ - switch (str[1]) { - case '@': - return UNCONST("$(.TARGET)"); - case '%': - return UNCONST("$(.MEMBER)"); - case '*': - return UNCONST("$(.PREFIX)"); - case '!': - return UNCONST("$(.ARCHIVE)"); - } - } - /* + switch (str[1]) { + case '@': + return UNCONST("$(.TARGET)"); + case '%': + return UNCONST("$(.MEMBER)"); + case '*': + return UNCONST("$(.PREFIX)"); + case '!': + return UNCONST("$(.ARCHIVE)"); + } + } + /* * Error */ - return (flags & VARF_UNDEFERR) ? var_Error : varNoError; - } else { - haveModifier = FALSE; - tstr = &str[1]; - endc = str[1]; - } + return (flags & VARF_UNDEFERR) ? var_Error : varNoError; + } else { + haveModifier = FALSE; + tstr = &str[1]; + endc = str[1]; + } } else { - Buffer buf; /* Holds the variable name */ - int depth = 1; + Buffer buf; /* Holds the variable name */ + int depth = 1; - endc = startc == PROPEN ? PRCLOSE : BRCLOSE; - Buf_Init(&buf, 0); + endc = startc == PROPEN ? PRCLOSE : BRCLOSE; + Buf_Init(&buf, 0); - /* + /* * Skip to the end character or a colon, whichever comes first. */ - for (tstr = str + 2; *tstr != '\0'; tstr++) - { - /* + for (tstr = str + 2; *tstr != '\0'; tstr++) { + /* * Track depth so we can spot parse errors. */ - if (*tstr == startc) { - depth++; - } - if (*tstr == endc) { - if (--depth == 0) - break; - } - if (depth == 1 && *tstr == ':') { - break; - } - /* + if (*tstr == startc) { + depth++; + } + if (*tstr == endc) { + if (--depth == 0) + break; + } + if (depth == 1 && *tstr == ':') { + break; + } + /* * A variable inside a variable, expand */ - if (*tstr == '$') { - int rlen; - void *freeIt; - char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); - if (rval != NULL) { - Buf_AddBytes(&buf, strlen(rval), rval); - } - free(freeIt); - tstr += rlen - 1; - } - else - Buf_AddByte(&buf, *tstr); - } - if (*tstr == ':') { - haveModifier = TRUE; - } else if (*tstr == endc) { - haveModifier = FALSE; - } else { - /* + if (*tstr == '$') { + int rlen; + void *freeIt; + char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); + if (rval != NULL) { + Buf_AddBytes(&buf, strlen(rval), rval); + } + free(freeIt); + tstr += rlen - 1; + } else + Buf_AddByte(&buf, *tstr); + } + if (*tstr == ':') { + haveModifier = TRUE; + } else if (*tstr == endc) { + haveModifier = FALSE; + } else { + /* * If we never did find the end character, return NULL @@ -3872,9 +3893,9 @@ Var_Parse(const char *str, GNode *ctxt, int flags, */ - *lengthPtr = tstr - str; - Buf_Destroy(&buf, TRUE); - return (var_Error); - } - str = Buf_GetAll(&buf, &vlen); + *lengthPtr = tstr - str; + Buf_Destroy(&buf, TRUE); + return (var_Error); + } + str = Buf_GetAll(&buf, &vlen); - /* + /* * At this point, str points into newly allocated memory from @@ -3889,4 +3910,4 @@ Var_Parse(const char *str, GNode *ctxt, int flags, - v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); - /* + v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); + /* * Check also for bogus D and F forms of local variables since we're @@ -3894,28 +3915,26 @@ Var_Parse(const char *str, GNode *ctxt, int flags, */ - if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && - (vlen == 2) && (str[1] == 'F' || str[1] == 'D') && - strchr("@%?*!<>", str[0]) != NULL) { - /* + if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && + (vlen == 2) && (str[1] == 'F' || str[1] == 'D') && + strchr("@%?*!<>", str[0]) != NULL) { + /* * Well, it's local -- go look for it. */ - name[0] = *str; - name[1] = '\0'; - v = VarFind(name, ctxt, 0); - - if (v != NULL) { - if (str[1] == 'D') { - extramodifiers = "H:"; - } - else { /* F */ - extramodifiers = "T:"; - } - } - } - - if (v == NULL) { - if (((vlen == 1) || - (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) && - ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) - { - /* + name[0] = *str; + name[1] = '\0'; + v = VarFind(name, ctxt, 0); + + if (v != NULL) { + if (str[1] == 'D') { + extramodifiers = "H:"; + } else { /* F */ + extramodifiers = "T:"; + } + } + } + + if (v == NULL) { + if (((vlen == 1) || + (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) && + ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) { + /* * If substituting a local variable in a non-local context, @@ -3928,28 +3947,26 @@ Var_Parse(const char *str, GNode *ctxt, int flags, */ - switch (*str) { - case '@': - case '%': - case '*': - case '!': - dynamic = TRUE; - break; - } - } else if ((vlen > 2) && (*str == '.') && - isupper((unsigned char) str[1]) && - ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) - { - int len; - - len = vlen - 1; - if ((strncmp(str, ".TARGET", len) == 0) || - (strncmp(str, ".ARCHIVE", len) == 0) || - (strncmp(str, ".PREFIX", len) == 0) || - (strncmp(str, ".MEMBER", len) == 0)) - { - dynamic = TRUE; - } - } - - if (!haveModifier) { - /* + switch (*str) { + case '@': + case '%': + case '*': + case '!': + dynamic = TRUE; + break; + } + } else if ((vlen > 2) && (*str == '.') && + isupper((unsigned char) str[1]) && + ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) { + int len; + + len = vlen - 1; + if ((strncmp(str, ".TARGET", len) == 0) || + (strncmp(str, ".ARCHIVE", len) == 0) || + (strncmp(str, ".PREFIX", len) == 0) || + (strncmp(str, ".MEMBER", len) == 0)) { + dynamic = TRUE; + } + } + + if (!haveModifier) { + /* * No modifiers -- have specification length so we can return @@ -3957,14 +3974,14 @@ Var_Parse(const char *str, GNode *ctxt, int flags, */ - *lengthPtr = tstr - start + 1; - if (dynamic) { - char *pstr = bmake_strndup(start, *lengthPtr); - *freePtr = pstr; - Buf_Destroy(&buf, TRUE); - return(pstr); - } else { - Buf_Destroy(&buf, TRUE); - return (flags & VARF_UNDEFERR) ? var_Error : varNoError; - } - } else { - /* + *lengthPtr = tstr - start + 1; + if (dynamic) { + char *pstr = bmake_strndup(start, *lengthPtr); + *freePtr = pstr; + Buf_Destroy(&buf, TRUE); + return (pstr); + } else { + Buf_Destroy(&buf, TRUE); + return (flags & VARF_UNDEFERR) ? var_Error : varNoError; + } + } else { + /* * Still need to get to the end of the variable specification, @@ -3972,10 +3989,10 @@ Var_Parse(const char *str, GNode *ctxt, int flags, */ - v = bmake_malloc(sizeof(Var)); - v->name = UNCONST(str); - Buf_Init(&v->val, 1); - v->flags = VAR_JUNK; - Buf_Destroy(&buf, FALSE); - } - } else - Buf_Destroy(&buf, TRUE); + v = bmake_malloc(sizeof(Var)); + v->name = UNCONST(str); + Buf_Init(&v->val, 1); + v->flags = VAR_JUNK; + Buf_Destroy(&buf, FALSE); + } + } else + Buf_Destroy(&buf, TRUE); } @@ -3983,6 +4000,6 @@ Var_Parse(const char *str, GNode *ctxt, int flags, if (v->flags & VAR_IN_USE) { - Fatal("Variable %s is recursive.", v->name); - /*NOTREACHED*/ + Fatal("Variable %s is recursive.", v->name); + /*NOTREACHED*/ } else { - v->flags |= VAR_IN_USE; + v->flags |= VAR_IN_USE; } @@ -3999,4 +4016,4 @@ Var_Parse(const char *str, GNode *ctxt, int flags, if (strchr(nstr, '$') != NULL) { - nstr = Var_Subst(NULL, nstr, ctxt, flags); - *freePtr = nstr; + nstr = Var_Subst(NULL, nstr, ctxt, flags); + *freePtr = nstr; } @@ -4006,27 +4023,27 @@ Var_Parse(const char *str, GNode *ctxt, int flags, if ((nstr != NULL) && (haveModifier || extramodifiers != NULL)) { - void *extraFree; - int used; - - extraFree = NULL; - if (extramodifiers != NULL) { - nstr = ApplyModifiers(nstr, extramodifiers, '(', ')', - v, ctxt, flags, &used, &extraFree); - } - - if (haveModifier) { - /* Skip initial colon. */ - tstr++; - - nstr = ApplyModifiers(nstr, tstr, startc, endc, - v, ctxt, flags, &used, freePtr); - tstr += used; - free(extraFree); - } else { - *freePtr = extraFree; - } + void *extraFree; + int used; + + extraFree = NULL; + if (extramodifiers != NULL) { + nstr = ApplyModifiers(nstr, extramodifiers, '(', ')', + v, ctxt, flags, &used, &extraFree); + } + + if (haveModifier) { + /* Skip initial colon. */ + tstr++; + + nstr = ApplyModifiers(nstr, tstr, startc, endc, + v, ctxt, flags, &used, freePtr); + tstr += used; + free(extraFree); + } else { + *freePtr = extraFree; + } } if (*tstr) { - *lengthPtr = tstr - start + 1; + *lengthPtr = tstr - start + 1; } else { - *lengthPtr = tstr - start; + *lengthPtr = tstr - start; } @@ -4034,8 +4051,8 @@ Var_Parse(const char *str, GNode *ctxt, int flags, if (v->flags & VAR_FROM_ENV) { - Boolean destroy = FALSE; + Boolean destroy = FALSE; - if (nstr != Buf_GetAll(&v->val, NULL)) { - destroy = TRUE; - } else { - /* + if (nstr != Buf_GetAll(&v->val, NULL)) { + destroy = TRUE; + } else { + /* * Returning the value unmodified, so tell the caller to free @@ -4043,7 +4060,7 @@ Var_Parse(const char *str, GNode *ctxt, int flags, */ - *freePtr = nstr; - } - VarFreeEnv(v, destroy); + *freePtr = nstr; + } + VarFreeEnv(v, destroy); } else if (v->flags & VAR_JUNK) { - /* + /* * Perform any free'ing needed and set *freePtr to NULL so the caller @@ -4052,18 +4069,18 @@ Var_Parse(const char *str, GNode *ctxt, int flags, */ - if (!(v->flags & VAR_KEEP)) { - if (*freePtr) { - free(nstr); - *freePtr = NULL; - } - if (dynamic) { - nstr = bmake_strndup(start, *lengthPtr); - *freePtr = nstr; - } else { - nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError; - } - } - if (nstr != Buf_GetAll(&v->val, NULL)) - Buf_Destroy(&v->val, TRUE); - free(v->name); - free(v); + if (!(v->flags & VAR_KEEP)) { + if (*freePtr) { + free(nstr); + *freePtr = NULL; + } + if (dynamic) { + nstr = bmake_strndup(start, *lengthPtr); + *freePtr = nstr; + } else { + nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError; + } + } + if (nstr != Buf_GetAll(&v->val, NULL)) + Buf_Destroy(&v->val, TRUE); + free(v->name); + free(v); } @@ -4095,9 +4112,8 @@ Var_Parse(const char *str, GNode *ctxt, int flags, char * -Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) -{ - Buffer buf; /* Buffer for forming things */ - char *val; /* Value to substitute for a variable */ - int length; /* Length of the variable invocation */ - Boolean trailingBslash; /* variable ends in \ */ - void *freeIt = NULL; /* Set if it should be freed */ +Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) { + Buffer buf; /* Buffer for forming things */ + char *val; /* Value to substitute for a variable */ + int length; /* Length of the variable invocation */ + Boolean trailingBslash; /* variable ends in \ */ + void *freeIt = NULL; /* Set if it should be freed */ static Boolean errorReported; /* Set true if an error has already @@ -4111,6 +4127,6 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) while (*str) { - if (*str == '\n' && trailingBslash) - Buf_AddByte(&buf, ' '); - if (var == NULL && (*str == '$') && (str[1] == '$')) { - /* + if (*str == '\n' && trailingBslash) + Buf_AddByte(&buf, ' '); + if (var == NULL && (*str == '$') && (str[1] == '$')) { + /* * A dollar sign may be escaped either with another dollar sign. @@ -4119,9 +4135,9 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) */ - if (save_dollars && (flags & VARF_ASSIGN)) - Buf_AddByte(&buf, *str); - str++; - Buf_AddByte(&buf, *str); - str++; - } else if (*str != '$') { - /* + if (save_dollars && (flags & VARF_ASSIGN)) + Buf_AddByte(&buf, *str); + str++; + Buf_AddByte(&buf, *str); + str++; + } else if (*str != '$') { + /* * Skip as many characters as possible -- either to the end of @@ -4129,37 +4145,35 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) */ - const char *cp; - - for (cp = str++; *str != '$' && *str != '\0'; str++) - continue; - Buf_AddBytes(&buf, str - cp, cp); - } else { - if (var != NULL) { - int expand; - for (;;) { - if (str[1] == '\0') { - /* A trailing $ is kind of a special case */ - Buf_AddByte(&buf, str[0]); - str++; - expand = FALSE; - } else if (str[1] != PROPEN && str[1] != BROPEN) { - if (str[1] != *var || strlen(var) > 1) { - Buf_AddBytes(&buf, 2, str); - str += 2; - expand = FALSE; - } - else - expand = TRUE; - break; - } - else { - const char *p; - - /* + const char *cp; + + for (cp = str++; *str != '$' && *str != '\0'; str++) + continue; + Buf_AddBytes(&buf, str - cp, cp); + } else { + if (var != NULL) { + int expand; + for (;;) { + if (str[1] == '\0') { + /* A trailing $ is kind of a special case */ + Buf_AddByte(&buf, str[0]); + str++; + expand = FALSE; + } else if (str[1] != PROPEN && str[1] != BROPEN) { + if (str[1] != *var || strlen(var) > 1) { + Buf_AddBytes(&buf, 2, str); + str += 2; + expand = FALSE; + } else + expand = TRUE; + break; + } else { + const char *p; + + /* * Scan up to the end of the variable name. */ - for (p = &str[2]; *p && - *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++) - if (*p == '$') - break; - /* + for (p = &str[2]; *p && + *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++) + if (*p == '$') + break; + /* * A variable inside the variable. We cannot expand @@ -4168,11 +4182,11 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) */ - if (*p == '$') { - Buf_AddBytes(&buf, p - str, str); - str = p; - continue; - } - - if (strncmp(var, str + 2, p - str - 2) != 0 || - var[p - str - 2] != '\0') { - /* + if (*p == '$') { + Buf_AddBytes(&buf, p - str, str); + str = p; + continue; + } + + if (strncmp(var, str + 2, p - str - 2) != 0 || + var[p - str - 2] != '\0') { + /* * Not the variable we want to expand, scan @@ -4180,20 +4194,19 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) */ - for (;*p != '$' && *p != '\0'; p++) - continue; - Buf_AddBytes(&buf, p - str, str); - str = p; - expand = FALSE; - } - else - expand = TRUE; - break; - } - } - if (!expand) - continue; - } - - val = Var_Parse(str, ctxt, flags, &length, &freeIt); - - /* + for (; *p != '$' && *p != '\0'; p++) + continue; + Buf_AddBytes(&buf, p - str, str); + str = p; + expand = FALSE; + } else + expand = TRUE; + break; + } + } + if (!expand) + continue; + } + + val = Var_Parse(str, ctxt, flags, &length, &freeIt); + + /* * When we come down here, val should either point to the @@ -4203,4 +4216,4 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) */ - if (val == var_Error || val == varNoError) { - /* + if (val == var_Error || val == varNoError) { + /* * If performing old-time variable substitution, skip over @@ -4210,6 +4223,6 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) */ - if (oldVars) { - str += length; - } else if ((flags & VARF_UNDEFERR) || val == var_Error) { - /* + if (oldVars) { + str += length; + } else if ((flags & VARF_UNDEFERR) || val == var_Error) { + /* * If variable is undefined, complain and skip the @@ -4218,14 +4231,14 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) */ - if (!errorReported) { - Parse_Error(PARSE_FATAL, - "Undefined variable \"%.*s\"",length,str); - } - str += length; - errorReported = TRUE; - } else { - Buf_AddByte(&buf, *str); - str += 1; - } - } else { - /* + if (!errorReported) { + Parse_Error(PARSE_FATAL, + "Undefined variable \"%.*s\"", length, str); + } + str += length; + errorReported = TRUE; + } else { + Buf_AddByte(&buf, *str); + str += 1; + } + } else { + /* * We've now got a variable structure to store in. But first, @@ -4233,5 +4246,5 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) */ - str += length; + str += length; - /* + /* * Copy all the characters from the variable value straight @@ -4239,9 +4252,9 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) */ - length = strlen(val); - Buf_AddBytes(&buf, length, val); - trailingBslash = length > 0 && val[length - 1] == '\\'; - } - free(freeIt); - freeIt = NULL; - } + length = strlen(val); + Buf_AddBytes(&buf, length, val); + trailingBslash = length > 0 && val[length - 1] == '\\'; + } + free(freeIt); + freeIt = NULL; + } } @@ -4269,3 +4282,3 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) #if 0 -char * + char * Var_GetTail(char *file) @@ -4313,4 +4326,3 @@ Var_GetHead(char *file) void -Var_Init(void) -{ +Var_Init(void) { VAR_INTERNAL = Targ_NewGN("Internal"); @@ -4323,4 +4335,3 @@ Var_Init(void) void -Var_End(void) -{ +Var_End(void) { } @@ -4330,5 +4341,4 @@ Var_End(void) static void -VarPrintVar(void *vp) -{ - Var *v = (Var *)vp; +VarPrintVar(void *vp) { + Var *v = (Var *) vp; fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL)); @@ -4343,4 +4353,3 @@ VarPrintVar(void *vp) void -Var_Dump(GNode *ctxt) -{ +Var_Dump(GNode *ctxt) { Hash_Search search; @@ -4349,6 +4358,6888 @@ Var_Dump(GNode *ctxt) for (h = Hash_EnumFirst(&ctxt->context, &search); - h != NULL; - h = Hash_EnumNext(&search)) { - VarPrintVar(Hash_GetValue(h)); + h != NULL; + h = Hash_EnumNext(&search)) { + VarPrintVar(Hash_GetValue(h)); + } +} + +#if (!defined(HAVE_REGCOMP) || !defined(HAVE_REGERROR) || !defined(HAVE_REGEXEC) || !defined(HAVE_REGFREE)) + +extern char * nl_langinfo(nl_item item); + +/* Extended regular expression matching and search library. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +static void re_string_construct_common(const char *str, Idx len, + re_string_t *pstr, + RE_TRANSLATE_TYPE trans, bool icase, + const re_dfa_t *dfa); + +static re_dfastate_t *create_ci_newstate(const re_dfa_t *dfa, + const re_node_set *nodes, + re_hashval_t hash); + +static re_dfastate_t *create_cd_newstate(const re_dfa_t *dfa, + const re_node_set *nodes, + unsigned int context, + re_hashval_t hash); + +static reg_errcode_t re_string_realloc_buffers(re_string_t *pstr, + Idx new_buf_len); + +static void build_upper_buffer(re_string_t *pstr); + +static void re_string_translate_buffer(re_string_t *pstr); + +static unsigned int re_string_context_at(const re_string_t *input, Idx idx, + int eflags) __attribute__ ((pure)); + +static reg_errcode_t match_ctx_init(re_match_context_t *cache, int eflags, + Idx n); + +static void match_ctx_clean(re_match_context_t *mctx); + +static void match_ctx_free(re_match_context_t *cache); + +static reg_errcode_t match_ctx_add_entry(re_match_context_t *cache, Idx node, + Idx str_idx, Idx from, Idx to); + +static Idx search_cur_bkref_entry(const re_match_context_t *mctx, Idx str_idx); + +static reg_errcode_t match_ctx_add_subtop(re_match_context_t *mctx, Idx node, + Idx str_idx); + +static re_sub_match_last_t *match_ctx_add_sublast(re_sub_match_top_t *subtop, + Idx node, Idx str_idx); + +static void sift_ctx_init(re_sift_context_t *sctx, re_dfastate_t **sifted_sts, + re_dfastate_t **limited_sts, Idx last_node, + Idx last_str_idx); + +static reg_errcode_t re_search_internal(const regex_t *preg, + const char *string, Idx length, + Idx start, Idx last_start, Idx stop, + size_t nmatch, regmatch_t pmatch[], + int eflags); + +static regoff_t re_search_2_stub(struct re_pattern_buffer *bufp, + const char *string1, Idx length1, + const char *string2, Idx length2, + Idx start, regoff_t range, + struct re_registers *regs, + Idx stop, bool ret_len); + +static regoff_t re_search_stub(struct re_pattern_buffer *bufp, + const char *string, Idx length, Idx start, + regoff_t range, Idx stop, + struct re_registers *regs, + bool ret_len); + +static unsigned re_copy_regs(struct re_registers *regs, regmatch_t *pmatch, + Idx nregs, int regs_allocated); + +static reg_errcode_t prune_impossible_nodes(re_match_context_t *mctx); + +static Idx check_matching(re_match_context_t *mctx, bool fl_longest_match, + Idx *p_match_first); + +static Idx check_halt_state_context(const re_match_context_t *mctx, + const re_dfastate_t *state, Idx idx); + +static void update_regs(const re_dfa_t *dfa, regmatch_t *pmatch, + regmatch_t *prev_idx_match, Idx cur_node, + Idx cur_idx, Idx nmatch); + +static reg_errcode_t push_fail_stack(struct re_fail_stack_t *fs, + Idx str_idx, Idx dest_node, Idx nregs, + regmatch_t *regs, + re_node_set *eps_via_nodes); + +static reg_errcode_t set_regs(const regex_t *preg, + const re_match_context_t *mctx, + size_t nmatch, regmatch_t *pmatch, + bool fl_backtrack); + +static reg_errcode_t free_fail_stack_return(struct re_fail_stack_t *fs); + +static reg_errcode_t sift_states_backward(const re_match_context_t *mctx, + re_sift_context_t *sctx); + +static reg_errcode_t build_sifted_states(const re_match_context_t *mctx, + re_sift_context_t *sctx, Idx str_idx, + re_node_set *cur_dest); + +static reg_errcode_t update_cur_sifted_state(const re_match_context_t *mctx, + re_sift_context_t *sctx, + Idx str_idx, + re_node_set *dest_nodes); + +static reg_errcode_t add_epsilon_src_nodes(const re_dfa_t *dfa, + re_node_set *dest_nodes, + const re_node_set *candidates); + +static bool check_dst_limits(const re_match_context_t *mctx, + const re_node_set *limits, + Idx dst_node, Idx dst_idx, Idx src_node, + Idx src_idx); + +static int check_dst_limits_calc_pos_1(const re_match_context_t *mctx, + int boundaries, Idx subexp_idx, + Idx from_node, Idx bkref_idx); + +static int check_dst_limits_calc_pos(const re_match_context_t *mctx, + Idx limit, Idx subexp_idx, + Idx node, Idx str_idx, + Idx bkref_idx); + +static reg_errcode_t check_subexp_limits(const re_dfa_t *dfa, + re_node_set *dest_nodes, + const re_node_set *candidates, + re_node_set *limits, + struct re_backref_cache_entry *bkref_ents, + Idx str_idx); + +static reg_errcode_t sift_states_bkref(const re_match_context_t *mctx, + re_sift_context_t *sctx, + Idx str_idx, const re_node_set *candidates); + +static reg_errcode_t merge_state_array(const re_dfa_t *dfa, + re_dfastate_t **dst, + re_dfastate_t **src, Idx num); + +static re_dfastate_t *find_recover_state(reg_errcode_t *err, + re_match_context_t *mctx); + +static re_dfastate_t *transit_state(reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *state); + +static re_dfastate_t *merge_state_with_log(reg_errcode_t *err, + re_match_context_t *mctx, + re_dfastate_t *next_state); + +static reg_errcode_t check_subexp_matching_top(re_match_context_t *mctx, + re_node_set *cur_nodes, + Idx str_idx); + +static reg_errcode_t transit_state_bkref(re_match_context_t *mctx, + const re_node_set *nodes); + +static reg_errcode_t get_subexp(re_match_context_t *mctx, + Idx bkref_node, Idx bkref_str_idx); + +static reg_errcode_t get_subexp_sub(re_match_context_t *mctx, + const re_sub_match_top_t *sub_top, + re_sub_match_last_t *sub_last, + Idx bkref_node, Idx bkref_str); + +static Idx find_subexp_node(const re_dfa_t *dfa, const re_node_set *nodes, + Idx subexp_idx, int type); + +static reg_errcode_t check_arrival(re_match_context_t *mctx, + state_array_t *path, Idx top_node, + Idx top_str, Idx last_node, Idx last_str, + int type); + +static reg_errcode_t check_arrival_add_next_nodes(re_match_context_t *mctx, + Idx str_idx, + re_node_set *cur_nodes, + re_node_set *next_nodes); + +static reg_errcode_t check_arrival_expand_ecl(const re_dfa_t *dfa, + re_node_set *cur_nodes, + Idx ex_subexp, int type); + +static reg_errcode_t check_arrival_expand_ecl_sub(const re_dfa_t *dfa, + re_node_set *dst_nodes, + Idx target, Idx ex_subexp, + int type); + +static reg_errcode_t expand_bkref_cache(re_match_context_t *mctx, + re_node_set *cur_nodes, Idx cur_str, + Idx subexp_num, int type); + +static bool build_trtable(const re_dfa_t *dfa, re_dfastate_t *state); + +static Idx group_nodes_into_DFAstates(const re_dfa_t *dfa, + const re_dfastate_t *state, + re_node_set *states_node, + bitset_t *states_ch); + +static bool check_node_accept(const re_match_context_t *mctx, + const re_token_t *node, Idx idx); + +static reg_errcode_t extend_buffers(re_match_context_t *mctx, int min_len); + +/* Check NODE match the current context. */ + +static bool +check_halt_node_context(const re_dfa_t *dfa, Idx node, unsigned int context) { + re_token_type_t type = dfa->nodes[node].type; + unsigned int constraint = dfa->nodes[node].constraint; + if (type != END_OF_RE) + return false; + if (!constraint) + return true; + if (NOT_SATISFY_NEXT_CONSTRAINT(constraint, context)) + return false; + return true; +} + +/* Check the halt state STATE match the current context. + Return 0 if not match, if the node, STATE has, is a halt node and + match the context, return the node. */ + +static Idx +check_halt_state_context(const re_match_context_t *mctx, + const re_dfastate_t *state, Idx idx) { + Idx i; + unsigned int context; + context = re_string_context_at(&mctx->input, idx, mctx->eflags); + for (i = 0; i < state->nodes.nelem; ++i) + if (check_halt_node_context(mctx->dfa, state->nodes.elems[i], context)) + return state->nodes.elems[i]; + return 0; +} + +/* Functions for string operation. */ + +/* This function allocate the buffers. It is necessary to call + re_string_reconstruct before using the object. */ + +static reg_errcode_t + +re_string_allocate(re_string_t *pstr, const char *str, Idx len, Idx init_len, + RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) { + reg_errcode_t ret; + Idx init_buf_len; + +/* Ensure at least one character fits into the buffers. */ + if (init_len < dfa->mb_cur_max) + init_len = dfa->mb_cur_max; + init_buf_len = (len + 1 < init_len) ? len + 1 : init_len; + re_string_construct_common(str, len, pstr, trans, icase, dfa); + + ret = re_string_realloc_buffers(pstr, init_buf_len); + if ((ret != REG_NOERROR)) + return ret; + + pstr->word_char = dfa->word_char; + pstr->word_ops_used = dfa->word_ops_used; + pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; + pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len; + pstr->valid_raw_len = pstr->valid_len; + return REG_NOERROR; +} + +/* This function allocate the buffers, and initialize them. */ + +static reg_errcode_t + +re_string_construct(re_string_t *pstr, const char *str, Idx len, + RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) { + reg_errcode_t ret; + memset(pstr, '\0', sizeof(re_string_t)); + re_string_construct_common(str, len, pstr, trans, icase, dfa); + + if (len > 0) { + ret = re_string_realloc_buffers(pstr, len + 1); + if ((ret != REG_NOERROR)) + return ret; + } + pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; + + if (icase) { + + build_upper_buffer(pstr); + } else { + + { + if (trans != NULL) + re_string_translate_buffer(pstr); + else { + pstr->valid_len = pstr->bufs_len; + pstr->valid_raw_len = pstr->bufs_len; + } + } + } + + return REG_NOERROR; +} + +/* Helper functions for re_string_allocate, and re_string_construct. */ + +static reg_errcode_t + +re_string_realloc_buffers(re_string_t *pstr, Idx new_buf_len) { + + if (pstr->mbs_allocated) { + unsigned char *new_mbs = re_realloc(pstr->mbs, + unsigned char, + new_buf_len); + if ((new_mbs == NULL)) + return REG_ESPACE; + pstr->mbs = new_mbs; } + pstr->bufs_len = new_buf_len; + return REG_NOERROR; } + + +static void +re_string_construct_common(const char *str, Idx len, re_string_t *pstr, + RE_TRANSLATE_TYPE trans, bool icase, + const re_dfa_t *dfa) { + pstr->raw_mbs = (const unsigned char *) str; + pstr->len = len; + pstr->raw_len = len; + pstr->trans = trans; + pstr->icase = icase; + pstr->mbs_allocated = (trans != NULL || icase); + pstr->mb_cur_max = dfa->mb_cur_max; + pstr->is_utf8 = dfa->is_utf8; + pstr->map_notascii = dfa->map_notascii; + pstr->stop = pstr->len; + pstr->raw_stop = pstr->stop; +} + +/* Build the buffer PSTR->MBS, and apply the translation if we need. + This function is used in case of REG_ICASE. */ + +static void +build_upper_buffer(re_string_t *pstr) { + Idx char_idx, end_idx; + end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; + + for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx) { + int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; + if ((pstr->trans != NULL)) + ch = pstr->trans[ch]; + pstr->mbs[char_idx] = toupper(ch); + } + pstr->valid_len = char_idx; + pstr->valid_raw_len = char_idx; +} + +/* Apply TRANS to the buffer in PSTR. */ + +static void +re_string_translate_buffer(re_string_t *pstr) { + Idx buf_idx, end_idx; + end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; + + for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx) { + int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; + pstr->mbs[buf_idx] = pstr->trans[ch]; + } + + pstr->valid_len = buf_idx; + pstr->valid_raw_len = buf_idx; +} + +/* This function re-construct the buffers. + Concretely, convert to wide character in case of pstr->mb_cur_max > 1, + convert to upper case in case of REG_ICASE, apply translation. */ + +static reg_errcode_t + +re_string_reconstruct(re_string_t *pstr, Idx idx, int eflags) { + Idx offset; + + if ((pstr->raw_mbs_idx <= idx)) + offset = idx - pstr->raw_mbs_idx; + else { +/* Reset buffer. */ + + pstr->len = pstr->raw_len; + pstr->stop = pstr->raw_stop; + pstr->valid_len = 0; + pstr->raw_mbs_idx = 0; + pstr->valid_raw_len = 0; + pstr->offsets_needed = 0; + pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF + : CONTEXT_NEWLINE | CONTEXT_BEGBUF); + if (!pstr->mbs_allocated) + pstr->mbs = (unsigned char *) pstr->raw_mbs; + offset = idx; + } + + if ((offset != 0)) { +/* Should the already checked characters be kept? */ + if ((offset < pstr->valid_raw_len)) { +/* Yes, move them to the front of the buffer. */ + + { + pstr->tip_context = re_string_context_at(pstr, offset - 1, + eflags); + + if ((pstr->mbs_allocated)) + memmove(pstr->mbs, pstr->mbs + offset, + pstr->valid_len - offset); + pstr->valid_len -= offset; + pstr->valid_raw_len -= offset; + + } + } else { + + pstr->valid_len = 0; + + { + int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; + pstr->valid_raw_len = 0; + if (pstr->trans) + c = pstr->trans[c]; + pstr->tip_context = (bitset_contain(pstr->word_char, c) + ? CONTEXT_WORD + : ((IS_NEWLINE(c) && pstr->newline_anchor) + ? CONTEXT_NEWLINE : 0)); + } + } + if (!(pstr->mbs_allocated)) + pstr->mbs += offset; + } + pstr->raw_mbs_idx = idx; + pstr->len -= offset; + pstr->stop -= offset; + +/* Then build the buffers. */ + + if ((pstr->mbs_allocated)) { + if (pstr->icase) + build_upper_buffer(pstr); + else if (pstr->trans != NULL) + re_string_translate_buffer(pstr); + } else + pstr->valid_len = pstr->len; + + pstr->cur_idx = 0; + return REG_NOERROR; +} + +static unsigned char +__attribute__ ((pure)) +re_string_peek_byte_case(const re_string_t *pstr, Idx idx) { + int ch; + Idx off; + + /* Handle the common (easiest) cases first. */ + if ((!pstr->mbs_allocated)) + return re_string_peek_byte(pstr, idx); + + off = pstr->cur_idx + idx; + + ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; + + return ch; +} + +static unsigned char +re_string_fetch_byte_case(re_string_t *pstr) { + if ((!pstr->mbs_allocated)) + return re_string_fetch_byte(pstr); + + return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++]; +} + +static void +re_string_destruct(re_string_t *pstr) { + + if (pstr->mbs_allocated) + re_free(pstr->mbs); +} + +/* Return the context at IDX in INPUT. */ + +static unsigned int +re_string_context_at(const re_string_t *input, Idx idx, int eflags) { + int c; + if ((idx < 0)) + /* In this case, we use the value stored in input->tip_context, + since we can't know the character in input->mbs[-1] here. */ + return input->tip_context; + if ((idx == input->len)) + return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF + : CONTEXT_NEWLINE | CONTEXT_ENDBUF); + + { + c = re_string_byte_at(input, idx); + if (bitset_contain(input->word_char, c)) + return CONTEXT_WORD; + return IS_NEWLINE(c) && input->newline_anchor ? CONTEXT_NEWLINE : 0; + } +} + +/* Functions for set operation. */ + +static reg_errcode_t + +re_node_set_alloc(re_node_set *set, Idx size) { + set->alloc = size; + set->nelem = 0; + set->elems = re_malloc(Idx, size); + if ((set->elems == NULL) + && (MALLOC_0_IS_NONNULL || size != 0)) + return REG_ESPACE; + return REG_NOERROR; +} + +static reg_errcode_t + +re_node_set_init_1(re_node_set *set, Idx elem) { + set->alloc = 1; + set->nelem = 1; + set->elems = re_malloc(Idx, 1); + if ((set->elems == NULL)) { + set->alloc = set->nelem = 0; + return REG_ESPACE; + } + set->elems[0] = elem; + return REG_NOERROR; +} + +static reg_errcode_t + +re_node_set_init_2(re_node_set *set, Idx elem1, Idx elem2) { + set->alloc = 2; + set->elems = re_malloc(Idx, 2); + if ((set->elems == NULL)) + return REG_ESPACE; + if (elem1 == elem2) { + set->nelem = 1; + set->elems[0] = elem1; + } else { + set->nelem = 2; + if (elem1 < elem2) { + set->elems[0] = elem1; + set->elems[1] = elem2; + } else { + set->elems[0] = elem2; + set->elems[1] = elem1; + } + } + return REG_NOERROR; +} + +static reg_errcode_t + +re_node_set_init_copy(re_node_set *dest, const re_node_set *src) { + dest->nelem = src->nelem; + if (src->nelem > 0) { + dest->alloc = dest->nelem; + dest->elems = re_malloc(Idx, dest->alloc); + if ((dest->elems == NULL)) { + dest->alloc = dest->nelem = 0; + return REG_ESPACE; + } + memcpy(dest->elems, src->elems, src->nelem * sizeof(Idx)); + } else + re_node_set_init_empty(dest); + return REG_NOERROR; +} + +/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to + DEST. Return value indicate the error code or REG_NOERROR if succeeded. + Note: We assume dest->elems is NULL, when dest->alloc is 0. */ + +static reg_errcode_t + +re_node_set_add_intersect(re_node_set *dest, const re_node_set *src1, + const re_node_set *src2) { + Idx i1, i2, is, id, delta, sbase; + if (src1->nelem == 0 || src2->nelem == 0) + return REG_NOERROR; + +/* We need dest->nelem + 2 * elems_in_intersection; this is a + conservative estimate. */ + if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) { + Idx new_alloc = src1->nelem + src2->nelem + dest->alloc; + Idx *new_elems = re_realloc(dest->elems, Idx, new_alloc); + if ((new_elems == NULL)) + return REG_ESPACE; + dest->elems = new_elems; + dest->alloc = new_alloc; + } + +/* Find the items in the intersection of SRC1 and SRC2, and copy + into the top of DEST those that are not already in DEST itself. */ + sbase = dest->nelem + src1->nelem + src2->nelem; + i1 = src1->nelem - 1; + i2 = src2->nelem - 1; + id = dest->nelem - 1; + for (;;) { + if (src1->elems[i1] == src2->elems[i2]) { +/* Try to find the item in DEST. Maybe we could binary search? */ + while (id >= 0 && dest->elems[id] > src1->elems[i1]) + --id; + + if (id < 0 || dest->elems[id] != src1->elems[i1]) + dest->elems[--sbase] = src1->elems[i1]; + + if (--i1 < 0 || --i2 < 0) + break; + } + +/* Lower the highest of the two items. */ + else if (src1->elems[i1] < src2->elems[i2]) { + if (--i2 < 0) + break; + } else { + if (--i1 < 0) + break; + } + } + + id = dest->nelem - 1; + is = dest->nelem + src1->nelem + src2->nelem - 1; + delta = is - sbase + 1; + +/* Now copy. When DELTA becomes zero, the remaining + DEST elements are already in place; this is more or + less the same loop that is in re_node_set_merge. */ + dest->nelem += delta; + if (delta > 0 && id >= 0) + for (;;) { + if (dest->elems[is] > dest->elems[id]) { +/* Copy from the top. */ + dest->elems[id + delta--] = dest->elems[is--]; + if (delta == 0) + break; + } else { +/* Slide from the bottom. */ + dest->elems[id + delta] = dest->elems[id]; + if (--id < 0) + break; + } + } + +/* Copy remaining SRC elements. */ + memcpy(dest->elems, dest->elems + sbase, delta * sizeof(Idx)); + + return REG_NOERROR; +} + +/* Calculate the union set of the sets SRC1 and SRC2. And store it to + DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ + +static reg_errcode_t + +re_node_set_init_union(re_node_set *dest, const re_node_set *src1, + const re_node_set *src2) { + Idx i1, i2, id; + if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) { + dest->alloc = src1->nelem + src2->nelem; + dest->elems = re_malloc(Idx, dest->alloc); + if ((dest->elems == NULL)) + return REG_ESPACE; + } else { + if (src1 != NULL && src1->nelem > 0) + return re_node_set_init_copy(dest, src1); + else if (src2 != NULL && src2->nelem > 0) + return re_node_set_init_copy(dest, src2); + else + re_node_set_init_empty(dest); + return REG_NOERROR; + } + for (i1 = i2 = id = 0; i1 < src1->nelem && i2 < src2->nelem;) { + if (src1->elems[i1] > src2->elems[i2]) { + dest->elems[id++] = src2->elems[i2++]; + continue; + } + if (src1->elems[i1] == src2->elems[i2]) + ++i2; + dest->elems[id++] = src1->elems[i1++]; + } + if (i1 < src1->nelem) { + memcpy(dest->elems + id, src1->elems + i1, + (src1->nelem - i1) * sizeof(Idx)); + id += src1->nelem - i1; + } else if (i2 < src2->nelem) { + memcpy(dest->elems + id, src2->elems + i2, + (src2->nelem - i2) * sizeof(Idx)); + id += src2->nelem - i2; + } + dest->nelem = id; + return REG_NOERROR; +} + +/* Calculate the union set of the sets DEST and SRC. And store it to + DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ + +static reg_errcode_t + +re_node_set_merge(re_node_set *dest, const re_node_set *src) { + Idx is, id, sbase, delta; + if (src == NULL || src->nelem == 0) + return REG_NOERROR; + if (dest->alloc < 2 * src->nelem + dest->nelem) { + Idx new_alloc = 2 * (src->nelem + dest->alloc); + Idx *new_buffer = re_realloc(dest->elems, Idx, new_alloc); + if ((new_buffer == NULL)) + return REG_ESPACE; + dest->elems = new_buffer; + dest->alloc = new_alloc; + } + + if ((dest->nelem == 0)) { + dest->nelem = src->nelem; + memcpy(dest->elems, src->elems, src->nelem * sizeof(Idx)); + return REG_NOERROR; + } + +/* Copy into the top of DEST the items of SRC that are not + found in DEST. Maybe we could binary search in DEST? */ + for (sbase = dest->nelem + 2 * src->nelem, + is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0;) { + if (dest->elems[id] == src->elems[is]) + is--, id--; + else if (dest->elems[id] < src->elems[is]) + dest->elems[--sbase] = src->elems[is--]; + else /* if (dest->elems[id] > src->elems[is]) */ + --id; + } + + if (is >= 0) { +/* If DEST is exhausted, the remaining items of SRC must be unique. */ + sbase -= is + 1; + memcpy(dest->elems + sbase, src->elems, (is + 1) * sizeof(Idx)); + } + + id = dest->nelem - 1; + is = dest->nelem + 2 * src->nelem - 1; + delta = is - sbase + 1; + if (delta == 0) + return REG_NOERROR; + +/* Now copy. When DELTA becomes zero, the remaining + DEST elements are already in place. */ + dest->nelem += delta; + for (;;) { + if (dest->elems[is] > dest->elems[id]) { +/* Copy from the top. */ + dest->elems[id + delta--] = dest->elems[is--]; + if (delta == 0) + break; + } else { +/* Slide from the bottom. */ + dest->elems[id + delta] = dest->elems[id]; + if (--id < 0) { +/* Copy remaining SRC elements. */ + memcpy(dest->elems, dest->elems + sbase, + delta * sizeof(Idx)); + break; + } + } + } + + return REG_NOERROR; +} + +/* Insert the new element ELEM to the re_node_set* SET. + SET should not already have ELEM. + Return true if successful. */ + +static bool + +re_node_set_insert(re_node_set *set, Idx elem) { + Idx idx; +/* In case the set is empty. */ + if (set->alloc == 0) + return (re_node_set_init_1(set, elem) == REG_NOERROR); + + if ((set->nelem) == 0) { +/* We already guaranteed above that set->alloc != 0. */ + set->elems[0] = elem; + ++set->nelem; + return true; + } + +/* Realloc if we need. */ + if (set->alloc == set->nelem) { + Idx *new_elems; + set->alloc = set->alloc * 2; + new_elems = re_realloc(set->elems, Idx, set->alloc); + if ((new_elems == NULL)) + return false; + set->elems = new_elems; + } + +/* Move the elements which follows the new element. Test the + first element separately to skip a check in the inner loop. */ + if (elem < set->elems[0]) { + idx = 0; + for (idx = set->nelem; idx > 0; idx--) + set->elems[idx] = set->elems[idx - 1]; + } else { + for (idx = set->nelem; set->elems[idx - 1] > elem; idx--) + set->elems[idx] = set->elems[idx - 1]; + } + +/* Insert the new element. */ + set->elems[idx] = elem; + ++set->nelem; + return true; +} + +/* Insert the new element ELEM to the re_node_set* SET. + SET should not already have any element greater than or equal to ELEM. + Return true if successful. */ + +static bool + +re_node_set_insert_last(re_node_set *set, Idx elem) { +/* Realloc if we need. */ + if (set->alloc == set->nelem) { + Idx *new_elems; + set->alloc = (set->alloc + 1) * 2; + new_elems = re_realloc(set->elems, Idx, set->alloc); + if ((new_elems == NULL)) + return false; + set->elems = new_elems; + } + +/* Insert the new element. */ + set->elems[set->nelem++] = elem; + return true; +} + +/* Compare two node sets SET1 and SET2. + Return true if SET1 and SET2 are equivalent. */ + +static bool +__attribute__ ((pure)) +re_node_set_compare(const re_node_set *set1, const re_node_set *set2) { + Idx i; + if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) + return false; + for (i = set1->nelem; --i >= 0;) + if (set1->elems[i] != set2->elems[i]) + return false; + return true; +} + +/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ + +static Idx +__attribute__ ((pure)) +re_node_set_contains(const re_node_set *set, Idx elem) { + __re_size_t idx, right, mid; + if (set->nelem <= 0) + return 0; + + /* Binary search the element. */ + idx = 0; + right = set->nelem - 1; + while (idx < right) { + mid = (idx + right) / 2; + if (set->elems[mid] < elem) + idx = mid + 1; + else + right = mid; + } + return set->elems[idx] == elem ? idx + 1 : 0; +} + +static void +re_node_set_remove_at(re_node_set *set, Idx idx) { + if (idx < 0 || idx >= set->nelem) + return; + --set->nelem; + for (; idx < set->nelem; idx++) + set->elems[idx] = set->elems[idx + 1]; +} + + +/* Add the token TOKEN to dfa->nodes, and return the index of the token. + Or return -1 if an error occurred. */ + +static Idx +re_dfa_add_node(re_dfa_t *dfa, re_token_t token) { + if ((dfa->nodes_len >= dfa->nodes_alloc)) { + size_t new_nodes_alloc = dfa->nodes_alloc * 2; + Idx *new_nexts, *new_indices; + re_node_set *new_edests, *new_eclosures; + re_token_t *new_nodes; + + /* Avoid overflows in realloc. */ + const size_t max_object_size = MAX (sizeof(re_token_t), + MAX(sizeof(re_node_set), + sizeof(Idx))); + if ((MIN (IDX_MAX, SIZE_MAX / max_object_size) + < new_nodes_alloc)) + return -1; + + new_nodes = re_realloc(dfa->nodes, re_token_t, new_nodes_alloc); + if ((new_nodes == NULL)) + return -1; + dfa->nodes = new_nodes; + new_nexts = re_realloc(dfa->nexts, Idx, new_nodes_alloc); + new_indices = re_realloc(dfa->org_indices, Idx, new_nodes_alloc); + new_edests = re_realloc(dfa->edests, re_node_set, new_nodes_alloc); + new_eclosures = re_realloc(dfa->eclosures, re_node_set, new_nodes_alloc); + if ((new_nexts == NULL || new_indices == NULL + || new_edests == NULL || new_eclosures == NULL)) { + re_free(new_nexts); + re_free(new_indices); + re_free(new_edests); + re_free(new_eclosures); + return -1; + } + dfa->nexts = new_nexts; + dfa->org_indices = new_indices; + dfa->edests = new_edests; + dfa->eclosures = new_eclosures; + dfa->nodes_alloc = new_nodes_alloc; + } + dfa->nodes[dfa->nodes_len] = token; + dfa->nodes[dfa->nodes_len].constraint = 0; + dfa->nexts[dfa->nodes_len] = -1; + re_node_set_init_empty(dfa->edests + dfa->nodes_len); + re_node_set_init_empty(dfa->eclosures + dfa->nodes_len); + return dfa->nodes_len++; +} + +static re_hashval_t +calc_state_hash(const re_node_set *nodes, unsigned int context) { + re_hashval_t hash = nodes->nelem + context; + Idx i; + for (i = 0; i < nodes->nelem; i++) + hash += nodes->elems[i]; + return hash; +} + +/* Search for the state whose node_set is equivalent to NODES. + Return the pointer to the state, if we found it in the DFA. + Otherwise create the new one and return it. In case of an error + return NULL and set the error code in ERR. + Note: - We assume NULL as the invalid state, then it is possible that + return value is NULL and ERR is REG_NOERROR. + - We never return non-NULL value in case of any errors, it is for + optimization. */ + +static re_dfastate_t * + +re_acquire_state(reg_errcode_t *err, const re_dfa_t *dfa, + const re_node_set *nodes) { + re_hashval_t hash; + re_dfastate_t *new_state; + struct re_state_table_entry *spot; + Idx i; +#if defined GCC_LINT || defined lint + /* Suppress bogus uninitialized-variable warnings. */ + *err = REG_NOERROR; +#endif + if ((nodes->nelem == 0)) { + *err = REG_NOERROR; + return NULL; + } + hash = calc_state_hash(nodes, 0); + spot = dfa->state_table + (hash & dfa->state_hash_mask); + + for (i = 0; i < spot->num; i++) { + re_dfastate_t *state = spot->array[i]; + if (hash != state->hash) + continue; + if (re_node_set_compare(&state->nodes, nodes)) + return state; + } + +/* There are no appropriate state in the dfa, create the new one. */ + new_state = create_ci_newstate(dfa, nodes, hash); + if ((new_state == NULL)) + *err = REG_ESPACE; + + return new_state; +} + +/* Search for the state whose node_set is equivalent to NODES and + whose context is equivalent to CONTEXT. + Return the pointer to the state, if we found it in the DFA. + Otherwise create the new one and return it. In case of an error + return NULL and set the error code in ERR. + Note: - We assume NULL as the invalid state, then it is possible that + return value is NULL and ERR is REG_NOERROR. + - We never return non-NULL value in case of any errors, it is for + optimization. */ + +static re_dfastate_t * + +re_acquire_state_context(reg_errcode_t *err, const re_dfa_t *dfa, + const re_node_set *nodes, unsigned int context) { + re_hashval_t hash; + re_dfastate_t *new_state; + struct re_state_table_entry *spot; + Idx i; +#if defined GCC_LINT || defined lint + /* Suppress bogus uninitialized-variable warnings. */ + *err = REG_NOERROR; +#endif + if (nodes->nelem == 0) { + *err = REG_NOERROR; + return NULL; + } + hash = calc_state_hash(nodes, context); + spot = dfa->state_table + (hash & dfa->state_hash_mask); + + for (i = 0; i < spot->num; i++) { + re_dfastate_t *state = spot->array[i]; + if (state->hash == hash + && state->context == context + && re_node_set_compare(state->entrance_nodes, nodes)) + return state; + } +/* There are no appropriate state in 'dfa', create the new one. */ + new_state = create_cd_newstate(dfa, nodes, context, hash); + if ((new_state == NULL)) + *err = REG_ESPACE; + + return new_state; +} + +/* Finish initialization of the new state NEWSTATE, and using its hash value + HASH put in the appropriate bucket of DFA's state table. Return value + indicates the error code if failed. */ + +static reg_errcode_t + +register_state(const re_dfa_t *dfa, re_dfastate_t *newstate, + re_hashval_t hash) { + struct re_state_table_entry *spot; + reg_errcode_t err; + Idx i; + + newstate->hash = hash; + err = re_node_set_alloc(&newstate->non_eps_nodes, newstate->nodes.nelem); + if ((err != REG_NOERROR)) + return REG_ESPACE; + for (i = 0; i < newstate->nodes.nelem; i++) { + Idx elem = newstate->nodes.elems[i]; + if (!IS_EPSILON_NODE(dfa->nodes[elem].type)) + if (!re_node_set_insert_last(&newstate->non_eps_nodes, elem)) + return REG_ESPACE; + } + + spot = dfa->state_table + (hash & dfa->state_hash_mask); + if ((spot->alloc <= spot->num)) { + Idx new_alloc = 2 * spot->num + 2; + re_dfastate_t **new_array = re_realloc(spot->array, re_dfastate_t * , + new_alloc); + if ((new_array == NULL)) + return REG_ESPACE; + spot->array = new_array; + spot->alloc = new_alloc; + } + spot->array[spot->num++] = newstate; + return REG_NOERROR; +} + +static void +free_state(re_dfastate_t *state) { + re_node_set_free(&state->non_eps_nodes); + re_node_set_free(&state->inveclosure); + if (state->entrance_nodes != &state->nodes) { + re_node_set_free(state->entrance_nodes); + re_free(state->entrance_nodes); + } + re_node_set_free(&state->nodes); + re_free(state->word_trtable); + re_free(state->trtable); + re_free(state); +} + +/* Create the new state which is independent of contexts. + Return the new state if succeeded, otherwise return NULL. */ + +static re_dfastate_t * + +create_ci_newstate(const re_dfa_t *dfa, const re_node_set *nodes, + re_hashval_t hash) { + Idx i; + reg_errcode_t err; + re_dfastate_t *newstate; + + newstate = (re_dfastate_t *) calloc(sizeof(re_dfastate_t), 1); + if ((newstate == NULL)) + return NULL; + err = re_node_set_init_copy(&newstate->nodes, nodes); + if ((err != REG_NOERROR)) { + re_free(newstate); + return NULL; + } + + newstate->entrance_nodes = &newstate->nodes; + for (i = 0; i < nodes->nelem; i++) { + re_token_t *node = dfa->nodes + nodes->elems[i]; + re_token_type_t type = node->type; + if (type == CHARACTER && !node->constraint) + continue; + + /* If the state has the halt node, the state is a halt state. */ + if (type == END_OF_RE) + newstate->halt = 1; + else if (type == OP_BACK_REF) + newstate->has_backref = 1; + else if (type == ANCHOR || node->constraint) + newstate->has_constraint = 1; + } + err = register_state(dfa, newstate, hash); + if ((err != REG_NOERROR)) { + free_state(newstate); + newstate = NULL; + } + return newstate; +} + +/* Create the new state which is depend on the context CONTEXT. + Return the new state if succeeded, otherwise return NULL. */ + +static re_dfastate_t * + +create_cd_newstate(const re_dfa_t *dfa, const re_node_set *nodes, + unsigned int context, re_hashval_t hash) { + Idx i, nctx_nodes = 0; + reg_errcode_t err; + re_dfastate_t *newstate; + + newstate = (re_dfastate_t *) calloc(sizeof(re_dfastate_t), 1); + if ((newstate == NULL)) + return NULL; + err = re_node_set_init_copy(&newstate->nodes, nodes); + if ((err != REG_NOERROR)) { + re_free(newstate); + return NULL; + } + + newstate->context = context; + newstate->entrance_nodes = &newstate->nodes; + + for (i = 0; i < nodes->nelem; i++) { + re_token_t *node = dfa->nodes + nodes->elems[i]; + re_token_type_t type = node->type; + unsigned int constraint = node->constraint; + + if (type == CHARACTER && !constraint) + continue; + + /* If the state has the halt node, the state is a halt state. */ + if (type == END_OF_RE) + newstate->halt = 1; + else if (type == OP_BACK_REF) + newstate->has_backref = 1; + + if (constraint) { + if (newstate->entrance_nodes == &newstate->nodes) { + newstate->entrance_nodes = re_malloc(re_node_set, 1); + if ((newstate->entrance_nodes == NULL)) { + free_state(newstate); + return NULL; + } + if (re_node_set_init_copy(newstate->entrance_nodes, nodes) + != REG_NOERROR) + return NULL; + nctx_nodes = 0; + newstate->has_constraint = 1; + } + + if (NOT_SATISFY_PREV_CONSTRAINT(constraint, context)) { + re_node_set_remove_at(&newstate->nodes, i - nctx_nodes); + ++nctx_nodes; + } + } + } + err = register_state(dfa, newstate, hash); + if ((err != REG_NOERROR)) { + free_state(newstate); + newstate = NULL; + } + return newstate; +} + +/* Extended regular expression matching and search library. + Copyright (C) 2002-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Isamu Hasegawa . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef RE_TRANSLATE_TYPE +# define __RE_TRANSLATE_TYPE unsigned char * +# ifdef __USE_GNU +# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE +# endif +#endif + +# define __REPB_PREFIX(name) name + + +static reg_errcode_t re_compile_internal(regex_t *preg, const char *pattern, + size_t length, reg_syntax_t syntax); + +static void re_compile_fastmap_iter(regex_t *bufp, + const re_dfastate_t *init_state, + char *fastmap); + +static reg_errcode_t init_dfa(re_dfa_t *dfa, size_t pat_len); + +static void free_workarea_compile(regex_t *preg); + +static reg_errcode_t create_initial_state(re_dfa_t *dfa); + +static reg_errcode_t analyze(regex_t *preg); + +static reg_errcode_t preorder(bin_tree_t *root, + reg_errcode_t (fn(void *, bin_tree_t *)), + void *extra); + +static reg_errcode_t postorder(bin_tree_t *root, + reg_errcode_t (fn(void *, bin_tree_t *)), + void *extra); + +static reg_errcode_t optimize_subexps(void *extra, bin_tree_t *node); + +static reg_errcode_t lower_subexps(void *extra, bin_tree_t *node); + +static bin_tree_t *lower_subexp(reg_errcode_t *err, regex_t *preg, + bin_tree_t *node); + +static reg_errcode_t calc_first(void *extra, bin_tree_t *node); + +static reg_errcode_t calc_next(void *extra, bin_tree_t *node); + +static reg_errcode_t link_nfa_nodes(void *extra, bin_tree_t *node); + +static Idx duplicate_node(re_dfa_t *dfa, Idx org_idx, unsigned int constraint); + +static Idx search_duplicated_node(const re_dfa_t *dfa, Idx org_node, + unsigned int constraint); + +static reg_errcode_t calc_eclosure(re_dfa_t *dfa); + +static reg_errcode_t calc_eclosure_iter(re_node_set *new_set, re_dfa_t *dfa, + Idx node, bool root); + +static reg_errcode_t calc_inveclosure(re_dfa_t *dfa); + +static Idx fetch_number(re_string_t *input, re_token_t *token, + reg_syntax_t syntax); + +static int peek_token(re_token_t *token, re_string_t *input, + reg_syntax_t syntax); + +static bin_tree_t *parse(re_string_t *regexp, regex_t *preg, + reg_syntax_t syntax, reg_errcode_t *err); + +static bin_tree_t *parse_reg_exp(re_string_t *regexp, regex_t *preg, + re_token_t *token, reg_syntax_t syntax, + Idx nest, reg_errcode_t *err); + +static bin_tree_t *parse_branch(re_string_t *regexp, regex_t *preg, + re_token_t *token, reg_syntax_t syntax, + Idx nest, reg_errcode_t *err); + +static bin_tree_t *parse_expression(re_string_t *regexp, regex_t *preg, + re_token_t *token, reg_syntax_t syntax, + Idx nest, reg_errcode_t *err); + +static bin_tree_t *parse_sub_exp(re_string_t *regexp, regex_t *preg, + re_token_t *token, reg_syntax_t syntax, + Idx nest, reg_errcode_t *err); + +static bin_tree_t *parse_dup_op(bin_tree_t *dup_elem, re_string_t *regexp, + re_dfa_t *dfa, re_token_t *token, + reg_syntax_t syntax, reg_errcode_t *err); + +static bin_tree_t *parse_bracket_exp(re_string_t *regexp, re_dfa_t *dfa, + re_token_t *token, reg_syntax_t syntax, + reg_errcode_t *err); + +static reg_errcode_t parse_bracket_element(bracket_elem_t *elem, + re_string_t *regexp, + re_token_t *token, int token_len, + re_dfa_t *dfa, + reg_syntax_t syntax, + bool accept_hyphen); + +static reg_errcode_t parse_bracket_symbol(bracket_elem_t *elem, + re_string_t *regexp, + re_token_t *token); + +static reg_errcode_t build_equiv_class(bitset_t sbcset, + const unsigned char *name); + +static reg_errcode_t build_charclass(RE_TRANSLATE_TYPE trans, + bitset_t sbcset, + const char *class_name, + reg_syntax_t syntax); + +static bin_tree_t *build_charclass_op(re_dfa_t *dfa, + RE_TRANSLATE_TYPE trans, + const char *class_name, + const char *extra, + bool non_match, reg_errcode_t *err); + +static bin_tree_t *create_tree(re_dfa_t *dfa, + bin_tree_t *left, bin_tree_t *right, + re_token_type_t type); + +static bin_tree_t *create_token_tree(re_dfa_t *dfa, + bin_tree_t *left, bin_tree_t *right, + const re_token_t *token); + +static bin_tree_t *duplicate_tree(const bin_tree_t *src, re_dfa_t *dfa); + +static void free_token(re_token_t *node); + +static reg_errcode_t free_tree(void *extra, bin_tree_t *node); + +static reg_errcode_t mark_opt_subexp(void *extra, bin_tree_t *node); + +/* This table gives an error message for each of the error codes listed + in regex.h. Obviously the order here has to be same as there. + POSIX doesn't require that we do anything for REG_NOERROR, + but why not be nice? */ + +static const char __re_error_msgid[] = + { +#define REG_NOERROR_IDX 0 + gettext_noop("Success") /* REG_NOERROR */ + "\0" +#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") + gettext_noop ("No match") /* REG_NOMATCH */ + "\0" +#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") + gettext_noop ("Invalid regular expression") /* REG_BADPAT */ + "\0" +#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") + gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ + "\0" +#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") + gettext_noop ("Invalid character class name") /* REG_ECTYPE */ + "\0" +#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") + gettext_noop ("Trailing backslash") /* REG_EESCAPE */ + "\0" +#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") + gettext_noop ("Invalid back reference") /* REG_ESUBREG */ + "\0" +#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") + gettext_noop ("Unmatched [, [^, [:, [., or [=") /* REG_EBRACK */ + "\0" +#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [, [^, [:, [., or [=") + gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ + "\0" +#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") + gettext_noop ("Unmatched \\{") /* REG_EBRACE */ + "\0" +#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") + gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ + "\0" +#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") + gettext_noop ("Invalid range end") /* REG_ERANGE */ + "\0" +#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") + gettext_noop ("Memory exhausted") /* REG_ESPACE */ + "\0" +#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") + gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ + "\0" +#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") + gettext_noop ("Premature end of regular expression") /* REG_EEND */ + "\0" +#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") + gettext_noop ("Regular expression too big") /* REG_ESIZE */ + "\0" +#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") + gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ + }; + +static const size_t __re_error_msgid_idx[] = + { + REG_NOERROR_IDX, + REG_NOMATCH_IDX, + REG_BADPAT_IDX, + REG_ECOLLATE_IDX, + REG_ECTYPE_IDX, + REG_EESCAPE_IDX, + REG_ESUBREG_IDX, + REG_EBRACK_IDX, + REG_EPAREN_IDX, + REG_EBRACE_IDX, + REG_BADBR_IDX, + REG_ERANGE_IDX, + REG_ESPACE_IDX, + REG_BADRPT_IDX, + REG_EEND_IDX, + REG_ESIZE_IDX, + REG_ERPAREN_IDX + }; + +/* Entry points for GNU code. */ + +/* re_compile_pattern is the GNU regular expression compiler: it + compiles PATTERN (of length LENGTH) and puts the result in BUFP. + Returns 0 if the pattern was valid, otherwise an error string. + + Assumes the 'allocated' (and perhaps 'buffer') and 'translate' fields + are set in BUFP on entry. */ + +const char * +re_compile_pattern(const char *pattern, size_t length, + struct re_pattern_buffer *bufp) { + reg_errcode_t ret; + + /* And GNU code determines whether or not to get register information + by passing null for the REGS argument to re_match, etc., not by + setting no_sub, unless RE_NO_SUB is set. */ + bufp->no_sub = !!(re_syntax_options & RE_NO_SUB); + + /* Match anchors at newline. */ + bufp->newline_anchor = 1; + + ret = re_compile_internal(bufp, pattern, length, re_syntax_options); + + if (!ret) + return NULL; + return gettext(__re_error_msgid + __re_error_msgid_idx[(int) ret]); +} + + +/* Set by 're_set_syntax' to the current regexp syntax to recognize. Can + also be assigned to arbitrarily: each pattern buffer stores its own + syntax, so it can be changed between regex compilations. */ +/* This has no initializer because initialized variables in Emacs + become read-only after dumping. */ +reg_syntax_t re_syntax_options; + + +/* Specify the precise syntax of regexps for compilation. This provides + for compatibility for various utilities which historically have + different, incompatible syntaxes. + + The argument SYNTAX is a bit mask comprised of the various bits + defined in regex.h. We return the old syntax. */ + +reg_syntax_t +re_set_syntax(reg_syntax_t syntax) { + reg_syntax_t ret = re_syntax_options; + + re_syntax_options = syntax; + return ret; +} + +int +re_compile_fastmap(struct re_pattern_buffer *bufp) { + re_dfa_t *dfa = bufp->buffer; + char *fastmap = bufp->fastmap; + + memset(fastmap, '\0', sizeof(char) * SBC_MAX); + re_compile_fastmap_iter(bufp, dfa->init_state, fastmap); + if (dfa->init_state != dfa->init_state_word) + re_compile_fastmap_iter(bufp, dfa->init_state_word, fastmap); + if (dfa->init_state != dfa->init_state_nl) + re_compile_fastmap_iter(bufp, dfa->init_state_nl, fastmap); + if (dfa->init_state != dfa->init_state_begbuf) + re_compile_fastmap_iter(bufp, dfa->init_state_begbuf, fastmap); + bufp->fastmap_accurate = 1; + return 0; +} + + +static inline void +__attribute__ ((always_inline)) +re_set_fastmap(char *fastmap, bool icase, int ch) { + fastmap[ch] = 1; + if (icase) + fastmap[tolower(ch)] = 1; +} + +/* Helper function for re_compile_fastmap. + Compile fastmap for the initial_state INIT_STATE. */ + +static void +re_compile_fastmap_iter(regex_t *bufp, const re_dfastate_t *init_state, + char *fastmap) { + re_dfa_t *dfa = bufp->buffer; + Idx node_cnt; + bool icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); + for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) { + Idx node = init_state->nodes.elems[node_cnt]; + re_token_type_t type = dfa->nodes[node].type; + + if (type == CHARACTER) { + re_set_fastmap(fastmap, icase, dfa->nodes[node].opr.c); + } else if (type == SIMPLE_BRACKET) { + int i, ch; + for (i = 0, ch = 0; i < BITSET_WORDS; ++i) { + int j; + bitset_word_t w = dfa->nodes[node].opr.sbcset[i]; + for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) + if (w & ((bitset_word_t) 1 << j)) + re_set_fastmap(fastmap, icase, ch); + } + } else if (type == OP_PERIOD + || type == END_OF_RE) { + memset(fastmap, '\1', sizeof(char) * SBC_MAX); + if (type == END_OF_RE) + bufp->can_be_null = 1; + return; + } + } +} + +/* Entry point for POSIX code. */ +/* regcomp takes a regular expression as a string and compiles it. + + PREG is a regex_t *. We do not expect any fields to be initialized, + since POSIX says we shouldn't. Thus, we set + + 'buffer' to the compiled pattern; + 'used' to the length of the compiled pattern; + 'syntax' to RE_SYNTAX_POSIX_EXTENDED if the + REG_EXTENDED bit in CFLAGS is set; otherwise, to + RE_SYNTAX_POSIX_BASIC; + 'newline_anchor' to REG_NEWLINE being set in CFLAGS; + 'fastmap' to an allocated space for the fastmap; + 'fastmap_accurate' to zero; + 're_nsub' to the number of subexpressions in PATTERN. + + PATTERN is the address of the pattern string. + + CFLAGS is a series of bits which affect compilation. + + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we + use POSIX basic syntax. + + If REG_NEWLINE is set, then . and [^...] don't match newline. + Also, regexec will try a match beginning after every newline. + + If REG_ICASE is set, then we considers upper- and lowercase + versions of letters to be equivalent when matching. + + If REG_NOSUB is set, then when PREG is passed to regexec, that + routine will report only success or failure, and nothing about the + registers. + + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for + the return codes and their meanings.) */ + +int +regcomp(regex_t *_Restrict_ preg, const char *_Restrict_ pattern, int cflags) { + reg_errcode_t ret; + reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED + : RE_SYNTAX_POSIX_BASIC); + + preg->buffer = NULL; + preg->allocated = 0; + preg->used = 0; + + /* Try to allocate space for the fastmap. */ + preg->fastmap = re_malloc( + char, SBC_MAX); + if ((preg->fastmap == NULL)) + return REG_ESPACE; + + syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; + + /* If REG_NEWLINE is set, newlines are treated differently. */ + if (cflags & REG_NEWLINE) { /* REG_NEWLINE implies neither . nor [^...] match newline. */ + syntax &= ~RE_DOT_NEWLINE; + syntax |= RE_HAT_LISTS_NOT_NEWLINE; + /* It also changes the matching behavior. */ + preg->newline_anchor = 1; + } else + preg->newline_anchor = 0; + preg->no_sub = !!(cflags & REG_NOSUB); + preg->translate = NULL; + + ret = re_compile_internal(preg, pattern, strlen(pattern), syntax); + + /* POSIX doesn't distinguish between an unmatched open-group and an + unmatched close-group: both are REG_EPAREN. */ + if (ret == REG_ERPAREN) + ret = REG_EPAREN; + + /* We have already checked preg->fastmap != NULL. */ + if ((ret == REG_NOERROR)) + /* Compute the fastmap now, since regexec cannot modify the pattern + buffer. This function never fails in this implementation. */ + (void) re_compile_fastmap(preg); + else { + /* Some error occurred while compiling the expression. */ + re_free(preg->fastmap); + preg->fastmap = NULL; + } + + return (int) ret; +} + +/* Returns a message corresponding to an error code, ERRCODE, returned + from either regcomp or regexec. We don't use PREG here. */ + +size_t +regerror(int errcode, const regex_t *_Restrict_ preg, char *_Restrict_ errbuf, + size_t errbuf_size) { + const char *msg; + size_t msg_size; + int nerrcodes = sizeof __re_error_msgid_idx / sizeof __re_error_msgid_idx[0]; + + if ((errcode < 0 || errcode >= nerrcodes)) + /* Only error codes returned by the rest of the code should be passed + to this routine. If we are given anything else, or if other regex + code generates an invalid error code, then the program has a bug. + Dump core so we can fix it. */ + abort(); + + msg = gettext(__re_error_msgid + __re_error_msgid_idx[errcode]); + + msg_size = strlen(msg) + 1; /* Includes the null. */ + + if ((errbuf_size != 0)) { + size_t cpy_size = msg_size; + if ((msg_size > errbuf_size)) { + cpy_size = errbuf_size - 1; + errbuf[cpy_size] = '\0'; + } + memcpy(errbuf, msg, cpy_size); + } + + return msg_size; +} + +static void +free_dfa_content(re_dfa_t *dfa) { + Idx i, j; + + if (dfa->nodes) + for (i = 0; i < dfa->nodes_len; ++i) + free_token(dfa->nodes + i); + re_free(dfa->nexts); + for (i = 0; i < dfa->nodes_len; ++i) { + if (dfa->eclosures != NULL) + re_node_set_free(dfa->eclosures + i); + if (dfa->inveclosures != NULL) + re_node_set_free(dfa->inveclosures + i); + if (dfa->edests != NULL) + re_node_set_free(dfa->edests + i); + } + re_free(dfa->edests); + re_free(dfa->eclosures); + re_free(dfa->inveclosures); + re_free(dfa->nodes); + + if (dfa->state_table) + for (i = 0; i <= dfa->state_hash_mask; ++i) { + struct re_state_table_entry *entry = dfa->state_table + i; + for (j = 0; j < entry->num; ++j) { + re_dfastate_t *state = entry->array[j]; + free_state(state); + } + re_free(entry->array); + } + re_free(dfa->state_table); + re_free(dfa->subexp_map); + re_free(dfa); +} + + +/* Free dynamically allocated space used by PREG. */ + +void +regfree(regex_t *preg) { + re_dfa_t *dfa = preg->buffer; + if ((dfa != NULL)) { + lock_fini(dfa->lock); + free_dfa_content(dfa); + } + preg->buffer = NULL; + preg->allocated = 0; + + re_free(preg->fastmap); + preg->fastmap = NULL; + + re_free(preg->translate); + preg->translate = NULL; +} + +/* Internal entry point. + Compile the regular expression PATTERN, whose length is LENGTH. + SYNTAX indicate regular expression's syntax. */ + +static reg_errcode_t +re_compile_internal(regex_t *preg, const char *pattern, size_t length, + reg_syntax_t syntax) { + reg_errcode_t err = REG_NOERROR; + re_dfa_t *dfa; + re_string_t regexp; + + /* Initialize the pattern buffer. */ + preg->fastmap_accurate = 0; + preg->syntax = syntax; + preg->not_bol = preg->not_eol = 0; + preg->used = 0; + preg->re_nsub = 0; + preg->can_be_null = 0; + preg->regs_allocated = REGS_UNALLOCATED; + + /* Initialize the dfa. */ + dfa = preg->buffer; + if ((preg->allocated < sizeof(re_dfa_t))) { + /* If zero allocated, but buffer is non-null, try to realloc + enough space. This loses if buffer's address is bogus, but + that is the user's responsibility. If ->buffer is NULL this + is a simple allocation. */ + dfa = re_realloc(preg->buffer, re_dfa_t, 1); + if (dfa == NULL) + return REG_ESPACE; + preg->allocated = sizeof(re_dfa_t); + preg->buffer = dfa; + } + preg->used = sizeof(re_dfa_t); + + err = init_dfa(dfa, length); + if ((err == REG_NOERROR && lock_init(dfa->lock) != 0)) + err = REG_ESPACE; + if ((err != REG_NOERROR)) { + free_dfa_content(dfa); + preg->buffer = NULL; + preg->allocated = 0; + return err; + } + err = re_string_construct(®exp, pattern, length, preg->translate, + (syntax & RE_ICASE) != 0, dfa); + if ((err != REG_NOERROR)) { + re_compile_internal_free_return: + free_workarea_compile(preg); + re_string_destruct(®exp); + lock_fini(dfa->lock); + free_dfa_content(dfa); + preg->buffer = NULL; + preg->allocated = 0; + return err; + } + + /* Parse the regular expression, and build a structure tree. */ + preg->re_nsub = 0; + dfa->str_tree = parse(®exp, preg, syntax, &err); + if ((dfa->str_tree == NULL)) + goto re_compile_internal_free_return; + + /* Analyze the tree and create the nfa. */ + err = analyze(preg); + if ((err != REG_NOERROR)) + goto re_compile_internal_free_return; + + /* Then create the initial state of the dfa. */ + err = create_initial_state(dfa); + + /* Release work areas. */ + free_workarea_compile(preg); + re_string_destruct(®exp); + + if ((err != REG_NOERROR)) { + lock_fini(dfa->lock); + free_dfa_content(dfa); + preg->buffer = NULL; + preg->allocated = 0; + } + + return err; +} + +/* Initialize DFA. We use the length of the regular expression PAT_LEN + as the initial length of some arrays. */ + +static reg_errcode_t +init_dfa(re_dfa_t *dfa, size_t pat_len) { + __re_size_t table_size; + const char *codeset_name; + + size_t max_i18n_object_size = 0; + + size_t max_object_size = + MAX (sizeof(struct re_state_table_entry), + MAX(sizeof(re_token_t), + MAX(sizeof(re_node_set), + MAX(sizeof(regmatch_t), + max_i18n_object_size)))); + + memset(dfa, '\0', sizeof(re_dfa_t)); + + /* Force allocation of str_tree_storage the first time. */ + dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; + + /* Avoid overflows. The extra "/ 2" is for the table_size doubling + calculation below, and for similar doubling calculations + elsewhere. And it's <= rather than <, because some of the + doubling calculations add 1 afterwards. */ + if ((MIN (IDX_MAX, SIZE_MAX / max_object_size) / 2 + <= pat_len)) + return REG_ESPACE; + + dfa->nodes_alloc = pat_len + 1; + dfa->nodes = re_malloc(re_token_t, dfa->nodes_alloc); + + /* table_size = 2 ^ ceil(log pat_len) */ + for (table_size = 1;; table_size <<= 1) + if (table_size > pat_len) + break; + + dfa->state_table = calloc(sizeof(struct re_state_table_entry), table_size); + dfa->state_hash_mask = table_size - 1; + + dfa->mb_cur_max = MB_CUR_MAX; + codeset_name = nl_langinfo(CODESET); + if ((codeset_name[0] == 'U' || codeset_name[0] == 'u') + && (codeset_name[1] == 'T' || codeset_name[1] == 't') + && (codeset_name[2] == 'F' || codeset_name[2] == 'f') + && strcmp(codeset_name + 3 + (codeset_name[3] == '-'), "8") == 0) + dfa->is_utf8 = 1; + + /* We check exhaustively in the loop below if this charset is a + superset of ASCII. */ + dfa->map_notascii = 0; + + if ((dfa->nodes == NULL || dfa->state_table == NULL)) + return REG_ESPACE; + return REG_NOERROR; +} + +/* Initialize WORD_CHAR table, which indicate which character is + "word". In this case "word" means that it is the word construction + character used by some operators like "\<", "\>", etc. */ + +static void +init_word_char(re_dfa_t *dfa) { + int i = 0; + int j; + int ch = 0; + dfa->word_ops_used = 1; + if ((dfa->map_notascii == 0)) { + /* Avoid uint32_t and uint64_t as some non-GCC platforms lack + them, an issue when this code is used in Gnulib. */ + bitset_word_t bits0 = 0x00000000; + bitset_word_t bits1 = 0x03ff0000; + bitset_word_t bits2 = 0x87fffffe; + bitset_word_t bits3 = 0x07fffffe; + if (BITSET_WORD_BITS == 64) { + /* Pacify gcc -Woverflow on 32-bit platformns. */ + dfa->word_char[0] = bits1 << 31 << 1 | bits0; + dfa->word_char[1] = bits3 << 31 << 1 | bits2; + i = 2; + } else if (BITSET_WORD_BITS == 32) { + dfa->word_char[0] = bits0; + dfa->word_char[1] = bits1; + dfa->word_char[2] = bits2; + dfa->word_char[3] = bits3; + i = 4; + } else + goto general_case; + ch = 128; + + if ((dfa->is_utf8)) { + memset(&dfa->word_char[i], '\0', (SBC_MAX - ch) / 8); + return; + } + } + + general_case: + for (; i < BITSET_WORDS; ++i) + for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) + if (isalnum(ch) || ch == '_') + dfa->word_char[i] |= (bitset_word_t) 1 << j; +} + +/* Free the work area which are only used while compiling. */ + +static void +free_workarea_compile(regex_t *preg) { + re_dfa_t *dfa = preg->buffer; + bin_tree_storage_t *storage, *next; + for (storage = dfa->str_tree_storage; storage; storage = next) { + next = storage->next; + re_free(storage); + } + dfa->str_tree_storage = NULL; + dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE; + dfa->str_tree = NULL; + re_free(dfa->org_indices); + dfa->org_indices = NULL; +} + +/* Create initial states for all contexts. */ + +static reg_errcode_t +create_initial_state(re_dfa_t *dfa) { + Idx first, i; + reg_errcode_t err; + re_node_set init_nodes; + + /* Initial states have the epsilon closure of the node which is + the first node of the regular expression. */ + first = dfa->str_tree->first->node_idx; + dfa->init_node = first; + err = re_node_set_init_copy(&init_nodes, dfa->eclosures + first); + if ((err != REG_NOERROR)) + return err; + + /* The back-references which are in initial states can epsilon transit, + since in this case all of the subexpressions can be null. + Then we add epsilon closures of the nodes which are the next nodes of + the back-references. */ + if (dfa->nbackref > 0) + for (i = 0; i < init_nodes.nelem; ++i) { + Idx node_idx = init_nodes.elems[i]; + re_token_type_t type = dfa->nodes[node_idx].type; + + Idx clexp_idx; + if (type != OP_BACK_REF) + continue; + for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) { + re_token_t *clexp_node; + clexp_node = dfa->nodes + init_nodes.elems[clexp_idx]; + if (clexp_node->type == OP_CLOSE_SUBEXP + && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx) + break; + } + if (clexp_idx == init_nodes.nelem) + continue; + + if (type == OP_BACK_REF) { + Idx dest_idx = dfa->edests[node_idx].elems[0]; + if (!re_node_set_contains(&init_nodes, dest_idx)) { + reg_errcode_t merge_err + = re_node_set_merge(&init_nodes, dfa->eclosures + dest_idx); + if (merge_err != REG_NOERROR) + return merge_err; + i = 0; + } + } + } + + /* It must be the first time to invoke acquire_state. */ + dfa->init_state = re_acquire_state_context(&err, dfa, &init_nodes, 0); + /* We don't check ERR here, since the initial state must not be NULL. */ + if ((dfa->init_state == NULL)) + return err; + if (dfa->init_state->has_constraint) { + dfa->init_state_word = re_acquire_state_context(&err, dfa, &init_nodes, + CONTEXT_WORD); + dfa->init_state_nl = re_acquire_state_context(&err, dfa, &init_nodes, + CONTEXT_NEWLINE); + dfa->init_state_begbuf = re_acquire_state_context(&err, dfa, + &init_nodes, + CONTEXT_NEWLINE + | CONTEXT_BEGBUF); + if ((dfa->init_state_word == NULL + || dfa->init_state_nl == NULL + || dfa->init_state_begbuf == NULL)) + return err; + } else + dfa->init_state_word = dfa->init_state_nl + = dfa->init_state_begbuf = dfa->init_state; + + re_node_set_free(&init_nodes); + return REG_NOERROR; +} + + +/* Analyze the structure tree, and calculate "first", "next", "edest", + "eclosure", and "inveclosure". */ + +static reg_errcode_t +analyze(regex_t *preg) { + re_dfa_t *dfa = preg->buffer; + reg_errcode_t ret; + + /* Allocate arrays. */ + dfa->nexts = re_malloc(Idx, dfa->nodes_alloc); + dfa->org_indices = re_malloc(Idx, dfa->nodes_alloc); + dfa->edests = re_malloc(re_node_set, dfa->nodes_alloc); + dfa->eclosures = re_malloc(re_node_set, dfa->nodes_alloc); + if ((dfa->nexts == NULL || dfa->org_indices == NULL + || dfa->edests == NULL || dfa->eclosures == NULL)) + return REG_ESPACE; + + dfa->subexp_map = re_malloc(Idx, preg->re_nsub); + if (dfa->subexp_map != NULL) { + Idx i; + for (i = 0; i < preg->re_nsub; i++) + dfa->subexp_map[i] = i; + preorder(dfa->str_tree, optimize_subexps, dfa); + for (i = 0; i < preg->re_nsub; i++) + if (dfa->subexp_map[i] != i) + break; + if (i == preg->re_nsub) { + re_free(dfa->subexp_map); + dfa->subexp_map = NULL; + } + } + + ret = postorder(dfa->str_tree, lower_subexps, preg); + if ((ret != REG_NOERROR)) + return ret; + ret = postorder(dfa->str_tree, calc_first, dfa); + if ((ret != REG_NOERROR)) + return ret; + preorder(dfa->str_tree, calc_next, dfa); + ret = preorder(dfa->str_tree, link_nfa_nodes, dfa); + if ((ret != REG_NOERROR)) + return ret; + ret = calc_eclosure(dfa); + if ((ret != REG_NOERROR)) + return ret; + + /* We only need this during the prune_impossible_nodes pass in regexec.c; + skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */ + if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match) + || dfa->nbackref) { + dfa->inveclosures = re_malloc(re_node_set, dfa->nodes_len); + if ((dfa->inveclosures == NULL)) + return REG_ESPACE; + ret = calc_inveclosure(dfa); + } + + return ret; +} + +/* Our parse trees are very unbalanced, so we cannot use a stack to + implement parse tree visits. Instead, we use parent pointers and + some hairy code in these two functions. */ +static reg_errcode_t +postorder(bin_tree_t *root, reg_errcode_t (fn(void *, bin_tree_t *)), + void *extra) { + bin_tree_t *node, *prev; + + for (node = root;;) { + /* Descend down the tree, preferably to the left (or to the right + if that's the only child). */ + while (node->left || node->right) + if (node->left) + node = node->left; + else + node = node->right; + + do { + reg_errcode_t err = fn(extra, node); + if ((err != REG_NOERROR)) + return err; + if (node->parent == NULL) + return REG_NOERROR; + prev = node; + node = node->parent; + } + /* Go up while we have a node that is reached from the right. */ + while (node->right == prev || node->right == NULL); + node = node->right; + } +} + +static reg_errcode_t +preorder(bin_tree_t *root, reg_errcode_t (fn(void *, bin_tree_t *)), + void *extra) { + bin_tree_t *node; + + for (node = root;;) { + reg_errcode_t err = fn(extra, node); + if ((err != REG_NOERROR)) + return err; + + /* Go to the left node, or up and to the right. */ + if (node->left) + node = node->left; + else { + bin_tree_t *prev = NULL; + while (node->right == prev || node->right == NULL) { + prev = node; + node = node->parent; + if (!node) + return REG_NOERROR; + } + node = node->right; + } + } +} + +/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell + re_search_internal to map the inner one's opr.idx to this one's. Adjust + backreferences as well. Requires a preorder visit. */ +static reg_errcode_t +optimize_subexps(void *extra, bin_tree_t *node) { + re_dfa_t *dfa = (re_dfa_t *) extra; + + if (node->token.type == OP_BACK_REF && dfa->subexp_map) { + int idx = node->token.opr.idx; + node->token.opr.idx = dfa->subexp_map[idx]; + dfa->used_bkref_map |= 1 << node->token.opr.idx; + } else if (node->token.type == SUBEXP + && node->left && node->left->token.type == SUBEXP) { + Idx other_idx = node->left->token.opr.idx; + + node->left = node->left->left; + if (node->left) + node->left->parent = node; + + dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx]; + if (other_idx < BITSET_WORD_BITS) + dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx); + } + + return REG_NOERROR; +} + +/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation + of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */ +static reg_errcode_t +lower_subexps(void *extra, bin_tree_t *node) { + regex_t *preg = (regex_t *) extra; + reg_errcode_t err = REG_NOERROR; + + if (node->left && node->left->token.type == SUBEXP) { + node->left = lower_subexp(&err, preg, node->left); + if (node->left) + node->left->parent = node; + } + if (node->right && node->right->token.type == SUBEXP) { + node->right = lower_subexp(&err, preg, node->right); + if (node->right) + node->right->parent = node; + } + + return err; +} + +static bin_tree_t * +lower_subexp(reg_errcode_t *err, regex_t *preg, bin_tree_t *node) { + re_dfa_t *dfa = preg->buffer; + bin_tree_t *body = node->left; + bin_tree_t *op, *cls, *tree1, *tree; + + if (preg->no_sub + /* We do not optimize empty subexpressions, because otherwise we may + have bad CONCAT nodes with NULL children. This is obviously not + very common, so we do not lose much. An example that triggers + this case is the sed "script" /\(\)/x. */ + && node->left != NULL + && (node->token.opr.idx >= BITSET_WORD_BITS + || !(dfa->used_bkref_map + & ((bitset_word_t) 1 << node->token.opr.idx)))) + return node->left; + + /* Convert the SUBEXP node to the concatenation of an + OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */ + op = create_tree(dfa, NULL, NULL, OP_OPEN_SUBEXP); + cls = create_tree(dfa, NULL, NULL, OP_CLOSE_SUBEXP); + tree1 = body ? create_tree(dfa, body, cls, CONCAT) : cls; + tree = create_tree(dfa, op, tree1, CONCAT); + if ((tree == NULL || tree1 == NULL + || op == NULL || cls == NULL)) { + *err = REG_ESPACE; + return NULL; + } + + op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx; + op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp; + return tree; +} + +/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton + nodes. Requires a postorder visit. */ +static reg_errcode_t +calc_first(void *extra, bin_tree_t *node) { + re_dfa_t *dfa = (re_dfa_t *) extra; + if (node->token.type == CONCAT) { + node->first = node->left->first; + node->node_idx = node->left->node_idx; + } else { + node->first = node; + node->node_idx = re_dfa_add_node(dfa, node->token); + if ((node->node_idx == -1)) + return REG_ESPACE; + if (node->token.type == ANCHOR) + dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type; + } + return REG_NOERROR; +} + +/* Pass 2: compute NEXT on the tree. Preorder visit. */ +static reg_errcode_t +calc_next(void *extra, bin_tree_t *node) { + switch (node->token.type) { + case OP_DUP_ASTERISK: + node->left->next = node; + break; + case CONCAT: + node->left->next = node->right->first; + node->right->next = node->next; + break; + default: + if (node->left) + node->left->next = node->next; + if (node->right) + node->right->next = node->next; + break; + } + return REG_NOERROR; +} + +/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */ +static reg_errcode_t +link_nfa_nodes(void *extra, bin_tree_t *node) { + re_dfa_t *dfa = (re_dfa_t *) extra; + Idx idx = node->node_idx; + reg_errcode_t err = REG_NOERROR; + + switch (node->token.type) { + case CONCAT: + break; + + case END_OF_RE: + assert(node->next == NULL); + break; + + case OP_DUP_ASTERISK: + case OP_ALT: { + Idx left, right; + dfa->has_plural_match = 1; + if (node->left != NULL) + left = node->left->first->node_idx; + else + left = node->next->node_idx; + if (node->right != NULL) + right = node->right->first->node_idx; + else + right = node->next->node_idx; + assert(left > -1); + assert(right > -1); + err = re_node_set_init_2(dfa->edests + idx, left, right); + } + break; + + case ANCHOR: + case OP_OPEN_SUBEXP: + case OP_CLOSE_SUBEXP: + err = re_node_set_init_1(dfa->edests + idx, node->next->node_idx); + break; + + case OP_BACK_REF: + dfa->nexts[idx] = node->next->node_idx; + if (node->token.type == OP_BACK_REF) + err = re_node_set_init_1(dfa->edests + idx, dfa->nexts[idx]); + break; + + default: + assert(!IS_EPSILON_NODE(node->token.type)); + dfa->nexts[idx] = node->next->node_idx; + break; + } + + return err; +} + +/* Duplicate the epsilon closure of the node ROOT_NODE. + Note that duplicated nodes have constraint INIT_CONSTRAINT in addition + to their own constraint. */ + +static reg_errcode_t +duplicate_node_closure(re_dfa_t *dfa, Idx top_org_node, Idx top_clone_node, + Idx root_node, unsigned int init_constraint) { + Idx org_node, clone_node; + bool ok; + unsigned int constraint = init_constraint; + for (org_node = top_org_node, clone_node = top_clone_node;;) { + Idx org_dest, clone_dest; + if (dfa->nodes[org_node].type == OP_BACK_REF) { + /* If the back reference epsilon-transit, its destination must + also have the constraint. Then duplicate the epsilon closure + of the destination of the back reference, and store it in + edests of the back reference. */ + org_dest = dfa->nexts[org_node]; + re_node_set_empty(dfa->edests + clone_node); + clone_dest = duplicate_node(dfa, org_dest, constraint); + if ((clone_dest == -1)) + return REG_ESPACE; + dfa->nexts[clone_node] = dfa->nexts[org_node]; + ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); + if ((!ok)) + return REG_ESPACE; + } else if (dfa->edests[org_node].nelem == 0) { + /* In case of the node can't epsilon-transit, don't duplicate the + destination and store the original destination as the + destination of the node. */ + dfa->nexts[clone_node] = dfa->nexts[org_node]; + break; + } else if (dfa->edests[org_node].nelem == 1) { + /* In case of the node can epsilon-transit, and it has only one + destination. */ + org_dest = dfa->edests[org_node].elems[0]; + re_node_set_empty(dfa->edests + clone_node); + /* If the node is root_node itself, it means the epsilon closure + has a loop. Then tie it to the destination of the root_node. */ + if (org_node == root_node && clone_node != org_node) { + ok = re_node_set_insert(dfa->edests + clone_node, org_dest); + if ((!ok)) + return REG_ESPACE; + break; + } + /* In case the node has another constraint, append it. */ + constraint |= dfa->nodes[org_node].constraint; + clone_dest = duplicate_node(dfa, org_dest, constraint); + if ((clone_dest == -1)) + return REG_ESPACE; + ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); + if ((!ok)) + return REG_ESPACE; + } else /* dfa->edests[org_node].nelem == 2 */ + { + /* In case of the node can epsilon-transit, and it has two + destinations. In the bin_tree_t and DFA, that's '|' and '*'. */ + org_dest = dfa->edests[org_node].elems[0]; + re_node_set_empty(dfa->edests + clone_node); + /* Search for a duplicated node which satisfies the constraint. */ + clone_dest = search_duplicated_node(dfa, org_dest, constraint); + if (clone_dest == -1) { + /* There is no such duplicated node, create a new one. */ + reg_errcode_t err; + clone_dest = duplicate_node(dfa, org_dest, constraint); + if ((clone_dest == -1)) + return REG_ESPACE; + ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); + if ((!ok)) + return REG_ESPACE; + err = duplicate_node_closure(dfa, org_dest, clone_dest, + root_node, constraint); + if ((err != REG_NOERROR)) + return err; + } else { + /* There is a duplicated node which satisfies the constraint, + use it to avoid infinite loop. */ + ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); + if ((!ok)) + return REG_ESPACE; + } + + org_dest = dfa->edests[org_node].elems[1]; + clone_dest = duplicate_node(dfa, org_dest, constraint); + if ((clone_dest == -1)) + return REG_ESPACE; + ok = re_node_set_insert(dfa->edests + clone_node, clone_dest); + if ((!ok)) + return REG_ESPACE; + } + org_node = org_dest; + clone_node = clone_dest; + } + return REG_NOERROR; +} + +/* Search for a node which is duplicated from the node ORG_NODE, and + satisfies the constraint CONSTRAINT. */ + +static Idx +search_duplicated_node(const re_dfa_t *dfa, Idx org_node, + unsigned int constraint) { + Idx idx; + for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) { + if (org_node == dfa->org_indices[idx] + && constraint == dfa->nodes[idx].constraint) + return idx; /* Found. */ + } + return -1; /* Not found. */ +} + +/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. + Return the index of the new node, or -1 if insufficient storage is + available. */ + +static Idx +duplicate_node(re_dfa_t *dfa, Idx org_idx, unsigned int constraint) { + Idx dup_idx = re_dfa_add_node(dfa, dfa->nodes[org_idx]); + if ((dup_idx != -1)) { + dfa->nodes[dup_idx].constraint = constraint; + dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint; + dfa->nodes[dup_idx].duplicated = 1; + + /* Store the index of the original node. */ + dfa->org_indices[dup_idx] = org_idx; + } + return dup_idx; +} + +static reg_errcode_t +calc_inveclosure(re_dfa_t *dfa) { + Idx src, idx; + bool ok; + for (idx = 0; idx < dfa->nodes_len; ++idx) + re_node_set_init_empty(dfa->inveclosures + idx); + + for (src = 0; src < dfa->nodes_len; ++src) { + Idx *elems = dfa->eclosures[src].elems; + for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) { + ok = re_node_set_insert_last(dfa->inveclosures + elems[idx], src); + if ((!ok)) + return REG_ESPACE; + } + } + + return REG_NOERROR; +} + +/* Calculate "eclosure" for all the node in DFA. */ + +static reg_errcode_t +calc_eclosure(re_dfa_t *dfa) { + Idx node_idx; + bool incomplete; + incomplete = false; + /* For each nodes, calculate epsilon closure. */ + for (node_idx = 0;; ++node_idx) { + reg_errcode_t err; + re_node_set eclosure_elem; + if (node_idx == dfa->nodes_len) { + if (!incomplete) + break; + incomplete = false; + node_idx = 0; + } + + /* If we have already calculated, skip it. */ + if (dfa->eclosures[node_idx].nelem != 0) + continue; + /* Calculate epsilon closure of 'node_idx'. */ + err = calc_eclosure_iter(&eclosure_elem, dfa, node_idx, true); + if ((err != REG_NOERROR)) + return err; + + if (dfa->eclosures[node_idx].nelem == 0) { + incomplete = true; + re_node_set_free(&eclosure_elem); + } + } + return REG_NOERROR; +} + +/* Calculate epsilon closure of NODE. */ + +static reg_errcode_t +calc_eclosure_iter(re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root) { + reg_errcode_t err; + Idx i; + re_node_set eclosure; + bool ok; + bool incomplete = false; + err = re_node_set_alloc(&eclosure, dfa->edests[node].nelem + 1); + if ((err != REG_NOERROR)) + return err; + + /* This indicates that we are calculating this node now. + We reference this value to avoid infinite loop. */ + dfa->eclosures[node].nelem = -1; + + /* If the current node has constraints, duplicate all nodes + since they must inherit the constraints. */ + if (dfa->nodes[node].constraint + && dfa->edests[node].nelem + && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) { + err = duplicate_node_closure(dfa, node, node, node, + dfa->nodes[node].constraint); + if ((err != REG_NOERROR)) + return err; + } + + /* Expand each epsilon destination nodes. */ + if (IS_EPSILON_NODE(dfa->nodes[node].type)) + for (i = 0; i < dfa->edests[node].nelem; ++i) { + re_node_set eclosure_elem; + Idx edest = dfa->edests[node].elems[i]; + /* If calculating the epsilon closure of 'edest' is in progress, + return intermediate result. */ + if (dfa->eclosures[edest].nelem == -1) { + incomplete = true; + continue; + } + /* If we haven't calculated the epsilon closure of 'edest' yet, + calculate now. Otherwise use calculated epsilon closure. */ + if (dfa->eclosures[edest].nelem == 0) { + err = calc_eclosure_iter(&eclosure_elem, dfa, edest, false); + if ((err != REG_NOERROR)) + return err; + } else + eclosure_elem = dfa->eclosures[edest]; + /* Merge the epsilon closure of 'edest'. */ + err = re_node_set_merge(&eclosure, &eclosure_elem); + if ((err != REG_NOERROR)) + return err; + /* If the epsilon closure of 'edest' is incomplete, + the epsilon closure of this node is also incomplete. */ + if (dfa->eclosures[edest].nelem == 0) { + incomplete = true; + re_node_set_free(&eclosure_elem); + } + } + + /* An epsilon closure includes itself. */ + ok = re_node_set_insert(&eclosure, node); + if ((!ok)) + return REG_ESPACE; + if (incomplete && !root) + dfa->eclosures[node].nelem = 0; + else + dfa->eclosures[node] = eclosure; + *new_set = eclosure; + return REG_NOERROR; +} + +/* Functions for token which are used in the parser. */ + +/* Fetch a token from INPUT. + We must not use this function inside bracket expressions. */ + +static void +fetch_token(re_token_t *result, re_string_t *input, reg_syntax_t syntax) { + re_string_skip_bytes(input, peek_token(result, input, syntax)); +} + +/* Peek a token from INPUT, and return the length of the token. + We must not use this function inside bracket expressions. */ + +static int +peek_token(re_token_t *token, re_string_t *input, reg_syntax_t syntax) { + unsigned char c; + + if (re_string_eoi(input)) { + token->type = END_OF_RE; + return 0; + } + + c = re_string_peek_byte(input, 0); + token->opr.c = c; + + token->word_char = 0; + + if (c == '\\') { + unsigned char c2; + if (re_string_cur_idx(input) + 1 >= re_string_length(input)) { + token->type = BACK_SLASH; + return 1; + } + + c2 = re_string_peek_byte_case(input, 1); + token->opr.c = c2; + token->type = CHARACTER; + + token->word_char = IS_WORD_CHAR(c2) != 0; + + switch (c2) { + case '|': + if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) + token->type = OP_ALT; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (!(syntax & RE_NO_BK_REFS)) { + token->type = OP_BACK_REF; + token->opr.idx = c2 - '1'; + } + break; + case '<': + if (!(syntax & RE_NO_GNU_OPS)) { + token->type = ANCHOR; + token->opr.ctx_type = WORD_FIRST; + } + break; + case '>': + if (!(syntax & RE_NO_GNU_OPS)) { + token->type = ANCHOR; + token->opr.ctx_type = WORD_LAST; + } + break; + case 'b': + if (!(syntax & RE_NO_GNU_OPS)) { + token->type = ANCHOR; + token->opr.ctx_type = WORD_DELIM; + } + break; + case 'B': + if (!(syntax & RE_NO_GNU_OPS)) { + token->type = ANCHOR; + token->opr.ctx_type = NOT_WORD_DELIM; + } + break; + case 'w': + if (!(syntax & RE_NO_GNU_OPS)) + token->type = OP_WORD; + break; + case 'W': + if (!(syntax & RE_NO_GNU_OPS)) + token->type = OP_NOTWORD; + break; + case 's': + if (!(syntax & RE_NO_GNU_OPS)) + token->type = OP_SPACE; + break; + case 'S': + if (!(syntax & RE_NO_GNU_OPS)) + token->type = OP_NOTSPACE; + break; + case '`': + if (!(syntax & RE_NO_GNU_OPS)) { + token->type = ANCHOR; + token->opr.ctx_type = BUF_FIRST; + } + break; + case '\'': + if (!(syntax & RE_NO_GNU_OPS)) { + token->type = ANCHOR; + token->opr.ctx_type = BUF_LAST; + } + break; + case '(': + if (!(syntax & RE_NO_BK_PARENS)) + token->type = OP_OPEN_SUBEXP; + break; + case ')': + if (!(syntax & RE_NO_BK_PARENS)) + token->type = OP_CLOSE_SUBEXP; + break; + case '+': + if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) + token->type = OP_DUP_PLUS; + break; + case '?': + if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) + token->type = OP_DUP_QUESTION; + break; + case '{': + if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) + token->type = OP_OPEN_DUP_NUM; + break; + case '}': + if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) + token->type = OP_CLOSE_DUP_NUM; + break; + default: + break; + } + return 2; + } + + token->type = CHARACTER; + + token->word_char = IS_WORD_CHAR(token->opr.c); + + switch (c) { + case '\n': + if (syntax & RE_NEWLINE_ALT) + token->type = OP_ALT; + break; + case '|': + if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) + token->type = OP_ALT; + break; + case '*': + token->type = OP_DUP_ASTERISK; + break; + case '+': + if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) + token->type = OP_DUP_PLUS; + break; + case '?': + if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) + token->type = OP_DUP_QUESTION; + break; + case '{': + if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + token->type = OP_OPEN_DUP_NUM; + break; + case '}': + if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) + token->type = OP_CLOSE_DUP_NUM; + break; + case '(': + if (syntax & RE_NO_BK_PARENS) + token->type = OP_OPEN_SUBEXP; + break; + case ')': + if (syntax & RE_NO_BK_PARENS) + token->type = OP_CLOSE_SUBEXP; + break; + case '[': + token->type = OP_OPEN_BRACKET; + break; + case '.': + token->type = OP_PERIOD; + break; + case '^': + if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) && + re_string_cur_idx(input) != 0) { + char prev = re_string_peek_byte(input, -1); + if (!(syntax & RE_NEWLINE_ALT) || prev != '\n') + break; + } + token->type = ANCHOR; + token->opr.ctx_type = LINE_FIRST; + break; + case '$': + if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && + re_string_cur_idx(input) + 1 != re_string_length(input)) { + re_token_t next; + re_string_skip_bytes(input, 1); + peek_token(&next, input, syntax); + re_string_skip_bytes(input, -1); + if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP) + break; + } + token->type = ANCHOR; + token->opr.ctx_type = LINE_LAST; + break; + default: + break; + } + return 1; +} + +/* Peek a token from INPUT, and return the length of the token. + We must not use this function out of bracket expressions. */ + +static int +peek_token_bracket(re_token_t *token, re_string_t *input, reg_syntax_t syntax) { + unsigned char c; + if (re_string_eoi(input)) { + token->type = END_OF_RE; + return 0; + } + c = re_string_peek_byte(input, 0); + token->opr.c = c; + + if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) + && re_string_cur_idx(input) + 1 < re_string_length(input)) { + /* In this case, '\' escape a character. */ + unsigned char c2; + re_string_skip_bytes(input, 1); + c2 = re_string_peek_byte(input, 0); + token->opr.c = c2; + token->type = CHARACTER; + return 1; + } + if (c == '[') /* '[' is a special char in a bracket exps. */ + { + unsigned char c2; + int token_len; + if (re_string_cur_idx(input) + 1 < re_string_length(input)) + c2 = re_string_peek_byte(input, 1); + else + c2 = 0; + token->opr.c = c2; + token_len = 2; + switch (c2) { + case '.': + token->type = OP_OPEN_COLL_ELEM; + break; + + case '=': + token->type = OP_OPEN_EQUIV_CLASS; + break; + + case ':': + if (syntax & RE_CHAR_CLASSES) { + token->type = OP_OPEN_CHAR_CLASS; + break; + } + FALLTHROUGH; + default: + token->type = CHARACTER; + token->opr.c = c; + token_len = 1; + break; + } + return token_len; + } + switch (c) { + case '-': + token->type = OP_CHARSET_RANGE; + break; + case ']': + token->type = OP_CLOSE_BRACKET; + break; + case '^': + token->type = OP_NON_MATCH_LIST; + break; + default: + token->type = CHARACTER; + } + return 1; +} + +/* Functions for parser. */ + +/* Entry point of the parser. + Parse the regular expression REGEXP and return the structure tree. + If an error occurs, ERR is set by error code, and return NULL. + This function build the following tree, from regular expression : + CAT + / \ + / \ + EOR + + CAT means concatenation. + EOR means end of regular expression. */ + +static bin_tree_t * +parse(re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, + reg_errcode_t *err) { + re_dfa_t *dfa = preg->buffer; + bin_tree_t *tree, *eor, *root; + re_token_t current_token; + dfa->syntax = syntax; + fetch_token(¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); + tree = parse_reg_exp(regexp, preg, ¤t_token, syntax, 0, err); + if ((*err != REG_NOERROR && tree == NULL)) + return NULL; + eor = create_tree(dfa, NULL, NULL, END_OF_RE); + if (tree != NULL) + root = create_tree(dfa, tree, eor, CONCAT); + else + root = eor; + if ((eor == NULL || root == NULL)) { + *err = REG_ESPACE; + return NULL; + } + return root; +} + +/* This function build the following tree, from regular expression + |: + ALT + / \ + / \ + + + ALT means alternative, which represents the operator '|'. */ + +static bin_tree_t * +parse_reg_exp(re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { + re_dfa_t *dfa = preg->buffer; + bin_tree_t *tree, *branch = NULL; + bitset_word_t initial_bkref_map = dfa->completed_bkref_map; + tree = parse_branch(regexp, preg, token, syntax, nest, err); + if ((*err != REG_NOERROR && tree == NULL)) + return NULL; + + while (token->type == OP_ALT) { + fetch_token(token, regexp, syntax | RE_CARET_ANCHORS_HERE); + if (token->type != OP_ALT && token->type != END_OF_RE + && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { + bitset_word_t accumulated_bkref_map = dfa->completed_bkref_map; + dfa->completed_bkref_map = initial_bkref_map; + branch = parse_branch(regexp, preg, token, syntax, nest, err); + if ((*err != REG_NOERROR && branch == NULL)) { + if (tree != NULL) + postorder(tree, free_tree, NULL); + return NULL; + } + dfa->completed_bkref_map |= accumulated_bkref_map; + } else + branch = NULL; + tree = create_tree(dfa, tree, branch, OP_ALT); + if ((tree == NULL)) { + *err = REG_ESPACE; + return NULL; + } + } + return tree; +} + +/* This function build the following tree, from regular expression + : + CAT + / \ + / \ + + + CAT means concatenation. */ + +static bin_tree_t * +parse_branch(re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { + bin_tree_t *tree, *expr; + re_dfa_t *dfa = preg->buffer; + tree = parse_expression(regexp, preg, token, syntax, nest, err); + if ((*err != REG_NOERROR && tree == NULL)) + return NULL; + + while (token->type != OP_ALT && token->type != END_OF_RE + && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { + expr = parse_expression(regexp, preg, token, syntax, nest, err); + if ((*err != REG_NOERROR && expr == NULL)) { + if (tree != NULL) + postorder(tree, free_tree, NULL); + return NULL; + } + if (tree != NULL && expr != NULL) { + bin_tree_t *newtree = create_tree(dfa, tree, expr, CONCAT); + if (newtree == NULL) { + postorder(expr, free_tree, NULL); + postorder(tree, free_tree, NULL); + *err = REG_ESPACE; + return NULL; + } + tree = newtree; + } else if (tree == NULL) + tree = expr; + /* Otherwise expr == NULL, we don't need to create new tree. */ + } + return tree; +} + +/* This function build the following tree, from regular expression a*: + * + | + a +*/ + +static bin_tree_t * +parse_expression(re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { + re_dfa_t *dfa = preg->buffer; + bin_tree_t *tree; + switch (token->type) { + case CHARACTER: + tree = create_token_tree(dfa, NULL, NULL, token); + if ((tree == NULL)) { + *err = REG_ESPACE; + return NULL; + } + break; + + case OP_OPEN_SUBEXP: + tree = parse_sub_exp(regexp, preg, token, syntax, nest + 1, err); + if ((*err != REG_NOERROR && tree == NULL)) + return NULL; + break; + + case OP_OPEN_BRACKET: + tree = parse_bracket_exp(regexp, dfa, token, syntax, err); + if ((*err != REG_NOERROR && tree == NULL)) + return NULL; + break; + + case OP_BACK_REF: + if (!(dfa->completed_bkref_map & (1 << token->opr.idx))) { + *err = REG_ESUBREG; + return NULL; + } + dfa->used_bkref_map |= 1 << token->opr.idx; + tree = create_token_tree(dfa, NULL, NULL, token); + if ((tree == NULL)) { + *err = REG_ESPACE; + return NULL; + } + ++dfa->nbackref; + dfa->has_mb_node = 1; + break; + + case OP_OPEN_DUP_NUM: + if (syntax & RE_CONTEXT_INVALID_DUP) { + *err = REG_BADRPT; + return NULL; + } + FALLTHROUGH; + case OP_DUP_ASTERISK: + case OP_DUP_PLUS: + case OP_DUP_QUESTION: + if (syntax & RE_CONTEXT_INVALID_OPS) { + *err = REG_BADRPT; + return NULL; + } else if (syntax & RE_CONTEXT_INDEP_OPS) { + fetch_token(token, regexp, syntax); + return parse_expression(regexp, preg, token, syntax, nest, err); + } + FALLTHROUGH; + case OP_CLOSE_SUBEXP: + if ((token->type == OP_CLOSE_SUBEXP) && + !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) { + *err = REG_ERPAREN; + return NULL; + } + FALLTHROUGH; + case OP_CLOSE_DUP_NUM: + /* We treat it as a normal character. */ + + /* Then we can these characters as normal characters. */ + token->type = CHARACTER; + /* mb_partial and word_char bits should be initialized already + by peek_token. */ + tree = create_token_tree(dfa, NULL, NULL, token); + if ((tree == NULL)) { + *err = REG_ESPACE; + return NULL; + } + break; + + case ANCHOR: + if ((token->opr.ctx_type + & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST)) + && dfa->word_ops_used == 0) + init_word_char(dfa); + if (token->opr.ctx_type == WORD_DELIM + || token->opr.ctx_type == NOT_WORD_DELIM) { + bin_tree_t *tree_first, *tree_last; + if (token->opr.ctx_type == WORD_DELIM) { + token->opr.ctx_type = WORD_FIRST; + tree_first = create_token_tree(dfa, NULL, NULL, token); + token->opr.ctx_type = WORD_LAST; + } else { + token->opr.ctx_type = INSIDE_WORD; + tree_first = create_token_tree(dfa, NULL, NULL, token); + token->opr.ctx_type = INSIDE_NOTWORD; + } + tree_last = create_token_tree(dfa, NULL, NULL, token); + tree = create_tree(dfa, tree_first, tree_last, OP_ALT); + if ((tree_first == NULL || tree_last == NULL + || tree == NULL)) { + *err = REG_ESPACE; + return NULL; + } + } else { + tree = create_token_tree(dfa, NULL, NULL, token); + if ((tree == NULL)) { + *err = REG_ESPACE; + return NULL; + } + } + /* We must return here, since ANCHORs can't be followed + by repetition operators. + eg. RE"^*" is invalid or "", + it must not be "". */ + fetch_token(token, regexp, syntax); + return tree; + + case OP_PERIOD: + tree = create_token_tree(dfa, NULL, NULL, token); + if ((tree == NULL)) { + *err = REG_ESPACE; + return NULL; + } + if (dfa->mb_cur_max > 1) + dfa->has_mb_node = 1; + break; + + case OP_WORD: + case OP_NOTWORD: + tree = build_charclass_op(dfa, regexp->trans, + "alnum", + "_", + token->type == OP_NOTWORD, err); + if ((*err != REG_NOERROR && tree == NULL)) + return NULL; + break; + + case OP_SPACE: + case OP_NOTSPACE: + tree = build_charclass_op(dfa, regexp->trans, + "space", + "", + token->type == OP_NOTSPACE, err); + if ((*err != REG_NOERROR && tree == NULL)) + return NULL; + break; + + case OP_ALT: + case END_OF_RE: + return NULL; + + case BACK_SLASH: + *err = REG_EESCAPE; + return NULL; + + default: + /* Must not happen? */ + return NULL; + } + fetch_token(token, regexp, syntax); + + while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS + || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) { + bin_tree_t *dup_tree = parse_dup_op(tree, regexp, dfa, token, + syntax, err); + if ((*err != REG_NOERROR && dup_tree == NULL)) { + if (tree != NULL) + postorder(tree, free_tree, NULL); + return NULL; + } + tree = dup_tree; + /* In BRE consecutive duplications are not allowed. */ + if ((syntax & RE_CONTEXT_INVALID_DUP) + && (token->type == OP_DUP_ASTERISK + || token->type == OP_OPEN_DUP_NUM)) { + if (tree != NULL) + postorder(tree, free_tree, NULL); + *err = REG_BADRPT; + return NULL; + } + } + + return tree; +} + +/* This function build the following tree, from regular expression + (): + SUBEXP + | + +*/ + +static bin_tree_t * +parse_sub_exp(re_string_t *regexp, regex_t *preg, re_token_t *token, + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { + re_dfa_t *dfa = preg->buffer; + bin_tree_t *tree; + size_t cur_nsub; + cur_nsub = preg->re_nsub++; + + fetch_token(token, regexp, syntax | RE_CARET_ANCHORS_HERE); + + /* The subexpression may be a null string. */ + if (token->type == OP_CLOSE_SUBEXP) + tree = NULL; + else { + tree = parse_reg_exp(regexp, preg, token, syntax, nest, err); + if ((*err == REG_NOERROR + && token->type != OP_CLOSE_SUBEXP)) { + if (tree != NULL) + postorder(tree, free_tree, NULL); + *err = REG_EPAREN; + } + if ((*err != REG_NOERROR)) + return NULL; + } + + if (cur_nsub <= '9' - '1') + dfa->completed_bkref_map |= 1 << cur_nsub; + + tree = create_tree(dfa, tree, NULL, SUBEXP); + if ((tree == NULL)) { + *err = REG_ESPACE; + return NULL; + } + tree->token.opr.idx = cur_nsub; + return tree; +} + +/* This function parse repetition operators like "*", "+", "{1,3}" etc. */ + +static bin_tree_t * +parse_dup_op(bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, + re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) { + bin_tree_t *tree = NULL, *old_tree = NULL; + Idx i, start, end, start_idx = re_string_cur_idx(regexp); + re_token_t start_token = *token; + + if (token->type == OP_OPEN_DUP_NUM) { + end = 0; + start = fetch_number(regexp, token, syntax); + if (start == -1) { + if (token->type == CHARACTER && token->opr.c == ',') + start = 0; /* We treat "{,m}" as "{0,m}". */ + else { + *err = REG_BADBR; /* {} is invalid. */ + return NULL; + } + } + if ((start != -2)) { + /* We treat "{n}" as "{n,n}". */ + end = ((token->type == OP_CLOSE_DUP_NUM) ? start + : ((token->type == CHARACTER && token->opr.c == ',') + ? fetch_number(regexp, token, syntax) : -2)); + } + if ((start == -2 || end == -2)) { + /* Invalid sequence. */ + if ((!(syntax & RE_INVALID_INTERVAL_ORD))) { + if (token->type == END_OF_RE) + *err = REG_EBRACE; + else + *err = REG_BADBR; + + return NULL; + } + + /* If the syntax bit is set, rollback. */ + re_string_set_index(regexp, start_idx); + *token = start_token; + token->type = CHARACTER; + /* mb_partial and word_char bits should be already initialized by + peek_token. */ + return elem; + } + + if (((end != -1 && start > end) + || token->type != OP_CLOSE_DUP_NUM)) { + /* First number greater than second. */ + *err = REG_BADBR; + return NULL; + } + + if ((RE_DUP_MAX < (end == -1 ? start : end))) { + *err = REG_ESIZE; + return NULL; + } + } else { + start = (token->type == OP_DUP_PLUS) ? 1 : 0; + end = (token->type == OP_DUP_QUESTION) ? 1 : -1; + } + + fetch_token(token, regexp, syntax); + + if ((elem == NULL)) + return NULL; + if ((start == 0 && end == 0)) { + postorder(elem, free_tree, NULL); + return NULL; + } + + /* Extract "{n,m}" to "...{0,}". */ + if ((start > 0)) { + tree = elem; + for (i = 2; i <= start; ++i) { + elem = duplicate_tree(elem, dfa); + tree = create_tree(dfa, tree, elem, CONCAT); + if ((elem == NULL || tree == NULL)) + goto parse_dup_op_espace; + } + + if (start == end) + return tree; + + /* Duplicate ELEM before it is marked optional. */ + elem = duplicate_tree(elem, dfa); + if ((elem == NULL)) + goto parse_dup_op_espace; + old_tree = tree; + } else + old_tree = NULL; + + if (elem->token.type == SUBEXP) { + uintptr_t subidx = elem->token.opr.idx; + postorder(elem, mark_opt_subexp, (void *) subidx); + } + + tree = create_tree(dfa, elem, NULL, + (end == -1 ? OP_DUP_ASTERISK : OP_ALT)); + if ((tree == NULL)) + goto parse_dup_op_espace; + + /* This loop is actually executed only when end != -1, + to rewrite {0,n} as ((...?)?)?... We have + already created the start+1-th copy. */ + if (TYPE_SIGNED(Idx) || end != -1) + for (i = start + 2; i <= end; ++i) { + elem = duplicate_tree(elem, dfa); + tree = create_tree(dfa, tree, elem, CONCAT); + if ((elem == NULL || tree == NULL)) + goto parse_dup_op_espace; + + tree = create_tree(dfa, tree, NULL, OP_ALT); + if ((tree == NULL)) + goto parse_dup_op_espace; + } + + if (old_tree) + tree = create_tree(dfa, old_tree, tree, CONCAT); + + return tree; + + parse_dup_op_espace: + *err = REG_ESPACE; + return NULL; +} + +/* Size of the names for collating symbol/equivalence_class/character_class. + I'm not sure, but maybe enough. */ +#define BRACKET_NAME_BUF_SIZE 32 + +/* Local function for parse_bracket_exp only used in case of NOT _LIBC. + Build the range expression which starts from START_ELEM, and ends + at END_ELEM. The result are written to MBCSET and SBCSET. + RANGE_ALLOC is the allocated size of mbcset->range_starts, and + mbcset->range_ends, is a pointer argument since we may + update it. */ + +static reg_errcode_t +build_range_exp(const reg_syntax_t syntax, + bitset_t sbcset, + const bracket_elem_t *start_elem, + const bracket_elem_t *end_elem) { + unsigned int start_ch, end_ch; + /* Equivalence Classes and Character Classes can't be a range start/end. */ + if ((start_elem->type == EQUIV_CLASS + || start_elem->type == CHAR_CLASS + || end_elem->type == EQUIV_CLASS + || end_elem->type == CHAR_CLASS)) + return REG_ERANGE; + + /* We can handle no multi character collating elements without libc + support. */ + if (((start_elem->type == COLL_SYM + && strlen((char *) start_elem->opr.name) > 1) + || (end_elem->type == COLL_SYM + && strlen((char *) end_elem->opr.name) > 1))) + return REG_ECOLLATE; + + { + unsigned int ch; + start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch + : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] + : 0)); + end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch + : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] + : 0)); + if (start_ch > end_ch) + return REG_ERANGE; + /* Build the table for single byte characters. */ + for (ch = 0; ch < SBC_MAX; ++ch) + if (start_ch <= ch && ch <= end_ch) + bitset_set(sbcset, ch); + } + return REG_NOERROR; +} + +/* Helper function for parse_bracket_exp only used in case of NOT _LIBC.. + Build the collating element which is represented by NAME. + The result are written to MBCSET and SBCSET. + COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a + pointer argument since we may update it. */ + +static reg_errcode_t +build_collating_symbol(bitset_t sbcset, const unsigned char *name) { + size_t name_len = strlen((const char *) name); + if ((name_len != 1)) + return REG_ECOLLATE; + else { + bitset_set(sbcset, name[0]); + return REG_NOERROR; + } +} + + +/* This function parse bracket expression like "[abc]", "[a-c]", + "[[.a-a.]]" etc. */ + +static bin_tree_t * +parse_bracket_exp(re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, + reg_syntax_t syntax, reg_errcode_t *err) { + re_token_t br_token; + re_bitset_ptr_t sbcset; + bool non_match = false; + bin_tree_t *work_tree; + int token_len; + bool first_round = true; + sbcset = (re_bitset_ptr_t) calloc(sizeof(bitset_t), 1); + if ((sbcset == NULL)) { + re_free(sbcset); + *err = REG_ESPACE; + return NULL; + } + + token_len = peek_token_bracket(token, regexp, syntax); + if ((token->type == END_OF_RE)) { + *err = REG_BADPAT; + goto parse_bracket_exp_free_return; + } + if (token->type == OP_NON_MATCH_LIST) { + non_match = true; + if (syntax & RE_HAT_LISTS_NOT_NEWLINE) + bitset_set(sbcset, '\n'); + re_string_skip_bytes(regexp, token_len); /* Skip a token. */ + token_len = peek_token_bracket(token, regexp, syntax); + if ((token->type == END_OF_RE)) { + *err = REG_BADPAT; + goto parse_bracket_exp_free_return; + } + } + + /* We treat the first ']' as a normal character. */ + if (token->type == OP_CLOSE_BRACKET) + token->type = CHARACTER; + + while (1) { + bracket_elem_t start_elem, end_elem; + unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; + unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; + reg_errcode_t ret; + int token_len2 = 0; + bool is_range_exp = false; + re_token_t token2; + + start_elem.opr.name = start_name_buf; + start_elem.type = COLL_SYM; + ret = parse_bracket_element(&start_elem, regexp, token, token_len, dfa, + syntax, first_round); + if ((ret != REG_NOERROR)) { + *err = ret; + goto parse_bracket_exp_free_return; + } + first_round = false; + + /* Get information about the next token. We need it in any case. */ + token_len = peek_token_bracket(token, regexp, syntax); + + /* Do not check for ranges if we know they are not allowed. */ + if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS) { + if ((token->type == END_OF_RE)) { + *err = REG_EBRACK; + goto parse_bracket_exp_free_return; + } + if (token->type == OP_CHARSET_RANGE) { + re_string_skip_bytes(regexp, token_len); /* Skip '-'. */ + token_len2 = peek_token_bracket(&token2, regexp, syntax); + if ((token2.type == END_OF_RE)) { + *err = REG_EBRACK; + goto parse_bracket_exp_free_return; + } + if (token2.type == OP_CLOSE_BRACKET) { + /* We treat the last '-' as a normal character. */ + re_string_skip_bytes(regexp, -token_len); + token->type = CHARACTER; + } else + is_range_exp = true; + } + } + + if (is_range_exp == true) { + end_elem.opr.name = end_name_buf; + end_elem.type = COLL_SYM; + ret = parse_bracket_element(&end_elem, regexp, &token2, token_len2, + dfa, syntax, true); + if ((ret != REG_NOERROR)) { + *err = ret; + goto parse_bracket_exp_free_return; + } + + token_len = peek_token_bracket(token, regexp, syntax); + + *err = build_range_exp(syntax, sbcset, &start_elem, &end_elem); + + if ((*err != REG_NOERROR)) + goto parse_bracket_exp_free_return; + } else { + switch (start_elem.type) { + case SB_CHAR: + bitset_set(sbcset, start_elem.opr.ch); + break; + case EQUIV_CLASS: + *err = build_equiv_class(sbcset, + start_elem.opr.name); + if ((*err != REG_NOERROR)) + goto parse_bracket_exp_free_return; + break; + case COLL_SYM: + *err = build_collating_symbol(sbcset, + start_elem.opr.name); + if ((*err != REG_NOERROR)) + goto parse_bracket_exp_free_return; + break; + case CHAR_CLASS: + *err = build_charclass(regexp->trans, sbcset, + (const char *) start_elem.opr.name, + syntax); + if ((*err != REG_NOERROR)) + goto parse_bracket_exp_free_return; + break; + default: + assert(0); + break; + } + } + if ((token->type == END_OF_RE)) { + *err = REG_EBRACK; + goto parse_bracket_exp_free_return; + } + if (token->type == OP_CLOSE_BRACKET) + break; + } + + re_string_skip_bytes(regexp, token_len); /* Skip a token. */ + + /* If it is non-matching list. */ + if (non_match) + bitset_not(sbcset); + + { + /* Build a tree for simple bracket. */ + br_token.type = SIMPLE_BRACKET; + br_token.opr.sbcset = sbcset; + work_tree = create_token_tree(dfa, NULL, NULL, &br_token); + if ((work_tree == NULL)) + goto parse_bracket_exp_espace; + } + return work_tree; + + parse_bracket_exp_espace: + *err = REG_ESPACE; + parse_bracket_exp_free_return: + re_free(sbcset); + return NULL; +} + +/* Parse an element in the bracket expression. */ + +static reg_errcode_t +parse_bracket_element(bracket_elem_t *elem, re_string_t *regexp, + re_token_t *token, int token_len, re_dfa_t *dfa, + reg_syntax_t syntax, bool accept_hyphen) { + re_string_skip_bytes(regexp, token_len); /* Skip a token. */ + if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS + || token->type == OP_OPEN_EQUIV_CLASS) + return parse_bracket_symbol(elem, regexp, token); + if ((token->type == OP_CHARSET_RANGE) && !accept_hyphen) { + /* A '-' must only appear as anything but a range indicator before + the closing bracket. Everything else is an error. */ + re_token_t token2; + (void) peek_token_bracket(&token2, regexp, syntax); + if (token2.type != OP_CLOSE_BRACKET) + /* The actual error value is not standardized since this whole + case is undefined. But ERANGE makes good sense. */ + return REG_ERANGE; + } + elem->type = SB_CHAR; + elem->opr.ch = token->opr.c; + return REG_NOERROR; +} + +/* Parse a bracket symbol in the bracket expression. Bracket symbols are + such as [::], [..], and + [==]. */ + +static reg_errcode_t +parse_bracket_symbol(bracket_elem_t *elem, re_string_t *regexp, + re_token_t *token) { + unsigned char ch, delim = token->opr.c; + int i = 0; + if (re_string_eoi(regexp)) + return REG_EBRACK; + for (;; ++i) { + if (i >= BRACKET_NAME_BUF_SIZE) + return REG_EBRACK; + if (token->type == OP_OPEN_CHAR_CLASS) + ch = re_string_fetch_byte_case(regexp); + else + ch = re_string_fetch_byte(regexp); + if (re_string_eoi(regexp)) + return REG_EBRACK; + if (ch == delim && re_string_peek_byte(regexp, 0) == ']') + break; + elem->opr.name[i] = ch; + } + re_string_skip_bytes(regexp, 1); + elem->opr.name[i] = '\0'; + switch (token->type) { + case OP_OPEN_COLL_ELEM: + elem->type = COLL_SYM; + break; + case OP_OPEN_EQUIV_CLASS: + elem->type = EQUIV_CLASS; + break; + case OP_OPEN_CHAR_CLASS: + elem->type = CHAR_CLASS; + break; + default: + break; + } + return REG_NOERROR; +} + +/* Helper function for parse_bracket_exp. + Build the equivalence class which is represented by NAME. + The result are written to MBCSET and SBCSET. + EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes, + is a pointer argument since we may update it. */ + +static reg_errcode_t +build_equiv_class(bitset_t sbcset, const unsigned char *name) { + { + if ((strlen((const char *) name) != 1)) + return REG_ECOLLATE; + bitset_set(sbcset, *name); + } + return REG_NOERROR; +} + +/* Helper function for parse_bracket_exp. + Build the character class which is represented by NAME. + The result are written to MBCSET and SBCSET. + CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes, + is a pointer argument since we may update it. */ + +static reg_errcode_t +build_charclass(RE_TRANSLATE_TYPE trans, bitset_t sbcset, + const char *class_name, reg_syntax_t syntax) { + int i; + const char *name = class_name; + + /* In case of REG_ICASE "upper" and "lower" match the both of + upper and lower cases. */ + if ((syntax & RE_ICASE) + && (strcmp(name, "upper") == 0 || strcmp(name, "lower") == 0)) + name = "alpha"; + +#define BUILD_CHARCLASS_LOOP(ctype_func) \ + do { \ + if ( (trans != NULL)) \ + { \ + for (i = 0; i < SBC_MAX; ++i) \ + if (ctype_func (i)) \ + bitset_set (sbcset, trans[i]); \ + } \ + else \ + { \ + for (i = 0; i < SBC_MAX; ++i) \ + if (ctype_func (i)) \ + bitset_set (sbcset, i); \ + } \ + } while (0) + + if (strcmp(name, "alnum") == 0) + BUILD_CHARCLASS_LOOP (isalnum); + else if (strcmp(name, "cntrl") == 0) + BUILD_CHARCLASS_LOOP (iscntrl); + else if (strcmp(name, "lower") == 0) + BUILD_CHARCLASS_LOOP (islower); + else if (strcmp(name, "space") == 0) + BUILD_CHARCLASS_LOOP (isspace); + else if (strcmp(name, "alpha") == 0) + BUILD_CHARCLASS_LOOP (isalpha); + else if (strcmp(name, "digit") == 0) + BUILD_CHARCLASS_LOOP (isdigit); + else if (strcmp(name, "print") == 0) + BUILD_CHARCLASS_LOOP (isprint); + else if (strcmp(name, "upper") == 0) + BUILD_CHARCLASS_LOOP (isupper); + else if (strcmp(name, "blank") == 0) + BUILD_CHARCLASS_LOOP (isblank); + else if (strcmp(name, "graph") == 0) + BUILD_CHARCLASS_LOOP (isgraph); + else if (strcmp(name, "punct") == 0) + BUILD_CHARCLASS_LOOP (ispunct); + else if (strcmp(name, "xdigit") == 0) + BUILD_CHARCLASS_LOOP (isxdigit); + else + return REG_ECTYPE; + + return REG_NOERROR; +} + +static bin_tree_t * +build_charclass_op(re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, + const char *class_name, + const char *extra, bool non_match, + reg_errcode_t *err) { + re_bitset_ptr_t sbcset; + reg_errcode_t ret; + re_token_t br_token; + bin_tree_t *tree; + + sbcset = (re_bitset_ptr_t) calloc(sizeof(bitset_t), 1); + if ((sbcset == NULL)) { + *err = REG_ESPACE; + return NULL; + } + + /* We don't care the syntax in this case. */ + ret = build_charclass(trans, sbcset, + class_name, 0); + + if ((ret != REG_NOERROR)) { + re_free(sbcset); + *err = ret; + return NULL; + } + /* \w match '_' also. */ + for (; *extra; extra++) + bitset_set(sbcset, *extra); + + /* If it is non-matching list. */ + if (non_match) + bitset_not(sbcset); + + /* Build a tree for simple bracket. */ + br_token.type = SIMPLE_BRACKET; + br_token.opr.sbcset = sbcset; + tree = create_token_tree(dfa, NULL, NULL, &br_token); + if ((tree == NULL)) + goto build_word_op_espace; + + return tree; + + build_word_op_espace: + re_free(sbcset); + *err = REG_ESPACE; + return NULL; +} + +/* This is intended for the expressions like "a{1,3}". + Fetch a number from 'input', and return the number. + Return -1 if the number field is empty like "{,1}". + Return RE_DUP_MAX + 1 if the number field is too large. + Return -2 if an error occurred. */ + +static Idx +fetch_number(re_string_t *input, re_token_t *token, reg_syntax_t syntax) { + Idx num = -1; + unsigned char c; + while (1) { + fetch_token(token, input, syntax); + c = token->opr.c; + if ((token->type == END_OF_RE)) + return -2; + if (token->type == OP_CLOSE_DUP_NUM || c == ',') + break; + num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2) + ? -2 + : num == -1 + ? c - '0' + : MIN (RE_DUP_MAX + 1, num * 10 + c - '0')); + } + return num; +} + +/* Functions for binary tree operation. */ + +/* Create a tree node. */ + +static bin_tree_t * +create_tree(re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, + re_token_type_t type) { + re_token_t t; + t.type = type; + return create_token_tree(dfa, left, right, &t); +} + +static bin_tree_t * +create_token_tree(re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, + const re_token_t *token) { + bin_tree_t *tree; + if ((dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE)) { + bin_tree_storage_t *storage = re_malloc(bin_tree_storage_t, 1); + + if (storage == NULL) + return NULL; + storage->next = dfa->str_tree_storage; + dfa->str_tree_storage = storage; + dfa->str_tree_storage_idx = 0; + } + tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++]; + + tree->parent = NULL; + tree->left = left; + tree->right = right; + tree->token = *token; + tree->token.duplicated = 0; + tree->token.opt_subexp = 0; + tree->first = NULL; + tree->next = NULL; + tree->node_idx = -1; + + if (left != NULL) + left->parent = tree; + if (right != NULL) + right->parent = tree; + return tree; +} + +/* Mark the tree SRC as an optional subexpression. + To be called from preorder or postorder. */ + +static reg_errcode_t +mark_opt_subexp(void *extra, bin_tree_t *node) { + Idx idx = (uintptr_t) extra; + if (node->token.type == SUBEXP && node->token.opr.idx == idx) + node->token.opt_subexp = 1; + + return REG_NOERROR; +} + +/* Free the allocated memory inside NODE. */ + +static void +free_token(re_token_t *node) { + if (node->type == SIMPLE_BRACKET && node->duplicated == 0) + re_free(node->opr.sbcset); +} + +/* Worker function for tree walking. Free the allocated memory inside NODE + and its children. */ + +static reg_errcode_t +free_tree(void *extra, bin_tree_t *node) { + free_token(&node->token); + return REG_NOERROR; +} + + +/* Duplicate the node SRC, and return new node. This is a preorder + visit similar to the one implemented by the generic visitor, but + we need more infrastructure to maintain two parallel trees --- so, + it's easier to duplicate. */ + +static bin_tree_t * +duplicate_tree(const bin_tree_t *root, re_dfa_t *dfa) { + const bin_tree_t *node; + bin_tree_t *dup_root; + bin_tree_t **p_new = &dup_root, *dup_node = root->parent; + + for (node = root;;) { + /* Create a new tree and link it back to the current parent. */ + *p_new = create_token_tree(dfa, NULL, NULL, &node->token); + if (*p_new == NULL) + return NULL; + (*p_new)->parent = dup_node; + (*p_new)->token.duplicated = 1; + dup_node = *p_new; + + /* Go to the left node, or up and to the right. */ + if (node->left) { + node = node->left; + p_new = &dup_node->left; + } else { + const bin_tree_t *prev = NULL; + while (node->right == prev || node->right == NULL) { + prev = node; + node = node->parent; + dup_node = dup_node->parent; + if (!node) + return dup_root; + } + node = node->right; + p_new = &dup_node->right; + } + } +} + +static reg_errcode_t +prune_impossible_nodes(re_match_context_t *mctx) { + const re_dfa_t *const dfa = mctx->dfa; + Idx halt_node, match_last; + reg_errcode_t ret; + re_dfastate_t **sifted_states; + re_dfastate_t **lim_states = NULL; + re_sift_context_t sctx; + match_last = mctx->match_last; + halt_node = mctx->last_node; + +/* Avoid overflow. */ + if ((MIN (IDX_MAX, SIZE_MAX / sizeof(re_dfastate_t * )) + <= match_last)) + return REG_ESPACE; + + sifted_states = re_malloc(re_dfastate_t * , match_last + 1); + if ((sifted_states == NULL)) { + ret = REG_ESPACE; + goto free_return; + } + if (dfa->nbackref) { + lim_states = re_malloc(re_dfastate_t * , match_last + 1); + if ((lim_states == NULL)) { + ret = REG_ESPACE; + goto free_return; + } + while (1) { + memset(lim_states, '\0', + sizeof(re_dfastate_t * ) * (match_last + 1)); + sift_ctx_init(&sctx, sifted_states, lim_states, halt_node, + match_last); + ret = sift_states_backward(mctx, &sctx); + re_node_set_free(&sctx.limits); + if ((ret != REG_NOERROR)) + goto free_return; + if (sifted_states[0] != NULL || lim_states[0] != NULL) + break; + do { + --match_last; + if (match_last < 0) { + ret = REG_NOMATCH; + goto free_return; + } + } while (mctx->state_log[match_last] == NULL + || !mctx->state_log[match_last]->halt); + halt_node = check_halt_state_context(mctx, + mctx->state_log[match_last], + match_last); + } + ret = merge_state_array(dfa, sifted_states, lim_states, + match_last + 1); + re_free(lim_states); + lim_states = NULL; + if ((ret != REG_NOERROR)) + goto free_return; + } else { + sift_ctx_init(&sctx, sifted_states, lim_states, halt_node, match_last); + ret = sift_states_backward(mctx, &sctx); + re_node_set_free(&sctx.limits); + if ((ret != REG_NOERROR)) + goto free_return; + if (sifted_states[0] == NULL) { + ret = REG_NOMATCH; + goto free_return; + } + } + re_free(mctx->state_log); + mctx->state_log = sifted_states; + sifted_states = NULL; + mctx->last_node = halt_node; + mctx->match_last = match_last; + ret = REG_NOERROR; + free_return: + re_free(sifted_states); + re_free(lim_states); + return ret; +} + +/* Acquire an initial state and return it. + We must select appropriate initial state depending on the context, + since initial states may have constraints like "\<", "^", etc.. */ + +static inline re_dfastate_t * +acquire_init_state_context(reg_errcode_t *err, const re_match_context_t *mctx, + Idx idx) { + const re_dfa_t *const dfa = mctx->dfa; + if (dfa->init_state->has_constraint) { + unsigned int context; + context = re_string_context_at(&mctx->input, idx - 1, mctx->eflags); + if (IS_WORD_CONTEXT(context)) + return dfa->init_state_word; + else if (IS_ORDINARY_CONTEXT(context)) + return dfa->init_state; + else if (IS_BEGBUF_CONTEXT(context) && IS_NEWLINE_CONTEXT(context)) + return dfa->init_state_begbuf; + else if (IS_NEWLINE_CONTEXT(context)) + return dfa->init_state_nl; + else if (IS_BEGBUF_CONTEXT(context)) { + /* It is relatively rare case, then calculate on demand. */ + return re_acquire_state_context(err, dfa, + dfa->init_state->entrance_nodes, + context); + } else + /* Must not happen? */ + return dfa->init_state; + } else + return dfa->init_state; +} + +/* Check whether the node accepts the byte which is IDX-th + byte of the INPUT. */ + +static bool +check_node_accept(const re_match_context_t *mctx, const re_token_t *node, + Idx idx) { + unsigned char ch; + ch = re_string_byte_at(&mctx->input, idx); + switch (node->type) { + case CHARACTER: + if (node->opr.c != ch) + return false; + break; + + case SIMPLE_BRACKET: + if (!bitset_contain(node->opr.sbcset, ch)) + return false; + break; + + case OP_PERIOD: + if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE)) + || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL))) + return false; + break; + + default: + return false; + } + + if (node->constraint) { + /* The node has constraints. Check whether the current context + satisfies the constraints. */ + unsigned int context = re_string_context_at(&mctx->input, idx, + mctx->eflags); + if (NOT_SATISFY_NEXT_CONSTRAINT(node->constraint, context)) + return false; + } + + return true; +} + + +/* Extend the buffers, if the buffers have run out. */ + +static reg_errcode_t +extend_buffers(re_match_context_t + *mctx, + int min_len +) { + reg_errcode_t ret; + re_string_t *pstr = &mctx->input; + +/* Avoid overflow. */ + if ( + (MIN (IDX_MAX, SIZE_MAX / sizeof(re_dfastate_t * )) / 2 + <= pstr->bufs_len)) + return + REG_ESPACE; + +/* Double the lengths of the buffers, but allocate at least MIN_LEN. */ + ret = re_string_realloc_buffers(pstr, + MAX (min_len, + MIN(pstr->len, pstr->bufs_len * 2))); + if ( + (ret + != REG_NOERROR)) + return + ret; + + if (mctx->state_log != NULL) { +/* And double the length of state_log. */ +/* XXX We have no indication of the size of this buffer. If this +allocation fail we have no indication that the state_log array +does not have the right size. */ + re_dfastate_t **new_array = re_realloc(mctx->state_log, re_dfastate_t * , + pstr->bufs_len + 1); + if ( + (new_array + == NULL)) + return + REG_ESPACE; + mctx-> + state_log = new_array; + } + +/* Then reconstruct the buffers. */ + if (pstr->icase) { + build_upper_buffer(pstr); + } else { + { + if (pstr->trans != NULL) + re_string_translate_buffer(pstr); + } + } + return + REG_NOERROR; +} + +/* Functions for state transition. */ + +/* Helper functions for transit_state. */ + +/* Return the first entry with the same str_idx, or -1 if none is + found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ + +static Idx +search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx) +{ + Idx left, right, mid, last; + last = right = mctx->nbkref_ents; + for (left = 0; left < right;) + { + mid = (left + right) / 2; + if (mctx->bkref_ents[mid].str_idx < str_idx) + left = mid + 1; + else + right = mid; + } + if (left < last && mctx->bkref_ents[left].str_idx == str_idx) + return left; + else + return -1; +} + +/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches + at STR_IDX. */ + +static reg_errcode_t +match_ctx_add_subtop(re_match_context_t *mctx, Idx node, Idx str_idx) { + if ((mctx->nsub_tops == mctx->asub_tops)) { + Idx new_asub_tops = mctx->asub_tops * 2; + re_sub_match_top_t **new_array = re_realloc(mctx->sub_tops, + re_sub_match_top_t * , + new_asub_tops); + if ((new_array == NULL)) + return REG_ESPACE; + mctx->sub_tops = new_array; + mctx->asub_tops = new_asub_tops; + } + mctx->sub_tops[mctx->nsub_tops] = calloc(1, sizeof(re_sub_match_top_t)); + if ((mctx->sub_tops[mctx->nsub_tops] == NULL)) + return REG_ESPACE; + mctx->sub_tops[mctx->nsub_tops]->node = node; + mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx; + return REG_NOERROR; +} + +/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches + at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ + +static re_sub_match_last_t * +match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx) +{ + re_sub_match_last_t *new_entry; + if ( (subtop->nlasts == subtop->alasts)) + { + Idx new_alasts = 2 * subtop->alasts + 1; + re_sub_match_last_t **new_array = re_realloc (subtop->lasts, + re_sub_match_last_t *, + new_alasts); + if ( (new_array == NULL)) + return NULL; + subtop->lasts = new_array; + subtop->alasts = new_alasts; + } + new_entry = calloc (1, sizeof (re_sub_match_last_t)); + if ( (new_entry != NULL)) + { + subtop->lasts[subtop->nlasts] = new_entry; + new_entry->node = node; + new_entry->str_idx = str_idx; + ++subtop->nlasts; + } + return new_entry; +} + + +/* From the node set CUR_NODES, pick up the nodes whose types are + OP_OPEN_SUBEXP and which have corresponding back references in the regular + expression. And register them to use them later for evaluating the + corresponding back references. */ + +static reg_errcode_t +check_subexp_matching_top(re_match_context_t *mctx, re_node_set *cur_nodes, + Idx str_idx) { + const re_dfa_t *const dfa = mctx->dfa; + Idx node_idx; + reg_errcode_t err; + + /* TODO: This isn't efficient. + Because there might be more than one nodes whose types are + OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all + nodes. + E.g. RE: (a){2} */ + for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx) { + Idx node = cur_nodes->elems[node_idx]; + if (dfa->nodes[node].type == OP_OPEN_SUBEXP + && dfa->nodes[node].opr.idx < BITSET_WORD_BITS + && (dfa->used_bkref_map + & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx))) { + err = match_ctx_add_subtop(mctx, node, str_idx); + if ((err != REG_NOERROR)) + return err; + } + } + return REG_NOERROR; +} + +/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA + corresponding to the DFA). + Return the destination node, and update EPS_VIA_NODES; + return -1 in case of errors. */ + +static Idx +proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, + Idx *pidx, Idx node, re_node_set *eps_via_nodes, + struct re_fail_stack_t *fs) +{ + const re_dfa_t *const dfa = mctx->dfa; + Idx i; + bool ok; + if (IS_EPSILON_NODE (dfa->nodes[node].type)) + { + re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; + re_node_set *edests = &dfa->edests[node]; + Idx dest_node; + ok = re_node_set_insert (eps_via_nodes, node); + if ( (! ok)) + return -2; + /* Pick up a valid destination, or return -1 if none + is found. */ + for (dest_node = -1, i = 0; i < edests->nelem; ++i) + { + Idx candidate = edests->elems[i]; + if (!re_node_set_contains (cur_nodes, candidate)) + continue; + if (dest_node == -1) + dest_node = candidate; + + else + { + /* In order to avoid infinite loop like "(a*)*", return the second + epsilon-transition if the first was already considered. */ + if (re_node_set_contains (eps_via_nodes, dest_node)) + return candidate; + + /* Otherwise, push the second epsilon-transition on the fail stack. */ + else if (fs != NULL + && push_fail_stack (fs, *pidx, candidate, nregs, regs, + eps_via_nodes)) + return -2; + + /* We know we are going to exit. */ + break; + } + } + return dest_node; + } + else + { + Idx naccepted = 0; + re_token_type_t type = dfa->nodes[node].type; + + if (type == OP_BACK_REF) + { + Idx subexp_idx = dfa->nodes[node].opr.idx + 1; + naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; + if (fs != NULL) + { + if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) + return -1; + else if (naccepted) + { + char *buf = (char *) re_string_get_buffer (&mctx->input); + if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, + naccepted) != 0) + return -1; + } + } + + if (naccepted == 0) + { + Idx dest_node; + ok = re_node_set_insert (eps_via_nodes, node); + if ( (! ok)) + return -2; + dest_node = dfa->edests[node].elems[0]; + if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, + dest_node)) + return dest_node; + } + } + + if (naccepted != 0 + || check_node_accept (mctx, dfa->nodes + node, *pidx)) + { + Idx dest_node = dfa->nexts[node]; + *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; + if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL + || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, + dest_node))) + return -1; + re_node_set_empty (eps_via_nodes); + return dest_node; + } + } + return -1; +} + +static reg_errcode_t + +push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, + Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes) +{ + reg_errcode_t err; + Idx num = fs->num++; + if (fs->num == fs->alloc) + { + struct re_fail_stack_ent_t *new_array; + new_array = re_realloc (fs->stack, struct re_fail_stack_ent_t, + fs->alloc * 2); + if (new_array == NULL) + return REG_ESPACE; + fs->alloc *= 2; + fs->stack = new_array; + } + fs->stack[num].idx = str_idx; + fs->stack[num].node = dest_node; + fs->stack[num].regs = re_malloc (regmatch_t, nregs); + if (fs->stack[num].regs == NULL) + return REG_ESPACE; + memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); + err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); + return err; +} + +static Idx +pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs, + regmatch_t *regs, re_node_set *eps_via_nodes) +{ + Idx num = --fs->num; + assert (num >= 0); + *pidx = fs->stack[num].idx; + memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); + re_node_set_free (eps_via_nodes); + re_free (fs->stack[num].regs); + *eps_via_nodes = fs->stack[num].eps_via_nodes; + return fs->stack[num].node; +} + +/* Set the positions where the subexpressions are starts/ends to registers + PMATCH. + Note: We assume that pmatch[0] is already set, and + pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */ + +static reg_errcode_t + +set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, + regmatch_t *pmatch, bool fl_backtrack) +{ + const re_dfa_t *dfa = preg->buffer; + Idx idx, cur_node; + re_node_set eps_via_nodes; + struct re_fail_stack_t *fs; + struct re_fail_stack_t fs_body = { 0, 2, NULL }; + regmatch_t *prev_idx_match; + bool prev_idx_match_malloced = false; + if (fl_backtrack) + { + fs = &fs_body; + fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); + if (fs->stack == NULL) + return REG_ESPACE; + } + else + fs = NULL; + + cur_node = dfa->init_node; + re_node_set_init_empty (&eps_via_nodes); + + if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) + prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); + else + { + prev_idx_match = re_malloc (regmatch_t, nmatch); + if (prev_idx_match == NULL) + { + free_fail_stack_return (fs); + return REG_ESPACE; + } + prev_idx_match_malloced = true; + } + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); + + for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) + { + update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); + + if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) + { + Idx reg_idx; + if (fs) + { + for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) + if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) + break; + if (reg_idx == nmatch) + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return free_fail_stack_return (fs); + } + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, + &eps_via_nodes); + } + else + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return REG_NOERROR; + } + } + + /* Proceed to next node. */ + cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node, + &eps_via_nodes, fs); + + if ( (cur_node < 0)) + { + if ( (cur_node == -2)) + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + free_fail_stack_return (fs); + return REG_ESPACE; + } + if (fs) + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, + &eps_via_nodes); + else + { + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return REG_NOMATCH; + } + } + } + re_node_set_free (&eps_via_nodes); + if (prev_idx_match_malloced) + re_free (prev_idx_match); + return free_fail_stack_return (fs); +} + +static reg_errcode_t +free_fail_stack_return (struct re_fail_stack_t *fs) +{ + if (fs) + { + Idx fs_idx; + for (fs_idx = 0; fs_idx < fs->num; ++fs_idx) + { + re_node_set_free (&fs->stack[fs_idx].eps_via_nodes); + re_free (fs->stack[fs_idx].regs); + } + re_free (fs->stack); + } + return REG_NOERROR; +} + +static void +update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, + regmatch_t *prev_idx_match, Idx cur_node, Idx cur_idx, Idx nmatch) +{ + int type = dfa->nodes[cur_node].type; + if (type == OP_OPEN_SUBEXP) + { + Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; + + /* We are at the first node of this sub expression. */ + if (reg_num < nmatch) + { + pmatch[reg_num].rm_so = cur_idx; + pmatch[reg_num].rm_eo = -1; + } + } + else if (type == OP_CLOSE_SUBEXP) + { + Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; + if (reg_num < nmatch) + { + /* We are at the last node of this sub expression. */ + if (pmatch[reg_num].rm_so < cur_idx) + { + pmatch[reg_num].rm_eo = cur_idx; + /* This is a non-empty match or we are not inside an optional + subexpression. Accept this right away. */ + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); + } + else + { + if (dfa->nodes[cur_node].opt_subexp + && prev_idx_match[reg_num].rm_so != -1) + /* We transited through an empty match for an optional + subexpression, like (a?)*, and this is not the subexp's + first match. Copy back the old content of the registers + so that matches of an inner subexpression are undone as + well, like in ((a?))*. */ + memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch); + else + /* We completed a subexpression, but it may be part of + an optional one, so do not update PREV_IDX_MATCH. */ + pmatch[reg_num].rm_eo = cur_idx; + } + } + } +} + +/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 + and sift the nodes in each states according to the following rules. + Updated state_log will be wrote to STATE_LOG. + + Rules: We throw away the Node 'a' in the STATE_LOG[STR_IDX] if... + 1. When STR_IDX == MATCH_LAST(the last index in the state_log): + If 'a' isn't the LAST_NODE and 'a' can't epsilon transit to + the LAST_NODE, we throw away the node 'a'. + 2. When 0 <= STR_IDX < MATCH_LAST and 'a' accepts + string 's' and transit to 'b': + i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw + away the node 'a'. + ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is + thrown away, we throw away the node 'a'. + 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b': + i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the + node 'a'. + ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away, + we throw away the node 'a'. */ + +#define STATE_NODE_CONTAINS(state,node) \ + ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) + +static reg_errcode_t +sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) +{ + reg_errcode_t err; + int null_cnt = 0; + Idx str_idx = sctx->last_str_idx; + re_node_set cur_dest; + + /* Build sifted state_log[str_idx]. It has the nodes which can epsilon + transit to the last_node and the last_node itself. */ + err = re_node_set_init_1 (&cur_dest, sctx->last_node); + if ( (err != REG_NOERROR)) + return err; + err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); + if ( (err != REG_NOERROR)) + goto free_return; + + /* Then check each states in the state_log. */ + while (str_idx > 0) + { + /* Update counters. */ + null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; + if (null_cnt > mctx->max_mb_elem_len) + { + memset (sctx->sifted_states, '\0', + sizeof (re_dfastate_t *) * str_idx); + re_node_set_free (&cur_dest); + return REG_NOERROR; + } + re_node_set_empty (&cur_dest); + --str_idx; + + if (mctx->state_log[str_idx]) + { + err = build_sifted_states (mctx, sctx, str_idx, &cur_dest); + if ( (err != REG_NOERROR)) + goto free_return; + } + + /* Add all the nodes which satisfy the following conditions: + - It can epsilon transit to a node in CUR_DEST. + - It is in CUR_SRC. + And update state_log. */ + err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); + if ( (err != REG_NOERROR)) + goto free_return; + } + err = REG_NOERROR; + free_return: + re_node_set_free (&cur_dest); + return err; +} + +static reg_errcode_t +build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, + Idx str_idx, re_node_set *cur_dest) +{ + const re_dfa_t *const dfa = mctx->dfa; + const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; + Idx i; + + /* Then build the next sifted state. + We build the next sifted state on 'cur_dest', and update + 'sifted_states[str_idx]' with 'cur_dest'. + Note: + 'cur_dest' is the sifted state from 'state_log[str_idx + 1]'. + 'cur_src' points the node_set of the old 'state_log[str_idx]' + (with the epsilon nodes pre-filtered out). */ + for (i = 0; i < cur_src->nelem; i++) + { + Idx prev_node = cur_src->elems[i]; + int naccepted = 0; + bool ok; + + /* We don't check backreferences here. + See update_cur_sifted_state(). */ + if (!naccepted + && check_node_accept (mctx, dfa->nodes + prev_node, str_idx) + && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], + dfa->nexts[prev_node])) + naccepted = 1; + + if (naccepted == 0) + continue; + + if (sctx->limits.nelem) + { + Idx to_idx = str_idx + naccepted; + if (check_dst_limits (mctx, &sctx->limits, + dfa->nexts[prev_node], to_idx, + prev_node, str_idx)) + continue; + } + ok = re_node_set_insert (cur_dest, prev_node); + if ( (! ok)) + return REG_ESPACE; + } + + return REG_NOERROR; +} + +static reg_errcode_t +clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_idx) +{ + Idx top = mctx->state_log_top; + + if ((next_state_log_idx >= mctx->input.bufs_len + && mctx->input.bufs_len < mctx->input.len) + || (next_state_log_idx >= mctx->input.valid_len + && mctx->input.valid_len < mctx->input.len)) + { + reg_errcode_t err; + err = extend_buffers (mctx, next_state_log_idx + 1); + if ( (err != REG_NOERROR)) + return err; + } + + if (top < next_state_log_idx) + { + memset (mctx->state_log + top + 1, '\0', + sizeof (re_dfastate_t *) * (next_state_log_idx - top)); + mctx->state_log_top = next_state_log_idx; + } + return REG_NOERROR; +} + +/* Enumerate all the candidates which the backreference BKREF_NODE can match + at BKREF_STR_IDX, and register them by match_ctx_add_entry(). + Note that we might collect inappropriate candidates here. + However, the cost of checking them strictly here is too high, then we + delay these checking for prune_impossible_nodes(). */ + +static reg_errcode_t + +get_subexp(re_match_context_t *mctx, Idx bkref_node, Idx bkref_str_idx) { + const re_dfa_t *const dfa = mctx->dfa; + Idx subexp_num, sub_top_idx; + const char *buf = (const char *) re_string_get_buffer(&mctx->input); +/* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ + Idx cache_idx = search_cur_bkref_entry(mctx, bkref_str_idx); + if (cache_idx != -1) { + const struct re_backref_cache_entry *entry + = mctx->bkref_ents + cache_idx; + do + if (entry->node == bkref_node) + return REG_NOERROR; /* We already checked it. */ + while (entry++->more); + } + + subexp_num = dfa->nodes[bkref_node].opr.idx; + +/* For each sub expression */ + for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) { + reg_errcode_t err; + re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx]; + re_sub_match_last_t *sub_last; + Idx sub_last_idx, sl_str, bkref_str_off; + + if (dfa->nodes[sub_top->node].opr.idx != subexp_num) + continue; /* It isn't related. */ + + sl_str = sub_top->str_idx; + bkref_str_off = bkref_str_idx; +/* At first, check the last node of sub expressions we already +evaluated. */ + for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx) { + regoff_t sl_str_diff; + sub_last = sub_top->lasts[sub_last_idx]; + sl_str_diff = sub_last->str_idx - sl_str; +/* The matched string by the sub expression match with the substring + at the back reference? */ + if (sl_str_diff > 0) { + if ((bkref_str_off + sl_str_diff + > mctx->input.valid_len)) { +/* Not enough chars for a successful match. */ + if (bkref_str_off + sl_str_diff > mctx->input.len) + break; + + err = clean_state_log_if_needed(mctx, + bkref_str_off + + sl_str_diff); + if ((err != REG_NOERROR)) + return err; + buf = (const char *) re_string_get_buffer(&mctx->input); + } + if (memcmp(buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0) +/* We don't need to search this sub expression any more. */ + break; + } + bkref_str_off += sl_str_diff; + sl_str += sl_str_diff; + err = get_subexp_sub(mctx, sub_top, sub_last, bkref_node, + bkref_str_idx); + +/* Reload buf, since the preceding call might have reallocated + the buffer. */ + buf = (const char *) re_string_get_buffer(&mctx->input); + + if (err == REG_NOMATCH) + continue; + if ((err != REG_NOERROR)) + return err; + } + + if (sub_last_idx < sub_top->nlasts) + continue; + if (sub_last_idx > 0) + ++sl_str; +/* Then, search for the other last nodes of the sub expression. */ + for (; sl_str <= bkref_str_idx; ++sl_str) { + Idx cls_node; + regoff_t sl_str_off; + const re_node_set *nodes; + sl_str_off = sl_str - sub_top->str_idx; +/* The matched string by the sub expression match with the substring + at the back reference? */ + if (sl_str_off > 0) { + if ((bkref_str_off >= mctx->input.valid_len)) { +/* If we are at the end of the input, we cannot match. */ + if (bkref_str_off >= mctx->input.len) + break; + + err = extend_buffers(mctx, bkref_str_off + 1); + if ((err != REG_NOERROR)) + return err; + + buf = (const char *) re_string_get_buffer(&mctx->input); + } + if (buf[bkref_str_off++] != buf[sl_str - 1]) + break; /* We don't need to search this sub expression + any more. */ + } + if (mctx->state_log[sl_str] == NULL) + continue; +/* Does this state have a ')' of the sub expression? */ + nodes = &mctx->state_log[sl_str]->nodes; + cls_node = find_subexp_node(dfa, nodes, subexp_num, + OP_CLOSE_SUBEXP); + if (cls_node == -1) + continue; /* No. */ + if (sub_top->path == NULL) { + sub_top->path = calloc(sizeof(state_array_t), + sl_str - sub_top->str_idx + 1); + if (sub_top->path == NULL) + return REG_ESPACE; + } +/* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node + in the current context? */ + err = check_arrival(mctx, sub_top->path, sub_top->node, + sub_top->str_idx, cls_node, sl_str, + OP_CLOSE_SUBEXP); + if (err == REG_NOMATCH) + continue; + if ((err != REG_NOERROR)) + return err; + sub_last = match_ctx_add_sublast(sub_top, cls_node, sl_str); + if ((sub_last == NULL)) + return REG_ESPACE; + err = get_subexp_sub(mctx, sub_top, sub_last, bkref_node, + bkref_str_idx); + if (err == REG_NOMATCH) + continue; + } + } + return REG_NOERROR; +} + +/* Helper functions for get_subexp(). */ + +/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR. + If it can arrive, register the sub expression expressed with SUB_TOP + and SUB_LAST. */ + +static reg_errcode_t +get_subexp_sub(re_match_context_t *mctx, const re_sub_match_top_t *sub_top, + re_sub_match_last_t *sub_last, Idx bkref_node, Idx bkref_str) { + reg_errcode_t err; + Idx to_idx; + /* Can the subexpression arrive the back reference? */ + err = check_arrival(mctx, &sub_last->path, sub_last->node, + sub_last->str_idx, bkref_node, bkref_str, + OP_OPEN_SUBEXP); + if (err != REG_NOERROR) + return err; + err = match_ctx_add_entry(mctx, bkref_node, bkref_str, sub_top->str_idx, + sub_last->str_idx); + if ((err != REG_NOERROR)) + return err; + to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx; + return clean_state_log_if_needed(mctx, to_idx); +} + +/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX. + Search '(' if FL_OPEN, or search ')' otherwise. + TODO: This function isn't efficient... + Because there might be more than one nodes whose types are + OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all + nodes. + E.g. RE: (a){2} */ + +static Idx +find_subexp_node(const re_dfa_t *dfa, const re_node_set *nodes, + Idx subexp_idx, int type) { + Idx cls_idx; + for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) { + Idx cls_node = nodes->elems[cls_idx]; + const re_token_t *node = dfa->nodes + cls_node; + if (node->type == type + && node->opr.idx == subexp_idx) + return cls_node; + } + return -1; +} + +/* Check whether the node TOP_NODE at TOP_STR can arrive to the node + LAST_NODE at LAST_STR. We record the path onto PATH since it will be + heavily reused. + Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ + +static reg_errcode_t + +check_arrival(re_match_context_t *mctx, state_array_t *path, Idx top_node, + Idx top_str, Idx last_node, Idx last_str, int type) { + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err = REG_NOERROR; + Idx subexp_num, backup_cur_idx, str_idx, null_cnt; + re_dfastate_t *cur_state = NULL; + re_node_set *cur_nodes, next_nodes; + re_dfastate_t **backup_state_log; + unsigned int context; + + subexp_num = dfa->nodes[top_node].opr.idx; +/* Extend the buffer if we need. */ + if ((path->alloc < last_str + mctx->max_mb_elem_len + 1)) { + re_dfastate_t **new_array; + Idx old_alloc = path->alloc; + Idx incr_alloc = last_str + mctx->max_mb_elem_len + 1; + Idx new_alloc; + if ((IDX_MAX - old_alloc < incr_alloc)) + return REG_ESPACE; + new_alloc = old_alloc + incr_alloc; + if ((SIZE_MAX / sizeof(re_dfastate_t * ) < new_alloc)) + return REG_ESPACE; + new_array = re_realloc(path->array, re_dfastate_t * , new_alloc); + if ((new_array == NULL)) + return REG_ESPACE; + path->array = new_array; + path->alloc = new_alloc; + memset(new_array + old_alloc, '\0', + sizeof(re_dfastate_t * ) * (path->alloc - old_alloc)); + } + + str_idx = path->next_idx ? path->next_idx : top_str; + +/* Temporary modify MCTX. */ + backup_state_log = mctx->state_log; + backup_cur_idx = mctx->input.cur_idx; + mctx->state_log = path->array; + mctx->input.cur_idx = str_idx; + +/* Setup initial node set. */ + context = re_string_context_at(&mctx->input, str_idx - 1, mctx->eflags); + if (str_idx == top_str) { + err = re_node_set_init_1(&next_nodes, top_node); + if ((err != REG_NOERROR)) + return err; + err = check_arrival_expand_ecl(dfa, &next_nodes, subexp_num, type); + if ((err != REG_NOERROR)) { + re_node_set_free(&next_nodes); + return err; + } + } else { + cur_state = mctx->state_log[str_idx]; + if (cur_state && cur_state->has_backref) { + err = re_node_set_init_copy(&next_nodes, &cur_state->nodes); + if ((err != REG_NOERROR)) + return err; + } else + re_node_set_init_empty(&next_nodes); + } + if (str_idx == top_str || (cur_state && cur_state->has_backref)) { + if (next_nodes.nelem) { + err = expand_bkref_cache(mctx, &next_nodes, str_idx, + subexp_num, type); + if ((err != REG_NOERROR)) { + re_node_set_free(&next_nodes); + return err; + } + } + cur_state = re_acquire_state_context(&err, dfa, &next_nodes, context); + if ((cur_state == NULL && err != REG_NOERROR)) { + re_node_set_free(&next_nodes); + return err; + } + mctx->state_log[str_idx] = cur_state; + } + + for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;) { + re_node_set_empty(&next_nodes); + if (mctx->state_log[str_idx + 1]) { + err = re_node_set_merge(&next_nodes, + &mctx->state_log[str_idx + 1]->nodes); + if ((err != REG_NOERROR)) { + re_node_set_free(&next_nodes); + return err; + } + } + if (cur_state) { + err = check_arrival_add_next_nodes(mctx, str_idx, + &cur_state->non_eps_nodes, + &next_nodes); + if ((err != REG_NOERROR)) { + re_node_set_free(&next_nodes); + return err; + } + } + ++str_idx; + if (next_nodes.nelem) { + err = check_arrival_expand_ecl(dfa, &next_nodes, subexp_num, type); + if ((err != REG_NOERROR)) { + re_node_set_free(&next_nodes); + return err; + } + err = expand_bkref_cache(mctx, &next_nodes, str_idx, + subexp_num, type); + if ((err != REG_NOERROR)) { + re_node_set_free(&next_nodes); + return err; + } + } + context = re_string_context_at(&mctx->input, str_idx - 1, mctx->eflags); + cur_state = re_acquire_state_context(&err, dfa, &next_nodes, context); + if ((cur_state == NULL && err != REG_NOERROR)) { + re_node_set_free(&next_nodes); + return err; + } + mctx->state_log[str_idx] = cur_state; + null_cnt = cur_state == NULL ? null_cnt + 1 : 0; + } + re_node_set_free(&next_nodes); + cur_nodes = (mctx->state_log[last_str] == NULL ? NULL + : &mctx->state_log[last_str]->nodes); + path->next_idx = str_idx; + +/* Fix MCTX. */ + mctx->state_log = backup_state_log; + mctx->input.cur_idx = backup_cur_idx; + +/* Then check the current node set has the node LAST_NODE. */ + if (cur_nodes != NULL && re_node_set_contains(cur_nodes, last_node)) + return REG_NOERROR; + + return REG_NOMATCH; +} + +/* Helper functions for check_arrival. */ + +/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them + to NEXT_NODES. + TODO: This function is similar to the functions transit_state*(), + however this function has many additional works. + Can't we unify them? */ + +static reg_errcode_t + +check_arrival_add_next_nodes(re_match_context_t *mctx, Idx str_idx, + re_node_set *cur_nodes, re_node_set *next_nodes) { + const re_dfa_t *const dfa = mctx->dfa; + bool ok; + Idx cur_idx; + re_node_set union_set; + re_node_set_init_empty(&union_set); + for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) { + int naccepted = 0; + Idx cur_node = cur_nodes->elems[cur_idx]; + if (naccepted + || check_node_accept(mctx, dfa->nodes + cur_node, str_idx)) { + ok = re_node_set_insert(next_nodes, dfa->nexts[cur_node]); + if ((!ok)) { + re_node_set_free(&union_set); + return REG_ESPACE; + } + } + } + re_node_set_free(&union_set); + return REG_NOERROR; +} + +/* For all the nodes in CUR_NODES, add the epsilon closures of them to + CUR_NODES, however exclude the nodes which are: + - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN. + - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN. +*/ + +static reg_errcode_t +check_arrival_expand_ecl(const re_dfa_t *dfa, re_node_set *cur_nodes, + Idx ex_subexp, int type) { + reg_errcode_t err; + Idx idx, outside_node; + re_node_set new_nodes; + err = re_node_set_alloc(&new_nodes, cur_nodes->nelem); + if ((err != REG_NOERROR)) + return err; + /* Create a new node set NEW_NODES with the nodes which are epsilon + closures of the node in CUR_NODES. */ + + for (idx = 0; idx < cur_nodes->nelem; ++idx) { + Idx cur_node = cur_nodes->elems[idx]; + const re_node_set *eclosure = dfa->eclosures + cur_node; + outside_node = find_subexp_node(dfa, eclosure, ex_subexp, type); + if (outside_node == -1) { + /* There are no problematic nodes, just merge them. */ + err = re_node_set_merge(&new_nodes, eclosure); + if ((err != REG_NOERROR)) { + re_node_set_free(&new_nodes); + return err; + } + } else { + /* There are problematic nodes, re-calculate incrementally. */ + err = check_arrival_expand_ecl_sub(dfa, &new_nodes, cur_node, + ex_subexp, type); + if ((err != REG_NOERROR)) { + re_node_set_free(&new_nodes); + return err; + } + } + } + re_node_set_free(cur_nodes); + *cur_nodes = new_nodes; + return REG_NOERROR; +} + +/* Helper function for check_arrival_expand_ecl. + Check incrementally the epsilon closure of TARGET, and if it isn't + problematic append it to DST_NODES. */ + +static reg_errcode_t + +check_arrival_expand_ecl_sub(const re_dfa_t *dfa, re_node_set *dst_nodes, + Idx target, Idx ex_subexp, int type) { + Idx cur_node; + for (cur_node = target; !re_node_set_contains(dst_nodes, cur_node);) { + bool ok; + + if (dfa->nodes[cur_node].type == type + && dfa->nodes[cur_node].opr.idx == ex_subexp) { + if (type == OP_CLOSE_SUBEXP) { + ok = re_node_set_insert(dst_nodes, cur_node); + if ((!ok)) + return REG_ESPACE; + } + break; + } + ok = re_node_set_insert(dst_nodes, cur_node); + if ((!ok)) + return REG_ESPACE; + if (dfa->edests[cur_node].nelem == 0) + break; + if (dfa->edests[cur_node].nelem == 2) { + reg_errcode_t err; + err = check_arrival_expand_ecl_sub(dfa, dst_nodes, + dfa->edests[cur_node].elems[1], + ex_subexp, type); + if ((err != REG_NOERROR)) + return err; + } + cur_node = dfa->edests[cur_node].elems[0]; + } + return REG_NOERROR; +} + +/* For all the back references in the current state, calculate the + destination of the back references by the appropriate entry + in MCTX->BKREF_ENTS. */ + +static reg_errcode_t +expand_bkref_cache(re_match_context_t *mctx, re_node_set *cur_nodes, + Idx cur_str, Idx subexp_num, int type) { + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + Idx cache_idx_start = search_cur_bkref_entry(mctx, cur_str); + struct re_backref_cache_entry *ent; + + if (cache_idx_start == -1) + return REG_NOERROR; + + restart: + ent = mctx->bkref_ents + cache_idx_start; + do { + Idx to_idx, next_node; + +/* Is this entry ENT is appropriate? */ + if (!re_node_set_contains(cur_nodes, ent->node)) + continue; /* No. */ + + to_idx = cur_str + ent->subexp_to - ent->subexp_from; +/* Calculate the destination of the back reference, and append it +to MCTX->STATE_LOG. */ + if (to_idx == cur_str) { +/* The backreference did epsilon transit, we must re-check all the + node in the current state. */ + re_node_set new_dests; + reg_errcode_t err2, err3; + next_node = dfa->edests[ent->node].elems[0]; + if (re_node_set_contains(cur_nodes, next_node)) + continue; + err = re_node_set_init_1(&new_dests, next_node); + err2 = check_arrival_expand_ecl(dfa, &new_dests, subexp_num, type); + err3 = re_node_set_merge(cur_nodes, &new_dests); + re_node_set_free(&new_dests); + if ((err != REG_NOERROR || err2 != REG_NOERROR + || err3 != REG_NOERROR)) { + err = (err != REG_NOERROR ? err + : (err2 != REG_NOERROR ? err2 : err3)); + return err; + } +/* TODO: It is still inefficient... */ + goto restart; + } else { + re_node_set union_set; + next_node = dfa->nexts[ent->node]; + if (mctx->state_log[to_idx]) { + bool ok; + if (re_node_set_contains(&mctx->state_log[to_idx]->nodes, + next_node)) + continue; + err = re_node_set_init_copy(&union_set, + &mctx->state_log[to_idx]->nodes); + ok = re_node_set_insert(&union_set, next_node); + if ((err != REG_NOERROR || !ok)) { + re_node_set_free(&union_set); + err = err != REG_NOERROR ? err : REG_ESPACE; + return err; + } + } else { + err = re_node_set_init_1(&union_set, next_node); + if ((err != REG_NOERROR)) + return err; + } + mctx->state_log[to_idx] = re_acquire_state(&err, dfa, &union_set); + re_node_set_free(&union_set); + if ((mctx->state_log[to_idx] == NULL + && err != REG_NOERROR)) + return err; + } + } while (ent++->more); + return REG_NOERROR; +} + +/* Build transition table for the state. + Return true if successful. */ + +static bool +build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) +{ + reg_errcode_t err; + Idx i, j; + int ch; + bool need_word_trtable = false; + bitset_word_t elem, mask; + bool dests_node_malloced = false; + bool dest_states_malloced = false; + Idx ndests; /* Number of the destination states from 'state'. */ + re_dfastate_t **trtable; + re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; + re_node_set follows, *dests_node; + bitset_t *dests_ch; + bitset_t acceptable; + + struct dests_alloc + { + re_node_set dests_node[SBC_MAX]; + bitset_t dests_ch[SBC_MAX]; + } *dests_alloc; + + /* We build DFA states which corresponds to the destination nodes + from 'state'. 'dests_node[i]' represents the nodes which i-th + destination state contains, and 'dests_ch[i]' represents the + characters which i-th destination state accepts. */ + if (__libc_use_alloca (sizeof (struct dests_alloc))) + dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); + else + { + dests_alloc = re_malloc (struct dests_alloc, 1); + if ( (dests_alloc == NULL)) + return false; + dests_node_malloced = true; + } + dests_node = dests_alloc->dests_node; + dests_ch = dests_alloc->dests_ch; + + /* Initialize transition table. */ + state->word_trtable = state->trtable = NULL; + + /* At first, group all nodes belonging to 'state' into several + destinations. */ + ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch); + if ( (ndests <= 0)) + { + if (dests_node_malloced) + re_free (dests_alloc); + /* Return false in case of an error, true otherwise. */ + if (ndests == 0) + { + state->trtable = (re_dfastate_t **) + calloc (sizeof (re_dfastate_t *), SBC_MAX); + if ( (state->trtable == NULL)) + return false; + return true; + } + return false; + } + + err = re_node_set_alloc (&follows, ndests + 1); + if ( (err != REG_NOERROR)) + goto out_free; + + /* Avoid arithmetic overflow in size calculation. */ + size_t ndests_max + = ((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) + / (3 * sizeof (re_dfastate_t *))); + if ( (ndests_max < ndests)) + goto out_free; + + if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX + + ndests * 3 * sizeof (re_dfastate_t *))) + dest_states = (re_dfastate_t **) + alloca (ndests * 3 * sizeof (re_dfastate_t *)); + else + { + dest_states = re_malloc (re_dfastate_t *, ndests * 3); + if ( (dest_states == NULL)) + { + out_free: + if (dest_states_malloced) + re_free (dest_states); + re_node_set_free (&follows); + for (i = 0; i < ndests; ++i) + re_node_set_free (dests_node + i); + if (dests_node_malloced) + re_free (dests_alloc); + return false; + } + dest_states_malloced = true; + } + dest_states_word = dest_states + ndests; + dest_states_nl = dest_states_word + ndests; + bitset_empty (acceptable); + + /* Then build the states for all destinations. */ + for (i = 0; i < ndests; ++i) + { + Idx next_node; + re_node_set_empty (&follows); + /* Merge the follows of this destination states. */ + for (j = 0; j < dests_node[i].nelem; ++j) + { + next_node = dfa->nexts[dests_node[i].elems[j]]; + if (next_node != -1) + { + err = re_node_set_merge (&follows, dfa->eclosures + next_node); + if ( (err != REG_NOERROR)) + goto out_free; + } + } + dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); + if ( (dest_states[i] == NULL && err != REG_NOERROR)) + goto out_free; + /* If the new state has context constraint, + build appropriate states for these contexts. */ + if (dest_states[i]->has_constraint) + { + dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, + CONTEXT_WORD); + if ( (dest_states_word[i] == NULL + && err != REG_NOERROR)) + goto out_free; + + if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) + need_word_trtable = true; + + dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, + CONTEXT_NEWLINE); + if ( (dest_states_nl[i] == NULL && err != REG_NOERROR)) + goto out_free; + } + else + { + dest_states_word[i] = dest_states[i]; + dest_states_nl[i] = dest_states[i]; + } + bitset_merge (acceptable, dests_ch[i]); + } + + if (! (need_word_trtable)) + { + /* We don't care about whether the following character is a word + character, or we are in a single-byte character set so we can + discern by looking at the character code: allocate a + 256-entry transition table. */ + trtable = state->trtable = + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); + if ( (trtable == NULL)) + goto out_free; + + /* For all characters ch...: */ + for (i = 0; i < BITSET_WORDS; ++i) + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; + elem; + mask <<= 1, elem >>= 1, ++ch) + if ( (elem & 1)) + { + /* There must be exactly one destination which accepts + character ch. See group_nodes_into_DFAstates. */ + for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) + ; + + /* j-th destination accepts the word character ch. */ + if (dfa->word_char[i] & mask) + trtable[ch] = dest_states_word[j]; + else + trtable[ch] = dest_states[j]; + } + } + else + { + /* We care about whether the following character is a word + character, and we are in a multi-byte character set: discern + by looking at the character code: build two 256-entry + transition tables, one starting at trtable[0] and one + starting at trtable[SBC_MAX]. */ + trtable = state->word_trtable = + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); + if ( (trtable == NULL)) + goto out_free; + + /* For all characters ch...: */ + for (i = 0; i < BITSET_WORDS; ++i) + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; + elem; + mask <<= 1, elem >>= 1, ++ch) + if ( (elem & 1)) + { + /* There must be exactly one destination which accepts + character ch. See group_nodes_into_DFAstates. */ + for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) + ; + + /* j-th destination accepts the word character ch. */ + trtable[ch] = dest_states[j]; + trtable[ch + SBC_MAX] = dest_states_word[j]; + } + } + + /* new line */ + if (bitset_contain (acceptable, NEWLINE_CHAR)) + { + /* The current state accepts newline character. */ + for (j = 0; j < ndests; ++j) + if (bitset_contain (dests_ch[j], NEWLINE_CHAR)) + { + /* k-th destination accepts newline character. */ + trtable[NEWLINE_CHAR] = dest_states_nl[j]; + if (need_word_trtable) + trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j]; + /* There must be only one destination which accepts + newline. See group_nodes_into_DFAstates. */ + break; + } + } + + if (dest_states_malloced) + re_free (dest_states); + + re_node_set_free (&follows); + for (i = 0; i < ndests; ++i) + re_node_set_free (dests_node + i); + + if (dests_node_malloced) + re_free (dests_alloc); + + return true; +} + +/* Group all nodes belonging to STATE into several destinations. + Then for all destinations, set the nodes belonging to the destination + to DESTS_NODE[i] and set the characters accepted by the destination + to DEST_CH[i]. This function return the number of destinations. */ + +static Idx +group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, + re_node_set *dests_node, bitset_t *dests_ch) +{ + reg_errcode_t err; + bool ok; + Idx i, j, k; + Idx ndests; /* Number of the destinations from 'state'. */ + bitset_t accepts; /* Characters a node can accept. */ + const re_node_set *cur_nodes = &state->nodes; + bitset_empty (accepts); + ndests = 0; + + /* For all the nodes belonging to 'state', */ + for (i = 0; i < cur_nodes->nelem; ++i) + { + re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; + re_token_type_t type = node->type; + unsigned int constraint = node->constraint; + + /* Enumerate all single byte character this node can accept. */ + if (type == CHARACTER) + bitset_set (accepts, node->opr.c); + else if (type == SIMPLE_BRACKET) + { + bitset_merge (accepts, node->opr.sbcset); + } + else if (type == OP_PERIOD) + { + bitset_set_all (accepts); + if (!(dfa->syntax & RE_DOT_NEWLINE)) + bitset_clear (accepts, '\n'); + if (dfa->syntax & RE_DOT_NOT_NULL) + bitset_clear (accepts, '\0'); + } + else + continue; + + /* Check the 'accepts' and sift the characters which are not + match it the context. */ + if (constraint) + { + if (constraint & NEXT_NEWLINE_CONSTRAINT) + { + bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); + bitset_empty (accepts); + if (accepts_newline) + bitset_set (accepts, NEWLINE_CHAR); + else + continue; + } + if (constraint & NEXT_ENDBUF_CONSTRAINT) + { + bitset_empty (accepts); + continue; + } + + if (constraint & NEXT_WORD_CONSTRAINT) + { + bitset_word_t any_set = 0; + if (type == CHARACTER && !node->word_char) + { + bitset_empty (accepts); + continue; + } + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= dfa->word_char[j]); + if (!any_set) + continue; + } + if (constraint & NEXT_NOTWORD_CONSTRAINT) + { + bitset_word_t any_set = 0; + if (type == CHARACTER && node->word_char) + { + bitset_empty (accepts); + continue; + } + for (j = 0; j < BITSET_WORDS; ++j) + any_set |= (accepts[j] &= ~dfa->word_char[j]); + if (!any_set) + continue; + } + } + + /* Then divide 'accepts' into DFA states, or create a new + state. Above, we make sure that accepts is not empty. */ + for (j = 0; j < ndests; ++j) + { + bitset_t intersec; /* Intersection sets, see below. */ + bitset_t remains; + /* Flags, see below. */ + bitset_word_t has_intersec, not_subset, not_consumed; + + /* Optimization, skip if this state doesn't accept the character. */ + if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) + continue; + + /* Enumerate the intersection set of this state and 'accepts'. */ + has_intersec = 0; + for (k = 0; k < BITSET_WORDS; ++k) + has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; + /* And skip if the intersection set is empty. */ + if (!has_intersec) + continue; + + /* Then check if this state is a subset of 'accepts'. */ + not_subset = not_consumed = 0; + for (k = 0; k < BITSET_WORDS; ++k) + { + not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; + not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; + } + + /* If this state isn't a subset of 'accepts', create a + new group state, which has the 'remains'. */ + if (not_subset) + { + bitset_copy (dests_ch[ndests], remains); + bitset_copy (dests_ch[j], intersec); + err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); + if ( (err != REG_NOERROR)) + goto error_return; + ++ndests; + } + + /* Put the position in the current group. */ + ok = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); + if ( (! ok)) + goto error_return; + + /* If all characters are consumed, go to next node. */ + if (!not_consumed) + break; + } + /* Some characters remain, create a new group. */ + if (j == ndests) + { + bitset_copy (dests_ch[ndests], accepts); + err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); + if ( (err != REG_NOERROR)) + goto error_return; + ++ndests; + bitset_empty (accepts); + } + } + return ndests; + error_return: + for (j = 0; j < ndests; ++j) + re_node_set_free (dests_node + j); + return -1; +} + + +static reg_errcode_t +update_cur_sifted_state (const re_match_context_t *mctx, + re_sift_context_t *sctx, Idx str_idx, + re_node_set *dest_nodes) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err = REG_NOERROR; + const re_node_set *candidates; + candidates = ((mctx->state_log[str_idx] == NULL) ? NULL + : &mctx->state_log[str_idx]->nodes); + + if (dest_nodes->nelem == 0) + sctx->sifted_states[str_idx] = NULL; + else + { + if (candidates) + { + /* At first, add the nodes which can epsilon transit to a node in + DEST_NODE. */ + err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); + if ( (err != REG_NOERROR)) + return err; + + /* Then, check the limitations in the current sift_context. */ + if (sctx->limits.nelem) + { + err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, + mctx->bkref_ents, str_idx); + if ( (err != REG_NOERROR)) + return err; + } + } + + sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); + if ( (err != REG_NOERROR)) + return err; + } + + if (candidates && mctx->state_log[str_idx]->has_backref) + { + err = sift_states_bkref (mctx, sctx, str_idx, candidates); + if ( (err != REG_NOERROR)) + return err; + } + return REG_NOERROR; +} + +static reg_errcode_t + +add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, + const re_node_set *candidates) +{ + reg_errcode_t err = REG_NOERROR; + Idx i; + + re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes); + if ( (err != REG_NOERROR)) + return err; + + if (!state->inveclosure.alloc) + { + err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem); + if ( (err != REG_NOERROR)) + return REG_ESPACE; + for (i = 0; i < dest_nodes->nelem; i++) + { + err = re_node_set_merge (&state->inveclosure, + dfa->inveclosures + dest_nodes->elems[i]); + if ( (err != REG_NOERROR)) + return REG_ESPACE; + } + } + return re_node_set_add_intersect (dest_nodes, candidates, + &state->inveclosure); +} + +static reg_errcode_t +sub_epsilon_src_nodes (const re_dfa_t *dfa, Idx node, re_node_set *dest_nodes, + const re_node_set *candidates) +{ + Idx ecl_idx; + reg_errcode_t err; + re_node_set *inv_eclosure = dfa->inveclosures + node; + re_node_set except_nodes; + re_node_set_init_empty (&except_nodes); + for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) + { + Idx cur_node = inv_eclosure->elems[ecl_idx]; + if (cur_node == node) + continue; + if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) + { + Idx edst1 = dfa->edests[cur_node].elems[0]; + Idx edst2 = ((dfa->edests[cur_node].nelem > 1) + ? dfa->edests[cur_node].elems[1] : -1); + if ((!re_node_set_contains (inv_eclosure, edst1) + && re_node_set_contains (dest_nodes, edst1)) + || (edst2 > 0 + && !re_node_set_contains (inv_eclosure, edst2) + && re_node_set_contains (dest_nodes, edst2))) + { + err = re_node_set_add_intersect (&except_nodes, candidates, + dfa->inveclosures + cur_node); + if ( (err != REG_NOERROR)) + { + re_node_set_free (&except_nodes); + return err; + } + } + } + } + for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) + { + Idx cur_node = inv_eclosure->elems[ecl_idx]; + if (!re_node_set_contains (&except_nodes, cur_node)) + { + Idx idx = re_node_set_contains (dest_nodes, cur_node) - 1; + re_node_set_remove_at (dest_nodes, idx); + } + } + re_node_set_free (&except_nodes); + return REG_NOERROR; +} + +static bool +check_dst_limits (const re_match_context_t *mctx, const re_node_set *limits, + Idx dst_node, Idx dst_idx, Idx src_node, Idx src_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + Idx lim_idx, src_pos, dst_pos; + + Idx dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx); + Idx src_bkref_idx = search_cur_bkref_entry (mctx, src_idx); + for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) + { + Idx subexp_idx; + struct re_backref_cache_entry *ent; + ent = mctx->bkref_ents + limits->elems[lim_idx]; + subexp_idx = dfa->nodes[ent->node].opr.idx; + + dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], + subexp_idx, dst_node, dst_idx, + dst_bkref_idx); + src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], + subexp_idx, src_node, src_idx, + src_bkref_idx); + + /* In case of: + ( ) + ( ) + ( ) */ + if (src_pos == dst_pos) + continue; /* This is unrelated limitation. */ + else + return true; + } + return false; +} + +static int +check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, + Idx subexp_idx, Idx from_node, Idx bkref_idx) +{ + const re_dfa_t *const dfa = mctx->dfa; + const re_node_set *eclosures = dfa->eclosures + from_node; + Idx node_idx; + + /* Else, we are on the boundary: examine the nodes on the epsilon + closure. */ + for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) + { + Idx node = eclosures->elems[node_idx]; + switch (dfa->nodes[node].type) + { + case OP_BACK_REF: + if (bkref_idx != -1) + { + struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx; + do + { + Idx dst; + int cpos; + + if (ent->node != node) + continue; + + if (subexp_idx < BITSET_WORD_BITS + && !(ent->eps_reachable_subexps_map + & ((bitset_word_t) 1 << subexp_idx))) + continue; + + /* Recurse trying to reach the OP_OPEN_SUBEXP and + OP_CLOSE_SUBEXP cases below. But, if the + destination node is the same node as the source + node, don't recurse because it would cause an + infinite loop: a regex that exhibits this behavior + is ()\1*\1* */ + dst = dfa->edests[node].elems[0]; + if (dst == from_node) + { + if (boundaries & 1) + return -1; + else /* if (boundaries & 2) */ + return 0; + } + + cpos = + check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, + dst, bkref_idx); + if (cpos == -1 /* && (boundaries & 1) */) + return -1; + if (cpos == 0 && (boundaries & 2)) + return 0; + + if (subexp_idx < BITSET_WORD_BITS) + ent->eps_reachable_subexps_map + &= ~((bitset_word_t) 1 << subexp_idx); + } + while (ent++->more); + } + break; + + case OP_OPEN_SUBEXP: + if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx) + return -1; + break; + + case OP_CLOSE_SUBEXP: + if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx) + return 0; + break; + + default: + break; + } + } + + return (boundaries & 2) ? 1 : 0; +} + +static int +check_dst_limits_calc_pos (const re_match_context_t *mctx, Idx limit, + Idx subexp_idx, Idx from_node, Idx str_idx, + Idx bkref_idx) +{ + struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; + int boundaries; + + /* If we are outside the range of the subexpression, return -1 or 1. */ + if (str_idx < lim->subexp_from) + return -1; + + if (lim->subexp_to < str_idx) + return 1; + + /* If we are within the subexpression, return 0. */ + boundaries = (str_idx == lim->subexp_from); + boundaries |= (str_idx == lim->subexp_to) << 1; + if (boundaries == 0) + return 0; + + /* Else, examine epsilon closure. */ + return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, + from_node, bkref_idx); +} + +/* Check the limitations of sub expressions LIMITS, and remove the nodes + which are against limitations from DEST_NODES. */ + +static reg_errcode_t +check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, + const re_node_set *candidates, re_node_set *limits, + struct re_backref_cache_entry *bkref_ents, Idx str_idx) +{ + reg_errcode_t err; + Idx node_idx, lim_idx; + + for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) + { + Idx subexp_idx; + struct re_backref_cache_entry *ent; + ent = bkref_ents + limits->elems[lim_idx]; + + if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) + continue; /* This is unrelated limitation. */ + + subexp_idx = dfa->nodes[ent->node].opr.idx; + if (ent->subexp_to == str_idx) + { + Idx ops_node = -1; + Idx cls_node = -1; + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) + { + Idx node = dest_nodes->elems[node_idx]; + re_token_type_t type = dfa->nodes[node].type; + if (type == OP_OPEN_SUBEXP + && subexp_idx == dfa->nodes[node].opr.idx) + ops_node = node; + else if (type == OP_CLOSE_SUBEXP + && subexp_idx == dfa->nodes[node].opr.idx) + cls_node = node; + } + + /* Check the limitation of the open subexpression. */ + /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ + if (ops_node >= 0) + { + err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes, + candidates); + if ( (err != REG_NOERROR)) + return err; + } + + /* Check the limitation of the close subexpression. */ + if (cls_node >= 0) + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) + { + Idx node = dest_nodes->elems[node_idx]; + if (!re_node_set_contains (dfa->inveclosures + node, + cls_node) + && !re_node_set_contains (dfa->eclosures + node, + cls_node)) + { + /* It is against this limitation. + Remove it form the current sifted state. */ + err = sub_epsilon_src_nodes (dfa, node, dest_nodes, + candidates); + if ( (err != REG_NOERROR)) + return err; + --node_idx; + } + } + } + else /* (ent->subexp_to != str_idx) */ + { + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) + { + Idx node = dest_nodes->elems[node_idx]; + re_token_type_t type = dfa->nodes[node].type; + if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) + { + if (subexp_idx != dfa->nodes[node].opr.idx) + continue; + /* It is against this limitation. + Remove it form the current sifted state. */ + err = sub_epsilon_src_nodes (dfa, node, dest_nodes, + candidates); + if ( (err != REG_NOERROR)) + return err; + } + } + } + } + return REG_NOERROR; +} + +static reg_errcode_t + +sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, + Idx str_idx, const re_node_set *candidates) +{ + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + Idx node_idx, node; + re_sift_context_t local_sctx; + Idx first_idx = search_cur_bkref_entry (mctx, str_idx); + + if (first_idx == -1) + return REG_NOERROR; + + local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ + + for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) + { + Idx enabled_idx; + re_token_type_t type; + struct re_backref_cache_entry *entry; + node = candidates->elems[node_idx]; + type = dfa->nodes[node].type; + /* Avoid infinite loop for the REs like "()\1+". */ + if (node == sctx->last_node && str_idx == sctx->last_str_idx) + continue; + if (type != OP_BACK_REF) + continue; + + entry = mctx->bkref_ents + first_idx; + enabled_idx = first_idx; + do + { + Idx subexp_len; + Idx to_idx; + Idx dst_node; + bool ok; + re_dfastate_t *cur_state; + + if (entry->node != node) + continue; + subexp_len = entry->subexp_to - entry->subexp_from; + to_idx = str_idx + subexp_len; + dst_node = (subexp_len ? dfa->nexts[node] + : dfa->edests[node].elems[0]); + + if (to_idx > sctx->last_str_idx + || sctx->sifted_states[to_idx] == NULL + || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node) + || check_dst_limits (mctx, &sctx->limits, node, + str_idx, dst_node, to_idx)) + continue; + + if (local_sctx.sifted_states == NULL) + { + local_sctx = *sctx; + err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); + if ( (err != REG_NOERROR)) + goto free_return; + } + local_sctx.last_node = node; + local_sctx.last_str_idx = str_idx; + ok = re_node_set_insert (&local_sctx.limits, enabled_idx); + if ( (! ok)) + { + err = REG_ESPACE; + goto free_return; + } + cur_state = local_sctx.sifted_states[str_idx]; + err = sift_states_backward (mctx, &local_sctx); + if ( (err != REG_NOERROR)) + goto free_return; + if (sctx->limited_states != NULL) + { + err = merge_state_array (dfa, sctx->limited_states, + local_sctx.sifted_states, + str_idx + 1); + if ( (err != REG_NOERROR)) + goto free_return; + } + local_sctx.sifted_states[str_idx] = cur_state; + re_node_set_remove (&local_sctx.limits, enabled_idx); + + /* mctx->bkref_ents may have changed, reload the pointer. */ + entry = mctx->bkref_ents + enabled_idx; + } + while (enabled_idx++, entry++->more); + } + err = REG_NOERROR; + free_return: + if (local_sctx.sifted_states != NULL) + { + re_node_set_free (&local_sctx.limits); + } + + return err; +} + + +static reg_errcode_t +transit_state_bkref(re_match_context_t *mctx, const re_node_set *nodes) { + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + Idx i; + Idx cur_str_idx = re_string_cur_idx(&mctx->input); + + for (i = 0; i < nodes->nelem; ++i) { + Idx dest_str_idx, prev_nelem, bkc_idx; + Idx node_idx = nodes->elems[i]; + unsigned int context; + const re_token_t *node = dfa->nodes + node_idx; + re_node_set *new_dest_nodes; + + /* Check whether 'node' is a backreference or not. */ + if (node->type != OP_BACK_REF) + continue; + + if (node->constraint) { + context = re_string_context_at(&mctx->input, cur_str_idx, + mctx->eflags); + if (NOT_SATISFY_NEXT_CONSTRAINT(node->constraint, context)) + continue; + } + + /* 'node' is a backreference. + Check the substring which the substring matched. */ + bkc_idx = mctx->nbkref_ents; + err = get_subexp(mctx, node_idx, cur_str_idx); + if ((err != REG_NOERROR)) + goto free_return; + + /* And add the epsilon closures (which is 'new_dest_nodes') of + the backreference to appropriate state_log. */ + + for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) { + Idx subexp_len; + re_dfastate_t *dest_state; + struct re_backref_cache_entry *bkref_ent; + bkref_ent = mctx->bkref_ents + bkc_idx; + if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) + continue; + subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; + new_dest_nodes = (subexp_len == 0 + ? dfa->eclosures + dfa->edests[node_idx].elems[0] + : dfa->eclosures + dfa->nexts[node_idx]); + dest_str_idx = (cur_str_idx + bkref_ent->subexp_to + - bkref_ent->subexp_from); + context = re_string_context_at(&mctx->input, dest_str_idx - 1, + mctx->eflags); + dest_state = mctx->state_log[dest_str_idx]; + prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 + : mctx->state_log[cur_str_idx]->nodes.nelem); + /* Add 'new_dest_node' to state_log. */ + if (dest_state == NULL) { + mctx->state_log[dest_str_idx] + = re_acquire_state_context(&err, dfa, new_dest_nodes, + context); + if ((mctx->state_log[dest_str_idx] == NULL + && err != REG_NOERROR)) + goto free_return; + } else { + re_node_set dest_nodes; + err = re_node_set_init_union(&dest_nodes, + dest_state->entrance_nodes, + new_dest_nodes); + if ((err != REG_NOERROR)) { + re_node_set_free(&dest_nodes); + goto free_return; + } + mctx->state_log[dest_str_idx] + = re_acquire_state_context(&err, dfa, &dest_nodes, context); + re_node_set_free(&dest_nodes); + if ((mctx->state_log[dest_str_idx] == NULL + && err != REG_NOERROR)) + goto free_return; + } + /* We need to check recursively if the backreference can epsilon + transit. */ + if (subexp_len == 0 + && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) { + err = check_subexp_matching_top(mctx, new_dest_nodes, + cur_str_idx); + if ((err != REG_NOERROR)) + goto free_return; + err = transit_state_bkref(mctx, new_dest_nodes); + if ((err != REG_NOERROR)) + goto free_return; + } + } + } + err = REG_NOERROR; + free_return: + return err; +} + +/* Return the next state to which the current state STATE will transit by + accepting the current input byte, and update STATE_LOG if necessary. + If STATE can accept a multibyte char/collating element/back reference + update the destination of STATE_LOG. */ + +static re_dfastate_t * + +transit_state(reg_errcode_t + *err, + re_match_context_t *mctx, + re_dfastate_t + *state) { + re_dfastate_t **trtable; + unsigned char ch; + +/* Use transition table */ + ch = re_string_fetch_byte(&mctx->input); + for (;;) { + trtable = state->trtable; + if ((trtable != NULL)) + return trtable[ch]; + + trtable = state->word_trtable; + if ((trtable != NULL)) { + unsigned int context; + context + = re_string_context_at(&mctx->input, + re_string_cur_idx(&mctx->input) - 1, + mctx->eflags); + if ( + IS_WORD_CONTEXT(context) + ) + return trtable[ch + SBC_MAX]; + else + return trtable[ch]; + } + + if (! + build_trtable(mctx + ->dfa, state)) { + * + err = REG_ESPACE; + return + NULL; + } + +/* Retry, we now have a transition table. */ + } +} + +/* Update the state_log if we need */ +static re_dfastate_t * +merge_state_with_log(reg_errcode_t *err, re_match_context_t *mctx, + re_dfastate_t *next_state) { + const re_dfa_t *const dfa = mctx->dfa; + Idx cur_idx = re_string_cur_idx(&mctx->input); + + if (cur_idx > mctx->state_log_top) { + mctx->state_log[cur_idx] = next_state; + mctx->state_log_top = cur_idx; + } else if (mctx->state_log[cur_idx] == 0) { + mctx->state_log[cur_idx] = next_state; + } else { + re_dfastate_t *pstate; + unsigned int context; + re_node_set next_nodes, *log_nodes, *table_nodes = NULL; + /* If (state_log[cur_idx] != 0), it implies that cur_idx is + the destination of a multibyte char/collating element/ + back reference. Then the next state is the union set of + these destinations and the results of the transition table. */ + pstate = mctx->state_log[cur_idx]; + log_nodes = pstate->entrance_nodes; + if (next_state != NULL) { + table_nodes = next_state->entrance_nodes; + *err = re_node_set_init_union(&next_nodes, table_nodes, + log_nodes); + if ((*err != REG_NOERROR)) + return NULL; + } else + next_nodes = *log_nodes; + /* Note: We already add the nodes of the initial state, + then we don't need to add them here. */ + + context = re_string_context_at(&mctx->input, + re_string_cur_idx(&mctx->input) - 1, + mctx->eflags); + next_state = mctx->state_log[cur_idx] + = re_acquire_state_context(err, dfa, &next_nodes, context); + /* We don't need to check errors here, since the return value of + this function is next_state and ERR is already set. */ + + if (table_nodes != NULL) + re_node_set_free(&next_nodes); + } + + if ((dfa->nbackref) && next_state != NULL) { + /* Check OP_OPEN_SUBEXP in the current state in case that we use them + later. We must check them here, since the back references in the + next state might use them. */ + *err = check_subexp_matching_top(mctx, &next_state->nodes, + cur_idx); + if ((*err != REG_NOERROR)) + return NULL; + + /* If the next state has back references. */ + if (next_state->has_backref) { + *err = transit_state_bkref(mctx, &next_state->nodes); + if ((*err != REG_NOERROR)) + return NULL; + next_state = mctx->state_log[cur_idx]; + } + } + + return next_state; +} + +/* Skip bytes in the input that correspond to part of a + multi-byte match, then look in the log for a state + from which to restart matching. */ +static re_dfastate_t * +find_recover_state(reg_errcode_t *err, re_match_context_t *mctx) { + re_dfastate_t *cur_state; + do { + Idx max = mctx->state_log_top; + Idx cur_str_idx = re_string_cur_idx(&mctx->input); + + do { + if (++cur_str_idx > max) + return NULL; + re_string_skip_bytes(&mctx->input, 1); + } while (mctx->state_log[cur_str_idx] == NULL); + + cur_state = merge_state_with_log(err, mctx, NULL); + } while (*err == REG_NOERROR && cur_state == NULL); + return cur_state; +} + +/* Functions for matching context. */ + +/* Initialize MCTX. */ + +static reg_errcode_t +match_ctx_init(re_match_context_t *mctx, int eflags, Idx n) { + mctx->eflags = eflags; + mctx->match_last = -1; + if (n > 0) { +/* Avoid overflow. */ + size_t max_object_size = + MAX (sizeof(struct re_backref_cache_entry), + sizeof(re_sub_match_top_t * )); + if ((MIN (IDX_MAX, SIZE_MAX / max_object_size) < n)) + return REG_ESPACE; + + mctx->bkref_ents = re_malloc( + struct re_backref_cache_entry, n); + mctx->sub_tops = re_malloc(re_sub_match_top_t * , n); + if ((mctx->bkref_ents == NULL || mctx->sub_tops == NULL)) + return REG_ESPACE; + } +/* Already zero-ed by the caller. + else + mctx->bkref_ents = NULL; + mctx->nbkref_ents = 0; + mctx->nsub_tops = 0; */ + mctx->abkref_ents = n; + mctx->max_mb_elem_len = 1; + mctx->asub_tops = n; + return REG_NOERROR; +} + +/* Clean the entries which depend on the current input in MCTX. + This function must be invoked when the matcher changes the start index + of the input, or changes the input string. */ + +static void +match_ctx_clean(re_match_context_t *mctx) { + Idx st_idx; + for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) { + Idx sl_idx; + re_sub_match_top_t *top = mctx->sub_tops[st_idx]; + for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx) { + re_sub_match_last_t *last = top->lasts[sl_idx]; + re_free(last->path.array); + re_free(last); + } + re_free(top->lasts); + if (top->path) { + re_free(top->path->array); + re_free(top->path); + } + re_free(top); + } + + mctx->nsub_tops = 0; + mctx->nbkref_ents = 0; +} + +/* Free all the memory associated with MCTX. */ + +static void +match_ctx_free(re_match_context_t *mctx) { + /* First, free all the memory associated with MCTX->SUB_TOPS. */ + match_ctx_clean(mctx); + re_free(mctx->sub_tops); + re_free(mctx->bkref_ents); +} + +/* Add a new backreference entry to MCTX. + Note that we assume that caller never call this function with duplicate + entry, and call with STR_IDX which isn't smaller than any existing entry. +*/ + +static reg_errcode_t + +match_ctx_add_entry(re_match_context_t *mctx, Idx node, Idx str_idx, Idx from, + Idx to) { + if (mctx->nbkref_ents >= mctx->abkref_ents) { + struct re_backref_cache_entry *new_entry; + new_entry = re_realloc(mctx->bkref_ents, + struct re_backref_cache_entry, + mctx->abkref_ents * 2); + if ((new_entry == NULL)) { + re_free(mctx->bkref_ents); + return REG_ESPACE; + } + mctx->bkref_ents = new_entry; + memset(mctx->bkref_ents + mctx->nbkref_ents, '\0', + sizeof(struct re_backref_cache_entry) * mctx->abkref_ents); + mctx->abkref_ents *= 2; + } + if (mctx->nbkref_ents > 0 + && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx) + mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1; + + mctx->bkref_ents[mctx->nbkref_ents].node = node; + mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; + mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; + mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; + +/* This is a cache that saves negative results of check_dst_limits_calc_pos. + If bit N is clear, means that this entry won't epsilon-transition to + an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If + it is set, check_dst_limits_calc_pos_1 will recurse and try to find one + such node. + + A backreference does not epsilon-transition unless it is empty, so set + to all zeros if FROM != TO. */ + mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map + = (from == to ? -1 : 0); + + mctx->bkref_ents[mctx->nbkref_ents++].more = 0; + if (mctx->max_mb_elem_len < to - from) + mctx->max_mb_elem_len = to - from; + return REG_NOERROR; +} + +/* Check whether the regular expression match input string INPUT or not, + and return the index where the matching end. Return -1 if + there is no match, and return -2 in case of an error. + FL_LONGEST_MATCH means we want the POSIX longest matching. + If P_MATCH_FIRST is not NULL, and the match fails, it is set to the + next place where we may want to try matching. + Note that the matcher assumes that the matching starts from the current + index of the buffer. */ + +static Idx +check_matching(re_match_context_t *mctx, bool fl_longest_match, + Idx *p_match_first) { + const re_dfa_t *const dfa = mctx->dfa; + reg_errcode_t err; + Idx match = 0; + Idx match_last = -1; + Idx cur_str_idx = re_string_cur_idx(&mctx->input); + re_dfastate_t *cur_state; + bool at_init_state = p_match_first != NULL; + Idx next_start_idx = cur_str_idx; + + err = REG_NOERROR; + cur_state = acquire_init_state_context(&err, mctx, cur_str_idx); +/* An initial state must not be NULL (invalid). */ + if ((cur_state == NULL)) { + assert(err == REG_ESPACE); + return -2; + } + + if (mctx->state_log != NULL) { + mctx->state_log[cur_str_idx] = cur_state; + +/* Check OP_OPEN_SUBEXP in the initial state in case that we use them +later. E.g. Processing back references. */ + if ((dfa->nbackref)) { + at_init_state = false; + err = check_subexp_matching_top(mctx, &cur_state->nodes, 0); + if ((err != REG_NOERROR)) + return err; + + if (cur_state->has_backref) { + err = transit_state_bkref(mctx, &cur_state->nodes); + if ((err != REG_NOERROR)) + return err; + } + } + } + +/* If the RE accepts NULL string. */ + if ((cur_state->halt)) { + if (!cur_state->has_constraint + || check_halt_state_context(mctx, cur_state, cur_str_idx)) { + if (!fl_longest_match) + return cur_str_idx; + else { + match_last = cur_str_idx; + match = 1; + } + } + } + + while (!re_string_eoi(&mctx->input)) { + re_dfastate_t *old_state = cur_state; + Idx next_char_idx = re_string_cur_idx(&mctx->input) + 1; + + if (((next_char_idx >= mctx->input.bufs_len) + && mctx->input.bufs_len < mctx->input.len) + || ((next_char_idx >= mctx->input.valid_len) + && mctx->input.valid_len < mctx->input.len)) { + err = extend_buffers(mctx, next_char_idx + 1); + if ((err != REG_NOERROR)) { + assert(err == REG_ESPACE); + return -2; + } + } + + cur_state = transit_state(&err, mctx, cur_state); + if (mctx->state_log != NULL) + cur_state = merge_state_with_log(&err, mctx, cur_state); + + if (cur_state == NULL) { +/* Reached the invalid state or an error. Try to recover a valid + state using the state log, if available and if we have not + already found a valid (even if not the longest) match. */ + if ((err != REG_NOERROR)) + return -2; + + if (mctx->state_log == NULL + || (match && !fl_longest_match) + || (cur_state = find_recover_state(&err, mctx)) == NULL) + break; + } + + if ((at_init_state)) { + if (old_state == cur_state) + next_start_idx = next_char_idx; + else + at_init_state = false; + } + + if (cur_state->halt) { +/* Reached a halt state. + Check the halt state can satisfy the current context. */ + if (!cur_state->has_constraint + || check_halt_state_context(mctx, cur_state, + re_string_cur_idx(&mctx->input))) { +/* We found an appropriate halt state. */ + match_last = re_string_cur_idx(&mctx->input); + match = 1; + +/* We found a match, do not modify match_first below. */ + p_match_first = NULL; + if (!fl_longest_match) + break; + } + } + } + + if (p_match_first) + *p_match_first += next_start_idx; + + return match_last; +} + +/* Searches for a compiled pattern PREG in the string STRING, whose + length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same + meaning as with regexec. LAST_START is START + RANGE, where + START and RANGE have the same meaning as with re_search. + Return REG_NOERROR if we find a match, and REG_NOMATCH if not, + otherwise return the error code. + Note: We assume front end functions already check ranges. + (0 <= LAST_START && LAST_START <= LENGTH) */ + +static reg_errcode_t +re_search_internal(const regex_t *preg, const char *string, Idx length, + Idx start, Idx last_start, Idx stop, size_t nmatch, + regmatch_t pmatch[], int eflags) { + reg_errcode_t err; + const re_dfa_t *dfa = preg->buffer; + Idx left_lim, right_lim; + int incr; + bool fl_longest_match; + int match_kind; + Idx match_first; + Idx match_last = -1; + Idx extra_nmatch; + bool sb; + int ch; + re_match_context_t mctx; + char *fastmap = ((preg->fastmap != NULL && preg->fastmap_accurate + && start != last_start && !preg->can_be_null) + ? preg->fastmap : NULL); + RE_TRANSLATE_TYPE t = preg->translate; + + memset(&mctx, '\0', sizeof(re_match_context_t)); + mctx.dfa = dfa; + + + extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0; + nmatch -= extra_nmatch; + + /* Check if the DFA haven't been compiled. */ + if ((preg->used == 0 || dfa->init_state == NULL + || dfa->init_state_word == NULL + || dfa->init_state_nl == NULL + || dfa->init_state_begbuf == NULL)) + return REG_NOMATCH; + + /* If initial states with non-begbuf contexts have no elements, + the regex must be anchored. If preg->newline_anchor is set, + we'll never use init_state_nl, so do not check it. */ + if (dfa->init_state->nodes.nelem == 0 + && dfa->init_state_word->nodes.nelem == 0 + && (dfa->init_state_nl->nodes.nelem == 0 + || !preg->newline_anchor)) { + if (start != 0 && last_start != 0) + return REG_NOMATCH; + start = last_start = 0; + } + + /* We must check the longest matching, if nmatch > 0. */ + fl_longest_match = (nmatch != 0 || dfa->nbackref); + + err = re_string_allocate(&mctx.input, string, length, dfa->nodes_len + 1, + preg->translate, (preg->syntax & RE_ICASE) != 0, + dfa); + if ((err != REG_NOERROR)) + goto free_return; + mctx.input.stop = stop; + mctx.input.raw_stop = stop; + mctx.input.newline_anchor = preg->newline_anchor; + + err = match_ctx_init(&mctx, eflags, dfa->nbackref * 2); + if ((err != REG_NOERROR)) + goto free_return; + + /* We will log all the DFA states through which the dfa pass, + if nmatch > 1, or this dfa has "multibyte node", which is a + back-reference or a node which can accept multibyte character or + multi character collating element. */ + if (nmatch > 1 || dfa->has_mb_node) { + /* Avoid overflow. */ + if (((MIN (IDX_MAX, SIZE_MAX / sizeof(re_dfastate_t * )) + <= mctx.input.bufs_len))) { + err = REG_ESPACE; + goto free_return; + } + + mctx.state_log = re_malloc(re_dfastate_t * , mctx.input.bufs_len + 1); + if ((mctx.state_log == NULL)) { + err = REG_ESPACE; + goto free_return; + } + } else + mctx.state_log = NULL; + + match_first = start; + mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF + : CONTEXT_NEWLINE | CONTEXT_BEGBUF; + + /* Check incrementally whether the input string matches. */ + incr = (last_start < start) ? -1 : 1; + left_lim = (last_start < start) ? last_start : start; + right_lim = (last_start < start) ? start : last_start; + sb = dfa->mb_cur_max == 1; + match_kind = + (fastmap + ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) + | (start <= last_start ? 2 : 0) + | (t != NULL ? 1 : 0)) + : 8); + + for (;; match_first += incr) { + err = REG_NOMATCH; + if (match_first < left_lim || right_lim < match_first) + goto free_return; + + /* Advance as rapidly as possible through the string, until we + find a plausible place to start matching. This may be done + with varying efficiency, so there are various possibilities: + only the most common of them are specialized, in order to + save on code size. We use a switch statement for speed. */ + switch (match_kind) { + case 8: + /* No fastmap. */ + break; + + case 7: + /* Fastmap with single-byte translation, match forward. */ + while ((match_first < right_lim) + && !fastmap[t[(unsigned char) string[match_first]]]) + ++match_first; + goto forward_match_found_start_or_reached_end; + + case 6: + /* Fastmap without translation, match forward. */ + while ((match_first < right_lim) + && !fastmap[(unsigned char) string[match_first]]) + ++match_first; + + forward_match_found_start_or_reached_end: + if ((match_first == right_lim)) { + ch = match_first >= length + ? 0 : (unsigned char) string[match_first]; + if (!fastmap[t ? t[ch] : ch]) + goto free_return; + } + break; + + case 4: + case 5: + /* Fastmap without multi-byte translation, match backwards. */ + while (match_first >= left_lim) { + ch = match_first >= length + ? 0 : (unsigned char) string[match_first]; + if (fastmap[t ? t[ch] : ch]) + break; + --match_first; + } + if (match_first < left_lim) + goto free_return; + break; + + default: + /* In this case, we can't determine easily the current byte, + since it might be a component byte of a multibyte + character. Then we use the constructed buffer instead. */ + for (;;) { + /* If MATCH_FIRST is out of the valid range, reconstruct the + buffers. */ + __re_size_t offset = match_first - mctx.input.raw_mbs_idx; + if ((offset + >= (__re_size_t) mctx.input.valid_raw_len)) { + err = re_string_reconstruct(&mctx.input, match_first, + eflags); + if ((err != REG_NOERROR)) + goto free_return; + + offset = match_first - mctx.input.raw_mbs_idx; + } + /* If MATCH_FIRST is out of the buffer, leave it as '\0'. + Note that MATCH_FIRST must not be smaller than 0. */ + ch = (match_first >= length + ? 0 : re_string_byte_at(&mctx.input, offset)); + if (fastmap[ch]) + break; + match_first += incr; + if (match_first < left_lim || match_first > right_lim) { + err = REG_NOMATCH; + goto free_return; + } + } + break; + } + + /* Reconstruct the buffers so that the matcher can assume that + the matching starts from the beginning of the buffer. */ + err = re_string_reconstruct(&mctx.input, match_first, eflags); + if ((err != REG_NOERROR)) + goto free_return; + + /* It seems to be appropriate one, then use the matcher. */ + /* We assume that the matching starts from 0. */ + mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; + match_last = check_matching(&mctx, fl_longest_match, + start <= last_start ? &match_first : NULL); + if (match_last != -1) { + if ((match_last == -2)) { + err = REG_ESPACE; + goto free_return; + } else { + mctx.match_last = match_last; + if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) { + re_dfastate_t *pstate = mctx.state_log[match_last]; + mctx.last_node = check_halt_state_context(&mctx, pstate, + match_last); + } + if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) + || dfa->nbackref) { + err = prune_impossible_nodes(&mctx); + if (err == REG_NOERROR) + break; + if ((err != REG_NOMATCH)) + goto free_return; + match_last = -1; + } else + break; /* We found a match. */ + } + } + + match_ctx_clean(&mctx); + } + + /* Set pmatch[] if we need. */ + if (nmatch > 0) { + Idx reg_idx; + + /* Initialize registers. */ + for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) + pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; + + /* Set the points where matching start/end. */ + pmatch[0].rm_so = 0; + pmatch[0].rm_eo = mctx.match_last; + /* FIXME: This function should fail if mctx.match_last exceeds + the maximum possible regoff_t value. We need a new error + code REG_OVERFLOW. */ + + if (!preg->no_sub && nmatch > 1) { + err = set_regs(preg, &mctx, nmatch, pmatch, + dfa->has_plural_match && dfa->nbackref > 0); + if ((err != REG_NOERROR)) + goto free_return; + } + + /* At last, add the offset to each register, since we slid + the buffers so that we could assume that the matching starts + from 0. */ + for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) + if (pmatch[reg_idx].rm_so != -1) { + pmatch[reg_idx].rm_so += match_first; + pmatch[reg_idx].rm_eo += match_first; + } + for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx) { + pmatch[nmatch + reg_idx].rm_so = -1; + pmatch[nmatch + reg_idx].rm_eo = -1; + } + + if (dfa->subexp_map) + for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++) + if (dfa->subexp_map[reg_idx] != reg_idx) { + pmatch[reg_idx + 1].rm_so + = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so; + pmatch[reg_idx + 1].rm_eo + = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo; + } + } + + free_return: + re_free(mctx.state_log); + if (dfa->nbackref) + match_ctx_free(&mctx); + re_string_destruct(&mctx.input); + return err; +} + +/* Helper functions. */ + +static reg_errcode_t +merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, + re_dfastate_t **src, Idx num) +{ + Idx st_idx; + reg_errcode_t err; + for (st_idx = 0; st_idx < num; ++st_idx) + { + if (dst[st_idx] == NULL) + dst[st_idx] = src[st_idx]; + else if (src[st_idx] != NULL) + { + re_node_set merged_set; + err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, + &src[st_idx]->nodes); + if ( (err != REG_NOERROR)) + return err; + dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); + re_node_set_free (&merged_set); + if ( (err != REG_NOERROR)) + return err; + } + } + return REG_NOERROR; +} + +static void +sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, + re_dfastate_t **limited_sts, Idx last_node, Idx last_str_idx) +{ + sctx->sifted_states = sifted_sts; + sctx->limited_states = limited_sts; + sctx->last_node = last_node; + sctx->last_str_idx = last_str_idx; + re_node_set_init_empty (&sctx->limits); +} + + +/* regexec searches for a given pattern, specified by PREG, in the + string STRING. + + If NMATCH is zero or REG_NOSUB was set in the cflags argument to + 'regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at + least NMATCH elements, and we set them to the offsets of the + corresponding matched substrings. + + EFLAGS specifies "execution flags" which affect matching: if + REG_NOTBOL is set, then ^ does not match at the beginning of the + string; if REG_NOTEOL is set, then $ does not match at the end. + + We return 0 if we find a match and REG_NOMATCH if not. */ + +int +regexec(const regex_t *_Restrict_ preg, const char *_Restrict_ string, + size_t nmatch, regmatch_t pmatch[], int eflags) { + reg_errcode_t err; + Idx start, length; + re_dfa_t *dfa = preg->buffer; + + if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) + return REG_BADPAT; + + if (eflags & REG_STARTEND) { + start = pmatch[0].rm_so; + length = pmatch[0].rm_eo; + } else { + start = 0; + length = strlen(string); + } + + lock_lock(dfa->lock); + if (preg->no_sub) + err = re_search_internal(preg, string, length, start, length, + length, 0, NULL, eflags); + else + err = re_search_internal(preg, string, length, start, length, + length, nmatch, pmatch, eflags); + lock_unlock(dfa->lock); + return err != REG_NOERROR; +} + +#endif diff --git a/wait.h b/wait.h index 7408d15..3bea227 100644 --- a/wait.h +++ b/wait.h @@ -26,3 +26,7 @@ +#ifdef HAVE_SYS_WAIT_H #include +#else +#include "headers-mingw/sys_wait.h" +#endif