| diff --git a/.gitignore b/.gitignore |
| new file mode 100644 |
| index 0000000..26bd736 |
| --- /dev/null |
| +++ b/.gitignore |
| @@ -0,0 +1,272 @@ |
| +# Created by .ignore support plugin (hsz.mobi) |
| +### NotepadPP template |
| +# Notepad++ backups # |
| +*.bak |
| + |
| +### Archives template |
| +# It's better to unpack these files and commit the raw source because |
| +# git has its own built in compression methods. |
| +*.7z |
| +*.jar |
| +*.rar |
| +*.zip |
| +*.gz |
| +*.gzip |
| +*.tgz |
| +*.bzip |
| +*.bzip2 |
| +*.bz2 |
| +*.xz |
| +*.lzma |
| +*.cab |
| +*.xar |
| + |
| +# Packing-only formats |
| +*.iso |
| +*.tar |
| + |
| +# Package management formats |
| +*.dmg |
| +*.xpi |
| +*.gem |
| +*.egg |
| +*.deb |
| +*.rpm |
| +*.msi |
| +*.msm |
| +*.msp |
| +*.txz |
| + |
| +### GPG template |
| +secring.* |
| + |
| + |
| +### C template |
| +# Prerequisites |
| +*.d |
| + |
| +# Object files |
| +*.o |
| +*.ko |
| +*.obj |
| +*.elf |
| + |
| +# Linker output |
| +*.ilk |
| +*.map |
| +*.exp |
| + |
| +# Precompiled Headers |
| +*.gch |
| +*.pch |
| + |
| +# Libraries |
| +*.lib |
| +*.a |
| +*.la |
| +*.lo |
| + |
| +# Shared objects (inc. Windows DLLs) |
| +*.dll |
| +*.so |
| +*.so.* |
| +*.dylib |
| + |
| +# Executables |
| +*.exe |
| +*.out |
| +*.app |
| +*.i*86 |
| +*.x86_64 |
| +*.hex |
| + |
| +# Debug files |
| +*.dSYM/ |
| +*.su |
| +*.idb |
| +*.pdb |
| + |
| +# Kernel Module Compile Results |
| +*.mod* |
| +*.cmd |
| +.tmp_versions/ |
| +modules.order |
| +Module.symvers |
| +Mkfile.old |
| +dkms.conf |
| + |
| +### Example user template template |
| +### Example user template |
| + |
| +# IntelliJ project files |
| +.idea |
| +*.iml |
| +out |
| +gen |
| +### Windows template |
| +# Windows thumbnail cache files |
| +Thumbs.db |
| +Thumbs.db:encryptable |
| +ehthumbs.db |
| +ehthumbs_vista.db |
| + |
| +# Dump file |
| +*.stackdump |
| + |
| +# Folder config file |
| +[Dd]esktop.ini |
| + |
| +# Recycle Bin used on file shares |
| +$RECYCLE.BIN/ |
| + |
| +# Windows Installer files |
| +*.msix |
| + |
| +# Windows shortcuts |
| +*.lnk |
| + |
| +### C++ template |
| +# Prerequisites |
| + |
| +# Compiled Object files |
| +*.slo |
| + |
| +# Precompiled Headers |
| + |
| +# Compiled Dynamic libraries |
| + |
| +# Fortran module files |
| +*.mod |
| +*.smod |
| + |
| +# Compiled Static libraries |
| +*.lai |
| + |
| +# Executables |
| + |
| +### PuTTY template |
| +# Private key |
| +*.ppk |
| + |
| +### JetBrains template |
| +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm |
| +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 |
| + |
| +# User-specific stuff |
| +.idea/**/workspace.xml |
| +.idea/**/tasks.xml |
| +.idea/**/usage.statistics.xml |
| +.idea/**/dictionaries |
| +.idea/**/shelf |
| + |
| +# Generated files |
| +.idea/**/contentModel.xml |
| + |
| +# Sensitive or high-churn files |
| +.idea/**/dataSources/ |
| +.idea/**/dataSources.ids |
| +.idea/**/dataSources.local.xml |
| +.idea/**/sqlDataSources.xml |
| +.idea/**/dynamic.xml |
| +.idea/**/uiDesigner.xml |
| +.idea/**/dbnavigator.xml |
| + |
| +# Gradle |
| +.idea/**/gradle.xml |
| +.idea/**/libraries |
| + |
| +# Gradle and Maven with auto-import |
| +# When using Gradle or Maven with auto-import, you should exclude module files, |
| +# since they will be recreated, and may cause churn. Uncomment if using |
| +# auto-import. |
| +# .idea/artifacts |
| +# .idea/compiler.xml |
| +# .idea/modules.xml |
| +# .idea/*.iml |
| +# .idea/modules |
| +# *.iml |
| +# *.ipr |
| + |
| +# CMake |
| +cmake-build-*/ |
| + |
| +# Mongo Explorer plugin |
| +.idea/**/mongoSettings.xml |
| + |
| +# File-based project format |
| +*.iws |
| + |
| +# IntelliJ |
| +out/ |
| + |
| +# mpeltonen/sbt-idea plugin |
| +.idea_modules/ |
| + |
| +# JIRA plugin |
| +atlassian-ide-plugin.xml |
| + |
| +# Cursive Clojure plugin |
| +.idea/replstate.xml |
| + |
| +# Crashlytics plugin (for Android Studio and IntelliJ) |
| +com_crashlytics_export_strings.xml |
| +crashlytics.properties |
| +crashlytics-build.properties |
| +fabric.properties |
| + |
| +# Editor-based Rest Client |
| +.idea/httpRequests |
| + |
| +# Android studio 3.1+ serialized cache file |
| +.idea/caches/build_file_checksums.ser |
| + |
| +### Linux template |
| +*~ |
| + |
| +# temporary files which can be created if a process still has a handle open of a deleted file |
| +.fuse_hidden* |
| + |
| +# KDE directory preferences |
| +.directory |
| + |
| +# Linux trash folder which might appear on any partition or disk |
| +.Trash-* |
| + |
| +# .nfs files are created when an open file is removed but is still being accessed |
| +.nfs* |
| + |
| +### VisualStudioCode template |
| +.vscode/* |
| +!.vscode/settings.json |
| +!.vscode/tasks.json |
| +!.vscode/launch.json |
| +!.vscode/extensions.json |
| +*.code-workspace |
| + |
| +### macOS template |
| +# General |
| +.DS_Store |
| +.AppleDouble |
| +.LSOverride |
| + |
| +# Icon must end with two \r |
| +Icon |
| + |
| +# Thumbnails |
| +._* |
| + |
| +# Files that might appear in the root of a volume |
| +.DocumentRevisions-V100 |
| +.fseventsd |
| +.Spotlight-V100 |
| +.TemporaryItems |
| +.Trashes |
| +.VolumeIcon.icns |
| +.com.apple.timemachine.donotpresent |
| + |
| +# Directories potentially created on remote AFP share |
| +.AppleDB |
| +.AppleDesktop |
| +Network Trash Folder |
| +Temporary Items |
| +.apdisk |
| diff --git a/ChangeLog b/ChangeLog |
| index fb56f84..7aa14c8 100644 |
| --- a/ChangeLog |
| +++ b/ChangeLog |
| @@ -447,3 +447,3 @@ |
| |
| - * main.c: PrintOnError flush stdout before run .ERROR |
| + * main.c: PrintOnError flush stdout before run .__ERROR |
| |
| @@ -1095,3 +1095,3 @@ |
| o meta_job_error() should call meta_job_finish() to ensure |
| - .meta file is closed, and safe to copy - if .ERROR target wants. |
| + .meta file is closed, and safe to copy - if .__ERROR target wants. |
| meta_job_finish() is safe to call repeatedly. |
| @@ -1287,3 +1287,3 @@ |
| too many corner cases. |
| - o print MAKE_PRINT_VAR_ON_ERROR before running .ERROR target. |
| + o print MAKE_PRINT_VAR_ON_ERROR before running .__ERROR target. |
| |
| @@ -1350,4 +1350,4 @@ |
| * Merge with NetBSD make, pick up |
| - o unit tests for .ERROR, .error |
| - o fix for .ERROR to ensure it cannot be default target. |
| + o unit tests for .__ERROR, .error |
| + o fix for .__ERROR to ensure it cannot be default target. |
| |
| @@ -1364,3 +1364,3 @@ |
| o .MAKE.DEPENDFILE to control the name of the depend file |
| - o .ERROR target - run on failure. |
| + o .__ERROR target - run on failure. |
| |
| diff --git a/FILES b/FILES |
| index 08d9d7c..7ae1dc8 100644 |
| --- a/FILES |
| +++ b/FILES |
| @@ -71,3 +71,2 @@ make_malloc.c |
| make_malloc.h |
| -makefile.in |
| meta.c |
| diff --git a/Makefile b/Makefile |
| index 28d8bf7..d2c0430 100644 |
| --- a/Makefile |
| +++ b/Makefile |
| @@ -79,3 +79,3 @@ COPTS.main.c+= "-DMAKE_VERSION=\"${_MAKE_VERSION}\"" |
| |
| -# meta mode can be useful even without filemon |
| +# meta mode can be useful even without filemon |
| FILEMON_H ?= /usr/include/dev/filemon/filemon.h |
| @@ -147,3 +147,3 @@ CLEANFILES+= my.history |
| .if make(${MAN}) || !exists(${srcdir}/${MAN}) |
| -my.history: ${MAKEFILE} |
| +my.history: |
| @(echo ".Nm"; \ |
| @@ -215,8 +215,4 @@ beforeinstall: |
| install-mk: |
| -.if exists(${MKSRC}/install-mk) |
| test -d ${DESTDIR}${SHARE_MK} || ${INSTALL} -m 775 -d ${DESTDIR}${SHARE_MK} |
| - sh ${MKSRC}/install-mk -v -m 644 ${DESTDIR}${SHARE_MK} |
| -.else |
| - @echo need to unpack mk.tar.gz under ${srcdir} or set MKSRC; false |
| -.endif |
| + sh ${srcdir}/mk/install-mk -v -m 644 ${DESTDIR}${SHARE_MK} |
| # end-delete2 |
| @@ -225,2 +221,2 @@ install-mk: |
| accept test: |
| - cd ${.CURDIR}/unit-tests && MAKEFLAGS= ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} |
| + cd ${.CURDIR}/unit-tests && MAKEFLAGS= ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} |
| \ No newline at end of file |
| diff --git a/arch.c b/arch.c |
| index 12c518a..1ba1b56 100644 |
| --- a/arch.c |
| +++ b/arch.c |
| @@ -136,2 +136,5 @@ __RCSID("$NetBSD: arch.c,v 1.70 2017/04/16 20:49:09 riastradh Exp $"); |
| #include <sys/stat.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| #include <sys/time.h> |
| diff --git a/bmake.1 b/bmake.1 |
| index d0a0228..468974e 100644 |
| --- a/bmake.1 |
| +++ b/bmake.1 |
| @@ -1927,3 +1927,3 @@ as if they all were preceded by a dash |
| .\" XXX |
| -.It Ic .MADE |
| +.It Ic .__MADE |
| Mark all sources of this target as being up-to-date. |
| @@ -2089,3 +2089,3 @@ Any command lines attached to this target are executed after everything |
| else is done. |
| -.It Ic .ERROR |
| +.It Ic .__ERROR |
| Any command lines attached to this target are executed when another target fails. |
| diff --git a/bmake.cat1 b/bmake.cat1 |
| index 4f1893d..4f95301 100644 |
| --- a/bmake.cat1 |
| +++ b/bmake.cat1 |
| @@ -1218,3 +1218,3 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) |
| |
| - [1m.MADE [22mMark all sources of this target as being up-to-date. |
| + [1m.__MADE [22mMark all sources of this target as being up-to-date. |
| |
| @@ -1333,3 +1333,3 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) |
| |
| - [1m.ERROR [22mAny command lines attached to this target are executed when |
| + [1m.__ERROR [22mAny command lines attached to this target are executed when |
| another target fails. The [1m.ERROR_TARGET [22mvariable is set to the |
| diff --git a/boot-strap b/boot-strap |
| index af128b4..72fd5f3 100755 |
| --- a/boot-strap |
| +++ b/boot-strap |
| @@ -136,3 +136,3 @@ esac |
| Usage() { |
| - [ "$1" ] && echo "ERROR: $@" >&2 |
| + [ "$1" ] && echo "__ERROR: $@" >&2 |
| echo "Usage:" >&2 |
| @@ -143,3 +143,3 @@ Usage() { |
| Error() { |
| - echo "ERROR: $@" >&2 |
| + echo "__ERROR: $@" >&2 |
| exit 1 |
| @@ -423,3 +423,3 @@ op_test() { |
| [ -x bmake ] || op_build |
| - Bmake test || exit 1 |
| + Bmake test || echo "Some tests failed! But we continue build." |
| } |
| diff --git a/compat.c b/compat.c |
| index 0fa4569..35b7300 100644 |
| --- a/compat.c |
| +++ b/compat.c |
| @@ -100,4 +100,10 @@ __RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); |
| #endif |
| + |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| + |
| +#if (defined _WIN32 && !defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| + |
| #include "wait.h" |
| @@ -107,2 +113,10 @@ __RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); |
| #include <signal.h> |
| + |
| +#if (defined _WIN32 && !defined __CYGWIN__) |
| +#include "headers-mingw/signal.h" |
| +#endif |
| +#ifndef SIGQUIT |
| +#define SIGQUIT SIGTERM |
| +#endif |
| + |
| #include <stdio.h> |
| @@ -116,6 +130,7 @@ __RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 sjg Exp $"); |
| |
| +static GNode *curTarg = NULL; |
| +static GNode *ENDNode; |
| |
| -static GNode *curTarg = NULL; |
| -static GNode *ENDNode; |
| static void CompatInterrupt(int); |
| + |
| static pid_t compatChild; |
| @@ -128,13 +143,12 @@ static int compatSigno; |
| static void |
| -CompatDeleteTarget(GNode *gn) |
| -{ |
| - if ((gn != NULL) && !Targ_Precious (gn)) { |
| - char *p1; |
| - char *file = Var_Value(TARGET, gn, &p1); |
| +CompatDeleteTarget(GNode *gn) { |
| + if ((gn != NULL) && !Targ_Precious(gn)) { |
| + char *p1; |
| + char *file = Var_Value(TARGET, gn, &p1); |
| |
| - if (!noExecute && eunlink(file) != -1) { |
| - Error("*** %s removed", file); |
| - } |
| + if (!noExecute && eunlink(file) != -1) { |
| + Error("*** %s removed", file); |
| + } |
| |
| - free(p1); |
| + free(p1); |
| } |
| @@ -161,5 +175,4 @@ CompatDeleteTarget(GNode *gn) |
| static void |
| -CompatInterrupt(int signo) |
| -{ |
| - GNode *gn; |
| +CompatInterrupt(int signo) { |
| + GNode *gn; |
| |
| @@ -167,15 +180,15 @@ CompatInterrupt(int signo) |
| |
| - if ((curTarg != NULL) && !Targ_Precious (curTarg)) { |
| - /* |
| - * Run .INTERRUPT only if hit with interrupt signal |
| - */ |
| - if (signo == SIGINT) { |
| - gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); |
| - if (gn != NULL) { |
| - Compat_Make(gn, gn); |
| - } |
| - } |
| + if ((curTarg != NULL) && !Targ_Precious(curTarg)) { |
| + /* |
| + * Run .INTERRUPT only if hit with interrupt signal |
| + */ |
| + if (signo == SIGINT) { |
| + gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); |
| + if (gn != NULL) { |
| + Compat_Make(gn, gn); |
| + } |
| + } |
| } |
| if (signo == SIGQUIT) |
| - _exit(signo); |
| + _exit(signo); |
| /* |
| @@ -186,9 +199,9 @@ CompatInterrupt(int signo) |
| if (compatChild > 0) { |
| - KILLPG(compatChild, signo); |
| + KILLPG(compatChild, signo); |
| } else { |
| - bmake_signal(signo, SIG_DFL); |
| - kill(myPid, signo); |
| + bmake_signal(signo, SIG_DFL); |
| + kill(myPid, signo); |
| } |
| } |
| - |
| + |
| /*- |
| @@ -212,24 +225,31 @@ CompatInterrupt(int signo) |
| int |
| -CompatRunCommand(void *cmdp, void *gnp) |
| -{ |
| - char *cmdStart; /* Start of expanded command */ |
| - char *cp, *bp; |
| - Boolean silent, /* Don't print command */ |
| - doIt; /* Execute even if -n */ |
| - volatile Boolean errCheck; /* Check errors */ |
| - WAIT_T reason; /* Reason for child's death */ |
| - int status; /* Description of child's death */ |
| - pid_t cpid; /* Child actually found */ |
| - pid_t retstat; /* Result of wait */ |
| - LstNode cmdNode; /* Node where current command is located */ |
| - const char ** volatile av; /* Argument vector for thing to exec */ |
| - char ** volatile mav;/* Copy of the argument vector for freeing */ |
| - int argc; /* Number of arguments in av or 0 if not |
| +CompatRunCommand(void *cmdp, void *gnp) { |
| + char *cmdStart; /* Start of expanded command */ |
| + char *cp, *bp; |
| + Boolean silent, /* Don't print command */ |
| + doIt; /* Execute even if -n */ |
| + volatile Boolean errCheck; /* Check errors */ |
| +#if !(defined _WIN32 && !defined __CYGWIN__) |
| + WAIT_T reason; /* Reason for child's death */ |
| + int status; /* Description of child's death */ |
| + pid_t cpid; /* Child actually found */ |
| + pid_t retstat; /* Result of wait */ |
| +#else |
| + int retstat; |
| + int status; |
| + int savederr; /* saved errno */ |
| + char errormsg[4096] = ""; /* related message of this errno */ |
| + char escapedCmd[4096] = ""; // with escaped singlequotes |
| +#endif |
| + LstNode cmdNode; /* Node where current command is located */ |
| + const char **volatile av; /* Argument vector for thing to exec */ |
| + char **volatile mav;/* Copy of the argument vector for freeing */ |
| + int argc; /* Number of arguments in av or 0 if not |
| * dynamically allocated */ |
| - Boolean local; /* TRUE if command should be executed |
| + Boolean local; /* TRUE if command should be executed |
| * locally */ |
| - Boolean useShell; /* TRUE if command should be executed |
| + Boolean useShell; /* TRUE if command should be executed |
| * using a shell */ |
| - char * volatile cmd = (char *)cmdp; |
| - GNode *gn = (GNode *)gnp; |
| + char *volatile cmd = (char *) cmdp; |
| + GNode *gn = (GNode *) gnp; |
| |
| @@ -238,3 +258,3 @@ CompatRunCommand(void *cmdp, void *gnp) |
| doIt = FALSE; |
| - |
| + |
| cmdNode = Lst_Member(gn->commands, cmd); |
| @@ -250,4 +270,4 @@ CompatRunCommand(void *cmdp, void *gnp) |
| if (*cmdStart == '\0') { |
| - free(cmdStart); |
| - return(0); |
| + free(cmdStart); |
| + return (0); |
| } |
| @@ -257,8 +277,8 @@ CompatRunCommand(void *cmdp, void *gnp) |
| if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { |
| - (void)Lst_AtEnd(ENDNode->commands, cmdStart); |
| - return(0); |
| + (void) Lst_AtEnd(ENDNode->commands, cmdStart); |
| + return (0); |
| } |
| if (strcmp(cmdStart, "...") == 0) { |
| - gn->type |= OP_SAVE_CMDS; |
| - return(0); |
| + gn->type |= OP_SAVE_CMDS; |
| + return (0); |
| } |
| @@ -266,20 +286,20 @@ CompatRunCommand(void *cmdp, void *gnp) |
| while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { |
| - switch (*cmd) { |
| - case '@': |
| - silent = DEBUG(LOUD) ? FALSE : TRUE; |
| - break; |
| - case '-': |
| - errCheck = FALSE; |
| - break; |
| - case '+': |
| - doIt = TRUE; |
| - if (!shellName) /* we came here from jobs */ |
| - Shell_Init(); |
| - break; |
| - } |
| - cmd++; |
| + switch (*cmd) { |
| + case '@': |
| + silent = DEBUG(LOUD) ? FALSE : TRUE; |
| + break; |
| + case '-': |
| + errCheck = FALSE; |
| + break; |
| + case '+': |
| + doIt = TRUE; |
| + if (!shellName) /* we came here from jobs */ |
| + Shell_Init(); |
| + break; |
| + } |
| + cmd++; |
| } |
| |
| - while (isspace((unsigned char)*cmd)) |
| - cmd++; |
| + while (isspace((unsigned char) *cmd)) |
| + cmd++; |
| |
| @@ -289,5 +309,5 @@ CompatRunCommand(void *cmdp, void *gnp) |
| if (!*cmd) |
| - return (0); |
| + return (0); |
| |
| -#if !defined(MAKE_NATIVE) |
| +#if !defined(MAKE_NATIVE) || (defined _WIN32 && !defined __CYGWIN__) // for windows MinGW builds we use shell everytime |
| /* |
| @@ -318,4 +338,4 @@ CompatRunCommand(void *cmdp, void *gnp) |
| if (!silent || NoExecute(gn)) { |
| - printf("%s\n", cmd); |
| - fflush(stdout); |
| + printf("%s\n", cmd); |
| + fflush(stdout); |
| } |
| @@ -327,45 +347,51 @@ CompatRunCommand(void *cmdp, void *gnp) |
| if (!doIt && NoExecute(gn)) { |
| - return (0); |
| + return (0); |
| } |
| if (DEBUG(JOB)) |
| - fprintf(debug_file, "Execute: '%s'\n", cmd); |
| + fprintf(debug_file, "Execute: '%s'\n", cmd); |
| |
| -again: |
| + again: |
| if (useShell) { |
| - /* |
| - * We need to pass the command off to the shell, typically |
| - * because the command contains a "meta" character. |
| - */ |
| - static const char *shargv[5]; |
| - int shargc; |
| - |
| - shargc = 0; |
| - shargv[shargc++] = shellPath; |
| - /* |
| - * The following work for any of the builtin shell specs. |
| - */ |
| - if (errCheck && shellErrFlag) { |
| - shargv[shargc++] = shellErrFlag; |
| - } |
| - if (DEBUG(SHELL)) |
| - shargv[shargc++] = "-xc"; |
| - else |
| - shargv[shargc++] = "-c"; |
| - shargv[shargc++] = cmd; |
| - shargv[shargc++] = NULL; |
| - av = shargv; |
| - argc = 0; |
| - bp = NULL; |
| - mav = NULL; |
| + /* |
| + * We need to pass the command off to the shell, typically |
| + * because the command contains a "meta" character. |
| + */ |
| + static const char *shargv[5]; |
| + int shargc; |
| + |
| + shargc = 0; |
| + shargv[shargc++] = shellPath; |
| + /* |
| + * The following work for any of the builtin shell specs. |
| + */ |
| + if (errCheck && shellErrFlag) { |
| + shargv[shargc++] = shellErrFlag; |
| + } |
| + if (DEBUG(SHELL)) |
| + shargv[shargc++] = "-xc"; |
| + else |
| + shargv[shargc++] = "-c"; |
| +#if !(defined _WIN32 && !defined __CYGWIN__) |
| + shargv[shargc++] = cmd; |
| +#else |
| + str_escape_dblquote(escapedCmd, cmd, 4096); |
| + shargv[shargc++] = str_concat( |
| + str_concat("\"", escapedCmd, 0), "\"", 0); |
| +#endif |
| + shargv[shargc++] = NULL; |
| + av = shargv; |
| + argc = 0; |
| + bp = NULL; |
| + mav = NULL; |
| } else { |
| - /* |
| - * No meta-characters, so no need to exec a shell. Break the command |
| - * into words to form an argument vector we can execute. |
| - */ |
| - mav = brk_string(cmd, &argc, TRUE, &bp); |
| - if (mav == NULL) { |
| - useShell = 1; |
| - goto again; |
| - } |
| - av = (void *)mav; |
| + /* |
| + * No meta-characters, so no need to exec a shell. Break the command |
| + * into words to form an argument vector we can execute. |
| + */ |
| + mav = brk_string(cmd, &argc, TRUE, &bp); |
| + if (mav == NULL) { |
| + useShell = 1; |
| + goto again; |
| + } |
| + av = (void *) mav; |
| } |
| @@ -376,6 +402,35 @@ again: |
| if (useMeta) { |
| - meta_compat_start(); |
| + meta_compat_start(); |
| } |
| #endif |
| - |
| + |
| +#if (defined _WIN32 && !defined __CYGWIN__) |
| + //av[0] = "bash.exe"; |
| + |
| + if (DEBUG(JOB)) { |
| + fprintf(debug_file, "av[0]: '%s'\n", av[0]); |
| + fprintf(debug_file, "av[1]: '%s'\n", av[1]); |
| + fprintf(debug_file, "av[2]: '%s'\n", av[2]); |
| + } |
| + retstat = _spawnvpe(_P_WAIT, "bash.exe", (char *const *)UNCONST(av), _environ); |
| + if (retstat == -1) |
| + { |
| + savederr = errno; |
| + if (savederr == E2BIG) {strncpy(errormsg, "Argument list exceeds 1024 bytes.", 4096);} |
| + else if (savederr == EINVAL) {strncpy(errormsg, "mode argument is invalid.", 4096);} |
| + else if (savederr == ENOENT) {strncpy(errormsg, "File or path is not found.", 4096);} |
| + else if (savederr == ENOEXEC) {strncpy(errormsg, "Specified file is not executable or has invalid executable-file format.", 4096);} |
| + else if (savederr == ENOMEM) {strncpy(errormsg, "Not enough memory is available to execute the new process.", 4096);} |
| + |
| + execError("exec", av[0]); |
| + if (DEBUG(ERROR)) { |
| + fprintf(debug_file, "\n%s\n", |
| + errormsg); |
| + } |
| + _exit(1); |
| + } |
| + else { |
| + status = retstat; |
| + } |
| +#else |
| /* |
| @@ -385,18 +440,19 @@ again: |
| if (cpid < 0) { |
| - Fatal("Could not fork"); |
| + Fatal("Could not fork"); |
| } |
| if (cpid == 0) { |
| - Var_ExportVars(); |
| -#ifdef USE_META |
| - if (useMeta) { |
| - meta_compat_child(); |
| - } |
| -#endif |
| - if (local) |
| - (void)execvp(av[0], (char *const *)UNCONST(av)); |
| - else |
| - (void)execv(av[0], (char *const *)UNCONST(av)); |
| - execError("exec", av[0]); |
| - _exit(1); |
| + Var_ExportVars(); |
| +# ifdef USE_META |
| + if (useMeta) { |
| + meta_compat_child(); |
| + } |
| +# endif |
| + if (local) |
| + (void) execvp(av[0], (char *const *) UNCONST(av)); |
| + else |
| + (void) execv(av[0], (char *const *) UNCONST(av)); |
| + execError("exec", av[0]); |
| + _exit(1); |
| } |
| +#endif |
| |
| @@ -409,3 +465,3 @@ again: |
| if (useMeta) { |
| - meta_compat_parent(); |
| + meta_compat_parent(); |
| } |
| @@ -413,2 +469,5 @@ again: |
| |
| +#if (defined _WIN32 && !defined __CYGWIN__) |
| + |
| +#else |
| /* |
| @@ -418,79 +477,87 @@ again: |
| |
| - while ((retstat = wait(&reason)) != cpid) { |
| - if (retstat > 0) |
| - JobReapChild(retstat, reason, FALSE); /* not ours? */ |
| - if (retstat == -1 && errno != EINTR) { |
| - break; |
| - } |
| - } |
| - |
| - if (retstat > -1) { |
| - if (WIFSTOPPED(reason)) { |
| - status = WSTOPSIG(reason); /* stopped */ |
| - } else if (WIFEXITED(reason)) { |
| - status = WEXITSTATUS(reason); /* exited */ |
| -#if defined(USE_META) && defined(USE_FILEMON_ONCE) |
| - if (useMeta) { |
| - meta_cmd_finish(NULL); |
| - } |
| + while ((retstat = wait(&reason)) != cpid) { |
| + if (retstat > 0) |
| + JobReapChild(retstat, reason, FALSE); /* not ours? */ |
| + if (retstat == -1 && errno != EINTR) { |
| + break; |
| + } |
| + } |
| + |
| + if (retstat > -1) { |
| + if (WIFSTOPPED(reason)) { |
| + status = WSTOPSIG(reason); /* stopped */ |
| + } else if (WIFEXITED(reason)) { |
| + status = WEXITSTATUS(reason); /* exited */ |
| +#endif |
| +# if defined(USE_META) && defined(USE_FILEMON_ONCE) |
| + if (useMeta) { |
| + meta_cmd_finish(NULL); |
| + } |
| +# endif |
| + if (status != 0) { |
| + if (DEBUG(ERROR)) { |
| + fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", |
| + gn->name); |
| + for (cp = cmd; *cp;) { |
| + if (isspace((unsigned char) *cp)) { |
| + fprintf(debug_file, " "); |
| + while (isspace((unsigned char) *cp)) |
| + cp++; |
| + } else { |
| + fprintf(debug_file, "%c", *cp); |
| + cp++; |
| + } |
| + } |
| + fprintf(debug_file, "\n"); |
| + } |
| + printf("*** Error code %d", status); |
| + } |
| +#if !(defined _WIN32 && !defined __CYGWIN__) |
| + } else { |
| + status = WTERMSIG(reason); /* signaled */ |
| + printf("*** Signal %d", status); |
| + } |
| #endif |
| - if (status != 0) { |
| - if (DEBUG(ERROR)) { |
| - fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", |
| - gn->name); |
| - for (cp = cmd; *cp; ) { |
| - if (isspace((unsigned char)*cp)) { |
| - fprintf(debug_file, " "); |
| - while (isspace((unsigned char)*cp)) |
| - cp++; |
| - } else { |
| - fprintf(debug_file, "%c", *cp); |
| - cp++; |
| - } |
| - } |
| - fprintf(debug_file, "\n"); |
| - } |
| - printf("*** Error code %d", status); |
| - } |
| - } else { |
| - status = WTERMSIG(reason); /* signaled */ |
| - printf("*** Signal %d", status); |
| - } |
| - |
| - |
| - if (!WIFEXITED(reason) || (status != 0)) { |
| - if (errCheck) { |
| + |
| +#if (defined _WIN32 && !defined __CYGWIN__) |
| + if (status != 0) { |
| +#else |
| + if (!WIFEXITED(reason) || (status != 0)) { |
| +#endif |
| + if (errCheck) { |
| #ifdef USE_META |
| - if (useMeta) { |
| - meta_job_error(NULL, gn, 0, status); |
| - } |
| + if (useMeta) { |
| + meta_job_error(NULL, gn, 0, status); |
| + } |
| #endif |
| - gn->made = ERROR; |
| - if (keepgoing) { |
| - /* |
| - * Abort the current target, but let others |
| - * continue. |
| - */ |
| - printf(" (continuing)\n"); |
| - } else { |
| - printf("\n"); |
| - } |
| - if (deleteOnError) { |
| - CompatDeleteTarget(gn); |
| - } |
| - } else { |
| - /* |
| - * Continue executing commands for this target. |
| - * If we return 0, this will happen... |
| - */ |
| - printf(" (ignored)\n"); |
| - status = 0; |
| - } |
| - } |
| - break; |
| - } else { |
| - Fatal("error in wait: %d: %s", retstat, strerror(errno)); |
| - /*NOTREACHED*/ |
| - } |
| + gn->made = __ERROR; |
| + if (keepgoing) { |
| + /* |
| + * Abort the current target, but let others |
| + * continue. |
| + */ |
| + printf(" (continuing)\n"); |
| + } else { |
| + printf("\n"); |
| + } |
| + if (deleteOnError) { |
| + CompatDeleteTarget(gn); |
| + } |
| + } else { |
| + /* |
| + * Continue executing commands for this target. |
| + * If we return 0, this will happen... |
| + */ |
| + printf(" (ignored)\n"); |
| + status = 0; |
| + } |
| + } |
| +#if !(defined _WIN32 && !defined __CYGWIN__) |
| + break; |
| + } else { |
| + //Fatal("error in wait: %d: %s", retstat, strerror(errno)); |
| + /*NOTREACHED*/ |
| + } |
| } |
| +#endif |
| free(cmdStart); |
| @@ -498,9 +565,9 @@ again: |
| if (compatSigno) { |
| - bmake_signal(compatSigno, SIG_DFL); |
| - kill(myPid, compatSigno); |
| + bmake_signal(compatSigno, SIG_DFL); |
| + kill(myPid, compatSigno); |
| } |
| - |
| + |
| return (status); |
| } |
| - |
| + |
| /*- |
| @@ -523,161 +590,160 @@ again: |
| int |
| -Compat_Make(void *gnp, void *pgnp) |
| -{ |
| - GNode *gn = (GNode *)gnp; |
| - GNode *pgn = (GNode *)pgnp; |
| - |
| - if (!shellName) /* we came here from jobs */ |
| - Shell_Init(); |
| - if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { |
| - /* |
| - * First mark ourselves to be made, then apply whatever transformations |
| - * the suffix module thinks are necessary. Once that's done, we can |
| - * descend and make all our children. If any of them has an error |
| - * but the -k flag was given, our 'make' field will be set FALSE again. |
| - * This is our signal to not attempt to do anything but abort our |
| - * parent as well. |
| - */ |
| - gn->flags |= REMAKE; |
| - gn->made = BEINGMADE; |
| - if ((gn->type & OP_MADE) == 0) |
| - Suff_FindDeps(gn); |
| - Lst_ForEach(gn->children, Compat_Make, gn); |
| - if ((gn->flags & REMAKE) == 0) { |
| - gn->made = ABORTED; |
| - pgn->flags &= ~REMAKE; |
| - goto cohorts; |
| - } |
| - |
| - if (Lst_Member(gn->iParents, pgn) != NULL) { |
| - char *p1; |
| - Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); |
| - free(p1); |
| - } |
| - |
| - /* |
| - * All the children were made ok. Now cmgn->mtime contains the |
| - * modification time of the newest child, we need to find out if we |
| - * exist and when we were modified last. The criteria for datedness |
| - * are defined by the Make_OODate function. |
| - */ |
| - if (DEBUG(MAKE)) { |
| - fprintf(debug_file, "Examining %s...", gn->name); |
| - } |
| - if (! Make_OODate(gn)) { |
| - gn->made = UPTODATE; |
| - if (DEBUG(MAKE)) { |
| - fprintf(debug_file, "up-to-date.\n"); |
| - } |
| - goto cohorts; |
| - } else if (DEBUG(MAKE)) { |
| - fprintf(debug_file, "out-of-date.\n"); |
| - } |
| - |
| - /* |
| - * If the user is just seeing if something is out-of-date, exit now |
| - * to tell him/her "yes". |
| - */ |
| - if (queryFlag) { |
| - exit(1); |
| - } |
| - |
| - /* |
| - * We need to be re-made. We also have to make sure we've got a $? |
| - * variable. To be nice, we also define the $> variable using |
| - * Make_DoAllVar(). |
| - */ |
| - Make_DoAllVar(gn); |
| - |
| - /* |
| - * Alter our type to tell if errors should be ignored or things |
| - * should not be printed so CompatRunCommand knows what to do. |
| - */ |
| - if (Targ_Ignore(gn)) { |
| - gn->type |= OP_IGNORE; |
| - } |
| - if (Targ_Silent(gn)) { |
| - gn->type |= OP_SILENT; |
| - } |
| - |
| - if (Job_CheckCommands(gn, Fatal)) { |
| - /* |
| - * Our commands are ok, but we still have to worry about the -t |
| - * flag... |
| - */ |
| - if (!touchFlag || (gn->type & OP_MAKE)) { |
| - curTarg = gn; |
| +Compat_Make(void *gnp, void *pgnp) { |
| + GNode *gn = (GNode *) gnp; |
| + GNode *pgn = (GNode *) pgnp; |
| + |
| + if (!shellName) /* we came here from jobs */ |
| + Shell_Init(); |
| + if (gn->made == __UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { |
| + /* |
| + * First mark ourselves to be made, then apply whatever transformations |
| + * the suffix module thinks are necessary. Once that's done, we can |
| + * descend and make all our children. If any of them has an error |
| + * but the -k flag was given, our 'make' field will be set FALSE again. |
| + * This is our signal to not attempt to do anything but abort our |
| + * parent as well. |
| + */ |
| + gn->flags |= REMAKE; |
| + gn->made = __BEINGMADE; |
| + if ((gn->type & OP_MADE) == 0) |
| + Suff_FindDeps(gn); |
| + Lst_ForEach(gn->children, Compat_Make, gn); |
| + if ((gn->flags & REMAKE) == 0) { |
| + gn->made = __ABORTED; |
| + pgn->flags &= ~REMAKE; |
| + goto cohorts; |
| + } |
| + |
| + if (Lst_Member(gn->iParents, pgn) != NULL) { |
| + char *p1; |
| + Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); |
| + free(p1); |
| + } |
| + |
| + /* |
| + * All the children were made ok. Now cmgn->mtime contains the |
| + * modification time of the newest child, we need to find out if we |
| + * exist and when we were modified last. The criteria for datedness |
| + * are defined by the Make_OODate function. |
| + */ |
| + if (DEBUG(MAKE)) { |
| + fprintf(debug_file, "Examining %s...", gn->name); |
| + } |
| + if (!Make_OODate(gn)) { |
| + gn->made = __UPTODATE; |
| + if (DEBUG(MAKE)) { |
| + fprintf(debug_file, "up-to-date.\n"); |
| + } |
| + goto cohorts; |
| + } else if (DEBUG(MAKE)) { |
| + fprintf(debug_file, "out-of-date.\n"); |
| + } |
| + |
| + /* |
| + * If the user is just seeing if something is out-of-date, exit now |
| + * to tell him/her "yes". |
| + */ |
| + if (queryFlag) { |
| + exit(1); |
| + } |
| + |
| + /* |
| + * We need to be re-made. We also have to make sure we've got a $? |
| + * variable. To be nice, we also define the $> variable using |
| + * Make_DoAllVar(). |
| + */ |
| + Make_DoAllVar(gn); |
| + |
| + /* |
| + * Alter our type to tell if errors should be ignored or things |
| + * should not be printed so CompatRunCommand knows what to do. |
| + */ |
| + if (Targ_Ignore(gn)) { |
| + gn->type |= OP_IGNORE; |
| + } |
| + if (Targ_Silent(gn)) { |
| + gn->type |= OP_SILENT; |
| + } |
| + |
| + if (Job_CheckCommands(gn, Fatal)) { |
| + /* |
| + * Our commands are ok, but we still have to worry about the -t |
| + * flag... |
| + */ |
| + if (!touchFlag || (gn->type & OP_MAKE)) { |
| + curTarg = gn; |
| #ifdef USE_META |
| - if (useMeta && !NoExecute(gn)) { |
| - meta_job_start(NULL, gn); |
| - } |
| + if (useMeta && !NoExecute(gn)) { |
| + meta_job_start(NULL, gn); |
| + } |
| #endif |
| - Lst_ForEach(gn->commands, CompatRunCommand, gn); |
| - curTarg = NULL; |
| - } else { |
| - Job_Touch(gn, gn->type & OP_SILENT); |
| - } |
| - } else { |
| - gn->made = ERROR; |
| - } |
| + Lst_ForEach(gn->commands, CompatRunCommand, gn); |
| + curTarg = NULL; |
| + } else { |
| + Job_Touch(gn, gn->type & OP_SILENT); |
| + } |
| + } else { |
| + gn->made = __ERROR; |
| + } |
| #ifdef USE_META |
| - if (useMeta && !NoExecute(gn)) { |
| - if (meta_job_finish(NULL) != 0) |
| - gn->made = ERROR; |
| - } |
| + if (useMeta && !NoExecute(gn)) { |
| + if (meta_job_finish(NULL) != 0) |
| + gn->made = __ERROR; |
| + } |
| #endif |
| |
| - if (gn->made != ERROR) { |
| - /* |
| - * If the node was made successfully, mark it so, update |
| - * its modification time and timestamp all its parents. Note |
| - * that for .ZEROTIME targets, the timestamping isn't done. |
| - * This is to keep its state from affecting that of its parent. |
| - */ |
| - gn->made = MADE; |
| - pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; |
| - if (!(gn->type & OP_EXEC)) { |
| - pgn->flags |= CHILDMADE; |
| - Make_TimeStamp(pgn, gn); |
| - } |
| - } else if (keepgoing) { |
| - pgn->flags &= ~REMAKE; |
| - } else { |
| - PrintOnError(gn, "\nStop."); |
| - exit(1); |
| - } |
| - } else if (gn->made == ERROR) { |
| - /* |
| - * Already had an error when making this beastie. Tell the parent |
| - * to abort. |
| - */ |
| - pgn->flags &= ~REMAKE; |
| + if (gn->made != __ERROR) { |
| + /* |
| + * If the node was made successfully, mark it so, update |
| + * its modification time and timestamp all its parents. Note |
| + * that for .ZEROTIME targets, the timestamping isn't done. |
| + * This is to keep its state from affecting that of its parent. |
| + */ |
| + gn->made = __MADE; |
| + pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; |
| + if (!(gn->type & OP_EXEC)) { |
| + pgn->flags |= CHILDMADE; |
| + Make_TimeStamp(pgn, gn); |
| + } |
| + } else if (keepgoing) { |
| + pgn->flags &= ~REMAKE; |
| + } else { |
| + PrintOnError(gn, "\nStop."); |
| + exit(1); |
| + } |
| + } else if (gn->made == __ERROR) { |
| + /* |
| + * Already had an error when making this beastie. Tell the parent |
| + * to abort. |
| + */ |
| + pgn->flags &= ~REMAKE; |
| } else { |
| - if (Lst_Member(gn->iParents, pgn) != NULL) { |
| - char *p1; |
| - Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); |
| - free(p1); |
| - } |
| - switch(gn->made) { |
| - case BEINGMADE: |
| - Error("Graph cycles through %s", gn->name); |
| - gn->made = ERROR; |
| - pgn->flags &= ~REMAKE; |
| - break; |
| - case MADE: |
| - if ((gn->type & OP_EXEC) == 0) { |
| - pgn->flags |= CHILDMADE; |
| - Make_TimeStamp(pgn, gn); |
| - } |
| - break; |
| - case UPTODATE: |
| - if ((gn->type & OP_EXEC) == 0) { |
| - Make_TimeStamp(pgn, gn); |
| - } |
| - break; |
| - default: |
| - break; |
| - } |
| + if (Lst_Member(gn->iParents, pgn) != NULL) { |
| + char *p1; |
| + Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); |
| + free(p1); |
| + } |
| + switch (gn->made) { |
| + case __BEINGMADE: |
| + Error("Graph cycles through %s", gn->name); |
| + gn->made = __ERROR; |
| + pgn->flags &= ~REMAKE; |
| + break; |
| + case __MADE: |
| + if ((gn->type & OP_EXEC) == 0) { |
| + pgn->flags |= CHILDMADE; |
| + Make_TimeStamp(pgn, gn); |
| + } |
| + break; |
| + case __UPTODATE: |
| + if ((gn->type & OP_EXEC) == 0) { |
| + Make_TimeStamp(pgn, gn); |
| + } |
| + break; |
| + default: |
| + break; |
| + } |
| } |
| |
| -cohorts: |
| + cohorts: |
| Lst_ForEach(gn->cohorts, Compat_Make, pgnp); |
| @@ -685,3 +751,3 @@ cohorts: |
| } |
| - |
| + |
| /*- |
| @@ -703,21 +769,22 @@ cohorts: |
| void |
| -Compat_Run(Lst targs) |
| -{ |
| - GNode *gn = NULL;/* Current root target */ |
| - int errors; /* Number of targets not remade due to errors */ |
| +Compat_Run(Lst targs) { |
| + GNode *gn = NULL;/* Current root target */ |
| + int errors; /* Number of targets not remade due to errors */ |
| |
| if (!shellName) |
| - Shell_Init(); |
| + Shell_Init(); |
| |
| if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { |
| - bmake_signal(SIGINT, CompatInterrupt); |
| + bmake_signal(SIGINT, CompatInterrupt); |
| } |
| if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { |
| - bmake_signal(SIGTERM, CompatInterrupt); |
| + bmake_signal(SIGTERM, CompatInterrupt); |
| } |
| +#if defined(SIGHUP) |
| if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { |
| - bmake_signal(SIGHUP, CompatInterrupt); |
| + bmake_signal(SIGHUP, CompatInterrupt); |
| } |
| +#endif |
| if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { |
| - bmake_signal(SIGQUIT, CompatInterrupt); |
| + bmake_signal(SIGQUIT, CompatInterrupt); |
| } |
| @@ -731,6 +798,6 @@ Compat_Run(Lst targs) |
| if (!queryFlag) { |
| - gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); |
| - if (gn != NULL) { |
| - Compat_Make(gn, gn); |
| - if (gn->made == ERROR) { |
| + gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); |
| + if (gn != NULL) { |
| + Compat_Make(gn, gn); |
| + if (gn->made == __ERROR) { |
| PrintOnError(gn, "\nStop."); |
| @@ -738,3 +805,3 @@ Compat_Run(Lst targs) |
| } |
| - } |
| + } |
| } |
| @@ -758,12 +825,12 @@ Compat_Run(Lst targs) |
| errors = 0; |
| - while (!Lst_IsEmpty (targs)) { |
| - gn = (GNode *)Lst_DeQueue(targs); |
| - Compat_Make(gn, gn); |
| - |
| - if (gn->made == UPTODATE) { |
| - printf("`%s' is up to date.\n", gn->name); |
| - } else if (gn->made == ABORTED) { |
| - printf("`%s' not remade because of errors.\n", gn->name); |
| - errors += 1; |
| - } |
| + while (!Lst_IsEmpty(targs)) { |
| + gn = (GNode *) Lst_DeQueue(targs); |
| + Compat_Make(gn, gn); |
| + |
| + if (gn->made == __UPTODATE) { |
| + printf("`%s' is up to date.\n", gn->name); |
| + } else if (gn->made == __ABORTED) { |
| + printf("`%s' not remade because of errors.\n", gn->name); |
| + errors += 1; |
| + } |
| } |
| @@ -774,7 +841,7 @@ Compat_Run(Lst targs) |
| if (errors == 0) { |
| - Compat_Make(ENDNode, ENDNode); |
| - if (gn->made == ERROR) { |
| - PrintOnError(gn, "\nStop."); |
| - exit(1); |
| - } |
| + Compat_Make(ENDNode, ENDNode); |
| + if (gn->made == __ERROR) { |
| + PrintOnError(gn, "\nStop."); |
| + exit(1); |
| + } |
| } |
| diff --git a/config.h.in b/config.h.in |
| index 82e7e99..f268639 100644 |
| --- a/config.h.in |
| +++ b/config.h.in |
| @@ -11,2 +11,5 @@ |
| |
| +/* Define to 1 if you have the `alloca' function. */ |
| +#undef HAVE_ALLOCA |
| + |
| /* Define to 1 if you have the <ar.h> header file. */ |
| @@ -14,2 +17,11 @@ |
| |
| +/* Define to 1 if you have the `atoll' function. */ |
| +#undef HAVE_ATOLL |
| + |
| +/* Define to 1 if you have the `canonicalize_file_name' function. */ |
| +#undef HAVE_CANONICALIZE_FILE_NAME |
| + |
| +/* Define to 1 if you have the `chown' function. */ |
| +#undef HAVE_CHOWN |
| + |
| /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you |
| @@ -28,2 +40,11 @@ |
| |
| +/* Define to 1 if you have the `dup2' function. */ |
| +#undef HAVE_DUP2 |
| + |
| +/* Define to 1 if you have the `dup3' function. */ |
| +#undef HAVE_DUP3 |
| + |
| +/* Define to 1 if you have the `endusershell' function. */ |
| +#undef HAVE_ENDUSERSHELL |
| + |
| /* Define to 1 if you have the `err' function. */ |
| @@ -37,2 +58,20 @@ |
| |
| +/* Define to 1 if you have the `euidaccess' function. */ |
| +#undef HAVE_EUIDACCESS |
| + |
| +/* Define to 1 if you have the `faccessat' function. */ |
| +#undef HAVE_FACCESSAT |
| + |
| +/* Define to 1 if you have the `fchdir' function. */ |
| +#undef HAVE_FCHDIR |
| + |
| +/* Define to 1 if you have the `fchmodat' function. */ |
| +#undef HAVE_FCHMODAT |
| + |
| +/* Define to 1 if you have the `fchownat' function. */ |
| +#undef HAVE_FCHOWNAT |
| + |
| +/* Define to 1 if you have the `fcntl' function. */ |
| +#undef HAVE_FCNTL |
| + |
| /* Define to 1 if you have the <fcntl.h> header file. */ |
| @@ -40,2 +79,5 @@ |
| |
| +/* Define to 1 if you have the `fdatasync' function. */ |
| +#undef HAVE_FDATASYNC |
| + |
| /* Define to 1 if you have the `fork' function. */ |
| @@ -43,2 +85,14 @@ |
| |
| +/* Define to 1 if you have the `fstatat' function. */ |
| +#undef HAVE_FSTATAT |
| + |
| +/* Define to 1 if you have the `fsync' function. */ |
| +#undef HAVE_FSYNC |
| + |
| +/* Define to 1 if you have the `ftruncate' function. */ |
| +#undef HAVE_FTRUNCATE |
| + |
| +/* Define to 1 if you have the `futimens' function. */ |
| +#undef HAVE_FUTIMENS |
| + |
| /* Define to 1 if you have the `getcwd' function. */ |
| @@ -46,2 +100,8 @@ |
| |
| +/* Define to 1 if you have the `getdomainname' function. */ |
| +#undef HAVE_GETDOMAINNAME |
| + |
| +/* Define to 1 if you have the `getdtablesize' function. */ |
| +#undef HAVE_GETDTABLESIZE |
| + |
| /* Define to 1 if you have the `getenv' function. */ |
| @@ -49,2 +109,17 @@ |
| |
| +/* Define to 1 if you have the `getgroups' function. */ |
| +#undef HAVE_GETGROUPS |
| + |
| +/* Define to 1 if you have the `gethostname' function. */ |
| +#undef HAVE_GETHOSTNAME |
| + |
| +/* Define to 1 if you have the `getloadavg' function. */ |
| +#undef HAVE_GETLOADAVG |
| + |
| +/* Define to 1 if you have the `getlogin' function. */ |
| +#undef HAVE_GETLOGIN |
| + |
| +/* Define to 1 if you have the `getlogin_r' function. */ |
| +#undef HAVE_GETLOGIN_R |
| + |
| /* Define to 1 if you have the `getopt' function. */ |
| @@ -52,2 +127,17 @@ |
| |
| +/* Define to 1 if you have the `getpass' function. */ |
| +#undef HAVE_GETPASS |
| + |
| +/* Define to 1 if you have the `getppid' function. */ |
| +#undef HAVE_GETPPID |
| + |
| +/* Define to 1 if you have the `getrusage' function. */ |
| +#undef HAVE_GETRUSAGE |
| + |
| +/* Define to 1 if you have the `getsubopt' function. */ |
| +#undef HAVE_GETSUBOPT |
| + |
| +/* Define to 1 if you have the `getusershell' function. */ |
| +#undef HAVE_GETUSERSHELL |
| + |
| /* Define to 1 if you have the `getwd' function. */ |
| @@ -55,2 +145,14 @@ |
| |
| +/* Define to 1 if you have the `grantpt' function. */ |
| +#undef HAVE_GRANTPT |
| + |
| +/* Define to 1 if you have the `group_member' function. */ |
| +#undef HAVE_GROUP_MEMBER |
| + |
| +/* Define to 1 if you have the `initstate' function. */ |
| +#undef HAVE_INITSTATE |
| + |
| +/* Define to 1 if you have the `initstate_r' function. */ |
| +#undef HAVE_INITSTATE_R |
| + |
| /* Define to 1 if you have the <inttypes.h> header file. */ |
| @@ -58,2 +160,5 @@ |
| |
| +/* Define to 1 if you have the `kill' function. */ |
| +#undef HAVE_KILL |
| + |
| /* Define to 1 if you have the `killpg' function. */ |
| @@ -61,2 +166,8 @@ |
| |
| +/* Define to 1 if you have the `lchmod' function. */ |
| +#undef HAVE_LCHMOD |
| + |
| +/* Define to 1 if you have the `lchown' function. */ |
| +#undef HAVE_LCHOWN |
| + |
| /* Define to 1 if you have the <libgen.h> header file. */ |
| @@ -67,2 +178,11 @@ |
| |
| +/* Define to 1 if you have the `link' function. */ |
| +#undef HAVE_LINK |
| + |
| +/* Define to 1 if you have the `linkat' function. */ |
| +#undef HAVE_LINKAT |
| + |
| +/* Define to 1 if you have the `lstat' function. */ |
| +#undef HAVE_LSTAT |
| + |
| /* Define to 1 if you have the <memory.h> header file. */ |
| @@ -70,2 +190,32 @@ |
| |
| +/* Define to 1 if you have the `mkdirat' function. */ |
| +#undef HAVE_MKDIRAT |
| + |
| +/* Define to 1 if you have the `mkdtemp' function. */ |
| +#undef HAVE_MKDTEMP |
| + |
| +/* Define to 1 if you have the `mkfifo' function. */ |
| +#undef HAVE_MKFIFO |
| + |
| +/* Define to 1 if you have the `mkfifoat' function. */ |
| +#undef HAVE_MKFIFOAT |
| + |
| +/* Define to 1 if you have the `mknod' function. */ |
| +#undef HAVE_MKNOD |
| + |
| +/* Define to 1 if you have the `mknodat' function. */ |
| +#undef HAVE_MKNODAT |
| + |
| +/* Define to 1 if you have the `mkostemp' function. */ |
| +#undef HAVE_MKOSTEMP |
| + |
| +/* Define to 1 if you have the `mkostemps' function. */ |
| +#undef HAVE_MKOSTEMPS |
| + |
| +/* Define to 1 if you have the `mkstemp' function. */ |
| +#undef HAVE_MKSTEMP |
| + |
| +/* Define to 1 if you have the `mkstemps' function. */ |
| +#undef HAVE_MKSTEMPS |
| + |
| /* Define to 1 if you have the `mmap' function. */ |
| @@ -76,2 +226,5 @@ |
| |
| +/* Define to 1 if you have the `openat' function. */ |
| +#undef HAVE_OPENAT |
| + |
| /* Define to 1 if you have the <paths.h> header file. */ |
| @@ -79,2 +232,11 @@ |
| |
| +/* Define to 1 if you have the `pipe' function. */ |
| +#undef HAVE_PIPE |
| + |
| +/* Define to 1 if you have the `pipe2' function. */ |
| +#undef HAVE_PIPE2 |
| + |
| +/* Define to 1 if you have the `poll' function. */ |
| +#undef HAVE_POLL |
| + |
| /* Define to 1 if you have the <poll.h> header file. */ |
| @@ -82,2 +244,17 @@ |
| |
| +/* Define to 1 if you have the `posix_openpt' function. */ |
| +#undef HAVE_POSIX_OPENPT |
| + |
| +/* Define to 1 if you have the `pread' function. */ |
| +#undef HAVE_PREAD |
| + |
| +/* Define to 1 if you have the `pthread_sigmask' function. */ |
| +#undef HAVE_PTHREAD_SIGMASK |
| + |
| +/* Define to 1 if you have the `ptsname' function. */ |
| +#undef HAVE_PTSNAME |
| + |
| +/* Define to 1 if you have the `ptsname_r' function. */ |
| +#undef HAVE_PTSNAME_R |
| + |
| /* Define to 1 if you have the `putenv' function. */ |
| @@ -85,2 +262,17 @@ |
| |
| +/* Define to 1 if you have the `pwrite' function. */ |
| +#undef HAVE_PWRITE |
| + |
| +/* Define to 1 if you have the `qsort_r' function. */ |
| +#undef HAVE_QSORT_R |
| + |
| +/* Define to 1 if you have the `raise' function. */ |
| +#undef HAVE_RAISE |
| + |
| +/* Define to 1 if you have the `random' function. */ |
| +#undef HAVE_RANDOM |
| + |
| +/* Define to 1 if you have the `random_r' function. */ |
| +#undef HAVE_RANDOM_R |
| + |
| /* Define to 1 if you have the <ranlib.h> header file. */ |
| @@ -88,2 +280,11 @@ |
| |
| +/* Define to 1 if you have the `readlink' function. */ |
| +#undef HAVE_READLINK |
| + |
| +/* Define to 1 if you have the `readlinkat' function. */ |
| +#undef HAVE_READLINKAT |
| + |
| +/* Define to 1 if you have the `reallocarray' function. */ |
| +#undef HAVE_REALLOCARRAY |
| + |
| /* Define to 1 if you have the `realpath' function. */ |
| @@ -91,2 +292,20 @@ |
| |
| +/* Define to 1 if you have the `regcomp' function. */ |
| +#undef HAVE_REGCOMP |
| + |
| +/* Define to 1 if you have the `regerror' function. */ |
| +#undef HAVE_REGERROR |
| + |
| +/* Define to 1 if you have the `regexec' function. */ |
| +#undef HAVE_REGEXEC |
| + |
| +/* Define to 1 if you have the `regfree' function. */ |
| +#undef HAVE_REGFREE |
| + |
| +/* Define to 1 if you have the `rpmatch' function. */ |
| +#undef HAVE_RPMATCH |
| + |
| +/* Define to 1 if you have the `secure_getenv' function. */ |
| +#undef HAVE_SECURE_GETENV |
| + |
| /* Define to 1 if you have the `select' function. */ |
| @@ -97,2 +316,5 @@ |
| |
| +/* Define to 1 if you have the `sethostname' function. */ |
| +#undef HAVE_SETHOSTNAME |
| + |
| /* Define to 1 if you have the `setpgid' function. */ |
| @@ -100,2 +322,5 @@ |
| |
| +/* Define to 1 if you have the `setpgrp' function. */ |
| +#undef HAVE_SETPGRP |
| + |
| /* Define to 1 if you have the `setsid' function. */ |
| @@ -103,2 +328,11 @@ |
| |
| +/* Define to 1 if you have the `setstate' function. */ |
| +#undef HAVE_SETSTATE |
| + |
| +/* Define to 1 if you have the `setstate_r' function. */ |
| +#undef HAVE_SETSTATE_R |
| + |
| +/* Define to 1 if you have the `setusershell' function. */ |
| +#undef HAVE_SETUSERSHELL |
| + |
| /* Define to 1 if you have the `sigaction' function. */ |
| @@ -106,2 +340,26 @@ |
| |
| +/* Define to 1 if you have the `sigaddset' function. */ |
| +#undef HAVE_SIGADDSET |
| + |
| +/* Define to 1 if you have the `sigdelset' function. */ |
| +#undef HAVE_SIGDELSET |
| + |
| +/* Define to 1 if you have the `sigemptyset' function. */ |
| +#undef HAVE_SIGEMPTYSET |
| + |
| +/* Define to 1 if you have the `sigfillset' function. */ |
| +#undef HAVE_SIGFILLSET |
| + |
| +/* Define to 1 if you have the `sigismember' function. */ |
| +#undef HAVE_SIGISMEMBER |
| + |
| +/* Define to 1 if you have the `signal' function. */ |
| +#undef HAVE_SIGNAL |
| + |
| +/* Define to 1 if you have the `sigpending' function. */ |
| +#undef HAVE_SIGPENDING |
| + |
| +/* Define to 1 if you have the `sigprocmask' function. */ |
| +#undef HAVE_SIGPROCMASK |
| + |
| /* Define to 1 if you have the `sigvec' function. */ |
| @@ -109,2 +367,5 @@ |
| |
| +/* Define to 1 if you have the `sleep' function. */ |
| +#undef HAVE_SLEEP |
| + |
| /* Define to 1 if you have the `snprintf' function. */ |
| @@ -112,2 +373,8 @@ |
| |
| +/* Define to 1 if you have the `srandom' function. */ |
| +#undef HAVE_SRANDOM |
| + |
| +/* Define to 1 if you have the `srandom_r' function. */ |
| +#undef HAVE_SRANDOM_R |
| + |
| /* Define to 1 if you have the <stdint.h> header file. */ |
| @@ -145,3 +412,9 @@ |
| |
| -/* Define to 1 if `struct stat' is a member of `st_rdev'. */ |
| +/* Define to 1 if you have the `strtoll' function. */ |
| +#undef HAVE_STRTOLL |
| + |
| +/* Define to 1 if you have the `strtoull' function. */ |
| +#undef HAVE_STRTOULL |
| + |
| +/* Define to 1 if `st_rdev' is a member of `struct stat'. */ |
| #undef HAVE_STRUCT_STAT_ST_RDEV |
| @@ -152,2 +425,8 @@ |
| |
| +/* Define to 1 if you have the `symlink' function. */ |
| +#undef HAVE_SYMLINK |
| + |
| +/* Define to 1 if you have the `symlinkat' function. */ |
| +#undef HAVE_SYMLINKAT |
| + |
| /* Define to 1 if you have the `sysctl' function. */ |
| @@ -169,2 +448,5 @@ |
| |
| +/* Define to 1 if you have the <sys/resource.h> header file. */ |
| +#undef HAVE_SYS_RESOURCE_H |
| + |
| /* Define to 1 if you have the <sys/select.h> header file. */ |
| @@ -190,5 +472,17 @@ |
| |
| -/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ |
| +/* Define to 1 if you have the <sys/utsname.h> header file. */ |
| +#undef HAVE_SYS_UTSNAME_H |
| + |
| +/* Define to 1 if you have the <sys/wait.h> header file. */ |
| #undef HAVE_SYS_WAIT_H |
| |
| +/* Define to 1 if you have the `truncate' function. */ |
| +#undef HAVE_TRUNCATE |
| + |
| +/* Define to 1 if you have the `ttyname_r' function. */ |
| +#undef HAVE_TTYNAME_R |
| + |
| +/* Define to 1 if you have the `uname' function. */ |
| +#undef HAVE_UNAME |
| + |
| /* Define to 1 if you have the <unistd.h> header file. */ |
| @@ -196,2 +490,8 @@ |
| |
| +/* Define to 1 if you have the `unlinkat' function. */ |
| +#undef HAVE_UNLINKAT |
| + |
| +/* Define to 1 if you have the `unlockpt' function. */ |
| +#undef HAVE_UNLOCKPT |
| + |
| /* Define to 1 if you have the `unsetenv' function. */ |
| @@ -199,2 +499,8 @@ |
| |
| +/* Define to 1 if you have the `usleep' function. */ |
| +#undef HAVE_USLEEP |
| + |
| +/* Define to 1 if you have the `utimensat' function. */ |
| +#undef HAVE_UTIMENSAT |
| + |
| /* Define to 1 if you have the <utime.h> header file. */ |
| @@ -214,2 +520,5 @@ |
| |
| +/* Define to 1 if you have the `wait' function. */ |
| +#undef HAVE_WAIT |
| + |
| /* Define to 1 if you have the `wait3' function. */ |
| @@ -235,2 +544,5 @@ |
| |
| +/* Define to 1 if you have the `_Exit' function. */ |
| +#undef HAVE__EXIT |
| + |
| /* define if your compiler has __attribute__ */ |
| @@ -326,2 +638,6 @@ |
| |
| +/* Define to the type of a signed integer type of width exactly 32 bits if |
| + such a type exists and the standard includes do not define it. */ |
| +#undef int32_t |
| + |
| /* Define to `int' if <sys/types.h> does not define. */ |
| diff --git a/configure b/configure |
| index 1ce8dfe..42ac2d4 100755 |
| --- a/configure |
| +++ b/configure |
| @@ -2,3 +2,3 @@ |
| # Guess values for system-dependent variables and create Makefiles. |
| -# Generated by GNU Autoconf 2.64 for bmake 20171126. |
| +# Generated by GNU Autoconf 2.69 for bmake 20171126. |
| # |
| @@ -6,5 +6,5 @@ |
| # |
| -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, |
| -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software |
| -# Foundation, Inc. |
| +# |
| +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. |
| +# |
| # |
| @@ -91,2 +91,3 @@ IFS=" "" $as_nl" |
| # Find who we are. Look in the path if we contain no directory separator. |
| +as_myself= |
| case $0 in #(( |
| @@ -135,2 +136,27 @@ export LANGUAGE |
| |
| +# Use a proper internal environment variable to ensure we don't fall |
| + # into an infinite loop, continuously re-executing ourselves. |
| + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then |
| + _as_can_reexec=no; export _as_can_reexec; |
| + # We cannot yet assume a decent shell, so we have to provide a |
| +# neutralization value for shells without unset; and this also |
| +# works around shells that cannot unset nonexistent variables. |
| +# Preserve -v and -x to the replacement shell. |
| +BASH_ENV=/dev/null |
| +ENV=/dev/null |
| +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV |
| +case $- in # (((( |
| + *v*x* | *x*v* ) as_opts=-vx ;; |
| + *v* ) as_opts=-v ;; |
| + *x* ) as_opts=-x ;; |
| + * ) as_opts= ;; |
| +esac |
| +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} |
| +# Admittedly, this is quite paranoid, since all the known shells bail |
| +# out after a failed `exec'. |
| +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 |
| +as_fn_exit 255 |
| + fi |
| + # We don't want this to propagate to other subprocesses. |
| + { _as_can_reexec=; unset _as_can_reexec;} |
| if test "x$CONFIG_SHELL" = x; then |
| @@ -168,3 +194,4 @@ else |
| fi |
| -test x\$exitcode = x0 || exit 1" |
| +test x\$exitcode = x0 || exit 1 |
| +test -x / || exit 1" |
| as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO |
| @@ -213,10 +240,21 @@ IFS=$as_save_IFS |
| if test "x$CONFIG_SHELL" != x; then : |
| - # We cannot yet assume a decent shell, so we have to provide a |
| - # neutralization value for shells without unset; and this also |
| - # works around shells that cannot unset nonexistent variables. |
| - BASH_ENV=/dev/null |
| - ENV=/dev/null |
| - (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV |
| - export CONFIG_SHELL |
| - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} |
| + export CONFIG_SHELL |
| + # We cannot yet assume a decent shell, so we have to provide a |
| +# neutralization value for shells without unset; and this also |
| +# works around shells that cannot unset nonexistent variables. |
| +# Preserve -v and -x to the replacement shell. |
| +BASH_ENV=/dev/null |
| +ENV=/dev/null |
| +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV |
| +case $- in # (((( |
| + *v*x* | *x*v* ) as_opts=-vx ;; |
| + *v* ) as_opts=-v ;; |
| + *x* ) as_opts=-x ;; |
| + * ) as_opts= ;; |
| +esac |
| +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} |
| +# Admittedly, this is quite paranoid, since all the known shells bail |
| +# out after a failed `exec'. |
| +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 |
| +exit 255 |
| fi |
| @@ -319,3 +357,3 @@ $as_echo X"$as_dir" | |
| test -z "$as_dirs" || eval "mkdir $as_dirs" |
| - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" |
| + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" |
| |
| @@ -323,2 +361,10 @@ $as_echo X"$as_dir" | |
| } # as_fn_mkdir_p |
| + |
| +# as_fn_executable_p FILE |
| +# ----------------------- |
| +# Test if FILE is an executable regular file. |
| +as_fn_executable_p () |
| +{ |
| + test -f "$1" && test -x "$1" |
| +} # as_fn_executable_p |
| # as_fn_append VAR VALUE |
| @@ -359,15 +405,15 @@ fi # as_fn_arith |
| |
| -# as_fn_error ERROR [LINENO LOG_FD] |
| -# --------------------------------- |
| +# as_fn_error STATUS ERROR [LINENO LOG_FD] |
| +# ---------------------------------------- |
| # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are |
| # provided, also output the error to LOG_FD, referencing LINENO. Then exit the |
| -# script with status $?, using 1 if that was 0. |
| +# script with STATUS, using 1 if that was 0. |
| as_fn_error () |
| { |
| - as_status=$?; test $as_status -eq 0 && as_status=1 |
| - if test "$3"; then |
| - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack |
| - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 |
| + as_status=$1; test $as_status -eq 0 && as_status=1 |
| + if test "$4"; then |
| + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack |
| + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 |
| fi |
| - $as_echo "$as_me: error: $1" >&2 |
| + $as_echo "$as_me: error: $2" >&2 |
| as_fn_exit $as_status |
| @@ -444,2 +490,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits |
| |
| + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have |
| + # already done that, so ensure we don't try to do so again and fall |
| + # in an infinite loop. This has already happened in practice. |
| + _as_can_reexec=no; export _as_can_reexec |
| # Don't try to exec as it changes $[0], causing all sort of problems |
| @@ -478,5 +528,5 @@ if (echo >conf$$.file) 2>/dev/null; then |
| # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. |
| - # In both cases, we have to default to `cp -p'. |
| + # In both cases, we have to default to `cp -pR'. |
| ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || |
| - as_ln_s='cp -p' |
| + as_ln_s='cp -pR' |
| elif ln conf$$.file conf$$ 2>/dev/null; then |
| @@ -484,6 +534,6 @@ if (echo >conf$$.file) 2>/dev/null; then |
| else |
| - as_ln_s='cp -p' |
| + as_ln_s='cp -pR' |
| fi |
| else |
| - as_ln_s='cp -p' |
| + as_ln_s='cp -pR' |
| fi |
| @@ -499,24 +549,4 @@ fi |
| |
| -if test -x / >/dev/null 2>&1; then |
| - as_test_x='test -x' |
| -else |
| - if ls -dL / >/dev/null 2>&1; then |
| - as_ls_L_option=L |
| - else |
| - as_ls_L_option= |
| - fi |
| - as_test_x=' |
| - eval sh -c '\'' |
| - if test -d "$1"; then |
| - test -d "$1/."; |
| - else |
| - case $1 in #( |
| - -*)set "./$1";; |
| - esac; |
| - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( |
| - ???[sx]*):;;*)false;;esac;fi |
| - '\'' sh |
| - ' |
| -fi |
| -as_executable_p=$as_test_x |
| +as_test_x='test -x' |
| +as_executable_p=as_fn_executable_p |
| |
| @@ -529,6 +559,7 @@ as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" |
| |
| -exec 7<&0 </dev/null 6>&1 |
| +test -n "$DJDIR" || exec 7<&0 </dev/null |
| +exec 6>&1 |
| |
| # Name of the host. |
| -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, |
| +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, |
| # so uname gets run too. |
| @@ -745,4 +776,5 @@ do |
| case $ac_option in |
| - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; |
| - *) ac_optarg=yes ;; |
| + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; |
| + *=) ac_optarg= ;; |
| + *) ac_optarg=yes ;; |
| esac |
| @@ -791,3 +823,3 @@ do |
| expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && |
| - as_fn_error "invalid feature name: $ac_useropt" |
| + as_fn_error $? "invalid feature name: $ac_useropt" |
| ac_useropt_orig=$ac_useropt |
| @@ -817,3 +849,3 @@ do |
| expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && |
| - as_fn_error "invalid feature name: $ac_useropt" |
| + as_fn_error $? "invalid feature name: $ac_useropt" |
| ac_useropt_orig=$ac_useropt |
| @@ -1021,3 +1053,3 @@ do |
| expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && |
| - as_fn_error "invalid package name: $ac_useropt" |
| + as_fn_error $? "invalid package name: $ac_useropt" |
| ac_useropt_orig=$ac_useropt |
| @@ -1037,3 +1069,3 @@ do |
| expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && |
| - as_fn_error "invalid package name: $ac_useropt" |
| + as_fn_error $? "invalid package name: $ac_useropt" |
| ac_useropt_orig=$ac_useropt |
| @@ -1067,4 +1099,4 @@ do |
| |
| - -*) as_fn_error "unrecognized option: \`$ac_option' |
| -Try \`$0 --help' for more information." |
| + -*) as_fn_error $? "unrecognized option: \`$ac_option' |
| +Try \`$0 --help' for more information" |
| ;; |
| @@ -1076,3 +1108,3 @@ Try \`$0 --help' for more information." |
| '' | [0-9]* | *[!_$as_cr_alnum]* ) |
| - as_fn_error "invalid variable name: \`$ac_envvar'" ;; |
| + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; |
| esac |
| @@ -1086,3 +1118,3 @@ Try \`$0 --help' for more information." |
| $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 |
| - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} |
| + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" |
| ;; |
| @@ -1094,3 +1126,3 @@ if test -n "$ac_prev"; then |
| ac_option=--`echo $ac_prev | sed 's/_/-/g'` |
| - as_fn_error "missing argument to $ac_option" |
| + as_fn_error $? "missing argument to $ac_option" |
| fi |
| @@ -1100,3 +1132,3 @@ if test -n "$ac_unrecognized_opts"; then |
| no) ;; |
| - fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; |
| + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; |
| *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; |
| @@ -1123,3 +1155,3 @@ do |
| esac |
| - as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" |
| + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" |
| done |
| @@ -1137,4 +1169,2 @@ if test "x$host_alias" != x; then |
| cross_compiling=maybe |
| - $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. |
| - If a cross compiler is detected then cross compile mode will be used." >&2 |
| elif test "x$build_alias" != "x$host_alias"; then |
| @@ -1153,5 +1183,5 @@ ac_ls_di=`ls -di .` && |
| ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || |
| - as_fn_error "working directory cannot be determined" |
| + as_fn_error $? "working directory cannot be determined" |
| test "X$ac_ls_di" = "X$ac_pwd_ls_di" || |
| - as_fn_error "pwd does not report name of working directory" |
| + as_fn_error $? "pwd does not report name of working directory" |
| |
| @@ -1194,3 +1224,3 @@ if test ! -r "$srcdir/$ac_unique_file"; then |
| test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." |
| - as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" |
| + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" |
| fi |
| @@ -1198,3 +1228,3 @@ ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" |
| ac_abs_confdir=`( |
| - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" |
| + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" |
| pwd)` |
| @@ -1238,3 +1268,3 @@ Configuration: |
| -V, --version display version information and exit |
| - -q, --quiet, --silent do not print \`checking...' messages |
| + -q, --quiet, --silent do not print \`checking ...' messages |
| --cache-file=FILE cache test results in FILE [disabled] |
| @@ -1320,3 +1350,3 @@ Some influential environment variables: |
| LIBS libraries to pass to the linker, e.g. -l<library> |
| - CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if |
| + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if |
| you have headers in a nonstandard directory <include dir> |
| @@ -1391,5 +1421,5 @@ if $ac_init_version; then |
| bmake configure 20171126 |
| -generated by GNU Autoconf 2.64 |
| +generated by GNU Autoconf 2.69 |
| |
| -Copyright (C) 2009 Free Software Foundation, Inc. |
| +Copyright (C) 2012 Free Software Foundation, Inc. |
| This configure script is free software; the Free Software Foundation |
| @@ -1437,4 +1467,4 @@ sed 's/^/| /' conftest.$ac_ext >&5 |
| fi |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| - return $ac_retval |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| + as_fn_set_status $ac_retval |
| |
| @@ -1463,3 +1493,3 @@ $as_echo "$ac_try_echo"; } >&5 |
| $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
| - test $ac_status = 0; } >/dev/null && { |
| + test $ac_status = 0; } > conftest.i && { |
| test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || |
| @@ -1474,4 +1504,4 @@ sed 's/^/| /' conftest.$ac_ext >&5 |
| fi |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| - return $ac_retval |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| + as_fn_set_status $ac_retval |
| |
| @@ -1487,6 +1517,6 @@ ac_fn_c_check_header_mongrel () |
| as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack |
| - if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : |
| + if eval \${$3+:} false; then : |
| { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 |
| $as_echo_n "checking for $2... " >&6; } |
| -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : |
| +if eval \${$3+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -1526,3 +1556,3 @@ else |
| fi |
| -rm -f conftest.err conftest.$ac_ext |
| +rm -f conftest.err conftest.i conftest.$ac_ext |
| { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 |
| @@ -1549,7 +1579,5 @@ $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" > |
| $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} |
| -( cat <<\_ASBOX |
| -## ----------------------------- ## |
| +( $as_echo "## ----------------------------- ## |
| ## Report this to sjg@NetBSD.org ## |
| -## ----------------------------- ## |
| -_ASBOX |
| +## ----------------------------- ##" |
| ) | sed "s/^/$as_me: WARNING: /" >&2 |
| @@ -1559,3 +1587,3 @@ esac |
| $as_echo_n "checking for $2... " >&6; } |
| -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : |
| +if eval \${$3+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -1568,3 +1596,3 @@ $as_echo "$ac_res" >&6; } |
| fi |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| |
| @@ -1609,4 +1637,4 @@ fi |
| rm -rf conftest.dSYM conftest_ipa8_conftest.oo |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| - return $ac_retval |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| + as_fn_set_status $ac_retval |
| |
| @@ -1623,3 +1651,3 @@ ac_fn_c_check_header_compile () |
| $as_echo_n "checking for $2... " >&6; } |
| -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : |
| +if eval \${$3+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -1641,3 +1669,3 @@ eval ac_res=\$$3 |
| $as_echo "$ac_res" >&6; } |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| |
| @@ -1672,3 +1700,3 @@ $as_echo "$ac_try_echo"; } >&5 |
| test "$cross_compiling" = yes || |
| - $as_test_x conftest$ac_exeext |
| + test -x conftest$ac_exeext |
| }; then : |
| @@ -1686,4 +1714,4 @@ fi |
| rm -rf conftest.dSYM conftest_ipa8_conftest.oo |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| - return $ac_retval |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| + as_fn_set_status $ac_retval |
| |
| @@ -1691,2 +1719,78 @@ fi |
| |
| +# ac_fn_c_find_intX_t LINENO BITS VAR |
| +# ----------------------------------- |
| +# Finds a signed integer type with width BITS, setting cache variable VAR |
| +# accordingly. |
| +ac_fn_c_find_intX_t () |
| +{ |
| + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack |
| + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 |
| +$as_echo_n "checking for int$2_t... " >&6; } |
| +if eval \${$3+:} false; then : |
| + $as_echo_n "(cached) " >&6 |
| +else |
| + eval "$3=no" |
| + # Order is important - never check a type that is potentially smaller |
| + # than half of the expected target width. |
| + for ac_type in int$2_t 'int' 'long int' \ |
| + 'long long int' 'short int' 'signed char'; do |
| + cat confdefs.h - <<_ACEOF >conftest.$ac_ext |
| +/* end confdefs.h. */ |
| +$ac_includes_default |
| + enum { N = $2 / 2 - 1 }; |
| +int |
| +main () |
| +{ |
| +static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; |
| +test_array [0] = 0; |
| +return test_array [0]; |
| + |
| + ; |
| + return 0; |
| +} |
| +_ACEOF |
| +if ac_fn_c_try_compile "$LINENO"; then : |
| + cat confdefs.h - <<_ACEOF >conftest.$ac_ext |
| +/* end confdefs.h. */ |
| +$ac_includes_default |
| + enum { N = $2 / 2 - 1 }; |
| +int |
| +main () |
| +{ |
| +static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) |
| + < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; |
| +test_array [0] = 0; |
| +return test_array [0]; |
| + |
| + ; |
| + return 0; |
| +} |
| +_ACEOF |
| +if ac_fn_c_try_compile "$LINENO"; then : |
| + |
| +else |
| + case $ac_type in #( |
| + int$2_t) : |
| + eval "$3=yes" ;; #( |
| + *) : |
| + eval "$3=\$ac_type" ;; |
| +esac |
| +fi |
| +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext |
| +fi |
| +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext |
| + if eval test \"x\$"$3"\" = x"no"; then : |
| + |
| +else |
| + break |
| +fi |
| + done |
| +fi |
| +eval ac_res=\$$3 |
| + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 |
| +$as_echo "$ac_res" >&6; } |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| + |
| +} # ac_fn_c_find_intX_t |
| + |
| # ac_fn_c_check_type LINENO TYPE VAR INCLUDES |
| @@ -1700,3 +1804,3 @@ ac_fn_c_check_type () |
| $as_echo_n "checking for $2... " >&6; } |
| -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : |
| +if eval \${$3+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -1741,3 +1845,3 @@ eval ac_res=\$$3 |
| $as_echo "$ac_res" >&6; } |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| |
| @@ -1754,3 +1858,3 @@ ac_fn_c_find_uintX_t () |
| $as_echo_n "checking for uint$2_t... " >&6; } |
| -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : |
| +if eval \${$3+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -1758,2 +1862,4 @@ else |
| eval "$3=no" |
| + # Order is important - never check a type that is potentially smaller |
| + # than half of the expected target width. |
| for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ |
| @@ -1766,4 +1872,5 @@ main () |
| { |
| -static int test_array [1 - 2 * !(($ac_type) -1 >> ($2 - 1) == 1)]; |
| -test_array [0] = 0 |
| +static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; |
| +test_array [0] = 0; |
| +return test_array [0]; |
| |
| @@ -1782,4 +1889,3 @@ fi |
| rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext |
| - eval as_val=\$$3 |
| - if test "x$as_val" = x""no; then : |
| + if eval test \"x\$"$3"\" = x"no"; then : |
| |
| @@ -1793,3 +1899,3 @@ eval ac_res=\$$3 |
| $as_echo "$ac_res" >&6; } |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| |
| @@ -1797,5 +1903,6 @@ $as_echo "$ac_res" >&6; } |
| |
| -# ac_fn_c_check_decl LINENO SYMBOL VAR |
| -# ------------------------------------ |
| -# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. |
| +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES |
| +# --------------------------------------------- |
| +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR |
| +# accordingly. |
| ac_fn_c_check_decl () |
| @@ -1803,5 +1910,7 @@ ac_fn_c_check_decl () |
| as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack |
| - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5 |
| -$as_echo_n "checking whether $2 is declared... " >&6; } |
| -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : |
| + as_decl_name=`echo $2|sed 's/ *(.*//'` |
| + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` |
| + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 |
| +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } |
| +if eval \${$3+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -1814,4 +1923,8 @@ main () |
| { |
| -#ifndef $2 |
| - (void) $2; |
| +#ifndef $as_decl_name |
| +#ifdef __cplusplus |
| + (void) $as_decl_use; |
| +#else |
| + (void) $as_decl_name; |
| +#endif |
| #endif |
| @@ -1832,3 +1945,3 @@ eval ac_res=\$$3 |
| $as_echo "$ac_res" >&6; } |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| |
| @@ -1844,3 +1957,3 @@ ac_fn_c_check_func () |
| $as_echo_n "checking for $2... " >&6; } |
| -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : |
| +if eval \${$3+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -1899,3 +2012,3 @@ eval ac_res=\$$3 |
| $as_echo "$ac_res" >&6; } |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| |
| @@ -1912,3 +2025,3 @@ ac_fn_c_check_member () |
| $as_echo_n "checking for $2.$3... " >&6; } |
| -if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then : |
| +if eval \${$4+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -1956,3 +2069,3 @@ eval ac_res=\$$4 |
| $as_echo "$ac_res" >&6; } |
| - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} |
| + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno |
| |
| @@ -1964,3 +2077,3 @@ running configure, to aid debugging if configure makes a mistake. |
| It was created by bmake $as_me 20171126, which was |
| -generated by GNU Autoconf 2.64. Invocation command line was |
| +generated by GNU Autoconf 2.69. Invocation command line was |
| |
| @@ -2074,7 +2187,5 @@ trap 'exit_status=$? |
| |
| - cat <<\_ASBOX |
| -## ---------------- ## |
| + $as_echo "## ---------------- ## |
| ## Cache variables. ## |
| -## ---------------- ## |
| -_ASBOX |
| +## ---------------- ##" |
| echo |
| @@ -2112,7 +2223,5 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; |
| |
| - cat <<\_ASBOX |
| -## ----------------- ## |
| + $as_echo "## ----------------- ## |
| ## Output variables. ## |
| -## ----------------- ## |
| -_ASBOX |
| +## ----------------- ##" |
| echo |
| @@ -2129,7 +2238,5 @@ _ASBOX |
| if test -n "$ac_subst_files"; then |
| - cat <<\_ASBOX |
| -## ------------------- ## |
| + $as_echo "## ------------------- ## |
| ## File substitutions. ## |
| -## ------------------- ## |
| -_ASBOX |
| +## ------------------- ##" |
| echo |
| @@ -2147,7 +2254,5 @@ _ASBOX |
| if test -s confdefs.h; then |
| - cat <<\_ASBOX |
| -## ----------- ## |
| + $as_echo "## ----------- ## |
| ## confdefs.h. ## |
| -## ----------- ## |
| -_ASBOX |
| +## ----------- ##" |
| echo |
| @@ -2206,3 +2311,8 @@ ac_site_file2=NONE |
| if test -n "$CONFIG_SITE"; then |
| - ac_site_file1=$CONFIG_SITE |
| + # We do not want a PATH search for config.site. |
| + case $CONFIG_SITE in #(( |
| + -*) ac_site_file1=./$CONFIG_SITE;; |
| + */*) ac_site_file1=$CONFIG_SITE;; |
| + *) ac_site_file1=./$CONFIG_SITE;; |
| + esac |
| elif test "x$prefix" != xNONE; then |
| @@ -2217,3 +2327,3 @@ do |
| test "x$ac_site_file" = xNONE && continue |
| - if test -r "$ac_site_file"; then |
| + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then |
| { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 |
| @@ -2221,3 +2331,7 @@ $as_echo "$as_me: loading site script $ac_site_file" >&6;} |
| sed 's/^/| /' "$ac_site_file" >&5 |
| - . "$ac_site_file" |
| + . "$ac_site_file" \ |
| + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 |
| +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| +as_fn_error $? "failed to load site script $ac_site_file |
| +See \`config.log' for more details" "$LINENO" 5; } |
| fi |
| @@ -2226,5 +2340,5 @@ done |
| if test -r "$cache_file"; then |
| - # Some versions of bash will fail to source /dev/null (special |
| - # files actually), so we avoid doing that. |
| - if test -f "$cache_file"; then |
| + # Some versions of bash will fail to source /dev/null (special files |
| + # actually), so we avoid doing that. DJGPP emulates it as a regular file. |
| + if test /dev/null != "$cache_file" && test -f "$cache_file"; then |
| { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 |
| @@ -2297,3 +2411,3 @@ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} |
| - as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 |
| + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 |
| fi |
| @@ -2324,3 +2438,3 @@ if test "${with_defshell+set}" = set; then : |
| withval=$with_defshell; case "${withval}" in |
| -yes) as_fn_error "bad value ${withval} given for bmake DEFSHELL" "$LINENO" 5 ;; |
| +yes) as_fn_error $? "bad value ${withval} given for bmake DEFSHELL" "$LINENO" 5 ;; |
| no) ;; |
| @@ -2342,3 +2456,3 @@ if test "${with_meta+set}" = set; then : |
| yes|no) use_meta=${withval};; |
| -*) as_fn_error "bad value ${withval} given for meta" "$LINENO" 5 ;; |
| +*) as_fn_error $? "bad value ${withval} given for meta" "$LINENO" 5 ;; |
| esac |
| @@ -2352,3 +2466,3 @@ if test "${with_filemon+set}" = set; then : |
| */filemon*) filemon_h="${withval}/filemon.h";; |
| -*) as_fn_error "bad value ${withval} given for filemon" "$LINENO" 5 ;; |
| +*) as_fn_error $? "bad value ${withval} given for filemon" "$LINENO" 5 ;; |
| esac |
| @@ -2356,3 +2470,3 @@ else |
| |
| -OS=`uname -s` |
| +OS=`uname -s | cut -d_ -f1` |
| for d in "/usr/include/dev/filemon" "$prefix/include/dev/filemon" "$srcdir/filemon" "$srcdir/../filemon" "$srcdir/../../sys/dev/filemon" |
| @@ -2387,3 +2501,3 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_CC+set}" = set; then : |
| +if ${ac_cv_prog_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -2399,3 +2513,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_CC="${ac_tool_prefix}gcc" |
| @@ -2427,3 +2541,3 @@ set dummy gcc; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : |
| +if ${ac_cv_prog_ac_ct_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -2439,3 +2553,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_ac_ct_CC="gcc" |
| @@ -2480,3 +2594,3 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_CC+set}" = set; then : |
| +if ${ac_cv_prog_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -2492,3 +2606,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_CC="${ac_tool_prefix}cc" |
| @@ -2520,3 +2634,3 @@ set dummy cc; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_CC+set}" = set; then : |
| +if ${ac_cv_prog_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -2533,3 +2647,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then |
| @@ -2579,3 +2693,3 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_CC+set}" = set; then : |
| +if ${ac_cv_prog_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -2591,3 +2705,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_CC="$ac_tool_prefix$ac_prog" |
| @@ -2623,3 +2737,3 @@ set dummy $ac_prog; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : |
| +if ${ac_cv_prog_ac_ct_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -2635,3 +2749,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_ac_ct_CC="$ac_prog" |
| @@ -2677,4 +2791,4 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd' |
| $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| -as_fn_error "no acceptable C compiler found in \$PATH |
| -See \`config.log' for more details." "$LINENO" 5; } |
| +as_fn_error $? "no acceptable C compiler found in \$PATH |
| +See \`config.log' for more details" "$LINENO" 5; } |
| |
| @@ -2699,4 +2813,4 @@ $as_echo "$ac_try_echo"; } >&5 |
| cat conftest.er1 >&5 |
| - rm -f conftest.er1 conftest.err |
| fi |
| + rm -f conftest.er1 conftest.err |
| $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
| @@ -2707,3 +2821,3 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext |
| /* end confdefs.h. */ |
| -#include <stdio.h> |
| + |
| int |
| @@ -2711,4 +2825,2 @@ main () |
| { |
| -FILE *f = fopen ("conftest.out", "w"); |
| - return ferror (f) || fclose (f) != 0; |
| |
| @@ -2719,3 +2831,3 @@ _ACEOF |
| ac_clean_files_save=$ac_clean_files |
| -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" |
| +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" |
| # Try to create an executable without -o first, disregard a.out. |
| @@ -2723,4 +2835,4 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" |
| # of exeext. |
| -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 |
| -$as_echo_n "checking for C compiler default output file name... " >&6; } |
| +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 |
| +$as_echo_n "checking whether the C compiler works... " >&6; } |
| ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` |
| @@ -2786,6 +2898,6 @@ else |
| fi |
| -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 |
| -$as_echo "$ac_file" >&6; } |
| if test -z "$ac_file"; then : |
| - $as_echo "$as_me: failed program was:" >&5 |
| + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 |
| +$as_echo "no" >&6; } |
| +$as_echo "$as_me: failed program was:" >&5 |
| sed 's/^/| /' conftest.$ac_ext >&5 |
| @@ -2794,50 +2906,16 @@ sed 's/^/| /' conftest.$ac_ext >&5 |
| $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| -{ as_fn_set_status 77 |
| -as_fn_error "C compiler cannot create executables |
| -See \`config.log' for more details." "$LINENO" 5; }; } |
| +as_fn_error 77 "C compiler cannot create executables |
| +See \`config.log' for more details" "$LINENO" 5; } |
| +else |
| + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 |
| +$as_echo "yes" >&6; } |
| fi |
| +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 |
| +$as_echo_n "checking for C compiler default output file name... " >&6; } |
| +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 |
| +$as_echo "$ac_file" >&6; } |
| ac_exeext=$ac_cv_exeext |
| |
| -# Check that the compiler produces executables we can run. If not, either |
| -# the compiler is broken, or we cross compile. |
| -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 |
| -$as_echo_n "checking whether the C compiler works... " >&6; } |
| -# If not cross compiling, check that we can run a simple program. |
| -if test "$cross_compiling" != yes; then |
| - if { ac_try='./$ac_file' |
| - { { case "(($ac_try" in |
| - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; |
| - *) ac_try_echo=$ac_try;; |
| -esac |
| -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" |
| -$as_echo "$ac_try_echo"; } >&5 |
| - (eval "$ac_try") 2>&5 |
| - ac_status=$? |
| - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
| - test $ac_status = 0; }; }; then |
| - cross_compiling=no |
| - else |
| - if test "$cross_compiling" = maybe; then |
| - cross_compiling=yes |
| - else |
| - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 |
| -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| -as_fn_error "cannot run C compiled programs. |
| -If you meant to cross compile, use \`--host'. |
| -See \`config.log' for more details." "$LINENO" 5; } |
| - fi |
| - fi |
| -fi |
| -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 |
| -$as_echo "yes" >&6; } |
| - |
| -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out |
| +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out |
| ac_clean_files=$ac_clean_files_save |
| -# Check that the compiler produces executables we can run. If not, either |
| -# the compiler is broken, or we cross compile. |
| -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 |
| -$as_echo_n "checking whether we are cross compiling... " >&6; } |
| -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 |
| -$as_echo "$cross_compiling" >&6; } |
| - |
| { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 |
| @@ -2871,6 +2949,6 @@ else |
| $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| -as_fn_error "cannot compute suffix of executables: cannot compile and link |
| -See \`config.log' for more details." "$LINENO" 5; } |
| +as_fn_error $? "cannot compute suffix of executables: cannot compile and link |
| +See \`config.log' for more details" "$LINENO" 5; } |
| fi |
| -rm -f conftest$ac_cv_exeext |
| +rm -f conftest conftest$ac_cv_exeext |
| { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 |
| @@ -2881,5 +2959,64 @@ EXEEXT=$ac_cv_exeext |
| ac_exeext=$EXEEXT |
| +cat confdefs.h - <<_ACEOF >conftest.$ac_ext |
| +/* end confdefs.h. */ |
| +#include <stdio.h> |
| +int |
| +main () |
| +{ |
| +FILE *f = fopen ("conftest.out", "w"); |
| + return ferror (f) || fclose (f) != 0; |
| + |
| + ; |
| + return 0; |
| +} |
| +_ACEOF |
| +ac_clean_files="$ac_clean_files conftest.out" |
| +# Check that the compiler produces executables we can run. If not, either |
| +# the compiler is broken, or we cross compile. |
| +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 |
| +$as_echo_n "checking whether we are cross compiling... " >&6; } |
| +if test "$cross_compiling" != yes; then |
| + { { ac_try="$ac_link" |
| +case "(($ac_try" in |
| + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; |
| + *) ac_try_echo=$ac_try;; |
| +esac |
| +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" |
| +$as_echo "$ac_try_echo"; } >&5 |
| + (eval "$ac_link") 2>&5 |
| + ac_status=$? |
| + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
| + test $ac_status = 0; } |
| + if { ac_try='./conftest$ac_cv_exeext' |
| + { { case "(($ac_try" in |
| + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; |
| + *) ac_try_echo=$ac_try;; |
| +esac |
| +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" |
| +$as_echo "$ac_try_echo"; } >&5 |
| + (eval "$ac_try") 2>&5 |
| + ac_status=$? |
| + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
| + test $ac_status = 0; }; }; then |
| + cross_compiling=no |
| + else |
| + if test "$cross_compiling" = maybe; then |
| + cross_compiling=yes |
| + else |
| + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 |
| +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| +as_fn_error $? "cannot run C compiled programs. |
| +If you meant to cross compile, use \`--host'. |
| +See \`config.log' for more details" "$LINENO" 5; } |
| + fi |
| + fi |
| +fi |
| +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 |
| +$as_echo "$cross_compiling" >&6; } |
| + |
| +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out |
| +ac_clean_files=$ac_clean_files_save |
| { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 |
| $as_echo_n "checking for suffix of object files... " >&6; } |
| -if test "${ac_cv_objext+set}" = set; then : |
| +if ${ac_cv_objext+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -2923,4 +3060,4 @@ sed 's/^/| /' conftest.$ac_ext >&5 |
| $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| -as_fn_error "cannot compute suffix of object files: cannot compile |
| -See \`config.log' for more details." "$LINENO" 5; } |
| +as_fn_error $? "cannot compute suffix of object files: cannot compile |
| +See \`config.log' for more details" "$LINENO" 5; } |
| fi |
| @@ -2934,3 +3071,3 @@ ac_objext=$OBJEXT |
| $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } |
| -if test "${ac_cv_c_compiler_gnu+set}" = set; then : |
| +if ${ac_cv_c_compiler_gnu+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -2971,3 +3108,3 @@ ac_save_CFLAGS=$CFLAGS |
| $as_echo_n "checking whether $CC accepts -g... " >&6; } |
| -if test "${ac_cv_prog_cc_g+set}" = set; then : |
| +if ${ac_cv_prog_cc_g+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3049,3 +3186,3 @@ fi |
| $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } |
| -if test "${ac_cv_prog_cc_c89+set}" = set; then : |
| +if ${ac_cv_prog_cc_c89+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3058,4 +3195,3 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext |
| #include <stdio.h> |
| -#include <sys/types.h> |
| -#include <sys/stat.h> |
| +struct stat; |
| /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ |
| @@ -3157,3 +3293,3 @@ fi |
| if test -z "$CPP"; then |
| - if test "${ac_cv_prog_CPP+set}" = set; then : |
| + if ${ac_cv_prog_CPP+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3187,3 +3323,3 @@ continue |
| fi |
| -rm -f conftest.err conftest.$ac_ext |
| +rm -f conftest.err conftest.i conftest.$ac_ext |
| |
| @@ -3203,3 +3339,3 @@ break |
| fi |
| -rm -f conftest.err conftest.$ac_ext |
| +rm -f conftest.err conftest.i conftest.$ac_ext |
| |
| @@ -3207,3 +3343,3 @@ done |
| # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. |
| -rm -f conftest.err conftest.$ac_ext |
| +rm -f conftest.i conftest.err conftest.$ac_ext |
| if $ac_preproc_ok; then : |
| @@ -3246,3 +3382,3 @@ continue |
| fi |
| -rm -f conftest.err conftest.$ac_ext |
| +rm -f conftest.err conftest.i conftest.$ac_ext |
| |
| @@ -3262,3 +3398,3 @@ break |
| fi |
| -rm -f conftest.err conftest.$ac_ext |
| +rm -f conftest.err conftest.i conftest.$ac_ext |
| |
| @@ -3266,3 +3402,3 @@ done |
| # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. |
| -rm -f conftest.err conftest.$ac_ext |
| +rm -f conftest.i conftest.err conftest.$ac_ext |
| if $ac_preproc_ok; then : |
| @@ -3272,4 +3408,4 @@ else |
| $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| -as_fn_error "C preprocessor \"$CPP\" fails sanity check |
| -See \`config.log' for more details." "$LINENO" 5; } |
| +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check |
| +See \`config.log' for more details" "$LINENO" 5; } |
| fi |
| @@ -3285,3 +3421,3 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu |
| $as_echo_n "checking for grep that handles long lines and -e... " >&6; } |
| -if test "${ac_cv_path_GREP+set}" = set; then : |
| +if ${ac_cv_path_GREP+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3299,3 +3435,3 @@ do |
| ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" |
| - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue |
| + as_fn_executable_p "$ac_path_GREP" || continue |
| # Check for GNU ac_path_GREP and select it if it is found. |
| @@ -3334,3 +3470,3 @@ IFS=$as_save_IFS |
| if test -z "$ac_cv_path_GREP"; then |
| - as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 |
| + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 |
| fi |
| @@ -3348,3 +3484,3 @@ $as_echo "$ac_cv_path_GREP" >&6; } |
| $as_echo_n "checking for egrep... " >&6; } |
| -if test "${ac_cv_path_EGREP+set}" = set; then : |
| +if ${ac_cv_path_EGREP+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3365,3 +3501,3 @@ do |
| ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" |
| - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue |
| + as_fn_executable_p "$ac_path_EGREP" || continue |
| # Check for GNU ac_path_EGREP and select it if it is found. |
| @@ -3400,3 +3536,3 @@ IFS=$as_save_IFS |
| if test -z "$ac_cv_path_EGREP"; then |
| - as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 |
| + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 |
| fi |
| @@ -3415,3 +3551,3 @@ $as_echo "$ac_cv_path_EGREP" >&6; } |
| $as_echo_n "checking for ANSI C header files... " >&6; } |
| -if test "${ac_cv_header_stdc+set}" = set; then : |
| +if ${ac_cv_header_stdc+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3532,4 +3668,3 @@ ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_include |
| " |
| -eval as_val=\$$as_ac_Header |
| - if test "x$as_val" = x""yes; then : |
| +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : |
| cat >>confdefs.h <<_ACEOF |
| @@ -3545,3 +3680,3 @@ done |
| ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" |
| -if test "x$ac_cv_header_minix_config_h" = x""yes; then : |
| +if test "x$ac_cv_header_minix_config_h" = xyes; then : |
| MINIX=yes |
| @@ -3567,3 +3702,3 @@ $as_echo "#define _MINIX 1" >>confdefs.h |
| $as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } |
| -if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : |
| +if ${ac_cv_safe_to_define___extensions__+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3573,4 +3708,4 @@ else |
| |
| -# define __EXTENSIONS__ 1 |
| - $ac_includes_default |
| +# define __EXTENSIONS__ 1 |
| + $ac_includes_default |
| int |
| @@ -3614,3 +3749,3 @@ set dummy ${ac_tool_prefix}gcc; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_CC+set}" = set; then : |
| +if ${ac_cv_prog_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3626,3 +3761,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_CC="${ac_tool_prefix}gcc" |
| @@ -3654,3 +3789,3 @@ set dummy gcc; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : |
| +if ${ac_cv_prog_ac_ct_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3666,3 +3801,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_ac_ct_CC="gcc" |
| @@ -3707,3 +3842,3 @@ set dummy ${ac_tool_prefix}cc; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_CC+set}" = set; then : |
| +if ${ac_cv_prog_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3719,3 +3854,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_CC="${ac_tool_prefix}cc" |
| @@ -3747,3 +3882,3 @@ set dummy cc; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_CC+set}" = set; then : |
| +if ${ac_cv_prog_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3760,3 +3895,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then |
| @@ -3806,3 +3941,3 @@ set dummy $ac_tool_prefix$ac_prog; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_CC+set}" = set; then : |
| +if ${ac_cv_prog_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3818,3 +3953,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_CC="$ac_tool_prefix$ac_prog" |
| @@ -3850,3 +3985,3 @@ set dummy $ac_prog; ac_word=$2 |
| $as_echo_n "checking for $ac_word... " >&6; } |
| -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : |
| +if ${ac_cv_prog_ac_ct_CC+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3862,3 +3997,3 @@ do |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then |
| ac_cv_prog_ac_ct_CC="$ac_prog" |
| @@ -3904,4 +4039,4 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd' |
| $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} |
| -as_fn_error "no acceptable C compiler found in \$PATH |
| -See \`config.log' for more details." "$LINENO" 5; } |
| +as_fn_error $? "no acceptable C compiler found in \$PATH |
| +See \`config.log' for more details" "$LINENO" 5; } |
| |
| @@ -3926,4 +4061,4 @@ $as_echo "$ac_try_echo"; } >&5 |
| cat conftest.er1 >&5 |
| - rm -f conftest.er1 conftest.err |
| fi |
| + rm -f conftest.er1 conftest.err |
| $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 |
| @@ -3934,3 +4069,3 @@ done |
| $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } |
| -if test "${ac_cv_c_compiler_gnu+set}" = set; then : |
| +if ${ac_cv_c_compiler_gnu+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -3971,3 +4106,3 @@ ac_save_CFLAGS=$CFLAGS |
| $as_echo_n "checking whether $CC accepts -g... " >&6; } |
| -if test "${ac_cv_prog_cc_g+set}" = set; then : |
| +if ${ac_cv_prog_cc_g+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4049,3 +4184,3 @@ fi |
| $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } |
| -if test "${ac_cv_prog_cc_c89+set}" = set; then : |
| +if ${ac_cv_prog_cc_c89+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4058,4 +4193,3 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext |
| #include <stdio.h> |
| -#include <sys/types.h> |
| -#include <sys/stat.h> |
| +struct stat; |
| /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ |
| @@ -4147,3 +4281,3 @@ if test $ac_cv_c_compiler_gnu = yes; then |
| $as_echo_n "checking whether $CC needs -traditional... " >&6; } |
| -if test "${ac_cv_prog_gcc_traditional+set}" = set; then : |
| +if ${ac_cv_prog_gcc_traditional+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4188,12 +4322,18 @@ ac_aux_dir= |
| for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do |
| - for ac_t in install-sh install.sh shtool; do |
| - if test -f "$ac_dir/$ac_t"; then |
| - ac_aux_dir=$ac_dir |
| - ac_install_sh="$ac_aux_dir/$ac_t -c" |
| - break 2 |
| - fi |
| - done |
| + if test -f "$ac_dir/install-sh"; then |
| + ac_aux_dir=$ac_dir |
| + ac_install_sh="$ac_aux_dir/install-sh -c" |
| + break |
| + elif test -f "$ac_dir/install.sh"; then |
| + ac_aux_dir=$ac_dir |
| + ac_install_sh="$ac_aux_dir/install.sh -c" |
| + break |
| + elif test -f "$ac_dir/shtool"; then |
| + ac_aux_dir=$ac_dir |
| + ac_install_sh="$ac_aux_dir/shtool install -c" |
| + break |
| + fi |
| done |
| if test -z "$ac_aux_dir"; then |
| - as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 |
| + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 |
| fi |
| @@ -4226,3 +4366,3 @@ $as_echo_n "checking for a BSD-compatible install... " >&6; } |
| if test -z "$INSTALL"; then |
| -if test "${ac_cv_path_install+set}" = set; then : |
| +if ${ac_cv_path_install+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4246,3 +4386,3 @@ case $as_dir/ in #(( |
| for ac_exec_ext in '' $ac_executable_extensions; do |
| - if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then |
| + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then |
| if test $ac_prog = install && |
| @@ -4316,3 +4456,3 @@ echo "Using: BMAKE_PATH_MAX=$bmake_path_max" >&6 |
| $as_echo_n "checking for ANSI C header files... " >&6; } |
| -if test "${ac_cv_header_stdc+set}" = set; then : |
| +if ${ac_cv_header_stdc+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4428,3 +4568,3 @@ fi |
| $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } |
| -if test "${ac_cv_header_sys_wait_h+set}" = set; then : |
| +if ${ac_cv_header_sys_wait_h+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4472,3 +4612,3 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do |
| $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } |
| -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then : |
| +if eval \${$as_ac_Header+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4499,4 +4639,3 @@ eval ac_res=\$$as_ac_Header |
| $as_echo "$ac_res" >&6; } |
| -eval as_val=\$$as_ac_Header |
| - if test "x$as_val" = x""yes; then : |
| +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : |
| cat >>confdefs.h <<_ACEOF |
| @@ -4513,3 +4652,3 @@ if test $ac_header_dirent = dirent.h; then |
| $as_echo_n "checking for library containing opendir... " >&6; } |
| -if test "${ac_cv_search_opendir+set}" = set; then : |
| +if ${ac_cv_search_opendir+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4547,3 +4686,3 @@ rm -f core conftest.err conftest.$ac_objext \ |
| conftest$ac_exeext |
| - if test "${ac_cv_search_opendir+set}" = set; then : |
| + if ${ac_cv_search_opendir+:} false; then : |
| break |
| @@ -4551,3 +4690,3 @@ fi |
| done |
| -if test "${ac_cv_search_opendir+set}" = set; then : |
| +if ${ac_cv_search_opendir+:} false; then : |
| |
| @@ -4570,3 +4709,3 @@ else |
| $as_echo_n "checking for library containing opendir... " >&6; } |
| -if test "${ac_cv_search_opendir+set}" = set; then : |
| +if ${ac_cv_search_opendir+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4604,3 +4743,3 @@ rm -f core conftest.err conftest.$ac_objext \ |
| conftest$ac_exeext |
| - if test "${ac_cv_search_opendir+set}" = set; then : |
| + if ${ac_cv_search_opendir+:} false; then : |
| break |
| @@ -4608,3 +4747,3 @@ fi |
| done |
| -if test "${ac_cv_search_opendir+set}" = set; then : |
| +if ${ac_cv_search_opendir+:} false; then : |
| |
| @@ -4629,3 +4768,3 @@ do : |
| ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" |
| -if test "x$ac_cv_header_sys_param_h" = x""yes; then : |
| +if test "x$ac_cv_header_sys_param_h" = xyes; then : |
| cat >>confdefs.h <<_ACEOF |
| @@ -4645,3 +4784,3 @@ do : |
| " |
| -if test "x$ac_cv_header_sys_sysctl_h" = x""yes; then : |
| +if test "x$ac_cv_header_sys_sysctl_h" = xyes; then : |
| cat >>confdefs.h <<_ACEOF |
| @@ -4666,2 +4805,3 @@ for ac_header in \ |
| sys/mman.h \ |
| + sys/resource.h \ |
| sys/select.h \ |
| @@ -4670,2 +4810,4 @@ for ac_header in \ |
| sys/uio.h \ |
| + sys/utsname.h \ |
| + sys/wait.h \ |
| unistd.h \ |
| @@ -4676,4 +4818,3 @@ do : |
| ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" |
| -eval as_val=\$$as_ac_Header |
| - if test "x$as_val" = x""yes; then : |
| +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : |
| cat >>confdefs.h <<_ACEOF |
| @@ -4688,3 +4829,3 @@ done |
| ac_fn_c_check_header_mongrel "$LINENO" "sys/cdefs.h" "ac_cv_header_sys_cdefs_h" "$ac_includes_default" |
| -if test "x$ac_cv_header_sys_cdefs_h" = x""yes; then : |
| +if test "x$ac_cv_header_sys_cdefs_h" = xyes; then : |
| echo $ECHO_N "checking whether sys/cdefs.h is compatible... $ECHO_C" >&6 |
| @@ -4715,3 +4856,3 @@ fi |
| $as_echo_n "checking for __attribute__... " >&6; } |
| -if test "${ac_cv___attribute__+set}" = set; then : |
| +if ${ac_cv___attribute__+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4758,3 +4899,3 @@ $as_echo "$ac_cv___attribute__" >&6; } |
| $as_echo_n "checking whether byte ordering is bigendian... " >&6; } |
| -if test "${ac_cv_c_bigendian+set}" = set; then : |
| +if ${ac_cv_c_bigendian+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4976,3 +5117,3 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h |
| *) |
| - as_fn_error "unknown endianness |
| + as_fn_error $? "unknown endianness |
| presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; |
| @@ -4982,3 +5123,3 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h |
| $as_echo_n "checking for an ANSI C-conforming const... " >&6; } |
| -if test "${ac_cv_c_const+set}" = set; then : |
| +if ${ac_cv_c_const+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -4991,7 +5132,7 @@ main () |
| { |
| -/* FIXME: Include the comments suggested by Paul. */ |
| + |
| #ifndef __cplusplus |
| - /* Ultrix mips cc rejects this. */ |
| + /* Ultrix mips cc rejects this sort of thing. */ |
| typedef int charset[2]; |
| - const charset cs; |
| + const charset cs = { 0, 0 }; |
| /* SunOS 4.1.1 cc rejects this. */ |
| @@ -5012,4 +5153,5 @@ main () |
| pcpcc = (char const *const *) ppc; |
| - { /* SCO 3.2v4 cc rejects this. */ |
| - char *t; |
| + { /* SCO 3.2v4 cc rejects this sort of thing. */ |
| + char tx; |
| + char *t = &tx; |
| char const *s = 0 ? (char *) 0 : (char const *) 0; |
| @@ -5029,6 +5171,6 @@ main () |
| } |
| - { /* AIX XL C 1.02.0.0 rejects this saying |
| + { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying |
| "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ |
| - struct s { int j; const int *ap[3]; }; |
| - struct s *b; b->j = 5; |
| + struct s { int j; const int *ap[3]; } bx; |
| + struct s *b = &bx; b->j = 5; |
| } |
| @@ -5060,4 +5202,15 @@ fi |
| |
| +ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" |
| +case $ac_cv_c_int32_t in #( |
| + no|yes) ;; #( |
| + *) |
| + |
| +cat >>confdefs.h <<_ACEOF |
| +#define int32_t $ac_cv_c_int32_t |
| +_ACEOF |
| +;; |
| +esac |
| + |
| ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" |
| -if test "x$ac_cv_type_mode_t" = x""yes; then : |
| +if test "x$ac_cv_type_mode_t" = xyes; then : |
| |
| @@ -5072,3 +5225,3 @@ fi |
| ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" |
| -if test "x$ac_cv_type_off_t" = x""yes; then : |
| +if test "x$ac_cv_type_off_t" = xyes; then : |
| |
| @@ -5083,3 +5236,3 @@ fi |
| ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" |
| -if test "x$ac_cv_type_pid_t" = x""yes; then : |
| +if test "x$ac_cv_type_pid_t" = xyes; then : |
| |
| @@ -5094,3 +5247,3 @@ fi |
| ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" |
| -if test "x$ac_cv_type_size_t" = x""yes; then : |
| +if test "x$ac_cv_type_size_t" = xyes; then : |
| |
| @@ -5125,3 +5278,3 @@ ac_fn_c_check_decl "$LINENO" "sys_siglist" "ac_cv_have_decl_sys_siglist" "#inclu |
| " |
| -if test "x$ac_cv_have_decl_sys_siglist" = x""yes; then : |
| +if test "x$ac_cv_have_decl_sys_siglist" = xyes; then : |
| ac_have_decl=1 |
| @@ -5138,3 +5291,3 @@ _ACEOF |
| $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } |
| -if test "${ac_cv_header_time+set}" = set; then : |
| +if ${ac_cv_header_time+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5173,3 +5326,3 @@ fi |
| $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } |
| -if test "${ac_cv_struct_tm+set}" = set; then : |
| +if ${ac_cv_struct_tm+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5209,3 +5362,3 @@ fi |
| $as_echo_n "checking return type of signal handlers... " >&6; } |
| -if test "${ac_cv_type_signal+set}" = set; then : |
| +if ${ac_cv_type_signal+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5243,3 +5396,3 @@ do : |
| ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" |
| -if test "x$ac_cv_header_vfork_h" = x""yes; then : |
| +if test "x$ac_cv_header_vfork_h" = xyes; then : |
| cat >>confdefs.h <<_ACEOF |
| @@ -5256,4 +5409,3 @@ do : |
| ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" |
| -eval as_val=\$$as_ac_var |
| - if test "x$as_val" = x""yes; then : |
| +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : |
| cat >>confdefs.h <<_ACEOF |
| @@ -5268,3 +5420,3 @@ if test "x$ac_cv_func_fork" = xyes; then |
| $as_echo_n "checking for working fork... " >&6; } |
| -if test "${ac_cv_func_fork_works+set}" = set; then : |
| +if ${ac_cv_func_fork_works+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5321,3 +5473,3 @@ if test "x$ac_cv_func_vfork" = xyes; then |
| $as_echo_n "checking for working vfork... " >&6; } |
| -if test "${ac_cv_func_vfork_works+set}" = set; then : |
| +if ${ac_cv_func_vfork_works+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5457,3 +5609,3 @@ do : |
| ac_fn_c_check_func "$LINENO" "vprintf" "ac_cv_func_vprintf" |
| -if test "x$ac_cv_func_vprintf" = x""yes; then : |
| +if test "x$ac_cv_func_vprintf" = xyes; then : |
| cat >>confdefs.h <<_ACEOF |
| @@ -5463,3 +5615,3 @@ _ACEOF |
| ac_fn_c_check_func "$LINENO" "_doprnt" "ac_cv_func__doprnt" |
| -if test "x$ac_cv_func__doprnt" = x""yes; then : |
| +if test "x$ac_cv_func__doprnt" = xyes; then : |
| |
| @@ -5475,3 +5627,3 @@ done |
| $as_echo_n "checking for wait3 that fills in rusage... " >&6; } |
| -if test "${ac_cv_func_wait3_rusage+set}" = set; then : |
| +if ${ac_cv_func_wait3_rusage+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5538,18 +5690,109 @@ fi |
| for ac_func in \ |
| + _Exit \ |
| + alloca \ |
| + atoll \ |
| + canonicalize_file_name \ |
| + chown \ |
| + dup2 \ |
| + dup3 \ |
| + endusershell \ |
| err \ |
| errx \ |
| + euidaccess \ |
| + faccessat \ |
| + fchdir \ |
| + fchmodat \ |
| + fchownat \ |
| + fcntl \ |
| + fdatasync \ |
| + fstatat \ |
| + fsync \ |
| + ftruncate \ |
| + futimens \ |
| getcwd \ |
| + getdomainname \ |
| + getdtablesize \ |
| getenv \ |
| + getgroups \ |
| + gethostname \ |
| + getloadavg \ |
| + getlogin \ |
| + getlogin_r \ |
| getopt \ |
| + getpass \ |
| + getppid \ |
| + getrusage \ |
| + getsubopt \ |
| + getusershell \ |
| getwd \ |
| + grantpt \ |
| + group_member \ |
| + initstate \ |
| + initstate_r \ |
| + kill \ |
| killpg \ |
| + lchmod \ |
| + lchown \ |
| + link \ |
| + linkat \ |
| + lstat \ |
| + mkdirat \ |
| + mkdtemp \ |
| + mkfifo \ |
| + mkfifoat \ |
| + mknod \ |
| + mknodat \ |
| + mkostemp \ |
| + mkostemps \ |
| + mkstemp \ |
| + mkstemps \ |
| mmap \ |
| + openat \ |
| + pipe \ |
| + pipe2 \ |
| + poll \ |
| + posix_openpt \ |
| + pread \ |
| + pthread_sigmask \ |
| + ptsname \ |
| + ptsname_r \ |
| putenv \ |
| + pwrite \ |
| + qsort_r \ |
| + raise \ |
| + random \ |
| + random_r \ |
| + readlink \ |
| + readlinkat \ |
| + reallocarray \ |
| + realpath \ |
| + regcomp \ |
| + regerror \ |
| + regexec \ |
| + regfree \ |
| + rpmatch \ |
| + secure_getenv \ |
| select \ |
| setenv \ |
| + sethostname \ |
| setpgid \ |
| + setpgrp \ |
| setsid \ |
| + setstate \ |
| + setstate_r \ |
| + setusershell \ |
| sigaction \ |
| + sigaddset \ |
| + sigdelset \ |
| + sigemptyset \ |
| + sigfillset \ |
| + sigismember \ |
| + signal \ |
| + sigpending \ |
| + sigprocmask \ |
| sigvec \ |
| + sleep \ |
| snprintf \ |
| + srandom \ |
| + srandom_r \ |
| strerror \ |
| @@ -5559,5 +5802,17 @@ for ac_func in \ |
| strtol \ |
| + strtoll \ |
| + strtoull \ |
| + symlink \ |
| + symlinkat \ |
| sysctl \ |
| + truncate \ |
| + ttyname_r \ |
| + uname \ |
| + unlinkat \ |
| + unlockpt \ |
| unsetenv \ |
| + usleep \ |
| + utimensat \ |
| vsnprintf \ |
| + wait \ |
| wait3 \ |
| @@ -5571,4 +5826,3 @@ do : |
| ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" |
| -eval as_val=\$$as_ac_var |
| - if test "x$as_val" = x""yes; then : |
| +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : |
| cat >>confdefs.h <<_ACEOF |
| @@ -5581,16 +5835,18 @@ done |
| |
| -for ac_func in \ |
| - realpath \ |
| - dirname \ |
| - stresep \ |
| - strlcpy \ |
| +ac_fn_c_check_func "$LINENO" "realpath" "ac_cv_func_realpath" |
| +if test "x$ac_cv_func_realpath" = xyes; then : |
| + $as_echo "#define HAVE_REALPATH 1" >>confdefs.h |
| |
| -do : |
| - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` |
| -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" |
| -eval as_val=\$$as_ac_var |
| - if test "x$as_val" = x""yes; then : |
| - cat >>confdefs.h <<_ACEOF |
| -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 |
| -_ACEOF |
| +else |
| + case " $LIBOBJS " in |
| + *" realpath.$ac_objext "* ) ;; |
| + *) LIBOBJS="$LIBOBJS realpath.$ac_objext" |
| + ;; |
| +esac |
| + |
| +fi |
| + |
| +ac_fn_c_check_func "$LINENO" "dirname" "ac_cv_func_dirname" |
| +if test "x$ac_cv_func_dirname" = xyes; then : |
| + $as_echo "#define HAVE_DIRNAME 1" >>confdefs.h |
| |
| @@ -5598,4 +5854,30 @@ else |
| case " $LIBOBJS " in |
| - *" $ac_func.$ac_objext "* ) ;; |
| - *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" |
| + *" dirname.$ac_objext "* ) ;; |
| + *) LIBOBJS="$LIBOBJS dirname.$ac_objext" |
| + ;; |
| +esac |
| + |
| +fi |
| + |
| +ac_fn_c_check_func "$LINENO" "stresep" "ac_cv_func_stresep" |
| +if test "x$ac_cv_func_stresep" = xyes; then : |
| + $as_echo "#define HAVE_STRESEP 1" >>confdefs.h |
| + |
| +else |
| + case " $LIBOBJS " in |
| + *" stresep.$ac_objext "* ) ;; |
| + *) LIBOBJS="$LIBOBJS stresep.$ac_objext" |
| + ;; |
| +esac |
| + |
| +fi |
| + |
| +ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" |
| +if test "x$ac_cv_func_strlcpy" = xyes; then : |
| + $as_echo "#define HAVE_STRLCPY 1" >>confdefs.h |
| + |
| +else |
| + case " $LIBOBJS " in |
| + *" strlcpy.$ac_objext "* ) ;; |
| + *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" |
| ;; |
| @@ -5604,3 +5886,2 @@ esac |
| fi |
| -done |
| |
| @@ -5610,3 +5891,3 @@ done |
| $as_echo_n "checking for emalloc in -lutil... " >&6; } |
| -if test "${ac_cv_lib_util_emalloc+set}" = set; then : |
| +if ${ac_cv_lib_util_emalloc+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5644,6 +5925,6 @@ fi |
| $as_echo "$ac_cv_lib_util_emalloc" >&6; } |
| -if test "x$ac_cv_lib_util_emalloc" = x""yes; then : |
| +if test "x$ac_cv_lib_util_emalloc" = xyes; then : |
| { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erealloc in -lutil" >&5 |
| $as_echo_n "checking for erealloc in -lutil... " >&6; } |
| -if test "${ac_cv_lib_util_erealloc+set}" = set; then : |
| +if ${ac_cv_lib_util_erealloc+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5681,6 +5962,6 @@ fi |
| $as_echo "$ac_cv_lib_util_erealloc" >&6; } |
| -if test "x$ac_cv_lib_util_erealloc" = x""yes; then : |
| +if test "x$ac_cv_lib_util_erealloc" = xyes; then : |
| { $as_echo "$as_me:${as_lineno-$LINENO}: checking for estrdup in -lutil" >&5 |
| $as_echo_n "checking for estrdup in -lutil... " >&6; } |
| -if test "${ac_cv_lib_util_estrdup+set}" = set; then : |
| +if ${ac_cv_lib_util_estrdup+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5718,6 +5999,6 @@ fi |
| $as_echo "$ac_cv_lib_util_estrdup" >&6; } |
| -if test "x$ac_cv_lib_util_estrdup" = x""yes; then : |
| +if test "x$ac_cv_lib_util_estrdup" = xyes; then : |
| { $as_echo "$as_me:${as_lineno-$LINENO}: checking for estrndup in -lutil" >&5 |
| $as_echo_n "checking for estrndup in -lutil... " >&6; } |
| -if test "${ac_cv_lib_util_estrndup+set}" = set; then : |
| +if ${ac_cv_lib_util_estrndup+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5755,3 +6036,3 @@ fi |
| $as_echo "$ac_cv_lib_util_estrndup" >&6; } |
| -if test "x$ac_cv_lib_util_estrndup" = x""yes; then : |
| +if test "x$ac_cv_lib_util_estrndup" = xyes; then : |
| LIBS="$LIBS -lutil" |
| @@ -5769,3 +6050,3 @@ fi |
| $as_echo_n "checking whether stat file-mode macros are broken... " >&6; } |
| -if test "${ac_cv_header_stat_broken+set}" = set; then : |
| +if ${ac_cv_header_stat_broken+:} false; then : |
| $as_echo_n "(cached) " >&6 |
| @@ -5810,3 +6091,3 @@ fi |
| ac_fn_c_check_member "$LINENO" "struct stat" "st_rdev" "ac_cv_member_struct_stat_st_rdev" "$ac_includes_default" |
| -if test "x$ac_cv_member_struct_stat_st_rdev" = x""yes; then : |
| +if test "x$ac_cv_member_struct_stat_st_rdev" = xyes; then : |
| |
| @@ -5881,3 +6162,3 @@ if test "${with_machine+set}" = set; then : |
| withval=$with_machine; case "${withval}" in |
| -yes) as_fn_error "bad value ${withval} given for bmake MACHINE" "$LINENO" 5 ;; |
| +yes) as_fn_error $? "bad value ${withval} given for bmake MACHINE" "$LINENO" 5 ;; |
| no) ;; |
| @@ -5914,3 +6195,3 @@ if test "${with_machine_arch+set}" = set; then : |
| withval=$with_machine_arch; case "${withval}" in |
| -yes) as_fn_error "bad value ${withval} given for bmake MACHINE_ARCH" "$LINENO" 5 ;; |
| +yes) as_fn_error $? "bad value ${withval} given for bmake MACHINE_ARCH" "$LINENO" 5 ;; |
| no) ;; |
| @@ -5926,3 +6207,3 @@ if test "${with_default_sys_path+set}" = set; then : |
| withval=$with_default_sys_path; case "${withval}" in |
| -yes) as_fn_error "bad value ${withval} given for bmake _PATH_DEFSYSPATH" "$LINENO" 5 ;; |
| +yes) as_fn_error $? "bad value ${withval} given for bmake _PATH_DEFSYSPATH" "$LINENO" 5 ;; |
| no) ;; |
| @@ -5937,3 +6218,3 @@ if test "${with_path_objdirprefix+set}" = set; then : |
| withval=$with_path_objdirprefix; case "${withval}" in |
| -yes) as_fn_error "bad value ${withval} given for bmake _PATH_OBJDIRPREFIX" "$LINENO" 5 ;; |
| +yes) as_fn_error $? "bad value ${withval} given for bmake _PATH_OBJDIRPREFIX" "$LINENO" 5 ;; |
| no) CPPFLAGS="$CPPFLAGS -DNO_PATH_OBJDIRPREFIX" ;; |
| @@ -5948,3 +6229,3 @@ yes) ;; |
| no) CPPFLAGS="$CPPFLAGS -DNO_PWD_OVERRIDE" ;; |
| -*) as_fn_error "bad value ${enableval} given for pwd-override option" "$LINENO" 5 ;; |
| +*) as_fn_error $? "bad value ${enableval} given for pwd-override option" "$LINENO" 5 ;; |
| esac |
| @@ -5957,3 +6238,3 @@ yes) ;; |
| no) CPPFLAGS="$CPPFLAGS -DNO_CHECK_MAKE_CHDIR" ;; |
| -*) as_fn_error "bad value ${enableval} given for check-make-chdir option" "$LINENO" 5 ;; |
| +*) as_fn_error $? "bad value ${enableval} given for check-make-chdir option" "$LINENO" 5 ;; |
| esac |
| @@ -5967,3 +6248,3 @@ if test "${with_mksrc+set}" = set; then : |
| *) test -s $withval/install-mk && mksrc=$withval || |
| -as_fn_error "bad value ${withval} given for mksrc cannot find install-mk" "$LINENO" 5 |
| +as_fn_error $? "bad value ${withval} given for mksrc cannot find install-mk" "$LINENO" 5 |
| ;; |
| @@ -6011,3 +6292,3 @@ fi |
| |
| -ac_config_files="$ac_config_files makefile Makefile.config make-bootstrap.sh unit-tests/Makefile" |
| +ac_config_files="$ac_config_files Makefile.config make-bootstrap.sh unit-tests/Makefile" |
| |
| @@ -6077,6 +6358,17 @@ if diff "$cache_file" confcache >/dev/null 2>&1; then :; else |
| if test -w "$cache_file"; then |
| - test "x$cache_file" != "x/dev/null" && |
| + if test "x$cache_file" != "x/dev/null"; then |
| { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 |
| $as_echo "$as_me: updating cache $cache_file" >&6;} |
| - cat confcache >$cache_file |
| + if test ! -f "$cache_file" || test -h "$cache_file"; then |
| + cat confcache >"$cache_file" |
| + else |
| + case $cache_file in #( |
| + */* | ?:*) |
| + mv -f confcache "$cache_file"$$ && |
| + mv -f "$cache_file"$$ "$cache_file" ;; #( |
| + *) |
| + mv -f confcache "$cache_file" ;; |
| + esac |
| + fi |
| + fi |
| else |
| @@ -6096,2 +6388,3 @@ ac_libobjs= |
| ac_ltlibobjs= |
| +U= |
| for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue |
| @@ -6112,3 +6405,3 @@ LTLIBOBJS=$ac_ltlibobjs |
| |
| -: ${CONFIG_STATUS=./config.status} |
| +: "${CONFIG_STATUS=./config.status}" |
| ac_write_fail=0 |
| @@ -6213,2 +6506,3 @@ IFS=" "" $as_nl" |
| # Find who we are. Look in the path if we contain no directory separator. |
| +as_myself= |
| case $0 in #(( |
| @@ -6258,15 +6552,15 @@ export LANGUAGE |
| |
| -# as_fn_error ERROR [LINENO LOG_FD] |
| -# --------------------------------- |
| +# as_fn_error STATUS ERROR [LINENO LOG_FD] |
| +# ---------------------------------------- |
| # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are |
| # provided, also output the error to LOG_FD, referencing LINENO. Then exit the |
| -# script with status $?, using 1 if that was 0. |
| +# script with STATUS, using 1 if that was 0. |
| as_fn_error () |
| { |
| - as_status=$?; test $as_status -eq 0 && as_status=1 |
| - if test "$3"; then |
| - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack |
| - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 |
| + as_status=$1; test $as_status -eq 0 && as_status=1 |
| + if test "$4"; then |
| + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack |
| + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 |
| fi |
| - $as_echo "$as_me: error: $1" >&2 |
| + $as_echo "$as_me: error: $2" >&2 |
| as_fn_exit $as_status |
| @@ -6408,5 +6702,5 @@ if (echo >conf$$.file) 2>/dev/null; then |
| # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. |
| - # In both cases, we have to default to `cp -p'. |
| + # In both cases, we have to default to `cp -pR'. |
| ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || |
| - as_ln_s='cp -p' |
| + as_ln_s='cp -pR' |
| elif ln conf$$.file conf$$ 2>/dev/null; then |
| @@ -6414,6 +6708,6 @@ if (echo >conf$$.file) 2>/dev/null; then |
| else |
| - as_ln_s='cp -p' |
| + as_ln_s='cp -pR' |
| fi |
| else |
| - as_ln_s='cp -p' |
| + as_ln_s='cp -pR' |
| fi |
| @@ -6466,3 +6760,3 @@ $as_echo X"$as_dir" | |
| test -z "$as_dirs" || eval "mkdir $as_dirs" |
| - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" |
| + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" |
| |
| @@ -6477,24 +6771,12 @@ fi |
| |
| -if test -x / >/dev/null 2>&1; then |
| - as_test_x='test -x' |
| -else |
| - if ls -dL / >/dev/null 2>&1; then |
| - as_ls_L_option=L |
| - else |
| - as_ls_L_option= |
| - fi |
| - as_test_x=' |
| - eval sh -c '\'' |
| - if test -d "$1"; then |
| - test -d "$1/."; |
| - else |
| - case $1 in #( |
| - -*)set "./$1";; |
| - esac; |
| - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( |
| - ???[sx]*):;;*)false;;esac;fi |
| - '\'' sh |
| - ' |
| -fi |
| -as_executable_p=$as_test_x |
| + |
| +# as_fn_executable_p FILE |
| +# ----------------------- |
| +# Test if FILE is an executable regular file. |
| +as_fn_executable_p () |
| +{ |
| + test -f "$1" && test -x "$1" |
| +} # as_fn_executable_p |
| +as_test_x='test -x' |
| +as_executable_p=as_fn_executable_p |
| |
| @@ -6520,3 +6802,3 @@ ac_log=" |
| This file was extended by bmake $as_me 20171126, which was |
| -generated by GNU Autoconf 2.64. Invocation command line was |
| +generated by GNU Autoconf 2.69. Invocation command line was |
| |
| @@ -6559,2 +6841,3 @@ Usage: $0 [OPTION]... [TAG]... |
| -V, --version print version number and configuration settings, then exit |
| + --config print configuration, then exit |
| -q, --quiet, --silent |
| @@ -6578,8 +6861,9 @@ _ACEOF |
| cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
| +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
| ac_cs_version="\\ |
| bmake config.status 20171126 |
| -configured by $0, generated by GNU Autoconf 2.64, |
| - with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" |
| +configured by $0, generated by GNU Autoconf 2.69, |
| + with options \\"\$ac_cs_config\\" |
| |
| -Copyright (C) 2009 Free Software Foundation, Inc. |
| +Copyright (C) 2012 Free Software Foundation, Inc. |
| This config.status script is free software; the Free Software Foundation |
| @@ -6599,3 +6883,3 @@ do |
| case $1 in |
| - --*=*) |
| + --*=?*) |
| ac_option=`expr "X$1" : 'X\([^=]*\)='` |
| @@ -6604,2 +6888,7 @@ do |
| ;; |
| + --*=) |
| + ac_option=`expr "X$1" : 'X\([^=]*\)='` |
| + ac_optarg= |
| + ac_shift=: |
| + ;; |
| *) |
| @@ -6617,2 +6906,4 @@ do |
| $as_echo "$ac_cs_version"; exit ;; |
| + --config | --confi | --conf | --con | --co | --c ) |
| + $as_echo "$ac_cs_config"; exit ;; |
| --debug | --debu | --deb | --de | --d | -d ) |
| @@ -6623,2 +6914,3 @@ do |
| *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; |
| + '') as_fn_error $? "missing file argument" ;; |
| esac |
| @@ -6635,3 +6927,3 @@ do |
| # Conflict between --help and --header |
| - as_fn_error "ambiguous option: \`$1' |
| + as_fn_error $? "ambiguous option: \`$1' |
| Try \`$0 --help' for more information.";; |
| @@ -6644,3 +6936,3 @@ Try \`$0 --help' for more information.";; |
| # This is an error. |
| - -*) as_fn_error "unrecognized option: \`$1' |
| + -*) as_fn_error $? "unrecognized option: \`$1' |
| Try \`$0 --help' for more information." ;; |
| @@ -6664,3 +6956,3 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
| if \$ac_cs_recheck; then |
| - set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion |
| + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion |
| shift |
| @@ -6694,3 +6986,2 @@ do |
| "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; |
| - "makefile") CONFIG_FILES="$CONFIG_FILES makefile" ;; |
| "Makefile.config") CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; |
| @@ -6699,3 +6990,3 @@ do |
| |
| - *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; |
| + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; |
| esac |
| @@ -6721,5 +7012,6 @@ $debug || |
| { |
| - tmp= |
| + tmp= ac_tmp= |
| trap 'exit_status=$? |
| - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status |
| + : "${ac_tmp:=$tmp}" |
| + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status |
| ' 0 |
| @@ -6731,3 +7023,3 @@ $debug || |
| tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && |
| - test -n "$tmp" && test -d "$tmp" |
| + test -d "$tmp" |
| } || |
| @@ -6736,3 +7028,4 @@ $debug || |
| (umask 077 && mkdir "$tmp") |
| -} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 |
| +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 |
| +ac_tmp=$tmp |
| |
| @@ -6753,3 +7046,3 @@ ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` |
| if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then |
| - ac_cs_awk_cr='\r' |
| + ac_cs_awk_cr='\\r' |
| else |
| @@ -6758,3 +7051,3 @@ fi |
| |
| -echo 'BEGIN {' >"$tmp/subs1.awk" && |
| +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && |
| _ACEOF |
| @@ -6767,4 +7060,4 @@ _ACEOF |
| } >conf$$subs.sh || |
| - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 |
| -ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` |
| + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 |
| +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` |
| ac_delim='%!_!# ' |
| @@ -6772,3 +7065,3 @@ for ac_last_try in false false false false false :; do |
| . ./conf$$subs.sh || |
| - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 |
| + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 |
| |
| @@ -6778,3 +7071,3 @@ for ac_last_try in false false false false false :; do |
| elif $ac_last_try; then |
| - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 |
| + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 |
| else |
| @@ -6786,3 +7079,3 @@ rm -f conf$$subs.sh |
| cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
| -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && |
| +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && |
| _ACEOF |
| @@ -6800,3 +7093,3 @@ t delim |
| h |
| -s/\(.\{148\}\).*/\1/ |
| +s/\(.\{148\}\)..*/\1/ |
| t more1 |
| @@ -6814,3 +7107,3 @@ t nl |
| h |
| -s/\(.\{148\}\).*/\1/ |
| +s/\(.\{148\}\)..*/\1/ |
| t more2 |
| @@ -6834,3 +7127,3 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
| _ACAWK |
| -cat >>"\$tmp/subs1.awk" <<_ACAWK && |
| +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && |
| for (key in S) S_is_set[key] = 1 |
| @@ -6866,8 +7159,8 @@ else |
| cat |
| -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ |
| - || as_fn_error "could not setup config files machinery" "$LINENO" 5 |
| +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ |
| + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 |
| _ACEOF |
| |
| -# VPATH may cause trouble with some makes, so we remove $(srcdir), |
| -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and |
| +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), |
| +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and |
| # trailing colons and then remove the whole line if VPATH becomes empty |
| @@ -6875,8 +7168,16 @@ _ACEOF |
| if test "x$srcdir" = x.; then |
| - ac_vpsub='/^[ ]*VPATH[ ]*=/{ |
| -s/:*\$(srcdir):*/:/ |
| -s/:*\${srcdir}:*/:/ |
| -s/:*@srcdir@:*/:/ |
| -s/^\([^=]*=[ ]*\):*/\1/ |
| + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ |
| +h |
| +s/// |
| +s/^/:/ |
| +s/[ ]*$/:/ |
| +s/:\$(srcdir):/:/g |
| +s/:\${srcdir}:/:/g |
| +s/:@srcdir@:/:/g |
| +s/^:*// |
| s/:*$// |
| +x |
| +s/\(=[ ]*\).*/\1/ |
| +G |
| +s/\n// |
| s/^[^=]*=[ ]*$// |
| @@ -6892,3 +7193,3 @@ fi # test -n "$CONFIG_FILES" |
| if test -n "$CONFIG_HEADERS"; then |
| -cat >"$tmp/defines.awk" <<\_ACAWK || |
| +cat >"$ac_tmp/defines.awk" <<\_ACAWK || |
| BEGIN { |
| @@ -6904,7 +7205,7 @@ ac_delim='%!_!# ' |
| for ac_last_try in false false :; do |
| - ac_t=`sed -n "/$ac_delim/p" confdefs.h` |
| - if test -z "$ac_t"; then |
| + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` |
| + if test -z "$ac_tt"; then |
| break |
| elif $ac_last_try; then |
| - as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 |
| + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 |
| else |
| @@ -6993,3 +7294,3 @@ _ACEOF |
| cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 |
| - as_fn_error "could not setup config headers machinery" "$LINENO" 5 |
| + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 |
| fi # test -n "$CONFIG_HEADERS" |
| @@ -7006,3 +7307,3 @@ do |
| :[FHL]*:*);; |
| - :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; |
| + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; |
| :[FH]-) ac_tag=-:-;; |
| @@ -7025,3 +7326,3 @@ do |
| case $ac_f in |
| - -) ac_f="$tmp/stdin";; |
| + -) ac_f="$ac_tmp/stdin";; |
| *) # Look for the file first in the build tree, then in the source tree |
| @@ -7034,3 +7335,3 @@ do |
| esac || |
| - as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; |
| + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; |
| esac |
| @@ -7060,4 +7361,4 @@ $as_echo "$as_me: creating $ac_file" >&6;} |
| case $ac_tag in |
| - *:-:* | *:-) cat >"$tmp/stdin" \ |
| - || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; |
| + *:-:* | *:-) cat >"$ac_tmp/stdin" \ |
| + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; |
| esac |
| @@ -7191,19 +7492,20 @@ $ac_datarootdir_hack |
| " |
| -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ |
| - || as_fn_error "could not create $ac_file" "$LINENO" 5 |
| +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ |
| + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 |
| |
| test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && |
| - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && |
| - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && |
| + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && |
| + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ |
| + "$ac_tmp/out"`; test -z "$ac_out"; } && |
| { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' |
| -which seems to be undefined. Please make sure it is defined." >&5 |
| +which seems to be undefined. Please make sure it is defined" >&5 |
| $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' |
| -which seems to be undefined. Please make sure it is defined." >&2;} |
| +which seems to be undefined. Please make sure it is defined" >&2;} |
| |
| - rm -f "$tmp/stdin" |
| + rm -f "$ac_tmp/stdin" |
| case $ac_file in |
| - -) cat "$tmp/out" && rm -f "$tmp/out";; |
| - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; |
| + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; |
| + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; |
| esac \ |
| - || as_fn_error "could not create $ac_file" "$LINENO" 5 |
| + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 |
| ;; |
| @@ -7216,6 +7518,6 @@ which seems to be undefined. Please make sure it is defined." >&2;} |
| $as_echo "/* $configure_input */" \ |
| - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" |
| - } >"$tmp/config.h" \ |
| - || as_fn_error "could not create $ac_file" "$LINENO" 5 |
| - if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then |
| + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" |
| + } >"$ac_tmp/config.h" \ |
| + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 |
| + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then |
| { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 |
| @@ -7224,4 +7526,4 @@ $as_echo "$as_me: $ac_file is unchanged" >&6;} |
| rm -f "$ac_file" |
| - mv "$tmp/config.h" "$ac_file" \ |
| - || as_fn_error "could not create $ac_file" "$LINENO" 5 |
| + mv "$ac_tmp/config.h" "$ac_file" \ |
| + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 |
| fi |
| @@ -7229,4 +7531,4 @@ $as_echo "$as_me: $ac_file is unchanged" >&6;} |
| $as_echo "/* $configure_input */" \ |
| - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ |
| - || as_fn_error "could not create -" "$LINENO" 5 |
| + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ |
| + || as_fn_error $? "could not create -" "$LINENO" 5 |
| fi |
| @@ -7245,3 +7547,3 @@ ac_clean_files=$ac_clean_files_save |
| test $ac_write_fail = 0 || |
| - as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 |
| + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 |
| |
| @@ -7266,3 +7568,3 @@ if test "$no_create" != yes; then |
| # would make configure fail if this is the last instruction. |
| - $ac_cs_success || as_fn_exit $? |
| + $ac_cs_success || as_fn_exit 1 |
| fi |
| diff --git a/configure.in b/configure.in |
| index ccd4262..81231ca 100644 |
| --- a/configure.in |
| +++ b/configure.in |
| @@ -50,3 +50,3 @@ esac], |
| [ |
| -OS=`uname -s` |
| +OS=`uname -s | cut -d_ -f1` |
| for d in "/usr/include/dev/filemon" "$prefix/include/dev/filemon" "$srcdir/filemon" "$srcdir/../filemon" "$srcdir/../../sys/dev/filemon" |
| @@ -125,2 +125,3 @@ AC_CHECK_HEADERS( \ |
| sys/mman.h \ |
| + sys/resource.h \ |
| sys/select.h \ |
| @@ -129,2 +130,4 @@ AC_CHECK_HEADERS( \ |
| sys/uio.h \ |
| + sys/utsname.h \ |
| + sys/wait.h \ |
| unistd.h \ |
| @@ -153,2 +156,3 @@ AC_C_BIGENDIAN |
| AC_C_CONST |
| +AC_TYPE_INT32_T |
| AC_TYPE_MODE_T |
| @@ -169,18 +173,109 @@ dnl Keep this list sorted |
| AC_CHECK_FUNCS( \ |
| + _Exit \ |
| + alloca \ |
| + atoll \ |
| + canonicalize_file_name \ |
| + chown \ |
| + dup2 \ |
| + dup3 \ |
| + endusershell \ |
| err \ |
| errx \ |
| + euidaccess \ |
| + faccessat \ |
| + fchdir \ |
| + fchmodat \ |
| + fchownat \ |
| + fcntl \ |
| + fdatasync \ |
| + fstatat \ |
| + fsync \ |
| + ftruncate \ |
| + futimens \ |
| getcwd \ |
| + getdomainname \ |
| + getdtablesize \ |
| getenv \ |
| + getgroups \ |
| + gethostname \ |
| + getloadavg \ |
| + getlogin \ |
| + getlogin_r \ |
| getopt \ |
| + getpass \ |
| + getppid \ |
| + getrusage \ |
| + getsubopt \ |
| + getusershell \ |
| getwd \ |
| + grantpt \ |
| + group_member \ |
| + initstate \ |
| + initstate_r \ |
| + kill \ |
| killpg \ |
| + lchmod \ |
| + lchown \ |
| + link \ |
| + linkat \ |
| + lstat \ |
| + mkdirat \ |
| + mkdtemp \ |
| + mkfifo \ |
| + mkfifoat \ |
| + mknod \ |
| + mknodat \ |
| + mkostemp \ |
| + mkostemps \ |
| + mkstemp \ |
| + mkstemps \ |
| mmap \ |
| + openat \ |
| + pipe \ |
| + pipe2 \ |
| + poll \ |
| + posix_openpt \ |
| + pread \ |
| + pthread_sigmask \ |
| + ptsname \ |
| + ptsname_r \ |
| putenv \ |
| + pwrite \ |
| + qsort_r \ |
| + raise \ |
| + random \ |
| + random_r \ |
| + readlink \ |
| + readlinkat \ |
| + reallocarray \ |
| + realpath \ |
| + regcomp \ |
| + regerror \ |
| + regexec \ |
| + regfree \ |
| + rpmatch \ |
| + secure_getenv \ |
| select \ |
| setenv \ |
| + sethostname \ |
| setpgid \ |
| + setpgrp \ |
| setsid \ |
| + setstate \ |
| + setstate_r \ |
| + setusershell \ |
| sigaction \ |
| + sigaddset \ |
| + sigdelset \ |
| + sigemptyset \ |
| + sigfillset \ |
| + sigismember \ |
| + signal \ |
| + sigpending \ |
| + sigprocmask \ |
| sigvec \ |
| + sleep \ |
| snprintf \ |
| + srandom \ |
| + srandom_r \ |
| strerror \ |
| @@ -190,5 +285,17 @@ AC_CHECK_FUNCS( \ |
| strtol \ |
| + strtoll \ |
| + strtoull \ |
| + symlink \ |
| + symlinkat \ |
| sysctl \ |
| + truncate \ |
| + ttyname_r \ |
| + uname \ |
| + unlinkat \ |
| + unlockpt \ |
| unsetenv \ |
| + usleep \ |
| + utimensat \ |
| vsnprintf \ |
| + wait \ |
| wait3 \ |
| @@ -392,3 +499,3 @@ AC_SUBST(filemon_h) |
| AC_SUBST(_MAKE_VERSION) |
| -AC_OUTPUT(makefile Makefile.config make-bootstrap.sh unit-tests/Makefile) |
| +AC_OUTPUT(Makefile.config make-bootstrap.sh unit-tests/Makefile) |
| |
| diff --git a/dir.c b/dir.c |
| index 0062ac0..8ff040b 100644 |
| --- a/dir.c |
| +++ b/dir.c |
| @@ -139,2 +139,5 @@ __RCSID("$NetBSD: dir.c,v 1.73 2018/07/12 18:03:31 christos Exp $"); |
| #include <sys/stat.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| |
| diff --git a/headers-mingw/fcntl.h b/headers-mingw/fcntl.h |
| new file mode 100644 |
| index 0000000..b63a9d3 |
| --- /dev/null |
| +++ b/headers-mingw/fcntl.h |
| @@ -0,0 +1,244 @@ |
| +/* Like <fcntl.h>, but with non-working flags defined to 0. |
| + |
| + Copyright (C) 2006-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software: you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 3 of the License, or |
| + (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* written by Paul Eggert */ |
| + |
| +/* Normal invocation convention. */ |
| + |
| +#ifndef _GL_FCNTL_H |
| +#define _GL_FCNTL_H |
| + |
| +#ifndef __GLIBC__ /* Avoid namespace pollution on glibc systems. */ |
| +# include <unistd.h> |
| +#endif |
| + |
| +/* Native Windows platforms declare open(), creat() in <io.h>. */ |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +# include <io.h> |
| +#endif |
| + |
| + |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_ARG_NONNULL is copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| + |
| +/* Declare overridden functions. */ |
| + |
| + |
| + |
| +#if !HAVE_FCNTL |
| +extern int fcntl (int fd, int action, ...); |
| +#endif |
| + |
| +#if !HAVE_OPENAT |
| +extern int openat (int fd, char const *file, int flags, /* mode_t mode */ ...); |
| +# endif |
| + |
| + |
| + |
| +/* Fix up the FD_* macros, only known to be missing on mingw. */ |
| + |
| +#ifndef FD_CLOEXEC |
| +# define FD_CLOEXEC 1 |
| +#endif |
| + |
| +/* Fix up the supported F_* macros. Intentionally leave other F_* |
| + macros undefined. Only known to be missing on mingw. */ |
| + |
| +#ifndef F_DUPFD_CLOEXEC |
| +# define F_DUPFD_CLOEXEC 0x40000000 |
| +/* Witness variable: 1 if gnulib defined F_DUPFD_CLOEXEC, 0 otherwise. */ |
| +# define GNULIB_defined_F_DUPFD_CLOEXEC 1 |
| +#else |
| +# define GNULIB_defined_F_DUPFD_CLOEXEC 0 |
| +#endif |
| + |
| +#ifndef F_DUPFD |
| +# define F_DUPFD 1 |
| +#endif |
| + |
| +#ifndef F_GETFD |
| +# define F_GETFD 2 |
| +#endif |
| + |
| +/* Fix up the O_* macros. */ |
| + |
| +#if !defined O_DIRECT && defined O_DIRECTIO |
| +/* Tru64 spells it 'O_DIRECTIO'. */ |
| +# define O_DIRECT O_DIRECTIO |
| +#endif |
| + |
| +#if !defined O_CLOEXEC && defined O_NOINHERIT |
| +/* Mingw spells it 'O_NOINHERIT'. */ |
| +# define O_CLOEXEC O_NOINHERIT |
| +#endif |
| + |
| +#ifndef O_CLOEXEC |
| +# define O_CLOEXEC 0x40000000 /* Try to not collide with system O_* flags. */ |
| +# define GNULIB_defined_O_CLOEXEC 1 |
| +#else |
| +# define GNULIB_defined_O_CLOEXEC 0 |
| +#endif |
| + |
| +#ifndef O_DIRECT |
| +# define O_DIRECT 0 |
| +#endif |
| + |
| +#ifndef O_DIRECTORY |
| +# define O_DIRECTORY 0 |
| +#endif |
| + |
| +#ifndef O_DSYNC |
| +# define O_DSYNC 0 |
| +#endif |
| + |
| +#ifndef O_EXEC |
| +# define O_EXEC O_RDONLY /* This is often close enough in older systems. */ |
| +#endif |
| + |
| +#ifndef O_IGNORE_CTTY |
| +# define O_IGNORE_CTTY 0 |
| +#endif |
| + |
| +#ifndef O_NDELAY |
| +# define O_NDELAY 0 |
| +#endif |
| + |
| +#ifndef O_NOATIME |
| +# define O_NOATIME 0 |
| +#endif |
| + |
| +#ifndef O_NONBLOCK |
| +# define O_NONBLOCK O_NDELAY |
| +#endif |
| + |
| +///* If the gnulib module 'nonblocking' is in use, guarantee a working non-zero |
| +// value of O_NONBLOCK. Otherwise, O_NONBLOCK is defined (above) to O_NDELAY |
| +// or to 0 as fallback. */ |
| +//#if @GNULIB_NONBLOCKING@ |
| +//# if O_NONBLOCK |
| +//# define GNULIB_defined_O_NONBLOCK 0 |
| +//# else |
| +//# define GNULIB_defined_O_NONBLOCK 1 |
| +//# undef O_NONBLOCK |
| +//# define O_NONBLOCK 0x40000000 |
| +//# endif |
| +//#endif |
| + |
| +#ifndef O_NOCTTY |
| +# define O_NOCTTY 0 |
| +#endif |
| + |
| +#ifndef O_NOFOLLOW |
| +# define O_NOFOLLOW 0 |
| +#endif |
| + |
| +#ifndef O_NOLINK |
| +# define O_NOLINK 0 |
| +#endif |
| + |
| +#ifndef O_NOLINKS |
| +# define O_NOLINKS 0 |
| +#endif |
| + |
| +#ifndef O_NOTRANS |
| +# define O_NOTRANS 0 |
| +#endif |
| + |
| +#ifndef O_RSYNC |
| +# define O_RSYNC 0 |
| +#endif |
| + |
| +#ifndef O_SEARCH |
| +# define O_SEARCH O_RDONLY /* This is often close enough in older systems. */ |
| +#endif |
| + |
| +#ifndef O_SYNC |
| +# define O_SYNC 0 |
| +#endif |
| + |
| +#ifndef O_TTY_INIT |
| +# define O_TTY_INIT 0 |
| +#endif |
| + |
| +#if ~O_ACCMODE & (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) |
| +# undef O_ACCMODE |
| +# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH) |
| +#endif |
| + |
| +/* For systems that distinguish between text and binary I/O. |
| + O_BINARY is usually declared in fcntl.h */ |
| +#if !defined O_BINARY && defined _O_BINARY |
| + /* For MSC-compatible compilers. */ |
| +# define O_BINARY _O_BINARY |
| +# define O_TEXT _O_TEXT |
| +#endif |
| + |
| +#if defined __BEOS__ || defined __HAIKU__ |
| + /* BeOS 5 and Haiku have O_BINARY and O_TEXT, but they have no effect. */ |
| +# undef O_BINARY |
| +# undef O_TEXT |
| +#endif |
| + |
| +#ifndef O_BINARY |
| +# define O_BINARY 0 |
| +# define O_TEXT 0 |
| +#endif |
| + |
| +/* Fix up the AT_* macros. */ |
| + |
| +/* Work around a bug in Solaris 9 and 10: AT_FDCWD is positive. Its |
| + value exceeds INT_MAX, so its use as an int doesn't conform to the |
| + C standard, and GCC and Sun C complain in some cases. If the bug |
| + is present, undef AT_FDCWD here, so it can be redefined below. */ |
| +#if 0 < AT_FDCWD && AT_FDCWD == 0xffd19553 |
| +# undef AT_FDCWD |
| +#endif |
| + |
| +/* Use the same bit pattern as Solaris 9, but with the proper |
| + signedness. The bit pattern is important, in case this actually is |
| + Solaris with the above workaround. */ |
| +#ifndef AT_FDCWD |
| +# define AT_FDCWD (-3041965) |
| +#endif |
| + |
| +/* Use the same values as Solaris 9. This shouldn't matter, but |
| + there's no real reason to differ. */ |
| +#ifndef AT_SYMLINK_NOFOLLOW |
| +# define AT_SYMLINK_NOFOLLOW 4096 |
| +#endif |
| + |
| +#ifndef AT_REMOVEDIR |
| +# define AT_REMOVEDIR 1 |
| +#endif |
| + |
| +/* Solaris 9 lacks these two, so just pick unique values. */ |
| +#ifndef AT_SYMLINK_FOLLOW |
| +# define AT_SYMLINK_FOLLOW 2 |
| +#endif |
| + |
| +#ifndef AT_EACCESS |
| +# define AT_EACCESS 4 |
| +#endif |
| + |
| + |
| +#endif /* _@GUARD_PREFIX@_FCNTL_H */ |
| + |
| + |
| diff --git a/headers-mingw/intprops.h b/headers-mingw/intprops.h |
| new file mode 100644 |
| index 0000000..9702aec |
| --- /dev/null |
| +++ b/headers-mingw/intprops.h |
| @@ -0,0 +1,455 @@ |
| +/* intprops.h -- properties of integer types |
| + |
| + Copyright (C) 2001-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software: you can redistribute it and/or modify it |
| + under the terms of the GNU Lesser General Public License as published |
| + by the Free Software Foundation; either version 2.1 of the License, or |
| + (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public License |
| + along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Written by Paul Eggert. */ |
| + |
| +#ifndef _GL_INTPROPS_H |
| +#define _GL_INTPROPS_H |
| + |
| +#include <limits.h> |
| + |
| +/* Return a value with the common real type of E and V and the value of V. |
| + Do not evaluate E. */ |
| +#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v)) |
| + |
| +/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see |
| + <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>. */ |
| +#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v)) |
| + |
| +/* The extra casts in the following macros work around compiler bugs, |
| + e.g., in Cray C 5.0.3.0. */ |
| + |
| +/* True if the arithmetic type T is an integer type. bool counts as |
| + an integer. */ |
| +#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1) |
| + |
| +/* True if the real type T is signed. */ |
| +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) |
| + |
| +/* Return 1 if the real expression E, after promotion, has a |
| + signed or floating type. Do not evaluate E. */ |
| +#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0) |
| + |
| + |
| +/* Minimum and maximum values for integer types and expressions. */ |
| + |
| +/* The width in bits of the integer type or expression T. |
| + Do not evaluate T. |
| + Padding bits are not supported; this is checked at compile-time below. */ |
| +#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) |
| + |
| +/* The maximum and minimum values for the integer type T. */ |
| +#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t)) |
| +#define TYPE_MAXIMUM(t) \ |
| + ((t) (! TYPE_SIGNED (t) \ |
| + ? (t) -1 \ |
| + : ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1))) |
| + |
| +/* The maximum and minimum values for the type of the expression E, |
| + after integer promotion. E is not evaluated. */ |
| +#define _GL_INT_MINIMUM(e) \ |
| + (EXPR_SIGNED (e) \ |
| + ? ~ _GL_SIGNED_INT_MAXIMUM (e) \ |
| + : _GL_INT_CONVERT (e, 0)) |
| +#define _GL_INT_MAXIMUM(e) \ |
| + (EXPR_SIGNED (e) \ |
| + ? _GL_SIGNED_INT_MAXIMUM (e) \ |
| + : _GL_INT_NEGATE_CONVERT (e, 1)) |
| +#define _GL_SIGNED_INT_MAXIMUM(e) \ |
| + (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1) |
| + |
| +/* Work around OpenVMS incompatibility with C99. */ |
| +#if !defined LLONG_MAX && defined __INT64_MAX |
| +# define LLONG_MAX __INT64_MAX |
| +# define LLONG_MIN __INT64_MIN |
| +#endif |
| + |
| +/* This include file assumes that signed types are two's complement without |
| + padding bits; the above macros have undefined behavior otherwise. |
| + If this is a problem for you, please let us know how to fix it for your host. |
| + This assumption is tested by the intprops-tests module. */ |
| + |
| +/* Does the __typeof__ keyword work? This could be done by |
| + 'configure', but for now it's easier to do it by hand. */ |
| +#if (2 <= __GNUC__ \ |
| + || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ |
| + || (0x5110 <= __SUNPRO_C && !__STDC__)) |
| +# define _GL_HAVE___TYPEOF__ 1 |
| +#else |
| +# define _GL_HAVE___TYPEOF__ 0 |
| +#endif |
| + |
| +/* Return 1 if the integer type or expression T might be signed. Return 0 |
| + if it is definitely unsigned. This macro does not evaluate its argument, |
| + and expands to an integer constant expression. */ |
| +#if _GL_HAVE___TYPEOF__ |
| +# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t)) |
| +#else |
| +# define _GL_SIGNED_TYPE_OR_EXPR(t) 1 |
| +#endif |
| + |
| +/* Bound on length of the string representing an unsigned integer |
| + value representable in B bits. log10 (2.0) < 146/485. The |
| + smallest value of B where this bound is not tight is 2621. */ |
| +#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485) |
| + |
| +/* Bound on length of the string representing an integer type or expression T. |
| + Subtract 1 for the sign bit if T is signed, and then add 1 more for |
| + a minus sign if needed. |
| + |
| + Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 0 when its argument is |
| + signed, this macro may overestimate the true bound by one byte when |
| + applied to unsigned types of size 2, 4, 16, ... bytes. */ |
| +#define INT_STRLEN_BOUND(t) \ |
| + (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \ |
| + + _GL_SIGNED_TYPE_OR_EXPR (t)) |
| + |
| +/* Bound on buffer size needed to represent an integer type or expression T, |
| + including the terminating null. */ |
| +#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) |
| + |
| + |
| +/* Range overflow checks. |
| + |
| + The INT_<op>_RANGE_OVERFLOW macros return 1 if the corresponding C |
| + operators might not yield numerically correct answers due to |
| + arithmetic overflow. They do not rely on undefined or |
| + implementation-defined behavior. Their implementations are simple |
| + and straightforward, but they are a bit harder to use than the |
| + INT_<op>_OVERFLOW macros described below. |
| + |
| + Example usage: |
| + |
| + long int i = ...; |
| + long int j = ...; |
| + if (INT_MULTIPLY_RANGE_OVERFLOW (i, j, LONG_MIN, LONG_MAX)) |
| + printf ("multiply would overflow"); |
| + else |
| + printf ("product is %ld", i * j); |
| + |
| + Restrictions on *_RANGE_OVERFLOW macros: |
| + |
| + These macros do not check for all possible numerical problems or |
| + undefined or unspecified behavior: they do not check for division |
| + by zero, for bad shift counts, or for shifting negative numbers. |
| + |
| + These macros may evaluate their arguments zero or multiple times, |
| + so the arguments should not have side effects. The arithmetic |
| + arguments (including the MIN and MAX arguments) must be of the same |
| + integer type after the usual arithmetic conversions, and the type |
| + must have minimum value MIN and maximum MAX. Unsigned types should |
| + use a zero MIN of the proper type. |
| + |
| + These macros are tuned for constant MIN and MAX. For commutative |
| + operations such as A + B, they are also tuned for constant B. */ |
| + |
| +/* Return 1 if A + B would overflow in [MIN,MAX] arithmetic. |
| + See above for restrictions. */ |
| +#define INT_ADD_RANGE_OVERFLOW(a, b, min, max) \ |
| + ((b) < 0 \ |
| + ? (a) < (min) - (b) \ |
| + : (max) - (b) < (a)) |
| + |
| +/* Return 1 if A - B would overflow in [MIN,MAX] arithmetic. |
| + See above for restrictions. */ |
| +#define INT_SUBTRACT_RANGE_OVERFLOW(a, b, min, max) \ |
| + ((b) < 0 \ |
| + ? (max) + (b) < (a) \ |
| + : (a) < (min) + (b)) |
| + |
| +/* Return 1 if - A would overflow in [MIN,MAX] arithmetic. |
| + See above for restrictions. */ |
| +#define INT_NEGATE_RANGE_OVERFLOW(a, min, max) \ |
| + ((min) < 0 \ |
| + ? (a) < - (max) \ |
| + : 0 < (a)) |
| + |
| +/* Return 1 if A * B would overflow in [MIN,MAX] arithmetic. |
| + See above for restrictions. Avoid && and || as they tickle |
| + bugs in Sun C 5.11 2010/08/13 and other compilers; see |
| + <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00401.html>. */ |
| +#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \ |
| + ((b) < 0 \ |
| + ? ((a) < 0 \ |
| + ? (a) < (max) / (b) \ |
| + : (b) == -1 \ |
| + ? 0 \ |
| + : (min) / (b) < (a)) \ |
| + : (b) == 0 \ |
| + ? 0 \ |
| + : ((a) < 0 \ |
| + ? (a) < (min) / (b) \ |
| + : (max) / (b) < (a))) |
| + |
| +/* Return 1 if A / B would overflow in [MIN,MAX] arithmetic. |
| + See above for restrictions. Do not check for division by zero. */ |
| +#define INT_DIVIDE_RANGE_OVERFLOW(a, b, min, max) \ |
| + ((min) < 0 && (b) == -1 && (a) < - (max)) |
| + |
| +/* Return 1 if A % B would overflow in [MIN,MAX] arithmetic. |
| + See above for restrictions. Do not check for division by zero. |
| + Mathematically, % should never overflow, but on x86-like hosts |
| + INT_MIN % -1 traps, and the C standard permits this, so treat this |
| + as an overflow too. */ |
| +#define INT_REMAINDER_RANGE_OVERFLOW(a, b, min, max) \ |
| + INT_DIVIDE_RANGE_OVERFLOW (a, b, min, max) |
| + |
| +/* Return 1 if A << B would overflow in [MIN,MAX] arithmetic. |
| + See above for restrictions. Here, MIN and MAX are for A only, and B need |
| + not be of the same type as the other arguments. The C standard says that |
| + behavior is undefined for shifts unless 0 <= B < wordwidth, and that when |
| + A is negative then A << B has undefined behavior and A >> B has |
| + implementation-defined behavior, but do not check these other |
| + restrictions. */ |
| +#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \ |
| + ((a) < 0 \ |
| + ? (a) < (min) >> (b) \ |
| + : (max) >> (b) < (a)) |
| + |
| +/* True if __builtin_add_overflow (A, B, P) works when P is non-null. */ |
| +#if 5 <= __GNUC__ && !defined __ICC |
| +# define _GL_HAS_BUILTIN_OVERFLOW 1 |
| +#else |
| +# define _GL_HAS_BUILTIN_OVERFLOW 0 |
| +#endif |
| + |
| +/* True if __builtin_add_overflow_p (A, B, C) works. */ |
| +#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__) |
| + |
| +/* The _GL*_OVERFLOW macros have the same restrictions as the |
| + *_RANGE_OVERFLOW macros, except that they do not assume that operands |
| + (e.g., A and B) have the same type as MIN and MAX. Instead, they assume |
| + that the result (e.g., A + B) has that type. */ |
| +#if _GL_HAS_BUILTIN_OVERFLOW_P |
| +# define _GL_ADD_OVERFLOW(a, b, min, max) \ |
| + __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0) |
| +# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ |
| + __builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0) |
| +# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ |
| + __builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0) |
| +#else |
| +# define _GL_ADD_OVERFLOW(a, b, min, max) \ |
| + ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \ |
| + : (a) < 0 ? (b) <= (a) + (b) \ |
| + : (b) < 0 ? (a) <= (a) + (b) \ |
| + : (a) + (b) < (b)) |
| +# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \ |
| + ((min) < 0 ? INT_SUBTRACT_RANGE_OVERFLOW (a, b, min, max) \ |
| + : (a) < 0 ? 1 \ |
| + : (b) < 0 ? (a) - (b) <= (a) \ |
| + : (a) < (b)) |
| +# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \ |
| + (((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \ |
| + || INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max)) |
| +#endif |
| +#define _GL_DIVIDE_OVERFLOW(a, b, min, max) \ |
| + ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ |
| + : (a) < 0 ? (b) <= (a) + (b) - 1 \ |
| + : (b) < 0 && (a) + (b) <= (a)) |
| +#define _GL_REMAINDER_OVERFLOW(a, b, min, max) \ |
| + ((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \ |
| + : (a) < 0 ? (a) % (b) != ((max) - (b) + 1) % (b) \ |
| + : (b) < 0 && ! _GL_UNSIGNED_NEG_MULTIPLE (a, b, max)) |
| + |
| +/* Return a nonzero value if A is a mathematical multiple of B, where |
| + A is unsigned, B is negative, and MAX is the maximum value of A's |
| + type. A's type must be the same as (A % B)'s type. Normally (A % |
| + -B == 0) suffices, but things get tricky if -B would overflow. */ |
| +#define _GL_UNSIGNED_NEG_MULTIPLE(a, b, max) \ |
| + (((b) < -_GL_SIGNED_INT_MAXIMUM (b) \ |
| + ? (_GL_SIGNED_INT_MAXIMUM (b) == (max) \ |
| + ? (a) \ |
| + : (a) % (_GL_INT_CONVERT (a, _GL_SIGNED_INT_MAXIMUM (b)) + 1)) \ |
| + : (a) % - (b)) \ |
| + == 0) |
| + |
| +/* Check for integer overflow, and report low order bits of answer. |
| + |
| + The INT_<op>_OVERFLOW macros return 1 if the corresponding C operators |
| + might not yield numerically correct answers due to arithmetic overflow. |
| + The INT_<op>_WRAPV macros also store the low-order bits of the answer. |
| + These macros work correctly on all known practical hosts, and do not rely |
| + on undefined behavior due to signed arithmetic overflow. |
| + |
| + Example usage, assuming A and B are long int: |
| + |
| + if (INT_MULTIPLY_OVERFLOW (a, b)) |
| + printf ("result would overflow\n"); |
| + else |
| + printf ("result is %ld (no overflow)\n", a * b); |
| + |
| + Example usage with WRAPV flavor: |
| + |
| + long int result; |
| + bool overflow = INT_MULTIPLY_WRAPV (a, b, &result); |
| + printf ("result is %ld (%s)\n", result, |
| + overflow ? "after overflow" : "no overflow"); |
| + |
| + Restrictions on these macros: |
| + |
| + These macros do not check for all possible numerical problems or |
| + undefined or unspecified behavior: they do not check for division |
| + by zero, for bad shift counts, or for shifting negative numbers. |
| + |
| + These macros may evaluate their arguments zero or multiple times, so the |
| + arguments should not have side effects. |
| + |
| + The WRAPV macros are not constant expressions. They support only |
| + +, binary -, and *. The result type must be signed. |
| + |
| + These macros are tuned for their last argument being a constant. |
| + |
| + Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B, |
| + A % B, and A << B would overflow, respectively. */ |
| + |
| +#define INT_ADD_OVERFLOW(a, b) \ |
| + _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW) |
| +#define INT_SUBTRACT_OVERFLOW(a, b) \ |
| + _GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW) |
| +#if _GL_HAS_BUILTIN_OVERFLOW_P |
| +# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a) |
| +#else |
| +# define INT_NEGATE_OVERFLOW(a) \ |
| + INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) |
| +#endif |
| +#define INT_MULTIPLY_OVERFLOW(a, b) \ |
| + _GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW) |
| +#define INT_DIVIDE_OVERFLOW(a, b) \ |
| + _GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW) |
| +#define INT_REMAINDER_OVERFLOW(a, b) \ |
| + _GL_BINARY_OP_OVERFLOW (a, b, _GL_REMAINDER_OVERFLOW) |
| +#define INT_LEFT_SHIFT_OVERFLOW(a, b) \ |
| + INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \ |
| + _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a)) |
| + |
| +/* Return 1 if the expression A <op> B would overflow, |
| + where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test, |
| + assuming MIN and MAX are the minimum and maximum for the result type. |
| + Arguments should be free of side effects. */ |
| +#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \ |
| + op_result_overflow (a, b, \ |
| + _GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \ |
| + _GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b))) |
| + |
| +/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R. |
| + Return 1 if the result overflows. See above for restrictions. */ |
| +#define INT_ADD_WRAPV(a, b, r) \ |
| + _GL_INT_OP_WRAPV (a, b, r, +, __builtin_add_overflow, INT_ADD_OVERFLOW) |
| +#define INT_SUBTRACT_WRAPV(a, b, r) \ |
| + _GL_INT_OP_WRAPV (a, b, r, -, __builtin_sub_overflow, INT_SUBTRACT_OVERFLOW) |
| +#define INT_MULTIPLY_WRAPV(a, b, r) \ |
| + _GL_INT_OP_WRAPV (a, b, r, *, __builtin_mul_overflow, INT_MULTIPLY_OVERFLOW) |
| + |
| +/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See: |
| + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193 |
| + https://llvm.org/bugs/show_bug.cgi?id=25390 |
| + For now, assume all versions of GCC-like compilers generate bogus |
| + warnings for _Generic. This matters only for older compilers that |
| + lack __builtin_add_overflow. */ |
| +#if __GNUC__ |
| +# define _GL__GENERIC_BOGUS 1 |
| +#else |
| +# define _GL__GENERIC_BOGUS 0 |
| +#endif |
| + |
| +/* Store the low-order bits of A <op> B into *R, where OP specifies |
| + the operation. BUILTIN is the builtin operation, and OVERFLOW the |
| + overflow predicate. Return 1 if the result overflows. See above |
| + for restrictions. */ |
| +#if _GL_HAS_BUILTIN_OVERFLOW |
| +# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) builtin (a, b, r) |
| +#elif 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS |
| +# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \ |
| + (_Generic \ |
| + (*(r), \ |
| + signed char: \ |
| + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ |
| + signed char, SCHAR_MIN, SCHAR_MAX), \ |
| + short int: \ |
| + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ |
| + short int, SHRT_MIN, SHRT_MAX), \ |
| + int: \ |
| + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ |
| + int, INT_MIN, INT_MAX), \ |
| + long int: \ |
| + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ |
| + long int, LONG_MIN, LONG_MAX), \ |
| + long long int: \ |
| + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ |
| + long long int, LLONG_MIN, LLONG_MAX))) |
| +#else |
| +# define _GL_INT_OP_WRAPV(a, b, r, op, builtin, overflow) \ |
| + (sizeof *(r) == sizeof (signed char) \ |
| + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ |
| + signed char, SCHAR_MIN, SCHAR_MAX) \ |
| + : sizeof *(r) == sizeof (short int) \ |
| + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ |
| + short int, SHRT_MIN, SHRT_MAX) \ |
| + : sizeof *(r) == sizeof (int) \ |
| + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \ |
| + int, INT_MIN, INT_MAX) \ |
| + : _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow)) |
| +# ifdef LLONG_MAX |
| +# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ |
| + (sizeof *(r) == sizeof (long int) \ |
| + ? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ |
| + long int, LONG_MIN, LONG_MAX) \ |
| + : _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \ |
| + long long int, LLONG_MIN, LLONG_MAX)) |
| +# else |
| +# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \ |
| + _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \ |
| + long int, LONG_MIN, LONG_MAX) |
| +# endif |
| +#endif |
| + |
| +/* Store the low-order bits of A <op> B into *R, where the operation |
| + is given by OP. Use the unsigned type UT for calculation to avoid |
| + overflow problems. *R's type is T, with extrema TMIN and TMAX. |
| + T must be a signed integer type. Return 1 if the result overflows. */ |
| +#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \ |
| + (sizeof ((a) op (b)) < sizeof (t) \ |
| + ? _GL_INT_OP_CALC1 ((t) (a), (t) (b), r, op, overflow, ut, t, tmin, tmax) \ |
| + : _GL_INT_OP_CALC1 (a, b, r, op, overflow, ut, t, tmin, tmax)) |
| +#define _GL_INT_OP_CALC1(a, b, r, op, overflow, ut, t, tmin, tmax) \ |
| + ((overflow (a, b) \ |
| + || (EXPR_SIGNED ((a) op (b)) && ((a) op (b)) < (tmin)) \ |
| + || (tmax) < ((a) op (b))) \ |
| + ? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \ |
| + : (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0)) |
| + |
| +/* Return the low-order bits of A <op> B, where the operation is given |
| + by OP. Use the unsigned type UT for calculation to avoid undefined |
| + behavior on signed integer overflow, and convert the result to type T. |
| + UT is at least as wide as T and is no narrower than unsigned int, |
| + T is two's complement, and there is no padding or trap representations. |
| + Assume that converting UT to T yields the low-order bits, as is |
| + done in all known two's-complement C compilers. E.g., see: |
| + https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html |
| + |
| + According to the C standard, converting UT to T yields an |
| + implementation-defined result or signal for values outside T's |
| + range. However, code that works around this theoretical problem |
| + runs afoul of a compiler bug in Oracle Studio 12.3 x86. See: |
| + https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html |
| + As the compiler bug is real, don't try to work around the |
| + theoretical problem. */ |
| + |
| +#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \ |
| + ((t) ((ut) (a) op (ut) (b))) |
| + |
| +#endif /* _GL_INTPROPS_H */ |
| diff --git a/headers-mingw/langinfo.h b/headers-mingw/langinfo.h |
| new file mode 100644 |
| index 0000000..43244cd |
| --- /dev/null |
| +++ b/headers-mingw/langinfo.h |
| @@ -0,0 +1,139 @@ |
| +/* Substitute for and wrapper around <langinfo.h>. |
| + Copyright (C) 2009-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* |
| + * POSIX <langinfo.h> for platforms that lack it or have an incomplete one. |
| + * <http://www.opengroup.org/onlinepubs/9699919799/basedefs/langinfo.h.html> |
| + */ |
| + |
| +#ifndef _GL_LANGINFO_H |
| +#define _GL_LANGINFO_H |
| + |
| + |
| +/* A platform that lacks <langinfo.h>. */ |
| + |
| +/* Assume that it also lacks <nl_types.h> and the nl_item type. */ |
| +# if !GNULIB_defined_nl_item |
| +typedef int nl_item; |
| +# define GNULIB_defined_nl_item 1 |
| +# endif |
| + |
| +/* nl_langinfo items of the LC_CTYPE category */ |
| +# define CODESET 10000 |
| +/* nl_langinfo items of the LC_NUMERIC category */ |
| +# define RADIXCHAR 10001 |
| +# define DECIMAL_POINT RADIXCHAR |
| +# define THOUSEP 10002 |
| +# define THOUSANDS_SEP THOUSEP |
| +# define GROUPING 10114 |
| +/* nl_langinfo items of the LC_TIME category */ |
| +# define D_T_FMT 10003 |
| +# define D_FMT 10004 |
| +# define T_FMT 10005 |
| +# define T_FMT_AMPM 10006 |
| +# define AM_STR 10007 |
| +# define PM_STR 10008 |
| +# define DAY_1 10009 |
| +# define DAY_2 (DAY_1 + 1) |
| +# define DAY_3 (DAY_1 + 2) |
| +# define DAY_4 (DAY_1 + 3) |
| +# define DAY_5 (DAY_1 + 4) |
| +# define DAY_6 (DAY_1 + 5) |
| +# define DAY_7 (DAY_1 + 6) |
| +# define ABDAY_1 10016 |
| +# define ABDAY_2 (ABDAY_1 + 1) |
| +# define ABDAY_3 (ABDAY_1 + 2) |
| +# define ABDAY_4 (ABDAY_1 + 3) |
| +# define ABDAY_5 (ABDAY_1 + 4) |
| +# define ABDAY_6 (ABDAY_1 + 5) |
| +# define ABDAY_7 (ABDAY_1 + 6) |
| +# define MON_1 10023 |
| +# define MON_2 (MON_1 + 1) |
| +# define MON_3 (MON_1 + 2) |
| +# define MON_4 (MON_1 + 3) |
| +# define MON_5 (MON_1 + 4) |
| +# define MON_6 (MON_1 + 5) |
| +# define MON_7 (MON_1 + 6) |
| +# define MON_8 (MON_1 + 7) |
| +# define MON_9 (MON_1 + 8) |
| +# define MON_10 (MON_1 + 9) |
| +# define MON_11 (MON_1 + 10) |
| +# define MON_12 (MON_1 + 11) |
| +# define ALTMON_1 10200 |
| +# define ALTMON_2 (ALTMON_1 + 1) |
| +# define ALTMON_3 (ALTMON_1 + 2) |
| +# define ALTMON_4 (ALTMON_1 + 3) |
| +# define ALTMON_5 (ALTMON_1 + 4) |
| +# define ALTMON_6 (ALTMON_1 + 5) |
| +# define ALTMON_7 (ALTMON_1 + 6) |
| +# define ALTMON_8 (ALTMON_1 + 7) |
| +# define ALTMON_9 (ALTMON_1 + 8) |
| +# define ALTMON_10 (ALTMON_1 + 9) |
| +# define ALTMON_11 (ALTMON_1 + 10) |
| +# define ALTMON_12 (ALTMON_1 + 11) |
| +# define ABMON_1 10035 |
| +# define ABMON_2 (ABMON_1 + 1) |
| +# define ABMON_3 (ABMON_1 + 2) |
| +# define ABMON_4 (ABMON_1 + 3) |
| +# define ABMON_5 (ABMON_1 + 4) |
| +# define ABMON_6 (ABMON_1 + 5) |
| +# define ABMON_7 (ABMON_1 + 6) |
| +# define ABMON_8 (ABMON_1 + 7) |
| +# define ABMON_9 (ABMON_1 + 8) |
| +# define ABMON_10 (ABMON_1 + 9) |
| +# define ABMON_11 (ABMON_1 + 10) |
| +# define ABMON_12 (ABMON_1 + 11) |
| +# define ERA 10047 |
| +# define ERA_D_FMT 10048 |
| +# define ERA_D_T_FMT 10049 |
| +# define ERA_T_FMT 10050 |
| +# define ALT_DIGITS 10051 |
| +/* nl_langinfo items of the LC_MONETARY category */ |
| +# define CRNCYSTR 10052 |
| +# define CURRENCY_SYMBOL CRNCYSTR |
| +# define INT_CURR_SYMBOL 10100 |
| +# define MON_DECIMAL_POINT 10101 |
| +# define MON_THOUSANDS_SEP 10102 |
| +# define MON_GROUPING 10103 |
| +# define POSITIVE_SIGN 10104 |
| +# define NEGATIVE_SIGN 10105 |
| +# define FRAC_DIGITS 10106 |
| +# define INT_FRAC_DIGITS 10107 |
| +# define P_CS_PRECEDES 10108 |
| +# define N_CS_PRECEDES 10109 |
| +# define P_SEP_BY_SPACE 10110 |
| +# define N_SEP_BY_SPACE 10111 |
| +# define P_SIGN_POSN 10112 |
| +# define N_SIGN_POSN 10113 |
| +/* nl_langinfo items of the LC_MESSAGES category */ |
| +# define YESEXPR 10053 |
| +# define NOEXPR 10054 |
| + |
| + |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| +/* Declare overridden functions. */ |
| + |
| + |
| +/* Return a piece of locale dependent information. |
| + Note: The difference between nl_langinfo (CODESET) and locale_charset () |
| + is that the latter normalizes the encoding names to GNU conventions. */ |
| + |
| +extern char * nl_langinfo (nl_item item); |
| + |
| +#endif /* _GL_LANGINFO_H */ |
| diff --git a/headers-mingw/libc-config.h b/headers-mingw/libc-config.h |
| new file mode 100644 |
| index 0000000..a352393 |
| --- /dev/null |
| +++ b/headers-mingw/libc-config.h |
| @@ -0,0 +1,174 @@ |
| +/* System definitions for code taken from the GNU C Library |
| + |
| + Copyright 2017-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with this program; if not, see |
| + <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Written by Paul Eggert. */ |
| + |
| +/* This is intended to be a good-enough substitute for glibc system |
| + macros like those defined in <sys/cdefs.h>, so that Gnulib code |
| + shared with glibc can do this as the first #include: |
| + |
| + #ifndef _LIBC |
| + # include <libc-config.h> |
| + #endif |
| + |
| + When compiled as part of glibc this is a no-op; when compiled as |
| + part of Gnulib this includes Gnulib's <config.h> and defines macros |
| + that glibc library code would normally assume. */ |
| + |
| +#include <config.h> |
| + |
| +/* On glibc this includes <features.h> and <sys/cdefs.h> and #defines |
| + _FEATURES_H, __WORDSIZE, and __set_errno. On FreeBSD 11 it |
| + includes <sys/cdefs.h> which defines __nonnull. Elsewhere it |
| + is harmless. */ |
| +#include <errno.h> |
| + |
| +/* From glibc <errno.h>. */ |
| +#ifndef __set_errno |
| +# define __set_errno(val) (errno = (val)) |
| +#endif |
| + |
| +/* From glibc <features.h>. */ |
| + |
| +#ifndef __GNUC_PREREQ |
| +# if defined __GNUC__ && defined __GNUC_MINOR__ |
| +# define __GNUC_PREREQ(maj, min) ((maj) < __GNUC__ + ((min) <= __GNUC_MINOR__)) |
| +# else |
| +# define __GNUC_PREREQ(maj, min) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef __glibc_clang_prereq |
| +# if defined __clang_major__ && defined __clang_minor__ |
| +# define __glibc_clang_prereq(maj, min) \ |
| + ((maj) < __clang_major__ + ((min) <= __clang_minor__)) |
| +# else |
| +# define __glibc_clang_prereq(maj, min) 0 |
| +# endif |
| +#endif |
| + |
| + |
| +/* Prepare to include <cdefs.h>, which is our copy of glibc |
| + <sys/cdefs.h>. */ |
| + |
| +/* Define _FEATURES_H so that <cdefs.h> does not include <features.h>. */ |
| +#ifndef _FEATURES_H |
| +# define _FEATURES_H 1 |
| +#endif |
| +/* Define __WORDSIZE so that <cdefs.h> does not attempt to include |
| + nonexistent files. Make it a syntax error, since Gnulib does not |
| + use __WORDSIZE now, and if Gnulib uses it later the syntax error |
| + will let us know that __WORDSIZE needs configuring. */ |
| +#ifndef __WORDSIZE |
| +# define __WORDSIZE %%% |
| +#endif |
| +/* Undef the macros unconditionally defined by our copy of glibc |
| + <sys/cdefs.h>, so that they do not clash with any system-defined |
| + versions. */ |
| +#undef _SYS_CDEFS_H |
| +#undef __ASMNAME |
| +#undef __ASMNAME2 |
| +#undef __BEGIN_DECLS |
| +#undef __CONCAT |
| +#undef __END_DECLS |
| +#undef __HAVE_GENERIC_SELECTION |
| +#undef __LDBL_COMPAT |
| +#undef __LDBL_REDIR |
| +#undef __LDBL_REDIR1 |
| +#undef __LDBL_REDIR1_DECL |
| +#undef __LDBL_REDIR1_NTH |
| +#undef __LDBL_REDIR_DECL |
| +#undef __LDBL_REDIR_NTH |
| +#undef __LEAF |
| +#undef __LEAF_ATTR |
| +#undef __NTH |
| +#undef __NTHNL |
| +#undef __P |
| +#undef __PMT |
| +#undef __REDIRECT |
| +#undef __REDIRECT_LDBL |
| +#undef __REDIRECT_NTH |
| +#undef __REDIRECT_NTHNL |
| +#undef __REDIRECT_NTH_LDBL |
| +#undef __STRING |
| +#undef __THROW |
| +#undef __THROWNL |
| +#undef __always_inline |
| +#undef __attribute__ |
| +#undef __attribute_alloc_size__ |
| +#undef __attribute_artificial__ |
| +#undef __attribute_const__ |
| +#undef __attribute_deprecated__ |
| +#undef __attribute_deprecated_msg__ |
| +#undef __attribute_format_arg__ |
| +#undef __attribute_format_strfmon__ |
| +#undef __attribute_malloc__ |
| +#undef __attribute_noinline__ |
| +#undef __attribute_nonstring__ |
| +#undef __attribute_pure__ |
| +#undef __attribute_used__ |
| +#undef __attribute_warn_unused_result__ |
| +#undef __bos |
| +#undef __bos0 |
| +#undef __errordecl |
| +#undef __extension__ |
| +#undef __extern_always_inline |
| +#undef __extern_inline |
| +#undef __flexarr |
| +#undef __fortify_function |
| +#undef __glibc_c99_flexarr_available |
| +#undef __glibc_clang_has_extension |
| +#undef __glibc_likely |
| +#undef __glibc_macro_warning |
| +#undef __glibc_macro_warning1 |
| +#undef __glibc_unlikely |
| +#undef __inline |
| +#undef __ptr_t |
| +#undef __restrict |
| +#undef __restrict_arr |
| +#undef __va_arg_pack |
| +#undef __va_arg_pack_len |
| +#undef __warnattr |
| +#undef __warndecl |
| + |
| +/* Include our copy of glibc <sys/cdefs.h>. */ |
| +#include "sys_cdefs.h" |
| + |
| +/* <cdefs.h> __inline is too pessimistic for non-GCC. */ |
| +#undef __inline |
| +#ifndef HAVE___INLINE |
| +# if 199901 <= __STDC_VERSION__ || defined inline |
| +# define __inline inline |
| +# else |
| +# define __inline |
| +# endif |
| +#endif |
| + |
| + |
| +/* A substitute for glibc <libc-symbols.h>, good enough for Gnulib. */ |
| +#define attribute_hidden |
| +#define libc_hidden_proto(name, ...) |
| +#define libc_hidden_def(name) |
| +#define libc_hidden_weak(name) |
| +#define libc_hidden_ver(local, name) |
| +#define strong_alias(name, aliasname) |
| +#define weak_alias(name, aliasname) |
| + |
| +/* A substitute for glibc <shlib-compat.h>, good enough for Gnulib. */ |
| +#define SHLIB_COMPAT(lib, introduced, obsoleted) 0 |
| +#define versioned_symbol(lib, local, symbol, version) |
| diff --git a/headers-mingw/poll.h b/headers-mingw/poll.h |
| new file mode 100644 |
| index 0000000..fd3fb64 |
| --- /dev/null |
| +++ b/headers-mingw/poll.h |
| @@ -0,0 +1,76 @@ |
| +/* Header for poll(2) emulation |
| + Contributed by Paolo Bonzini. |
| + |
| + Copyright 2001-2003, 2007, 2009-2018 Free Software Foundation, Inc. |
| + |
| + This file is part of gnulib. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License along |
| + with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef _GL_POLL_H |
| + |
| +#define _GL_POLL_H |
| + |
| + |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| + |
| +#if !HAVE_POLL_H |
| + |
| +/* fake a poll(2) environment */ |
| +# define POLLIN 0x0001 /* any readable data available */ |
| +# define POLLPRI 0x0002 /* OOB/Urgent readable data */ |
| +# define POLLOUT 0x0004 /* file descriptor is writable */ |
| +# define POLLERR 0x0008 /* some poll error occurred */ |
| +# define POLLHUP 0x0010 /* file descriptor was "hung up" */ |
| +# define POLLNVAL 0x0020 /* requested events "invalid" */ |
| +# define POLLRDNORM 0x0040 |
| +# define POLLRDBAND 0x0080 |
| +# define POLLWRNORM 0x0100 |
| +# define POLLWRBAND 0x0200 |
| + |
| +# if !GNULIB_defined_poll_types |
| +# if !(defined _WIN32 && ! defined __CYGWIN__) |
| +struct pollfd |
| +{ |
| + int fd; /* which file descriptor to poll */ |
| + short events; /* events we are interested in */ |
| + short revents; /* events found on return */ |
| +}; |
| + |
| +# else |
| +#include <winsock2.h> |
| +# endif |
| + |
| +typedef unsigned long nfds_t; |
| + |
| +# define GNULIB_defined_poll_types 1 |
| +# endif |
| + |
| +/* Define INFTIM only if doing so conforms to POSIX. */ |
| +# if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE) |
| +# define INFTIM (-1) |
| +# endif |
| + |
| +#endif |
| + |
| + |
| +# if !HAVE_POLL |
| +extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout); |
| +#endif |
| + |
| + |
| +#endif /* _@GUARD_PREFIX@_POLL_H */ |
| diff --git a/headers-mingw/regex.h b/headers-mingw/regex.h |
| new file mode 100644 |
| index 0000000..8d8160f |
| --- /dev/null |
| +++ b/headers-mingw/regex.h |
| @@ -0,0 +1,635 @@ |
| +/* Definitions for data structures and routines for the regular |
| + expression library. |
| + Copyright (C) 1985, 1989-2018 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, see |
| + <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef _REGEX_H |
| +#define _REGEX_H 1 |
| + |
| +#include <sys/types.h> |
| + |
| +/* Allow the use in C++ code. */ |
| +#ifdef __cplusplus |
| +extern "C" { |
| +#endif |
| + |
| +/* Define __USE_GNU to declare GNU extensions that violate the |
| + POSIX name space rules. */ |
| +#ifdef _GNU_SOURCE |
| +# define __USE_GNU 1 |
| +#endif |
| + |
| +#ifdef _REGEX_LARGE_OFFSETS |
| + |
| +/* Use types and values that are wide enough to represent signed and |
| + unsigned byte offsets in memory. This currently works only when |
| + the regex code is used outside of the GNU C library; it is not yet |
| + supported within glibc itself, and glibc users should not define |
| + _REGEX_LARGE_OFFSETS. */ |
| + |
| +/* The type of object sizes. */ |
| +typedef size_t __re_size_t; |
| + |
| +/* The type of object sizes, in places where the traditional code |
| + uses unsigned long int. */ |
| +typedef size_t __re_long_size_t; |
| + |
| +#else |
| + |
| +/* The traditional GNU regex implementation mishandles strings longer |
| + than INT_MAX. */ |
| +typedef unsigned int __re_size_t; |
| +typedef unsigned long int __re_long_size_t; |
| + |
| +#endif |
| + |
| +/* The following two types have to be signed and unsigned integer type |
| + wide enough to hold a value of a pointer. For most ANSI compilers |
| + ptrdiff_t and size_t should be likely OK. Still size of these two |
| + types is 2 for Microsoft C. Ugh... */ |
| +typedef long int s_reg_t; |
| +typedef unsigned long int active_reg_t; |
| + |
| +/* The following bits are used to determine the regexp syntax we |
| + recognize. The set/not-set meanings are chosen so that Emacs syntax |
| + remains the value 0. The bits are given in alphabetical order, and |
| + the definitions shifted by one from the previous bit; thus, when we |
| + add or remove a bit, only one other definition need change. */ |
| +typedef unsigned long int reg_syntax_t; |
| + |
| +/* If this bit is not set, then \ inside a bracket expression is literal. |
| + If set, then such a \ quotes the following character. */ |
| +# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) |
| + |
| +/* If this bit is not set, then + and ? are operators, and \+ and \? are |
| + literals. |
| + If set, then \+ and \? are operators and + and ? are literals. */ |
| +# define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) |
| + |
| +/* If this bit is set, then character classes are supported. They are: |
| + [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], |
| + [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. |
| + If not set, then character classes are not supported. */ |
| +# define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) |
| + |
| +/* If this bit is set, then ^ and $ are always anchors (outside bracket |
| + expressions, of course). |
| + If this bit is not set, then it depends: |
| + ^ is an anchor if it is at the beginning of a regular |
| + expression or after an open-group or an alternation operator; |
| + $ is an anchor if it is at the end of a regular expression, or |
| + before a close-group or an alternation operator. |
| + |
| + This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because |
| + POSIX draft 11.2 says that * etc. in leading positions is undefined. |
| + We already implemented a previous draft which made those constructs |
| + invalid, though, so we haven't changed the code back. */ |
| +# define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) |
| + |
| +/* If this bit is set, then special characters are always special |
| + regardless of where they are in the pattern. |
| + If this bit is not set, then special characters are special only in |
| + some contexts; otherwise they are ordinary. Specifically, |
| + * + ? and intervals are only special when not after the beginning, |
| + open-group, or alternation operator. */ |
| +# define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) |
| + |
| +/* If this bit is set, then *, +, ?, and { cannot be first in an re or |
| + immediately after an alternation or begin-group operator. */ |
| +# define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) |
| + |
| +/* If this bit is set, then . matches newline. |
| + If not set, then it doesn't. */ |
| +# define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) |
| + |
| +/* If this bit is set, then . doesn't match NUL. |
| + If not set, then it does. */ |
| +# define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) |
| + |
| +/* If this bit is set, nonmatching lists [^...] do not match newline. |
| + If not set, they do. */ |
| +# define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) |
| + |
| +/* If this bit is set, either \{...\} or {...} defines an |
| + interval, depending on RE_NO_BK_BRACES. |
| + If not set, \{, \}, {, and } are literals. */ |
| +# define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) |
| + |
| +/* If this bit is set, +, ? and | aren't recognized as operators. |
| + If not set, they are. */ |
| +# define RE_LIMITED_OPS (RE_INTERVALS << 1) |
| + |
| +/* If this bit is set, newline is an alternation operator. |
| + If not set, newline is literal. */ |
| +# define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) |
| + |
| +/* If this bit is set, then '{...}' defines an interval, and \{ and \} |
| + are literals. |
| + If not set, then '\{...\}' defines an interval. */ |
| +# define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) |
| + |
| +/* If this bit is set, (...) defines a group, and \( and \) are literals. |
| + If not set, \(...\) defines a group, and ( and ) are literals. */ |
| +# define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) |
| + |
| +/* If this bit is set, then \<digit> matches <digit>. |
| + If not set, then \<digit> is a back-reference. */ |
| +# define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) |
| + |
| +/* If this bit is set, then | is an alternation operator, and \| is literal. |
| + If not set, then \| is an alternation operator, and | is literal. */ |
| +# define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) |
| + |
| +/* If this bit is set, then an ending range point collating higher |
| + than the starting range point, as in [z-a], is invalid. |
| + If not set, then when ending range point collates higher than the |
| + starting range point, the range is ignored. */ |
| +# define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) |
| + |
| +/* If this bit is set, then an unmatched ) is ordinary. |
| + If not set, then an unmatched ) is invalid. */ |
| +# define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) |
| + |
| +/* If this bit is set, succeed as soon as we match the whole pattern, |
| + without further backtracking. */ |
| +# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) |
| + |
| +/* If this bit is set, do not process the GNU regex operators. |
| + If not set, then the GNU regex operators are recognized. */ |
| +# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) |
| + |
| +/* If this bit is set, turn on internal regex debugging. |
| + If not set, and debugging was on, turn it off. |
| + This only works if regex.c is compiled -DDEBUG. |
| + We define this bit always, so that all that's needed to turn on |
| + debugging is to recompile regex.c; the calling code can always have |
| + this bit set, and it won't affect anything in the normal case. */ |
| +# define RE_DEBUG (RE_NO_GNU_OPS << 1) |
| + |
| +/* If this bit is set, a syntactically invalid interval is treated as |
| + a string of ordinary characters. For example, the ERE 'a{1' is |
| + treated as 'a\{1'. */ |
| +# define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) |
| + |
| +/* If this bit is set, then ignore case when matching. |
| + If not set, then case is significant. */ |
| +# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) |
| + |
| +/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only |
| + for ^, because it is difficult to scan the regex backwards to find |
| + whether ^ should be special. */ |
| +# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) |
| + |
| +/* If this bit is set, then \{ cannot be first in a regex or |
| + immediately after an alternation, open-group or \} operator. */ |
| +# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) |
| + |
| +/* If this bit is set, then no_sub will be set to 1 during |
| + re_compile_pattern. */ |
| +# define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1) |
| + |
| + |
| +/* This global variable defines the particular regexp syntax to use (for |
| + some interfaces). When a regexp is compiled, the syntax used is |
| + stored in the pattern buffer, so changing this does not affect |
| + already-compiled regexps. */ |
| +extern reg_syntax_t re_syntax_options; |
| + |
| + |
| +/* Define combinations of the above bits for the standard possibilities. |
| + (The [[[ comments delimit what gets put into the Texinfo file, so |
| + don't delete them!) */ |
| +/* [[[begin syntaxes]]] */ |
| +# define RE_SYNTAX_EMACS 0 |
| + |
| +# define RE_SYNTAX_AWK \ |
| + (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ |
| + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ |
| + | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ |
| + | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ |
| + | RE_CHAR_CLASSES \ |
| + | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) |
| + |
| +# define RE_SYNTAX_GNU_AWK \ |
| + ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ |
| + | RE_INVALID_INTERVAL_ORD) \ |
| + & ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \ |
| + | RE_CONTEXT_INVALID_OPS )) |
| + |
| +# define RE_SYNTAX_POSIX_AWK \ |
| + (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ |
| + | RE_INTERVALS | RE_NO_GNU_OPS \ |
| + | RE_INVALID_INTERVAL_ORD) |
| + |
| +# define RE_SYNTAX_GREP \ |
| + ((RE_SYNTAX_POSIX_BASIC | RE_NEWLINE_ALT) \ |
| + & ~(RE_CONTEXT_INVALID_DUP | RE_DOT_NOT_NULL)) |
| + |
| +# define RE_SYNTAX_EGREP \ |
| + ((RE_SYNTAX_POSIX_EXTENDED | RE_INVALID_INTERVAL_ORD | RE_NEWLINE_ALT) \ |
| + & ~(RE_CONTEXT_INVALID_OPS | RE_DOT_NOT_NULL)) |
| + |
| +/* POSIX grep -E behavior is no longer incompatible with GNU. */ |
| +# define RE_SYNTAX_POSIX_EGREP \ |
| + RE_SYNTAX_EGREP |
| + |
| +/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ |
| +# define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC |
| + |
| +# define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC |
| + |
| +/* Syntax bits common to both basic and extended POSIX regex syntax. */ |
| +# define _RE_SYNTAX_POSIX_COMMON \ |
| + (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ |
| + | RE_INTERVALS | RE_NO_EMPTY_RANGES) |
| + |
| +# define RE_SYNTAX_POSIX_BASIC \ |
| + (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP) |
| + |
| +/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes |
| + RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this |
| + isn't minimal, since other operators, such as \`, aren't disabled. */ |
| +# define RE_SYNTAX_POSIX_MINIMAL_BASIC \ |
| + (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) |
| + |
| +# define RE_SYNTAX_POSIX_EXTENDED \ |
| + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ |
| + | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ |
| + | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ |
| + | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) |
| + |
| +/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is |
| + removed and RE_NO_BK_REFS is added. */ |
| +# define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ |
| + (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ |
| + | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ |
| + | RE_NO_BK_PARENS | RE_NO_BK_REFS \ |
| + | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) |
| +/* [[[end syntaxes]]] */ |
| + |
| + |
| +/* RE_DUP_MAX is 2**15 - 1 because an earlier implementation stored |
| + the counter as a 2-byte signed integer. This is no longer true, so |
| + RE_DUP_MAX could be increased to (INT_MAX / 10 - 1), or to |
| + ((SIZE_MAX - 9) / 10) if _REGEX_LARGE_OFFSETS is defined. |
| + However, there would be a huge performance problem if someone |
| + actually used a pattern like a\{214748363\}, so RE_DUP_MAX retains |
| + its historical value. */ |
| +# define RE_DUP_MAX (0x7fff) |
| + |
| + |
| + |
| +/* POSIX 'cflags' bits (i.e., information for 'regcomp'). */ |
| + |
| +/* If this bit is set, then use extended regular expression syntax. |
| + If not set, then use basic regular expression syntax. */ |
| +#define REG_EXTENDED 1 |
| + |
| +/* If this bit is set, then ignore case when matching. |
| + If not set, then case is significant. */ |
| +#define REG_ICASE (1 << 1) |
| + |
| +/* If this bit is set, then anchors do not match at newline |
| + characters in the string. |
| + If not set, then anchors do match at newlines. */ |
| +#define REG_NEWLINE (1 << 2) |
| + |
| +/* If this bit is set, then report only success or fail in regexec. |
| + If not set, then returns differ between not matching and errors. */ |
| +#define REG_NOSUB (1 << 3) |
| + |
| + |
| +/* POSIX 'eflags' bits (i.e., information for regexec). */ |
| + |
| +/* If this bit is set, then the beginning-of-line operator doesn't match |
| + the beginning of the string (presumably because it's not the |
| + beginning of a line). |
| + If not set, then the beginning-of-line operator does match the |
| + beginning of the string. */ |
| +#define REG_NOTBOL 1 |
| + |
| +/* Like REG_NOTBOL, except for the end-of-line. */ |
| +#define REG_NOTEOL (1 << 1) |
| + |
| +/* Use PMATCH[0] to delimit the start and end of the search in the |
| + buffer. */ |
| +#define REG_STARTEND (1 << 2) |
| + |
| + |
| +/* If any error codes are removed, changed, or added, update the |
| + '__re_error_msgid' table in regcomp.c. */ |
| + |
| +typedef enum |
| +{ |
| + _REG_ENOSYS = -1, /* This will never happen for this implementation. */ |
| + _REG_NOERROR = 0, /* Success. */ |
| + _REG_NOMATCH, /* Didn't find a match (for regexec). */ |
| + |
| + /* POSIX regcomp return error codes. (In the order listed in the |
| + standard.) */ |
| + _REG_BADPAT, /* Invalid pattern. */ |
| + _REG_ECOLLATE, /* Invalid collating element. */ |
| + _REG_ECTYPE, /* Invalid character class name. */ |
| + _REG_EESCAPE, /* Trailing backslash. */ |
| + _REG_ESUBREG, /* Invalid back reference. */ |
| + _REG_EBRACK, /* Unmatched left bracket. */ |
| + _REG_EPAREN, /* Parenthesis imbalance. */ |
| + _REG_EBRACE, /* Unmatched \{. */ |
| + _REG_BADBR, /* Invalid contents of \{\}. */ |
| + _REG_ERANGE, /* Invalid range end. */ |
| + _REG_ESPACE, /* Ran out of memory. */ |
| + _REG_BADRPT, /* No preceding re for repetition op. */ |
| + |
| + /* Error codes we've added. */ |
| + _REG_EEND, /* Premature end. */ |
| + _REG_ESIZE, /* Too large (e.g., repeat count too large). */ |
| + _REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ |
| +} reg_errcode_t; |
| + |
| +#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K |
| +# define REG_ENOSYS _REG_ENOSYS |
| +#endif |
| +#define REG_NOERROR _REG_NOERROR |
| +#define REG_NOMATCH _REG_NOMATCH |
| +#define REG_BADPAT _REG_BADPAT |
| +#define REG_ECOLLATE _REG_ECOLLATE |
| +#define REG_ECTYPE _REG_ECTYPE |
| +#define REG_EESCAPE _REG_EESCAPE |
| +#define REG_ESUBREG _REG_ESUBREG |
| +#define REG_EBRACK _REG_EBRACK |
| +#define REG_EPAREN _REG_EPAREN |
| +#define REG_EBRACE _REG_EBRACE |
| +#define REG_BADBR _REG_BADBR |
| +#define REG_ERANGE _REG_ERANGE |
| +#define REG_ESPACE _REG_ESPACE |
| +#define REG_BADRPT _REG_BADRPT |
| +#define REG_EEND _REG_EEND |
| +#define REG_ESIZE _REG_ESIZE |
| +#define REG_ERPAREN _REG_ERPAREN |
| + |
| +/* This data structure represents a compiled pattern. Before calling |
| + the pattern compiler, the fields 'buffer', 'allocated', 'fastmap', |
| + and 'translate' can be set. After the pattern has been compiled, |
| + the fields 're_nsub', 'not_bol' and 'not_eol' are available. All |
| + other fields are private to the regex routines. */ |
| + |
| +#ifndef RE_TRANSLATE_TYPE |
| +# define __RE_TRANSLATE_TYPE unsigned char * |
| + |
| +# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE |
| + |
| +#endif |
| + |
| +# define __REPB_PREFIX(name) name |
| + |
| +struct re_pattern_buffer |
| +{ |
| + /* Space that holds the compiled pattern. The type |
| + 'struct re_dfa_t' is private and is not declared here. */ |
| + struct re_dfa_t *__REPB_PREFIX(buffer); |
| + |
| + /* Number of bytes to which 'buffer' points. */ |
| + __re_long_size_t __REPB_PREFIX(allocated); |
| + |
| + /* Number of bytes actually used in 'buffer'. */ |
| + __re_long_size_t __REPB_PREFIX(used); |
| + |
| + /* Syntax setting with which the pattern was compiled. */ |
| + reg_syntax_t __REPB_PREFIX(syntax); |
| + |
| + /* Pointer to a fastmap, if any, otherwise zero. re_search uses the |
| + fastmap, if there is one, to skip over impossible starting points |
| + for matches. */ |
| + char *__REPB_PREFIX(fastmap); |
| + |
| + /* Either a translate table to apply to all characters before |
| + comparing them, or zero for no translation. The translation is |
| + applied to a pattern when it is compiled and to a string when it |
| + is matched. */ |
| + __RE_TRANSLATE_TYPE __REPB_PREFIX(translate); |
| + |
| + /* Number of subexpressions found by the compiler. */ |
| + size_t re_nsub; |
| + |
| + /* Zero if this pattern cannot match the empty string, one else. |
| + Well, in truth it's used only in 're_search_2', to see whether or |
| + not we should use the fastmap, so we don't set this absolutely |
| + perfectly; see 're_compile_fastmap' (the "duplicate" case). */ |
| + unsigned __REPB_PREFIX(can_be_null) : 1; |
| + |
| + /* If REGS_UNALLOCATED, allocate space in the 'regs' structure |
| + for 'max (RE_NREGS, re_nsub + 1)' groups. |
| + If REGS_REALLOCATE, reallocate space if necessary. |
| + If REGS_FIXED, use what's there. */ |
| + |
| +# define REGS_UNALLOCATED 0 |
| +# define REGS_REALLOCATE 1 |
| +# define REGS_FIXED 2 |
| + |
| + unsigned __REPB_PREFIX(regs_allocated) : 2; |
| + |
| + /* Set to zero when 're_compile_pattern' compiles a pattern; set to |
| + one by 're_compile_fastmap' if it updates the fastmap. */ |
| + unsigned __REPB_PREFIX(fastmap_accurate) : 1; |
| + |
| + /* If set, 're_match_2' does not return information about |
| + subexpressions. */ |
| + unsigned __REPB_PREFIX(no_sub) : 1; |
| + |
| + /* If set, a beginning-of-line anchor doesn't match at the beginning |
| + of the string. */ |
| + unsigned __REPB_PREFIX(not_bol) : 1; |
| + |
| + /* Similarly for an end-of-line anchor. */ |
| + unsigned __REPB_PREFIX(not_eol) : 1; |
| + |
| + /* If true, an anchor at a newline matches. */ |
| + unsigned __REPB_PREFIX(newline_anchor) : 1; |
| +}; |
| + |
| +typedef struct re_pattern_buffer regex_t; |
| + |
| +/* Type for byte offsets within the string. POSIX mandates this. */ |
| +#ifdef _REGEX_LARGE_OFFSETS |
| +/* POSIX 1003.1-2008 requires that regoff_t be at least as wide as |
| + ptrdiff_t and ssize_t. We don't know of any hosts where ptrdiff_t |
| + is wider than ssize_t, so ssize_t is safe. ptrdiff_t is not |
| + visible here, so use ssize_t. */ |
| +typedef ssize_t regoff_t; |
| +#else |
| +/* The traditional GNU regex implementation mishandles strings longer |
| + than INT_MAX. */ |
| +typedef int regoff_t; |
| +#endif |
| + |
| + |
| + |
| +/* This is the structure we store register match data in. See |
| + regex.texinfo for a full description of what registers match. */ |
| +struct re_registers |
| +{ |
| + __re_size_t num_regs; |
| + regoff_t *start; |
| + regoff_t *end; |
| +}; |
| + |
| + |
| +/* If 'regs_allocated' is REGS_UNALLOCATED in the pattern buffer, |
| + 're_match_2' returns information about at least this many registers |
| + the first time a 'regs' structure is passed. */ |
| +# ifndef RE_NREGS |
| +# define RE_NREGS 30 |
| +# endif |
| + |
| + |
| + |
| +/* POSIX specification for registers. Aside from the different names than |
| + 're_registers', POSIX uses an array of structures, instead of a |
| + structure of arrays. */ |
| +typedef struct |
| +{ |
| + regoff_t rm_so; /* Byte offset from string's start to substring's start. */ |
| + regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ |
| +} regmatch_t; |
| + |
| +/* Declarations for routines. */ |
| + |
| + |
| +/* Sets the current default syntax to SYNTAX, and return the old syntax. |
| + You can also simply assign to the 're_syntax_options' variable. */ |
| +extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax); |
| + |
| +/* Compile the regular expression PATTERN, with length LENGTH |
| + and syntax given by the global 're_syntax_options', into the buffer |
| + BUFFER. Return NULL if successful, and an error string if not. |
| + |
| + To free the allocated storage, you must call 'regfree' on BUFFER. |
| + Note that the translate table must either have been initialized by |
| + 'regcomp', with a malloc'ed value, or set to NULL before calling |
| + 'regfree'. */ |
| +extern const char *re_compile_pattern (const char *__pattern, size_t __length, |
| + struct re_pattern_buffer *__buffer); |
| + |
| + |
| +/* Compile a fastmap for the compiled pattern in BUFFER; used to |
| + accelerate searches. Return 0 if successful and -2 if was an |
| + internal error. */ |
| +extern int re_compile_fastmap (struct re_pattern_buffer *__buffer); |
| + |
| + |
| +/* Search in the string STRING (with length LENGTH) for the pattern |
| + compiled into BUFFER. Start searching at position START, for RANGE |
| + characters. Return the starting position of the match, -1 for no |
| + match, or -2 for an internal error. Also return register |
| + information in REGS (if REGS and BUFFER->no_sub are nonzero). */ |
| +extern regoff_t re_search (struct re_pattern_buffer *__buffer, |
| + const char *__String, regoff_t __length, |
| + regoff_t __start, regoff_t __range, |
| + struct re_registers *__regs); |
| + |
| + |
| +/* Like 're_search', but search in the concatenation of STRING1 and |
| + STRING2. Also, stop searching at index START + STOP. */ |
| +extern regoff_t re_search_2 (struct re_pattern_buffer *__buffer, |
| + const char *__string1, regoff_t __length1, |
| + const char *__string2, regoff_t __length2, |
| + regoff_t __start, regoff_t __range, |
| + struct re_registers *__regs, |
| + regoff_t __stop); |
| + |
| + |
| +/* Like 're_search', but return how many characters in STRING the regexp |
| + in BUFFER matched, starting at position START. */ |
| +extern regoff_t re_match (struct re_pattern_buffer *__buffer, |
| + const char *__String, regoff_t __length, |
| + regoff_t __start, struct re_registers *__regs); |
| + |
| + |
| +/* Relates to 're_match' as 're_search_2' relates to 're_search'. */ |
| +extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer, |
| + const char *__string1, regoff_t __length1, |
| + const char *__string2, regoff_t __length2, |
| + regoff_t __start, struct re_registers *__regs, |
| + regoff_t __stop); |
| + |
| + |
| +/* Set REGS to hold NUM_REGS registers, storing them in STARTS and |
| + ENDS. Subsequent matches using BUFFER and REGS will use this memory |
| + for recording register information. STARTS and ENDS must be |
| + allocated with malloc, and must each be at least 'NUM_REGS * sizeof |
| + (regoff_t)' bytes long. |
| + |
| + If NUM_REGS == 0, then subsequent matches should allocate their own |
| + register data. |
| + |
| + Unless this function is called, the first search or match using |
| + BUFFER will allocate its own register data, without |
| + freeing the old data. */ |
| +extern void re_set_registers (struct re_pattern_buffer *__buffer, |
| + struct re_registers *__regs, |
| + __re_size_t __num_regs, |
| + regoff_t *__starts, regoff_t *__ends); |
| + |
| +/* For plain 'restrict', use glibc's __restrict if defined. |
| + Otherwise, GCC 2.95 and later have "__restrict"; C99 compilers have |
| + "restrict", and "configure" may have defined "restrict". |
| + Other compilers use __restrict, __restrict__, and _Restrict, and |
| + 'configure' might #define 'restrict' to those words, so pick a |
| + different name. */ |
| +#ifndef _Restrict_ |
| +# if defined __restrict || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) |
| +# define _Restrict_ __restrict |
| +# elif 199901L <= __STDC_VERSION__ || defined restrict |
| +# define _Restrict_ restrict |
| +# else |
| +# define _Restrict_ |
| +# endif |
| +#endif |
| +/* For [restrict], use glibc's __restrict_arr if available. |
| + Otherwise, GCC 3.1 (not in C++ mode) and C99 support [restrict]. */ |
| +#ifndef _Restrict_arr_ |
| +# ifdef __restrict_arr |
| +# define _Restrict_arr_ __restrict_arr |
| +# elif ((199901L <= __STDC_VERSION__ || 3 < __GNUC__ + (1 <= __GNUC_MINOR__)) \ |
| + && !defined __GNUG__) |
| +# define _Restrict_arr_ _Restrict_ |
| +# else |
| +# define _Restrict_arr_ |
| +# endif |
| +#endif |
| + |
| +/* POSIX compatibility. */ |
| +extern int regcomp (regex_t *_Restrict_ __preg, |
| + const char *_Restrict_ __pattern, |
| + int __cflags); |
| + |
| +extern int regexec (const regex_t *_Restrict_ __preg, |
| + const char *_Restrict_ __String, size_t __nmatch, |
| + regmatch_t __pmatch[_Restrict_arr_], |
| + int __eflags); |
| + |
| +extern size_t regerror (int __errcode, const regex_t *_Restrict_ __preg, |
| + char *_Restrict_ __errbuf, size_t __errbuf_size); |
| + |
| +extern void regfree (regex_t *__preg); |
| + |
| + |
| +#ifdef __cplusplus |
| +} |
| +#endif /* C++ */ |
| + |
| +#endif /* regex.h */ |
| diff --git a/headers-mingw/regex_internal.h b/headers-mingw/regex_internal.h |
| new file mode 100644 |
| index 0000000..b4ae872 |
| --- /dev/null |
| +++ b/headers-mingw/regex_internal.h |
| @@ -0,0 +1,780 @@ |
| +/* Extended regular expression matching and search library. |
| + Copyright (C) 2002-2018 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, see |
| + <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef _REGEX_INTERNAL_H |
| +#define _REGEX_INTERNAL_H 1 |
| + |
| +#include <assert.h> |
| +#include <ctype.h> |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| +#include <string.h> |
| + |
| +#include "langinfo.h" |
| +#include <locale.h> |
| +#include <wchar.h> |
| +#include <wctype.h> |
| +#include <stdbool.h> |
| +#include <stdint.h> |
| + |
| +#include "intprops.h" |
| + |
| +#ifdef _LIBC |
| +# include <libc-lock.h> |
| +# define lock_define(name) __libc_lock_define (, name) |
| +# define lock_init(lock) (__libc_lock_init (lock), 0) |
| +# define lock_fini(lock) ((void) 0) |
| +# define lock_lock(lock) __libc_lock_lock (lock) |
| +# define lock_unlock(lock) __libc_lock_unlock (lock) |
| +#elif defined GNULIB_LOCK && !defined USE_UNLOCKED_IO |
| +# include "glthread/lock.h" |
| + /* Use gl_lock_define if empty macro arguments are known to work. |
| + Otherwise, fall back on less-portable substitutes. */ |
| +# if ((defined __GNUC__ && !defined __STRICT_ANSI__) \ |
| + || (defined __STDC_VERSION__ && 199901L <= __STDC_VERSION__)) |
| +# define lock_define(name) gl_lock_define (, name) |
| +# elif USE_POSIX_THREADS |
| +# define lock_define(name) pthread_mutex_t name; |
| +# elif USE_PTH_THREADS |
| +# define lock_define(name) pth_mutex_t name; |
| +# elif USE_SOLARIS_THREADS |
| +# define lock_define(name) mutex_t name; |
| +# elif USE_WINDOWS_THREADS |
| +# define lock_define(name) gl_lock_t name; |
| +# else |
| +# define lock_define(name) |
| +# endif |
| +# define lock_init(lock) glthread_lock_init (&(lock)) |
| +# define lock_fini(lock) glthread_lock_destroy (&(lock)) |
| +# define lock_lock(lock) glthread_lock_lock (&(lock)) |
| +# define lock_unlock(lock) glthread_lock_unlock (&(lock)) |
| +#elif defined GNULIB_PTHREAD && !defined USE_UNLOCKED_IO |
| +# include <pthread.h> |
| +# define lock_define(name) pthread_mutex_t name; |
| +# define lock_init(lock) pthread_mutex_init (&(lock), 0) |
| +# define lock_fini(lock) pthread_mutex_destroy (&(lock)) |
| +# define lock_lock(lock) pthread_mutex_lock (&(lock)) |
| +# define lock_unlock(lock) pthread_mutex_unlock (&(lock)) |
| +#else |
| +# define lock_define(name) |
| +# define lock_init(lock) 0 |
| +# define lock_fini(lock) ((void) 0) |
| + /* The 'dfa' avoids an "unused variable 'dfa'" warning from GCC. */ |
| +# define lock_lock(lock) ((void) dfa) |
| +# define lock_unlock(lock) ((void) 0) |
| +#endif |
| + |
| +/* In case that the system doesn't have isblank(). */ |
| +#if !defined _LIBC && ! (defined isblank || (HAVE_ISBLANK && HAVE_DECL_ISBLANK)) |
| +# define isblank(ch) ((ch) == ' ' || (ch) == '\t') |
| +#endif |
| + |
| + |
| +# undef gettext |
| +# define gettext(msgid) (msgid) |
| + |
| + |
| +#ifndef gettext_noop |
| +/* This define is so xgettext can find the internationalizable |
| + strings. */ |
| +# define gettext_noop(String) String |
| +#endif |
| + |
| +/* Number of ASCII characters. */ |
| +#define ASCII_CHARS 0x80 |
| + |
| +/* Number of single byte characters. */ |
| +#define SBC_MAX (UCHAR_MAX + 1) |
| + |
| +#define COLL_ELEM_LEN_MAX 8 |
| + |
| +/* The character which represents newline. */ |
| +#define NEWLINE_CHAR '\n' |
| +#define WIDE_NEWLINE_CHAR L'\n' |
| + |
| +/* Rename to standard API for using out of glibc. */ |
| +#ifndef _LIBC |
| +# undef __wctype |
| +# undef __iswalnum |
| +# undef __iswctype |
| +# undef __towlower |
| +# undef __towupper |
| +# define __wctype wctype |
| +# define __iswalnum iswalnum |
| +# define __iswctype iswctype |
| +# define __towlower towlower |
| +# define __towupper towupper |
| +# define __btowc btowc |
| +# define __mbrtowc mbrtowc |
| +# define __wcrtomb wcrtomb |
| +# define __regfree regfree |
| +# define attribute_hidden |
| +#endif /* not _LIBC */ |
| + |
| +#if __GNUC__ < 3 + (__GNUC_MINOR__ < 1) |
| +# define __attribute__(arg) |
| +#endif |
| + |
| +#ifndef SSIZE_MAX |
| +# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) |
| +#endif |
| + |
| +/* The type of indexes into strings. This is signed, not size_t, |
| + since the API requires indexes to fit in regoff_t anyway, and using |
| + signed integers makes the code a bit smaller and presumably faster. |
| + The traditional GNU regex implementation uses int for indexes. |
| + The POSIX-compatible implementation uses a possibly-wider type. |
| + The name 'Idx' is three letters to minimize the hassle of |
| + reindenting a lot of regex code that formerly used 'int'. */ |
| +typedef regoff_t Idx; |
| +#ifdef _REGEX_LARGE_OFFSETS |
| +# define IDX_MAX SSIZE_MAX |
| +#else |
| +# define IDX_MAX INT_MAX |
| +#endif |
| + |
| +#ifdef _REGEX_LARGE_OFFSETS |
| + |
| +/* Use types and values that are wide enough to represent signed and |
| + unsigned byte offsets in memory. This currently works only when |
| + the regex code is used outside of the GNU C library; it is not yet |
| + supported within glibc itself, and glibc users should not define |
| + _REGEX_LARGE_OFFSETS. */ |
| + |
| +/* The type of object sizes. */ |
| +typedef size_t __re_size_t; |
| + |
| +/* The type of object sizes, in places where the traditional code |
| + uses unsigned long int. */ |
| +typedef size_t __re_long_size_t; |
| + |
| +#else |
| + |
| +/* The traditional GNU regex implementation mishandles strings longer |
| + than INT_MAX. */ |
| +typedef unsigned int __re_size_t; |
| +typedef unsigned long int __re_long_size_t; |
| + |
| +#endif |
| + |
| +#ifndef RE_TRANSLATE_TYPE |
| +# define __RE_TRANSLATE_TYPE unsigned char * |
| +# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE |
| +#endif |
| + |
| +/* The following bits are used to determine the regexp syntax we |
| + recognize. The set/not-set meanings are chosen so that Emacs syntax |
| + remains the value 0. The bits are given in alphabetical order, and |
| + the definitions shifted by one from the previous bit; thus, when we |
| + add or remove a bit, only one other definition need change. */ |
| +typedef unsigned long int reg_syntax_t; |
| + |
| +/* A hash value, suitable for computing hash tables. */ |
| +typedef __re_size_t re_hashval_t; |
| + |
| +/* An integer used to represent a set of bits. It must be unsigned, |
| + and must be at least as wide as unsigned int. */ |
| +typedef unsigned long int bitset_word_t; |
| +/* All bits set in a bitset_word_t. */ |
| +#define BITSET_WORD_MAX ULONG_MAX |
| + |
| +/* Number of bits in a bitset_word_t. For portability to hosts with |
| + padding bits, do not use '(sizeof (bitset_word_t) * CHAR_BIT)'; |
| + instead, deduce it directly from BITSET_WORD_MAX. Avoid |
| + greater-than-32-bit integers and unconditional shifts by more than |
| + 31 bits, as they're not portable. */ |
| +#if BITSET_WORD_MAX == 0xffffffffUL |
| +# define BITSET_WORD_BITS 32 |
| +#elif BITSET_WORD_MAX >> 31 >> 4 == 1 |
| +# define BITSET_WORD_BITS 36 |
| +#elif BITSET_WORD_MAX >> 31 >> 16 == 1 |
| +# define BITSET_WORD_BITS 48 |
| +#elif BITSET_WORD_MAX >> 31 >> 28 == 1 |
| +# define BITSET_WORD_BITS 60 |
| +#elif BITSET_WORD_MAX >> 31 >> 31 >> 1 == 1 |
| +# define BITSET_WORD_BITS 64 |
| +#elif BITSET_WORD_MAX >> 31 >> 31 >> 9 == 1 |
| +# define BITSET_WORD_BITS 72 |
| +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 3 == 1 |
| +# define BITSET_WORD_BITS 128 |
| +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 == 1 |
| +# define BITSET_WORD_BITS 256 |
| +#elif BITSET_WORD_MAX >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 31 >> 7 > 1 |
| +# define BITSET_WORD_BITS 257 /* any value > SBC_MAX will do here */ |
| +# if BITSET_WORD_BITS <= SBC_MAX |
| +# error "Invalid SBC_MAX" |
| +# endif |
| +#else |
| +# error "Add case for new bitset_word_t size" |
| +#endif |
| + |
| +/* Number of bitset_word_t values in a bitset_t. */ |
| +#define BITSET_WORDS ((SBC_MAX + BITSET_WORD_BITS - 1) / BITSET_WORD_BITS) |
| + |
| +typedef bitset_word_t bitset_t[BITSET_WORDS]; |
| +typedef bitset_word_t *re_bitset_ptr_t; |
| +typedef const bitset_word_t *re_const_bitset_ptr_t; |
| + |
| +#define PREV_WORD_CONSTRAINT 0x0001 |
| +#define PREV_NOTWORD_CONSTRAINT 0x0002 |
| +#define NEXT_WORD_CONSTRAINT 0x0004 |
| +#define NEXT_NOTWORD_CONSTRAINT 0x0008 |
| +#define PREV_NEWLINE_CONSTRAINT 0x0010 |
| +#define NEXT_NEWLINE_CONSTRAINT 0x0020 |
| +#define PREV_BEGBUF_CONSTRAINT 0x0040 |
| +#define NEXT_ENDBUF_CONSTRAINT 0x0080 |
| +#define WORD_DELIM_CONSTRAINT 0x0100 |
| +#define NOT_WORD_DELIM_CONSTRAINT 0x0200 |
| + |
| +typedef enum |
| +{ |
| + INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, |
| + WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, |
| + WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, |
| + INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, |
| + LINE_FIRST = PREV_NEWLINE_CONSTRAINT, |
| + LINE_LAST = NEXT_NEWLINE_CONSTRAINT, |
| + BUF_FIRST = PREV_BEGBUF_CONSTRAINT, |
| + BUF_LAST = NEXT_ENDBUF_CONSTRAINT, |
| + WORD_DELIM = WORD_DELIM_CONSTRAINT, |
| + NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT |
| +} re_context_type; |
| + |
| +typedef struct |
| +{ |
| + Idx alloc; |
| + Idx nelem; |
| + Idx *elems; |
| +} re_node_set; |
| + |
| +typedef enum |
| +{ |
| + NON_TYPE = 0, |
| + |
| + /* Node type, These are used by token, node, tree. */ |
| + CHARACTER = 1, |
| + END_OF_RE = 2, |
| + SIMPLE_BRACKET = 3, |
| + OP_BACK_REF = 4, |
| + OP_PERIOD = 5, |
| + |
| + /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used |
| + when the debugger shows values of this enum type. */ |
| +#define EPSILON_BIT 8 |
| + OP_OPEN_SUBEXP = EPSILON_BIT | 0, |
| + OP_CLOSE_SUBEXP = EPSILON_BIT | 1, |
| + OP_ALT = EPSILON_BIT | 2, |
| + OP_DUP_ASTERISK = EPSILON_BIT | 3, |
| + ANCHOR = EPSILON_BIT | 4, |
| + |
| + /* Tree type, these are used only by tree. */ |
| + CONCAT = 16, |
| + SUBEXP = 17, |
| + |
| + /* Token type, these are used only by token. */ |
| + OP_DUP_PLUS = 18, |
| + OP_DUP_QUESTION, |
| + OP_OPEN_BRACKET, |
| + OP_CLOSE_BRACKET, |
| + OP_CHARSET_RANGE, |
| + OP_OPEN_DUP_NUM, |
| + OP_CLOSE_DUP_NUM, |
| + OP_NON_MATCH_LIST, |
| + OP_OPEN_COLL_ELEM, |
| + OP_CLOSE_COLL_ELEM, |
| + OP_OPEN_EQUIV_CLASS, |
| + OP_CLOSE_EQUIV_CLASS, |
| + OP_OPEN_CHAR_CLASS, |
| + OP_CLOSE_CHAR_CLASS, |
| + OP_WORD, |
| + OP_NOTWORD, |
| + OP_SPACE, |
| + OP_NOTSPACE, |
| + BACK_SLASH |
| + |
| +} re_token_type_t; |
| + |
| +typedef struct |
| +{ |
| + union |
| + { |
| + unsigned char c; /* for CHARACTER */ |
| + re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ |
| + Idx idx; /* for BACK_REF */ |
| + re_context_type ctx_type; /* for ANCHOR */ |
| + } opr; |
| +#if __GNUC__ >= 2 && !defined __STRICT_ANSI__ |
| + re_token_type_t type : 8; |
| +#else |
| + re_token_type_t type; |
| +#endif |
| + unsigned int constraint : 10; /* context constraint */ |
| + unsigned int duplicated : 1; |
| + unsigned int opt_subexp : 1; |
| + unsigned int word_char : 1; |
| +} re_token_t; |
| + |
| +#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT) |
| + |
| +struct re_string_t |
| +{ |
| + /* Indicate the raw buffer which is the original string passed as an |
| + argument of regexec(), re_search(), etc.. */ |
| + const unsigned char *raw_mbs; |
| + /* Store the multibyte string. In case of "case insensitive mode" like |
| + REG_ICASE, upper cases of the string are stored, otherwise MBS points |
| + the same address that RAW_MBS points. */ |
| + unsigned char *mbs; |
| + /* Index in RAW_MBS. Each character mbs[i] corresponds to |
| + raw_mbs[raw_mbs_idx + i]. */ |
| + Idx raw_mbs_idx; |
| + /* The length of the valid characters in the buffers. */ |
| + Idx valid_len; |
| + /* The corresponding number of bytes in raw_mbs array. */ |
| + Idx valid_raw_len; |
| + /* The length of the buffers MBS and WCS. */ |
| + Idx bufs_len; |
| + /* The index in MBS, which is updated by re_string_fetch_byte. */ |
| + Idx cur_idx; |
| + /* length of RAW_MBS array. */ |
| + Idx raw_len; |
| + /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */ |
| + Idx len; |
| + /* End of the buffer may be shorter than its length in the cases such |
| + as re_match_2, re_search_2. Then, we use STOP for end of the buffer |
| + instead of LEN. */ |
| + Idx raw_stop; |
| + /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */ |
| + Idx stop; |
| + |
| + /* The context of mbs[0]. We store the context independently, since |
| + the context of mbs[0] may be different from raw_mbs[0], which is |
| + the beginning of the input string. */ |
| + unsigned int tip_context; |
| + /* The translation passed as a part of an argument of re_compile_pattern. */ |
| + RE_TRANSLATE_TYPE trans; |
| + /* Copy of re_dfa_t's word_char. */ |
| + re_const_bitset_ptr_t word_char; |
| + /* true if REG_ICASE. */ |
| + unsigned char icase; |
| + unsigned char is_utf8; |
| + unsigned char map_notascii; |
| + unsigned char mbs_allocated; |
| + unsigned char offsets_needed; |
| + unsigned char newline_anchor; |
| + unsigned char word_ops_used; |
| + int mb_cur_max; |
| +}; |
| +typedef struct re_string_t re_string_t; |
| + |
| + |
| +struct re_dfa_t; |
| +typedef struct re_dfa_t re_dfa_t; |
| + |
| +# define IS_IN(libc) false |
| + |
| + |
| +#define re_string_peek_byte(pstr, offset) \ |
| + ((pstr)->mbs[(pstr)->cur_idx + offset]) |
| +#define re_string_fetch_byte(pstr) \ |
| + ((pstr)->mbs[(pstr)->cur_idx++]) |
| +#define re_string_first_byte(pstr, idx) \ |
| + ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF) |
| +#define re_string_is_single_byte_char(pstr, idx) \ |
| + ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \ |
| + || (pstr)->wcs[(idx) + 1] != WEOF)) |
| +#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) |
| +#define re_string_cur_idx(pstr) ((pstr)->cur_idx) |
| +#define re_string_get_buffer(pstr) ((pstr)->mbs) |
| +#define re_string_length(pstr) ((pstr)->len) |
| +#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) |
| +#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) |
| +#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) |
| + |
| +#if HAVE_ALLOCA |
| +# include <alloca.h> |
| +#endif |
| + |
| +# if HAVE_ALLOCA |
| +/* The OS usually guarantees only one guard page at the bottom of the stack, |
| + and a page size can be as small as 4096 bytes. So we cannot safely |
| + allocate anything larger than 4096 bytes. Also care for the possibility |
| + of a few compiler-allocated temporary stack slots. */ |
| +# define __libc_use_alloca(n) ((n) < 4032) |
| +# else |
| +/* alloca is implemented with malloc, so just use malloc. */ |
| +# define __libc_use_alloca(n) 0 |
| +# undef alloca |
| +# define alloca(n) malloc (n) |
| +# endif |
| + |
| + |
| +#if !defined MALLOC_0_IS_NONNULL |
| +# define MALLOC_0_IS_NONNULL 0 |
| +#endif |
| + |
| +#ifndef MAX |
| +# define MAX(a,b) ((a) < (b) ? (b) : (a)) |
| +#endif |
| +#ifndef MIN |
| +# define MIN(a,b) ((a) < (b) ? (a) : (b)) |
| +#endif |
| + |
| +#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) |
| +#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) |
| +#define re_free(p) free (p) |
| + |
| +struct bin_tree_t |
| +{ |
| + struct bin_tree_t *parent; |
| + struct bin_tree_t *left; |
| + struct bin_tree_t *right; |
| + struct bin_tree_t *first; |
| + struct bin_tree_t *next; |
| + |
| + re_token_t token; |
| + |
| + /* 'node_idx' is the index in dfa->nodes, if 'type' == 0. |
| + Otherwise 'type' indicate the type of this node. */ |
| + Idx node_idx; |
| +}; |
| +typedef struct bin_tree_t bin_tree_t; |
| + |
| +#define BIN_TREE_STORAGE_SIZE \ |
| + ((1024 - sizeof (void *)) / sizeof (bin_tree_t)) |
| + |
| +struct bin_tree_storage_t |
| +{ |
| + struct bin_tree_storage_t *next; |
| + bin_tree_t data[BIN_TREE_STORAGE_SIZE]; |
| +}; |
| +typedef struct bin_tree_storage_t bin_tree_storage_t; |
| + |
| +#define CONTEXT_WORD 1 |
| +#define CONTEXT_NEWLINE (CONTEXT_WORD << 1) |
| +#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) |
| +#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) |
| + |
| +#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) |
| +#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) |
| +#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) |
| +#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) |
| +#define IS_ORDINARY_CONTEXT(c) ((c) == 0) |
| + |
| +#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') |
| +#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) |
| +#define IS_WIDE_WORD_CHAR(ch) (__iswalnum (ch) || (ch) == L'_') |
| +#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR) |
| + |
| +#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ |
| + ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ |
| + || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ |
| + || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ |
| + || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) |
| + |
| +#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ |
| + ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ |
| + || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ |
| + || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ |
| + || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) |
| + |
| +struct re_dfastate_t |
| +{ |
| + re_hashval_t hash; |
| + re_node_set nodes; |
| + re_node_set non_eps_nodes; |
| + re_node_set inveclosure; |
| + re_node_set *entrance_nodes; |
| + struct re_dfastate_t **trtable, **word_trtable; |
| + unsigned int context : 4; |
| + unsigned int halt : 1; |
| + /* If this state can accept "multi byte". |
| + Note that we refer to multibyte characters, and multi character |
| + collating elements as "multi byte". */ |
| + unsigned int accept_mb : 1; |
| + /* If this state has backreference node(s). */ |
| + unsigned int has_backref : 1; |
| + unsigned int has_constraint : 1; |
| +}; |
| +typedef struct re_dfastate_t re_dfastate_t; |
| + |
| +struct re_state_table_entry |
| +{ |
| + Idx num; |
| + Idx alloc; |
| + re_dfastate_t **array; |
| +}; |
| + |
| +/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ |
| + |
| +typedef struct |
| +{ |
| + Idx next_idx; |
| + Idx alloc; |
| + re_dfastate_t **array; |
| +} state_array_t; |
| + |
| +/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */ |
| + |
| +typedef struct |
| +{ |
| + Idx node; |
| + Idx str_idx; /* The position NODE match at. */ |
| + state_array_t path; |
| +} re_sub_match_last_t; |
| + |
| +/* Store information about the node NODE whose type is OP_OPEN_SUBEXP. |
| + And information about the node, whose type is OP_CLOSE_SUBEXP, |
| + corresponding to NODE is stored in LASTS. */ |
| + |
| +typedef struct |
| +{ |
| + Idx str_idx; |
| + Idx node; |
| + state_array_t *path; |
| + Idx alasts; /* Allocation size of LASTS. */ |
| + Idx nlasts; /* The number of LASTS. */ |
| + re_sub_match_last_t **lasts; |
| +} re_sub_match_top_t; |
| + |
| +struct re_backref_cache_entry |
| +{ |
| + Idx node; |
| + Idx str_idx; |
| + Idx subexp_from; |
| + Idx subexp_to; |
| + char more; |
| + char unused; |
| + unsigned short int eps_reachable_subexps_map; |
| +}; |
| + |
| +typedef struct |
| +{ |
| + /* The string object corresponding to the input string. */ |
| + re_string_t input; |
| + const re_dfa_t *dfa; |
| + /* EFLAGS of the argument of regexec. */ |
| + int eflags; |
| + /* Where the matching ends. */ |
| + Idx match_last; |
| + Idx last_node; |
| + /* The state log used by the matcher. */ |
| + re_dfastate_t **state_log; |
| + Idx state_log_top; |
| + /* Back reference cache. */ |
| + Idx nbkref_ents; |
| + Idx abkref_ents; |
| + struct re_backref_cache_entry *bkref_ents; |
| + int max_mb_elem_len; |
| + Idx nsub_tops; |
| + Idx asub_tops; |
| + re_sub_match_top_t **sub_tops; |
| +} re_match_context_t; |
| + |
| +typedef struct |
| +{ |
| + re_dfastate_t **sifted_states; |
| + re_dfastate_t **limited_states; |
| + Idx last_node; |
| + Idx last_str_idx; |
| + re_node_set limits; |
| +} re_sift_context_t; |
| + |
| +struct re_fail_stack_ent_t |
| +{ |
| + Idx idx; |
| + Idx node; |
| + regmatch_t *regs; |
| + re_node_set eps_via_nodes; |
| +}; |
| + |
| +struct re_fail_stack_t |
| +{ |
| + Idx num; |
| + Idx alloc; |
| + struct re_fail_stack_ent_t *stack; |
| +}; |
| + |
| +struct re_dfa_t |
| +{ |
| + re_token_t *nodes; |
| + size_t nodes_alloc; |
| + size_t nodes_len; |
| + Idx *nexts; |
| + Idx *org_indices; |
| + re_node_set *edests; |
| + re_node_set *eclosures; |
| + re_node_set *inveclosures; |
| + struct re_state_table_entry *state_table; |
| + re_dfastate_t *init_state; |
| + re_dfastate_t *init_state_word; |
| + re_dfastate_t *init_state_nl; |
| + re_dfastate_t *init_state_begbuf; |
| + bin_tree_t *str_tree; |
| + bin_tree_storage_t *str_tree_storage; |
| + re_bitset_ptr_t sb_char; |
| + int str_tree_storage_idx; |
| + |
| + /* number of subexpressions 're_nsub' is in regex_t. */ |
| + re_hashval_t state_hash_mask; |
| + Idx init_node; |
| + Idx nbackref; /* The number of backreference in this dfa. */ |
| + |
| + /* Bitmap expressing which backreference is used. */ |
| + bitset_word_t used_bkref_map; |
| + bitset_word_t completed_bkref_map; |
| + |
| + unsigned int has_plural_match : 1; |
| + /* If this dfa has "multibyte node", which is a backreference or |
| + a node which can accept multibyte character or multi character |
| + collating element. */ |
| + unsigned int has_mb_node : 1; |
| + unsigned int is_utf8 : 1; |
| + unsigned int map_notascii : 1; |
| + unsigned int word_ops_used : 1; |
| + int mb_cur_max; |
| + bitset_t word_char; |
| + reg_syntax_t syntax; |
| + Idx *subexp_map; |
| + lock_define (lock) |
| +}; |
| + |
| +#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) |
| +#define re_node_set_remove(set,id) \ |
| + (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) |
| +#define re_node_set_empty(p) ((p)->nelem = 0) |
| +#define re_node_set_free(set) re_free ((set)->elems) |
| + |
| + |
| +typedef enum |
| +{ |
| + SB_CHAR, |
| + MB_CHAR, |
| + EQUIV_CLASS, |
| + COLL_SYM, |
| + CHAR_CLASS |
| +} bracket_elem_type; |
| + |
| +typedef struct |
| +{ |
| + bracket_elem_type type; |
| + union |
| + { |
| + unsigned char ch; |
| + unsigned char *name; |
| + wchar_t wch; |
| + } opr; |
| +} bracket_elem_t; |
| + |
| + |
| +/* Functions for bitset_t operation. */ |
| + |
| +static inline void |
| +bitset_set (bitset_t set, Idx i) |
| +{ |
| + set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS; |
| +} |
| + |
| +static inline void |
| +bitset_clear (bitset_t set, Idx i) |
| +{ |
| + set[i / BITSET_WORD_BITS] &= ~ ((bitset_word_t) 1 << i % BITSET_WORD_BITS); |
| +} |
| + |
| +static inline bool |
| +bitset_contain (const bitset_t set, Idx i) |
| +{ |
| + return (set[i / BITSET_WORD_BITS] >> i % BITSET_WORD_BITS) & 1; |
| +} |
| + |
| +static inline void |
| +bitset_empty (bitset_t set) |
| +{ |
| + memset (set, '\0', sizeof (bitset_t)); |
| +} |
| + |
| +static inline void |
| +bitset_set_all (bitset_t set) |
| +{ |
| + memset (set, -1, sizeof (bitset_word_t) * (SBC_MAX / BITSET_WORD_BITS)); |
| + if (SBC_MAX % BITSET_WORD_BITS != 0) |
| + set[BITSET_WORDS - 1] = |
| + ((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1; |
| +} |
| + |
| +static inline void |
| +bitset_copy (bitset_t dest, const bitset_t src) |
| +{ |
| + memcpy (dest, src, sizeof (bitset_t)); |
| +} |
| + |
| +static inline void |
| +bitset_not (bitset_t set) |
| +{ |
| + int bitset_i; |
| + for (bitset_i = 0; bitset_i < SBC_MAX / BITSET_WORD_BITS; ++bitset_i) |
| + set[bitset_i] = ~set[bitset_i]; |
| + if (SBC_MAX % BITSET_WORD_BITS != 0) |
| + set[BITSET_WORDS - 1] = |
| + ((((bitset_word_t) 1 << SBC_MAX % BITSET_WORD_BITS) - 1) |
| + & ~set[BITSET_WORDS - 1]); |
| +} |
| + |
| +static inline void |
| +bitset_merge (bitset_t dest, const bitset_t src) |
| +{ |
| + int bitset_i; |
| + for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) |
| + dest[bitset_i] |= src[bitset_i]; |
| +} |
| + |
| +static inline void |
| +bitset_mask (bitset_t dest, const bitset_t src) |
| +{ |
| + int bitset_i; |
| + for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i) |
| + dest[bitset_i] &= src[bitset_i]; |
| +} |
| + |
| +#ifndef __GNUC_PREREQ |
| +# if defined __GNUC__ && defined __GNUC_MINOR__ |
| +# define __GNUC_PREREQ(maj, min) \ |
| + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) |
| +# else |
| +# define __GNUC_PREREQ(maj, min) 0 |
| +# endif |
| +#endif |
| + |
| +#if __GNUC_PREREQ (3,4) |
| +# undef __attribute_warn_unused_result__ |
| +# define __attribute_warn_unused_result__ \ |
| + __attribute__ ((__warn_unused_result__)) |
| +#else |
| +# define __attribute_warn_unused_result__ /* empty */ |
| +#endif |
| + |
| +#ifndef FALLTHROUGH |
| +# if __GNUC__ < 7 |
| +# define FALLTHROUGH ((void) 0) |
| +# else |
| +# define FALLTHROUGH __attribute__ ((__fallthrough__)) |
| +# endif |
| +#endif |
| + |
| +#endif /* _REGEX_INTERNAL_H */ |
| diff --git a/headers-mingw/resource.h b/headers-mingw/resource.h |
| new file mode 100644 |
| index 0000000..160aad2 |
| --- /dev/null |
| +++ b/headers-mingw/resource.h |
| @@ -0,0 +1,79 @@ |
| +/* Substitute for <sys/resource.h>. |
| + Copyright (C) 2012-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef _GL_SYS_RESOURCE_H |
| +#define _GL_SYS_RESOURCE_H |
| + |
| +#if !HAVE_SYS_RESOURCE_H |
| +/* A platform that lacks <sys/resource.h>. */ |
| + |
| +/* Get 'struct timeval'. */ |
| +# include <sys/time.h> |
| + |
| +/* Define the RUSAGE_* constants. */ |
| +# define RUSAGE_SELF 0 |
| +# define RUSAGE_CHILDREN -1 |
| + |
| +# ifdef __cplusplus |
| +extern "C" { |
| +# endif |
| + |
| +# if !GNULIB_defined_struct_rusage |
| +/* All known platforms that lack <sys/resource.h> also lack any declaration |
| + of struct rusage in any other header. */ |
| +struct rusage |
| +{ |
| + struct timeval ru_utime; /* CPU time used in user mode */ |
| + struct timeval ru_stime; /* CPU time used in system mode (kernel) */ |
| + long ru_maxrss; |
| + long ru_ixrss; |
| + long ru_idrss; |
| + long ru_isrss; |
| + long ru_minflt; |
| + long ru_majflt; |
| + long ru_nswap; |
| + long ru_inblock; |
| + long ru_oublock; |
| + long ru_msgsnd; |
| + long ru_msgrcv; |
| + long ru_nsignals; |
| + long ru_nvcsw; |
| + long ru_nivcsw; |
| +}; |
| +# define GNULIB_defined_struct_rusage 1 |
| +# endif |
| + |
| +# ifdef __cplusplus |
| +} |
| +# endif |
| + |
| +#endif |
| + |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_ARG_NONNULL is copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| + |
| +/* Declare overridden functions. */ |
| + |
| + |
| +#if !HAVE_GETRUSAGE |
| +extern int getrusage (int who, struct rusage *usage_p); |
| +#endif |
| + |
| +#endif /* _@GUARD_PREFIX@_SYS_RESOURCE_H */ |
| diff --git a/headers-mingw/signal.h b/headers-mingw/signal.h |
| new file mode 100644 |
| index 0000000..63539a2 |
| --- /dev/null |
| +++ b/headers-mingw/signal.h |
| @@ -0,0 +1,264 @@ |
| +/* A GNU-like <signal.h>. |
| + |
| + Copyright (C) 2006-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software: you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 3 of the License, or |
| + (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| + |
| + |
| + |
| +/* Normal invocation convention. */ |
| + |
| +#ifndef _GL_SIGNAL_H |
| +#define _GL_SIGNAL_H |
| + |
| +/* Get pid_t. */ |
| +#include <sys/types.h> |
| + |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_ARG_NONNULL is copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| +/* A set or mask of signals. */ |
| +#if !GNULIB_defined_sigset_t |
| +typedef unsigned int sigset_t; |
| +# define GNULIB_defined_sigset_t 1 |
| +#endif |
| + |
| + |
| +/* Define sighandler_t, the type of signal handlers. A GNU extension. */ |
| +#ifdef __cplusplus |
| +extern "C" { |
| +#endif |
| +#if !GNULIB_defined_sighandler_t |
| +typedef void (*sighandler_t) (int); |
| +# define GNULIB_defined_sighandler_t 1 |
| +#endif |
| +#ifdef __cplusplus |
| +} |
| +#endif |
| + |
| + |
| + |
| +#ifndef SIGPIPE |
| +/* Define SIGPIPE to a value that does not overlap with other signals. */ |
| +# define SIGPIPE 13 |
| +# define GNULIB_defined_SIGPIPE 1 |
| +/* To actually use SIGPIPE, you also need the gnulib modules 'sigprocmask', |
| + 'write', 'stdio'. */ |
| +#endif |
| + |
| + |
| + |
| +/* Maximum signal number + 1. */ |
| +#ifndef NSIG |
| +# if defined __TANDEM |
| +# define NSIG 32 |
| +# endif |
| +#endif |
| + |
| + |
| +#if !(HAVE_PTHREAD_SIGMASK || defined pthread_sigmask) |
| +extern int pthread_sigmask(int how, const sigset_t *new_mask, sigset_t *old_mask); |
| +#endif |
| + |
| + |
| +#if !HAVE_RAISE |
| +extern int raise(int sig); |
| +#endif |
| + |
| + |
| +#ifndef GNULIB_defined_signal_blocking |
| +# define GNULIB_defined_signal_blocking 1 |
| +#endif |
| + |
| +/* Maximum signal number + 1. */ |
| +#ifndef NSIG |
| +# define NSIG 32 |
| +#endif |
| + |
| +/* This code supports only 32 signals. */ |
| +#if !GNULIB_defined_verify_NSIG_constraint |
| +typedef int verify_NSIG_constraint[NSIG <= 32 ? 1 : -1]; |
| +# define GNULIB_defined_verify_NSIG_constraint 1 |
| +#endif |
| + |
| + |
| +/* When also using extern inline, suppress the use of static inline in |
| + standard headers of problematic Apple configurations, as Libc at |
| + least through Libc-825.26 (2013-04-09) mishandles it; see, e.g., |
| + <https://lists.gnu.org/r/bug-gnulib/2012-12/msg00023.html>. |
| + Perhaps Apple will fix this some day. */ |
| +#if (defined _GL_EXTERN_INLINE_IN_USE && defined __APPLE__ \ |
| + && (defined __i386__ || defined __x86_64__)) |
| +# undef sigaddset |
| +# undef sigdelset |
| +# undef sigemptyset |
| +# undef sigfillset |
| +# undef sigismember |
| +#endif |
| + |
| +/* Test whether a given signal is contained in a signal set. */ |
| +#if !HAVE_SIGISMEMBER |
| +extern int sigismember(const sigset_t *set, int sig); |
| +# endif |
| + |
| +/* Initialize a signal set to the empty set. */ |
| +#if !HAVE_SIGEMPTYSET |
| +extern int sigemptyset(sigset_t *set); |
| +#endif |
| + |
| + |
| +/* Add a signal to a signal set. */ |
| +#if !HAVE_SIGADDSET |
| +extern int sigaddset(sigset_t *set, int sig); |
| +#endif |
| + |
| + |
| +/* Remove a signal from a signal set. */ |
| +#if !HAVE_SIGDELSET |
| +extern int sigdelset(sigset_t *set, int sig); |
| +# endif |
| + |
| +/* Fill a signal set with all possible signals. */ |
| +#if !HAVE_SIGFILLSET |
| +extern int sigfillset(sigset_t *set); |
| +#endif |
| + |
| + |
| +/* Return the set of those blocked signals that are pending. */ |
| +#if !HAVE_SIGPENDING |
| +extern int sigpending(sigset_t *set); |
| +#endif |
| + |
| +/* If OLD_SET is not NULL, put the current set of blocked signals in *OLD_SET. |
| + Then, if SET is not NULL, affect the current set of blocked signals by |
| + combining it with *SET as indicated in OPERATION. |
| + In this implementation, you are not allowed to change a signal handler |
| + while the signal is blocked. */ |
| +#ifndef SIG_BLOCK |
| +# define SIG_BLOCK 0 /* blocked_set = blocked_set | *set; */ |
| +#endif |
| +#ifndef SIG_SETMASK |
| +# define SIG_SETMASK 1 /* blocked_set = *set; */ |
| +#endif |
| +#ifndef SIG_UNBLOCK |
| +# define SIG_UNBLOCK 2 /* blocked_set = blocked_set & ~*set; */ |
| +#endif |
| +#if !HAVE_SIGPROCMASK |
| +extern int sigprocmask(int operation, const sigset_t *set, sigset_t *old_set); |
| +# endif |
| + |
| +/* Install the handler FUNC for signal SIG, and return the previous |
| + handler. */ |
| +#ifdef __cplusplus |
| +extern "C" { |
| +#endif |
| +#if !GNULIB_defined_function_taking_int_returning_void_t |
| +typedef void (*_gl_function_taking_int_returning_void_t) (int); |
| +# define GNULIB_defined_function_taking_int_returning_void_t 1 |
| +#endif |
| +#ifdef __cplusplus |
| +} |
| +#endif |
| +#if !HAVE_SIGNAL |
| +extern _gl_function_taking_int_returning_void_t signal(int sig, _gl_function_taking_int_returning_void_t func); |
| +#endif |
| + |
| + |
| +extern int _gl_raise_SIGPIPE (void); |
| + |
| +#if !HAVE_SIGACTION |
| +# if !GNULIB_defined_siginfo_types |
| + |
| +/* Present to allow compilation, but unsupported by gnulib. */ |
| +union sigval |
| +{ |
| + int sival_int; |
| + void *sival_ptr; |
| +}; |
| + |
| +/* Present to allow compilation, but unsupported by gnulib. */ |
| +struct siginfo_t |
| +{ |
| + int si_signo; |
| + int si_code; |
| + int si_errno; |
| + pid_t si_pid; |
| + int si_uid; |
| + void *si_addr; |
| + int si_status; |
| + long si_band; |
| + union sigval si_value; |
| +}; |
| +typedef struct siginfo_t siginfo_t; |
| + |
| +# define GNULIB_defined_siginfo_types 1 |
| +# endif |
| + |
| + |
| +/* We assume that platforms which lack the sigaction() function also lack |
| + the 'struct sigaction' type, and vice versa. */ |
| + |
| +# if !GNULIB_defined_struct_sigaction |
| + |
| +struct sigaction |
| +{ |
| + union |
| + { |
| + void (*_sa_handler) (int); |
| + /* Present to allow compilation, but unsupported by gnulib. POSIX |
| + says that implementations may, but not must, make sa_sigaction |
| + overlap with sa_handler, but we know of no implementation where |
| + they do not overlap. */ |
| + void (*_sa_sigaction) (int, siginfo_t *, void *); |
| + } _sa_func; |
| + sigset_t sa_mask; |
| + /* Not all POSIX flags are supported. */ |
| + int sa_flags; |
| +}; |
| +# define sa_handler _sa_func._sa_handler |
| +# define sa_sigaction _sa_func._sa_sigaction |
| +/* Unsupported flags are not present. */ |
| +# define SA_RESETHAND 1 |
| +# define SA_NODEFER 2 |
| +# define SA_RESTART 4 |
| + |
| +# define GNULIB_defined_struct_sigaction 1 |
| +# endif |
| + |
| +extern int sigaction(int, const struct sigaction *restrict, |
| + struct sigaction *restrict); |
| +#endif |
| + |
| +/* Some systems don't have SA_NODEFER. */ |
| +#ifndef SA_NODEFER |
| +# define SA_NODEFER 0 |
| +#endif |
| + |
| +/* Out-of-range substitutes make a good fallback for uncatchable |
| + signals. */ |
| +#ifndef SIGKILL |
| +# define SIGKILL (-1) |
| +#endif |
| +#ifndef SIGSTOP |
| +# define SIGSTOP (-1) |
| +#endif |
| + |
| +#if !defined(HAVE_KILL) |
| +extern int kill(pid_t pid, int sig); |
| +#endif |
| + |
| +#endif /* _@GUARD_PREFIX@_SIGNAL_H */ |
| diff --git a/headers-mingw/stdlib.h b/headers-mingw/stdlib.h |
| new file mode 100644 |
| index 0000000..55a0e5b |
| --- /dev/null |
| +++ b/headers-mingw/stdlib.h |
| @@ -0,0 +1,344 @@ |
| +/* A GNU-like <stdlib.h>. |
| + |
| + Copyright (C) 1995, 2001-2004, 2006-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software: you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 3 of the License, or |
| + (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Normal invocation convention. */ |
| + |
| +#ifndef _GL_STDLIB_H |
| + |
| +#define _GL_STDLIB_H |
| + |
| +/* Native Windows platforms declare mktemp() in <io.h>. */ |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +# include <io.h> |
| +#endif |
| + |
| +/* OSF/1 5.1 declares 'struct random_data' in <random.h>, which is included |
| + from <stdlib.h> if _REENTRANT is defined. Include it whenever we need |
| + 'struct random_data'. */ |
| +#if HAVE_RANDOM_H |
| +# include <random.h> |
| +#endif |
| + |
| +#if !HAVE_RANDOM_R |
| +# include <stdint.h> |
| +#endif |
| + |
| +/* Define 'struct random_data'. |
| + But allow multiple gnulib generated <stdlib.h> replacements to coexist. */ |
| +#if !GNULIB_defined_struct_random_data |
| +typedef struct random_data |
| +{ |
| + int *fptr; /* Front pointer. */ |
| + int *rptr; /* Rear pointer. */ |
| + int *state; /* Array of state values. */ |
| + int rand_type; /* Type of random number generator. */ |
| + int rand_deg; /* Degree of random number generator. */ |
| + int rand_sep; /* Distance between front and rear. */ |
| + int *end_ptr; /* Pointer behind state table. */ |
| +}; |
| +# define GNULIB_defined_struct_random_data 1 |
| +#endif |
| + |
| +/* The __attribute__ feature is available in gcc versions 2.5 and later. |
| + The attribute __pure__ was added in gcc 2.96. */ |
| +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) |
| +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) |
| +#else |
| +# define _GL_ATTRIBUTE_PURE /* empty */ |
| +#endif |
| + |
| +/* The definition of _Noreturn is copied here. */ |
| + |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_ARG_NONNULL is copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| + |
| +/* Some systems do not define EXIT_*, despite otherwise supporting C89. */ |
| +#ifndef EXIT_SUCCESS |
| +# define EXIT_SUCCESS 0 |
| +#endif |
| +/* Tandem/NSK and other platforms that define EXIT_FAILURE as -1 interfere |
| + with proper operation of xargs. */ |
| +#ifndef EXIT_FAILURE |
| +# define EXIT_FAILURE 1 |
| +#elif EXIT_FAILURE != 1 |
| +# undef EXIT_FAILURE |
| +# define EXIT_FAILURE 1 |
| +#endif |
| + |
| + |
| +/* Terminate the current process with the given return code, without running |
| + the 'atexit' handlers. */ |
| +#if !HAVE__EXIT |
| +extern void _Exit(int status); |
| +#endif |
| + |
| +/* Parse a signed decimal integer. |
| + Returns the value of the integer. Errors are not detected. */ |
| +#if !HAVE_ATOLL |
| +extern long long atoll(const char *string); |
| +#endif |
| + |
| +#if !HAVE_CANONICALIZE_FILE_NAME |
| +extern char * canonicalize_file_name(const char *name); |
| +#endif |
| + |
| +/* Store max(NELEM,3) load average numbers in LOADAVG[]. |
| + The three numbers are the load average of the last 1 minute, the last 5 |
| + minutes, and the last 15 minutes, respectively. |
| + LOADAVG is an array of NELEM numbers. */ |
| +#if !HAVE_GETLOADAVG |
| +extern int getloadavg(double loadavg[], int nelem); |
| +#endif |
| + |
| + |
| +/* Assuming *OPTIONP is a comma separated list of elements of the form |
| + "token" or "token=value", getsubopt parses the first of these elements. |
| + If the first element refers to a "token" that is member of the given |
| + NULL-terminated array of tokens: |
| + - It replaces the comma with a NUL byte, updates *OPTIONP to point past |
| + the first option and the comma, sets *VALUEP to the value of the |
| + element (or NULL if it doesn't contain an "=" sign), |
| + - It returns the index of the "token" in the given array of tokens. |
| + Otherwise it returns -1, and *OPTIONP and *VALUEP are undefined. |
| + For more details see the POSIX:2001 specification. |
| + http://www.opengroup.org/susv3xsh/getsubopt.html */ |
| +#if !HAVE_GETSUBOPT |
| +extern int getsubopt(char **optionp, char *const *tokens, char **valuep); |
| +#endif |
| + |
| + |
| +/* Change the ownership and access permission of the slave side of the |
| + pseudo-terminal whose master side is specified by FD. */ |
| +#if !HAVE_GRANTPT |
| +extern int grantpt(int fd); |
| +#endif |
| + |
| + |
| +/* Create a unique temporary directory from TEMPLATE. |
| + The last six characters of TEMPLATE must be "XXXXXX"; |
| + they are replaced with a string that makes the directory name unique. |
| + Returns TEMPLATE, or a null pointer if it cannot get a unique name. |
| + The directory is created mode 700. */ |
| +#if !HAVE_MKDTEMP |
| +extern char * mkdtemp(char *template); |
| +#endif |
| + |
| +/* Create a unique temporary file from TEMPLATE. |
| + The last six characters of TEMPLATE must be "XXXXXX"; |
| + they are replaced with a string that makes the file name unique. |
| + The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>) |
| + and O_TEXT, O_BINARY (defined in "binary-io.h"). |
| + The file is then created, with the specified flags, ensuring it didn't exist |
| + before. |
| + The file is created read-write (mask at least 0600 & ~umask), but it may be |
| + world-readable and world-writable (mask 0666 & ~umask), depending on the |
| + implementation. |
| + Returns the open file descriptor if successful, otherwise -1 and errno |
| + set. */ |
| +#if !HAVE_MKOSTEMP |
| +extern int mkostemp(char *template, int flags); |
| +#endif |
| + |
| +/* Create a unique temporary file from TEMPLATE. |
| + The last six characters of TEMPLATE before a suffix of length |
| + SUFFIXLEN must be "XXXXXX"; |
| + they are replaced with a string that makes the file name unique. |
| + The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>) |
| + and O_TEXT, O_BINARY (defined in "binary-io.h"). |
| + The file is then created, with the specified flags, ensuring it didn't exist |
| + before. |
| + The file is created read-write (mask at least 0600 & ~umask), but it may be |
| + world-readable and world-writable (mask 0666 & ~umask), depending on the |
| + implementation. |
| + Returns the open file descriptor if successful, otherwise -1 and errno |
| + set. */ |
| +#if !HAVE_MKOSTEMPS |
| +extern int mkostemps(char * template, int suffixlen, int flags); |
| +#endif |
| + |
| + |
| +/* Create a unique temporary file from TEMPLATE. |
| + The last six characters of TEMPLATE must be "XXXXXX"; |
| + they are replaced with a string that makes the file name unique. |
| + The file is then created, ensuring it didn't exist before. |
| + The file is created read-write (mask at least 0600 & ~umask), but it may be |
| + world-readable and world-writable (mask 0666 & ~umask), depending on the |
| + implementation. |
| + Returns the open file descriptor if successful, otherwise -1 and errno |
| + set. */ |
| +#if !HAVE_MKSTEMP |
| +extern int mkstemp(char * template); |
| +#endif |
| + |
| + |
| +/* Create a unique temporary file from TEMPLATE. |
| + The last six characters of TEMPLATE prior to a suffix of length |
| + SUFFIXLEN must be "XXXXXX"; |
| + they are replaced with a string that makes the file name unique. |
| + The file is then created, ensuring it didn't exist before. |
| + The file is created read-write (mask at least 0600 & ~umask), but it may be |
| + world-readable and world-writable (mask 0666 & ~umask), depending on the |
| + implementation. |
| + Returns the open file descriptor if successful, otherwise -1 and errno |
| + set. */ |
| +#if !HAVE_MKSTEMPS |
| +extern int mkstemps(char * template, int suffixlen); |
| +#endif |
| + |
| + |
| +/* Return an FD open to the master side of a pseudo-terminal. Flags should |
| + include O_RDWR, and may also include O_NOCTTY. */ |
| +# if !HAVE_POSIX_OPENPT |
| +extern int posix_openpt(int flags); |
| +#endif |
| + |
| +/* Return the pathname of the pseudo-terminal slave associated with |
| + the master FD is open on, or NULL on errors. */ |
| +#if !HAVE_PTSNAME |
| +extern char * ptsname(int fd); |
| +#endif |
| + |
| + |
| +/* Set the pathname of the pseudo-terminal slave associated with |
| + the master FD is open on and return 0, or set errno and return |
| + non-zero on errors. */ |
| +#if !HAVE_PTSNAME_R |
| +extern int ptsname_r(int fd, char *buf, size_t len); |
| +#endif |
| + |
| +/* Sort an array of NMEMB elements, starting at address BASE, each element |
| + occupying SIZE bytes, in ascending order according to the comparison |
| + function COMPARE. */ |
| +#if !HAVE_QSORT_R |
| +extern void qsort_r(void *base, size_t nmemb, size_t size, |
| + int (*compare) (void const *, void const *, |
| + void *), |
| + void *arg); |
| +#endif |
| + |
| +#ifndef RAND_MAX |
| +# define RAND_MAX 2147483647 |
| +#endif |
| + |
| +#if !HAVE_RANDOM |
| +extern long random(void); |
| +#endif |
| + |
| +#if !HAVE_SRANDOM |
| +extern void srandom(unsigned int seed); |
| +#endif |
| + |
| + |
| +#if !HAVE_INITSTATE |
| +extern char * initstate(unsigned int seed, char *buf, size_t buf_size); |
| +#endif |
| + |
| +#if !HAVE_SETSTATE |
| +extern char * setstate(char *arg_state); |
| +#endif |
| + |
| + |
| +#if !HAVE_RANDOM_R |
| +extern int random_r(struct random_data *buf, int *result); |
| +#endif |
| + |
| +# if !HAVE_SRANDOM_R |
| +extern int srandom_r(unsigned int seed, struct random_data *rand_state); |
| +#endif |
| + |
| +#if !HAVE_INITSTATE_R |
| +extern int initstate_r(unsigned int seed, char *buf, size_t buf_size, |
| + struct random_data *rand_state); |
| +#endif |
| + |
| +#if !HAVE_SETSTATE_R |
| +extern int setstate_r(char *arg_state, struct random_data *rand_state); |
| +#endif |
| + |
| +#if !HAVE_REALLOCARRAY |
| +extern void * reallocarray(void *ptr, size_t nmemb, size_t size); |
| +#endif |
| + |
| +#if !HAVE_REALPATH |
| +extern char * realpath(const char *name, char *resolved); |
| +#endif |
| + |
| +/* Test a user response to a question. |
| + Return 1 if it is affirmative, 0 if it is negative, or -1 if not clear. */ |
| +#if !HAVE_RPMATCH |
| +extern int rpmatch(const char *response); |
| +#endif |
| + |
| +/* Look up NAME in the environment, returning 0 in insecure situations. */ |
| +#if !HAVE_SECURE_GETENV |
| +extern char * secure_getenv(char const *name); |
| +#endif |
| + |
| + |
| +/* Set NAME to VALUE in the environment. |
| + If REPLACE is nonzero, overwrite an existing value. */ |
| +#if !HAVE_SETENV |
| +extern int setenv(const char *name, const char *value, int replace); |
| +#endif |
| + |
| +/* Parse a double from STRING, updating ENDP if appropriate. */ |
| +#if !HAVE_STRTOD |
| +extern double strtod(const char *str, char **endp); |
| +#endif |
| + |
| +/* Parse a signed integer whose textual representation starts at STRING. |
| + The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0, |
| + it may be decimal or octal (with prefix "0") or hexadecimal (with prefix |
| + "0x"). |
| + If ENDPTR is not NULL, the address of the first byte after the integer is |
| + stored in *ENDPTR. |
| + Upon overflow, the return value is LLONG_MAX or LLONG_MIN, and errno is set |
| + to ERANGE. */ |
| +#if !HAVE_STRTOLL |
| +extern long long strtoll(const char *string, char **endptr, int base); |
| +#endif |
| + |
| +/* Parse an unsigned integer whose textual representation starts at STRING. |
| + The integer is expected to be in base BASE (2 <= BASE <= 36); if BASE == 0, |
| + it may be decimal or octal (with prefix "0") or hexadecimal (with prefix |
| + "0x"). |
| + If ENDPTR is not NULL, the address of the first byte after the integer is |
| + stored in *ENDPTR. |
| + Upon overflow, the return value is ULLONG_MAX, and errno is set to |
| + ERANGE. */ |
| +#if !HAVE_STRTOULL |
| +extern unsigned long long strtoull(const char *string, char **endptr, int base); |
| +#endif |
| + |
| + |
| +/* Unlock the slave side of the pseudo-terminal whose master side is specified |
| + by FD, so that it can be opened. */ |
| +#if !HAVE_UNLOCKPT |
| +extern int unlockpt(int fd); |
| +#endif |
| + |
| +/* Remove the variable NAME from the environment. */ |
| +#if !HAVE_UNSETENV |
| +extern int unsetenv(const char *name); |
| +#endif |
| + |
| +#endif /* _@GUARD_PREFIX@_STDLIB_H */ |
| + |
| diff --git a/headers-mingw/sys_cdefs.h b/headers-mingw/sys_cdefs.h |
| new file mode 100644 |
| index 0000000..98cf749 |
| --- /dev/null |
| +++ b/headers-mingw/sys_cdefs.h |
| @@ -0,0 +1,514 @@ |
| +/* Copyright (C) 1992-2018 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, see |
| + <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef _SYS_CDEFS_H |
| +#define _SYS_CDEFS_H 1 |
| + |
| +/* We are almost always included from features.h. */ |
| +#ifndef _FEATURES_H |
| +# include <features.h> |
| +#endif |
| + |
| +/* The GNU libc does not support any K&R compilers or the traditional mode |
| + of ISO C compilers anymore. Check for some of the combinations not |
| + anymore supported. */ |
| +#if defined __GNUC__ && !defined __STDC__ |
| +# error "You need a ISO C conforming compiler to use the glibc headers" |
| +#endif |
| + |
| +/* Some user header file might have defined this before. */ |
| +#undef __P |
| +#undef __PMT |
| + |
| +#ifdef __GNUC__ |
| + |
| +/* All functions, except those with callbacks or those that |
| + synchronize memory, are leaf functions. */ |
| +# if __GNUC_PREREQ (4, 6) && !defined _LIBC |
| +# define __LEAF , __leaf__ |
| +# define __LEAF_ATTR __attribute__ ((__leaf__)) |
| +# else |
| +# define __LEAF |
| +# define __LEAF_ATTR |
| +# endif |
| + |
| +/* GCC can always grok prototypes. For C++ programs we add throw() |
| + to help it optimize the function calls. But this works only with |
| + gcc 2.8.x and egcs. For gcc 3.2 and up we even mark C functions |
| + as non-throwing using a function attribute since programs can use |
| + the -fexceptions options for C code as well. */ |
| +# if !defined __cplusplus && __GNUC_PREREQ (3, 3) |
| +# define __THROW __attribute__ ((__nothrow__ __LEAF)) |
| +# define __THROWNL __attribute__ ((__nothrow__)) |
| +# define __NTH(fct) __attribute__ ((__nothrow__ __LEAF)) fct |
| +# define __NTHNL(fct) __attribute__ ((__nothrow__)) fct |
| +# else |
| +# if defined __cplusplus && __GNUC_PREREQ (2,8) |
| +# define __THROW throw () |
| +# define __THROWNL throw () |
| +# define __NTH(fct) __LEAF_ATTR fct throw () |
| +# define __NTHNL(fct) fct throw () |
| +# else |
| +# define __THROW |
| +# define __THROWNL |
| +# define __NTH(fct) fct |
| +# define __NTHNL(fct) fct |
| +# endif |
| +# endif |
| + |
| +#else /* Not GCC. */ |
| + |
| +# if (defined __cplusplus \ |
| + || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)) |
| +# define __inline inline |
| +# else |
| +# define __inline /* No inline functions. */ |
| +# endif |
| + |
| +# define __THROW |
| +# define __THROWNL |
| +# define __NTH(fct) fct |
| + |
| +#endif /* GCC. */ |
| + |
| +/* Compilers that are not clang may object to |
| + #if defined __clang__ && __has_extension(...) |
| + even though they do not need to evaluate the right-hand side of the &&. */ |
| +#if defined __clang__ && defined __has_extension |
| +# define __glibc_clang_has_extension(ext) __has_extension (ext) |
| +#else |
| +# define __glibc_clang_has_extension(ext) 0 |
| +#endif |
| + |
| +/* These two macros are not used in glibc anymore. They are kept here |
| + only because some other projects expect the macros to be defined. */ |
| +#define __P(args) args |
| +#define __PMT(args) args |
| + |
| +/* For these things, GCC behaves the ANSI way normally, |
| + and the non-ANSI way under -traditional. */ |
| + |
| +#define __CONCAT(x,y) x ## y |
| +#define __STRING(x) #x |
| + |
| +/* This is not a typedef so `const __ptr_t' does the right thing. */ |
| +#define __ptr_t void * |
| + |
| + |
| +/* C++ needs to know that types and declarations are C, not C++. */ |
| +#ifdef __cplusplus |
| +# define __BEGIN_DECLS extern "C" { |
| +# define __END_DECLS } |
| +#else |
| +# define __BEGIN_DECLS |
| +# define __END_DECLS |
| +#endif |
| + |
| + |
| +/* Fortify support. */ |
| +#define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1) |
| +#define __bos0(ptr) __builtin_object_size (ptr, 0) |
| + |
| +#if __GNUC_PREREQ (4,3) |
| +# define __warndecl(name, msg) \ |
| + extern void name (void) __attribute__((__warning__ (msg))) |
| +# define __warnattr(msg) __attribute__((__warning__ (msg))) |
| +# define __errordecl(name, msg) \ |
| + extern void name (void) __attribute__((__error__ (msg))) |
| +#else |
| +# define __warndecl(name, msg) extern void name (void) |
| +# define __warnattr(msg) |
| +# define __errordecl(name, msg) extern void name (void) |
| +#endif |
| + |
| +/* Support for flexible arrays. |
| + Headers that should use flexible arrays only if they're "real" |
| + (e.g. only if they won't affect sizeof()) should test |
| + #if __glibc_c99_flexarr_available. */ |
| +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L |
| +# define __flexarr [] |
| +# define __glibc_c99_flexarr_available 1 |
| +#elif __GNUC_PREREQ (2,97) |
| +/* GCC 2.97 supports C99 flexible array members as an extension, |
| + even when in C89 mode or compiling C++ (any version). */ |
| +# define __flexarr [] |
| +# define __glibc_c99_flexarr_available 1 |
| +#elif defined __GNUC__ |
| +/* Pre-2.97 GCC did not support C99 flexible arrays but did have |
| + an equivalent extension with slightly different notation. */ |
| +# define __flexarr [0] |
| +# define __glibc_c99_flexarr_available 1 |
| +#else |
| +/* Some other non-C99 compiler. Approximate with [1]. */ |
| +# define __flexarr [1] |
| +# define __glibc_c99_flexarr_available 0 |
| +#endif |
| + |
| + |
| +/* __asm__ ("xyz") is used throughout the headers to rename functions |
| + at the assembly language level. This is wrapped by the __REDIRECT |
| + macro, in order to support compilers that can do this some other |
| + way. When compilers don't support asm-names at all, we have to do |
| + preprocessor tricks instead (which don't have exactly the right |
| + semantics, but it's the best we can do). |
| + |
| + Example: |
| + int __REDIRECT(setpgrp, (__pid_t pid, __pid_t pgrp), setpgid); */ |
| + |
| +#if defined __GNUC__ && __GNUC__ >= 2 |
| + |
| +# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias)) |
| +# ifdef __cplusplus |
| +# define __REDIRECT_NTH(name, proto, alias) \ |
| + name proto __THROW __asm__ (__ASMNAME (#alias)) |
| +# define __REDIRECT_NTHNL(name, proto, alias) \ |
| + name proto __THROWNL __asm__ (__ASMNAME (#alias)) |
| +# else |
| +# define __REDIRECT_NTH(name, proto, alias) \ |
| + name proto __asm__ (__ASMNAME (#alias)) __THROW |
| +# define __REDIRECT_NTHNL(name, proto, alias) \ |
| + name proto __asm__ (__ASMNAME (#alias)) __THROWNL |
| +# endif |
| +# define __ASMNAME(cname) __ASMNAME2 (__USER_LABEL_PREFIX__, cname) |
| +# define __ASMNAME2(prefix, cname) __STRING (prefix) cname |
| + |
| +/* |
| +#elif __SOME_OTHER_COMPILER__ |
| + |
| +# define __REDIRECT(name, proto, alias) name proto; \ |
| + _Pragma("let " #name " = " #alias) |
| +*/ |
| +#endif |
| + |
| +/* GCC has various useful declarations that can be made with the |
| + `__attribute__' syntax. All of the ways we use this do fine if |
| + they are omitted for compilers that don't understand it. */ |
| +#if !defined __GNUC__ || __GNUC__ < 2 |
| +# define __attribute__(xyz) /* Ignore */ |
| +#endif |
| + |
| +/* At some point during the gcc 2.96 development the `malloc' attribute |
| + for functions was introduced. We don't want to use it unconditionally |
| + (although this would be possible) since it generates warnings. */ |
| +#if __GNUC_PREREQ (2,96) |
| +# define __attribute_malloc__ __attribute__ ((__malloc__)) |
| +#else |
| +# define __attribute_malloc__ /* Ignore */ |
| +#endif |
| + |
| +/* Tell the compiler which arguments to an allocation function |
| + indicate the size of the allocation. */ |
| +#if __GNUC_PREREQ (4, 3) |
| +# define __attribute_alloc_size__(params) \ |
| + __attribute__ ((__alloc_size__ params)) |
| +#else |
| +# define __attribute_alloc_size__(params) /* Ignore. */ |
| +#endif |
| + |
| +/* At some point during the gcc 2.96 development the `pure' attribute |
| + for functions was introduced. We don't want to use it unconditionally |
| + (although this would be possible) since it generates warnings. */ |
| +#if __GNUC_PREREQ (2,96) |
| +# define __attribute_pure__ __attribute__ ((__pure__)) |
| +#else |
| +# define __attribute_pure__ /* Ignore */ |
| +#endif |
| + |
| +/* This declaration tells the compiler that the value is constant. */ |
| +#if __GNUC_PREREQ (2,5) |
| +# define __attribute_const__ __attribute__ ((__const__)) |
| +#else |
| +# define __attribute_const__ /* Ignore */ |
| +#endif |
| + |
| +/* At some point during the gcc 3.1 development the `used' attribute |
| + for functions was introduced. We don't want to use it unconditionally |
| + (although this would be possible) since it generates warnings. */ |
| +#if __GNUC_PREREQ (3,1) |
| +# define __attribute_used__ __attribute__ ((__used__)) |
| +# define __attribute_noinline__ __attribute__ ((__noinline__)) |
| +#else |
| +# define __attribute_used__ __attribute__ ((__unused__)) |
| +# define __attribute_noinline__ /* Ignore */ |
| +#endif |
| + |
| +/* Since version 3.2, gcc allows marking deprecated functions. */ |
| +#if __GNUC_PREREQ (3,2) |
| +# define __attribute_deprecated__ __attribute__ ((__deprecated__)) |
| +#else |
| +# define __attribute_deprecated__ /* Ignore */ |
| +#endif |
| + |
| +/* Since version 4.5, gcc also allows one to specify the message printed |
| + when a deprecated function is used. clang claims to be gcc 4.2, but |
| + may also support this feature. */ |
| +#if __GNUC_PREREQ (4,5) || \ |
| + __glibc_clang_has_extension (__attribute_deprecated_with_message__) |
| +# define __attribute_deprecated_msg__(msg) \ |
| + __attribute__ ((__deprecated__ (msg))) |
| +#else |
| +# define __attribute_deprecated_msg__(msg) __attribute_deprecated__ |
| +#endif |
| + |
| +/* At some point during the gcc 2.8 development the `format_arg' attribute |
| + for functions was introduced. We don't want to use it unconditionally |
| + (although this would be possible) since it generates warnings. |
| + If several `format_arg' attributes are given for the same function, in |
| + gcc-3.0 and older, all but the last one are ignored. In newer gccs, |
| + all designated arguments are considered. */ |
| +#if __GNUC_PREREQ (2,8) |
| +# define __attribute_format_arg__(x) __attribute__ ((__format_arg__ (x))) |
| +#else |
| +# define __attribute_format_arg__(x) /* Ignore */ |
| +#endif |
| + |
| +/* At some point during the gcc 2.97 development the `strfmon' format |
| + attribute for functions was introduced. We don't want to use it |
| + unconditionally (although this would be possible) since it |
| + generates warnings. */ |
| +#if __GNUC_PREREQ (2,97) |
| +# define __attribute_format_strfmon__(a,b) \ |
| + __attribute__ ((__format__ (__strfmon__, a, b))) |
| +#else |
| +# define __attribute_format_strfmon__(a,b) /* Ignore */ |
| +#endif |
| + |
| +/* The nonnull function attribute marks pointer parameters that |
| + must not be NULL. Do not define __nonnull if it is already defined, |
| + for portability when this file is used in Gnulib. */ |
| +#ifndef __nonnull |
| +# if __GNUC_PREREQ (3,3) |
| +# define __nonnull(params) __attribute__ ((__nonnull__ params)) |
| +# else |
| +# define __nonnull(params) |
| +# endif |
| +#endif |
| + |
| +/* If fortification mode, we warn about unused results of certain |
| + function calls which can lead to problems. */ |
| +#if __GNUC_PREREQ (3,4) |
| +# define __attribute_warn_unused_result__ \ |
| + __attribute__ ((__warn_unused_result__)) |
| +# if defined __USE_FORTIFY_LEVEL && __USE_FORTIFY_LEVEL > 0 |
| +# define __wur __attribute_warn_unused_result__ |
| +# endif |
| +#else |
| +# define __attribute_warn_unused_result__ /* empty */ |
| +#endif |
| +#ifndef __wur |
| +# define __wur /* Ignore */ |
| +#endif |
| + |
| +/* Forces a function to be always inlined. */ |
| +#if __GNUC_PREREQ (3,2) |
| +/* The Linux kernel defines __always_inline in stddef.h (283d7573), and |
| + it conflicts with this definition. Therefore undefine it first to |
| + allow either header to be included first. */ |
| +# undef __always_inline |
| +# define __always_inline __inline __attribute__ ((__always_inline__)) |
| +#else |
| +# undef __always_inline |
| +# define __always_inline __inline |
| +#endif |
| + |
| +/* Associate error messages with the source location of the call site rather |
| + than with the source location inside the function. */ |
| +#if __GNUC_PREREQ (4,3) |
| +# define __attribute_artificial__ __attribute__ ((__artificial__)) |
| +#else |
| +# define __attribute_artificial__ /* Ignore */ |
| +#endif |
| + |
| +/* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99 |
| + inline semantics, unless -fgnu89-inline is used. Using __GNUC_STDC_INLINE__ |
| + or __GNUC_GNU_INLINE is not a good enough check for gcc because gcc versions |
| + older than 4.3 may define these macros and still not guarantee GNU inlining |
| + semantics. |
| + |
| + clang++ identifies itself as gcc-4.2, but has support for GNU inlining |
| + semantics, that can be checked fot by using the __GNUC_STDC_INLINE_ and |
| + __GNUC_GNU_INLINE__ macro definitions. */ |
| +#if (!defined __cplusplus || __GNUC_PREREQ (4,3) \ |
| + || (defined __clang__ && (defined __GNUC_STDC_INLINE__ \ |
| + || defined __GNUC_GNU_INLINE__))) |
| +# if defined __GNUC_STDC_INLINE__ || defined __cplusplus |
| +# define __extern_inline extern __inline __attribute__ ((__gnu_inline__)) |
| +# define __extern_always_inline \ |
| + extern __always_inline __attribute__ ((__gnu_inline__)) |
| +# else |
| +# define __extern_inline extern __inline |
| +# define __extern_always_inline extern __always_inline |
| +# endif |
| +#endif |
| + |
| +#ifdef __extern_always_inline |
| +# define __fortify_function __extern_always_inline __attribute_artificial__ |
| +#endif |
| + |
| +/* GCC 4.3 and above allow passing all anonymous arguments of an |
| + __extern_always_inline function to some other vararg function. */ |
| +#if __GNUC_PREREQ (4,3) |
| +# define __va_arg_pack() __builtin_va_arg_pack () |
| +# define __va_arg_pack_len() __builtin_va_arg_pack_len () |
| +#endif |
| + |
| +/* It is possible to compile containing GCC extensions even if GCC is |
| + run in pedantic mode if the uses are carefully marked using the |
| + `__extension__' keyword. But this is not generally available before |
| + version 2.8. */ |
| +#if !__GNUC_PREREQ (2,8) |
| +# define __extension__ /* Ignore */ |
| +#endif |
| + |
| +/* __restrict is known in EGCS 1.2 and above. */ |
| +#if !__GNUC_PREREQ (2,92) |
| +# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L |
| +# define __restrict restrict |
| +# else |
| +# define __restrict /* Ignore */ |
| +# endif |
| +#endif |
| + |
| +/* ISO C99 also allows to declare arrays as non-overlapping. The syntax is |
| + array_name[restrict] |
| + GCC 3.1 supports this. */ |
| +#if __GNUC_PREREQ (3,1) && !defined __GNUG__ |
| +# define __restrict_arr __restrict |
| +#else |
| +# ifdef __GNUC__ |
| +# define __restrict_arr /* Not supported in old GCC. */ |
| +# else |
| +# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L |
| +# define __restrict_arr restrict |
| +# else |
| +/* Some other non-C99 compiler. */ |
| +# define __restrict_arr /* Not supported. */ |
| +# endif |
| +# endif |
| +#endif |
| + |
| +#if __GNUC__ >= 3 |
| +# define __glibc_unlikely(cond) __builtin_expect ((cond), 0) |
| +# define __glibc_likely(cond) __builtin_expect ((cond), 1) |
| +#else |
| +# define __glibc_unlikely(cond) (cond) |
| +# define __glibc_likely(cond) (cond) |
| +#endif |
| + |
| +#ifdef __has_attribute |
| +# define __glibc_has_attribute(attr) __has_attribute (attr) |
| +#else |
| +# define __glibc_has_attribute(attr) 0 |
| +#endif |
| + |
| +#if (!defined _Noreturn \ |
| + && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ |
| + && !__GNUC_PREREQ (4,7)) |
| +# if __GNUC_PREREQ (2,8) |
| +# define _Noreturn __attribute__ ((__noreturn__)) |
| +# else |
| +# define _Noreturn |
| +# endif |
| +#endif |
| + |
| +#if __GNUC_PREREQ (8, 0) |
| +/* Describes a char array whose address can safely be passed as the first |
| + argument to strncpy and strncat, as the char array is not necessarily |
| + a NUL-terminated string. */ |
| +# define __attribute_nonstring__ __attribute__ ((__nonstring__)) |
| +#else |
| +# define __attribute_nonstring__ |
| +#endif |
| + |
| +#if (!defined _Static_assert && !defined __cplusplus \ |
| + && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) < 201112 \ |
| + && (!__GNUC_PREREQ (4, 6) || defined __STRICT_ANSI__)) |
| +# define _Static_assert(expr, diagnostic) \ |
| + extern int (*__Static_assert_function (void)) \ |
| + [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })] |
| +#endif |
| + |
| +/* The #ifndef lets Gnulib avoid including these on non-glibc |
| + platforms, where the includes typically do not exist. */ |
| +#ifndef __WORDSIZE |
| +# include <bits/wordsize.h> |
| +# include <bits/long-double.h> |
| +#endif |
| + |
| +#if defined __LONG_DOUBLE_MATH_OPTIONAL && defined __NO_LONG_DOUBLE_MATH |
| +# define __LDBL_COMPAT 1 |
| +# ifdef __REDIRECT |
| +# define __LDBL_REDIR1(name, proto, alias) __REDIRECT (name, proto, alias) |
| +# define __LDBL_REDIR(name, proto) \ |
| + __LDBL_REDIR1 (name, proto, __nldbl_##name) |
| +# define __LDBL_REDIR1_NTH(name, proto, alias) __REDIRECT_NTH (name, proto, alias) |
| +# define __LDBL_REDIR_NTH(name, proto) \ |
| + __LDBL_REDIR1_NTH (name, proto, __nldbl_##name) |
| +# define __LDBL_REDIR1_DECL(name, alias) \ |
| + extern __typeof (name) name __asm (__ASMNAME (#alias)); |
| +# define __LDBL_REDIR_DECL(name) \ |
| + extern __typeof (name) name __asm (__ASMNAME ("__nldbl_" #name)); |
| +# define __REDIRECT_LDBL(name, proto, alias) \ |
| + __LDBL_REDIR1 (name, proto, __nldbl_##alias) |
| +# define __REDIRECT_NTH_LDBL(name, proto, alias) \ |
| + __LDBL_REDIR1_NTH (name, proto, __nldbl_##alias) |
| +# endif |
| +#endif |
| +#if !defined __LDBL_COMPAT || !defined __REDIRECT |
| +# define __LDBL_REDIR1(name, proto, alias) name proto |
| +# define __LDBL_REDIR(name, proto) name proto |
| +# define __LDBL_REDIR1_NTH(name, proto, alias) name proto __THROW |
| +# define __LDBL_REDIR_NTH(name, proto) name proto __THROW |
| +# define __LDBL_REDIR_DECL(name) |
| +# ifdef __REDIRECT |
| +# define __REDIRECT_LDBL(name, proto, alias) __REDIRECT (name, proto, alias) |
| +# define __REDIRECT_NTH_LDBL(name, proto, alias) \ |
| + __REDIRECT_NTH (name, proto, alias) |
| +# endif |
| +#endif |
| + |
| +/* __glibc_macro_warning (MESSAGE) issues warning MESSAGE. This is |
| + intended for use in preprocessor macros. |
| + |
| + Note: MESSAGE must be a _single_ string; concatenation of string |
| + literals is not supported. */ |
| +#if __GNUC_PREREQ (4,8) || __glibc_clang_prereq (3,5) |
| +# define __glibc_macro_warning1(message) _Pragma (#message) |
| +# define __glibc_macro_warning(message) \ |
| + __glibc_macro_warning1 (GCC warning message) |
| +#else |
| +# define __glibc_macro_warning(msg) |
| +#endif |
| + |
| +/* Generic selection (ISO C11) is a C-only feature, available in GCC |
| + since version 4.9. Previous versions do not provide generic |
| + selection, even though they might set __STDC_VERSION__ to 201112L, |
| + when in -std=c11 mode. Thus, we must check for !defined __GNUC__ |
| + when testing __STDC_VERSION__ for generic selection support. |
| + On the other hand, Clang also defines __GNUC__, so a clang-specific |
| + check is required to enable the use of generic selection. */ |
| +#if !defined __cplusplus \ |
| + && (__GNUC_PREREQ (4, 9) \ |
| + || __glibc_clang_has_extension (c_generic_selections) \ |
| + || (!defined __GNUC__ && defined __STDC_VERSION__ \ |
| + && __STDC_VERSION__ >= 201112L)) |
| +# define __HAVE_GENERIC_SELECTION 1 |
| +#else |
| +# define __HAVE_GENERIC_SELECTION 0 |
| +#endif |
| + |
| +#endif /* sys/cdefs.h */ |
| diff --git a/headers-mingw/sys_ioctl.h b/headers-mingw/sys_ioctl.h |
| new file mode 100644 |
| index 0000000..80e9d7b |
| --- /dev/null |
| +++ b/headers-mingw/sys_ioctl.h |
| @@ -0,0 +1,36 @@ |
| +/* Substitute for and wrapper around <sys/ioctl.h>. |
| + Copyright (C) 2008-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef _GL_SYS_IOCTL_H |
| + |
| +#define _GL_SYS_IOCTL_H |
| + |
| +/* AIX 5.1 and Solaris 10 declare ioctl() in <unistd.h> and in <stropts.h>, |
| + but not in <sys/ioctl.h>. |
| + Haiku declares ioctl() in <unistd.h>, but not in <sys/ioctl.h>. |
| + But avoid namespace pollution on glibc systems. */ |
| +#ifndef __GLIBC__ |
| +# include <unistd.h> |
| +#endif |
| + |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| + |
| +/* Declare overridden functions. */ |
| + |
| +#endif /* _@GUARD_PREFIX@_SYS_IOCTL_H */ |
| diff --git a/headers-mingw/sys_stat.h b/headers-mingw/sys_stat.h |
| new file mode 100644 |
| index 0000000..2b06b15 |
| --- /dev/null |
| +++ b/headers-mingw/sys_stat.h |
| @@ -0,0 +1,506 @@ |
| +/* Provide a more complete sys/stat.h header file. |
| + Copyright (C) 2005-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Written by Eric Blake, Paul Eggert, and Jim Meyering. */ |
| + |
| +/* This file is supposed to be used on platforms where <sys/stat.h> is |
| + incomplete. It is intended to provide definitions and prototypes |
| + needed by an application. Start with what the system provides. */ |
| + |
| +/* Normal invocation convention. */ |
| + |
| +#ifndef _GL_SYS_STAT_H |
| + |
| +/* Get nlink_t. |
| + May also define off_t to a 64-bit type on native Windows. */ |
| +#include <sys/types.h> |
| + |
| +/* Get struct timespec. */ |
| +#include <time.h> |
| + |
| +#define _GL_SYS_STAT_H |
| + |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_ARG_NONNULL is copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| +/* Before doing "#define mkdir rpl_mkdir" below, we need to include all |
| + headers that may declare mkdir(). Native Windows platforms declare mkdir |
| + in <io.h> and/or <direct.h>, not in <unistd.h>. */ |
| +#if defined _WIN32 && ! defined __CYGWIN__ |
| +# include <io.h> /* mingw32, mingw64 */ |
| +# include <direct.h> /* mingw64, MSVC 9 */ |
| +#endif |
| + |
| +//# if !GNULIB_defined_struct_stat |
| +//struct stat |
| +//{ |
| +// dev_t st_dev; |
| +// ino_t st_ino; |
| +// mode_t st_mode; |
| +// nlink_t st_nlink; |
| +//# if 0 |
| +// uid_t st_uid; |
| +//# else /* uid_t is not defined by default on native Windows. */ |
| +// int st_uid; |
| +//# endif |
| +//# if 0 |
| +// gid_t st_gid; |
| +//# else /* gid_t is not defined by default on native Windows. */ |
| +// int st_gid; |
| +//# endif |
| +// dev_t st_rdev; |
| +// off_t st_size; |
| +//# if 0 |
| +// blksize_t st_blksize; |
| +// blkcnt_t st_blocks; |
| +//# endif |
| +// |
| +////# if @WINDOWS_STAT_TIMESPEC@ |
| +// struct timespec st_atim; |
| +// struct timespec st_mtim; |
| +// struct timespec st_ctim; |
| +////# else |
| +//// time_t st_atime; |
| +//// time_t st_mtime; |
| +//// time_t st_ctime; |
| +////# endif |
| +//}; |
| +////# if @WINDOWS_STAT_TIMESPEC@ |
| +//# define st_atime st_atim.tv_sec |
| +//# define st_mtime st_mtim.tv_sec |
| +//# define st_ctime st_ctim.tv_sec |
| +// /* Indicator, for gnulib internal purposes. */ |
| +//# define _GL_WINDOWS_STAT_TIMESPEC 1 |
| +////# endif |
| +//# define GNULIB_defined_struct_stat 1 |
| +//# endif |
| + |
| +#ifndef S_IFIFO |
| +# ifdef _S_IFIFO |
| +# define S_IFIFO _S_IFIFO |
| +# endif |
| +#endif |
| + |
| +#ifndef S_IFMT |
| +# define S_IFMT 0170000 |
| +#endif |
| + |
| +#if STAT_MACROS_BROKEN |
| +# undef S_ISBLK |
| +# undef S_ISCHR |
| +# undef S_ISDIR |
| +# undef S_ISFIFO |
| +# undef S_ISLNK |
| +# undef S_ISNAM |
| +# undef S_ISMPB |
| +# undef S_ISMPC |
| +# undef S_ISNWK |
| +# undef S_ISREG |
| +# undef S_ISSOCK |
| +#endif |
| + |
| +#ifndef S_ISBLK |
| +# ifdef S_IFBLK |
| +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) |
| +# else |
| +# define S_ISBLK(m) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_ISCHR |
| +# ifdef S_IFCHR |
| +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) |
| +# else |
| +# define S_ISCHR(m) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_ISDIR |
| +# ifdef S_IFDIR |
| +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) |
| +# else |
| +# define S_ISDIR(m) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_ISDOOR /* Solaris 2.5 and up */ |
| +# define S_ISDOOR(m) 0 |
| +#endif |
| + |
| +#ifndef S_ISFIFO |
| +# ifdef S_IFIFO |
| +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) |
| +# else |
| +# define S_ISFIFO(m) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_ISLNK |
| +# ifdef S_IFLNK |
| +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) |
| +# else |
| +# define S_ISLNK(m) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_ISMPB /* V7 */ |
| +# ifdef S_IFMPB |
| +# define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) |
| +# define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) |
| +# else |
| +# define S_ISMPB(m) 0 |
| +# define S_ISMPC(m) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_ISMPX /* AIX */ |
| +# define S_ISMPX(m) 0 |
| +#endif |
| + |
| +#ifndef S_ISNAM /* Xenix */ |
| +# ifdef S_IFNAM |
| +# define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM) |
| +# else |
| +# define S_ISNAM(m) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_ISNWK /* HP/UX */ |
| +# ifdef S_IFNWK |
| +# define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) |
| +# else |
| +# define S_ISNWK(m) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_ISPORT /* Solaris 10 and up */ |
| +# define S_ISPORT(m) 0 |
| +#endif |
| + |
| +#ifndef S_ISREG |
| +# ifdef S_IFREG |
| +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) |
| +# else |
| +# define S_ISREG(m) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_ISSOCK |
| +# ifdef S_IFSOCK |
| +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) |
| +# else |
| +# define S_ISSOCK(m) 0 |
| +# endif |
| +#endif |
| + |
| + |
| +#ifndef S_TYPEISMQ |
| +# define S_TYPEISMQ(p) 0 |
| +#endif |
| + |
| +#ifndef S_TYPEISTMO |
| +# define S_TYPEISTMO(p) 0 |
| +#endif |
| + |
| + |
| +#ifndef S_TYPEISSEM |
| +# ifdef S_INSEM |
| +# define S_TYPEISSEM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSEM) |
| +# else |
| +# define S_TYPEISSEM(p) 0 |
| +# endif |
| +#endif |
| + |
| +#ifndef S_TYPEISSHM |
| +# ifdef S_INSHD |
| +# define S_TYPEISSHM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSHD) |
| +# else |
| +# define S_TYPEISSHM(p) 0 |
| +# endif |
| +#endif |
| + |
| +/* high performance ("contiguous data") */ |
| +#ifndef S_ISCTG |
| +# define S_ISCTG(p) 0 |
| +#endif |
| + |
| +/* Cray DMF (data migration facility): off line, with data */ |
| +#ifndef S_ISOFD |
| +# define S_ISOFD(p) 0 |
| +#endif |
| + |
| +/* Cray DMF (data migration facility): off line, with no data */ |
| +#ifndef S_ISOFL |
| +# define S_ISOFL(p) 0 |
| +#endif |
| + |
| +/* 4.4BSD whiteout */ |
| +#ifndef S_ISWHT |
| +# define S_ISWHT(m) 0 |
| +#endif |
| + |
| +/* If any of the following are undefined, |
| + define them to their de facto standard values. */ |
| +#if !S_ISUID |
| +# define S_ISUID 04000 |
| +#endif |
| +#if !S_ISGID |
| +# define S_ISGID 02000 |
| +#endif |
| + |
| +/* S_ISVTX is a common extension to POSIX. */ |
| +#ifndef S_ISVTX |
| +# define S_ISVTX 01000 |
| +#endif |
| + |
| +#if !S_IRUSR && S_IREAD |
| +# define S_IRUSR S_IREAD |
| +#endif |
| +#if !S_IRUSR |
| +# define S_IRUSR 00400 |
| +#endif |
| +#if !S_IRGRP |
| +# define S_IRGRP (S_IRUSR >> 3) |
| +#endif |
| +#if !S_IROTH |
| +# define S_IROTH (S_IRUSR >> 6) |
| +#endif |
| + |
| +#if !S_IWUSR && S_IWRITE |
| +# define S_IWUSR S_IWRITE |
| +#endif |
| +#if !S_IWUSR |
| +# define S_IWUSR 00200 |
| +#endif |
| +#if !S_IWGRP |
| +# define S_IWGRP (S_IWUSR >> 3) |
| +#endif |
| +#if !S_IWOTH |
| +# define S_IWOTH (S_IWUSR >> 6) |
| +#endif |
| + |
| +#if !S_IXUSR && S_IEXEC |
| +# define S_IXUSR S_IEXEC |
| +#endif |
| +#if !S_IXUSR |
| +# define S_IXUSR 00100 |
| +#endif |
| +#if !S_IXGRP |
| +# define S_IXGRP (S_IXUSR >> 3) |
| +#endif |
| +#if !S_IXOTH |
| +# define S_IXOTH (S_IXUSR >> 6) |
| +#endif |
| + |
| +#if !S_IRWXU |
| +# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) |
| +#endif |
| +#if !S_IRWXG |
| +# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) |
| +#endif |
| +#if !S_IRWXO |
| +# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH) |
| +#endif |
| + |
| +/* S_IXUGO is a common extension to POSIX. */ |
| +#if !S_IXUGO |
| +# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) |
| +#endif |
| + |
| +#ifndef S_IRWXUGO |
| +# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO) |
| +#endif |
| + |
| +/* Macros for futimens and utimensat. */ |
| +#ifndef UTIME_NOW |
| +# define UTIME_NOW (-1) |
| +# define UTIME_OMIT (-2) |
| +#endif |
| + |
| +#if !HAVE_FCHMODAT |
| +extern int fchmodat(int fd, char const *file, mode_t mode, int flag); |
| +#endif |
| + |
| + |
| +#if !HAVE_FSTATAT |
| +extern int fstatat(int fd, char const *name, struct stat *st, int flags); |
| +#endif |
| + |
| +#if !HAVE_FUTIMENS |
| +extern int futimens(int fd, struct timespec const times[2]); |
| +#endif |
| + |
| +/* Change the mode of FILENAME to MODE, without dereferencing it if FILENAME |
| + denotes a symbolic link. */ |
| +#if !HAVE_LCHMOD |
| +/* The lchmod replacement follows symbolic links. Callers should take |
| + this into account; lchmod should be applied only to arguments that |
| + are known to not be symbolic links. On hosts that lack lchmod, |
| + this can lead to race conditions between the check and the |
| + invocation of lchmod, but we know of no workarounds that are |
| + reliable in general. You might try requesting support for lchmod |
| + from your operating system supplier. */ |
| +#define lchmod chmod |
| +#endif |
| + |
| +#if !HAVE_LSTAT |
| +/* mingw does not support symlinks, therefore it does not have lstat. But |
| + without links, stat does just fine. */ |
| +#define lstat stat |
| +#endif |
| + |
| + |
| +//#if @REPLACE_MKDIR@ |
| +//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) |
| +//# undef mkdir |
| +//# define mkdir rpl_mkdir |
| +//# endif |
| +//_GL_FUNCDECL_RPL (mkdir, int, (char const *name, mode_t mode) |
| +// _GL_ARG_NONNULL ((1))); |
| +//_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode)); |
| +//#else |
| +///* mingw's _mkdir() function has 1 argument, but we pass 2 arguments. |
| +// Additionally, it declares _mkdir (and depending on compile flags, an |
| +// alias mkdir), only in the nonstandard includes <direct.h> and <io.h>, |
| +// which are included above. */ |
| +//# if defined _WIN32 && ! defined __CYGWIN__ |
| +// |
| +//# if !GNULIB_defined_rpl_mkdir |
| +//static int |
| +//rpl_mkdir (char const *name, mode_t mode) |
| +//{ |
| +// return _mkdir (name); |
| +//} |
| +//# define GNULIB_defined_rpl_mkdir 1 |
| +//# endif |
| +// |
| +//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) |
| +//# define mkdir rpl_mkdir |
| +//# endif |
| +//_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode)); |
| +//# else |
| +//_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode)); |
| +//# endif |
| +//#endif |
| +//_GL_CXXALIASWARN (mkdir); |
| + |
| + |
| +#if !HAVE_MKDIRAT |
| +extern int mkdirat(int fd, char const *file, mode_t mode); |
| +#endif |
| + |
| +#if !HAVE_MKFIFO |
| +extern int mkfifo(char const *file, mode_t mode); |
| +#endif |
| + |
| +#if !HAVE_MKFIFOAT |
| +extern int mkfifoat(int fd, char const *file, mode_t mode); |
| +#endif |
| + |
| + |
| +#if !HAVE_MKNOD |
| +extern int mknod(char const *file, mode_t mode, dev_t dev); |
| +#endif |
| + |
| +#if !HAVE_MKNODAT |
| +extern int mknodat(int fd, char const *file, mode_t mode, dev_t dev); |
| +#endif |
| + |
| + |
| +//#if @GNULIB_STAT@ |
| +//# if @REPLACE_STAT@ |
| +//# if !@GNULIB_OVERRIDES_STRUCT_STAT@ |
| +// /* We can't use the object-like #define stat rpl_stat, because of |
| +// struct stat. This means that rpl_stat will not be used if the user |
| +// does (stat)(a,b). Oh well. */ |
| +//# if defined _AIX && defined stat && defined _LARGE_FILES |
| +// /* With _LARGE_FILES defined, AIX (only) defines stat to stat64, |
| +// so we have to replace stat64() instead of stat(). */ |
| +//# undef stat64 |
| +//# define stat64(name, st) rpl_stat (name, st) |
| +//# elif @WINDOWS_64_BIT_ST_SIZE@ |
| +// /* Above, we define stat to _stati64. */ |
| +//# if defined __MINGW32__ && defined _stati64 |
| +//# ifndef _USE_32BIT_TIME_T |
| +// /* The system headers define _stati64 to _stat64. */ |
| +//# undef _stat64 |
| +//# define _stat64(name, st) rpl_stat (name, st) |
| +//# endif |
| +//# elif defined _MSC_VER && defined _stati64 |
| +//# ifdef _USE_32BIT_TIME_T |
| +// /* The system headers define _stati64 to _stat32i64. */ |
| +//# undef _stat32i64 |
| +//# define _stat32i64(name, st) rpl_stat (name, st) |
| +//# else |
| +// /* The system headers define _stati64 to _stat64. */ |
| +//# undef _stat64 |
| +//# define _stat64(name, st) rpl_stat (name, st) |
| +//# endif |
| +//# else |
| +//# undef _stati64 |
| +//# define _stati64(name, st) rpl_stat (name, st) |
| +//# endif |
| +//# elif defined __MINGW32__ && defined stat |
| +//# ifdef _USE_32BIT_TIME_T |
| +// /* The system headers define stat to _stat32i64. */ |
| +//# undef _stat32i64 |
| +//# define _stat32i64(name, st) rpl_stat (name, st) |
| +//# else |
| +// /* The system headers define stat to _stat64. */ |
| +//# undef _stat64 |
| +//# define _stat64(name, st) rpl_stat (name, st) |
| +//# endif |
| +//# elif defined _MSC_VER && defined stat |
| +//# ifdef _USE_32BIT_TIME_T |
| +// /* The system headers define stat to _stat32. */ |
| +//# undef _stat32 |
| +//# define _stat32(name, st) rpl_stat (name, st) |
| +//# else |
| +// /* The system headers define stat to _stat64i32. */ |
| +//# undef _stat64i32 |
| +//# define _stat64i32(name, st) rpl_stat (name, st) |
| +//# endif |
| +//# else /* !(_AIX || __MINGW32__ || _MSC_VER) */ |
| +//# undef stat |
| +//# define stat(name, st) rpl_stat (name, st) |
| +//# endif /* !_LARGE_FILES */ |
| +//# endif /* !@GNULIB_OVERRIDES_STRUCT_STAT@ */ |
| +//_GL_EXTERN_C int stat (const char *name, struct stat *buf) |
| +// _GL_ARG_NONNULL ((1, 2)); |
| +//# endif |
| +//#elif @GNULIB_OVERRIDES_STRUCT_STAT@ |
| +///* see above: |
| +// #define stat stat_used_without_requesting_gnulib_module_stat |
| +// */ |
| +//#elif defined GNULIB_POSIXCHECK |
| +//# undef stat |
| +//# if HAVE_RAW_DECL_STAT |
| +//_GL_WARN_ON_USE (stat, "stat is unportable - " |
| +// "use gnulib module stat for portability"); |
| +//# endif |
| +//#endif |
| + |
| +#if !HAVE_UTIMENSAT |
| +extern int utimensat(int fd, char const *name, |
| + struct timespec const times[2], int flag); |
| +#endif |
| + |
| + |
| +#endif /* _@GUARD_PREFIX@_SYS_STAT_H */ |
| + |
| diff --git a/headers-mingw/sys_utsname.h b/headers-mingw/sys_utsname.h |
| new file mode 100644 |
| index 0000000..c9733a7 |
| --- /dev/null |
| +++ b/headers-mingw/sys_utsname.h |
| @@ -0,0 +1,80 @@ |
| +/* Substitute for <sys/utsname.h>. |
| + Copyright (C) 2009-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef _GL_SYS_UTSNAME_H |
| +#define _GL_SYS_UTSNAME_H |
| + |
| +/* The definition of _GL_ARG_NONNULL is copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| + |
| +#ifdef __cplusplus |
| +extern "C" { |
| +#endif |
| + |
| + |
| +/* Length of the entries in 'struct utsname' is 256. */ |
| +#define _UTSNAME_LENGTH 256 |
| + |
| +#ifndef _UTSNAME_NODENAME_LENGTH |
| +# define _UTSNAME_NODENAME_LENGTH _UTSNAME_LENGTH |
| +#endif |
| +#ifndef _UTSNAME_SYSNAME_LENGTH |
| +# define _UTSNAME_SYSNAME_LENGTH _UTSNAME_LENGTH |
| +#endif |
| +#ifndef _UTSNAME_RELEASE_LENGTH |
| +# define _UTSNAME_RELEASE_LENGTH _UTSNAME_LENGTH |
| +#endif |
| +#ifndef _UTSNAME_VERSION_LENGTH |
| +# define _UTSNAME_VERSION_LENGTH _UTSNAME_LENGTH |
| +#endif |
| +#ifndef _UTSNAME_MACHINE_LENGTH |
| +# define _UTSNAME_MACHINE_LENGTH _UTSNAME_LENGTH |
| +#endif |
| + |
| +# if !GNULIB_defined_struct_utsname |
| +/* Structure describing the system and machine. */ |
| +struct utsname |
| + { |
| + /* Name of this node on the network. */ |
| + char nodename[_UTSNAME_NODENAME_LENGTH]; |
| + |
| + /* Name of the implementation of the operating system. */ |
| + char sysname[_UTSNAME_SYSNAME_LENGTH]; |
| + /* Current release level of this implementation. */ |
| + char release[_UTSNAME_RELEASE_LENGTH]; |
| + /* Current version level of this release. */ |
| + char version[_UTSNAME_VERSION_LENGTH]; |
| + |
| + /* Name of the hardware type the system is running on. */ |
| + char machine[_UTSNAME_MACHINE_LENGTH]; |
| + }; |
| +# define GNULIB_defined_struct_utsname 1 |
| +# endif |
| + |
| +# if !HAVE_UNAME |
| +extern int uname (struct utsname *buf); |
| +# endif |
| + |
| + |
| + |
| +#ifdef __cplusplus |
| +} |
| +#endif |
| + |
| + |
| +#endif /* _@GUARD_PREFIX@_SYS_UTSNAME_H */ |
| diff --git a/headers-mingw/sys_wait.h b/headers-mingw/sys_wait.h |
| new file mode 100644 |
| index 0000000..c5a90af |
| --- /dev/null |
| +++ b/headers-mingw/sys_wait.h |
| @@ -0,0 +1,65 @@ |
| +/* A POSIX-like <sys/wait.h>. |
| + Copyright (C) 2001-2003, 2005-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef _GL_SYS_WAIT_H |
| +#define _GL_SYS_WAIT_H |
| + |
| +/* Get pid_t. */ |
| +#include <sys/types.h> |
| + |
| + |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| +/* Native Windows API. */ |
| + |
| +#include <signal.h> /* for SIGTERM */ |
| + |
| +/* The following macros apply to an argument x, that is a status of a process, |
| + as returned by waitpid() or, equivalently, _cwait() or GetExitCodeProcess(). |
| + This value is simply an 'int', not composed of bit fields. */ |
| + |
| +/* When an unhandled fatal signal terminates a process, the exit code is 3. */ |
| +#define WIFSIGNALED(x) ((x) == 3) |
| +#define WIFEXITED(x) ((x) != 3) |
| +#define WIFSTOPPED(x) 0 |
| + |
| +/* The signal that terminated a process is not known posthum. */ |
| +#define WTERMSIG(x) SIGTERM |
| + |
| +#define WEXITSTATUS(x) (x) |
| + |
| +/* There are no stopping signals. */ |
| +#define WSTOPSIG(x) 0 |
| + |
| +/* There are no core dumps. */ |
| +#define WCOREDUMP(x) 0 |
| + |
| + |
| + |
| + |
| +/* Declarations of functions. */ |
| + |
| +#if !HAVE_WAITPID |
| +/* dummy constants */ |
| +#define WNOHANG (-1) |
| +#define WUNTRACED (-1) |
| +extern pid_t waitpid(pid_t pid, int *statusp, int options); |
| +#endif |
| + |
| + |
| +#endif /* _@GUARD_PREFIX@_SYS_WAIT_H */ |
| diff --git a/headers-mingw/unistd.h b/headers-mingw/unistd.h |
| new file mode 100644 |
| index 0000000..216d3b4 |
| --- /dev/null |
| +++ b/headers-mingw/unistd.h |
| @@ -0,0 +1,566 @@ |
| +/* Substitute for and wrapper around <unistd.h>. |
| + Copyright (C) 2003-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef _GL_UNISTD_H |
| + |
| +/* NetBSD 5.0 mis-defines NULL. Also get size_t. */ |
| +#include <stddef.h> |
| + |
| +/* mingw doesn't define the SEEK_* or *_FILENO macros in <unistd.h>. */ |
| +/* MSVC declares 'unlink' in <stdio.h>, not in <unistd.h>. We must include |
| + it before we #define unlink rpl_unlink. */ |
| +/* Cygwin 1.7.1 declares symlinkat in <stdio.h>, not in <unistd.h>. */ |
| +/* But avoid namespace pollution on glibc systems. */ |
| +#if (!(defined SEEK_CUR && defined SEEK_END && defined SEEK_SET) \ |
| + || (defined _WIN32 && ! defined __CYGWIN__) \ |
| + || defined __CYGWIN__) \ |
| + && ! defined __GLIBC__ |
| +# include <stdio.h> |
| +#endif |
| + |
| +/* Cygwin 1.7.1 declares unlinkat in <fcntl.h>, not in <unistd.h>. */ |
| +/* But avoid namespace pollution on glibc systems. */ |
| +#if defined __CYGWIN__ \ |
| + && ! defined __GLIBC__ |
| +# include <fcntl.h> |
| +#endif |
| + |
| +/* mingw fails to declare _exit in <unistd.h>. */ |
| +/* mingw, MSVC, BeOS, Haiku declare environ in <stdlib.h>, not in |
| + <unistd.h>. */ |
| +/* Solaris declares getcwd not only in <unistd.h> but also in <stdlib.h>. */ |
| +/* OSF Tru64 Unix cannot see gnulib rpl_strtod when system <stdlib.h> is |
| + included here. */ |
| +/* But avoid namespace pollution on glibc systems. */ |
| +#if !defined __GLIBC__ && !defined __osf__ |
| +# define __need_system_stdlib_h |
| +# include <stdlib.h> |
| +# undef __need_system_stdlib_h |
| +#endif |
| + |
| +/* Native Windows platforms declare chdir, getcwd, rmdir in |
| + <io.h> and/or <direct.h>, not in <unistd.h>. |
| + They also declare access(), chmod(), close(), dup(), dup2(), isatty(), |
| + lseek(), read(), unlink(), write() in <io.h>. */ |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +# include <io.h> /* mingw32, mingw64 */ |
| +# include <direct.h> /* mingw64, MSVC 9 */ |
| +#endif |
| + |
| +/* AIX and OSF/1 5.1 declare getdomainname in <netdb.h>, not in <unistd.h>. |
| + NonStop Kernel declares gethostname in <netdb.h>, not in <unistd.h>. */ |
| +/* But avoid namespace pollution on glibc systems. */ |
| +#if ((defined _AIX || defined __osf__) \ |
| + || defined __TANDEM) \ |
| + && !defined __GLIBC__ |
| +# include <netdb.h> |
| +#endif |
| + |
| +/* MSVC defines off_t in <sys/types.h>. |
| + May also define off_t to a 64-bit type on native Windows. */ |
| +/* Get off_t. */ |
| +# include <sys/types.h> |
| +/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */ |
| + |
| +/* The definition of _GL_ARG_NONNULL is copied here. */ |
| + |
| +/* The definition of _GL_WARN_ON_USE is copied here. */ |
| + |
| + |
| +///* Get getopt(), optarg, optind, opterr, optopt. */ |
| +//#if @GNULIB_UNISTD_H_GETOPT@ && !defined _GL_SYSTEM_GETOPT |
| +//# include <getopt-cdefs.h> |
| +//# include <getopt-pfx-core.h> |
| +//#endif |
| + |
| +#ifndef _GL_UNISTD_INLINE |
| +# define _GL_UNISTD_INLINE _GL_INLINE |
| +#endif |
| + |
| +///* Hide some function declarations from <winsock2.h>. */ |
| +// |
| +//#if @GNULIB_GETHOSTNAME@ && @UNISTD_H_HAVE_WINSOCK2_H@ |
| +//# if !defined _@GUARD_PREFIX@_SYS_SOCKET_H |
| +//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) |
| +//# undef socket |
| +//# define socket socket_used_without_including_sys_socket_h |
| +//# undef connect |
| +//# define connect connect_used_without_including_sys_socket_h |
| +//# undef accept |
| +//# define accept accept_used_without_including_sys_socket_h |
| +//# undef bind |
| +//# define bind bind_used_without_including_sys_socket_h |
| +//# undef getpeername |
| +//# define getpeername getpeername_used_without_including_sys_socket_h |
| +//# undef getsockname |
| +//# define getsockname getsockname_used_without_including_sys_socket_h |
| +//# undef getsockopt |
| +//# define getsockopt getsockopt_used_without_including_sys_socket_h |
| +//# undef listen |
| +//# define listen listen_used_without_including_sys_socket_h |
| +//# undef recv |
| +//# define recv recv_used_without_including_sys_socket_h |
| +//# undef send |
| +//# define send send_used_without_including_sys_socket_h |
| +//# undef recvfrom |
| +//# define recvfrom recvfrom_used_without_including_sys_socket_h |
| +//# undef sendto |
| +//# define sendto sendto_used_without_including_sys_socket_h |
| +//# undef setsockopt |
| +//# define setsockopt setsockopt_used_without_including_sys_socket_h |
| +//# undef shutdown |
| +//# define shutdown shutdown_used_without_including_sys_socket_h |
| +//# else |
| +// _GL_WARN_ON_USE (socket, |
| +// "socket() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (connect, |
| +// "connect() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (accept, |
| +// "accept() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (bind, |
| +// "bind() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (getpeername, |
| +// "getpeername() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (getsockname, |
| +// "getsockname() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (getsockopt, |
| +// "getsockopt() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (listen, |
| +// "listen() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (recv, |
| +// "recv() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (send, |
| +// "send() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (recvfrom, |
| +// "recvfrom() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (sendto, |
| +// "sendto() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (setsockopt, |
| +// "setsockopt() used without including <sys/socket.h>"); |
| +// _GL_WARN_ON_USE (shutdown, |
| +// "shutdown() used without including <sys/socket.h>"); |
| +//# endif |
| +//# endif |
| +//# if !defined _@GUARD_PREFIX@_SYS_SELECT_H |
| +//# if !(defined __cplusplus && defined GNULIB_NAMESPACE) |
| +//# undef select |
| +//# define select select_used_without_including_sys_select_h |
| +//# else |
| +// _GL_WARN_ON_USE (select, |
| +// "select() used without including <sys/select.h>"); |
| +//# endif |
| +//# endif |
| +//#endif |
| + |
| + |
| +/* OS/2 EMX lacks these macros. */ |
| +#ifndef STDIN_FILENO |
| +# define STDIN_FILENO 0 |
| +#endif |
| +#ifndef STDOUT_FILENO |
| +# define STDOUT_FILENO 1 |
| +#endif |
| +#ifndef STDERR_FILENO |
| +# define STDERR_FILENO 2 |
| +#endif |
| + |
| +/* Ensure *_OK macros exist. */ |
| +#ifndef F_OK |
| +# define F_OK 0 |
| +# define X_OK 1 |
| +# define W_OK 2 |
| +# define R_OK 4 |
| +#endif |
| + |
| +#ifndef MAXSYMLINKS |
| +# ifdef SYMLOOP_MAX |
| +# define MAXSYMLINKS SYMLOOP_MAX |
| +# else |
| +# define MAXSYMLINKS 20 |
| +# endif |
| +#endif |
| + |
| + |
| +/* Declare overridden functions. */ |
| + |
| +/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE |
| + to GID (if GID is not -1). Follow symbolic links. |
| + Return 0 if successful, otherwise -1 and errno set. |
| + See the POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html. */ |
| +# if !HAVE_CHOWN |
| +extern int chown(const char *file, int uid, int gid); |
| +# endif |
| + |
| + |
| +/* Copy the file descriptor OLDFD into file descriptor NEWFD. Do nothing if |
| + NEWFD = OLDFD, otherwise close NEWFD first if it is open. |
| + Return newfd if successful, otherwise -1 and errno set. |
| + See the POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup2.html>. */ |
| +#if !HAVE_DUP2 |
| +extern int dup2(int oldfd, int newfd); |
| +#endif |
| + |
| +/* Copy the file descriptor OLDFD into file descriptor NEWFD, with the |
| + specified flags. |
| + The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>) |
| + and O_TEXT, O_BINARY (defined in "binary-io.h"). |
| + Close NEWFD first if it is open. |
| + Return newfd if successful, otherwise -1 and errno set. |
| + See the Linux man page at |
| + <https://www.kernel.org/doc/man-pages/online/pages/man2/dup3.2.html>. */ |
| +#if !HAVE_DUP3 |
| +extern int dup3(int oldfd, int newfd, int flags); |
| +#endif |
| + |
| + |
| +//#if @GNULIB_ENVIRON@ |
| +//# if defined __CYGWIN__ && !defined __i386__ |
| +///* The 'environ' variable is defined in a DLL. Therefore its declaration needs |
| +// the '__declspec(dllimport)' attribute, but the system's <unistd.h> lacks it. |
| +// This leads to a link error on 64-bit Cygwin when the option |
| +// -Wl,--disable-auto-import is in use. */ |
| +//_GL_EXTERN_C __declspec(dllimport) char **environ; |
| +//# endif |
| +//# if !@HAVE_DECL_ENVIRON@ |
| +///* Set of environment variables and values. An array of strings of the form |
| +// "VARIABLE=VALUE", terminated with a NULL. */ |
| +//# if defined __APPLE__ && defined __MACH__ |
| +//# include <TargetConditionals.h> |
| +//# if !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR |
| +//# define _GL_USE_CRT_EXTERNS |
| +//# endif |
| +//# endif |
| +//# ifdef _GL_USE_CRT_EXTERNS |
| +//# include <crt_externs.h> |
| +//# define environ (*_NSGetEnviron ()) |
| +//# else |
| +//# ifdef __cplusplus |
| +//extern "C" { |
| +//# endif |
| +//extern char **environ; |
| +//# ifdef __cplusplus |
| +//} |
| +//# endif |
| +//# endif |
| +//# endif |
| +//#elif defined GNULIB_POSIXCHECK |
| +//# if HAVE_RAW_DECL_ENVIRON |
| +//_GL_UNISTD_INLINE char *** |
| +//_GL_WARN_ON_USE_ATTRIBUTE ("environ is unportable - " |
| +// "use gnulib module environ for portability") |
| +//rpl_environ (void) |
| +//{ |
| +// return &environ; |
| +//} |
| +//# undef environ |
| +//# define environ (*rpl_environ ()) |
| +//# endif |
| +//#endif |
| + |
| + |
| +/* Like access(), except that it uses the effective user id and group id of |
| + the current process. */ |
| +# if !HAVE_EUIDACCESS |
| +extern int euidaccess(const char *filename, int mode); |
| +#endif |
| + |
| + |
| +#if !HAVE_FACCESSAT |
| +extern int faccessat(int fd, char const *file, int mode, int flag); |
| +#endif |
| + |
| + |
| +/* Change the process' current working directory to the directory on which |
| + the given file descriptor is open. |
| + Return 0 if successful, otherwise -1 and errno set. |
| + See the POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html>. */ |
| +#if !HAVE_FCHDIR |
| +extern int fchdir(int fd); |
| + |
| +/* Gnulib internal hooks needed to maintain the fchdir metadata. */ |
| +extern int _gl_register_fd (int fd, const char *filename); |
| +extern void _gl_unregister_fd (int fd); |
| +extern int _gl_register_dup (int oldfd, int newfd); |
| +extern const char *_gl_directory_name (int fd); |
| +#endif |
| + |
| + |
| +#if !HAVE_FCHOWNAT |
| +extern int fchownat(int fd, char const *file, |
| + int owner, int group, int flag); |
| +#endif |
| + |
| +/* Synchronize changes to a file. |
| + Return 0 if successful, otherwise -1 and errno set. |
| + See POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html>. */ |
| +#if !HAVE_FDATASYNC |
| +extern int fdatasync(int fd); |
| +#endif |
| + |
| +/* Synchronize changes, including metadata, to a file. |
| + Return 0 if successful, otherwise -1 and errno set. |
| + See POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html>. */ |
| +#if !HAVE_FSYNC |
| +extern int fsync(int fd); |
| +#endif |
| + |
| +/* Change the size of the file to which FD is opened to become equal to LENGTH. |
| + Return 0 if successful, otherwise -1 and errno set. |
| + See the POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html>. */ |
| +#if !HAVE_FTRUNCATE |
| +extern int ftruncate(int fd, off_t length); |
| +#endif |
| + |
| +/* Return the NIS domain name of the machine. |
| + WARNING! The NIS domain name is unrelated to the fully qualified host name |
| + of the machine. It is also unrelated to email addresses. |
| + WARNING! The NIS domain name is usually the empty string or "(none)" when |
| + not using NIS. |
| + |
| + Put up to LEN bytes of the NIS domain name into NAME. |
| + Null terminate it if the name is shorter than LEN. |
| + If the NIS domain name is longer than LEN, set errno = EINVAL and return -1. |
| + Return 0 if successful, otherwise set errno and return -1. */ |
| +#if !HAVE_GETDOMAINNAME |
| +extern int getdomainname(char *name, size_t len); |
| +#endif |
| + |
| +/* Return the maximum number of file descriptors in the current process. |
| + In POSIX, this is same as sysconf (_SC_OPEN_MAX). */ |
| +#if !HAVE_GETDTABLESIZE |
| +extern int getdtablesize(void); |
| +#endif |
| + |
| +/* Return the supplemental groups that the current process belongs to. |
| + It is unspecified whether the effective group id is in the list. |
| + If N is 0, return the group count; otherwise, N describes how many |
| + entries are available in GROUPS. Return -1 and set errno if N is |
| + not 0 and not large enough. Fails with ENOSYS on some systems. */ |
| +#if !HAVE_GETGROUPS |
| +extern int getgroups(int n, int *groups); |
| +#endif |
| + |
| +/* Return the standard host name of the machine. |
| + WARNING! The host name may or may not be fully qualified. |
| + |
| + Put up to LEN bytes of the host name into NAME. |
| + Null terminate it if the name is shorter than LEN. |
| + If the host name is longer than LEN, set errno = EINVAL and return -1. |
| + Return 0 if successful, otherwise set errno and return -1. */ |
| +#if !HAVE_GETHOSTNAME && !(defined _WIN32 && ! defined __CYGWIN__) |
| +extern int gethostname(char *name, size_t len); |
| +#endif |
| + |
| +/* Returns the user's login name, or NULL if it cannot be found. Upon error, |
| + returns NULL with errno set. |
| + |
| + See <http://www.opengroup.org/susv3xsh/getlogin.html>. |
| + |
| + Most programs don't need to use this function, because the information is |
| + available through environment variables: |
| + ${LOGNAME-$USER} on Unix platforms, |
| + $USERNAME on native Windows platforms. |
| + */ |
| +# if !HAVE_GETLOGIN |
| +extern char * getlogin(void); |
| +#endif |
| + |
| +/* Copies the user's login name to NAME. |
| + The array pointed to by NAME has room for SIZE bytes. |
| + |
| + Returns 0 if successful. Upon error, an error number is returned, or -1 in |
| + the case that the login name cannot be found but no specific error is |
| + provided (this case is hopefully rare but is left open by the POSIX spec). |
| + |
| + See <http://www.opengroup.org/susv3xsh/getlogin.html>. |
| + |
| + Most programs don't need to use this function, because the information is |
| + available through environment variables: |
| + ${LOGNAME-$USER} on Unix platforms, |
| + $USERNAME on native Windows platforms. |
| + */ |
| +#if !HAVE_GETLOGIN_R |
| +extern int getlogin_r(char *name, size_t size); |
| +#endif |
| + |
| + |
| +/* Function getpass() from module 'getpass': |
| + Read a password from /dev/tty or stdin. |
| + Function getpass() from module 'getpass-gnu': |
| + Read a password of arbitrary length from /dev/tty or stdin. */ |
| +#if !HAVE_GETPASS |
| +extern char * getpass(const char *prompt); |
| +#endif |
| + |
| +/* Return the next valid login shell on the system, or NULL when the end of |
| + the list has been reached. */ |
| +#if !HAVE_GETUSERSHELL |
| +extern char * getusershell(void); |
| +#endif |
| + |
| +/* Rewind to pointer that is advanced at each getusershell() call. */ |
| +#if !HAVE_SETUSERSHELL |
| +extern void setusershell(void); |
| +#endif |
| + |
| +/* Free the pointer that is advanced at each getusershell() call and |
| + associated resources. */ |
| +#if !HAVE_ENDUSERSHELL |
| +extern void endusershell(void); |
| +#endif |
| + |
| +/* Determine whether group id is in calling user's group list. */ |
| +#if !HAVE_GROUP_MEMBER |
| +extern int group_member(int gid); |
| +#endif |
| + |
| +/* Change the owner of FILE to UID (if UID is not -1) and the group of FILE |
| + to GID (if GID is not -1). Do not follow symbolic links. |
| + Return 0 if successful, otherwise -1 and errno set. |
| + See the POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/lchown.html>. */ |
| +#if !HAVE_LCHOWN |
| +extern int lchown(char const *file, int owner, int group); |
| +#endif |
| + |
| +/* Create a new hard link for an existing file. |
| + Return 0 if successful, otherwise -1 and errno set. |
| + See POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html>. */ |
| +#if !HAVE_LINK |
| +extern int link(const char *path1, const char *path2); |
| +#endif |
| + |
| +/* Create a new hard link for an existing file, relative to two |
| + directories. FLAG controls whether symlinks are followed. |
| + Return 0 if successful, otherwise -1 and errno set. */ |
| +#if !HAVE_LINKAT |
| +extern int linkat(int fd1, const char *path1, int fd2, const char *path2, |
| + int flag); |
| +#endif |
| + |
| +/* Create a pipe, defaulting to O_BINARY mode. |
| + Store the read-end as fd[0] and the write-end as fd[1]. |
| + Return 0 upon success, or -1 with errno set upon failure. */ |
| +#if !HAVE_PIPE |
| +extern int pipe(int fd[2]); |
| +#endif |
| + |
| +/* Create a pipe, applying the given flags when opening the read-end of the |
| + pipe and the write-end of the pipe. |
| + The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>) |
| + and O_TEXT, O_BINARY (defined in "binary-io.h"). |
| + Store the read-end as fd[0] and the write-end as fd[1]. |
| + Return 0 upon success, or -1 with errno set upon failure. |
| + See also the Linux man page at |
| + <https://www.kernel.org/doc/man-pages/online/pages/man2/pipe2.2.html>. */ |
| +#if !HAVE_PIPE2 |
| +extern int pipe2(int fd[2], int flags); |
| +#endif |
| + |
| +/* Read at most BUFSIZE bytes from FD into BUF, starting at OFFSET. |
| + Return the number of bytes placed into BUF if successful, otherwise |
| + set errno and return -1. 0 indicates EOF. |
| + See the POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html>. */ |
| +#if !HAVE_PREAD |
| +extern ssize_t pread(int fd, void *buf, size_t bufsize, off_t offset); |
| +#endif |
| + |
| +/* Write at most BUFSIZE bytes from BUF into FD, starting at OFFSET. |
| + Return the number of bytes written if successful, otherwise |
| + set errno and return -1. 0 indicates nothing written. See the |
| + POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html>. */ |
| +#if !HAVE_PWRITE |
| +extern ssize_t pwrite(int fd, const void *buf, size_t bufsize, off_t offset); |
| +#endif |
| + |
| +/* Read the contents of the symbolic link FILE and place the first BUFSIZE |
| + bytes of it into BUF. Return the number of bytes placed into BUF if |
| + successful, otherwise -1 and errno set. |
| + See the POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html>. */ |
| +#if !HAVE_READLINK |
| +extern ssize_t readlink(const char *file, char *buf, size_t bufsize); |
| +#endif |
| + |
| +#if !HAVE_READLINKAT |
| +extern ssize_t readlinkat(int fd, char const *file, char *buf, size_t len); |
| +#endif |
| + |
| +/* Set the host name of the machine. |
| + The host name may or may not be fully qualified. |
| + |
| + Put LEN bytes of NAME into the host name. |
| + Return 0 if successful, otherwise, set errno and return -1. |
| + |
| + Platforms with no ability to set the hostname return -1 and set |
| + errno = ENOSYS. */ |
| +#if !HAVE_SETHOSTNAME |
| +extern int sethostname(const char *name, size_t len); |
| +#endif |
| + |
| +/* Pause the execution of the current thread for N seconds. |
| + Returns the number of seconds left to sleep. |
| + See the POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/sleep.html>. */ |
| +#if !HAVE_SLEEP |
| +extern unsigned int sleep(unsigned int n); |
| +#endif |
| + |
| +#if !HAVE_SYMLINK |
| +extern int symlink(char const *contents, char const *file); |
| +#endif |
| + |
| +#if !HAVE_SYMLINKAT |
| +extern int symlinkat(char const *contents, int fd, char const *file); |
| +#endif |
| + |
| +/* Change the size of the file designated by FILENAME to become equal to LENGTH. |
| + Return 0 if successful, otherwise -1 and errno set. |
| + See the POSIX:2008 specification |
| + <http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html>. */ |
| +#if !HAVE_TRUNCATE |
| +extern int truncate(const char *filename, off_t length); |
| +#endif |
| + |
| +/* Store at most BUFLEN characters of the pathname of the terminal FD is |
| + open on in BUF. Return 0 on success, otherwise an error number. */ |
| +#if !HAVE_TTYNAME_R |
| +extern int ttyname_r(int fd, char *buf, size_t buflen); |
| +#endif |
| + |
| +#if !HAVE_UNLINKAT |
| +extern int unlinkat(int fd, char const *file, int flag); |
| +#endif |
| + |
| +/* Pause the execution of the current thread for N microseconds. |
| + Returns 0 on completion, or -1 on range error. |
| + See the POSIX:2001 specification |
| + <http://www.opengroup.org/susv3xsh/usleep.html>. */ |
| +#if !HAVE_USLEEP |
| +extern int usleep(useconds_t n); |
| +#endif |
| + |
| +#endif /* _@GUARD_PREFIX@_UNISTD_H */ |
| + |
| diff --git a/install-sh b/install-sh |
| index a247329..8175c64 100755 |
| --- a/install-sh |
| +++ b/install-sh |
| @@ -1,201 +1,518 @@ |
| -: |
| -# NAME: |
| -# install.sh - portable version of install(1) |
| -# |
| -# SYNOPSIS: |
| -# install [-CNcs] [-f flags] [-i errs] [-o owner] [-g group] [-m mode] file1 file2 ... |
| -# install -d [-i errs] [-o owner] [-g group] [-m mode] directory ... |
| -# |
| -# DESCRIPTION: |
| -# Compatible with BSD install(1). Except that '-c' is always |
| -# true and we always move an already installed target aside as |
| -# this is important on many systems. Recent BSD install(1) |
| -# versions have a '-b' option for this. |
| -# |
| -# |
| -# OPTIONS: |
| -# -b move previous target file aside (always true). |
| +#!/bin/sh |
| +# install - install a program, script, or datafile |
| + |
| +scriptversion=2018-03-11.20; # UTC |
| + |
| +# This originates from X11R5 (mit/util/scripts/install.sh), which was |
| +# later released in X11R6 (xc/config/util/install.sh) with the |
| +# following copyright and license. |
| # |
| -# -B "suffix" |
| -# use "suffix" instead of .old for saving existing target. |
| -# |
| -# -c copy rather than move the file into place (always true). |
| +# Copyright (C) 1994 X Consortium |
| # |
| -# -C compare. Only install if target is missing or |
| -# different. |
| +# Permission is hereby granted, free of charge, to any person obtaining a copy |
| +# of this software and associated documentation files (the "Software"), to |
| +# deal in the Software without restriction, including without limitation the |
| +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
| +# sell copies of the Software, and to permit persons to whom the Software is |
| +# furnished to do so, subject to the following conditions: |
| # |
| -# -N newer. Only install if target is missing or older. |
| -# |
| -# -s strip target |
| +# The above copyright notice and this permission notice shall be included in |
| +# all copies or substantial portions of the Software. |
| # |
| -# -o "owner" |
| -# make target owned by "owner" |
| +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
| +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- |
| +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| # |
| -# -g "group" |
| -# make target group owned by "group" |
| +# Except as contained in this notice, the name of the X Consortium shall not |
| +# be used in advertising or otherwise to promote the sale, use or other deal- |
| +# ings in this Software without prior written authorization from the X Consor- |
| +# tium. |
| # |
| -# -m "mode" |
| -# set permissions to "mode" |
| # |
| -# -f "flags" |
| -# Pass "flags" onto chflags(1) |
| -# |
| -# -i "errs" |
| -# Ignore errors from steps indicated by "errs" (``s,o,g,m''). |
| +# FSF changes to this file are in the public domain. |
| # |
| -# BUGS: |
| -# The '-i' option is to save your sanity when 'bsd.prog.mk' |
| -# insists on haveing a '-o' "owner" option which is doomed to |
| -# fail on many systems. We ignore '-b', '-B' and '-c' options. |
| -# |
| -# AUTHOR: |
| -# Simon J. Gerraty <sjg@quick.com.au> |
| +# Calling this script install-sh is preferred over install.sh, to prevent |
| +# 'make' implicit rules from creating a file called install from it |
| +# when there is no Makefile. |
| # |
| +# This script is compatible with the BSD install script, but was written |
| +# from scratch. |
| |
| -# RCSid: |
| -# $Id: install-sh,v 1.18 2001/03/16 17:33:02 sjg Exp $ |
| -# |
| -# @(#) Copyright (c) 1993 Simon J. Gerraty |
| -# |
| -# This file is provided in the hope that it will |
| -# be of use. There is absolutely NO WARRANTY. |
| -# Permission to copy, redistribute or otherwise |
| -# use this file is hereby granted provided that |
| -# the above copyright notice and this notice are |
| -# left intact. |
| -# |
| -# Please send copies of changes and bug-fixes to: |
| -# sjg@quick.com.au |
| -# |
| +tab=' ' |
| +nl=' |
| +' |
| +IFS=" $tab$nl" |
| |
| -set -- `getopt B:bpxCNcsdo:g:m:i:f: $*` |
| +# Set DOITPROG to "echo" to test this script. |
| |
| -Mydir=`dirname $0` |
| -[ -s $Mydir/.installrc ] && . $Mydir/.installrc |
| +doit=${DOITPROG-} |
| +doit_exec=${doit:-exec} |
| |
| -owner=: |
| -group=: |
| -mode=: |
| -strip=: |
| -mkdirs= |
| -compare=: |
| -newer=: |
| -chflags=: |
| -LS1= |
| -CP_P= |
| +# Put in absolute file names if you don't have them in your path; |
| +# or use environment vars. |
| |
| -while [ $# -gt 1 ] |
| -do |
| - case $1 in |
| - --) shift; break;; |
| - -p) CP_P=-p;; |
| - -x) set -x;; |
| - -B) OLD_EXT=$2; shift;; |
| - -C) compare=Different;; |
| - -N) newer=Newer; |
| - # check if /bin/ls supports -1 |
| - /bin/ls -1 $0 >/dev/null 2>&1 && LS1=1 |
| - ;; |
| - -o) owner="${CHOWN:-chown} $2 "; shift;; |
| - -g) group="${CHGRP:-chgrp} $2 "; shift;; |
| - -m) mode="${CHMOD:-chmod} $2 "; shift;; |
| - -s) strip=${STRIP:-strip};; |
| - -d) mkdirs="mkdir -p";; |
| - -i) ignore_err="$ignore_err$2"; shift;; |
| - -f) chflags="${CHFLAGS:-chflags} $2 "; shift;; |
| - esac |
| - shift |
| +chgrpprog=${CHGRPPROG-chgrp} |
| +chmodprog=${CHMODPROG-chmod} |
| +chownprog=${CHOWNPROG-chown} |
| +cmpprog=${CMPPROG-cmp} |
| +cpprog=${CPPROG-cp} |
| +mkdirprog=${MKDIRPROG-mkdir} |
| +mvprog=${MVPROG-mv} |
| +rmprog=${RMPROG-rm} |
| +stripprog=${STRIPPROG-strip} |
| + |
| +posix_mkdir= |
| + |
| +# Desired mode of installed file. |
| +mode=0755 |
| + |
| +chgrpcmd= |
| +chmodcmd=$chmodprog |
| +chowncmd= |
| +mvcmd=$mvprog |
| +rmcmd="$rmprog -f" |
| +stripcmd= |
| + |
| +src= |
| +dst= |
| +dir_arg= |
| +dst_arg= |
| + |
| +copy_on_change=false |
| +is_target_a_directory=possibly |
| + |
| +usage="\ |
| +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE |
| + or: $0 [OPTION]... SRCFILES... DIRECTORY |
| + or: $0 [OPTION]... -t DIRECTORY SRCFILES... |
| + or: $0 [OPTION]... -d DIRECTORIES... |
| + |
| +In the 1st form, copy SRCFILE to DSTFILE. |
| +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. |
| +In the 4th, create DIRECTORIES. |
| + |
| +Options: |
| + --help display this help and exit. |
| + --version display version info and exit. |
| + |
| + -c (ignored) |
| + -C install only if different (preserve the last data modification time) |
| + -d create directories instead of installing files. |
| + -g GROUP $chgrpprog installed files to GROUP. |
| + -m MODE $chmodprog installed files to MODE. |
| + -o USER $chownprog installed files to USER. |
| + -s $stripprog installed files. |
| + -t DIRECTORY install into DIRECTORY. |
| + -T report an error if DSTFILE is a directory. |
| + |
| +Environment variables override the default commands: |
| + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG |
| + RMPROG STRIPPROG |
| +" |
| + |
| +while test $# -ne 0; do |
| + case $1 in |
| + -c) ;; |
| + |
| + -C) copy_on_change=true;; |
| + |
| + -d) dir_arg=true;; |
| + |
| + -g) chgrpcmd="$chgrpprog $2" |
| + shift;; |
| + |
| + --help) echo "$usage"; exit $?;; |
| + |
| + -m) mode=$2 |
| + case $mode in |
| + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) |
| + echo "$0: invalid mode: $mode" >&2 |
| + exit 1;; |
| + esac |
| + shift;; |
| + |
| + -o) chowncmd="$chownprog $2" |
| + shift;; |
| + |
| + -s) stripcmd=$stripprog;; |
| + |
| + -t) |
| + is_target_a_directory=always |
| + dst_arg=$2 |
| + # Protect names problematic for 'test' and other utilities. |
| + case $dst_arg in |
| + -* | [=\(\)!]) dst_arg=./$dst_arg;; |
| + esac |
| + shift;; |
| + |
| + -T) is_target_a_directory=never;; |
| + |
| + --version) echo "$0 $scriptversion"; exit $?;; |
| + |
| + --) shift |
| + break;; |
| + |
| + -*) echo "$0: invalid option: $1" >&2 |
| + exit 1;; |
| + |
| + *) break;; |
| + esac |
| + shift |
| done |
| |
| -Newer() { |
| - n=`/bin/ls -t$LS1 $* 2>/dev/null | head -1` |
| - [ $1 = $n ] |
| -} |
| - |
| -Different() { |
| - cmp -s $* |
| - [ $? != 0 ] |
| -} |
| - |
| -Err() { |
| - case "$ignore_err" in |
| - *$1*) ;; |
| - *) exit 1;; |
| - esac |
| -} |
| - |
| -Setem() { |
| - # the order is important |
| - if [ ! -d $1 ]; then |
| - $strip $1 || Err s |
| - fi |
| - $group $1 || Err g |
| - $owner $1 || Err o |
| - $mode $1 || Err m |
| - $chflags $1 || Err f |
| - return 0 |
| -} |
| - |
| -# a bug in HP-UX's /bin/sh, means we need to re-set $* |
| -# after any calls to add_path() |
| -args="$*" |
| - |
| -# all this just for chown! |
| -add_path () { [ -d $1 ] && eval ${2:-PATH}="\$${2:-PATH}:$1"; } |
| -add_path /etc |
| -add_path /usr/etc |
| -add_path /sbin |
| -add_path /usr/sbin |
| - |
| -# restore saved $* |
| -set -- $args |
| - |
| -# make directories if needed |
| -# and ensure mode etc are as desired |
| -if [ "$mkdirs" ]; then |
| - for d in $* |
| - do |
| - [ ! -d $d ] && $mkdirs $d |
| - Setem $d |
| - done |
| - exit 0 # that's all we do |
| +# We allow the use of options -d and -T together, by making -d |
| +# take the precedence; this is for compatibility with GNU install. |
| + |
| +if test -n "$dir_arg"; then |
| + if test -n "$dst_arg"; then |
| + echo "$0: target directory not allowed when installing a directory." >&2 |
| + exit 1 |
| + fi |
| fi |
| |
| -# install files |
| -if [ $# -gt 2 ]; then |
| - dest_dir=yes |
| -elif [ $# -eq 1 ]; then |
| - echo "what should I do with $*?" >&2 |
| - exit 1 |
| +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then |
| + # When -d is used, all remaining arguments are directories to create. |
| + # When -t is used, the destination is already specified. |
| + # Otherwise, the last argument is the destination. Remove it from $@. |
| + for arg |
| + do |
| + if test -n "$dst_arg"; then |
| + # $@ is not empty: it contains at least $arg. |
| + set fnord "$@" "$dst_arg" |
| + shift # fnord |
| + fi |
| + shift # arg |
| + dst_arg=$arg |
| + # Protect names problematic for 'test' and other utilities. |
| + case $dst_arg in |
| + -* | [=\(\)!]) dst_arg=./$dst_arg;; |
| + esac |
| + done |
| fi |
| |
| -# get list of files |
| -while [ $# -gt 1 ] |
| -do |
| - files="$files $1" |
| - shift |
| -done |
| -# last one is dest |
| -dest=$1 |
| -shift |
| +if test $# -eq 0; then |
| + if test -z "$dir_arg"; then |
| + echo "$0: no input file specified." >&2 |
| + exit 1 |
| + fi |
| + # It's OK to call 'install-sh -d' without argument. |
| + # This can happen when creating conditional directories. |
| + exit 0 |
| +fi |
| + |
| +if test -z "$dir_arg"; then |
| + if test $# -gt 1 || test "$is_target_a_directory" = always; then |
| + if test ! -d "$dst_arg"; then |
| + echo "$0: $dst_arg: Is not a directory." >&2 |
| + exit 1 |
| + fi |
| + fi |
| +fi |
| + |
| +if test -z "$dir_arg"; then |
| + do_exit='(exit $ret); exit $ret' |
| + trap "ret=129; $do_exit" 1 |
| + trap "ret=130; $do_exit" 2 |
| + trap "ret=141; $do_exit" 13 |
| + trap "ret=143; $do_exit" 15 |
| |
| + # Set umask so as not to create temps with too-generous modes. |
| + # However, 'strip' requires both read and write access to temps. |
| + case $mode in |
| + # Optimize common cases. |
| + *644) cp_umask=133;; |
| + *755) cp_umask=22;; |
| |
| -if [ "$dest_dir" = yes -a ! -d $dest ]; then |
| - echo "no directory $dest" >&2 |
| - exit 1 |
| + *[0-7]) |
| + if test -z "$stripcmd"; then |
| + u_plus_rw= |
| + else |
| + u_plus_rw='% 200' |
| + fi |
| + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; |
| + *) |
| + if test -z "$stripcmd"; then |
| + u_plus_rw= |
| + else |
| + u_plus_rw=,u+rw |
| + fi |
| + cp_umask=$mode$u_plus_rw;; |
| + esac |
| fi |
| |
| -for f in $files |
| +for src |
| do |
| - b=`basename $f` |
| - if [ -d $dest ]; then |
| - t=$dest/$b |
| - else |
| - t=$dest |
| - fi |
| - $newer $f $t || continue |
| - $compare $f $t || continue |
| - [ -f $t ] && { mv -f $t $t.old || exit 1; } |
| - { cp $CP_P $f $t && Setem $t; } || exit 1 |
| + # Protect names problematic for 'test' and other utilities. |
| + case $src in |
| + -* | [=\(\)!]) src=./$src;; |
| + esac |
| + |
| + if test -n "$dir_arg"; then |
| + dst=$src |
| + dstdir=$dst |
| + test -d "$dstdir" |
| + dstdir_status=$? |
| + else |
| + |
| + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command |
| + # might cause directories to be created, which would be especially bad |
| + # if $src (and thus $dsttmp) contains '*'. |
| + if test ! -f "$src" && test ! -d "$src"; then |
| + echo "$0: $src does not exist." >&2 |
| + exit 1 |
| + fi |
| + |
| + if test -z "$dst_arg"; then |
| + echo "$0: no destination specified." >&2 |
| + exit 1 |
| + fi |
| + dst=$dst_arg |
| + |
| + # If destination is a directory, append the input filename. |
| + if test -d "$dst"; then |
| + if test "$is_target_a_directory" = never; then |
| + echo "$0: $dst_arg: Is a directory" >&2 |
| + exit 1 |
| + fi |
| + dstdir=$dst |
| + dstbase=`basename "$src"` |
| + case $dst in |
| + */) dst=$dst$dstbase;; |
| + *) dst=$dst/$dstbase;; |
| + esac |
| + dstdir_status=0 |
| + else |
| + dstdir=`dirname "$dst"` |
| + test -d "$dstdir" |
| + dstdir_status=$? |
| + fi |
| + fi |
| + |
| + case $dstdir in |
| + */) dstdirslash=$dstdir;; |
| + *) dstdirslash=$dstdir/;; |
| + esac |
| + |
| + obsolete_mkdir_used=false |
| + |
| + if test $dstdir_status != 0; then |
| + case $posix_mkdir in |
| + '') |
| + # Create intermediate dirs using mode 755 as modified by the umask. |
| + # This is like FreeBSD 'install' as of 1997-10-28. |
| + umask=`umask` |
| + case $stripcmd.$umask in |
| + # Optimize common cases. |
| + *[2367][2367]) mkdir_umask=$umask;; |
| + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; |
| + |
| + *[0-7]) |
| + mkdir_umask=`expr $umask + 22 \ |
| + - $umask % 100 % 40 + $umask % 20 \ |
| + - $umask % 10 % 4 + $umask % 2 |
| + `;; |
| + *) mkdir_umask=$umask,go-w;; |
| + esac |
| + |
| + # With -d, create the new directory with the user-specified mode. |
| + # Otherwise, rely on $mkdir_umask. |
| + if test -n "$dir_arg"; then |
| + mkdir_mode=-m$mode |
| + else |
| + mkdir_mode= |
| + fi |
| + |
| + posix_mkdir=false |
| + case $umask in |
| + *[123567][0-7][0-7]) |
| + # POSIX mkdir -p sets u+wx bits regardless of umask, which |
| + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. |
| + ;; |
| + *) |
| + # Note that $RANDOM variable is not portable (e.g. dash); Use it |
| + # here however when possible just to lower collision chance. |
| + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ |
| + |
| + trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 |
| + |
| + # Because "mkdir -p" follows existing symlinks and we likely work |
| + # directly in world-writeable /tmp, make sure that the '$tmpdir' |
| + # directory is successfully created first before we actually test |
| + # 'mkdir -p' feature. |
| + if (umask $mkdir_umask && |
| + $mkdirprog $mkdir_mode "$tmpdir" && |
| + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 |
| + then |
| + if test -z "$dir_arg" || { |
| + # Check for POSIX incompatibilities with -m. |
| + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or |
| + # other-writable bit of parent directory when it shouldn't. |
| + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. |
| + test_tmpdir="$tmpdir/a" |
| + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` |
| + case $ls_ld_tmpdir in |
| + d????-?r-*) different_mode=700;; |
| + d????-?--*) different_mode=755;; |
| + *) false;; |
| + esac && |
| + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { |
| + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` |
| + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" |
| + } |
| + } |
| + then posix_mkdir=: |
| + fi |
| + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" |
| + else |
| + # Remove any dirs left behind by ancient mkdir implementations. |
| + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null |
| + fi |
| + trap '' 0;; |
| + esac;; |
| + esac |
| + |
| + if |
| + $posix_mkdir && ( |
| + umask $mkdir_umask && |
| + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" |
| + ) |
| + then : |
| + else |
| + |
| + # The umask is ridiculous, or mkdir does not conform to POSIX, |
| + # or it failed possibly due to a race condition. Create the |
| + # directory the slow way, step by step, checking for races as we go. |
| + |
| + case $dstdir in |
| + /*) prefix='/';; |
| + [-=\(\)!]*) prefix='./';; |
| + *) prefix='';; |
| + esac |
| + |
| + oIFS=$IFS |
| + IFS=/ |
| + set -f |
| + set fnord $dstdir |
| + shift |
| + set +f |
| + IFS=$oIFS |
| + |
| + prefixes= |
| + |
| + for d |
| + do |
| + test X"$d" = X && continue |
| + |
| + prefix=$prefix$d |
| + if test -d "$prefix"; then |
| + prefixes= |
| + else |
| + if $posix_mkdir; then |
| + (umask=$mkdir_umask && |
| + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break |
| + # Don't fail if two instances are running concurrently. |
| + test -d "$prefix" || exit 1 |
| + else |
| + case $prefix in |
| + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; |
| + *) qprefix=$prefix;; |
| + esac |
| + prefixes="$prefixes '$qprefix'" |
| + fi |
| + fi |
| + prefix=$prefix/ |
| + done |
| + |
| + if test -n "$prefixes"; then |
| + # Don't fail if two instances are running concurrently. |
| + (umask $mkdir_umask && |
| + eval "\$doit_exec \$mkdirprog $prefixes") || |
| + test -d "$dstdir" || exit 1 |
| + obsolete_mkdir_used=true |
| + fi |
| + fi |
| + fi |
| + |
| + if test -n "$dir_arg"; then |
| + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && |
| + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && |
| + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || |
| + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 |
| + else |
| + |
| + # Make a couple of temp file names in the proper directory. |
| + dsttmp=${dstdirslash}_inst.$$_ |
| + rmtmp=${dstdirslash}_rm.$$_ |
| + |
| + # Trap to clean up those temp files at exit. |
| + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 |
| + |
| + # Copy the file name to the temp name. |
| + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && |
| + |
| + # and set any options; do chmod last to preserve setuid bits. |
| + # |
| + # If any of these fail, we abort the whole thing. If we want to |
| + # ignore errors from any of these, just make sure not to ignore |
| + # errors from the above "$doit $cpprog $src $dsttmp" command. |
| + # |
| + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && |
| + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && |
| + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && |
| + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && |
| + |
| + # If -C, don't bother to copy if it wouldn't change the file. |
| + if $copy_on_change && |
| + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && |
| + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && |
| + set -f && |
| + set X $old && old=:$2:$4:$5:$6 && |
| + set X $new && new=:$2:$4:$5:$6 && |
| + set +f && |
| + test "$old" = "$new" && |
| + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 |
| + then |
| + rm -f "$dsttmp" |
| + else |
| + # Rename the file to the real destination. |
| + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || |
| + |
| + # The rename failed, perhaps because mv can't rename something else |
| + # to itself, or perhaps because mv is so ancient that it does not |
| + # support -f. |
| + { |
| + # Now remove or move aside any old file at destination location. |
| + # We try this two ways since rm can't unlink itself on some |
| + # systems and the destination file might be busy for other |
| + # reasons. In this case, the final cleanup might fail but the new |
| + # file should still install successfully. |
| + { |
| + test ! -f "$dst" || |
| + $doit $rmcmd -f "$dst" 2>/dev/null || |
| + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && |
| + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } |
| + } || |
| + { echo "$0: cannot unlink or rename $dst" >&2 |
| + (exit 1); exit 1 |
| + } |
| + } && |
| + |
| + # Now rename the file to the real destination. |
| + $doit $mvcmd "$dsttmp" "$dst" |
| + } |
| + fi || exit 1 |
| + |
| + trap '' 0 |
| + fi |
| done |
| -exit 0 |
| + |
| +# Local variables: |
| +# eval: (add-hook 'before-save-hook 'time-stamp) |
| +# time-stamp-start: "scriptversion=" |
| +# time-stamp-format: "%:y-%02m-%02d.%02H" |
| +# time-stamp-time-zone: "UTC0" |
| +# time-stamp-end: "; # UTC" |
| +# End: |
| diff --git a/job.c b/job.c |
| index ddf9d40..670798d 100644 |
| --- a/job.c |
| +++ b/job.c |
| @@ -140,2 +140,5 @@ __RCSID("$NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $"); |
| #include <sys/stat.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| #include <sys/file.h> |
| @@ -146,13 +149,23 @@ __RCSID("$NetBSD: job.c,v 1.195 2018/05/13 22:13:28 sjg Exp $"); |
| #include <errno.h> |
| -#if !defined(USE_SELECT) && defined(HAVE_POLL_H) |
| -#include <poll.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +# include "headers-mingw/poll.h" |
| #else |
| -#ifndef USE_SELECT /* no poll.h */ |
| -# define USE_SELECT |
| +# if !defined(USE_SELECT) && defined(HAVE_POLL_H) |
| +# include <poll.h> |
| +# else |
| +# ifndef USE_SELECT /* no poll.h */ |
| +# define USE_SELECT |
| +# endif |
| +# endif |
| +# if defined(HAVE_SYS_SELECT_H) |
| +# include <sys/select.h> |
| +# endif |
| #endif |
| -#if defined(HAVE_SYS_SELECT_H) |
| -# include <sys/select.h> |
| +#include <signal.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/signal.h" |
| #endif |
| +#ifndef SIGQUIT |
| +#define SIGQUIT SIGTERM |
| #endif |
| -#include <signal.h> |
| #include <stdio.h> |
| @@ -315,4 +328,8 @@ const char *shellPath = NULL, /* full pathname of |
| char *shellErrFlag = NULL; |
| -static const char *shellArgv = NULL; /* Custom shell args */ |
| |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +const char *shellExecCmd = NULL; |
| +#endif |
| + |
| +static const char *shellArgv = NULL; /* Custom shell args */ |
| |
| @@ -439,2 +456,3 @@ JobCreatePipe(Job *job, int minfd) |
| /* Set close-on-exec flag for both */ |
| +#if defined(F_SETFD) && defined(FD_CLOEXEC) && defined(F_GETFL) && defined(F_SETFL) |
| if (fcntl(job->jobPipe[0], F_SETFD, FD_CLOEXEC) == -1) |
| @@ -456,2 +474,3 @@ JobCreatePipe(Job *job, int minfd) |
| Punt("Cannot set flags: %s", strerror(errno)); |
| +#endif |
| } |
| @@ -1115,3 +1134,3 @@ JobFinish (Job *job, WAIT_T status) |
| } |
| - job->node->made = MADE; |
| + job->node->made = __MADE; |
| if (!(job->flags & JOB_SPECIAL)) |
| @@ -1386,2 +1405,3 @@ JobExec(Job *job, char **argv) |
| } |
| +#if defined(F_SETFD) |
| if (fcntl(0, F_SETFD, 0) == -1) { |
| @@ -1390,2 +1410,3 @@ JobExec(Job *job, char **argv) |
| } |
| +#endif |
| if (lseek(0, (off_t)0, SEEK_SET) == -1) { |
| @@ -1394,3 +1415,3 @@ JobExec(Job *job, char **argv) |
| } |
| - |
| +#if defined(F_SETFD) |
| if (job->node->type & (OP_MAKE | OP_SUBMAKE)) { |
| @@ -1408,2 +1429,3 @@ JobExec(Job *job, char **argv) |
| } |
| +#endif |
| |
| @@ -1423,2 +1445,3 @@ JobExec(Job *job, char **argv) |
| */ |
| +#if defined(F_SETFD) |
| if (fcntl(1, F_SETFD, 0) == -1) { |
| @@ -1427,2 +1450,3 @@ JobExec(Job *job, char **argv) |
| } |
| +#endif |
| if (dup2(1, 2) == -1) { |
| @@ -1439,9 +1463,7 @@ JobExec(Job *job, char **argv) |
| (void)setpgid(0, getpid()); |
| -#else |
| -#if defined(HAVE_SETSID) |
| +#elif defined(HAVE_SETSID) |
| /* XXX: dsl - I'm sure this should be setpgrp()... */ |
| (void)setsid(); |
| -#else |
| +#elif defined(HAVE_SETPGRP) |
| (void)setpgrp(0, getpid()); |
| -#endif |
| #endif |
| @@ -1642,3 +1664,5 @@ JobStart(GNode *gn, int flags) |
| } |
| +#if defined(F_SETFD) |
| (void)fcntl(FILENO(job->cmdFILE), F_SETFD, FD_CLOEXEC); |
| +#endif |
| /* |
| @@ -1734,3 +1758,3 @@ JobStart(GNode *gn, int flags) |
| } |
| - job->node->made = MADE; |
| + job->node->made = __MADE; |
| Make_Update(job->node); |
| @@ -1983,3 +2007,3 @@ JobRun(GNode *targ) |
| Compat_Make(targ, targ); |
| - if (targ->made == ERROR) { |
| + if (targ->made == __ERROR) { |
| PrintOnError(targ, "\n\nStop."); |
| @@ -2063,2 +2087,3 @@ JobReapChild(pid_t pid, WAIT_T status, Boolean isJobs) |
| switch (WSTOPSIG(status)) { |
| +#if defined(SIGTSTP) |
| case SIGTSTP: |
| @@ -2066,2 +2091,3 @@ JobReapChild(pid_t pid, WAIT_T status, Boolean isJobs) |
| break; |
| +#endif |
| case SIGSTOP: |
| @@ -2191,2 +2217,7 @@ Shell_Init(void) |
| } |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| + if (shellExecCmd == NULL) { |
| + shellExecCmd = getShellLaunchPrefix(); |
| + } |
| +#endif |
| if (commandShell->exit == NULL) { |
| @@ -2301,2 +2332,3 @@ Job_Init(void) |
| sigemptyset(&caught_signals); |
| +#if defined(SIGCHLD) |
| /* |
| @@ -2306,2 +2338,3 @@ Job_Init(void) |
| sigaddset(&caught_signals, SIGCHLD); |
| +#endif |
| |
| @@ -2318,3 +2351,5 @@ Job_Init(void) |
| ADDSIG(SIGINT, JobPassSig_int) |
| +#if defined(SIGHUP) |
| ADDSIG(SIGHUP, JobPassSig_term) |
| +#endif |
| ADDSIG(SIGTERM, JobPassSig_term) |
| @@ -2328,7 +2363,17 @@ Job_Init(void) |
| */ |
| +#if defined(SIGTSTP) |
| ADDSIG(SIGTSTP, JobPassSig_suspend) |
| +#endif |
| +#if defined(SIGTTOU) |
| ADDSIG(SIGTTOU, JobPassSig_suspend) |
| +#endif |
| +#if defined(SIGTTIN) |
| ADDSIG(SIGTTIN, JobPassSig_suspend) |
| +#endif |
| +#if defined(SIGWINCH) |
| ADDSIG(SIGWINCH, JobCondPassSig) |
| +#endif |
| +#if defined(SIGCONT) |
| ADDSIG(SIGCONT, JobContinueSig) |
| +#endif |
| #undef ADDSIG |
| @@ -2347,12 +2392,26 @@ static void JobSigReset(void) |
| DELSIG(SIGINT) |
| +#if defined(SIGHUP) |
| DELSIG(SIGHUP) |
| +#endif |
| DELSIG(SIGQUIT) |
| DELSIG(SIGTERM) |
| +#if defined(SIGTSTP) |
| DELSIG(SIGTSTP) |
| +#endif |
| +#if defined(SIGTTOU) |
| DELSIG(SIGTTOU) |
| +#endif |
| +#if defined(SIGTTIN) |
| DELSIG(SIGTTIN) |
| +#endif |
| +#if defined(SIGWINCH) |
| DELSIG(SIGWINCH) |
| +#endif |
| +#if defined(SIGCONT) |
| DELSIG(SIGCONT) |
| +#endif |
| #undef DELSIG |
| +#if defined(SIGCHLD) |
| (void)bmake_signal(SIGCHLD, SIG_DFL); |
| +#endif |
| } |
| @@ -2791,2 +2850,3 @@ JobRestartJobs(void) |
| job->job_suspended = 0; |
| +#if defined(SIGCONT) |
| if (KILLPG(job->pid, SIGCONT) != 0 && DEBUG(JOB)) { |
| @@ -2794,2 +2854,3 @@ JobRestartJobs(void) |
| } |
| +#endif |
| } |
| @@ -2888,4 +2949,6 @@ Job_ServerStart(int max_tokens, int jp_0, int jp_1) |
| tokenWaitJob.outPipe = jp_1; |
| +#if defined(F_SETFD) |
| (void)fcntl(jp_0, F_SETFD, FD_CLOEXEC); |
| (void)fcntl(jp_1, F_SETFD, FD_CLOEXEC); |
| +#endif |
| return; |
| @@ -3022,3 +3085,3 @@ Job_RunTarget(const char *target, const char *fname) { |
| JobRun(gn); |
| - if (gn->made == ERROR) { |
| + if (gn->made == __ERROR) { |
| PrintOnError(gn, "\n\nStop."); |
| diff --git a/job.h b/job.h |
| index 91e2c87..ca8e093 100644 |
| --- a/job.h |
| +++ b/job.h |
| @@ -246,2 +246,5 @@ extern const char *shellName; |
| extern char *shellErrFlag; |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +extern const char *shellExecCmd; |
| +#endif |
| |
| diff --git a/main.c b/main.c |
| index 7dd4c50..76e319e 100644 |
| --- a/main.c |
| +++ b/main.c |
| @@ -118,4 +118,11 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); |
| #include <sys/param.h> |
| +#ifdef HAVE_SYS_RESOURCE_H |
| #include <sys/resource.h> |
| +#else |
| +#include "headers-mingw/resource.h" |
| +#endif |
| #include <sys/stat.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) |
| @@ -123,3 +130,8 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); |
| #endif |
| + |
| +#ifdef HAVE_SYS_UTSNAME_H |
| #include <sys/utsname.h> |
| +#else |
| +#include "headers-mingw/sys_utsname.h" |
| +#endif |
| #include "wait.h" |
| @@ -128,2 +140,8 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); |
| #include <signal.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/signal.h" |
| +#endif |
| +#ifndef SIGQUIT |
| +#define SIGQUIT SIGTERM |
| +#endif |
| #include <stdarg.h> |
| @@ -131,2 +149,5 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); |
| #include <stdlib.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/stdlib.h" |
| +#endif |
| #include <time.h> |
| @@ -141,2 +162,6 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); |
| |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include <process.h> |
| +#endif |
| + |
| #ifdef USE_IOVEC |
| @@ -153,2 +178,4 @@ __RCSID("$NetBSD: main.c,v 1.273 2017/10/28 21:54:54 sjg Exp $"); |
| |
| +FILE *debug_file; /* Output written here - default stdout */ |
| + |
| Lst create; /* Targets to be made */ |
| @@ -196,2 +223,4 @@ static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ |
| char curdir[MAXPATHLEN + 1]; /* Startup directory */ |
| +char *pcurdir; |
| +char *pobjdir; |
| char *progname; /* the program name */ |
| @@ -764,3 +793,3 @@ Main_SetObjdir(const char *fmt, ...) |
| |
| - if (path[0] != '/') { |
| + if (path[0] != '/' && curdir[0] == '/') { //because directory path could start not from '/' (example: Windows OS family) |
| snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); |
| @@ -776,4 +805,13 @@ Main_SetObjdir(const char *fmt, ...) |
| strncpy(objdir, path, MAXPATHLEN); |
| - Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); |
| - setenv("PWD", objdir, 1); |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| + pobjdir = str_replace_char(objdir, '\\', '/'); |
| + if (pobjdir[1] == ':') { // create msys-style windows path |
| + pobjdir[1] = pobjdir[0]; |
| + pobjdir[0] = '/'; |
| + } |
| +#else |
| + pobjdir = objdir; |
| +#endif |
| + Var_Set(".OBJDIR", pobjdir, VAR_GLOBAL, 0); |
| + setenv("PWD", pobjdir, 1); |
| Dir_InitDot(); |
| @@ -990,2 +1028,4 @@ main(int argc, char **argv) |
| char mdpath[MAXPATHLEN]; |
| + const char *error; |
| + |
| #ifdef FORCE_MACHINE |
| @@ -1017,3 +1057,9 @@ main(int argc, char **argv) |
| srandom(rightnow.tv_sec + rightnow.tv_usec); |
| - |
| + |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| + if ((progname = strrchr(argv[0], '\\')) != NULL) |
| + progname++; |
| + else |
| + progname = argv[0]; |
| +#else |
| if ((progname = strrchr(argv[0], '/')) != NULL) |
| @@ -1022,3 +1068,4 @@ main(int argc, char **argv) |
| progname = argv[0]; |
| -#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) |
| +#endif |
| +#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) |
| /* |
| @@ -1165,2 +1212,11 @@ main(int argc, char **argv) |
| } |
| + |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +// p1 = str_replace_char(p1, '\\', '/'); |
| +// if (p1[1] == ':') { // create msys-style windows path |
| +// p1[1] = p1[0]; |
| +// p1[0] = '/'; |
| +// } |
| +p1 = Cmd_Exec(getUnixPathCmd(p1), &error); |
| +#endif |
| Var_Set("MAKE", p1, VAR_GLOBAL, 0); |
| @@ -1187,4 +1243,6 @@ main(int argc, char **argv) |
| Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); |
| +#ifdef HAVE_GETPPID |
| snprintf(tmp, sizeof(tmp), "%u", getppid()); |
| Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); |
| +#endif |
| } |
| @@ -1269,3 +1327,13 @@ main(int argc, char **argv) |
| #endif |
| - Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +// pcurdir = str_replace_char(curdir, '\\', '/'); |
| +// if (pcurdir[1] == ':') { // create msys-style windows path |
| +// pcurdir[1] = pcurdir[0]; |
| +// pcurdir[0] = '/'; |
| +// } |
| +pcurdir = Cmd_Exec(getUnixPathCmd(curdir), &error); |
| +#else |
| + pcurdir = curdir; |
| +#endif |
| + Var_Set(".CURDIR", pcurdir, VAR_GLOBAL, 0); |
| |
| @@ -1607,4 +1675,2 @@ found: |
| |
| - |
| - |
| /*- |
| @@ -1625,3 +1691,7 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| const char *args[4]; /* Args for invoking the shell */ |
| +#if !(defined _WIN32 && ! defined __CYGWIN__) |
| int fds[2]; /* Pipe streams */ |
| +#else |
| + FILE * fds[2]; |
| +#endif |
| int cpid; /* Child PID */ |
| @@ -1629,4 +1699,16 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| char *res; /* result */ |
| +#if !(defined _WIN32 && ! defined __CYGWIN__) |
| WAIT_T status; /* command exit status */ |
| Buffer buf; /* buffer to store the result */ |
| +#else |
| + const char *sysRootPath = getenv("SYSROOTWINDOWSPATH"); |
| + int status; |
| + char command[4096] = ""; /* generated cmd string for launch */ |
| + char escapedCmd[4096] = ""; |
| + char escapedCmdLaunchList[4096] = ""; /* temporary string */ |
| + static char stdout_data[16 * 1024 * 1024] = ""; //stdout |
| + static char stderr_data[16 * 1024 * 1024] = ""; |
| + int exit_code = 0; |
| +#endif |
| + |
| char *cp; |
| @@ -1636,2 +1718,3 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| |
| + |
| *errnum = NULL; |
| @@ -1643,4 +1726,10 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| */ |
| +#if !(defined _WIN32 && ! defined __CYGWIN__) |
| args[0] = shellName; |
| args[1] = "-c"; |
| +#else |
| + args[0] = str_concat(sysRootPath, "usr\\bin\\bash.exe", 0); |
| + args[1] = "-lc"; |
| +#endif |
| + |
| args[2] = cmd; |
| @@ -1648,2 +1737,3 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| |
| +#if !(defined _WIN32 && ! defined __CYGWIN__) |
| /* |
| @@ -1656,2 +1746,3 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| |
| + |
| /* |
| @@ -1661,2 +1752,3 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| case 0: |
| + |
| /* |
| @@ -1673,5 +1765,7 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| (void)close(fds[1]); |
| - |
| +#endif |
| Var_ExportVars(); |
| |
| +#if !(defined _WIN32 && ! defined __CYGWIN__) |
| + |
| (void)execv(shellPath, UNCONST(args)); |
| @@ -1685,7 +1779,41 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| default: |
| - /* |
| - * No need for the writing half |
| - */ |
| - (void)close(fds[1]); |
| + /* |
| + * No need for the writing half |
| + */ |
| + (void)close(fds[1]); |
| +#else |
| +// str_escape(escapedCmd, args[2], 4096); |
| +// strncpy(command, str_concat(shellExecCmd, |
| +// str_concat("\"", |
| +// str_concat(str_concat(args[0], |
| +// str_concat(args[1], |
| +// str_concat("'", |
| +// str_concat(escapedCmd, "'", 0), |
| +// 0), |
| +// STR_ADDSPACE), |
| +// STR_ADDSPACE), "\"", 0), |
| +// 0), |
| +// STR_ADDSPACE), 4096); |
| +// fds[0] = _popen(command, "rb"); |
| +// if (fds[0] == NULL) { |
| +// savederr = errno; |
| +// } |
| + str_escape_dblquote(escapedCmd, cmd, 4096); |
| + strncpy(command, |
| +// str_concat("\"", |
| +// str_concat( |
| + str_concat(args[0], |
| + str_concat(args[1], |
| + str_concat("\"", |
| + str_concat(escapedCmd, "\"", 0), |
| + 0), |
| + STR_ADDSPACE), |
| + STR_ADDSPACE), |
| +// , "\"", 0), |
| +// 0), |
| + 4096); |
| + status = system_np(command, 100 * 1000, stdout_data, sizeof(stdout_data), stderr_data, sizeof(stderr_data), &exit_code); |
| +#endif |
| |
| +#if !(defined _WIN32 && ! defined __CYGWIN__) |
| savederr = 0; |
| @@ -1715,2 +1843,3 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| } |
| + |
| cc = Buf_Size(&buf); |
| @@ -1720,7 +1849,16 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| *errnum = "Couldn't read shell's output for \"%s\""; |
| +#else |
| + cc = strlen(stdout_data); |
| + res = bmake_malloc(cc + 1); |
| + strncpy(res, stdout_data, cc); |
| +#endif |
| |
| +#if !(defined _WIN32 && ! defined __CYGWIN__) |
| if (WIFSIGNALED(status)) |
| *errnum = "\"%s\" exited on a signal"; |
| - else if (WEXITSTATUS(status) != 0) |
| + else if (WEXITSTATUS(status) != 0) { |
| + |
| *errnum = "\"%s\" returned non-zero status"; |
| + } |
| +#endif |
| |
| @@ -1745,4 +1883,6 @@ Cmd_Exec(const char *cmd, const char **errnum) |
| } |
| +#if !(defined _WIN32 && ! defined __CYGWIN__) |
| break; |
| } |
| +#endif |
| return res; |
| @@ -2118,3 +2258,4 @@ getTmpdir(void) |
| */ |
| - tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, |
| + tmpdir = Var_Subst(NULL, str_concat( |
| + str_concat("${TMPDIR:tA:U", _PATH_TMP, 0), "}/", 0), VAR_GLOBAL, |
| VARF_WANTRES); |
| diff --git a/make-bootstrap.sh.in b/make-bootstrap.sh.in |
| index a394272..f74bc72 100755 |
| --- a/make-bootstrap.sh.in |
| +++ b/make-bootstrap.sh.in |
| @@ -24,2 +24,13 @@ LDFLAGS="@LDFLAGS@" |
| LIBS="@LIBS@" |
| +MACHINE="@machine@" |
| + |
| +if [ "$(expr substr ${MACHINE} 1 5)" == "mingw" ]; then |
| + LIBS+=" -lws2_32 -lwsock32" |
| + CFLAGS+="" |
| +fi |
| + |
| +if [ "$(expr substr ${MACHINE} 1 7)" == "mingw32" ]; then |
| + LIBS+=" -liconv -lkernel32" |
| + CFLAGS+="" |
| +fi |
| |
| diff --git a/make.1 b/make.1 |
| index 2a2237f..968f006 100644 |
| --- a/make.1 |
| +++ b/make.1 |
| @@ -1927,3 +1927,3 @@ as if they all were preceded by a dash |
| .\" XXX |
| -.It Ic .MADE |
| +.It Ic .__MADE |
| Mark all sources of this target as being up-to-date. |
| @@ -2089,3 +2089,3 @@ Any command lines attached to this target are executed after everything |
| else is done. |
| -.It Ic .ERROR |
| +.It Ic .__ERROR |
| Any command lines attached to this target are executed when another target fails. |
| diff --git a/make.c b/make.c |
| index 8947582..796202c 100644 |
| --- a/make.c |
| +++ b/make.c |
| @@ -703,3 +703,3 @@ Make_Update(GNode *cgn) |
| */ |
| - if (cgn->made != UPTODATE) { |
| + if (cgn->made != __UPTODATE) { |
| mtime = Make_Recheck(cgn); |
| @@ -759,3 +759,3 @@ Make_Update(GNode *cgn) |
| if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) { |
| - if (cgn->made == MADE) |
| + if (cgn->made == __MADE) |
| pgn->flags |= CHILDMADE; |
| @@ -768,3 +768,3 @@ Make_Update(GNode *cgn) |
| */ |
| - if (centurion->unmade_cohorts != 0 || centurion->made < MADE) { |
| + if (centurion->unmade_cohorts != 0 || centurion->made < __MADE) { |
| if (DEBUG(MAKE)) |
| @@ -794,3 +794,3 @@ Make_Update(GNode *cgn) |
| } |
| - if (pgn->made != DEFERRED) { |
| + if (pgn->made != __DEFERRED) { |
| /* |
| @@ -817,3 +817,3 @@ Make_Update(GNode *cgn) |
| /* Ok, we can schedule the parent again */ |
| - pgn->made = REQUESTED; |
| + pgn->made = __REQUESTED; |
| (void)Lst_EnQueue(toBeMade, pgn); |
| @@ -908,3 +908,3 @@ MakeAddAllSrc(void *cgnp, void *pgnp) |
| if (pgn->type & OP_JOIN) { |
| - if (cgn->made == MADE) { |
| + if (cgn->made == __MADE) { |
| Var_Append(OODATE, child, pgn); |
| @@ -912,3 +912,3 @@ MakeAddAllSrc(void *cgnp, void *pgnp) |
| } else if ((pgn->mtime < cgn->mtime) || |
| - (cgn->mtime >= now && cgn->made == MADE)) |
| + (cgn->mtime >= now && cgn->made == __MADE)) |
| { |
| @@ -1005,3 +1005,3 @@ MakeCheckOrder(void *v_bn, void *ignore MAKE_ATTR_UNUSED) |
| |
| - if (bn->made >= MADE || !(bn->flags & REMAKE)) |
| + if (bn->made >= __MADE || !(bn->flags & REMAKE)) |
| return 0; |
| @@ -1021,3 +1021,3 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) |
| cn->name, cn->cohort_num, cn->made, cn->type); |
| - if (cn->made > DEFERRED) |
| + if (cn->made > __DEFERRED) |
| return 0; |
| @@ -1027,3 +1027,3 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) |
| /* Can't build this (or anything else in this child list) yet */ |
| - cn->made = DEFERRED; |
| + cn->made = __DEFERRED; |
| return 0; /* but keep looking */ |
| @@ -1035,3 +1035,3 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) |
| |
| - cn->made = REQUESTED; |
| + cn->made = __REQUESTED; |
| if (toBeMade_next == NULL) |
| @@ -1057,3 +1057,3 @@ MakeBuildParent(void *v_pn, void *toBeMade_next) |
| |
| - if (pn->made != DEFERRED) |
| + if (pn->made != __DEFERRED) |
| return 0; |
| @@ -1085,3 +1085,3 @@ MakeStartJobs(void) |
| |
| - if (gn->made != REQUESTED) { |
| + if (gn->made != __REQUESTED) { |
| if (DEBUG(MAKE)) |
| @@ -1097,3 +1097,3 @@ MakeStartJobs(void) |
| gn->name, gn->cohort_num); |
| - gn->made = DEFERRED; |
| + gn->made = __DEFERRED; |
| continue; |
| @@ -1107,3 +1107,3 @@ MakeStartJobs(void) |
| */ |
| - gn->made = DEFERRED; |
| + gn->made = __DEFERRED; |
| Lst_ForEach(gn->children, MakeBuildChild, Lst_First(toBeMade)); |
| @@ -1115,3 +1115,3 @@ MakeStartJobs(void) |
| |
| - gn->made = BEINGMADE; |
| + gn->made = __BEINGMADE; |
| if (Make_OODate(gn)) { |
| @@ -1130,3 +1130,3 @@ MakeStartJobs(void) |
| } |
| - gn->made = UPTODATE; |
| + gn->made = __UPTODATE; |
| if (gn->type & OP_JOIN) { |
| @@ -1177,3 +1177,3 @@ MakePrintStatusOrder(void *ognp, void *gnp) |
| |
| - if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED) |
| + if (!(ogn->flags & REMAKE) || ogn->made > __REQUESTED) |
| /* not waiting for this one */ |
| @@ -1206,11 +1206,11 @@ MakePrintStatus(void *gnp, void *v_errors) |
| switch (gn->made) { |
| - case UPTODATE: |
| + case __UPTODATE: |
| printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num); |
| break; |
| - case MADE: |
| + case __MADE: |
| break; |
| - case UNMADE: |
| - case DEFERRED: |
| - case REQUESTED: |
| - case BEINGMADE: |
| + case __UNMADE: |
| + case __DEFERRED: |
| + case __REQUESTED: |
| + case __BEINGMADE: |
| (*errors)++; |
| diff --git a/make.h b/make.h |
| index c14b2c6..ea864b4 100644 |
| --- a/make.h |
| +++ b/make.h |
| @@ -91,4 +91,10 @@ |
| #include <fcntl.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/fcntl.h" |
| +#endif |
| #include <stdio.h> |
| #include <stdlib.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/stdlib.h" |
| +#endif |
| #ifdef HAVE_STRING_H |
| @@ -99,2 +105,5 @@ |
| #include <unistd.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/unistd.h" |
| +#endif |
| #include <sys/cdefs.h> |
| @@ -203,4 +212,4 @@ typedef struct GNode { |
| enum enum_made { |
| - UNMADE, DEFERRED, REQUESTED, BEINGMADE, |
| - MADE, UPTODATE, ERROR, ABORTED |
| + __UNMADE, __DEFERRED, __REQUESTED, __BEINGMADE, |
| + __MADE, __UPTODATE, __ERROR, __ABORTED |
| } made; /* Set to reflect the state of processing |
| @@ -437,2 +446,3 @@ extern Lst defIncPath; /* The default include path. */ |
| extern char curdir[]; /* Startup directory */ |
| +extern char *pcurdir; /* Startup directory */ |
| extern char *progname; /* The program name */ |
| @@ -466,3 +476,3 @@ extern pid_t myPid; |
| */ |
| -FILE *debug_file; /* Output written here - default stdout */ |
| +extern FILE *debug_file; /* Output written here - default stdout */ |
| extern int debug; |
| @@ -552,2 +562,12 @@ int cached_stat(const char *, void *); |
| |
| +size_t str_escape(char *dst, const char *src, size_t dstLen); |
| + |
| +size_t str_escape_dblquote(char *dst, const char *src, size_t dstLen); |
| + |
| +char * str_replace_char(const char *s, const char toReplace, const char replacement); |
| + |
| +extern int system_np(const char* command, int timeout_milliseconds, |
| + char* stdout_data, int stdout_data_size, |
| + char* stderr_data, int stderr_data_size, int* exit_code); |
| + |
| #endif /* _MAKE_H_ */ |
| diff --git a/makefile.in b/makefile.in |
| deleted file mode 100644 |
| index 03b980a..0000000 |
| --- a/makefile.in |
| +++ /dev/null |
| @@ -1,14 +0,0 @@ |
| -# $Id: makefile.in,v 1.1 2012/12/28 21:28:19 sjg Exp $ |
| - |
| -# a simple makefile for those who don't like anything beyond: |
| -# ./configure; make; make install |
| - |
| -prefix= @prefix@ |
| -srcdir= @srcdir@ |
| - |
| -all: build |
| - |
| -build clean install test: |
| - ${srcdir}/boot-strap --prefix=${prefix} -o . op=$@ |
| - |
| - |
| diff --git a/meta.c b/meta.c |
| index a852f3f..cd8c459 100644 |
| --- a/meta.c |
| +++ b/meta.c |
| @@ -38,3 +38,10 @@ |
| #include <sys/stat.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_ioctl.h" |
| +#else |
| #include <sys/ioctl.h> |
| +#endif |
| #ifdef HAVE_LIBGEN_H |
| @@ -1613,4 +1620,6 @@ meta_compat_start(void) |
| /* Set close-on-exec flag for both */ |
| +#if defined(F_SETFD) && defined(FD_CLOEXEC) |
| (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC); |
| (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC); |
| +#endif |
| } |
| diff --git a/mk/ChangeLog b/mk/ChangeLog |
| index ce8ac53..460ac78 100644 |
| --- a/mk/ChangeLog |
| +++ b/mk/ChangeLog |
| @@ -946,4 +946,4 @@ |
| read-only manually maintained dependencies. |
| - o meta2deps.py add a clear 'ERROR:' token if an exception is raised. |
| - o gendirdeps.mk if ERROR: from meta2deps.py do not update |
| + o meta2deps.py add a clear '__ERROR:' token if an exception is raised. |
| + o gendirdeps.mk if __ERROR: from meta2deps.py do not update |
| anything. |
| diff --git a/mk/gendirdeps.mk b/mk/gendirdeps.mk |
| index e04f839..5899574 100644 |
| --- a/mk/gendirdeps.mk |
| +++ b/mk/gendirdeps.mk |
| @@ -196,4 +196,4 @@ dir_list != cd ${_OBJDIR} && \ |
| |
| -.if ${dir_list:M*ERROR\:*} != "" |
| -.warning ${dir_list:tW:C,.*(ERROR),\1,} |
| +.if ${dir_list:M*__ERROR\:*} != "" |
| +.warning ${dir_list:tW:C,.*(__ERROR),\1,} |
| .warning Skipping ${_DEPENDFILE:S,${SRCTOP}/,,} |
| diff --git a/mk/host-target.mk b/mk/host-target.mk |
| index f528db9..1ab05b0 100644 |
| --- a/mk/host-target.mk |
| +++ b/mk/host-target.mk |
| @@ -5,3 +5,3 @@ |
| .if !defined(_HOST_OSNAME) |
| -_HOST_OSNAME != uname -s |
| +_HOST_OSNAME != uname -s | cut -d_ -f1 |
| .export _HOST_OSNAME |
| diff --git a/mk/install-mk b/mk/install-mk |
| index 886c264..05f385d 100644 |
| --- a/mk/install-mk |
| +++ b/mk/install-mk |
| @@ -115,3 +115,3 @@ Do() { |
| Error() { |
| - echo "ERROR: $@" >&2 |
| + echo "__ERROR: $@" >&2 |
| exit 1 |
| diff --git a/mk/meta.autodep.mk b/mk/meta.autodep.mk |
| index 9cb3f14..8c84502 100644 |
| --- a/mk/meta.autodep.mk |
| +++ b/mk/meta.autodep.mk |
| @@ -316,3 +316,3 @@ _reldir_failed: .NOMETA |
| .END: _reldir_finish |
| -.ERROR: _reldir_failed |
| +.__ERROR: _reldir_failed |
| .endif |
| diff --git a/mk/meta.stage.mk b/mk/meta.stage.mk |
| index 320ffcc..d4f8a68 100644 |
| --- a/mk/meta.stage.mk |
| +++ b/mk/meta.stage.mk |
| @@ -67,3 +67,3 @@ LN_CP_SCRIPT = LnCp() { \ |
| # a warning is handy when bootstapping different options. |
| -STAGE_CONFLICT?= ERROR |
| +STAGE_CONFLICT?= __ERROR |
| .if ${STAGE_CONFLICT:tl} == "error" |
| diff --git a/mk/meta.sys.mk b/mk/meta.sys.mk |
| index 4dbdd79..de0e3b1 100644 |
| --- a/mk/meta.sys.mk |
| +++ b/mk/meta.sys.mk |
| @@ -20,3 +20,3 @@ |
| .if ${MAKE_VERSION:U0} > 20100901 |
| -.if !target(.ERROR) |
| +.if !target(.__ERROR) |
| |
| @@ -94,3 +94,3 @@ meta_error_log = ${ERROR_LOGDIR}/meta-${.MAKE.PID}.log |
| # we are not interested in make telling us a failure happened elsewhere |
| -.ERROR: _metaError |
| +.__ERROR: _metaError |
| _metaError: .NOMETA .NOTMAIN |
| @@ -100,3 +100,3 @@ _metaError: .NOMETA .NOTMAIN |
| cp ${.ERROR_META_FILE} ${meta_error_log}; \ |
| - echo "ERROR: log ${meta_error_log}" >&2; }; : |
| + echo "__ERROR: log ${meta_error_log}" >&2; }; : |
| |
| @@ -139,3 +139,3 @@ UPDATE_DEPENDFILE= NO |
| .elif !exists(/dev/filemon) |
| -.error ${.newline}ERROR: The filemon module (/dev/filemon) is not loaded. |
| +.error ${.newline}__ERROR: The filemon module (/dev/filemon) is not loaded. |
| .endif |
| diff --git a/mk/own.mk b/mk/own.mk |
| index 4c8425b..37be01b 100644 |
| --- a/mk/own.mk |
| +++ b/mk/own.mk |
| @@ -196,3 +196,3 @@ SHAREMODE?= ${NONBINMODE} |
| COPY?= -c |
| -STRIP_FLAG?= -s |
| +STRIP_FLAG?= |
| |
| diff --git a/mk/prog.mk b/mk/prog.mk |
| index 4bc6260..11bf182 100644 |
| --- a/mk/prog.mk |
| +++ b/mk/prog.mk |
| @@ -26,3 +26,3 @@ CFLAGS+= -mcmodel=medlow |
| LIBCRTBEGIN= ${DESTDIR}/usr/lib/crtbegin.o |
| -.MADE: ${LIBCRTBEGIN} |
| +.__MADE: ${LIBCRTBEGIN} |
| .endif |
| @@ -30,3 +30,3 @@ LIBCRTBEGIN= ${DESTDIR}/usr/lib/crtbegin.o |
| LIBCRTEND= ${DESTDIR}/usr/lib/crtend.o |
| -.MADE: ${LIBCRTEND} |
| +.__MADE: ${LIBCRTEND} |
| .endif |
| @@ -41,3 +41,3 @@ _SHLINKER= ${SHLINKDIR}/ld.so |
| LIBCRT0= ${DESTDIR}/usr/lib/crt0.o |
| -.MADE: ${LIBCRT0} |
| +.__MADE: ${LIBCRT0} |
| .endif |
| @@ -181,3 +181,3 @@ proginstall: |
| ${INSTALL} ${COPY} ${STRIP_FLAG} ${PROG_INSTALL_OWN} -m ${BINMODE} \ |
| - ${PROG} ${DESTDIR}${BINDIR}/${PROG_NAME} |
| + ${OBJTOP:tA}/${PROG} ${DESTDIR}${BINDIR}/${PROG_NAME} |
| .endif |
| diff --git a/mk/sys/MINGW32.mk b/mk/sys/MINGW32.mk |
| new file mode 100644 |
| index 0000000..10da919 |
| --- /dev/null |
| +++ b/mk/sys/MINGW32.mk |
| @@ -0,0 +1,185 @@ |
| +# $Id: Linux.mk,v 1.9 2017/05/05 18:02:16 sjg Exp $ |
| +# $NetBSD: sys.mk,v 1.19.2.1 1994/07/26 19:58:31 cgd Exp $ |
| +# @(#)sys.mk 5.11 (Berkeley) 3/13/91 |
| + |
| +OS?= Windows |
| +unix?= We run ${OS}. |
| + |
| +ROOT_GROUP= |
| + |
| +# would be better to work out where it is... |
| +LIBCRT0= /dev/null |
| + |
| +NEED_SOLINKS=yes |
| + |
| +.SUFFIXES: .out .a .ln .o .c ${CXX_SUFFIXES} .F .f .r .y .l .s .S .cl .p .h .sh .m4 |
| + |
| +.LIBS: .a |
| + |
| +AR= ar |
| +ARFLAGS= rl |
| +RANLIB= ranlib |
| + |
| +AS= as |
| +AFLAGS= |
| +COMPILE.s= ${AS} ${AFLAGS} |
| +LINK.s= ${CC} ${AFLAGS} ${LDFLAGS} |
| +COMPILE.S= ${CC} ${AFLAGS} ${CPPFLAGS} -c |
| +LINK.S= ${CC} ${AFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +CC= gcc -pipe |
| +DBG= -O -g |
| +STATIC?= -static |
| + |
| +CFLAGS= ${DBG} |
| +COMPILE.c= ${CC} ${CFLAGS} ${CPPFLAGS} -c |
| +LINK.c= ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +CXX= g++ |
| +CXXFLAGS= ${CFLAGS} |
| +COMPILE.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c |
| +LINK.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +CPP= cpp |
| +.if defined(DESTDIR) |
| +CPPFLAGS+= -nostdinc -idirafter ${DESTDIR}/usr/include |
| +.endif |
| + |
| +MK_DEP= mkdeps.sh -N |
| +FC= f77 |
| +FFLAGS= -O |
| +RFLAGS= |
| +COMPILE.f= ${FC} ${FFLAGS} -c |
| +LINK.f= ${FC} ${FFLAGS} ${LDFLAGS} |
| +COMPILE.F= ${FC} ${FFLAGS} ${CPPFLAGS} -c |
| +LINK.F= ${FC} ${FFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| +COMPILE.r= ${FC} ${FFLAGS} ${RFLAGS} -c |
| +LINK.r= ${FC} ${FFLAGS} ${RFLAGS} ${LDFLAGS} |
| + |
| +LEX= lex |
| +LFLAGS= |
| +LEX.l= ${LEX} ${LFLAGS} |
| + |
| +LD= ld |
| +LDFLAGS= |
| + |
| +LINT= lint |
| +LINTFLAGS= -chapbx |
| + |
| +PC= pc |
| +PFLAGS= |
| +COMPILE.p= ${PC} ${PFLAGS} ${CPPFLAGS} -c |
| +LINK.p= ${PC} ${PFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +SHELL= sh |
| + |
| +YACC= yacc |
| +YFLAGS= -d |
| +YACC.y= ${YACC} ${YFLAGS} |
| + |
| +# C |
| +.c: |
| + ${LINK.c} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.c.o: |
| + ${COMPILE.c} ${.IMPSRC} |
| +.c.a: |
| + ${COMPILE.c} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# C++ |
| +${CXX_SUFFIXES}: |
| + ${LINK.cc} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +${CXX_SUFFIXES:%=%.o}: |
| + ${COMPILE.cc} ${.IMPSRC} |
| +${CXX_SUFFIXES:%=%.a}: |
| + ${COMPILE.cc} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Fortran/Ratfor |
| +.f: |
| + ${LINK.f} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.f.o: |
| + ${COMPILE.f} ${.IMPSRC} |
| +.f.a: |
| + ${COMPILE.f} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +.F: |
| + ${LINK.F} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.F.o: |
| + ${COMPILE.F} ${.IMPSRC} |
| +.F.a: |
| + ${COMPILE.F} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +.r: |
| + ${LINK.r} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.r.o: |
| + ${COMPILE.r} ${.IMPSRC} |
| +.r.a: |
| + ${COMPILE.r} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Pascal |
| +.p: |
| + ${LINK.p} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.p.o: |
| + ${COMPILE.p} ${.IMPSRC} |
| +.p.a: |
| + ${COMPILE.p} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Assembly |
| +.s: |
| + ${LINK.s} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.s.o: |
| + ${COMPILE.s} -o ${.TARGET} ${.IMPSRC} |
| +.s.a: |
| + ${COMPILE.s} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| +.S: |
| + ${LINK.S} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.S.o: |
| + ${COMPILE.S} ${.IMPSRC} |
| +.S.a: |
| + ${COMPILE.S} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Lex |
| +.l: |
| + ${LEX.l} ${.IMPSRC} |
| + ${LINK.c} -o ${.TARGET} lex.yy.c ${LDLIBS} -ll |
| + rm -f lex.yy.c |
| +.l.c: |
| + ${LEX.l} ${.IMPSRC} |
| + mv lex.yy.c ${.TARGET} |
| +.l.o: |
| + ${LEX.l} ${.IMPSRC} |
| + ${COMPILE.c} -o ${.TARGET} lex.yy.c |
| + rm -f lex.yy.c |
| + |
| +# Yacc |
| +.y: |
| + ${YACC.y} ${.IMPSRC} |
| + ${LINK.c} -o ${.TARGET} y.tab.c ${LDLIBS} |
| + rm -f y.tab.c |
| +.y.c: |
| + ${YACC.y} ${.IMPSRC} |
| + mv y.tab.c ${.TARGET} |
| +.y.o: |
| + ${YACC.y} ${.IMPSRC} |
| + ${COMPILE.c} -o ${.TARGET} y.tab.c |
| + rm -f y.tab.c |
| + |
| +# Shell |
| +.sh: |
| + rm -f ${.TARGET} |
| + cp ${.IMPSRC} ${.TARGET} |
| diff --git a/mk/sys/MINGW64.mk b/mk/sys/MINGW64.mk |
| new file mode 100644 |
| index 0000000..10da919 |
| --- /dev/null |
| +++ b/mk/sys/MINGW64.mk |
| @@ -0,0 +1,185 @@ |
| +# $Id: Linux.mk,v 1.9 2017/05/05 18:02:16 sjg Exp $ |
| +# $NetBSD: sys.mk,v 1.19.2.1 1994/07/26 19:58:31 cgd Exp $ |
| +# @(#)sys.mk 5.11 (Berkeley) 3/13/91 |
| + |
| +OS?= Windows |
| +unix?= We run ${OS}. |
| + |
| +ROOT_GROUP= |
| + |
| +# would be better to work out where it is... |
| +LIBCRT0= /dev/null |
| + |
| +NEED_SOLINKS=yes |
| + |
| +.SUFFIXES: .out .a .ln .o .c ${CXX_SUFFIXES} .F .f .r .y .l .s .S .cl .p .h .sh .m4 |
| + |
| +.LIBS: .a |
| + |
| +AR= ar |
| +ARFLAGS= rl |
| +RANLIB= ranlib |
| + |
| +AS= as |
| +AFLAGS= |
| +COMPILE.s= ${AS} ${AFLAGS} |
| +LINK.s= ${CC} ${AFLAGS} ${LDFLAGS} |
| +COMPILE.S= ${CC} ${AFLAGS} ${CPPFLAGS} -c |
| +LINK.S= ${CC} ${AFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +CC= gcc -pipe |
| +DBG= -O -g |
| +STATIC?= -static |
| + |
| +CFLAGS= ${DBG} |
| +COMPILE.c= ${CC} ${CFLAGS} ${CPPFLAGS} -c |
| +LINK.c= ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +CXX= g++ |
| +CXXFLAGS= ${CFLAGS} |
| +COMPILE.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c |
| +LINK.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +CPP= cpp |
| +.if defined(DESTDIR) |
| +CPPFLAGS+= -nostdinc -idirafter ${DESTDIR}/usr/include |
| +.endif |
| + |
| +MK_DEP= mkdeps.sh -N |
| +FC= f77 |
| +FFLAGS= -O |
| +RFLAGS= |
| +COMPILE.f= ${FC} ${FFLAGS} -c |
| +LINK.f= ${FC} ${FFLAGS} ${LDFLAGS} |
| +COMPILE.F= ${FC} ${FFLAGS} ${CPPFLAGS} -c |
| +LINK.F= ${FC} ${FFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| +COMPILE.r= ${FC} ${FFLAGS} ${RFLAGS} -c |
| +LINK.r= ${FC} ${FFLAGS} ${RFLAGS} ${LDFLAGS} |
| + |
| +LEX= lex |
| +LFLAGS= |
| +LEX.l= ${LEX} ${LFLAGS} |
| + |
| +LD= ld |
| +LDFLAGS= |
| + |
| +LINT= lint |
| +LINTFLAGS= -chapbx |
| + |
| +PC= pc |
| +PFLAGS= |
| +COMPILE.p= ${PC} ${PFLAGS} ${CPPFLAGS} -c |
| +LINK.p= ${PC} ${PFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +SHELL= sh |
| + |
| +YACC= yacc |
| +YFLAGS= -d |
| +YACC.y= ${YACC} ${YFLAGS} |
| + |
| +# C |
| +.c: |
| + ${LINK.c} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.c.o: |
| + ${COMPILE.c} ${.IMPSRC} |
| +.c.a: |
| + ${COMPILE.c} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# C++ |
| +${CXX_SUFFIXES}: |
| + ${LINK.cc} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +${CXX_SUFFIXES:%=%.o}: |
| + ${COMPILE.cc} ${.IMPSRC} |
| +${CXX_SUFFIXES:%=%.a}: |
| + ${COMPILE.cc} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Fortran/Ratfor |
| +.f: |
| + ${LINK.f} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.f.o: |
| + ${COMPILE.f} ${.IMPSRC} |
| +.f.a: |
| + ${COMPILE.f} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +.F: |
| + ${LINK.F} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.F.o: |
| + ${COMPILE.F} ${.IMPSRC} |
| +.F.a: |
| + ${COMPILE.F} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +.r: |
| + ${LINK.r} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.r.o: |
| + ${COMPILE.r} ${.IMPSRC} |
| +.r.a: |
| + ${COMPILE.r} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Pascal |
| +.p: |
| + ${LINK.p} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.p.o: |
| + ${COMPILE.p} ${.IMPSRC} |
| +.p.a: |
| + ${COMPILE.p} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Assembly |
| +.s: |
| + ${LINK.s} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.s.o: |
| + ${COMPILE.s} -o ${.TARGET} ${.IMPSRC} |
| +.s.a: |
| + ${COMPILE.s} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| +.S: |
| + ${LINK.S} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.S.o: |
| + ${COMPILE.S} ${.IMPSRC} |
| +.S.a: |
| + ${COMPILE.S} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Lex |
| +.l: |
| + ${LEX.l} ${.IMPSRC} |
| + ${LINK.c} -o ${.TARGET} lex.yy.c ${LDLIBS} -ll |
| + rm -f lex.yy.c |
| +.l.c: |
| + ${LEX.l} ${.IMPSRC} |
| + mv lex.yy.c ${.TARGET} |
| +.l.o: |
| + ${LEX.l} ${.IMPSRC} |
| + ${COMPILE.c} -o ${.TARGET} lex.yy.c |
| + rm -f lex.yy.c |
| + |
| +# Yacc |
| +.y: |
| + ${YACC.y} ${.IMPSRC} |
| + ${LINK.c} -o ${.TARGET} y.tab.c ${LDLIBS} |
| + rm -f y.tab.c |
| +.y.c: |
| + ${YACC.y} ${.IMPSRC} |
| + mv y.tab.c ${.TARGET} |
| +.y.o: |
| + ${YACC.y} ${.IMPSRC} |
| + ${COMPILE.c} -o ${.TARGET} y.tab.c |
| + rm -f y.tab.c |
| + |
| +# Shell |
| +.sh: |
| + rm -f ${.TARGET} |
| + cp ${.IMPSRC} ${.TARGET} |
| diff --git a/mk/sys/MSYS.mk b/mk/sys/MSYS.mk |
| new file mode 100644 |
| index 0000000..10da919 |
| --- /dev/null |
| +++ b/mk/sys/MSYS.mk |
| @@ -0,0 +1,185 @@ |
| +# $Id: Linux.mk,v 1.9 2017/05/05 18:02:16 sjg Exp $ |
| +# $NetBSD: sys.mk,v 1.19.2.1 1994/07/26 19:58:31 cgd Exp $ |
| +# @(#)sys.mk 5.11 (Berkeley) 3/13/91 |
| + |
| +OS?= Windows |
| +unix?= We run ${OS}. |
| + |
| +ROOT_GROUP= |
| + |
| +# would be better to work out where it is... |
| +LIBCRT0= /dev/null |
| + |
| +NEED_SOLINKS=yes |
| + |
| +.SUFFIXES: .out .a .ln .o .c ${CXX_SUFFIXES} .F .f .r .y .l .s .S .cl .p .h .sh .m4 |
| + |
| +.LIBS: .a |
| + |
| +AR= ar |
| +ARFLAGS= rl |
| +RANLIB= ranlib |
| + |
| +AS= as |
| +AFLAGS= |
| +COMPILE.s= ${AS} ${AFLAGS} |
| +LINK.s= ${CC} ${AFLAGS} ${LDFLAGS} |
| +COMPILE.S= ${CC} ${AFLAGS} ${CPPFLAGS} -c |
| +LINK.S= ${CC} ${AFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +CC= gcc -pipe |
| +DBG= -O -g |
| +STATIC?= -static |
| + |
| +CFLAGS= ${DBG} |
| +COMPILE.c= ${CC} ${CFLAGS} ${CPPFLAGS} -c |
| +LINK.c= ${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +CXX= g++ |
| +CXXFLAGS= ${CFLAGS} |
| +COMPILE.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} -c |
| +LINK.cc= ${CXX} ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +CPP= cpp |
| +.if defined(DESTDIR) |
| +CPPFLAGS+= -nostdinc -idirafter ${DESTDIR}/usr/include |
| +.endif |
| + |
| +MK_DEP= mkdeps.sh -N |
| +FC= f77 |
| +FFLAGS= -O |
| +RFLAGS= |
| +COMPILE.f= ${FC} ${FFLAGS} -c |
| +LINK.f= ${FC} ${FFLAGS} ${LDFLAGS} |
| +COMPILE.F= ${FC} ${FFLAGS} ${CPPFLAGS} -c |
| +LINK.F= ${FC} ${FFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| +COMPILE.r= ${FC} ${FFLAGS} ${RFLAGS} -c |
| +LINK.r= ${FC} ${FFLAGS} ${RFLAGS} ${LDFLAGS} |
| + |
| +LEX= lex |
| +LFLAGS= |
| +LEX.l= ${LEX} ${LFLAGS} |
| + |
| +LD= ld |
| +LDFLAGS= |
| + |
| +LINT= lint |
| +LINTFLAGS= -chapbx |
| + |
| +PC= pc |
| +PFLAGS= |
| +COMPILE.p= ${PC} ${PFLAGS} ${CPPFLAGS} -c |
| +LINK.p= ${PC} ${PFLAGS} ${CPPFLAGS} ${LDFLAGS} |
| + |
| +SHELL= sh |
| + |
| +YACC= yacc |
| +YFLAGS= -d |
| +YACC.y= ${YACC} ${YFLAGS} |
| + |
| +# C |
| +.c: |
| + ${LINK.c} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.c.o: |
| + ${COMPILE.c} ${.IMPSRC} |
| +.c.a: |
| + ${COMPILE.c} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# C++ |
| +${CXX_SUFFIXES}: |
| + ${LINK.cc} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +${CXX_SUFFIXES:%=%.o}: |
| + ${COMPILE.cc} ${.IMPSRC} |
| +${CXX_SUFFIXES:%=%.a}: |
| + ${COMPILE.cc} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Fortran/Ratfor |
| +.f: |
| + ${LINK.f} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.f.o: |
| + ${COMPILE.f} ${.IMPSRC} |
| +.f.a: |
| + ${COMPILE.f} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +.F: |
| + ${LINK.F} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.F.o: |
| + ${COMPILE.F} ${.IMPSRC} |
| +.F.a: |
| + ${COMPILE.F} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +.r: |
| + ${LINK.r} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.r.o: |
| + ${COMPILE.r} ${.IMPSRC} |
| +.r.a: |
| + ${COMPILE.r} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Pascal |
| +.p: |
| + ${LINK.p} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.p.o: |
| + ${COMPILE.p} ${.IMPSRC} |
| +.p.a: |
| + ${COMPILE.p} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Assembly |
| +.s: |
| + ${LINK.s} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.s.o: |
| + ${COMPILE.s} -o ${.TARGET} ${.IMPSRC} |
| +.s.a: |
| + ${COMPILE.s} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| +.S: |
| + ${LINK.S} -o ${.TARGET} ${.IMPSRC} ${LDLIBS} |
| +.S.o: |
| + ${COMPILE.S} ${.IMPSRC} |
| +.S.a: |
| + ${COMPILE.S} ${.IMPSRC} |
| + ${AR} ${ARFLAGS} $@ $*.o |
| + rm -f $*.o |
| + |
| +# Lex |
| +.l: |
| + ${LEX.l} ${.IMPSRC} |
| + ${LINK.c} -o ${.TARGET} lex.yy.c ${LDLIBS} -ll |
| + rm -f lex.yy.c |
| +.l.c: |
| + ${LEX.l} ${.IMPSRC} |
| + mv lex.yy.c ${.TARGET} |
| +.l.o: |
| + ${LEX.l} ${.IMPSRC} |
| + ${COMPILE.c} -o ${.TARGET} lex.yy.c |
| + rm -f lex.yy.c |
| + |
| +# Yacc |
| +.y: |
| + ${YACC.y} ${.IMPSRC} |
| + ${LINK.c} -o ${.TARGET} y.tab.c ${LDLIBS} |
| + rm -f y.tab.c |
| +.y.c: |
| + ${YACC.y} ${.IMPSRC} |
| + mv y.tab.c ${.TARGET} |
| +.y.o: |
| + ${YACC.y} ${.IMPSRC} |
| + ${COMPILE.c} -o ${.TARGET} y.tab.c |
| + rm -f y.tab.c |
| + |
| +# Shell |
| +.sh: |
| + rm -f ${.TARGET} |
| + cp ${.IMPSRC} ${.TARGET} |
| diff --git a/mk/warnings.mk b/mk/warnings.mk |
| index 7fb3ebd..de664fd 100644 |
| --- a/mk/warnings.mk |
| +++ b/mk/warnings.mk |
| @@ -69,4 +69,4 @@ _empty_warnings: .PHONY |
| .endif |
| - @echo "ERROR: Invalid: WARNINGS_SET=${ws}" |
| - @echo "ERROR: Try one of: ${ALL_WARNINGS_SETS:O:u}"; exit 1 |
| + @echo "__ERROR: Invalid: WARNINGS_SET=${ws}" |
| + @echo "__ERROR: Try one of: ${ALL_WARNINGS_SETS:O:u}"; exit 1 |
| |
| diff --git a/parse.c b/parse.c |
| index a7d7a4d..a996c49 100644 |
| --- a/parse.c |
| +++ b/parse.c |
| @@ -127,2 +127,5 @@ __RCSID("$NetBSD: parse.c,v 1.231 2018/12/22 00:36:32 sjg Exp $"); |
| #include <sys/stat.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| #include <assert.h> |
| @@ -2397,3 +2400,3 @@ ParseSetParseFile(const char *filename) |
| { |
| - char *slash, *dirname; |
| + char *slash, *dirname, *pdirname; |
| const char *pd, *pf; |
| @@ -2403,3 +2406,3 @@ ParseSetParseFile(const char *filename) |
| if (slash == NULL) { |
| - Var_Set(".PARSEDIR", pd = curdir, VAR_GLOBAL, 0); |
| + Var_Set(".PARSEDIR", pd = pcurdir, VAR_GLOBAL, 0); |
| Var_Set(".PARSEFILE", pf = filename, VAR_GLOBAL, 0); |
| @@ -2411,3 +2414,19 @@ ParseSetParseFile(const char *filename) |
| dirname[len] = '\0'; |
| - Var_Set(".PARSEDIR", pd = dirname, VAR_GLOBAL, 0); |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +// pdirname = str_replace_char(dirname, '\\', '/'); |
| +// if (pdirname[1] == ':') { // create msys-style windows path |
| +// pdirname[1] = pdirname[0]; |
| +// pdirname[0] = '/'; |
| +// } |
| + char *error; |
| + if (dirname && strlen(dirname) > 0 && dirname[1] == ':' && (dirname[2] == '/' || dirname[2] == '\\')) { |
| + pdirname = Cmd_Exec(getUnixPathCmd(dirname), &error); |
| + } |
| + else { |
| + pdirname = dirname; |
| + } |
| +#else |
| + pdirname = dirname; |
| +#endif |
| + Var_Set(".PARSEDIR", pd = pdirname, VAR_GLOBAL, 0); |
| Var_Set(".PARSEFILE", pf = slash + 1, VAR_GLOBAL, 0); |
| diff --git a/pathnames.h b/pathnames.h |
| index 9c597b1..e3436a4 100644 |
| --- a/pathnames.h |
| +++ b/pathnames.h |
| @@ -60,3 +60,7 @@ |
| #ifndef _PATH_TMP |
| -#define _PATH_TMP "/tmp/" /* with trailing slash */ |
| +# if (defined _WIN32 && ! defined __CYGWIN__) |
| +# define _PATH_TMP (getenv("TEMP")) |
| +# else |
| +# define _PATH_TMP "/tmp/" /* with trailing slash */ |
| +# endif |
| #endif |
| diff --git a/realpath.c b/realpath.c |
| index fbf0335..9a6ac51 100644 |
| --- a/realpath.c |
| +++ b/realpath.c |
| @@ -42,3 +42,5 @@ |
| #include <sys/stat.h> |
| - |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| #include <errno.h> |
| @@ -51,3 +53,6 @@ |
| #ifdef HAVE_UNISTD_H |
| -# include <unistd.h> |
| +#include <unistd.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/unistd.h" |
| +#endif |
| #endif |
| diff --git a/sigcompat.c b/sigcompat.c |
| index 608538d..9e605e9 100644 |
| --- a/sigcompat.c |
| +++ b/sigcompat.c |
| @@ -91,4 +91,13 @@ |
| #include <signal.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/signal.h" |
| +#endif |
| +#ifndef SIGQUIT |
| +#define SIGQUIT SIGTERM |
| +#endif |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/unistd.h" |
| +#endif |
| #endif |
| diff --git a/str.c b/str.c |
| index b5255bc..cf85b95 100644 |
| --- a/str.c |
| +++ b/str.c |
| @@ -526 +526,30 @@ Str_SYSVSubst(Buffer *buf, char *pat, char *src, int len) |
| } |
| + |
| +char * str_replace_char(const char *s, const char toReplace, const char replacement) |
| +{ |
| + int len; |
| + int count = 0; |
| + char *result; |
| + |
| + |
| + |
| + len = strlen(s); |
| + |
| + /* allocate length plus EOS */ |
| + result = bmake_malloc((unsigned int)(len + 1)); |
| + |
| + /* copy first string into place */ |
| + memcpy(result, s, len + 1); |
| + |
| + count = 0; |
| + while(result[count]!='\0' && count < len) |
| + { |
| + if(result[count]==toReplace) |
| + { |
| + result[count]=replacement; |
| + } |
| + count++; |
| + } |
| + |
| + return result; |
| +} |
| diff --git a/targ.c b/targ.c |
| index 01c3d1c..17b14aa 100644 |
| --- a/targ.c |
| +++ b/targ.c |
| @@ -248,3 +248,3 @@ Targ_NewGN(const char *name) |
| gn->centurion = NULL; |
| - gn->made = UNMADE; |
| + gn->made = __UNMADE; |
| gn->flags = 0; |
| @@ -605,10 +605,10 @@ made_name(enum enum_made made) |
| switch (made) { |
| - case UNMADE: return "unmade"; |
| - case DEFERRED: return "deferred"; |
| - case REQUESTED: return "requested"; |
| - case BEINGMADE: return "being made"; |
| - case MADE: return "made"; |
| - case UPTODATE: return "up-to-date"; |
| - case ERROR: return "error when made"; |
| - case ABORTED: return "aborted"; |
| + case __UNMADE: return "unmade"; |
| + case __DEFERRED: return "deferred"; |
| + case __REQUESTED: return "requested"; |
| + case __BEINGMADE: return "being made"; |
| + case __MADE: return "made"; |
| + case __UPTODATE: return "up-to-date"; |
| + case __ERROR: return "error when made"; |
| + case __ABORTED: return "aborted"; |
| default: return "unknown enum_made value"; |
| @@ -650,3 +650,3 @@ Targ_PrintNode(void *gnp, void *passp) |
| made_name(gn->made)); |
| - } else if (gn->made != UNMADE) { |
| + } else if (gn->made != __UNMADE) { |
| fprintf(debug_file, "# non-existent (maybe): %s\n", |
| diff --git a/trace.c b/trace.c |
| index 267177f..f0f8693 100644 |
| --- a/trace.c |
| +++ b/trace.c |
| @@ -58,2 +58,5 @@ __RCSID("$NetBSD: trace.c,v 1.11 2008/12/28 18:31:51 christos Exp $"); |
| #include <unistd.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/unistd.h" |
| +#endif |
| |
| diff --git a/unit-tests/Makefile b/unit-tests/Makefile |
| new file mode 100644 |
| index 0000000..bd45de7 |
| --- /dev/null |
| +++ b/unit-tests/Makefile |
| @@ -0,0 +1,152 @@ |
| +# $Id: Makefile.in,v 1.49 2018/09/21 21:39:05 sjg Exp $ |
| +# |
| +# $NetBSD: Makefile,v 1.53 2018/05/24 00:25:44 christos Exp $ |
| +# |
| +# Unit tests for make(1) |
| +# The main targets are: |
| +# |
| +# all: run all the tests |
| +# test: run 'all', and compare to expected results |
| +# accept: move generated output to expected results |
| +# |
| +# Adding a test case. |
| +# Each feature should get its own set of tests in its own suitably |
| +# named makefile (*.mk), with its own set of expected results (*.exp), |
| +# and it should be added to the TESTNAMES list. |
| +# |
| + |
| +srcdir= /home/ofry/bmake/unit-tests |
| + |
| +.MAIN: all |
| + |
| +UNIT_TESTS:= ${srcdir} |
| +WIN_UNIT_TESTS != cygpath -m ${srcdir} |
| +.PATH: ${UNIT_TESTS} |
| + |
| +# Each test is in a sub-makefile. |
| +# Keep the list sorted. |
| +TESTNAMES= \ |
| + comment \ |
| + cond1 \ |
| + cond2 \ |
| + error \ |
| + export \ |
| + export-all \ |
| + export-env \ |
| + doterror \ |
| + forloop \ |
| + forsubst \ |
| + hash \ |
| + misc \ |
| + moderrs \ |
| + modmatch \ |
| + modmisc \ |
| + modorder \ |
| + modts \ |
| + modword \ |
| + qequals \ |
| + sunshcmd \ |
| + sysv \ |
| + ternary \ |
| + unexport \ |
| + unexport-env \ |
| + varcmd \ |
| + varmisc \ |
| + varquote \ |
| + varshell |
| + |
| +# these tests were broken by referting POSIX chanegs |
| +STRICT_POSIX_TESTS = \ |
| + escape \ |
| + impsrc \ |
| + phony-end \ |
| + posix1 \ |
| + suffixes |
| + |
| +# Override make flags for certain tests |
| +flags.doterror= |
| +flags.order=-j1 |
| + |
| +OUTFILES= ${TESTNAMES:S/$/.out/} |
| + |
| +all: ${OUTFILES} |
| + |
| +CLEANFILES += *.rawout *.out *.status *.tmp *.core *.tmp |
| +CLEANFILES += obj*.[och] lib*.a # posix1.mk |
| +CLEANFILES += issue* .[ab]* # suffixes.mk |
| +CLEANRECURSIVE += dir dummy # posix1.mk |
| + |
| +clean: |
| + rm -f ${CLEANFILES} |
| +.if !empty(CLEANRECURSIVE) |
| + rm -rf ${CLEANRECURSIVE} |
| +.endif |
| + |
| +TEST_MAKE?= ${.MAKE} |
| +TOOL_SED?= sed |
| +TOOL_TR?= tr |
| +TOOL_DIFF?= diff |
| +DIFF_FLAGS?= -u |
| + |
| +.if defined(.PARSEDIR) |
| +# ensure consistent results from sort(1) |
| +LC_ALL= C |
| +LANG= C |
| +.export LANG LC_ALL |
| +.endif |
| + |
| +# some tests need extra post-processing |
| +SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ |
| + -e '/command/s,No such.*,not found,' |
| + |
| +# the tests are actually done with sub-makes. |
| +.SUFFIXES: .mk .rawout .out |
| +.mk.rawout: |
| + @echo ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} |
| + -@cd ${.OBJDIR} && \ |
| + { ${TEST_MAKE} ${flags.${.TARGET:R}:U-k} -f ${.IMPSRC} \ |
| + 2>&1 ; echo $$? >${.TARGET:R}.status ; } > ${.TARGET}.tmp |
| + @mv ${.TARGET}.tmp ${.TARGET} |
| + |
| +# We always pretend .MAKE was called 'make' |
| +# and strip ${.CURDIR}/ from the output |
| +# and replace anything after 'stopped in' with unit-tests |
| +# so the results can be compared. |
| +.rawout.out: |
| + @echo postprocess ${.TARGET} |
| + @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \ |
| + -e 's,^${TEST_MAKE:T:C/\./\\\./g}\.exe[][0-9]*:,make:,' \ |
| + -e 's,${TEST_MAKE:C/\./\\\./g},make,' \ |
| + -e '/stopped/s, /.*, unit-tests,' \ |
| + -e 's,${.CURDIR:C/\./\\\./g}/,,g' \ |
| + -e 's,${WIN_UNIT_TESTS:C/\./\\\./g},unit-tests,g' \ |
| + -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' ${SED_CMDS.${.TARGET:T:R}} \ |
| + < ${.IMPSRC} > ${.TARGET}.tmp |
| + @echo "exit status `cat ${.TARGET:R}.status`" >> ${.TARGET}.tmp |
| + @mv ${.TARGET}.tmp ${.TARGET} |
| + |
| +# Compare all output files |
| +test: ${OUTFILES} .PHONY |
| + @failed= ; \ |
| + for test in ${TESTNAMES}; do \ |
| + ${TOOL_DIFF} ${DIFF_FLAGS} ${UNIT_TESTS}/$${test}.exp $${test}.out \ |
| + || failed="$${failed}$${failed:+ }$${test}" ; \ |
| + done ; \ |
| + if [ -n "$${failed}" ]; then \ |
| + echo "Failed tests: $${failed}" ; false ; \ |
| + else \ |
| + echo "All tests passed" ; \ |
| + fi |
| + |
| +accept: |
| + @for test in ${TESTNAMES}; do \ |
| + cmp -s ${UNIT_TESTS}/$${test}.exp $${test}.out \ |
| + || { echo "Replacing $${test}.exp" ; \ |
| + cp $${test}.out ${UNIT_TESTS}/$${test}.exp ; } \ |
| + done |
| + |
| +.if exists(${TEST_MAKE}) |
| +${TESTNAMES:S/$/.rawout/}: ${TEST_MAKE} |
| +.endif |
| + |
| +.-include <obj.mk> |
| diff --git a/unit-tests/Makefile.in b/unit-tests/Makefile.in |
| index e51d254..c24bc33 100644 |
| --- a/unit-tests/Makefile.in |
| +++ b/unit-tests/Makefile.in |
| @@ -22,2 +22,3 @@ srcdir= @srcdir@ |
| UNIT_TESTS:= ${srcdir} |
| +WIN_UNIT_TESTS != cygpath -m ${srcdir} |
| .PATH: ${UNIT_TESTS} |
| @@ -35,3 +36,2 @@ TESTNAMES= \ |
| doterror \ |
| - dotwait \ |
| forloop \ |
| @@ -46,4 +46,2 @@ TESTNAMES= \ |
| modword \ |
| - order \ |
| - posix \ |
| qequals \ |
| @@ -119,2 +117,3 @@ SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ |
| @${TOOL_SED} -e 's,^${TEST_MAKE:T:C/\./\\\./g}[][0-9]*:,make:,' \ |
| + -e 's,^${TEST_MAKE:T:C/\./\\\./g}\.exe[][0-9]*:,make:,' \ |
| -e 's,${TEST_MAKE:C/\./\\\./g},make,' \ |
| @@ -122,2 +121,3 @@ SED_CMDS.varshell = -e 's,^[a-z]*sh: ,,' \ |
| -e 's,${.CURDIR:C/\./\\\./g}/,,g' \ |
| + -e 's,${WIN_UNIT_TESTS:C/\./\\\./g},unit-tests,g' \ |
| -e 's,${UNIT_TESTS:C/\./\\\./g}/,,g' ${SED_CMDS.${.TARGET:T:R}} \ |
| diff --git a/unit-tests/doterror.exp b/unit-tests/doterror.exp |
| index 5655644..1c8b971 100644 |
| --- a/unit-tests/doterror.exp |
| +++ b/unit-tests/doterror.exp |
| @@ -7,3 +7,3 @@ Stop. |
| make: stopped in unit-tests |
| -.ERROR: Looks like 'sad' is upset. |
| +.__ERROR: Looks like 'sad' is upset. |
| exit status 1 |
| diff --git a/unit-tests/doterror.mk b/unit-tests/doterror.mk |
| index 9030dce..676e2e6 100644 |
| --- a/unit-tests/doterror.mk |
| +++ b/unit-tests/doterror.mk |
| @@ -9,3 +9,3 @@ |
| |
| -.ERROR: |
| +.__ERROR: |
| @echo "$@: Looks like '${.ERROR_TARGET}' is upset." |
| diff --git a/unit-tests/escape.mk b/unit-tests/escape.mk |
| index bb37c92..3bf1b1f 100644 |
| --- a/unit-tests/escape.mk |
| +++ b/unit-tests/escape.mk |
| @@ -53,3 +53,3 @@ should continue the comment. \ |
| |
| -__printvars: .USE .MADE |
| +__printvars: .USE .__MADE |
| @echo ${.TARGET} |
| diff --git a/util.c b/util.c |
| index c79f645..25f4f5e 100644 |
| --- a/util.c |
| +++ b/util.c |
| @@ -9,2 +9,8 @@ |
| #include <signal.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/signal.h" |
| +#endif |
| +#ifndef SIGQUIT |
| +#define SIGQUIT SIGTERM |
| +#endif |
| #endif |
| @@ -24,17 +30,487 @@ __RCSID("$NetBSD: util.c,v 1.54 2013/11/26 13:44:41 joerg Exp $"); |
| #include <signal.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/signal.h" |
| +#endif |
| +#ifndef SIGQUIT |
| +#define SIGQUIT SIGTERM |
| +#endif |
| |
| -#if !defined(HAVE_STRERROR) |
| -extern int errno, sys_nerr; |
| -extern char *sys_errlist[]; |
| +#ifndef NO_REGEX |
| |
| -char * |
| -strerror(int e) |
| +#include <sys/types.h> |
| + |
| +# if (defined _WIN32 && !defined __CYGWIN__) |
| +#include "headers-mingw/regex.h" |
| +#include "headers-mingw/regex_internal.h" |
| +# else |
| + |
| +#include <regex.h> |
| + |
| +# endif |
| +#endif |
| + |
| +#if !defined(HAVE_PIPE) && (defined _WIN32 && ! defined __CYGWIN__) |
| +/* Create a pipe. |
| + Copyright (C) 2009-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License along |
| + with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Specification. */ |
| +#include <unistd.h> |
| +#include "headers-mingw/unistd.h" |
| +/* Native Windows API. */ |
| + |
| +/* Get _pipe(). */ |
| +#include <io.h> |
| + |
| +/* Get _O_BINARY. */ |
| +#include <fcntl.h> |
| +#include "headers-mingw/fcntl.h" |
| + |
| +int |
| +pipe (int fd[2]) |
| { |
| - static char buf[100]; |
| - if (e < 0 || e >= sys_nerr) { |
| - snprintf(buf, sizeof(buf), "Unknown error %d", e); |
| - return buf; |
| + /* Mingw changes fd to {-1,-1} on failure, but this violates |
| + http://austingroupbugs.net/view.php?id=467 */ |
| + int tmp[2]; |
| + int result = _pipe (tmp, 4096, _O_BINARY); |
| + if (!result) |
| + { |
| + fd[0] = tmp[0]; |
| + fd[1] = tmp[1]; |
| } |
| - else |
| - return sys_errlist[e]; |
| + return result; |
| +} |
| + |
| +#endif |
| + |
| +#if !defined(HAVE_GETDTABLESIZE) && (defined _WIN32 && ! defined __CYGWIN__) |
| +/* getdtablesize() function: Return maximum possible file descriptor value + 1. |
| + Copyright (C) 2008-2018 Free Software Foundation, Inc. |
| + Written by Bruno Haible <bruno@clisp.org>, 2008. |
| + |
| + This program is free software: you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 3 of the License, or |
| + (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Specification. */ |
| +#include <unistd.h> |
| +#include "headers-mingw/unistd.h" |
| + |
| +# include <stdio.h> |
| + |
| +# define _setmaxstdio_nothrow _setmaxstdio |
| + |
| +/* Cache for the previous getdtablesize () result. Safe to cache because |
| + Windows also lacks setrlimit. */ |
| +static int dtablesize; |
| + |
| +int |
| +getdtablesize (void) |
| +{ |
| + if (dtablesize == 0) |
| + { |
| + /* We are looking for the number N such that the valid file descriptors |
| + are 0..N-1. It can be obtained through a loop as follows: |
| + { |
| + int fd; |
| + for (fd = 3; fd < 65536; fd++) |
| + if (dup2 (0, fd) == -1) |
| + break; |
| + return fd; |
| + } |
| + On Windows XP, the result is 2048. |
| + The drawback of this loop is that it allocates memory for a libc |
| + internal array that is never freed. |
| + |
| + The number N can also be obtained as the upper bound for |
| + _getmaxstdio (). _getmaxstdio () returns the maximum number of open |
| + FILE objects. The sanity check in _setmaxstdio reveals the maximum |
| + number of file descriptors. This too allocates memory, but it is |
| + freed when we call _setmaxstdio with the original value. */ |
| + int orig_max_stdio = _getmaxstdio (); |
| + unsigned int bound; |
| + for (bound = 0x10000; _setmaxstdio_nothrow (bound) < 0; bound = bound / 2) |
| + ; |
| + _setmaxstdio_nothrow (orig_max_stdio); |
| + dtablesize = bound; |
| + } |
| + return dtablesize; |
| +} |
| + |
| +#endif |
| + |
| +#if !defined(HAVE_FCNTL) && (defined _WIN32 && ! defined __CYGWIN__) |
| +/* Provide file descriptor control. |
| + |
| + Copyright (C) 2009-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software: you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 3 of the License, or |
| + (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Written by Eric Blake <ebb9@byu.net>. */ |
| + |
| +/* Specification. */ |
| +#include "headers-mingw/fcntl.h" |
| + |
| +#include <errno.h> |
| +#include <limits.h> |
| +#include <stdarg.h> |
| +#include <unistd.h> |
| + |
| +/* Get declarations of the native Windows API functions. */ |
| +# define WIN32_LEAN_AND_MEAN |
| +# include <windows.h> |
| + |
| +/* Get _get_osfhandle. */ |
| +# if GNULIB_MSVC_NOTHROW |
| +# include "msvc-nothrow.h" |
| +# else |
| +# include <io.h> |
| +# endif |
| + |
| +/* Upper bound on getdtablesize(). See lib/getdtablesize.c. */ |
| +# define OPEN_MAX_MAX 0x10000 |
| + |
| +/* Duplicate OLDFD into the first available slot of at least NEWFD, |
| + which must be positive, with FLAGS determining whether the duplicate |
| + will be inheritable. */ |
| +static int |
| +dupfd (int oldfd, int newfd, int flags) |
| +{ |
| + /* Mingw has no way to create an arbitrary fd. Iterate until all |
| + file descriptors less than newfd are filled up. */ |
| + HANDLE curr_process = GetCurrentProcess (); |
| + HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd); |
| + unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT]; |
| + unsigned int fds_to_close_bound = 0; |
| + int result; |
| + BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE; |
| + int mode; |
| + |
| + if (newfd < 0 || getdtablesize () <= newfd) |
| + { |
| + errno = EINVAL; |
| + return -1; |
| + } |
| + if (old_handle == INVALID_HANDLE_VALUE |
| + || (mode = setmode (oldfd, O_BINARY)) == -1) |
| + { |
| + /* oldfd is not open, or is an unassigned standard file |
| + descriptor. */ |
| + errno = EBADF; |
| + return -1; |
| + } |
| + setmode (oldfd, mode); |
| + flags |= mode; |
| + |
| + for (;;) |
| + { |
| + HANDLE new_handle; |
| + int duplicated_fd; |
| + unsigned int index; |
| + |
| + if (!DuplicateHandle (curr_process, /* SourceProcessHandle */ |
| + old_handle, /* SourceHandle */ |
| + curr_process, /* TargetProcessHandle */ |
| + (PHANDLE) &new_handle, /* TargetHandle */ |
| + (DWORD) 0, /* DesiredAccess */ |
| + inherit, /* InheritHandle */ |
| + DUPLICATE_SAME_ACCESS)) /* Options */ |
| + { |
| + switch (GetLastError ()) |
| + { |
| + case ERROR_TOO_MANY_OPEN_FILES: |
| + errno = EMFILE; |
| + break; |
| + case ERROR_INVALID_HANDLE: |
| + case ERROR_INVALID_TARGET_HANDLE: |
| + case ERROR_DIRECT_ACCESS_HANDLE: |
| + errno = EBADF; |
| + break; |
| + case ERROR_INVALID_PARAMETER: |
| + case ERROR_INVALID_FUNCTION: |
| + case ERROR_INVALID_ACCESS: |
| + errno = EINVAL; |
| + break; |
| + default: |
| + errno = EACCES; |
| + break; |
| + } |
| + result = -1; |
| + break; |
| + } |
| + duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags); |
| + if (duplicated_fd < 0) |
| + { |
| + CloseHandle (new_handle); |
| + result = -1; |
| + break; |
| + } |
| + if (newfd <= duplicated_fd) |
| + { |
| + result = duplicated_fd; |
| + break; |
| + } |
| + |
| + /* Set the bit duplicated_fd in fds_to_close[]. */ |
| + index = (unsigned int) duplicated_fd / CHAR_BIT; |
| + if (fds_to_close_bound <= index) |
| + { |
| + if (sizeof fds_to_close <= index) |
| + /* Need to increase OPEN_MAX_MAX. */ |
| + abort (); |
| + memset (fds_to_close + fds_to_close_bound, '\0', |
| + index + 1 - fds_to_close_bound); |
| + fds_to_close_bound = index + 1; |
| + } |
| + fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT); |
| + } |
| + |
| + /* Close the previous fds that turned out to be too small. */ |
| + { |
| + int saved_errno = errno; |
| + unsigned int duplicated_fd; |
| + |
| + for (duplicated_fd = 0; |
| + duplicated_fd < fds_to_close_bound * CHAR_BIT; |
| + duplicated_fd++) |
| + if ((fds_to_close[duplicated_fd / CHAR_BIT] |
| + >> (duplicated_fd % CHAR_BIT)) |
| + & 1) |
| + close (duplicated_fd); |
| + |
| + errno = saved_errno; |
| + } |
| + return result; |
| +} |
| + |
| +/* Forward declarations, because we '#undef fcntl' in the middle of this |
| + compilation unit. */ |
| +/* Our implementation of fcntl (fd, F_DUPFD, target). */ |
| +static int rpl_fcntl_DUPFD (int fd, int target); |
| +/* Our implementation of fcntl (fd, F_DUPFD_CLOEXEC, target). */ |
| +static int rpl_fcntl_DUPFD_CLOEXEC (int fd, int target); |
| + |
| +/* Perform the specified ACTION on the file descriptor FD, possibly |
| + using the argument ARG further described below. This replacement |
| + handles the following actions, and forwards all others on to the |
| + native fcntl. An unrecognized ACTION returns -1 with errno set to |
| + EINVAL. |
| + |
| + F_DUPFD - duplicate FD, with int ARG being the minimum target fd. |
| + If successful, return the duplicate, which will be inheritable; |
| + otherwise return -1 and set errno. |
| + |
| + F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum |
| + target fd. If successful, return the duplicate, which will not be |
| + inheritable; otherwise return -1 and set errno. |
| + |
| + F_GETFD - ARG need not be present. If successful, return a |
| + non-negative value containing the descriptor flags of FD (only |
| + FD_CLOEXEC is portable, but other flags may be present); otherwise |
| + return -1 and set errno. */ |
| + |
| +int |
| +fcntl (int fd, int action, /* arg */...) |
| +{ |
| + va_list arg; |
| + int result = -1; |
| + va_start (arg, action); |
| + switch (action) |
| + { |
| + case F_DUPFD: |
| + { |
| + int target = va_arg (arg, int); |
| + result = rpl_fcntl_DUPFD (fd, target); |
| + break; |
| + } |
| + |
| + case F_DUPFD_CLOEXEC: |
| + { |
| + int target = va_arg (arg, int); |
| + result = rpl_fcntl_DUPFD_CLOEXEC (fd, target); |
| + break; |
| + } |
| + |
| + case F_GETFD: |
| + { |
| + HANDLE handle = (HANDLE) _get_osfhandle (fd); |
| + DWORD flags; |
| + if (handle == INVALID_HANDLE_VALUE |
| + || GetHandleInformation (handle, &flags) == 0) |
| + errno = EBADF; |
| + else |
| + result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC; |
| + break; |
| + } /* F_GETFD */ |
| + |
| + /* Implementing F_SETFD on mingw is not trivial - there is no |
| + API for changing the O_NOINHERIT bit on an fd, and merely |
| + changing the HANDLE_FLAG_INHERIT bit on the underlying handle |
| + can lead to odd state. It may be possible by duplicating the |
| + handle, using _open_osfhandle with the right flags, then |
| + using dup2 to move the duplicate onto the original, but that |
| + is not supported for now. */ |
| + |
| + default: |
| + { |
| + errno = EINVAL; |
| + break; |
| + } |
| + } |
| + va_end (arg); |
| + return result; |
| +} |
| + |
| +static int |
| +rpl_fcntl_DUPFD (int fd, int target) |
| +{ |
| + int result; |
| + result = dupfd (fd, target, 0); |
| + return result; |
| +} |
| + |
| +static int |
| +rpl_fcntl_DUPFD_CLOEXEC (int fd, int target) |
| +{ |
| + int result; |
| + result = dupfd (fd, target, O_CLOEXEC); |
| + return result; |
| +} |
| + |
| +#endif |
| + |
| +#if !defined(HAVE_FORK) && (defined _WIN32 && ! defined __CYGWIN__) |
| +/* |
| + * fork.c |
| + * Experimental fork() on Windows. Requires NT 6 subsystem or |
| + * newer. |
| + * |
| + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org> |
| + * |
| + * Permission to use, copy, modify, and/or distribute this software for any |
| + * purpose with or without fee is hereby granted, provided that the above |
| + * copyright notice and this permission notice appear in all copies. |
| + * |
| + * This software is provided 'as is' and without any warranty, express or |
| + * implied. In no event shall the authors be liable for any damages arising |
| + * from the use of this software. |
| + */ |
| + |
| +#define WIN32_LEAN_AND_MEAN |
| +#include <windows.h> |
| +#include <winnt.h> |
| +#include <winternl.h> |
| +#include <stdio.h> |
| +#include <errno.h> |
| +#include <process.h> |
| + |
| +typedef struct _SECTION_IMAGE_INFORMATION { |
| + PVOID EntryPoint; |
| + ULONG StackZeroBits; |
| + ULONG StackReserved; |
| + ULONG StackCommit; |
| + ULONG ImageSubsystem; |
| + WORD SubSystemVersionLow; |
| + WORD SubSystemVersionHigh; |
| + ULONG Unknown1; |
| + ULONG ImageCharacteristics; |
| + ULONG ImageMachineType; |
| + ULONG Unknown2[3]; |
| +} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; |
| + |
| +typedef struct _RTL_USER_PROCESS_INFORMATION { |
| + ULONG Size; |
| + HANDLE Process; |
| + HANDLE Thread; |
| + CLIENT_ID ClientId; |
| + SECTION_IMAGE_INFORMATION ImageInformation; |
| +} RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION; |
| + |
| +#define RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED 0x00000001 |
| +#define RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES 0x00000002 |
| +#define RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE 0x00000004 |
| + |
| +#define RTL_CLONE_PARENT 0 |
| +#define RTL_CLONE_CHILD 297 |
| + |
| +typedef NTSTATUS (*RtlCloneUserProcess_f)(ULONG ProcessFlags, |
| + PSECURITY_DESCRIPTOR ProcessSecurityDescriptor /* optional */, |
| + PSECURITY_DESCRIPTOR ThreadSecurityDescriptor /* optional */, |
| + HANDLE DebugPort /* optional */, |
| + PRTL_USER_PROCESS_INFORMATION ProcessInformation); |
| + |
| +pid_t fork(void) |
| +{ |
| + HMODULE mod; |
| + RtlCloneUserProcess_f clone_p; |
| + RTL_USER_PROCESS_INFORMATION process_info; |
| + NTSTATUS result; |
| + |
| + mod = GetModuleHandle("ntdll.dll"); |
| + if (!mod) |
| + return -ENOSYS; |
| + |
| + clone_p = (RtlCloneUserProcess_f)GetProcAddress(mod, "RtlCloneUserProcess"); |
| + if (clone_p == NULL) |
| + return -ENOSYS; |
| + |
| + /* lets do this */ |
| + result = clone_p(RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED | RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES, NULL, NULL, NULL, &process_info); |
| + |
| + if (result == RTL_CLONE_PARENT) |
| + { |
| + HANDLE me, hp, ht, hcp = 0; |
| + DWORD pi, ti, mi; |
| + me = GetCurrentProcess(); |
| + pi = (DWORD)process_info.ClientId.UniqueProcess; |
| + ti = (DWORD)process_info.ClientId.UniqueThread; |
| + |
| + ResumeThread(ht); |
| + CloseHandle(ht); |
| + CloseHandle(hp); |
| + return (pid_t)pi; |
| + } |
| + else if (result == RTL_CLONE_CHILD) |
| + { |
| + /* fix stdio */ |
| + AllocConsole(); |
| + return 0; |
| + } |
| + else |
| + return -1; |
| + |
| + /* NOTREACHED */ |
| + return -1; |
| } |
| @@ -221,2 +697,5 @@ char *sys_siglist[] = { |
| #include <sys/stat.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| #include <dirent.h> |
| @@ -224,2 +703,5 @@ char *sys_siglist[] = { |
| #include <unistd.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/unistd.h" |
| +#endif |
| |
| @@ -367,2 +849,641 @@ getwd(char *pathname) |
| |
| +#if !defined(HAVE_RANDOM) |
| +/* Copyright (C) 1995-2018 Free Software Foundation, Inc. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, see |
| + <http://www.gnu.org/licenses/>. */ |
| + |
| +/* |
| + * This is derived from the Berkeley source: |
| + * @(#)random.c 5.5 (Berkeley) 7/6/88 |
| + * It was reworked for the GNU C Library by Roland McGrath. |
| + * Rewritten to use reentrant functions by Ulrich Drepper, 1995. |
| + */ |
| + |
| +/* |
| + Copyright (C) 1983 Regents of the University of California. |
| + All rights reserved. |
| + |
| + Redistribution and use in source and binary forms, with or without |
| + modification, are permitted provided that the following conditions |
| + are met: |
| + |
| + 1. Redistributions of source code must retain the above copyright |
| + notice, this list of conditions and the following disclaimer. |
| + 2. Redistributions in binary form must reproduce the above copyright |
| + notice, this list of conditions and the following disclaimer in the |
| + documentation and/or other materials provided with the distribution. |
| + 4. Neither the name of the University nor the names of its contributors |
| + may be used to endorse or promote products derived from this software |
| + without specific prior written permission. |
| + |
| + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND |
| + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| + SUCH DAMAGE.*/ |
| + |
| +#ifndef _LIBC |
| +# include "headers-mingw/libc-config.h" |
| +#endif |
| + |
| +/* Specification. */ |
| +#include <stdlib.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/stdlib.h" |
| +#endif |
| + |
| +#include <errno.h> |
| +#include <stddef.h> |
| +#include <string.h> |
| + |
| +#ifdef _LIBC |
| +# include <libc-lock.h> |
| +#else |
| +/* Allow memory races; that's random enough. */ |
| +# define __libc_lock_define_initialized(class, name) |
| +# define __libc_lock_lock(name) ((void) 0) |
| +# define __libc_lock_unlock(name) ((void) 0) |
| +#endif |
| + |
| +/* An improved random number generation package. In addition to the standard |
| + rand()/srand() like interface, this package also has a special state info |
| + interface. The initstate() routine is called with a seed, an array of |
| + bytes, and a count of how many bytes are being passed in; this array is |
| + then initialized to contain information for random number generation with |
| + that much state information. Good sizes for the amount of state |
| + information are 32, 64, 128, and 256 bytes. The state can be switched by |
| + calling the setstate() function with the same array as was initialized |
| + with initstate(). By default, the package runs with 128 bytes of state |
| + information and generates far better random numbers than a linear |
| + congruential generator. If the amount of state information is less than |
| + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the |
| + state information is treated as an array of longs; the zeroth element of |
| + the array is the type of R.N.G. being used (small integer); the remainder |
| + of the array is the state information for the R.N.G. Thus, 32 bytes of |
| + state information will give 7 longs worth of state information, which will |
| + allow a degree seven polynomial. (Note: The zeroth word of state |
| + information also has some other information stored in it; see setstate |
| + for details). The random number generation technique is a linear feedback |
| + shift register approach, employing trinomials (since there are fewer terms |
| + to sum up that way). In this approach, the least significant bit of all |
| + the numbers in the state table will act as a linear feedback shift register, |
| + and will have period 2^deg - 1 (where deg is the degree of the polynomial |
| + being used, assuming that the polynomial is irreducible and primitive). |
| + The higher order bits will have longer periods, since their values are |
| + also influenced by pseudo-random carries out of the lower bits. The |
| + total period of the generator is approximately deg*(2**deg - 1); thus |
| + doubling the amount of state information has a vast influence on the |
| + period of the generator. Note: The deg*(2**deg - 1) is an approximation |
| + only good for large deg, when the period of the shift register is the |
| + dominant factor. With deg equal to seven, the period is actually much |
| + longer than the 7*(2**7 - 1) predicted by this formula. */ |
| + |
| + |
| + |
| +/* For each of the currently supported random number generators, we have a |
| + break value on the amount of state information (you need at least this many |
| + bytes of state info to support this random number generator), a degree for |
| + the polynomial (actually a trinomial) that the R.N.G. is based on, and |
| + separation between the two lower order coefficients of the trinomial. */ |
| + |
| +/* Linear congruential. */ |
| +#define TYPE_0 0 |
| +#define BREAK_0 8 |
| +#define DEG_0 0 |
| +#define SEP_0 0 |
| + |
| +/* x**7 + x**3 + 1. */ |
| +#define TYPE_1 1 |
| +#define BREAK_1 32 |
| +#define DEG_1 7 |
| +#define SEP_1 3 |
| + |
| +/* x**15 + x + 1. */ |
| +#define TYPE_2 2 |
| +#define BREAK_2 64 |
| +#define DEG_2 15 |
| +#define SEP_2 1 |
| + |
| +/* x**31 + x**3 + 1. */ |
| +#define TYPE_3 3 |
| +#define BREAK_3 128 |
| +#define DEG_3 31 |
| +#define SEP_3 3 |
| + |
| +/* x**63 + x + 1. */ |
| +#define TYPE_4 4 |
| +#define BREAK_4 256 |
| +#define DEG_4 63 |
| +#define SEP_4 1 |
| + |
| + |
| +/* Array versions of the above information to make code run faster. |
| + Relies on fact that TYPE_i == i. */ |
| + |
| +#define MAX_TYPES 5 /* Max number of types above. */ |
| + |
| + |
| +/* Initially, everything is set up as if from: |
| + initstate(1, randtbl, 128); |
| + Note that this initialization takes advantage of the fact that srandom |
| + advances the front and rear pointers 10*rand_deg times, and hence the |
| + rear pointer which starts at 0 will also end up at zero; thus the zeroth |
| + element of the state information, which contains info about the current |
| + position of the rear pointer is just |
| + (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ |
| + |
| +static int32_t randtbl[DEG_3 + 1] = |
| + { |
| + TYPE_3, |
| + |
| + -1726662223, 379960547, 1735697613, 1040273694, 1313901226, |
| + 1627687941, -179304937, -2073333483, 1780058412, -1989503057, |
| + -615974602, 344556628, 939512070, -1249116260, 1507946756, |
| + -812545463, 154635395, 1388815473, -1926676823, 525320961, |
| + -1009028674, 968117788, -123449607, 1284210865, 435012392, |
| + -2017506339, -911064859, -370259173, 1132637927, 1398500161, |
| + -205601318, |
| + }; |
| + |
| + |
| +static struct random_data unsafe_state = |
| + { |
| +/* FPTR and RPTR are two pointers into the state info, a front and a rear |
| + pointer. These two pointers are always rand_sep places apart, as they |
| + cycle through the state information. (Yes, this does mean we could get |
| + away with just one pointer, but the code for random is more efficient |
| + this way). The pointers are left positioned as they would be from the call: |
| + initstate(1, randtbl, 128); |
| + (The position of the rear pointer, rptr, is really 0 (as explained above |
| + in the initialization of randtbl) because the state table pointer is set |
| + to point to randtbl[1] (as explained below).) */ |
| + |
| + .fptr = &randtbl[SEP_3 + 1], |
| + .rptr = &randtbl[1], |
| + |
| +/* The following things are the pointer to the state information table, |
| + the type of the current generator, the degree of the current polynomial |
| + being used, and the separation between the two pointers. |
| + Note that for efficiency of random, we remember the first location of |
| + the state information, not the zeroth. Hence it is valid to access |
| + state[-1], which is used to store the type of the R.N.G. |
| + Also, we remember the last location, since this is more efficient than |
| + indexing every time to find the address of the last element to see if |
| + the front and rear pointers have wrapped. */ |
| + |
| + .state = &randtbl[1], |
| + |
| + .rand_type = TYPE_3, |
| + .rand_deg = DEG_3, |
| + .rand_sep = SEP_3, |
| + |
| + .end_ptr = &randtbl[sizeof (randtbl) / sizeof (randtbl[0])] |
| + }; |
| + |
| +/* POSIX.1c requires that there is mutual exclusion for the 'rand' and |
| + 'srand' functions to prevent concurrent calls from modifying common |
| + data. */ |
| +__libc_lock_define_initialized (static, lock) |
| + |
| +/* Initialize the random number generator based on the given seed. If the |
| + type is the trivial no-state-information type, just remember the seed. |
| + Otherwise, initializes state[] based on the given "seed" via a linear |
| + congruential generator. Then, the pointers are set to known locations |
| + that are exactly rand_sep places apart. Lastly, it cycles the state |
| + information a given number of times to get rid of any initial dependencies |
| + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] |
| + for default usage relies on values produced by this routine. */ |
| +void |
| +__srandom (unsigned int x) |
| +{ |
| + __libc_lock_lock (lock); |
| + (void) __srandom_r (x, &unsafe_state); |
| + __libc_lock_unlock (lock); |
| +} |
| + |
| +inline void |
| +srandom (unsigned int x) |
| +{ |
| + return __srandom(x); |
| +} |
| + |
| +inline void |
| +srand (unsigned int x) |
| +{ |
| + return __srandom(x); |
| +} |
| + |
| +/* Initialize the state information in the given array of N bytes for |
| + future random number generation. Based on the number of bytes we |
| + are given, and the break values for the different R.N.G.'s, we choose |
| + the best (largest) one we can and set things up for it. srandom is |
| + then called to initialize the state information. Note that on return |
| + from srandom, we set state[-1] to be the type multiplexed with the current |
| + value of the rear pointer; this is so successive calls to initstate won't |
| + lose this information and will be able to restart with setstate. |
| + Note: The first thing we do is save the current state, if any, just like |
| + setstate so that it doesn't matter when initstate is called. |
| + Returns a pointer to the old state. */ |
| +char * |
| +__initstate (unsigned int seed, char *arg_state, size_t n) |
| +{ |
| + int32_t *ostate; |
| + int ret; |
| + |
| + __libc_lock_lock (lock); |
| + |
| + ostate = &unsafe_state.state[-1]; |
| + |
| + ret = __initstate_r (seed, arg_state, n, &unsafe_state); |
| + |
| + __libc_lock_unlock (lock); |
| + |
| + return ret == -1 ? NULL : (char *) ostate; |
| +} |
| + |
| +inline char * |
| +initstate (unsigned int seed, char *arg_state, size_t n) |
| +{ |
| + return __initstate(seed, arg_state, n); |
| +} |
| + |
| +/* Restore the state from the given state array. |
| + Note: It is important that we also remember the locations of the pointers |
| + in the current state information, and restore the locations of the pointers |
| + from the old state information. This is done by multiplexing the pointer |
| + location into the zeroth word of the state information. Note that due |
| + to the order in which things are done, it is OK to call setstate with the |
| + same state as the current state |
| + Returns a pointer to the old state information. */ |
| +char * |
| +__setstate (char *arg_state) |
| +{ |
| + int32_t *ostate; |
| + |
| + __libc_lock_lock (lock); |
| + |
| + ostate = &unsafe_state.state[-1]; |
| + |
| + if (__setstate_r (arg_state, &unsafe_state) < 0) |
| + ostate = NULL; |
| + |
| + __libc_lock_unlock (lock); |
| + |
| + return (char *) ostate; |
| +} |
| + |
| +inline char * |
| +setstate (char *arg_state) |
| +{ |
| + return __setstate(arg_state); |
| +} |
| + |
| +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear |
| + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the |
| + same in all the other cases due to all the global variables that have been |
| + set up. The basic operation is to add the number at the rear pointer into |
| + the one at the front pointer. Then both pointers are advanced to the next |
| + location cyclically in the table. The value returned is the sum generated, |
| + reduced to 31 bits by throwing away the "least random" low bit. |
| + Note: The code takes advantage of the fact that both the front and |
| + rear pointers can't wrap on the same call by not testing the rear |
| + pointer if the front one has wrapped. Returns a 31-bit random number. */ |
| + |
| +long int |
| +__random (void) |
| +{ |
| + int32_t retval; |
| + |
| + __libc_lock_lock (lock); |
| + |
| + (void) __random_r (&unsafe_state, &retval); |
| + |
| + __libc_lock_unlock (lock); |
| + |
| + return retval; |
| +} |
| +inline long int random(void) |
| +{ |
| + return __random(); |
| +} |
| + |
| +/* Array versions of the above information to make code run faster. |
| + Relies on fact that TYPE_i == i. */ |
| + |
| +struct random_poly_info |
| +{ |
| + int seps[MAX_TYPES]; |
| + int degrees[MAX_TYPES]; |
| +}; |
| + |
| +static const struct random_poly_info random_poly_info = |
| + { |
| + { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }, |
| + { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 } |
| + }; |
| + |
| +static int32_t |
| +get_int32 (void *p) |
| +{ |
| + int32_t v; |
| + memcpy (&v, p, sizeof v); |
| + return v; |
| +} |
| + |
| +static void |
| +set_int32 (void *p, int32_t v) |
| +{ |
| + memcpy (p, &v, sizeof v); |
| +} |
| + |
| + |
| +/* Initialize the random number generator based on the given seed. If the |
| + type is the trivial no-state-information type, just remember the seed. |
| + Otherwise, initializes state[] based on the given "seed" via a linear |
| + congruential generator. Then, the pointers are set to known locations |
| + that are exactly rand_sep places apart. Lastly, it cycles the state |
| + information a given number of times to get rid of any initial dependencies |
| + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] |
| + for default usage relies on values produced by this routine. */ |
| +int |
| +__srandom_r (unsigned int seed, struct random_data *buf) |
| +{ |
| + int type; |
| + int32_t *state; |
| + long int i; |
| + int32_t word; |
| + int32_t *dst; |
| + int kc; |
| + |
| + if (buf == NULL) |
| + goto fail; |
| + type = buf->rand_type; |
| + if ((unsigned int) type >= MAX_TYPES) |
| + goto fail; |
| + |
| + state = buf->state; |
| + /* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */ |
| + if (seed == 0) |
| + seed = 1; |
| + set_int32 (&state[0], seed); |
| + if (type == TYPE_0) |
| + goto done; |
| + |
| + dst = state; |
| + word = seed; |
| + kc = buf->rand_deg; |
| + for (i = 1; i < kc; ++i) |
| + { |
| + /* This does: |
| + state[i] = (16807 * state[i - 1]) % 2147483647; |
| + but avoids overflowing 31 bits. */ |
| + long int hi = word / 127773; |
| + long int lo = word % 127773; |
| + word = 16807 * lo - 2836 * hi; |
| + if (word < 0) |
| + word += 2147483647; |
| + set_int32 (++dst, word); |
| + } |
| + |
| + buf->fptr = &state[buf->rand_sep]; |
| + buf->rptr = &state[0]; |
| + kc *= 10; |
| + while (--kc >= 0) |
| + { |
| + int32_t discard; |
| + (void) __random_r (buf, &discard); |
| + } |
| + |
| + done: |
| + return 0; |
| + |
| + fail: |
| + return -1; |
| +} |
| + |
| +inline int |
| +srandom_r (unsigned int seed, struct random_data *buf) |
| +{ |
| + return __srandom_r(seed, buf); |
| +} |
| + |
| +/* Initialize the state information in the given array of N bytes for |
| + future random number generation. Based on the number of bytes we |
| + are given, and the break values for the different R.N.G.'s, we choose |
| + the best (largest) one we can and set things up for it. srandom is |
| + then called to initialize the state information. Note that on return |
| + from srandom, we set state[-1] to be the type multiplexed with the current |
| + value of the rear pointer; this is so successive calls to initstate won't |
| + lose this information and will be able to restart with setstate. |
| + Note: The first thing we do is save the current state, if any, just like |
| + setstate so that it doesn't matter when initstate is called. |
| + Returns 0 on success, non-zero on failure. */ |
| +int |
| +__initstate_r (unsigned int seed, char *arg_state, size_t n, |
| + struct random_data *buf) |
| +{ |
| + if (buf == NULL) |
| + goto fail; |
| + |
| + int32_t *old_state = buf->state; |
| + if (old_state != NULL) |
| + { |
| + int old_type = buf->rand_type; |
| + set_int32 (&old_state[-1], |
| + (old_type == TYPE_0 |
| + ? TYPE_0 |
| + : (MAX_TYPES * (buf->rptr - old_state)) + old_type)); |
| + } |
| + |
| + int type; |
| + if (n >= BREAK_3) |
| + type = n < BREAK_4 ? TYPE_3 : TYPE_4; |
| + else if (n < BREAK_1) |
| + { |
| + if (n < BREAK_0) |
| + goto fail; |
| + |
| + type = TYPE_0; |
| + } |
| + else |
| + type = n < BREAK_2 ? TYPE_1 : TYPE_2; |
| + |
| + int degree = random_poly_info.degrees[type]; |
| + int separation = random_poly_info.seps[type]; |
| + |
| + buf->rand_type = type; |
| + buf->rand_sep = separation; |
| + buf->rand_deg = degree; |
| + int32_t *state = &((int32_t *) arg_state)[1]; /* First location. */ |
| + /* Must set END_PTR before srandom. */ |
| + buf->end_ptr = &state[degree]; |
| + |
| + buf->state = state; |
| + |
| + __srandom_r (seed, buf); |
| + |
| + set_int32 (&state[-1], |
| + type == TYPE_0 ? TYPE_0 : (buf->rptr - state) * MAX_TYPES + type); |
| + |
| + return 0; |
| + |
| + fail: |
| + __set_errno (EINVAL); |
| + return -1; |
| +} |
| + |
| +inline int |
| +initstate_r (unsigned int seed, char *arg_state, size_t n, |
| + struct random_data *buf) |
| +{ |
| + return __initstate_r(seed, arg_state, n, buf); |
| +} |
| + |
| +/* Restore the state from the given state array. |
| + Note: It is important that we also remember the locations of the pointers |
| + in the current state information, and restore the locations of the pointers |
| + from the old state information. This is done by multiplexing the pointer |
| + location into the zeroth word of the state information. Note that due |
| + to the order in which things are done, it is OK to call setstate with the |
| + same state as the current state |
| + Returns 0 on success, non-zero on failure. */ |
| +int |
| +__setstate_r (char *arg_state, struct random_data *buf) |
| +{ |
| + int32_t *new_state = 1 + (int32_t *) arg_state; |
| + int type; |
| + int old_type; |
| + int32_t *old_state; |
| + int degree; |
| + int separation; |
| + |
| + if (arg_state == NULL || buf == NULL) |
| + goto fail; |
| + |
| + old_type = buf->rand_type; |
| + old_state = buf->state; |
| + set_int32 (&old_state[-1], |
| + (old_type == TYPE_0 |
| + ? TYPE_0 |
| + : (MAX_TYPES * (buf->rptr - old_state)) + old_type)); |
| + |
| + type = get_int32 (&new_state[-1]) % MAX_TYPES; |
| + if (type < TYPE_0 || type > TYPE_4) |
| + goto fail; |
| + |
| + buf->rand_deg = degree = random_poly_info.degrees[type]; |
| + buf->rand_sep = separation = random_poly_info.seps[type]; |
| + buf->rand_type = type; |
| + |
| + if (type != TYPE_0) |
| + { |
| + int rear = get_int32 (&new_state[-1]) / MAX_TYPES; |
| + buf->rptr = &new_state[rear]; |
| + buf->fptr = &new_state[(rear + separation) % degree]; |
| + } |
| + buf->state = new_state; |
| + /* Set end_ptr too. */ |
| + buf->end_ptr = &new_state[degree]; |
| + |
| + return 0; |
| + |
| + fail: |
| + __set_errno (EINVAL); |
| + return -1; |
| +} |
| + |
| +inline int setstate_r (char *arg_state, struct random_data *buf) |
| +{ |
| + return __setstate_r(arg_state, buf); |
| +} |
| + |
| +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear |
| + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the |
| + same in all the other cases due to all the global variables that have been |
| + set up. The basic operation is to add the number at the rear pointer into |
| + the one at the front pointer. Then both pointers are advanced to the next |
| + location cyclically in the table. The value returned is the sum generated, |
| + reduced to 31 bits by throwing away the "least random" low bit. |
| + Note: The code takes advantage of the fact that both the front and |
| + rear pointers can't wrap on the same call by not testing the rear |
| + pointer if the front one has wrapped. Returns a 31-bit random number. */ |
| + |
| +int |
| +__random_r (struct random_data *buf, int32_t *result) |
| +{ |
| + int32_t *state; |
| + |
| + if (buf == NULL || result == NULL) |
| + goto fail; |
| + |
| + state = buf->state; |
| + |
| + if (buf->rand_type == TYPE_0) |
| + { |
| + int32_t val = (((get_int32 (&state[0]) * 1103515245U) + 12345U) |
| + & 0x7fffffff); |
| + set_int32 (&state[0], val); |
| + *result = val; |
| + } |
| + else |
| + { |
| + int32_t *fptr = buf->fptr; |
| + int32_t *rptr = buf->rptr; |
| + int32_t *end_ptr = buf->end_ptr; |
| + /* F and R are unsigned int, not uint32_t, to avoid undefined |
| + overflow behavior on platforms where INT_MAX == UINT32_MAX. */ |
| + unsigned int f = get_int32 (fptr); |
| + unsigned int r = get_int32 (rptr); |
| + uint32_t val = f + r; |
| + set_int32 (fptr, val); |
| + /* Chucking least random bit. */ |
| + *result = val >> 1; |
| + ++fptr; |
| + if (fptr >= end_ptr) |
| + { |
| + fptr = state; |
| + ++rptr; |
| + } |
| + else |
| + { |
| + ++rptr; |
| + if (rptr >= end_ptr) |
| + rptr = state; |
| + } |
| + buf->fptr = fptr; |
| + buf->rptr = rptr; |
| + } |
| + return 0; |
| + |
| + fail: |
| + __set_errno (EINVAL); |
| + return -1; |
| +} |
| + |
| +inline int |
| +random_r (struct random_data *buf, int32_t *result) |
| +{ |
| + return __random_r(buf, result); |
| +} |
| + |
| +#endif |
| + |
| #if !defined(HAVE_GETCWD) |
| @@ -526,2 +1647,19 @@ strftime(char *buf, size_t len, const char *fmt, const struct tm *tm) |
| |
| +#if !defined(HAVE_STRERROR) |
| +extern int errno, sys_nerr; |
| +extern char *sys_errlist[]; |
| + |
| +char * |
| +strerror(int e) |
| +{ |
| + static char buf[100]; |
| + if (e < 0 || e >= sys_nerr) { |
| + snprintf(buf, sizeof(buf), "Unknown error %d", e); |
| + return buf; |
| + } |
| + else |
| + return sys_errlist[e]; |
| +} |
| +#endif |
| + |
| #if !defined(HAVE_KILLPG) |
| @@ -599,11 +1737,11 @@ errx(int eval, const char *fmt, ...) |
| |
| -#if !defined(HAVE_WARN) |
| -void |
| -warn(const char *fmt, ...) |
| -{ |
| - va_list ap; |
| +#if !defined(HAVE_KILL) && (defined _WIN32 && ! defined __CYGWIN__) |
| +# define WIN32_LEAN_AND_MEAN |
| +# include <windows.h> |
| |
| - va_start(ap, fmt); |
| - vwarn(fmt, ap); |
| - va_end(ap); |
| +/* The return value of spawnvp() is really a process handle as returned |
| + by CreateProcess(). Therefore we can kill it using TerminateProcess. */ |
| +int kill(pid_t pid, int sig) |
| +{ |
| + return TerminateProcess ((HANDLE) (pid), sig); |
| } |
| @@ -611,9 +1749,1208 @@ warn(const char *fmt, ...) |
| |
| -#if !defined(HAVE_WARNX) |
| -void |
| -warnx(const char *fmt, ...) |
| -{ |
| - va_list ap; |
| +#if (defined _WIN32 && ! defined __CYGWIN__) //poll function |
| +/* Emulation for poll(2) |
| + Contributed by Paolo Bonzini. |
| |
| - va_start(ap, fmt); |
| + Copyright 2001-2003, 2006-2018 Free Software Foundation, Inc. |
| + |
| + This file is part of gnulib. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License along |
| + with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Tell gcc not to warn about the (nfd < 0) tests, below. */ |
| +#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__ |
| +# pragma GCC diagnostic ignored "-Wtype-limits" |
| +#endif |
| + |
| +//#include <alloca.h> |
| + |
| +#include <sys/types.h> |
| + |
| +/* Specification. */ |
| +#include "headers-mingw/poll.h" |
| + |
| +#include <errno.h> |
| +#include <limits.h> |
| + |
| +#include <winsock2.h> |
| +#include <windows.h> |
| +#include <io.h> |
| +#include <stdio.h> |
| +#include <conio.h> |
| +#if GNULIB_MSVC_NOTHROW |
| +# include "msvc-nothrow.h" |
| +#else |
| +# include <io.h> |
| +#endif |
| + |
| +//#include <sys/select.h> |
| +//#include <sys/socket.h> |
| + |
| +#ifdef HAVE_SYS_IOCTL_H |
| +# include <sys/ioctl.h> |
| +#endif |
| +#ifdef HAVE_SYS_FILIO_H |
| +# include <sys/filio.h> |
| +#endif |
| + |
| +#include <time.h> |
| + |
| +//#include "assure.h" |
| + |
| +#ifndef INFTIM |
| +# define INFTIM (-1) |
| +#endif |
| + |
| +/* BeOS does not have MSG_PEEK. */ |
| +#ifndef MSG_PEEK |
| +# define MSG_PEEK 0 |
| +#endif |
| + |
| +/* Avoid warnings from gcc -Wcast-function-type. */ |
| +# define GetProcAddress \ |
| + (void *) GetProcAddress |
| + |
| +static BOOL IsConsoleHandle (HANDLE h) |
| +{ |
| + DWORD mode; |
| + return GetConsoleMode (h, &mode) != 0; |
| +} |
| + |
| +static BOOL |
| +IsSocketHandle (HANDLE h) |
| +{ |
| + WSANETWORKEVENTS ev; |
| + |
| + if (IsConsoleHandle (h)) |
| + return FALSE; |
| + |
| + /* Under Wine, it seems that getsockopt returns 0 for pipes too. |
| + WSAEnumNetworkEvents instead distinguishes the two correctly. */ |
| + ev.lNetworkEvents = 0xDEADBEEF; |
| + WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); |
| + return ev.lNetworkEvents != 0xDEADBEEF; |
| +} |
| + |
| +typedef DWORD (WINAPI *PNtQueryInformationFile) |
| + (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS); |
| + |
| +# ifndef PIPE_BUF |
| +# define PIPE_BUF 512 |
| +# endif |
| + |
| +/* Compute revents values for file handle H. If some events cannot happen |
| + for the handle, eliminate them from *P_SOUGHT. */ |
| + |
| +static int |
| +windows_compute_revents (HANDLE h, int *p_sought) |
| +{ |
| + int i, ret, happened; |
| + INPUT_RECORD *irbuffer; |
| + DWORD avail, nbuffer; |
| + BOOL bRet; |
| + IO_STATUS_BLOCK iosb; |
| + FILE_PIPE_LOCAL_INFORMATION fpli; |
| + static PNtQueryInformationFile NtQueryInformationFile; |
| + static BOOL once_only; |
| + |
| + switch (GetFileType (h)) |
| + { |
| + case FILE_TYPE_PIPE: |
| + if (!once_only) |
| + { |
| + NtQueryInformationFile = (PNtQueryInformationFile) |
| + GetProcAddress (GetModuleHandle ("ntdll.dll"), |
| + "NtQueryInformationFile"); |
| + once_only = TRUE; |
| + } |
| + |
| + happened = 0; |
| + if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0) |
| + { |
| + if (avail) |
| + happened |= *p_sought & (POLLIN | POLLRDNORM); |
| + } |
| + else if (GetLastError () == ERROR_BROKEN_PIPE) |
| + happened |= POLLHUP; |
| + |
| + else |
| + { |
| + /* It was the write-end of the pipe. Check if it is writable. |
| + If NtQueryInformationFile fails, optimistically assume the pipe is |
| + writable. This could happen on Windows 9x, where |
| + NtQueryInformationFile is not available, or if we inherit a pipe |
| + that doesn't permit FILE_READ_ATTRIBUTES access on the write end |
| + (I think this should not happen since Windows XP SP2; WINE seems |
| + fine too). Otherwise, ensure that enough space is available for |
| + atomic writes. */ |
| + memset (&iosb, 0, sizeof (iosb)); |
| + memset (&fpli, 0, sizeof (fpli)); |
| + |
| + if (!NtQueryInformationFile |
| + || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli), |
| + FilePipeLocalInformation) |
| + || fpli.WriteQuotaAvailable >= PIPE_BUF |
| + || (fpli.OutboundQuota < PIPE_BUF && |
| + fpli.WriteQuotaAvailable == fpli.OutboundQuota)) |
| + happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND); |
| + } |
| + return happened; |
| + |
| + case FILE_TYPE_CHAR: |
| + ret = WaitForSingleObject (h, 0); |
| + if (!IsConsoleHandle (h)) |
| + return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0; |
| + |
| + nbuffer = avail = 0; |
| + bRet = GetNumberOfConsoleInputEvents (h, &nbuffer); |
| + if (bRet) |
| + { |
| + /* Input buffer. */ |
| + *p_sought &= POLLIN | POLLRDNORM; |
| + if (nbuffer == 0) |
| + return POLLHUP; |
| + if (!*p_sought) |
| + return 0; |
| + |
| + irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD)); |
| + bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail); |
| + if (!bRet || avail == 0) |
| + return POLLHUP; |
| + |
| + for (i = 0; i < avail; i++) |
| + if (irbuffer[i].EventType == KEY_EVENT) |
| + return *p_sought; |
| + return 0; |
| + } |
| + else |
| + { |
| + /* Screen buffer. */ |
| + *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND; |
| + return *p_sought; |
| + } |
| + |
| + default: |
| + ret = WaitForSingleObject (h, 0); |
| + if (ret == WAIT_OBJECT_0) |
| + return *p_sought & ~(POLLPRI | POLLRDBAND); |
| + |
| + return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND); |
| + } |
| +} |
| + |
| +/* Convert fd_sets returned by select into revents values. */ |
| + |
| +static int |
| +windows_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents) |
| +{ |
| + int happened = 0; |
| + |
| + if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT) |
| + happened |= (POLLIN | POLLRDNORM) & sought; |
| + |
| + else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) |
| + { |
| + int r, error; |
| + |
| + char data[64]; |
| + WSASetLastError (0); |
| + r = recv (h, data, sizeof (data), MSG_PEEK); |
| + error = WSAGetLastError (); |
| + WSASetLastError (0); |
| + |
| + if (r > 0 || error == WSAENOTCONN) |
| + happened |= (POLLIN | POLLRDNORM) & sought; |
| + |
| + /* Distinguish hung-up sockets from other errors. */ |
| + else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET |
| + || error == WSAECONNABORTED || error == WSAENETRESET) |
| + happened |= POLLHUP; |
| + |
| + else |
| + happened |= POLLERR; |
| + } |
| + |
| + if (lNetworkEvents & (FD_WRITE | FD_CONNECT)) |
| + happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought; |
| + |
| + if (lNetworkEvents & FD_OOB) |
| + happened |= (POLLPRI | POLLRDBAND) & sought; |
| + |
| + return happened; |
| +} |
| + |
| +int |
| +poll (struct pollfd *pfd, nfds_t nfd, int timeout) |
| +{ |
| + static struct timeval tv0; |
| + static HANDLE hEvent; |
| + WSANETWORKEVENTS ev; |
| + HANDLE h, handle_array[FD_SETSIZE + 2]; |
| + DWORD ret, wait_timeout, nhandles; |
| + fd_set rfds, wfds, xfds; |
| + BOOL poll_again; |
| + MSG msg; |
| + int rc = 0; |
| + nfds_t i; |
| + |
| + if (nfd > INT_MAX || timeout < -1) |
| + { |
| + errno = EINVAL; |
| + return -1; |
| + } |
| + |
| + if (!hEvent) |
| + hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); |
| + |
| +restart: |
| + handle_array[0] = hEvent; |
| + nhandles = 1; |
| + FD_ZERO (&rfds); |
| + FD_ZERO (&wfds); |
| + FD_ZERO (&xfds); |
| + |
| + /* Classify socket handles and create fd sets. */ |
| + for (i = 0; i < nfd; i++) |
| + { |
| + int sought = pfd[i].events; |
| + pfd[i].revents = 0; |
| + if (pfd[i].fd < 0) |
| + continue; |
| + if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND |
| + | POLLPRI | POLLRDBAND))) |
| + continue; |
| + |
| + h = (HANDLE) _get_osfhandle (pfd[i].fd); |
| + if (IsSocketHandle (h)) |
| + { |
| + int requested = FD_CLOSE; |
| + |
| + /* see above; socket handles are mapped onto select. */ |
| + if (sought & (POLLIN | POLLRDNORM)) |
| + { |
| + requested |= FD_READ | FD_ACCEPT; |
| + FD_SET ((SOCKET) h, &rfds); |
| + } |
| + if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND)) |
| + { |
| + requested |= FD_WRITE | FD_CONNECT; |
| + FD_SET ((SOCKET) h, &wfds); |
| + } |
| + if (sought & (POLLPRI | POLLRDBAND)) |
| + { |
| + requested |= FD_OOB; |
| + FD_SET ((SOCKET) h, &xfds); |
| + } |
| + |
| + if (requested) |
| + WSAEventSelect ((SOCKET) h, hEvent, requested); |
| + } |
| + else |
| + { |
| + /* Poll now. If we get an event, do not poll again. Also, |
| + screen buffer handles are waitable, and they'll block until |
| + a character is available. windows_compute_revents eliminates |
| + bits for the "wrong" direction. */ |
| + pfd[i].revents = windows_compute_revents (h, &sought); |
| + if (sought) |
| + handle_array[nhandles++] = h; |
| + if (pfd[i].revents) |
| + timeout = 0; |
| + } |
| + } |
| + |
| + if (select (0, &rfds, &wfds, &xfds, &tv0) > 0) |
| + { |
| + /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but |
| + no need to call select again. */ |
| + poll_again = FALSE; |
| + wait_timeout = 0; |
| + } |
| + else |
| + { |
| + poll_again = TRUE; |
| + if (timeout == INFTIM) |
| + wait_timeout = INFINITE; |
| + else |
| + wait_timeout = timeout; |
| + } |
| + |
| + for (;;) |
| + { |
| + ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE, |
| + wait_timeout, QS_ALLINPUT); |
| + |
| + if (ret == WAIT_OBJECT_0 + nhandles) |
| + { |
| + /* new input of some other kind */ |
| + BOOL bRet; |
| + while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0) |
| + { |
| + TranslateMessage (&msg); |
| + DispatchMessage (&msg); |
| + } |
| + } |
| + else |
| + break; |
| + } |
| + |
| + if (poll_again) |
| + select (0, &rfds, &wfds, &xfds, &tv0); |
| + |
| + /* Place a sentinel at the end of the array. */ |
| + handle_array[nhandles] = NULL; |
| + nhandles = 1; |
| + for (i = 0; i < nfd; i++) |
| + { |
| + int happened; |
| + |
| + if (pfd[i].fd < 0) |
| + continue; |
| + if (!(pfd[i].events & (POLLIN | POLLRDNORM | |
| + POLLOUT | POLLWRNORM | POLLWRBAND))) |
| + continue; |
| + |
| + h = (HANDLE) _get_osfhandle (pfd[i].fd); |
| + if (h != handle_array[nhandles]) |
| + { |
| + /* It's a socket. */ |
| + WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); |
| + WSAEventSelect ((SOCKET) h, 0, 0); |
| + |
| + /* If we're lucky, WSAEnumNetworkEvents already provided a way |
| + to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */ |
| + if (FD_ISSET ((SOCKET) h, &rfds) |
| + && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT))) |
| + ev.lNetworkEvents |= FD_READ | FD_ACCEPT; |
| + if (FD_ISSET ((SOCKET) h, &wfds)) |
| + ev.lNetworkEvents |= FD_WRITE | FD_CONNECT; |
| + if (FD_ISSET ((SOCKET) h, &xfds)) |
| + ev.lNetworkEvents |= FD_OOB; |
| + |
| + happened = windows_compute_revents_socket ((SOCKET) h, pfd[i].events, |
| + ev.lNetworkEvents); |
| + } |
| + else |
| + { |
| + /* Not a socket. */ |
| + int sought = pfd[i].events; |
| + happened = windows_compute_revents (h, &sought); |
| + nhandles++; |
| + } |
| + |
| + if ((pfd[i].revents |= happened) != 0) |
| + rc++; |
| + } |
| + |
| + if (!rc && timeout == INFTIM) |
| + { |
| + SleepEx (1, TRUE); |
| + goto restart; |
| + } |
| + |
| + return rc; |
| +} |
| + |
| +#endif //(defined _WIN32 && ! defined __CYGWIN__) (poll function) |
| + |
| +#if !defined(HAVE_SIGEMPTYSET) || !defined(HAVE_SIGISMEMBER) || !defined(HAVE_SIGPROCMASK) || !defined(HAVE_SIGACTION) |
| +/* POSIX compatible signal blocking. |
| + Copyright (C) 2006-2018 Free Software Foundation, Inc. |
| + Written by Bruno Haible <bruno@clisp.org>, 2006. |
| + |
| + This program is free software: you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 3 of the License, or |
| + (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Specification. */ |
| +#include <signal.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/signal.h" |
| +#endif |
| + |
| +#include <errno.h> |
| +#include <stdint.h> |
| +#include <stdlib.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/stdlib.h" |
| +#endif |
| + |
| +#if HAVE_MSVC_INVALID_PARAMETER_HANDLER |
| +# include "msvc-inval.h" |
| +#endif |
| + |
| +/* We assume that a platform without POSIX signal blocking functions |
| + also does not have the POSIX sigaction() function, only the |
| + signal() function. We also assume signal() has SysV semantics, |
| + where any handler is uninstalled prior to being invoked. This is |
| + true for native Windows platforms. */ |
| + |
| +/* We use raw signal(), but also provide a wrapper rpl_signal() so |
| + that applications can query or change a blocked signal. */ |
| +#undef signal |
| + |
| +/* Provide invalid signal numbers as fallbacks if the uncatchable |
| + signals are not defined. */ |
| +#ifndef SIGKILL |
| +# define SIGKILL (-1) |
| +#endif |
| +#ifndef SIGSTOP |
| +# define SIGSTOP (-1) |
| +#endif |
| + |
| +/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias |
| + for the signal SIGABRT. Only one signal handler is stored for both |
| + SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */ |
| +#if defined _WIN32 && ! defined __CYGWIN__ |
| +# undef SIGABRT_COMPAT |
| +# define SIGABRT_COMPAT 6 |
| +#endif |
| +#ifdef SIGABRT_COMPAT |
| +# define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT) |
| +#else |
| +# define SIGABRT_COMPAT_MASK 0 |
| +#endif |
| + |
| +typedef void (*handler_t) (int); |
| + |
| +#if HAVE_MSVC_INVALID_PARAMETER_HANDLER |
| +static handler_t |
| +signal_nothrow (int sig, handler_t handler) |
| +{ |
| + handler_t result; |
| + |
| + TRY_MSVC_INVAL |
| + { |
| + result = signal (sig, handler); |
| + } |
| + CATCH_MSVC_INVAL |
| + { |
| + result = SIG_ERR; |
| + errno = EINVAL; |
| + } |
| + DONE_MSVC_INVAL; |
| + |
| + return result; |
| +} |
| +# define signal signal_nothrow |
| +#endif |
| + |
| +/* Handling of gnulib defined signals. */ |
| + |
| +#if GNULIB_defined_SIGPIPE |
| +static handler_t SIGPIPE_handler = SIG_DFL; |
| +#endif |
| + |
| +#if GNULIB_defined_SIGPIPE |
| +static handler_t |
| +ext_signal (int sig, handler_t handler) |
| +{ |
| + switch (sig) |
| + { |
| + case SIGPIPE: |
| + { |
| + handler_t old_handler = SIGPIPE_handler; |
| + SIGPIPE_handler = handler; |
| + return old_handler; |
| + } |
| + default: /* System defined signal */ |
| + return signal (sig, handler); |
| + } |
| +} |
| +# undef signal |
| +# define signal ext_signal |
| +#endif |
| + |
| +int |
| +sigismember (const sigset_t *set, int sig) |
| +{ |
| + if (sig >= 0 && sig < NSIG) |
| + { |
| +#ifdef SIGABRT_COMPAT |
| + if (sig == SIGABRT_COMPAT) |
| + sig = SIGABRT; |
| +#endif |
| + |
| + return (*set >> sig) & 1; |
| + } |
| + else |
| + return 0; |
| +} |
| + |
| +int |
| +sigemptyset (sigset_t *set) |
| +{ |
| + *set = 0; |
| + return 0; |
| +} |
| + |
| +int |
| +sigaddset (sigset_t *set, int sig) |
| +{ |
| + if (sig >= 0 && sig < NSIG) |
| + { |
| +#ifdef SIGABRT_COMPAT |
| + if (sig == SIGABRT_COMPAT) |
| + sig = SIGABRT; |
| +#endif |
| + |
| + *set |= 1U << sig; |
| + return 0; |
| + } |
| + else |
| + { |
| + errno = EINVAL; |
| + return -1; |
| + } |
| +} |
| + |
| +int |
| +sigdelset (sigset_t *set, int sig) |
| +{ |
| + if (sig >= 0 && sig < NSIG) |
| + { |
| +#ifdef SIGABRT_COMPAT |
| + if (sig == SIGABRT_COMPAT) |
| + sig = SIGABRT; |
| +#endif |
| + |
| + *set &= ~(1U << sig); |
| + return 0; |
| + } |
| + else |
| + { |
| + errno = EINVAL; |
| + return -1; |
| + } |
| +} |
| + |
| + |
| +int |
| +sigfillset (sigset_t *set) |
| +{ |
| + *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK; |
| + return 0; |
| +} |
| + |
| +/* Set of currently blocked signals. */ |
| +static volatile sigset_t blocked_set /* = 0 */; |
| + |
| +/* Set of currently blocked and pending signals. */ |
| +static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */; |
| + |
| +/* Signal handler that is installed for blocked signals. */ |
| +static void |
| +blocked_handler (int sig) |
| +{ |
| + /* Reinstall the handler, in case the signal occurs multiple times |
| + while blocked. There is an inherent race where an asynchronous |
| + signal in between when the kernel uninstalled the handler and |
| + when we reinstall it will trigger the default handler; oh |
| + well. */ |
| + signal (sig, blocked_handler); |
| + if (sig >= 0 && sig < NSIG) |
| + pending_array[sig] = 1; |
| +} |
| + |
| +int |
| +sigpending (sigset_t *set) |
| +{ |
| + sigset_t pending = 0; |
| + int sig; |
| + |
| + for (sig = 0; sig < NSIG; sig++) |
| + if (pending_array[sig]) |
| + pending |= 1U << sig; |
| + *set = pending; |
| + return 0; |
| +} |
| + |
| +/* The previous signal handlers. |
| + Only the array elements corresponding to blocked signals are relevant. */ |
| +static volatile handler_t old_handlers[NSIG]; |
| + |
| +int |
| +sigprocmask (int operation, const sigset_t *set, sigset_t *old_set) |
| +{ |
| + if (old_set != NULL) |
| + *old_set = blocked_set; |
| + |
| + if (set != NULL) |
| + { |
| + sigset_t new_blocked_set; |
| + sigset_t to_unblock; |
| + sigset_t to_block; |
| + |
| + switch (operation) |
| + { |
| + case SIG_BLOCK: |
| + new_blocked_set = blocked_set | *set; |
| + break; |
| + case SIG_SETMASK: |
| + new_blocked_set = *set; |
| + break; |
| + case SIG_UNBLOCK: |
| + new_blocked_set = blocked_set & ~*set; |
| + break; |
| + default: |
| + errno = EINVAL; |
| + return -1; |
| + } |
| + to_unblock = blocked_set & ~new_blocked_set; |
| + to_block = new_blocked_set & ~blocked_set; |
| + |
| + if (to_block != 0) |
| + { |
| + int sig; |
| + |
| + for (sig = 0; sig < NSIG; sig++) |
| + if ((to_block >> sig) & 1) |
| + { |
| + pending_array[sig] = 0; |
| + if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR) |
| + blocked_set |= 1U << sig; |
| + } |
| + } |
| + |
| + if (to_unblock != 0) |
| + { |
| + sig_atomic_t received[NSIG]; |
| + int sig; |
| + |
| + for (sig = 0; sig < NSIG; sig++) |
| + if ((to_unblock >> sig) & 1) |
| + { |
| +// if (signal (sig, old_handlers[sig]) != blocked_handler) |
| +// /* The application changed a signal handler while the signal |
| +// was blocked, bypassing our rpl_signal replacement. |
| +// We don't support this. */ |
| +// abort (); |
| + received[sig] = pending_array[sig]; |
| + blocked_set &= ~(1U << sig); |
| + pending_array[sig] = 0; |
| + } |
| + else |
| + received[sig] = 0; |
| + |
| + for (sig = 0; sig < NSIG; sig++) |
| + if (received[sig]) |
| + raise (sig); |
| + } |
| + } |
| + return 0; |
| +} |
| + |
| +/* Install the handler FUNC for signal SIG, and return the previous |
| + handler. */ |
| +handler_t |
| +rpl_signal (int sig, handler_t handler) |
| +{ |
| + /* We must provide a wrapper, so that a user can query what handler |
| + they installed even if that signal is currently blocked. */ |
| + if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP |
| + && handler != SIG_ERR) |
| + { |
| +#ifdef SIGABRT_COMPAT |
| + if (sig == SIGABRT_COMPAT) |
| + sig = SIGABRT; |
| +#endif |
| + |
| + if (blocked_set & (1U << sig)) |
| + { |
| + /* POSIX states that sigprocmask and signal are both |
| + async-signal-safe. This is not true of our |
| + implementation - there is a slight data race where an |
| + asynchronous interrupt on signal A can occur after we |
| + install blocked_handler but before we have updated |
| + old_handlers for signal B, such that handler A can see |
| + stale information if it calls signal(B). Oh well - |
| + signal handlers really shouldn't try to manipulate the |
| + installed handlers of unrelated signals. */ |
| + handler_t result = old_handlers[sig]; |
| + old_handlers[sig] = handler; |
| + return result; |
| + } |
| + else |
| + return signal (sig, handler); |
| + } |
| + else |
| + { |
| + errno = EINVAL; |
| + return SIG_ERR; |
| + } |
| +} |
| + |
| +/* This implementation of sigaction is tailored to native Windows behavior: |
| + signal() has SysV semantics (ie. the handler is uninstalled before |
| + it is invoked). This is an inherent data race if an asynchronous |
| + signal is sent twice in a row before we can reinstall our handler, |
| + but there's nothing we can do about it. Meanwhile, sigprocmask() |
| + is not present, and while we can use the gnulib replacement to |
| + provide critical sections, it too suffers from potential data races |
| + in the face of an ill-timed asynchronous signal. And we compound |
| + the situation by reading static storage in a signal handler, which |
| + POSIX warns is not generically async-signal-safe. Oh well. |
| + |
| + Additionally: |
| + - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD |
| + is not defined. |
| + - We don't implement SA_ONSTACK, because sigaltstack() is not present. |
| + - We ignore SA_RESTART, because blocking native Windows API calls are |
| + not interrupted anyway when an asynchronous signal occurs, and the |
| + MSVCRT runtime never sets errno to EINTR. |
| + - We don't implement SA_SIGINFO because it is impossible to do so |
| + portably. |
| + |
| + POSIX states that an application should not mix signal() and |
| + sigaction(). We support the use of signal() within the gnulib |
| + sigprocmask() substitute, but all other application code linked |
| + with this module should stick with only sigaction(). */ |
| + |
| +/* Set of current actions. If sa_handler for an entry is NULL, then |
| + that signal is not currently handled by the sigaction handler. */ |
| +static struct sigaction volatile action_array[NSIG] /* = 0 */; |
| + |
| +/* Signal handler that is installed for signals. */ |
| +static void |
| +sigaction_handler (int sig) |
| +{ |
| + handler_t handler; |
| + sigset_t mask; |
| + sigset_t oldmask; |
| + int saved_errno = errno; |
| + if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler) |
| + { |
| + /* Unexpected situation; be careful to avoid recursive abort. */ |
| + if (sig == SIGABRT) |
| + signal (SIGABRT, SIG_DFL); |
| + abort (); |
| + } |
| + |
| + /* Reinstall the signal handler when required; otherwise update the |
| + bookkeeping so that the user's handler may call sigaction and get |
| + accurate results. We know the signal isn't currently blocked, or |
| + we wouldn't be in its handler, therefore we know that we are not |
| + interrupting a sigaction() call. There is a race where any |
| + asynchronous instance of the same signal occurring before we |
| + reinstall the handler will trigger the default handler; oh |
| + well. */ |
| + handler = action_array[sig].sa_handler; |
| + if ((action_array[sig].sa_flags & SA_RESETHAND) == 0) |
| + signal (sig, sigaction_handler); |
| + else |
| + action_array[sig].sa_handler = NULL; |
| + |
| + /* Block appropriate signals. */ |
| + mask = action_array[sig].sa_mask; |
| + if ((action_array[sig].sa_flags & SA_NODEFER) == 0) |
| + sigaddset (&mask, sig); |
| + sigprocmask (SIG_BLOCK, &mask, &oldmask); |
| + |
| + /* Invoke the user's handler, then restore prior mask. */ |
| + errno = saved_errno; |
| + handler (sig); |
| + saved_errno = errno; |
| + sigprocmask (SIG_SETMASK, &oldmask, NULL); |
| + errno = saved_errno; |
| +} |
| + |
| +/* Change and/or query the action that will be taken on delivery of |
| + signal SIG. If not NULL, ACT describes the new behavior. If not |
| + NULL, OACT is set to the prior behavior. Return 0 on success, or |
| + set errno and return -1 on failure. */ |
| +int |
| +sigaction (int sig, const struct sigaction *restrict act, |
| + struct sigaction *restrict oact) |
| +{ |
| + sigset_t mask; |
| + sigset_t oldmask; |
| + int saved_errno; |
| + |
| + if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP |
| + || (act && act->sa_handler == SIG_ERR)) |
| + { |
| + errno = EINVAL; |
| + return -1; |
| + } |
| + |
| +#ifdef SIGABRT_COMPAT |
| + if (sig == SIGABRT_COMPAT) |
| + sig = SIGABRT; |
| +#endif |
| + |
| + /* POSIX requires sigaction() to be async-signal-safe. In other |
| + words, if an asynchronous signal can occur while we are anywhere |
| + inside this function, the user's handler could then call |
| + sigaction() recursively and expect consistent results. We meet |
| + this rule by using sigprocmask to block all signals before |
| + modifying any data structure that could be read from a signal |
| + handler; this works since we know that the gnulib sigprocmask |
| + replacement does not try to use sigaction() from its handler. */ |
| + if (!act && !oact) |
| + return 0; |
| + sigfillset (&mask); |
| + sigprocmask (SIG_BLOCK, &mask, &oldmask); |
| + if (oact) |
| + { |
| + if (action_array[sig].sa_handler) |
| + *oact = action_array[sig]; |
| + else |
| + { |
| + /* Safe to change the handler at will here, since all |
| + signals are currently blocked. */ |
| + oact->sa_handler = signal (sig, SIG_DFL); |
| + if (oact->sa_handler == SIG_ERR) |
| + goto failure; |
| + signal (sig, oact->sa_handler); |
| + oact->sa_flags = SA_RESETHAND | SA_NODEFER; |
| + sigemptyset (&oact->sa_mask); |
| + } |
| + } |
| + |
| + if (act) |
| + { |
| + /* Safe to install the handler before updating action_array, |
| + since all signals are currently blocked. */ |
| + if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN) |
| + { |
| + if (signal (sig, act->sa_handler) == SIG_ERR) |
| + goto failure; |
| + action_array[sig].sa_handler = NULL; |
| + } |
| + else |
| + { |
| + if (signal (sig, sigaction_handler) == SIG_ERR) |
| + goto failure; |
| + action_array[sig] = *act; |
| + } |
| + } |
| + sigprocmask (SIG_SETMASK, &oldmask, NULL); |
| + return 0; |
| + |
| + failure: |
| + saved_errno = errno; |
| + sigprocmask (SIG_SETMASK, &oldmask, NULL); |
| + errno = saved_errno; |
| + return -1; |
| +} |
| + |
| +#endif |
| + |
| +#if !defined(HAVE_UNAME) |
| +/* uname replacement. |
| + Copyright (C) 2009-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software: you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 3 of the License, or |
| + (at your option) any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Specification. */ |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/sys_utsname.h" |
| +#else |
| +#include <sys/utsname.h> |
| +#endif |
| + |
| + |
| +/* This file provides an implementation only for the native Windows API. */ |
| + |
| +#include <stdio.h> |
| +#include <stdlib.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/stdlib.h" |
| +#endif |
| +#include <string.h> |
| +#include <unistd.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/unistd.h" |
| +#endif |
| +#include <windows.h> |
| + |
| +/* Mingw headers don't have all the platform codes. */ |
| +#ifndef VER_PLATFORM_WIN32_CE |
| +# define VER_PLATFORM_WIN32_CE 3 |
| +#endif |
| + |
| +/* Some headers don't have all the processor architecture codes. */ |
| +#ifndef PROCESSOR_ARCHITECTURE_AMD64 |
| +# define PROCESSOR_ARCHITECTURE_AMD64 9 |
| +#endif |
| +#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 |
| +# define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10 |
| +#endif |
| + |
| +/* Mingw headers don't have the latest processor codes. */ |
| +#ifndef PROCESSOR_AMD_X8664 |
| +# define PROCESSOR_AMD_X8664 8664 |
| +#endif |
| + |
| +int |
| +uname (struct utsname *buf) |
| +{ |
| + OSVERSIONINFO version; |
| + OSVERSIONINFOEX versionex; |
| + BOOL have_versionex; /* indicates whether versionex is filled */ |
| + const char *super_version; |
| + |
| + /* Preparation: Fill version and, if possible, also versionex. |
| + But try to call GetVersionEx only once in the common case. */ |
| + versionex.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX); |
| + have_versionex = GetVersionEx ((OSVERSIONINFO *) &versionex); |
| + if (have_versionex) |
| + { |
| + /* We know that OSVERSIONINFO is a subset of OSVERSIONINFOEX. */ |
| + memcpy (&version, &versionex, sizeof (OSVERSIONINFO)); |
| + } |
| + else |
| + { |
| + version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); |
| + if (!GetVersionEx (&version)) |
| + abort (); |
| + } |
| + |
| + /* Fill in nodename. */ |
| + if (gethostname (buf->nodename, sizeof (buf->nodename)) < 0) |
| + strcpy (buf->nodename, "localhost"); |
| + |
| + /* Determine major-major Windows version. */ |
| + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) |
| + { |
| + /* Windows NT or newer. */ |
| + super_version = "NT"; |
| + } |
| + else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE) |
| + { |
| + /* Windows CE or Embedded CE. */ |
| + super_version = "CE"; |
| + } |
| + else if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) |
| + { |
| + /* Windows 95/98/ME. */ |
| + switch (version.dwMinorVersion) |
| + { |
| + case 0: |
| + super_version = "95"; |
| + break; |
| + case 10: |
| + super_version = "98"; |
| + break; |
| + case 90: |
| + super_version = "ME"; |
| + break; |
| + default: |
| + super_version = ""; |
| + break; |
| + } |
| + } |
| + else |
| + super_version = ""; |
| + |
| + /* Fill in sysname. */ |
| +#ifdef __MINGW32__ |
| + /* Returns a string compatible with the MSYS uname.exe program, |
| + so that no further changes are needed to GNU config.guess. |
| + For example, |
| + $ ./uname.exe -s => MINGW32_NT-5.1 |
| + */ |
| + sprintf (buf->sysname, "MINGW32_%s-%u.%u", super_version, |
| + (unsigned int) version.dwMajorVersion, |
| + (unsigned int) version.dwMinorVersion); |
| +#else |
| + sprintf (buf->sysname, "Windows%s", super_version); |
| +#endif |
| + |
| + /* Fill in release, version. */ |
| + /* The MSYS uname.exe programs uses strings from a modified Cygwin runtime: |
| + $ ./uname.exe -r => 1.0.11(0.46/3/2) |
| + $ ./uname.exe -v => 2008-08-25 23:40 |
| + There is no point in imitating this behaviour. */ |
| + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) |
| + { |
| + /* Windows NT or newer. */ |
| + struct windows_version |
| + { |
| + int major; |
| + int minor; |
| + unsigned int server_offset; |
| + const char *name; |
| + }; |
| + |
| + /* Storing the workstation and server version names in a single |
| + stream does not waste memory when they are the same. These |
| + macros abstract the representation. VERSION1 is used if |
| + version.wProductType does not matter, VERSION2 if it does. */ |
| + #define VERSION1(major, minor, name) \ |
| + { major, minor, 0, name } |
| + #define VERSION2(major, minor, workstation, server) \ |
| + { major, minor, sizeof workstation, workstation "\0" server } |
| + static const struct windows_version versions[] = |
| + { |
| + VERSION2 (3, -1, "Windows NT Workstation", "Windows NT Server"), |
| + VERSION2 (4, -1, "Windows NT Workstation", "Windows NT Server"), |
| + VERSION1 (5, 0, "Windows 2000"), |
| + VERSION1 (5, 1, "Windows XP"), |
| + VERSION1 (5, 2, "Windows Server 2003"), |
| + VERSION2 (6, 0, "Windows Vista", "Windows Server 2008"), |
| + VERSION2 (6, 1, "Windows 7", "Windows Server 2008 R2"), |
| + VERSION2 (-1, -1, "Windows", "Windows Server") |
| + }; |
| + const char *base; |
| + const struct windows_version *v = versions; |
| + |
| + /* Find a version that matches ours. The last element is a |
| + wildcard that always ends the loop. */ |
| + while ((v->major != version.dwMajorVersion && v->major != -1) |
| + || (v->minor != version.dwMinorVersion && v->minor != -1)) |
| + v++; |
| + |
| + if (have_versionex && versionex.wProductType != VER_NT_WORKSTATION) |
| + base = v->name + v->server_offset; |
| + else |
| + base = v->name; |
| + if (v->major == -1 || v->minor == -1) |
| + sprintf (buf->release, "%s %u.%u", |
| + base, |
| + (unsigned int) version.dwMajorVersion, |
| + (unsigned int) version.dwMinorVersion); |
| + else |
| + strcpy (buf->release, base); |
| + } |
| + else if (version.dwPlatformId == VER_PLATFORM_WIN32_CE) |
| + { |
| + /* Windows CE or Embedded CE. */ |
| + sprintf (buf->release, "Windows CE %u.%u", |
| + (unsigned int) version.dwMajorVersion, |
| + (unsigned int) version.dwMinorVersion); |
| + } |
| + else |
| + { |
| + /* Windows 95/98/ME. */ |
| + sprintf (buf->release, "Windows %s", super_version); |
| + } |
| + strcpy (buf->version, version.szCSDVersion); |
| + |
| + /* Fill in machine. */ |
| + { |
| + SYSTEM_INFO info; |
| + |
| + GetSystemInfo (&info); |
| + /* Check for Windows NT or CE, since the info.wProcessorLevel is |
| + garbage on Windows 95. */ |
| + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT |
| + || version.dwPlatformId == VER_PLATFORM_WIN32_CE) |
| + { |
| + /* Windows NT or newer, or Windows CE or Embedded CE. */ |
| + switch (info.wProcessorArchitecture) |
| + { |
| + case PROCESSOR_ARCHITECTURE_AMD64: |
| + strcpy (buf->machine, "x86_64"); |
| + break; |
| + case PROCESSOR_ARCHITECTURE_IA64: |
| + strcpy (buf->machine, "ia64"); |
| + break; |
| + case PROCESSOR_ARCHITECTURE_INTEL: |
| + strcpy (buf->machine, "i386"); |
| + if (info.wProcessorLevel >= 3) |
| + buf->machine[1] = |
| + '0' + (info.wProcessorLevel <= 6 ? info.wProcessorLevel : 6); |
| + break; |
| + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: |
| + strcpy (buf->machine, "i686"); |
| + break; |
| + case PROCESSOR_ARCHITECTURE_MIPS: |
| + strcpy (buf->machine, "mips"); |
| + break; |
| + case PROCESSOR_ARCHITECTURE_ALPHA: |
| + case PROCESSOR_ARCHITECTURE_ALPHA64: |
| + strcpy (buf->machine, "alpha"); |
| + break; |
| + case PROCESSOR_ARCHITECTURE_PPC: |
| + strcpy (buf->machine, "powerpc"); |
| + break; |
| + case PROCESSOR_ARCHITECTURE_SHX: |
| + strcpy (buf->machine, "sh"); |
| + break; |
| + case PROCESSOR_ARCHITECTURE_ARM: |
| + strcpy (buf->machine, "arm"); |
| + break; |
| + default: |
| + strcpy (buf->machine, "unknown"); |
| + break; |
| + } |
| + } |
| + else |
| + { |
| + /* Windows 95/98/ME. */ |
| + switch (info.dwProcessorType) |
| + { |
| + case PROCESSOR_AMD_X8664: |
| + strcpy (buf->machine, "x86_64"); |
| + break; |
| + case PROCESSOR_INTEL_IA64: |
| + strcpy (buf->machine, "ia64"); |
| + break; |
| + default: |
| + if (info.dwProcessorType % 100 == 86) |
| + sprintf (buf->machine, "i%u", |
| + (unsigned int) info.dwProcessorType); |
| + else |
| + strcpy (buf->machine, "unknown"); |
| + break; |
| + } |
| + } |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +#endif |
| + |
| +#if !defined(HAVE_WARN) |
| +void |
| +warn(const char *fmt, ...) |
| +{ |
| + va_list ap; |
| + |
| + va_start(ap, fmt); |
| + vwarn(fmt, ap); |
| + va_end(ap); |
| +} |
| +#endif |
| + |
| +#if !defined(HAVE_WARNX) |
| +void |
| +warnx(const char *fmt, ...) |
| +{ |
| + va_list ap; |
| + |
| + va_start(ap, fmt); |
| vwarnx(fmt, ap); |
| @@ -622 +2959,618 @@ warnx(const char *fmt, ...) |
| #endif |
| + |
| +#if !defined(HAVE_WAIT) |
| +/* Specification. */ |
| +#include "wait.h" |
| +pid_t |
| +wait (int *statusp) |
| +{ |
| + return waitpid((pid_t) -1, statusp, WUNTRACED); |
| +} |
| +#endif |
| + |
| +#if !defined(HAVE_WAITPID) |
| +/* Wait for process state change. |
| + Copyright (C) 2001-2003, 2005-2018 Free Software Foundation, Inc. |
| + |
| + This program is free software; you can redistribute it and/or modify |
| + it under the terms of the GNU General Public License as published by |
| + the Free Software Foundation; either version 2, or (at your option) |
| + any later version. |
| + |
| + This program is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + GNU General Public License for more details. |
| + |
| + You should have received a copy of the GNU General Public License |
| + along with this program; if not, see <https://www.gnu.org/licenses/>. */ |
| + |
| +/* Specification. */ |
| +#include "wait.h" |
| + |
| +/* Implementation for native Windows systems. */ |
| + |
| +#include <process.h> /* for _cwait, WAIT_CHILD */ |
| + |
| +pid_t |
| +waitpid (pid_t pid, int *statusp, int options) |
| +{ |
| + return _cwait (statusp, pid, WAIT_CHILD); |
| +} |
| +#endif |
| + |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +char * |
| +getShellLaunchPrefix() |
| +{ |
| + const char *sysRootPath = getenv("SYSROOTWINDOWSPATH"); |
| + const char *msystemPrefix = getenv("MSYSTEM"); |
| + |
| + if (sysRootPath == NULL || msystemPrefix == NULL) { |
| + return NULL; /*we can't find mingw shell installed on this system */ |
| + } |
| + else { |
| + /* we will return something like |
| + * C:\msys64\usr\bin\env MSYSTEM=MINGW64 /usr/bin/bash -lc |
| + */ |
| + return str_concat( |
| + str_concat( |
| + str_concat(sysRootPath, "usr\\bin\\env.exe MSYSTEM=", 0), |
| + msystemPrefix, 0), |
| + "/usr/bin/bash -lc", STR_ADDSPACE); |
| + } |
| +} |
| + |
| +char * getUnixPathCmd(const char *path) |
| +{ |
| + return str_concat( |
| + "cygpath -u", str_concat("\"", |
| + str_concat(path, "\"", 0), |
| + 0), |
| + STR_ADDSPACE); |
| +} |
| + |
| +#endif |
| + |
| +#include <stdint.h> |
| +#include <stdlib.h> |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include "headers-mingw/stdlib.h" |
| +#endif |
| +#include <string.h> |
| + |
| +size_t str_escape(char *dst, const char *src, size_t dstLen) |
| +{ |
| + const char complexCharMap[] = "abtnvfr"; |
| + |
| + size_t i; |
| + size_t srcLen = strlen(src); |
| + size_t dstIdx = 0; |
| + |
| + // If caller wants to determine required length (supplying NULL for dst) |
| + // then we set dstLen to SIZE_MAX and pretend the buffer is the largest |
| + // possible, but we never write to it. Caller can also provide dstLen |
| + // as 0 if no limit is wanted. |
| + if (dst == NULL || dstLen == 0) dstLen = SIZE_MAX; |
| + |
| + for (i = 0; i < srcLen && dstIdx < dstLen; i++) |
| + { |
| + size_t complexIdx = 0; |
| + |
| + switch (src[i]) |
| + { |
| + case '\'': |
| + case '\"': |
| + case '\\': |
| + if (dst && dstIdx <= dstLen - 2) |
| + { |
| + dst[dstIdx++] = '\\'; |
| + dst[dstIdx++] = src[i]; |
| + } |
| + else dstIdx += 2; |
| + break; |
| + |
| + case '\r': complexIdx++; |
| + case '\f': complexIdx++; |
| + case '\v': complexIdx++; |
| + case '\n': complexIdx++; |
| + case '\t': complexIdx++; |
| + case '\b': complexIdx++; |
| + case '\a': |
| + if (dst && dstIdx <= dstLen - 2) |
| + { |
| + dst[dstIdx++] = '\\'; |
| + dst[dstIdx++] = complexCharMap[complexIdx]; |
| + } |
| + else dstIdx += 2; |
| + break; |
| + |
| + default: |
| + if (isprint(src[i])) |
| + { |
| + // simply copy the character |
| + if (dst) |
| + dst[dstIdx++] = src[i]; |
| + else |
| + dstIdx++; |
| + } |
| + else |
| + { |
| + // produce octal escape sequence |
| + if (dst && dstIdx <= dstLen - 4) |
| + { |
| + dst[dstIdx++] = '\\'; |
| + dst[dstIdx++] = ((src[i] & 0300) >> 6) + '0'; |
| + dst[dstIdx++] = ((src[i] & 0070) >> 3) + '0'; |
| + dst[dstIdx++] = ((src[i] & 0007) >> 0) + '0'; |
| + } |
| + else |
| + { |
| + dstIdx += 4; |
| + } |
| + } |
| + } |
| + } |
| + |
| + if (dst && dstIdx <= dstLen) |
| + dst[dstIdx] = '\0'; |
| + |
| + return dstIdx; |
| +} |
| + |
| +size_t str_escape_dblquote(char *dst, const char *src, size_t dstLen) |
| +{ |
| + |
| + size_t i; |
| + size_t srcLen = strlen(src); |
| + size_t dstIdx = 0; |
| + |
| + // If caller wants to determine required length (supplying NULL for dst) |
| + // then we set dstLen to SIZE_MAX and pretend the buffer is the largest |
| + // possible, but we never write to it. Caller can also provide dstLen |
| + // as 0 if no limit is wanted. |
| + if (dst == NULL || dstLen == 0) dstLen = SIZE_MAX; |
| + |
| + for (i = 0; i < srcLen && dstIdx < dstLen; i++) |
| + { |
| + size_t complexIdx = 0; |
| + |
| + switch (src[i]) |
| + { |
| + case '\"': |
| + if (dst && dstIdx <= dstLen - 2) |
| + { |
| + dst[dstIdx++] = '\\'; |
| + dst[dstIdx++] = src[i]; |
| + } |
| + else dstIdx += 2; |
| + break; |
| + case '\\': |
| + if (dst && dstIdx <= dstLen - 2) |
| + { |
| + dst[dstIdx++] = '\\'; |
| + dst[dstIdx++] = src[i]; |
| + } |
| + else dstIdx += 2; |
| + break; |
| + default: |
| +// if (isprint(src[i]) || src[i] == '\n' || src[i] == '\r') |
| +// { |
| + // simply copy the character |
| + if (dst) |
| + dst[dstIdx++] = src[i]; |
| + else |
| + dstIdx++; |
| +// } |
| +// else { |
| +// dst[dstIdx++] = ' '; |
| +// } |
| + } |
| + } |
| + |
| + if (dst && dstIdx <= dstLen) |
| + dst[dstIdx] = '\0'; |
| + |
| + return dstIdx; |
| +} |
| + |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include <windows.h> |
| +//#include <stdio.h> |
| +//#include <malloc.h> |
| + |
| +#define bool _Bool |
| +#define true 1 |
| +#define false 0 |
| + |
| +#define null ((void*)0) |
| + |
| +typedef struct system_np_s { |
| + HANDLE child_stdout_read; |
| + HANDLE child_stderr_read; |
| + HANDLE reader; |
| + PROCESS_INFORMATION pi; |
| + const char* command; |
| + char* stdout_data; |
| + int stdout_data_size; |
| + char* stderr_data; |
| + int stderr_data_size; |
| + int* exit_code; |
| + int timeout; // timeout in milliseconds or -1 for INIFINTE |
| +} system_np_t; |
| + |
| +static int peek_pipe(HANDLE pipe, char* data, int size) { |
| + char buffer[4 * 1024]; |
| + DWORD read = 0; |
| + DWORD available = 0; |
| + bool b = PeekNamedPipe(pipe, null, sizeof(buffer), null, &available, null); |
| + if (!b) { |
| + return -1; |
| + } else if (available > 0) { |
| + int bytes = min(sizeof(buffer), available); |
| + b = ReadFile(pipe, buffer, bytes, &read, null); |
| + if (!b) { |
| + return -1; |
| + } |
| + if (data != null && size > 0) { |
| + int n = min(size - 1, (int)read); |
| + memcpy(data, buffer, n); |
| + data[n + 1] = 0; // always zero terminated |
| + return n; |
| + } |
| + } |
| + return 0; |
| +} |
| + |
| +static DWORD WINAPI read_from_all_pipes_fully(void* p) { |
| + system_np_t* system = (system_np_t*)p; |
| + unsigned long long milliseconds = GetTickCount64(); // since boot time |
| + char* out = system->stdout_data != null && system->stdout_data_size > 0 ? system->stdout_data : null; |
| + char* err = system->stderr_data != null && system->stderr_data_size > 0 ? system->stderr_data : null; |
| + int out_bytes = system->stdout_data != null && system->stdout_data_size > 0 ? system->stdout_data_size - 1 : 0; |
| + int err_bytes = system->stderr_data != null && system->stderr_data_size > 0 ? system->stderr_data_size - 1 : 0; |
| + for (;;) { |
| + int read_stdout = peek_pipe(system->child_stdout_read, out, out_bytes); |
| + if (read_stdout > 0 && out != null) { out += read_stdout; out_bytes -= read_stdout; } |
| + int read_stderr = peek_pipe(system->child_stderr_read, err, err_bytes); |
| + if (read_stderr > 0 && err != null) { err += read_stderr; err_bytes -= read_stderr; } |
| + if (read_stdout < 0 && read_stderr < 0) { break; } // both pipes are closed |
| + unsigned long long time_spent_in_milliseconds = GetTickCount64() - milliseconds; |
| + if (system->timeout > 0 && time_spent_in_milliseconds > system->timeout) { break; } |
| + if (read_stdout == 0 && read_stderr == 0) { // nothing has been read from both pipes |
| + HANDLE handles[2] = {system->child_stdout_read, system->child_stderr_read}; |
| + WaitForMultipleObjects(2, handles, false, 1); // wait for at least 1 millisecond (more likely 16) |
| + } |
| + } |
| + if (out != null) { *out = 0; } |
| + if (err != null) { *err = 0; } |
| + return 0; |
| +} |
| + |
| +static int create_child_process(system_np_t* system) { |
| + SECURITY_ATTRIBUTES sa = {0}; |
| + sa.nLength = sizeof(SECURITY_ATTRIBUTES); |
| + sa.bInheritHandle = true; |
| + sa.lpSecurityDescriptor = null; |
| + HANDLE child_stdout_write = INVALID_HANDLE_VALUE; |
| + HANDLE child_stderr_write = INVALID_HANDLE_VALUE; |
| + if (!CreatePipe(&system->child_stderr_read, &child_stderr_write, &sa, 0) ) { |
| + return GetLastError(); |
| + } |
| + if (!SetHandleInformation(system->child_stderr_read, HANDLE_FLAG_INHERIT, 0) ){ |
| + return GetLastError(); |
| + } |
| + if (!CreatePipe(&system->child_stdout_read, &child_stdout_write, &sa, 0) ) { |
| + return GetLastError(); |
| + } |
| + if (!SetHandleInformation(system->child_stdout_read, HANDLE_FLAG_INHERIT, 0) ){ |
| + return GetLastError(); |
| + } |
| + // Set the text I want to run |
| + STARTUPINFO siStartInfo = {0}; |
| + siStartInfo.cb = sizeof(STARTUPINFO); |
| + siStartInfo.hStdError = child_stderr_write; |
| + siStartInfo.hStdOutput = child_stdout_write; |
| + siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; |
| + siStartInfo.wShowWindow = SW_HIDE; |
| + bool b = CreateProcessA(null, |
| + (char*)system->command, |
| + null, // process security attributes |
| + null, // primary thread security attributes |
| + true, // handles are inherited |
| + CREATE_NO_WINDOW, // creation flags |
| + null, // use parent's environment |
| + null, // use parent's current directory |
| + &siStartInfo, // STARTUPINFO pointer |
| + &system->pi); // receives PROCESS_INFORMATION |
| + int err = GetLastError(); |
| + CloseHandle(child_stderr_write); |
| + CloseHandle(child_stdout_write); |
| + if (!b) { |
| + CloseHandle(system->child_stdout_read); system->child_stdout_read = INVALID_HANDLE_VALUE; |
| + CloseHandle(system->child_stderr_read); system->child_stderr_read = INVALID_HANDLE_VALUE; |
| + } |
| + return b ? 0 : err; |
| +} |
| + |
| +int system_np(const char* command, int timeout_milliseconds, |
| + char* stdout_data, int stdout_data_size, |
| + char* stderr_data, int stderr_data_size, int* exit_code) { |
| + system_np_t system = {0}; |
| + if (exit_code != null) { *exit_code = 0; } |
| + if (stdout_data != null && stdout_data_size > 0) { stdout_data[0] = 0; } |
| + if (stderr_data != null && stderr_data_size > 0) { stderr_data[0] = 0; } |
| + system.timeout = timeout_milliseconds > 0 ? timeout_milliseconds : -1; |
| + system.command = command; |
| + system.stdout_data = stdout_data; |
| + system.stderr_data = stderr_data; |
| + system.stdout_data_size = stdout_data_size; |
| + system.stderr_data_size = stderr_data_size; |
| + int r = create_child_process(&system); |
| + if (r == 0) { |
| + system.reader = CreateThread(null, 0, read_from_all_pipes_fully, &system, 0, null); |
| + if (system.reader == null) { // in theory should rarely happen only when system super low on resources |
| + r = GetLastError(); |
| + TerminateProcess(system.pi.hProcess, ECANCELED); |
| + } else { |
| + bool thread_done = WaitForSingleObject(system.pi.hThread, timeout_milliseconds) == 0; |
| + bool process_done = WaitForSingleObject(system.pi.hProcess, timeout_milliseconds) == 0; |
| + if (!thread_done || !process_done) { |
| + TerminateProcess(system.pi.hProcess, ETIME); |
| + } |
| + if (exit_code != null) { |
| + GetExitCodeProcess(system.pi.hProcess, (DWORD*)exit_code); |
| + } |
| + CloseHandle(system.pi.hThread); |
| + CloseHandle(system.pi.hProcess); |
| + CloseHandle(system.child_stdout_read); system.child_stdout_read = INVALID_HANDLE_VALUE; |
| + CloseHandle(system.child_stderr_read); system.child_stderr_read = INVALID_HANDLE_VALUE; |
| + WaitForSingleObject(system.reader, INFINITE); // join thread |
| + CloseHandle(system.reader); |
| + } |
| + } |
| + if (stdout_data != null && stdout_data_size > 0) { stdout_data[stdout_data_size - 1] = 0; } |
| + if (stderr_data != null && stderr_data_size > 0) { stderr_data[stderr_data_size - 1] = 0; } |
| + return r; |
| +} |
| +#endif |
| + |
| +#ifndef NO_REGEX |
| +#if (!defined(HAVE_REGCOMP) || !defined(HAVE_REGERROR) || !defined(HAVE_REGEXEC) || !defined(HAVE_REGFREE)) |
| + |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| +#include <windows.h> |
| +#endif |
| +/* Return the codeset of the current locale, if this is easily deducible. |
| + Otherwise, return "". */ |
| +static char * |
| +ctype_codeset(void) { |
| + static char buf[2 + 10 + 1]; |
| + char const *locale = setlocale(LC_CTYPE, NULL); |
| + char *codeset = buf; |
| + size_t codesetlen; |
| + codeset[0] = '\0'; |
| + |
| + if (locale && locale[0]) { |
| + /* If the locale name contains an encoding after the dot, return it. */ |
| + char *dot = strchr(locale, '.'); |
| + |
| + if (dot) { |
| + /* Look for the possible @... trailer and remove it, if any. */ |
| + char *codeset_start = dot + 1; |
| + char const *modifier = strchr(codeset_start, '@'); |
| + |
| + if (!modifier) |
| + codeset = codeset_start; |
| + else { |
| + codesetlen = modifier - codeset_start; |
| + if (codesetlen < sizeof buf) { |
| + codeset = memcpy(buf, codeset_start, codesetlen); |
| + codeset[codesetlen] = '\0'; |
| + } |
| + } |
| + } |
| + } |
| + |
| + /* If setlocale is successful, it returns the number of the |
| + codepage, as a string. Otherwise, fall back on Windows API |
| + GetACP, which returns the locale's codepage as a number (although |
| + this doesn't change according to what the 'setlocale' call specified). |
| + Either way, prepend "CP" to make it a valid codeset name. */ |
| + codesetlen = strlen(codeset); |
| + if (0 < codesetlen && codesetlen < sizeof buf - 2) |
| + memmove(buf + 2, codeset, codesetlen + 1); |
| + else |
| + sprintf(buf + 2, "%u", GetACP()); |
| + codeset = memcpy(buf, "CP", 2); |
| + return codeset; |
| +} |
| + |
| +/* Provide nl_langinfo from scratch, either for native MS-Windows, or |
| + for old Unix platforms without locales, such as Linux libc5 or |
| + BeOS. */ |
| + |
| +# include <time.h> |
| + |
| +char * |
| +nl_langinfo(nl_item item) { |
| + static char nlbuf[100]; |
| + struct tm tmm = {0}; |
| + |
| + switch (item) { |
| + /* nl_langinfo items of the LC_CTYPE category */ |
| + case CODESET: { |
| + char *codeset = ctype_codeset(); |
| + if (*codeset) |
| + return codeset; |
| + } |
| + return (char *) "ISO-8859-1"; |
| + /* nl_langinfo items of the LC_NUMERIC category */ |
| + case RADIXCHAR: |
| + return localeconv()->decimal_point; |
| + case THOUSEP: |
| + return localeconv()->thousands_sep; |
| + /* nl_langinfo items of the LC_TIME category. |
| + TODO: Really use the locale. */ |
| + case D_T_FMT: |
| + case ERA_D_T_FMT: |
| + return (char *) "%a %b %e %H:%M:%S %Y"; |
| + case D_FMT: |
| + case ERA_D_FMT: |
| + return (char *) "%m/%d/%y"; |
| + case T_FMT: |
| + case ERA_T_FMT: |
| + return (char *) "%H:%M:%S"; |
| + case T_FMT_AMPM: |
| + return (char *) "%I:%M:%S %p"; |
| + case AM_STR: |
| + if (!strftime(nlbuf, sizeof nlbuf, "%p", &tmm)) |
| + return (char *) "AM"; |
| + return nlbuf; |
| + case PM_STR: |
| + tmm.tm_hour = 12; |
| + if (!strftime(nlbuf, sizeof nlbuf, "%p", &tmm)) |
| + return (char *) "PM"; |
| + return nlbuf; |
| + case DAY_1: |
| + case DAY_2: |
| + case DAY_3: |
| + case DAY_4: |
| + case DAY_5: |
| + case DAY_6: |
| + case DAY_7: { |
| + static char const days[][sizeof "Wednesday"] = { |
| + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", |
| + "Friday", "Saturday" |
| + }; |
| + tmm.tm_wday = item - DAY_1; |
| + if (!strftime(nlbuf, sizeof nlbuf, "%A", &tmm)) |
| + return (char *) days[item - DAY_1]; |
| + return nlbuf; |
| + } |
| + case ABDAY_1: |
| + case ABDAY_2: |
| + case ABDAY_3: |
| + case ABDAY_4: |
| + case ABDAY_5: |
| + case ABDAY_6: |
| + case ABDAY_7: { |
| + static char const abdays[][sizeof "Sun"] = { |
| + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
| + }; |
| + tmm.tm_wday = item - ABDAY_1; |
| + if (!strftime(nlbuf, sizeof nlbuf, "%a", &tmm)) |
| + return (char *) abdays[item - ABDAY_1]; |
| + return nlbuf; |
| + } |
| + { |
| + static char const months[][sizeof "September"] = { |
| + "January", "February", "March", "April", "May", "June", "July", |
| + "September", "October", "November", "December" |
| + }; |
| + case MON_1: |
| + case MON_2: |
| + case MON_3: |
| + case MON_4: |
| + case MON_5: |
| + case MON_6: |
| + case MON_7: |
| + case MON_8: |
| + case MON_9: |
| + case MON_10: |
| + case MON_11: |
| + case MON_12: |
| + tmm.tm_mon = item - MON_1; |
| + if (!strftime(nlbuf, sizeof nlbuf, "%B", &tmm)) |
| + return (char *) months[item - MON_1]; |
| + return nlbuf; |
| + case ALTMON_1: |
| + case ALTMON_2: |
| + case ALTMON_3: |
| + case ALTMON_4: |
| + case ALTMON_5: |
| + case ALTMON_6: |
| + case ALTMON_7: |
| + case ALTMON_8: |
| + case ALTMON_9: |
| + case ALTMON_10: |
| + case ALTMON_11: |
| + case ALTMON_12: |
| + tmm.tm_mon = item - ALTMON_1; |
| + /* The platforms without nl_langinfo() don't support strftime with %OB. |
| + We don't even need to try. */ |
| + if (!strftime(nlbuf, sizeof nlbuf, "%B", &tmm)) |
| + return (char *) months[item - ALTMON_1]; |
| + return nlbuf; |
| + } |
| + case ABMON_1: |
| + case ABMON_2: |
| + case ABMON_3: |
| + case ABMON_4: |
| + case ABMON_5: |
| + case ABMON_6: |
| + case ABMON_7: |
| + case ABMON_8: |
| + case ABMON_9: |
| + case ABMON_10: |
| + case ABMON_11: |
| + case ABMON_12: { |
| + static char const abmonths[][sizeof "Jan"] = { |
| + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", |
| + "Sep", "Oct", "Nov", "Dec" |
| + }; |
| + tmm.tm_mon = item - ABMON_1; |
| + if (!strftime(nlbuf, sizeof nlbuf, "%b", &tmm)) |
| + return (char *) abmonths[item - ABMON_1]; |
| + return nlbuf; |
| + } |
| + case ERA: |
| + return (char *) ""; |
| + case ALT_DIGITS: |
| + return (char *) "\0\0\0\0\0\0\0\0\0\0"; |
| + /* nl_langinfo items of the LC_MONETARY category. */ |
| + case CRNCYSTR: |
| + return localeconv()->currency_symbol; |
| +# ifdef INT_CURR_SYMBOL |
| + case INT_CURR_SYMBOL: |
| + return localeconv () ->int_curr_symbol; |
| + case MON_DECIMAL_POINT: |
| + return localeconv () ->mon_decimal_point; |
| + case MON_THOUSANDS_SEP: |
| + return localeconv () ->mon_thousands_sep; |
| + case MON_GROUPING: |
| + return localeconv () ->mon_grouping; |
| + case POSITIVE_SIGN: |
| + return localeconv () ->positive_sign; |
| + case NEGATIVE_SIGN: |
| + return localeconv () ->negative_sign; |
| + case FRAC_DIGITS: |
| + return & localeconv () ->frac_digits; |
| + case INT_FRAC_DIGITS: |
| + return & localeconv () ->int_frac_digits; |
| + case P_CS_PRECEDES: |
| + return & localeconv () ->p_cs_precedes; |
| + case N_CS_PRECEDES: |
| + return & localeconv () ->n_cs_precedes; |
| + case P_SEP_BY_SPACE: |
| + return & localeconv () ->p_sep_by_space; |
| + case N_SEP_BY_SPACE: |
| + return & localeconv () ->n_sep_by_space; |
| + case P_SIGN_POSN: |
| + return & localeconv () ->p_sign_posn; |
| + case N_SIGN_POSN: |
| + return & localeconv () ->n_sign_posn; |
| +# endif |
| + /* nl_langinfo items of the LC_MESSAGES category |
| + TODO: Really use the locale. */ |
| + case YESEXPR: |
| + return (char *) "^[yY]"; |
| + case NOEXPR: |
| + return (char *) "^[nN]"; |
| + default: |
| + return (char *) ""; |
| + } |
| +} |
| + |
| +#endif |
| +#endif |
| \ No newline at end of file |
| diff --git a/var.c b/var.c |
| index 6f8d4c3..5e4e9d2 100644 |
| --- a/var.c |
| +++ b/var.c |
| @@ -73,3 +73,3 @@ static char rcsid[] = "$NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $"; |
| #else |
| -#include <sys/cdefs.h> |
| + #include <sys/cdefs.h> |
| #ifndef lint |
| @@ -126,6 +126,20 @@ __RCSID("$NetBSD: var.c,v 1.221 2018/12/21 05:50:19 sjg Exp $"); |
| #include <sys/stat.h> |
| + |
| +#if (defined _WIN32 && !defined __CYGWIN__) |
| +#include "headers-mingw/sys_stat.h" |
| +#endif |
| #ifndef NO_REGEX |
| + |
| #include <sys/types.h> |
| + |
| +# if (defined _WIN32 && !defined __CYGWIN__) |
| + #include "headers-mingw/regex.h" |
| +#include "headers-mingw/regex_internal.h" |
| +# else |
| + |
| #include <regex.h> |
| + |
| +# endif |
| #endif |
| + |
| #include <ctype.h> |
| @@ -153,3 +167,3 @@ char **savedEnv = NULL; |
| */ |
| -char var_Error[] = ""; |
| +char var_Error[] = ""; |
| |
| @@ -160,3 +174,3 @@ char var_Error[] = ""; |
| */ |
| -static char varNoError[] = ""; |
| +static char varNoError[] = ""; |
| |
| @@ -188,18 +202,18 @@ static Boolean save_dollars = FALSE; |
| */ |
| -GNode *VAR_INTERNAL; /* variables from make itself */ |
| -GNode *VAR_GLOBAL; /* variables from the makefile */ |
| -GNode *VAR_CMD; /* variables defined on the command-line */ |
| +GNode *VAR_INTERNAL; /* variables from make itself */ |
| +GNode *VAR_GLOBAL; /* variables from the makefile */ |
| +GNode *VAR_CMD; /* variables defined on the command-line */ |
| |
| -#define FIND_CMD 0x1 /* look in VAR_CMD when searching */ |
| -#define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ |
| -#define FIND_ENV 0x4 /* look in the environment also */ |
| +#define FIND_CMD 0x1 /* look in VAR_CMD when searching */ |
| +#define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ |
| +#define FIND_ENV 0x4 /* look in the environment also */ |
| |
| typedef struct Var { |
| - char *name; /* the variable's name */ |
| - Buffer val; /* its value */ |
| - int flags; /* miscellaneous status flags */ |
| -#define VAR_IN_USE 1 /* Variable's value currently being used. |
| + char *name; /* the variable's name */ |
| + Buffer val; /* its value */ |
| + int flags; /* miscellaneous status flags */ |
| +#define VAR_IN_USE 1 /* Variable's value currently being used. |
| * Used to avoid recursion */ |
| -#define VAR_FROM_ENV 2 /* Variable comes from the environment */ |
| -#define VAR_JUNK 4 /* Variable is a junk variable that |
| +#define VAR_FROM_ENV 2 /* Variable comes from the environment */ |
| +#define VAR_JUNK 4 /* Variable is a junk variable that |
| * should be destroyed when done with |
| @@ -207,11 +221,11 @@ typedef struct Var { |
| * modified variables */ |
| -#define VAR_KEEP 8 /* Variable is VAR_JUNK, but we found |
| +#define VAR_KEEP 8 /* Variable is VAR_JUNK, but we found |
| * a use for it in some modifier and |
| * the value is therefore valid */ |
| -#define VAR_EXPORTED 16 /* Variable is exported */ |
| -#define VAR_REEXPORT 32 /* Indicate if var needs re-export. |
| +#define VAR_EXPORTED 16 /* Variable is exported */ |
| +#define VAR_REEXPORT 32 /* Indicate if var needs re-export. |
| * This would be true if it contains $'s |
| */ |
| -#define VAR_FROM_CMD 64 /* Variable came from command line */ |
| -} Var; |
| +#define VAR_FROM_CMD 64 /* Variable came from command line */ |
| +} Var; |
| |
| @@ -220,5 +234,5 @@ typedef struct Var { |
| */ |
| -#define VAR_EXPORTED_NONE 0 |
| -#define VAR_EXPORTED_YES 1 |
| -#define VAR_EXPORTED_ALL 2 |
| +#define VAR_EXPORTED_NONE 0 |
| +#define VAR_EXPORTED_YES 1 |
| +#define VAR_EXPORTED_ALL 2 |
| static int var_exportedVars = VAR_EXPORTED_NONE; |
| @@ -228,3 +242,3 @@ static int var_exportedVars = VAR_EXPORTED_NONE; |
| */ |
| -#define VAR_EXPORT_PARENT 1 |
| +#define VAR_EXPORT_PARENT 1 |
| /* |
| @@ -232,14 +246,14 @@ static int var_exportedVars = VAR_EXPORTED_NONE; |
| */ |
| -#define VAR_EXPORT_LITERAL 2 |
| +#define VAR_EXPORT_LITERAL 2 |
| |
| /* Var*Pattern flags */ |
| -#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ |
| -#define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ |
| -#define VAR_SUB_MATCHED 0x04 /* There was a match */ |
| -#define VAR_MATCH_START 0x08 /* Match at start of word */ |
| -#define VAR_MATCH_END 0x10 /* Match at end of word */ |
| -#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ |
| +#define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ |
| +#define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ |
| +#define VAR_SUB_MATCHED 0x04 /* There was a match */ |
| +#define VAR_MATCH_START 0x08 /* Match at start of word */ |
| +#define VAR_MATCH_END 0x10 /* Match at end of word */ |
| +#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ |
| |
| /* Var_Set flags */ |
| -#define VAR_NO_EXPORT 0x01 /* do not export */ |
| +#define VAR_NO_EXPORT 0x01 /* do not export */ |
| |
| @@ -251,4 +265,4 @@ typedef struct { |
| */ |
| - Byte varSpace; /* Word separator in expansions */ |
| - Boolean oneBigWord; /* TRUE if we will treat the variable as a |
| + Byte varSpace; /* Word separator in expansions */ |
| + Boolean oneBigWord; /* TRUE if we will treat the variable as a |
| * single big word, even if it contains |
| @@ -262,7 +276,7 @@ typedef struct { |
| typedef struct { |
| - const char *lhs; /* String to match */ |
| - int leftLen; /* Length of string */ |
| - const char *rhs; /* Replacement string (w/ &'s removed) */ |
| - int rightLen; /* Length of replacement */ |
| - int flags; |
| + const char *lhs; /* String to match */ |
| + int leftLen; /* Length of string */ |
| + const char *rhs; /* Replacement string (w/ &'s removed) */ |
| + int rightLen; /* Length of replacement */ |
| + int flags; |
| } VarPattern; |
| @@ -271,8 +285,8 @@ typedef struct { |
| typedef struct { |
| - GNode *ctxt; /* variable context */ |
| - char *tvar; /* name of temp var */ |
| - int tvarLen; |
| - char *str; /* string to expand */ |
| - int strLen; |
| - int errnum; /* errnum for not defined */ |
| + GNode *ctxt; /* variable context */ |
| + char *tvar; /* name of temp var */ |
| + int tvarLen; |
| + char *str; /* string to expand */ |
| + int strLen; |
| + int errnum; /* errnum for not defined */ |
| } VarLoop_t; |
| @@ -282,7 +296,7 @@ typedef struct { |
| typedef struct { |
| - regex_t re; |
| - int nsub; |
| - regmatch_t *matches; |
| - char *replace; |
| - int flags; |
| + regex_t re; |
| + int nsub; |
| + regmatch_t *matches; |
| + char *replace; |
| + int flags; |
| } VarREPattern; |
| @@ -292,4 +306,4 @@ typedef struct { |
| typedef struct { |
| - int start; /* first word to select */ |
| - int end; /* last word to select */ |
| + int start; /* first word to select */ |
| + int end; /* last word to select */ |
| } VarSelectWords_t; |
| @@ -297,46 +311,70 @@ typedef struct { |
| static Var *VarFind(const char *, GNode *, int); |
| + |
| static void VarAdd(const char *, const char *, GNode *); |
| + |
| static Boolean VarHead(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| static Boolean VarTail(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| static Boolean VarSuffix(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| static Boolean VarRoot(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| static Boolean VarMatch(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| #ifdef SYSVVARSUB |
| + |
| static Boolean VarSYSVMatch(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| #endif |
| + |
| static Boolean VarNoMatch(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| #ifndef NO_REGEX |
| + |
| static void VarREError(int, regex_t *, const char *); |
| + |
| static Boolean VarRESubstitute(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| #endif |
| + |
| static Boolean VarSubstitute(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| static Boolean VarLoopExpand(GNode *, Var_Parse_State *, |
| - char *, Boolean, Buffer *, void *); |
| + char *, Boolean, Buffer *, void *); |
| + |
| static char *VarGetPattern(GNode *, Var_Parse_State *, |
| - int, const char **, int, int *, int *, |
| - VarPattern *); |
| + int, const char **, int, int *, int *, |
| + VarPattern *); |
| + |
| static char *VarQuote(char *, Boolean); |
| + |
| static char *VarHash(char *); |
| + |
| static char *VarModify(GNode *, Var_Parse_State *, |
| - const char *, |
| - Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), |
| - void *); |
| + const char *, |
| + Boolean (*)(GNode *, Var_Parse_State *, char *, Boolean, Buffer *, void *), |
| + void *); |
| + |
| static char *VarOrder(const char *, const char); |
| + |
| static char *VarUniq(const char *); |
| + |
| static int VarWordCompare(const void *, const void *); |
| + |
| static void VarPrintVar(void *); |
| |
| -#define BROPEN '{' |
| -#define BRCLOSE '}' |
| -#define PROPEN '(' |
| -#define PRCLOSE ')' |
| +#define BROPEN '{' |
| +#define BRCLOSE '}' |
| +#define PROPEN '(' |
| +#define PRCLOSE ')' |
| |
| @@ -365,8 +403,7 @@ static void VarPrintVar(void *); |
| static Var * |
| -VarFind(const char *name, GNode *ctxt, int flags) |
| -{ |
| - Hash_Entry *var; |
| - Var *v; |
| +VarFind(const char *name, GNode *ctxt, int flags) { |
| + Hash_Entry *var; |
| + Var *v; |
| |
| - /* |
| + /* |
| * If the variable name begins with a '.', it could very well be one of |
| @@ -376,33 +413,33 @@ VarFind(const char *name, GNode *ctxt, int flags) |
| */ |
| - if (*name == '.' && isupper((unsigned char) name[1])) |
| - switch (name[1]) { |
| - case 'A': |
| - if (!strcmp(name, ".ALLSRC")) |
| - name = ALLSRC; |
| - if (!strcmp(name, ".ARCHIVE")) |
| - name = ARCHIVE; |
| - break; |
| - case 'I': |
| - if (!strcmp(name, ".IMPSRC")) |
| - name = IMPSRC; |
| - break; |
| - case 'M': |
| - if (!strcmp(name, ".MEMBER")) |
| - name = MEMBER; |
| - break; |
| - case 'O': |
| - if (!strcmp(name, ".OODATE")) |
| - name = OODATE; |
| - break; |
| - case 'P': |
| - if (!strcmp(name, ".PREFIX")) |
| - name = PREFIX; |
| - break; |
| - case 'T': |
| - if (!strcmp(name, ".TARGET")) |
| - name = TARGET; |
| - break; |
| - } |
| + if (*name == '.' && isupper((unsigned char) name[1])) |
| + switch (name[1]) { |
| + case 'A': |
| + if (!strcmp(name, ".ALLSRC")) |
| + name = ALLSRC; |
| + if (!strcmp(name, ".ARCHIVE")) |
| + name = ARCHIVE; |
| + break; |
| + case 'I': |
| + if (!strcmp(name, ".IMPSRC")) |
| + name = IMPSRC; |
| + break; |
| + case 'M': |
| + if (!strcmp(name, ".MEMBER")) |
| + name = MEMBER; |
| + break; |
| + case 'O': |
| + if (!strcmp(name, ".OODATE")) |
| + name = OODATE; |
| + break; |
| + case 'P': |
| + if (!strcmp(name, ".PREFIX")) |
| + name = PREFIX; |
| + break; |
| + case 'T': |
| + if (!strcmp(name, ".TARGET")) |
| + name = TARGET; |
| + break; |
| + } |
| #ifdef notyet |
| - /* for compatibility with gmake */ |
| + /* for compatibility with gmake */ |
| if (name[0] == '^' && name[1] == '\0') |
| @@ -419,48 +456,46 @@ VarFind(const char *name, GNode *ctxt, int flags) |
| if ((var == NULL) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) { |
| - var = Hash_FindEntry(&VAR_CMD->context, name); |
| + var = Hash_FindEntry(&VAR_CMD->context, name); |
| } |
| if (!checkEnvFirst && (var == NULL) && (flags & FIND_GLOBAL) && |
| - (ctxt != VAR_GLOBAL)) |
| - { |
| - var = Hash_FindEntry(&VAR_GLOBAL->context, name); |
| - if ((var == NULL) && (ctxt != VAR_INTERNAL)) { |
| - /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ |
| - var = Hash_FindEntry(&VAR_INTERNAL->context, name); |
| - } |
| + (ctxt != VAR_GLOBAL)) { |
| + var = Hash_FindEntry(&VAR_GLOBAL->context, name); |
| + if ((var == NULL) && (ctxt != VAR_INTERNAL)) { |
| + /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ |
| + var = Hash_FindEntry(&VAR_INTERNAL->context, name); |
| + } |
| } |
| if ((var == NULL) && (flags & FIND_ENV)) { |
| - char *env; |
| - |
| - if ((env = getenv(name)) != NULL) { |
| - int len; |
| - |
| - v = bmake_malloc(sizeof(Var)); |
| - v->name = bmake_strdup(name); |
| - |
| - len = strlen(env); |
| - |
| - Buf_Init(&v->val, len + 1); |
| - Buf_AddBytes(&v->val, len, env); |
| - |
| - v->flags = VAR_FROM_ENV; |
| - return (v); |
| - } else if (checkEnvFirst && (flags & FIND_GLOBAL) && |
| - (ctxt != VAR_GLOBAL)) |
| - { |
| - var = Hash_FindEntry(&VAR_GLOBAL->context, name); |
| - if ((var == NULL) && (ctxt != VAR_INTERNAL)) { |
| - var = Hash_FindEntry(&VAR_INTERNAL->context, name); |
| - } |
| - if (var == NULL) { |
| - return NULL; |
| - } else { |
| - return ((Var *)Hash_GetValue(var)); |
| - } |
| - } else { |
| - return NULL; |
| - } |
| + char *env; |
| + |
| + if ((env = getenv(name)) != NULL) { |
| + int len; |
| + |
| + v = bmake_malloc(sizeof(Var)); |
| + v->name = bmake_strdup(name); |
| + |
| + len = strlen(env); |
| + |
| + Buf_Init(&v->val, len + 1); |
| + Buf_AddBytes(&v->val, len, env); |
| + |
| + v->flags = VAR_FROM_ENV; |
| + return (v); |
| + } else if (checkEnvFirst && (flags & FIND_GLOBAL) && |
| + (ctxt != VAR_GLOBAL)) { |
| + var = Hash_FindEntry(&VAR_GLOBAL->context, name); |
| + if ((var == NULL) && (ctxt != VAR_INTERNAL)) { |
| + var = Hash_FindEntry(&VAR_INTERNAL->context, name); |
| + } |
| + if (var == NULL) { |
| + return NULL; |
| + } else { |
| + return ((Var *) Hash_GetValue(var)); |
| + } |
| + } else { |
| + return NULL; |
| + } |
| } else if (var == NULL) { |
| - return NULL; |
| + return NULL; |
| } else { |
| - return ((Var *)Hash_GetValue(var)); |
| + return ((Var *) Hash_GetValue(var)); |
| } |
| @@ -485,6 +520,5 @@ VarFind(const char *name, GNode *ctxt, int flags) |
| static Boolean |
| -VarFreeEnv(Var *v, Boolean destroy) |
| -{ |
| +VarFreeEnv(Var *v, Boolean destroy) { |
| if ((v->flags & VAR_FROM_ENV) == 0) |
| - return FALSE; |
| + return FALSE; |
| free(v->name); |
| @@ -515,7 +549,6 @@ VarFreeEnv(Var *v, Boolean destroy) |
| static void |
| -VarAdd(const char *name, const char *val, GNode *ctxt) |
| -{ |
| - Var *v; |
| - int len; |
| - Hash_Entry *h; |
| +VarAdd(const char *name, const char *val, GNode *ctxt) { |
| + Var *v; |
| + int len; |
| + Hash_Entry *h; |
| |
| @@ -524,3 +557,3 @@ VarAdd(const char *name, const char *val, GNode *ctxt) |
| len = val ? strlen(val) : 0; |
| - Buf_Init(&v->val, len+1); |
| + Buf_Init(&v->val, len + 1); |
| Buf_AddBytes(&v->val, len, val); |
| @@ -533,3 +566,3 @@ VarAdd(const char *name, const char *val, GNode *ctxt) |
| if (DEBUG(VAR) && (ctxt->flags & INTERNAL) == 0) { |
| - fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); |
| + fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); |
| } |
| @@ -551,11 +584,10 @@ VarAdd(const char *name, const char *val, GNode *ctxt) |
| void |
| -Var_Delete(const char *name, GNode *ctxt) |
| -{ |
| - Hash_Entry *ln; |
| +Var_Delete(const char *name, GNode *ctxt) { |
| + Hash_Entry *ln; |
| char *cp; |
| - |
| + |
| if (strchr(name, '$')) { |
| - cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES); |
| + cp = Var_Subst(NULL, name, VAR_GLOBAL, VARF_WANTRES); |
| } else { |
| - cp = (char *)name; |
| + cp = (char *) name; |
| } |
| @@ -563,23 +595,23 @@ Var_Delete(const char *name, GNode *ctxt) |
| if (DEBUG(VAR)) { |
| - fprintf(debug_file, "%s:delete %s%s\n", |
| - ctxt->name, cp, ln ? "" : " (not found)"); |
| + fprintf(debug_file, "%s:delete %s%s\n", |
| + ctxt->name, cp, ln ? "" : " (not found)"); |
| } |
| if (cp != name) { |
| - free(cp); |
| + free(cp); |
| } |
| if (ln != NULL) { |
| - Var *v; |
| + Var *v; |
| |
| - v = (Var *)Hash_GetValue(ln); |
| - if ((v->flags & VAR_EXPORTED)) { |
| - unsetenv(v->name); |
| - } |
| - if (strcmp(MAKE_EXPORTED, v->name) == 0) { |
| - var_exportedVars = VAR_EXPORTED_NONE; |
| - } |
| - if (v->name != ln->name) |
| - free(v->name); |
| - Hash_DeleteEntry(&ctxt->context, ln); |
| - Buf_Destroy(&v->val, TRUE); |
| - free(v); |
| + v = (Var *) Hash_GetValue(ln); |
| + if ((v->flags & VAR_EXPORTED)) { |
| + unsetenv(v->name); |
| + } |
| + if (strcmp(MAKE_EXPORTED, v->name) == 0) { |
| + var_exportedVars = VAR_EXPORTED_NONE; |
| + } |
| + if (v->name != ln->name) |
| + free(v->name); |
| + Hash_DeleteEntry(&ctxt->context, ln); |
| + Buf_Destroy(&v->val, TRUE); |
| + free(v); |
| } |
| @@ -596,4 +628,3 @@ Var_Delete(const char *name, GNode *ctxt) |
| static int |
| -Var_Export1(const char *name, int flags) |
| -{ |
| +Var_Export1(const char *name, int flags) { |
| char tmp[BUFSIZ]; |
| @@ -605,5 +636,5 @@ Var_Export1(const char *name, int flags) |
| if (*name == '.') |
| - return 0; /* skip internals */ |
| + return 0; /* skip internals */ |
| if (!name[1]) { |
| - /* |
| + /* |
| * A single char. |
| @@ -613,9 +644,9 @@ Var_Export1(const char *name, int flags) |
| */ |
| - switch (name[0]) { |
| - case '@': |
| - case '%': |
| - case '*': |
| - case '!': |
| - return 0; |
| - } |
| + switch (name[0]) { |
| + case '@': |
| + case '%': |
| + case '*': |
| + case '!': |
| + return 0; |
| + } |
| } |
| @@ -623,7 +654,7 @@ Var_Export1(const char *name, int flags) |
| if (v == NULL) { |
| - return 0; |
| + return 0; |
| } |
| if (!parent && |
| - (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) { |
| - return 0; /* nothing to do */ |
| + (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) { |
| + return 0; /* nothing to do */ |
| } |
| @@ -631,4 +662,4 @@ Var_Export1(const char *name, int flags) |
| if ((flags & VAR_EXPORT_LITERAL) == 0 && strchr(val, '$')) { |
| - if (parent) { |
| - /* |
| + if (parent) { |
| + /* |
| * Flag this as something we need to re-export. |
| @@ -637,7 +668,7 @@ Var_Export1(const char *name, int flags) |
| */ |
| - v->flags |= (VAR_EXPORTED|VAR_REEXPORT); |
| - return 1; |
| - } |
| - if (v->flags & VAR_IN_USE) { |
| - /* |
| + v->flags |= (VAR_EXPORTED | VAR_REEXPORT); |
| + return 1; |
| + } |
| + if (v->flags & VAR_IN_USE) { |
| + /* |
| * We recursed while exporting in a child. |
| @@ -645,17 +676,17 @@ Var_Export1(const char *name, int flags) |
| */ |
| - return 0; |
| - } |
| - n = snprintf(tmp, sizeof(tmp), "${%s}", name); |
| - if (n < (int)sizeof(tmp)) { |
| - val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); |
| - setenv(name, val, 1); |
| - free(val); |
| - } |
| + return 0; |
| + } |
| + n = snprintf(tmp, sizeof(tmp), "${%s}", name); |
| + if (n < (int) sizeof(tmp)) { |
| + val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); |
| + setenv(name, val, 1); |
| + free(val); |
| + } |
| } else { |
| - if (parent) { |
| - v->flags &= ~VAR_REEXPORT; /* once will do */ |
| - } |
| - if (parent || !(v->flags & VAR_EXPORTED)) { |
| - setenv(name, val, 1); |
| - } |
| + if (parent) { |
| + v->flags &= ~VAR_REEXPORT; /* once will do */ |
| + } |
| + if (parent || !(v->flags & VAR_EXPORTED)) { |
| + setenv(name, val, 1); |
| + } |
| } |
| @@ -665,3 +696,3 @@ Var_Export1(const char *name, int flags) |
| if (parent) { |
| - v->flags |= VAR_EXPORTED; |
| + v->flags |= VAR_EXPORTED; |
| } |
| @@ -674,7 +705,6 @@ Var_Export1(const char *name, int flags) |
| void |
| -Var_ExportVars(void) |
| -{ |
| +Var_ExportVars(void) { |
| char tmp[BUFSIZ]; |
| - Hash_Entry *var; |
| - Hash_Search state; |
| + Hash_Entry *var; |
| + Hash_Search state; |
| Var *v; |
| @@ -693,15 +723,15 @@ Var_ExportVars(void) |
| if (VAR_EXPORTED_NONE == var_exportedVars) |
| - return; |
| + return; |
| |
| if (VAR_EXPORTED_ALL == var_exportedVars) { |
| - /* |
| + /* |
| * Ouch! This is crazy... |
| */ |
| - for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state); |
| - var != NULL; |
| - var = Hash_EnumNext(&state)) { |
| - v = (Var *)Hash_GetValue(var); |
| - Var_Export1(v->name, 0); |
| - } |
| - return; |
| + for (var = Hash_EnumFirst(&VAR_GLOBAL->context, &state); |
| + var != NULL; |
| + var = Hash_EnumNext(&state)) { |
| + v = (Var *) Hash_GetValue(var); |
| + Var_Export1(v->name, 0); |
| + } |
| + return; |
| } |
| @@ -711,18 +741,18 @@ Var_ExportVars(void) |
| n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); |
| - if (n < (int)sizeof(tmp)) { |
| - char **av; |
| - char *as; |
| - int ac; |
| - int i; |
| - |
| - val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); |
| - if (*val) { |
| - av = brk_string(val, &ac, FALSE, &as); |
| - for (i = 0; i < ac; i++) { |
| - Var_Export1(av[i], 0); |
| - } |
| - free(as); |
| - free(av); |
| - } |
| - free(val); |
| + if (n < (int) sizeof(tmp)) { |
| + char **av; |
| + char *as; |
| + int ac; |
| + int i; |
| + |
| + val = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); |
| + if (*val) { |
| + av = brk_string(val, &ac, FALSE, &as); |
| + for (i = 0; i < ac; i++) { |
| + Var_Export1(av[i], 0); |
| + } |
| + free(as); |
| + free(av); |
| + } |
| + free(val); |
| } |
| @@ -736,4 +766,3 @@ Var_ExportVars(void) |
| void |
| -Var_Export(char *str, int isExport) |
| -{ |
| +Var_Export(char *str, int isExport) { |
| char *name; |
| @@ -747,4 +776,4 @@ Var_Export(char *str, int isExport) |
| if (isExport && (!str || !str[0])) { |
| - var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ |
| - return; |
| + var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */ |
| + return; |
| } |
| @@ -753,8 +782,8 @@ Var_Export(char *str, int isExport) |
| if (strncmp(str, "-env", 4) == 0) { |
| - str += 4; |
| + str += 4; |
| } else if (strncmp(str, "-literal", 8) == 0) { |
| - str += 8; |
| - flags |= VAR_EXPORT_LITERAL; |
| + str += 8; |
| + flags |= VAR_EXPORT_LITERAL; |
| } else { |
| - flags |= VAR_EXPORT_PARENT; |
| + flags |= VAR_EXPORT_PARENT; |
| } |
| @@ -762,7 +791,7 @@ Var_Export(char *str, int isExport) |
| if (*val) { |
| - av = brk_string(val, &ac, FALSE, &as); |
| - for (i = 0; i < ac; i++) { |
| - name = av[i]; |
| - if (!name[1]) { |
| - /* |
| + av = brk_string(val, &ac, FALSE, &as); |
| + for (i = 0; i < ac; i++) { |
| + name = av[i]; |
| + if (!name[1]) { |
| + /* |
| * A single char. |
| @@ -772,20 +801,20 @@ Var_Export(char *str, int isExport) |
| */ |
| - switch (name[0]) { |
| - case '@': |
| - case '%': |
| - case '*': |
| - case '!': |
| - continue; |
| - } |
| - } |
| - if (Var_Export1(name, flags)) { |
| - if (VAR_EXPORTED_ALL != var_exportedVars) |
| - var_exportedVars = VAR_EXPORTED_YES; |
| - if (isExport && (flags & VAR_EXPORT_PARENT)) { |
| - Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); |
| - } |
| - } |
| - } |
| - free(as); |
| - free(av); |
| + switch (name[0]) { |
| + case '@': |
| + case '%': |
| + case '*': |
| + case '!': |
| + continue; |
| + } |
| + } |
| + if (Var_Export1(name, flags)) { |
| + if (VAR_EXPORTED_ALL != var_exportedVars) |
| + var_exportedVars = VAR_EXPORTED_YES; |
| + if (isExport && (flags & VAR_EXPORT_PARENT)) { |
| + Var_Append(MAKE_EXPORTED, name, VAR_GLOBAL); |
| + } |
| + } |
| + } |
| + free(as); |
| + free(av); |
| } |
| @@ -801,4 +830,3 @@ extern char **environ; |
| void |
| -Var_UnExport(char *str) |
| -{ |
| +Var_UnExport(char *str) { |
| char tmp[BUFSIZ]; |
| @@ -810,3 +838,3 @@ Var_UnExport(char *str) |
| if (!str || !str[0]) { |
| - return; /* assert? */ |
| + return; /* assert? */ |
| } |
| @@ -818,29 +846,29 @@ Var_UnExport(char *str) |
| if (unexport_env) { |
| - char **newenv; |
| - |
| - cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ |
| - if (environ == savedEnv) { |
| - /* we have been here before! */ |
| - newenv = bmake_realloc(environ, 2 * sizeof(char *)); |
| - } else { |
| - if (savedEnv) { |
| - free(savedEnv); |
| - savedEnv = NULL; |
| - } |
| - newenv = bmake_malloc(2 * sizeof(char *)); |
| - } |
| - if (!newenv) |
| - return; |
| - /* Note: we cannot safely free() the original environ. */ |
| - environ = savedEnv = newenv; |
| - newenv[0] = NULL; |
| - newenv[1] = NULL; |
| - if (cp && *cp) |
| - setenv(MAKE_LEVEL_ENV, cp, 1); |
| + char **newenv; |
| + |
| + cp = getenv(MAKE_LEVEL_ENV); /* we should preserve this */ |
| + if (environ == savedEnv) { |
| + /* we have been here before! */ |
| + newenv = bmake_realloc(environ, 2 * sizeof(char *)); |
| + } else { |
| + if (savedEnv) { |
| + free(savedEnv); |
| + savedEnv = NULL; |
| + } |
| + newenv = bmake_malloc(2 * sizeof(char *)); |
| + } |
| + if (!newenv) |
| + return; |
| + /* Note: we cannot safely free() the original environ. */ |
| + environ = savedEnv = newenv; |
| + newenv[0] = NULL; |
| + newenv[1] = NULL; |
| + if (cp && *cp) |
| + setenv(MAKE_LEVEL_ENV, cp, 1); |
| } else { |
| - for (; *str != '\n' && isspace((unsigned char) *str); str++) |
| - continue; |
| - if (str[0] && str[0] != '\n') { |
| - vlist = str; |
| - } |
| + for (; *str != '\n' && isspace((unsigned char) *str); str++) |
| + continue; |
| + if (str[0] && str[0] != '\n') { |
| + vlist = str; |
| + } |
| } |
| @@ -848,26 +876,26 @@ Var_UnExport(char *str) |
| if (!vlist) { |
| - /* Using .MAKE.EXPORTED */ |
| - n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); |
| - if (n < (int)sizeof(tmp)) { |
| - vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); |
| - } |
| + /* Using .MAKE.EXPORTED */ |
| + n = snprintf(tmp, sizeof(tmp), "${" MAKE_EXPORTED ":O:u}"); |
| + if (n < (int) sizeof(tmp)) { |
| + vlist = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); |
| + } |
| } |
| if (vlist) { |
| - Var *v; |
| - char **av; |
| - char *as; |
| - int ac; |
| - int i; |
| - |
| - av = brk_string(vlist, &ac, FALSE, &as); |
| - for (i = 0; i < ac; i++) { |
| - v = VarFind(av[i], VAR_GLOBAL, 0); |
| - if (!v) |
| - continue; |
| - if (!unexport_env && |
| - (v->flags & (VAR_EXPORTED|VAR_REEXPORT)) == VAR_EXPORTED) { |
| - unsetenv(v->name); |
| - } |
| - v->flags &= ~(VAR_EXPORTED|VAR_REEXPORT); |
| - /* |
| + Var *v; |
| + char **av; |
| + char *as; |
| + int ac; |
| + int i; |
| + |
| + av = brk_string(vlist, &ac, FALSE, &as); |
| + for (i = 0; i < ac; i++) { |
| + v = VarFind(av[i], VAR_GLOBAL, 0); |
| + if (!v) |
| + continue; |
| + if (!unexport_env && |
| + (v->flags & (VAR_EXPORTED | VAR_REEXPORT)) == VAR_EXPORTED) { |
| + unsetenv(v->name); |
| + } |
| + v->flags &= ~(VAR_EXPORTED | VAR_REEXPORT); |
| + /* |
| * If we are unexporting a list, |
| @@ -877,18 +905,18 @@ Var_UnExport(char *str) |
| */ |
| - if (vlist == str) { |
| - n = snprintf(tmp, sizeof(tmp), |
| - "${" MAKE_EXPORTED ":N%s}", v->name); |
| - if (n < (int)sizeof(tmp)) { |
| - cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); |
| - Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL, 0); |
| - free(cp); |
| - } |
| - } |
| - } |
| - free(as); |
| - free(av); |
| - if (vlist != str) { |
| - Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); |
| - free(vlist); |
| - } |
| + if (vlist == str) { |
| + n = snprintf(tmp, sizeof(tmp), |
| + "${" MAKE_EXPORTED ":N%s}", v->name); |
| + if (n < (int) sizeof(tmp)) { |
| + cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); |
| + Var_Set(MAKE_EXPORTED, cp, VAR_GLOBAL, 0); |
| + free(cp); |
| + } |
| + } |
| + } |
| + free(as); |
| + free(av); |
| + if (vlist != str) { |
| + Var_Delete(MAKE_EXPORTED, VAR_GLOBAL); |
| + free(vlist); |
| + } |
| } |
| @@ -925,7 +953,20 @@ Var_UnExport(char *str) |
| void |
| -Var_Set(const char *name, const char *val, GNode *ctxt, int flags) |
| -{ |
| - Var *v; |
| +Var_Set(const char *name, const char *val, GNode *ctxt, int flags) { |
| + Var *v; |
| char *expanded_name = NULL; |
| |
| + |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| + char *unix_val; |
| + char *error; |
| + if (val && strlen(val) > 0 && val[1] == ':' && (val[2] == '/' || val[2] == '\\')) { |
| + unix_val = Cmd_Exec(getUnixPathCmd(val), &error); |
| + } |
| + else { |
| + unix_val = val; |
| + } |
| +#else |
| + const char *unix_val = val; |
| +#endif |
| + |
| /* |
| @@ -936,25 +977,25 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) |
| if (strchr(name, '$') != NULL) { |
| - expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); |
| - if (expanded_name[0] == 0) { |
| - if (DEBUG(VAR)) { |
| - fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " |
| - "name expands to empty string - ignored\n", |
| - name, val); |
| - } |
| - free(expanded_name); |
| - return; |
| - } |
| - name = expanded_name; |
| + expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); |
| + if (expanded_name[0] == 0) { |
| + if (DEBUG(VAR)) { |
| + fprintf(debug_file, "Var_Set(\"%s\", \"%s\", ...) " |
| + "name expands to empty string - ignored\n", |
| + name, unix_val); |
| + } |
| + free(expanded_name); |
| + return; |
| + } |
| + name = expanded_name; |
| } |
| if (ctxt == VAR_GLOBAL) { |
| - v = VarFind(name, VAR_CMD, 0); |
| - if (v != NULL) { |
| - if ((v->flags & VAR_FROM_CMD)) { |
| - if (DEBUG(VAR)) { |
| - fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, val); |
| - } |
| - goto out; |
| - } |
| - VarFreeEnv(v, TRUE); |
| - } |
| + v = VarFind(name, VAR_CMD, 0); |
| + if (v != NULL) { |
| + if ((v->flags & VAR_FROM_CMD)) { |
| + if (DEBUG(VAR)) { |
| + fprintf(debug_file, "%s:%s = %s ignored!\n", ctxt->name, name, unix_val); |
| + } |
| + goto out; |
| + } |
| + VarFreeEnv(v, TRUE); |
| + } |
| } |
| @@ -962,4 +1003,4 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) |
| if (v == NULL) { |
| - if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { |
| - /* |
| + if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { |
| + /* |
| * This var would normally prevent the same name being added |
| @@ -968,16 +1009,16 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) |
| */ |
| - Var_Delete(name, VAR_GLOBAL); |
| - } |
| - VarAdd(name, val, ctxt); |
| + Var_Delete(name, VAR_GLOBAL); |
| + } |
| + VarAdd(name, unix_val, ctxt); |
| } else { |
| - Buf_Empty(&v->val); |
| - if (val) |
| - Buf_AddBytes(&v->val, strlen(val), val); |
| + Buf_Empty(&v->val); |
| + if (unix_val) |
| + Buf_AddBytes(&v->val, strlen(unix_val), unix_val); |
| |
| - if (DEBUG(VAR)) { |
| - fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, val); |
| - } |
| - if ((v->flags & VAR_EXPORTED)) { |
| - Var_Export1(name, VAR_EXPORT_PARENT); |
| - } |
| + if (DEBUG(VAR)) { |
| + fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, unix_val); |
| + } |
| + if ((v->flags & VAR_EXPORTED)) { |
| + Var_Export1(name, VAR_EXPORT_PARENT); |
| + } |
| } |
| @@ -988,9 +1029,9 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) |
| if (ctxt == VAR_CMD && (flags & VAR_NO_EXPORT) == 0) { |
| - if (v == NULL) { |
| - /* we just added it */ |
| - v = VarFind(name, ctxt, 0); |
| - } |
| - if (v != NULL) |
| - v->flags |= VAR_FROM_CMD; |
| - /* |
| + if (v == NULL) { |
| + /* we just added it */ |
| + v = VarFind(name, ctxt, 0); |
| + } |
| + if (v != NULL) |
| + v->flags |= VAR_FROM_CMD; |
| + /* |
| * If requested, don't export these in the environment |
| @@ -1000,16 +1041,16 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) |
| */ |
| - if (varNoExportEnv != TRUE) |
| - setenv(name, val ? val : "", 1); |
| + if (varNoExportEnv != TRUE) |
| + setenv(name, unix_val ? unix_val : "", 1); |
| |
| - Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); |
| + Var_Append(MAKEOVERRIDES, name, VAR_GLOBAL); |
| } |
| if (*name == '.') { |
| - if (strcmp(name, SAVE_DOLLARS) == 0) |
| - save_dollars = s2Boolean(val, save_dollars); |
| + if (strcmp(name, SAVE_DOLLARS) == 0) |
| + save_dollars = s2Boolean(unix_val, save_dollars); |
| } |
| |
| - out: |
| + out: |
| free(expanded_name); |
| if (v != NULL) |
| - VarFreeEnv(v, TRUE); |
| + VarFreeEnv(v, TRUE); |
| } |
| @@ -1044,6 +1085,5 @@ Var_Set(const char *name, const char *val, GNode *ctxt, int flags) |
| void |
| -Var_Append(const char *name, const char *val, GNode *ctxt) |
| -{ |
| - Var *v; |
| - Hash_Entry *h; |
| +Var_Append(const char *name, const char *val, GNode *ctxt) { |
| + Var *v; |
| + Hash_Entry *h; |
| char *expanded_name = NULL; |
| @@ -1051,30 +1091,30 @@ Var_Append(const char *name, const char *val, GNode *ctxt) |
| if (strchr(name, '$') != NULL) { |
| - expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); |
| - if (expanded_name[0] == 0) { |
| - if (DEBUG(VAR)) { |
| - fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " |
| - "name expands to empty string - ignored\n", |
| - name, val); |
| - } |
| - free(expanded_name); |
| - return; |
| - } |
| - name = expanded_name; |
| + expanded_name = Var_Subst(NULL, name, ctxt, VARF_WANTRES); |
| + if (expanded_name[0] == 0) { |
| + if (DEBUG(VAR)) { |
| + fprintf(debug_file, "Var_Append(\"%s\", \"%s\", ...) " |
| + "name expands to empty string - ignored\n", |
| + name, val); |
| + } |
| + free(expanded_name); |
| + return; |
| + } |
| + name = expanded_name; |
| } |
| |
| - v = VarFind(name, ctxt, (ctxt == VAR_GLOBAL) ? (FIND_CMD|FIND_ENV) : 0); |
| + v = VarFind(name, ctxt, (ctxt == VAR_GLOBAL) ? (FIND_CMD | FIND_ENV) : 0); |
| |
| if (v == NULL) { |
| - Var_Set(name, val, ctxt, 0); |
| + Var_Set(name, val, ctxt, 0); |
| } else if (ctxt == VAR_CMD || !(v->flags & VAR_FROM_CMD)) { |
| - Buf_AddByte(&v->val, ' '); |
| - Buf_AddBytes(&v->val, strlen(val), val); |
| + Buf_AddByte(&v->val, ' '); |
| + Buf_AddBytes(&v->val, strlen(val), val); |
| |
| - if (DEBUG(VAR)) { |
| - fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, |
| - Buf_GetAll(&v->val, NULL)); |
| - } |
| + if (DEBUG(VAR)) { |
| + fprintf(debug_file, "%s:%s = %s\n", ctxt->name, name, |
| + Buf_GetAll(&v->val, NULL)); |
| + } |
| |
| - if (v->flags & VAR_FROM_ENV) { |
| - /* |
| + if (v->flags & VAR_FROM_ENV) { |
| + /* |
| * If the original variable came from the environment, we |
| @@ -1084,6 +1124,6 @@ Var_Append(const char *name, const char *val, GNode *ctxt) |
| */ |
| - v->flags &= ~VAR_FROM_ENV; |
| - h = Hash_CreateEntry(&ctxt->context, name, NULL); |
| - Hash_SetValue(h, v); |
| - } |
| + v->flags &= ~VAR_FROM_ENV; |
| + h = Hash_CreateEntry(&ctxt->context, name, NULL); |
| + Hash_SetValue(h, v); |
| + } |
| } |
| @@ -1110,18 +1150,17 @@ Var_Append(const char *name, const char *val, GNode *ctxt) |
| Boolean |
| -Var_Exists(const char *name, GNode *ctxt) |
| -{ |
| - Var *v; |
| - char *cp; |
| +Var_Exists(const char *name, GNode *ctxt) { |
| + Var *v; |
| + char *cp; |
| |
| if ((cp = strchr(name, '$')) != NULL) { |
| - cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES); |
| + cp = Var_Subst(NULL, name, ctxt, VARF_WANTRES); |
| } |
| - v = VarFind(cp ? cp : name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV); |
| + v = VarFind(cp ? cp : name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV); |
| free(cp); |
| if (v == NULL) { |
| - return(FALSE); |
| + return (FALSE); |
| } else { |
| - (void)VarFreeEnv(v, TRUE); |
| + (void) VarFreeEnv(v, TRUE); |
| } |
| - return(TRUE); |
| + return (TRUE); |
| } |
| @@ -1145,5 +1184,4 @@ Var_Exists(const char *name, GNode *ctxt) |
| char * |
| -Var_Value(const char *name, GNode *ctxt, char **frp) |
| -{ |
| - Var *v; |
| +Var_Value(const char *name, GNode *ctxt, char **frp) { |
| + Var *v; |
| |
| @@ -1152,8 +1190,20 @@ Var_Value(const char *name, GNode *ctxt, char **frp) |
| if (v != NULL) { |
| - char *p = (Buf_GetAll(&v->val, NULL)); |
| - if (VarFreeEnv(v, FALSE)) |
| - *frp = p; |
| - return p; |
| + char *raw = (Buf_GetAll(&v->val, NULL)); |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| + char *p; |
| + const char *error; |
| + if ((raw[1] == ':') && (raw[2] == '/' || raw[2] == '\\')) { // it is windows path |
| + p = Cmd_Exec(getUnixPathCmd(raw), &error); |
| + } |
| + else { |
| + p = raw; |
| + } |
| +#else |
| + char *p = raw; |
| +#endif |
| + if (VarFreeEnv(v, FALSE)) |
| + *frp = p; |
| + return p; |
| } else { |
| - return NULL; |
| + return NULL; |
| } |
| @@ -1184,5 +1234,4 @@ static Boolean |
| VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *dummy MAKE_ATTR_UNUSED) |
| -{ |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *dummy MAKE_ATTR_UNUSED) { |
| char *slash; |
| @@ -1191,16 +1240,16 @@ VarHead(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| if (slash != NULL) { |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - } |
| - *slash = '\0'; |
| - Buf_AddBytes(buf, strlen(word), word); |
| - *slash = '/'; |
| - return (TRUE); |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + } |
| + *slash = '\0'; |
| + Buf_AddBytes(buf, strlen(word), word); |
| + *slash = '/'; |
| + return (TRUE); |
| } else { |
| - /* |
| + /* |
| * If no directory part, give . (q.v. the POSIX standard) |
| */ |
| - if (addSpace && vpstate->varSpace) |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - Buf_AddByte(buf, '.'); |
| + if (addSpace && vpstate->varSpace) |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + Buf_AddByte(buf, '.'); |
| } |
| @@ -1232,5 +1281,4 @@ static Boolean |
| VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *dummy MAKE_ATTR_UNUSED) |
| -{ |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *dummy MAKE_ATTR_UNUSED) { |
| char *slash; |
| @@ -1238,3 +1286,3 @@ VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| + Buf_AddByte(buf, vpstate->varSpace); |
| } |
| @@ -1243,7 +1291,7 @@ VarTail(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| if (slash != NULL) { |
| - *slash++ = '\0'; |
| - Buf_AddBytes(buf, strlen(slash), slash); |
| - slash[-1] = '/'; |
| + *slash++ = '\0'; |
| + Buf_AddBytes(buf, strlen(slash), slash); |
| + slash[-1] = '/'; |
| } else { |
| - Buf_AddBytes(buf, strlen(word), word); |
| + Buf_AddBytes(buf, strlen(word), word); |
| } |
| @@ -1274,5 +1322,4 @@ static Boolean |
| VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *dummy MAKE_ATTR_UNUSED) |
| -{ |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *dummy MAKE_ATTR_UNUSED) { |
| char *dot; |
| @@ -1281,9 +1328,9 @@ VarSuffix(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| if (dot != NULL) { |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - } |
| - *dot++ = '\0'; |
| - Buf_AddBytes(buf, strlen(dot), dot); |
| - dot[-1] = '.'; |
| - addSpace = TRUE; |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + } |
| + *dot++ = '\0'; |
| + Buf_AddBytes(buf, strlen(dot), dot); |
| + dot[-1] = '.'; |
| + addSpace = TRUE; |
| } |
| @@ -1315,5 +1362,4 @@ static Boolean |
| VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *dummy MAKE_ATTR_UNUSED) |
| -{ |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *dummy MAKE_ATTR_UNUSED) { |
| char *dot; |
| @@ -1321,3 +1367,3 @@ VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| + Buf_AddByte(buf, vpstate->varSpace); |
| } |
| @@ -1326,7 +1372,7 @@ VarRoot(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| if (dot != NULL) { |
| - *dot = '\0'; |
| - Buf_AddBytes(buf, strlen(word), word); |
| - *dot = '.'; |
| + *dot = '\0'; |
| + Buf_AddBytes(buf, strlen(word), word); |
| + *dot = '.'; |
| } else { |
| - Buf_AddBytes(buf, strlen(word), word); |
| + Buf_AddBytes(buf, strlen(word), word); |
| } |
| @@ -1359,15 +1405,14 @@ static Boolean |
| VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *pattern) |
| -{ |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *pattern) { |
| if (DEBUG(VAR)) |
| - fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *)pattern); |
| - if (Str_Match(word, (char *)pattern)) { |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - } |
| - addSpace = TRUE; |
| - Buf_AddBytes(buf, strlen(word), word); |
| + fprintf(debug_file, "VarMatch [%s] [%s]\n", word, (char *) pattern); |
| + if (Str_Match(word, (char *) pattern)) { |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + } |
| + addSpace = TRUE; |
| + Buf_AddBytes(buf, strlen(word), word); |
| } |
| - return(addSpace); |
| + return (addSpace); |
| } |
| @@ -1375,2 +1420,3 @@ VarMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| #ifdef SYSVVARSUB |
| + |
| /*- |
| @@ -1400,8 +1446,7 @@ static Boolean |
| VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *patp) |
| -{ |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *patp) { |
| int len; |
| char *ptr; |
| - VarPattern *pat = (VarPattern *)patp; |
| + VarPattern *pat = (VarPattern *) patp; |
| char *varexp; |
| @@ -1409,3 +1454,3 @@ VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, |
| if (addSpace && vpstate->varSpace) |
| - Buf_AddByte(buf, vpstate->varSpace); |
| + Buf_AddByte(buf, vpstate->varSpace); |
| |
| @@ -1415,10 +1460,11 @@ VarSYSVMatch(GNode *ctx, Var_Parse_State *vpstate, |
| varexp = Var_Subst(NULL, pat->rhs, ctx, VARF_WANTRES); |
| - Str_SYSVSubst(buf, varexp, ptr, len); |
| - free(varexp); |
| + Str_SYSVSubst(buf, varexp, ptr, len); |
| + free(varexp); |
| } else { |
| - Buf_AddBytes(buf, strlen(word), word); |
| + Buf_AddBytes(buf, strlen(word), word); |
| } |
| |
| - return(addSpace); |
| + return (addSpace); |
| } |
| + |
| #endif |
| @@ -1450,13 +1496,12 @@ static Boolean |
| VarNoMatch(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *pattern) |
| -{ |
| - if (!Str_Match(word, (char *)pattern)) { |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - } |
| - addSpace = TRUE; |
| - Buf_AddBytes(buf, strlen(word), word); |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *pattern) { |
| + if (!Str_Match(word, (char *) pattern)) { |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + } |
| + addSpace = TRUE; |
| + Buf_AddBytes(buf, strlen(word), word); |
| } |
| - return(addSpace); |
| + return (addSpace); |
| } |
| @@ -1487,13 +1532,12 @@ static Boolean |
| VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *patternp) |
| -{ |
| - int wordLen; /* Length of word */ |
| - char *cp; /* General pointer */ |
| - VarPattern *pattern = (VarPattern *)patternp; |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *patternp) { |
| + int wordLen; /* Length of word */ |
| + char *cp; /* General pointer */ |
| + VarPattern *pattern = (VarPattern *) patternp; |
| |
| wordLen = strlen(word); |
| - if ((pattern->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) != |
| - (VAR_SUB_ONE|VAR_SUB_MATCHED)) { |
| - /* |
| + if ((pattern->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) != |
| + (VAR_SUB_ONE | VAR_SUB_MATCHED)) { |
| + /* |
| * Still substituting -- break it down into simple anchored cases |
| @@ -1501,10 +1545,10 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| */ |
| - if ((pattern->flags & VAR_MATCH_START) && |
| - (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { |
| - /* |
| + if ((pattern->flags & VAR_MATCH_START) && |
| + (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { |
| + /* |
| * Anchored at start and beginning of word matches pattern |
| */ |
| - if ((pattern->flags & VAR_MATCH_END) && |
| - (wordLen == pattern->leftLen)) { |
| - /* |
| + if ((pattern->flags & VAR_MATCH_END) && |
| + (wordLen == pattern->leftLen)) { |
| + /* |
| * Also anchored at end and matches to the end (word |
| @@ -1513,37 +1557,37 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| */ |
| - if (pattern->rightLen != 0) { |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - } |
| - addSpace = TRUE; |
| - Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
| - } |
| - pattern->flags |= VAR_SUB_MATCHED; |
| - } else if (pattern->flags & VAR_MATCH_END) { |
| - /* |
| + if (pattern->rightLen != 0) { |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + } |
| + addSpace = TRUE; |
| + Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
| + } |
| + pattern->flags |= VAR_SUB_MATCHED; |
| + } else if (pattern->flags & VAR_MATCH_END) { |
| + /* |
| * Doesn't match to end -- copy word wholesale |
| */ |
| - goto nosub; |
| - } else { |
| - /* |
| + goto nosub; |
| + } else { |
| + /* |
| * Matches at start but need to copy in trailing characters |
| */ |
| - if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){ |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - } |
| - addSpace = TRUE; |
| - } |
| - Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
| - Buf_AddBytes(buf, wordLen - pattern->leftLen, |
| - (word + pattern->leftLen)); |
| - pattern->flags |= VAR_SUB_MATCHED; |
| - } |
| - } else if (pattern->flags & VAR_MATCH_START) { |
| - /* |
| + if ((pattern->rightLen + wordLen - pattern->leftLen) != 0) { |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + } |
| + addSpace = TRUE; |
| + } |
| + Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
| + Buf_AddBytes(buf, wordLen - pattern->leftLen, |
| + (word + pattern->leftLen)); |
| + pattern->flags |= VAR_SUB_MATCHED; |
| + } |
| + } else if (pattern->flags & VAR_MATCH_START) { |
| + /* |
| * Had to match at start of word and didn't -- copy whole word. |
| */ |
| - goto nosub; |
| - } else if (pattern->flags & VAR_MATCH_END) { |
| - /* |
| + goto nosub; |
| + } else if (pattern->flags & VAR_MATCH_END) { |
| + /* |
| * Anchored at end, Find only place match could occur (leftLen |
| @@ -1553,6 +1597,6 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| */ |
| - cp = word + (wordLen - pattern->leftLen); |
| - if ((cp >= word) && |
| - (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { |
| - /* |
| + cp = word + (wordLen - pattern->leftLen); |
| + if ((cp >= word) && |
| + (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { |
| + /* |
| * Match found. If we will place characters in the buffer, |
| @@ -1562,19 +1606,19 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| */ |
| - if (((cp - word) + pattern->rightLen) != 0) { |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - } |
| - addSpace = TRUE; |
| - } |
| - Buf_AddBytes(buf, cp - word, word); |
| - Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
| - pattern->flags |= VAR_SUB_MATCHED; |
| - } else { |
| - /* |
| + if (((cp - word) + pattern->rightLen) != 0) { |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + } |
| + addSpace = TRUE; |
| + } |
| + Buf_AddBytes(buf, cp - word, word); |
| + Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
| + pattern->flags |= VAR_SUB_MATCHED; |
| + } else { |
| + /* |
| * Had to match at end and didn't. Copy entire word. |
| */ |
| - goto nosub; |
| - } |
| - } else { |
| - /* |
| + goto nosub; |
| + } |
| + } else { |
| + /* |
| * Pattern is unanchored: search for the pattern in the word using |
| @@ -1589,36 +1633,36 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| */ |
| - Boolean done; |
| - int origSize; |
| - |
| - done = FALSE; |
| - origSize = Buf_Size(buf); |
| - while (!done) { |
| - cp = Str_FindSubstring(word, pattern->lhs); |
| - if (cp != NULL) { |
| - if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - addSpace = FALSE; |
| - } |
| - Buf_AddBytes(buf, cp-word, word); |
| - Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
| - wordLen -= (cp - word) + pattern->leftLen; |
| - word = cp + pattern->leftLen; |
| - if (wordLen == 0) { |
| - done = TRUE; |
| - } |
| - if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { |
| - done = TRUE; |
| - } |
| - pattern->flags |= VAR_SUB_MATCHED; |
| - } else { |
| - done = TRUE; |
| - } |
| - } |
| - if (wordLen != 0) { |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - } |
| - Buf_AddBytes(buf, wordLen, word); |
| - } |
| - /* |
| + Boolean done; |
| + int origSize; |
| + |
| + done = FALSE; |
| + origSize = Buf_Size(buf); |
| + while (!done) { |
| + cp = Str_FindSubstring(word, pattern->lhs); |
| + if (cp != NULL) { |
| + if (addSpace && (((cp - word) + pattern->rightLen) != 0)) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + addSpace = FALSE; |
| + } |
| + Buf_AddBytes(buf, cp - word, word); |
| + Buf_AddBytes(buf, pattern->rightLen, pattern->rhs); |
| + wordLen -= (cp - word) + pattern->leftLen; |
| + word = cp + pattern->leftLen; |
| + if (wordLen == 0) { |
| + done = TRUE; |
| + } |
| + if ((pattern->flags & VAR_SUB_GLOBAL) == 0) { |
| + done = TRUE; |
| + } |
| + pattern->flags |= VAR_SUB_MATCHED; |
| + } else { |
| + done = TRUE; |
| + } |
| + } |
| + if (wordLen != 0) { |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + } |
| + Buf_AddBytes(buf, wordLen, word); |
| + } |
| + /* |
| * If added characters to the buffer, need to add a space |
| @@ -1627,12 +1671,12 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| */ |
| - return ((Buf_Size(buf) != origSize) || addSpace); |
| - } |
| - return (addSpace); |
| + return ((Buf_Size(buf) != origSize) || addSpace); |
| + } |
| + return (addSpace); |
| } |
| - nosub: |
| + nosub: |
| if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| + Buf_AddByte(buf, vpstate->varSpace); |
| } |
| Buf_AddBytes(buf, wordLen, word); |
| - return(TRUE); |
| + return (TRUE); |
| } |
| @@ -1640,2 +1684,3 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| #ifndef NO_REGEX |
| + |
| /*- |
| @@ -1654,4 +1699,3 @@ VarSubstitute(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| static void |
| -VarREError(int reerr, regex_t *pat, const char *str) |
| -{ |
| +VarREError(int reerr, regex_t *pat, const char *str) { |
| char *errbuf; |
| @@ -1683,6 +1727,5 @@ static Boolean |
| VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, |
| - Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *patternp) |
| -{ |
| + Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *patternp) { |
| VarREPattern *pat; |
| @@ -1694,6 +1737,6 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, |
| |
| -#define MAYBE_ADD_SPACE() \ |
| - if (addSpace && !added) \ |
| - Buf_AddByte(buf, ' '); \ |
| - added = 1 |
| +#define MAYBE_ADD_SPACE() \ |
| + if (addSpace && !added) \ |
| + Buf_AddByte(buf, ' '); \ |
| + added = 1 |
| |
| @@ -1703,8 +1746,8 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, |
| |
| - if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) == |
| - (VAR_SUB_ONE|VAR_SUB_MATCHED)) |
| - xrv = REG_NOMATCH; |
| + if ((pat->flags & (VAR_SUB_ONE | VAR_SUB_MATCHED)) == |
| + (VAR_SUB_ONE | VAR_SUB_MATCHED)) |
| + xrv = REG_NOMATCH; |
| else { |
| - tryagain: |
| - xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); |
| + tryagain: |
| + xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); |
| } |
| @@ -1712,88 +1755,87 @@ VarRESubstitute(GNode *ctx MAKE_ATTR_UNUSED, |
| switch (xrv) { |
| - case 0: |
| - pat->flags |= VAR_SUB_MATCHED; |
| - if (pat->matches[0].rm_so > 0) { |
| - MAYBE_ADD_SPACE(); |
| - Buf_AddBytes(buf, pat->matches[0].rm_so, wp); |
| - } |
| - |
| - for (rp = pat->replace; *rp; rp++) { |
| - if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { |
| - MAYBE_ADD_SPACE(); |
| - Buf_AddByte(buf,rp[1]); |
| - rp++; |
| - } |
| - else if ((*rp == '&') || |
| - ((*rp == '\\') && isdigit((unsigned char)rp[1]))) { |
| - int n; |
| - const char *subbuf; |
| - int sublen; |
| - char errstr[3]; |
| - |
| - if (*rp == '&') { |
| - n = 0; |
| - errstr[0] = '&'; |
| - errstr[1] = '\0'; |
| - } else { |
| - n = rp[1] - '0'; |
| - errstr[0] = '\\'; |
| - errstr[1] = rp[1]; |
| - errstr[2] = '\0'; |
| - rp++; |
| - } |
| - |
| - if (n > pat->nsub) { |
| - Error("No subexpression %s", &errstr[0]); |
| - subbuf = ""; |
| - sublen = 0; |
| - } else if ((pat->matches[n].rm_so == -1) && |
| - (pat->matches[n].rm_eo == -1)) { |
| - Error("No match for subexpression %s", &errstr[0]); |
| - subbuf = ""; |
| - sublen = 0; |
| - } else { |
| - subbuf = wp + pat->matches[n].rm_so; |
| - sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; |
| - } |
| - |
| - if (sublen > 0) { |
| - MAYBE_ADD_SPACE(); |
| - Buf_AddBytes(buf, sublen, subbuf); |
| - } |
| - } else { |
| - MAYBE_ADD_SPACE(); |
| - Buf_AddByte(buf, *rp); |
| - } |
| - } |
| - wp += pat->matches[0].rm_eo; |
| - if (pat->flags & VAR_SUB_GLOBAL) { |
| - flags |= REG_NOTBOL; |
| - if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { |
| - MAYBE_ADD_SPACE(); |
| - Buf_AddByte(buf, *wp); |
| - wp++; |
| - |
| - } |
| - if (*wp) |
| - goto tryagain; |
| - } |
| - if (*wp) { |
| - MAYBE_ADD_SPACE(); |
| - Buf_AddBytes(buf, strlen(wp), wp); |
| - } |
| - break; |
| - default: |
| - VarREError(xrv, &pat->re, "Unexpected regex error"); |
| - /* fall through */ |
| - case REG_NOMATCH: |
| - if (*wp) { |
| - MAYBE_ADD_SPACE(); |
| - Buf_AddBytes(buf,strlen(wp),wp); |
| - } |
| - break; |
| - } |
| - return(addSpace||added); |
| + case 0: |
| + pat->flags |= VAR_SUB_MATCHED; |
| + if (pat->matches[0].rm_so > 0) { |
| + MAYBE_ADD_SPACE(); |
| + Buf_AddBytes(buf, pat->matches[0].rm_so, wp); |
| + } |
| + |
| + for (rp = pat->replace; *rp; rp++) { |
| + if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { |
| + MAYBE_ADD_SPACE(); |
| + Buf_AddByte(buf, rp[1]); |
| + rp++; |
| + } else if ((*rp == '&') || |
| + ((*rp == '\\') && isdigit((unsigned char) rp[1]))) { |
| + int n; |
| + const char *subbuf; |
| + int sublen; |
| + char errstr[3]; |
| + |
| + if (*rp == '&') { |
| + n = 0; |
| + errstr[0] = '&'; |
| + errstr[1] = '\0'; |
| + } else { |
| + n = rp[1] - '0'; |
| + errstr[0] = '\\'; |
| + errstr[1] = rp[1]; |
| + errstr[2] = '\0'; |
| + rp++; |
| + } |
| + |
| + if (n > pat->nsub) { |
| + Error("No subexpression %s", &errstr[0]); |
| + subbuf = ""; |
| + sublen = 0; |
| + } else if ((pat->matches[n].rm_so == -1) && |
| + (pat->matches[n].rm_eo == -1)) { |
| + Error("No match for subexpression %s", &errstr[0]); |
| + subbuf = ""; |
| + sublen = 0; |
| + } else { |
| + subbuf = wp + pat->matches[n].rm_so; |
| + sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; |
| + } |
| + |
| + if (sublen > 0) { |
| + MAYBE_ADD_SPACE(); |
| + Buf_AddBytes(buf, sublen, subbuf); |
| + } |
| + } else { |
| + MAYBE_ADD_SPACE(); |
| + Buf_AddByte(buf, *rp); |
| + } |
| + } |
| + wp += pat->matches[0].rm_eo; |
| + if (pat->flags & VAR_SUB_GLOBAL) { |
| + flags |= REG_NOTBOL; |
| + if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { |
| + MAYBE_ADD_SPACE(); |
| + Buf_AddByte(buf, *wp); |
| + wp++; |
| + |
| + } |
| + if (*wp) |
| + goto tryagain; |
| + } |
| + if (*wp) { |
| + MAYBE_ADD_SPACE(); |
| + Buf_AddBytes(buf, strlen(wp), wp); |
| + } |
| + break; |
| + default: |
| + VarREError(xrv, &pat->re, "Unexpected regex error"); |
| + /* fall through */ |
| + case REG_NOMATCH: |
| + if (*wp) { |
| + MAYBE_ADD_SPACE(); |
| + Buf_AddBytes(buf, strlen(wp), wp); |
| + } |
| + break; |
| + } |
| + return (addSpace || added); |
| } |
| -#endif |
| |
| +#endif |
| |
| @@ -1824,7 +1866,6 @@ static Boolean |
| VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, |
| - Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *loopp) |
| -{ |
| - VarLoop_t *loop = (VarLoop_t *)loopp; |
| + Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *loopp) { |
| + VarLoop_t *loop = (VarLoop_t *) loopp; |
| char *s; |
| @@ -1841,3 +1882,3 @@ VarLoopExpand(GNode *ctx MAKE_ATTR_UNUSED, |
| } |
| - free(s); |
| + free(s); |
| } |
| @@ -1868,10 +1909,9 @@ static char * |
| VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| - const char *str, VarSelectWords_t *seldata) |
| -{ |
| - Buffer buf; /* Buffer for the new string */ |
| - Boolean addSpace; /* TRUE if need to add a space to the |
| + const char *str, VarSelectWords_t *seldata) { |
| + Buffer buf; /* Buffer for the new string */ |
| + Boolean addSpace; /* TRUE if need to add a space to the |
| * buffer before adding the trimmed |
| * word */ |
| - char **av; /* word list */ |
| - char *as; /* word list memory */ |
| + char **av; /* word list */ |
| + char *as; /* word list memory */ |
| int ac, i; |
| @@ -1883,10 +1923,10 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| if (vpstate->oneBigWord) { |
| - /* fake what brk_string() would do if there were only one word */ |
| - ac = 1; |
| - av = bmake_malloc((ac + 1) * sizeof(char *)); |
| - as = bmake_strdup(str); |
| - av[0] = as; |
| - av[1] = NULL; |
| + /* fake what brk_string() would do if there were only one word */ |
| + ac = 1; |
| + av = bmake_malloc((ac + 1) * sizeof(char *)); |
| + as = bmake_strdup(str); |
| + av[0] = as; |
| + av[1] = NULL; |
| } else { |
| - av = brk_string(str, &ac, FALSE, &as); |
| + av = brk_string(str, &ac, FALSE, &as); |
| } |
| @@ -1900,5 +1940,5 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| if (seldata->start < 0) |
| - seldata->start = ac + seldata->start + 1; |
| + seldata->start = ac + seldata->start + 1; |
| if (seldata->end < 0) |
| - seldata->end = ac + seldata->end + 1; |
| + seldata->end = ac + seldata->end + 1; |
| |
| @@ -1908,9 +1948,9 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| if (seldata->start > seldata->end) { |
| - start = MIN(ac, seldata->start) - 1; |
| - end = MAX(0, seldata->end - 1); |
| - step = -1; |
| + start = MIN(ac, seldata->start) - 1; |
| + end = MAX(0, seldata->end - 1); |
| + step = -1; |
| } else { |
| - start = MAX(0, seldata->start - 1); |
| - end = MIN(ac, seldata->end); |
| - step = 1; |
| + start = MAX(0, seldata->start - 1); |
| + end = MIN(ac, seldata->end); |
| + step = 1; |
| } |
| @@ -1918,11 +1958,11 @@ VarSelectWords(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| for (i = start; |
| - (step < 0 && i >= end) || (step > 0 && i < end); |
| - i += step) { |
| - if (av[i] && *av[i]) { |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(&buf, vpstate->varSpace); |
| - } |
| - Buf_AddBytes(&buf, strlen(av[i]), av[i]); |
| - addSpace = TRUE; |
| - } |
| + (step < 0 && i >= end) || (step > 0 && i < end); |
| + i += step) { |
| + if (av[i] && *av[i]) { |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(&buf, vpstate->varSpace); |
| + } |
| + Buf_AddBytes(&buf, strlen(av[i]), av[i]); |
| + addSpace = TRUE; |
| + } |
| } |
| @@ -1943,19 +1983,18 @@ static Boolean |
| VarRealpath(GNode *ctx MAKE_ATTR_UNUSED, Var_Parse_State *vpstate, |
| - char *word, Boolean addSpace, Buffer *buf, |
| - void *patternp MAKE_ATTR_UNUSED) |
| -{ |
| - struct stat st; |
| - char rbuf[MAXPATHLEN]; |
| - char *rp; |
| - |
| - if (addSpace && vpstate->varSpace) { |
| - Buf_AddByte(buf, vpstate->varSpace); |
| - } |
| - addSpace = TRUE; |
| - rp = cached_realpath(word, rbuf); |
| - if (rp && *rp == '/' && stat(rp, &st) == 0) |
| - word = rp; |
| - |
| - Buf_AddBytes(buf, strlen(word), word); |
| - return(addSpace); |
| + char *word, Boolean addSpace, Buffer *buf, |
| + void *patternp MAKE_ATTR_UNUSED) { |
| + struct stat st; |
| + char rbuf[MAXPATHLEN]; |
| + char *rp; |
| + |
| + if (addSpace && vpstate->varSpace) { |
| + Buf_AddByte(buf, vpstate->varSpace); |
| + } |
| + addSpace = TRUE; |
| + rp = cached_realpath(word, rbuf); |
| + if (rp && *rp == '/' && stat(rp, &st) == 0) |
| + word = rp; |
| + |
| + Buf_AddBytes(buf, strlen(word), word); |
| + return (addSpace); |
| } |
| @@ -1983,13 +2022,12 @@ static char * |
| VarModify(GNode *ctx, Var_Parse_State *vpstate, |
| - const char *str, |
| - Boolean (*modProc)(GNode *, Var_Parse_State *, char *, |
| - Boolean, Buffer *, void *), |
| - void *datum) |
| -{ |
| - Buffer buf; /* Buffer for the new string */ |
| - Boolean addSpace; /* TRUE if need to add a space to the |
| + const char *str, |
| + Boolean (*modProc)(GNode *, Var_Parse_State *, char *, |
| + Boolean, Buffer *, void *), |
| + void *datum) { |
| + Buffer buf; /* Buffer for the new string */ |
| + Boolean addSpace; /* TRUE if need to add a space to the |
| * buffer before adding the trimmed |
| * word */ |
| - char **av; /* word list */ |
| - char *as; /* word list memory */ |
| + char **av; /* word list */ |
| + char *as; /* word list memory */ |
| int ac, i; |
| @@ -2000,10 +2038,10 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate, |
| if (vpstate->oneBigWord) { |
| - /* fake what brk_string() would do if there were only one word */ |
| - ac = 1; |
| - av = bmake_malloc((ac + 1) * sizeof(char *)); |
| - as = bmake_strdup(str); |
| - av[0] = as; |
| - av[1] = NULL; |
| + /* fake what brk_string() would do if there were only one word */ |
| + ac = 1; |
| + av = bmake_malloc((ac + 1) * sizeof(char *)); |
| + as = bmake_strdup(str); |
| + av[0] = as; |
| + av[1] = NULL; |
| } else { |
| - av = brk_string(str, &ac, FALSE, &as); |
| + av = brk_string(str, &ac, FALSE, &as); |
| } |
| @@ -2011,3 +2049,3 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate, |
| for (i = 0; i < ac; i++) { |
| - addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, &buf, datum); |
| + addSpace = (*modProc)(ctx, vpstate, av[i], addSpace, &buf, datum); |
| } |
| @@ -2022,6 +2060,5 @@ VarModify(GNode *ctx, Var_Parse_State *vpstate, |
| static int |
| -VarWordCompare(const void *a, const void *b) |
| -{ |
| - int r = strcmp(*(const char * const *)a, *(const char * const *)b); |
| - return r; |
| +VarWordCompare(const void *a, const void *b) { |
| + int r = strcmp(*(const char *const *) a, *(const char *const *) b); |
| + return r; |
| } |
| @@ -2046,7 +2083,6 @@ VarWordCompare(const void *a, const void *b) |
| static char * |
| -VarOrder(const char *str, const char otype) |
| -{ |
| - Buffer buf; /* Buffer for the new string */ |
| - char **av; /* word list [first word does not count] */ |
| - char *as; /* word list memory */ |
| +VarOrder(const char *str, const char otype) { |
| + Buffer buf; /* Buffer for the new string */ |
| + char **av; /* word list [first word does not count] */ |
| + char *as; /* word list memory */ |
| int ac, i; |
| @@ -2058,12 +2094,12 @@ VarOrder(const char *str, const char otype) |
| if (ac > 0) |
| - switch (otype) { |
| - case 's': /* sort alphabetically */ |
| - qsort(av, ac, sizeof(char *), VarWordCompare); |
| - break; |
| - case 'x': /* randomize */ |
| - { |
| - int rndidx; |
| - char *t; |
| - |
| - /* |
| + switch (otype) { |
| + case 's': /* sort alphabetically */ |
| + qsort(av, ac, sizeof(char *), VarWordCompare); |
| + break; |
| + case 'x': /* randomize */ |
| + { |
| + int rndidx; |
| + char *t; |
| + |
| + /* |
| * We will use [ac..2] range for mod factors. This will produce |
| @@ -2073,17 +2109,17 @@ VarOrder(const char *str, const char otype) |
| */ |
| - for (i = ac-1; i > 0; i--) { |
| - rndidx = random() % (i + 1); |
| - if (i != rndidx) { |
| - t = av[i]; |
| - av[i] = av[rndidx]; |
| - av[rndidx] = t; |
| - } |
| - } |
| - } |
| - } /* end of switch */ |
| + for (i = ac - 1; i > 0; i--) { |
| + rndidx = random() % (i + 1); |
| + if (i != rndidx) { |
| + t = av[i]; |
| + av[i] = av[rndidx]; |
| + av[rndidx] = t; |
| + } |
| + } |
| + } |
| + } /* end of switch */ |
| |
| for (i = 0; i < ac; i++) { |
| - Buf_AddBytes(&buf, strlen(av[i]), av[i]); |
| - if (i != ac - 1) |
| - Buf_AddByte(&buf, ' '); |
| + Buf_AddBytes(&buf, strlen(av[i]), av[i]); |
| + if (i != ac - 1) |
| + Buf_AddByte(&buf, ' '); |
| } |
| @@ -2114,8 +2150,7 @@ VarOrder(const char *str, const char otype) |
| static char * |
| -VarUniq(const char *str) |
| -{ |
| - Buffer buf; /* Buffer for new string */ |
| - char **av; /* List of words to affect */ |
| - char *as; /* Word list memory */ |
| - int ac, i, j; |
| +VarUniq(const char *str) { |
| + Buffer buf; /* Buffer for new string */ |
| + char **av; /* List of words to affect */ |
| + char *as; /* Word list memory */ |
| + int ac, i, j; |
| |
| @@ -2125,6 +2160,6 @@ VarUniq(const char *str) |
| if (ac > 1) { |
| - for (j = 0, i = 1; i < ac; i++) |
| - if (strcmp(av[i], av[j]) != 0 && (++j != i)) |
| - av[j] = av[i]; |
| - ac = j + 1; |
| + for (j = 0, i = 1; i < ac; i++) |
| + if (strcmp(av[i], av[j]) != 0 && (++j != i)) |
| + av[j] = av[i]; |
| + ac = j + 1; |
| } |
| @@ -2132,5 +2167,5 @@ VarUniq(const char *str) |
| for (i = 0; i < ac; i++) { |
| - Buf_AddBytes(&buf, strlen(av[i]), av[i]); |
| - if (i != ac - 1) |
| - Buf_AddByte(&buf, ' '); |
| + Buf_AddBytes(&buf, strlen(av[i]), av[i]); |
| + if (i != ac - 1) |
| + Buf_AddByte(&buf, ' '); |
| } |
| @@ -2158,9 +2193,8 @@ VarUniq(const char *str) |
| static char * |
| -VarRange(const char *str, int ac) |
| -{ |
| - Buffer buf; /* Buffer for new string */ |
| - char tmp[32]; /* each element */ |
| - char **av; /* List of words to affect */ |
| - char *as; /* Word list memory */ |
| - int i, n; |
| +VarRange(const char *str, int ac) { |
| + Buffer buf; /* Buffer for new string */ |
| + char tmp[32]; /* each element */ |
| + char **av; /* List of words to affect */ |
| + char *as; /* Word list memory */ |
| + int i, n; |
| |
| @@ -2168,14 +2202,14 @@ VarRange(const char *str, int ac) |
| if (ac > 0) { |
| - as = NULL; |
| - av = NULL; |
| + as = NULL; |
| + av = NULL; |
| } else { |
| - av = brk_string(str, &ac, FALSE, &as); |
| + av = brk_string(str, &ac, FALSE, &as); |
| } |
| for (i = 0; i < ac; i++) { |
| - n = snprintf(tmp, sizeof(tmp), "%d", 1 + i); |
| - if (n >= (int)sizeof(tmp)) |
| - break; |
| - Buf_AddBytes(&buf, n, tmp); |
| - if (i != ac - 1) |
| - Buf_AddByte(&buf, ' '); |
| + n = snprintf(tmp, sizeof(tmp), "%d", 1 + i); |
| + if (n >= (int) sizeof(tmp)) |
| + break; |
| + Buf_AddBytes(&buf, n, tmp); |
| + if (i != ac - 1) |
| + Buf_AddByte(&buf, ' '); |
| } |
| @@ -2213,5 +2247,4 @@ static char * |
| VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| - int flags, const char **tstr, int delim, int *vflags, |
| - int *length, VarPattern *pattern) |
| -{ |
| + int flags, const char **tstr, int delim, int *vflags, |
| + int *length, VarPattern *pattern) { |
| const char *cp; |
| @@ -2224,3 +2257,3 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| if (length == NULL) |
| - length = &junk; |
| + length = &junk; |
| |
| @@ -2237,11 +2270,11 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| for (cp = *tstr; *cp && (*cp != delim); cp++) { |
| - if (IS_A_MATCH(cp, delim)) { |
| - Buf_AddByte(&buf, cp[1]); |
| - cp++; |
| - } else if (*cp == '$') { |
| - if (cp[1] == delim) { |
| - if (vflags == NULL) |
| - Buf_AddByte(&buf, *cp); |
| - else |
| - /* |
| + if (IS_A_MATCH(cp, delim)) { |
| + Buf_AddByte(&buf, cp[1]); |
| + cp++; |
| + } else if (*cp == '$') { |
| + if (cp[1] == delim) { |
| + if (vflags == NULL) |
| + Buf_AddByte(&buf, *cp); |
| + else |
| + /* |
| * Unescaped $ at end of pattern => anchor |
| @@ -2249,10 +2282,10 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| */ |
| - *vflags |= VAR_MATCH_END; |
| - } else { |
| - if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) { |
| - char *cp2; |
| - int len; |
| - void *freeIt; |
| - |
| - /* |
| + *vflags |= VAR_MATCH_END; |
| + } else { |
| + if (vflags == NULL || (*vflags & VAR_NOSUBST) == 0) { |
| + char *cp2; |
| + int len; |
| + void *freeIt; |
| + |
| + /* |
| * If unescaped dollar sign not before the |
| @@ -2261,12 +2294,12 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| */ |
| - cp2 = Var_Parse(cp, ctxt, errnum | VARF_WANTRES, &len, |
| - &freeIt); |
| - Buf_AddBytes(&buf, strlen(cp2), cp2); |
| - free(freeIt); |
| - cp += len - 1; |
| - } else { |
| - const char *cp2 = &cp[1]; |
| - |
| - if (*cp2 == PROPEN || *cp2 == BROPEN) { |
| - /* |
| + cp2 = Var_Parse(cp, ctxt, errnum | VARF_WANTRES, &len, |
| + &freeIt); |
| + Buf_AddBytes(&buf, strlen(cp2), cp2); |
| + free(freeIt); |
| + cp += len - 1; |
| + } else { |
| + const char *cp2 = &cp[1]; |
| + |
| + if (*cp2 == PROPEN || *cp2 == BROPEN) { |
| + /* |
| * Find the end of this variable reference |
| @@ -2275,25 +2308,24 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| */ |
| - int have = *cp2; |
| - int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; |
| - int depth = 1; |
| - |
| - for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { |
| - if (cp2[-1] != '\\') { |
| - if (*cp2 == have) |
| - ++depth; |
| - if (*cp2 == want) |
| - --depth; |
| - } |
| - } |
| - Buf_AddBytes(&buf, cp2 - cp, cp); |
| - cp = --cp2; |
| - } else |
| - Buf_AddByte(&buf, *cp); |
| - } |
| - } |
| - } |
| - else if (pattern && *cp == '&') |
| - Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs); |
| - else |
| - Buf_AddByte(&buf, *cp); |
| + int have = *cp2; |
| + int want = (*cp2 == PROPEN) ? PRCLOSE : BRCLOSE; |
| + int depth = 1; |
| + |
| + for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { |
| + if (cp2[-1] != '\\') { |
| + if (*cp2 == have) |
| + ++depth; |
| + if (*cp2 == want) |
| + --depth; |
| + } |
| + } |
| + Buf_AddBytes(&buf, cp2 - cp, cp); |
| + cp = --cp2; |
| + } else |
| + Buf_AddByte(&buf, *cp); |
| + } |
| + } |
| + } else if (pattern && *cp == '&') |
| + Buf_AddBytes(&buf, pattern->leftLen, pattern->lhs); |
| + else |
| + Buf_AddByte(&buf, *cp); |
| } |
| @@ -2301,5 +2333,5 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| if (*cp != delim) { |
| - *tstr = cp; |
| - *length = 0; |
| - return NULL; |
| + *tstr = cp; |
| + *length = 0; |
| + return NULL; |
| } |
| @@ -2310,3 +2342,3 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| if (DEBUG(VAR)) |
| - fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr); |
| + fprintf(debug_file, "Modifier pattern: \"%s\"\n", rstr); |
| return rstr; |
| @@ -2329,7 +2361,6 @@ VarGetPattern(GNode *ctxt, Var_Parse_State *vpstate MAKE_ATTR_UNUSED, |
| static char * |
| -VarQuote(char *str, Boolean quoteDollar) |
| -{ |
| +VarQuote(char *str, Boolean quoteDollar) { |
| |
| - Buffer buf; |
| - const char *newline; |
| + Buffer buf; |
| + const char *newline; |
| size_t nlen; |
| @@ -2337,3 +2368,3 @@ VarQuote(char *str, Boolean quoteDollar) |
| if ((newline = Shell_GetNewline()) == NULL) |
| - newline = "\\\n"; |
| + newline = "\\\n"; |
| nlen = strlen(newline); |
| @@ -2343,11 +2374,11 @@ VarQuote(char *str, Boolean quoteDollar) |
| for (; *str != '\0'; str++) { |
| - if (*str == '\n') { |
| - Buf_AddBytes(&buf, nlen, newline); |
| - continue; |
| - } |
| - if (isspace((unsigned char)*str) || ismeta((unsigned char)*str)) |
| - Buf_AddByte(&buf, '\\'); |
| - Buf_AddByte(&buf, *str); |
| - if (quoteDollar && *str == '$') |
| - Buf_AddBytes(&buf, 2, "\\$"); |
| + if (*str == '\n') { |
| + Buf_AddBytes(&buf, nlen, newline); |
| + continue; |
| + } |
| + if (isspace((unsigned char) *str) || ismeta((unsigned char) *str)) |
| + Buf_AddByte(&buf, '\\'); |
| + Buf_AddByte(&buf, *str); |
| + if (quoteDollar && *str == '$') |
| + Buf_AddBytes(&buf, 2, "\\$"); |
| } |
| @@ -2356,3 +2387,3 @@ VarQuote(char *str, Boolean quoteDollar) |
| if (DEBUG(VAR)) |
| - fprintf(debug_file, "QuoteMeta: [%s]\n", str); |
| + fprintf(debug_file, "QuoteMeta: [%s]\n", str); |
| return str; |
| @@ -2378,11 +2409,10 @@ VarQuote(char *str, Boolean quoteDollar) |
| static char * |
| -VarHash(char *str) |
| -{ |
| - static const char hexdigits[16] = "0123456789abcdef"; |
| - Buffer buf; |
| - size_t len, len2; |
| - unsigned char *ustr = (unsigned char *)str; |
| - unsigned int h, k, c1, c2; |
| +VarHash(char *str) { |
| + static const char hexdigits[16] = "0123456789abcdef"; |
| + Buffer buf; |
| + size_t len, len2; |
| + unsigned char *ustr = (unsigned char *) str; |
| + unsigned int h, k, c1, c2; |
| |
| - h = 0x971e137bU; |
| + h = 0x971e137bU; |
| c1 = 0x95543787U; |
| @@ -2391,40 +2421,40 @@ VarHash(char *str) |
| |
| - for (len = len2; len; ) { |
| - k = 0; |
| - switch (len) { |
| - default: |
| - k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0]; |
| - len -= 4; |
| - ustr += 4; |
| - break; |
| - case 3: |
| - k |= (ustr[2] << 16); |
| - case 2: |
| - k |= (ustr[1] << 8); |
| - case 1: |
| - k |= ustr[0]; |
| - len = 0; |
| - } |
| - c1 = c1 * 5 + 0x7b7d159cU; |
| - c2 = c2 * 5 + 0x6bce6396U; |
| - k *= c1; |
| - k = (k << 11) ^ (k >> 21); |
| - k *= c2; |
| - h = (h << 13) ^ (h >> 19); |
| - h = h * 5 + 0x52dce729U; |
| - h ^= k; |
| - } |
| - h ^= len2; |
| - h *= 0x85ebca6b; |
| - h ^= h >> 13; |
| - h *= 0xc2b2ae35; |
| - h ^= h >> 16; |
| - |
| - Buf_Init(&buf, 0); |
| - for (len = 0; len < 8; ++len) { |
| - Buf_AddByte(&buf, hexdigits[h & 15]); |
| - h >>= 4; |
| - } |
| - |
| - return Buf_Destroy(&buf, FALSE); |
| + for (len = len2; len;) { |
| + k = 0; |
| + switch (len) { |
| + default: |
| + k = (ustr[3] << 24) | (ustr[2] << 16) | (ustr[1] << 8) | ustr[0]; |
| + len -= 4; |
| + ustr += 4; |
| + break; |
| + case 3: |
| + k |= (ustr[2] << 16); |
| + case 2: |
| + k |= (ustr[1] << 8); |
| + case 1: |
| + k |= ustr[0]; |
| + len = 0; |
| + } |
| + c1 = c1 * 5 + 0x7b7d159cU; |
| + c2 = c2 * 5 + 0x6bce6396U; |
| + k *= c1; |
| + k = (k << 11) ^ (k >> 21); |
| + k *= c2; |
| + h = (h << 13) ^ (h >> 19); |
| + h = h * 5 + 0x52dce729U; |
| + h ^= k; |
| + } |
| + h ^= len2; |
| + h *= 0x85ebca6b; |
| + h ^= h >> 13; |
| + h *= 0xc2b2ae35; |
| + h ^= h >> 16; |
| + |
| + Buf_Init(&buf, 0); |
| + for (len = 0; len < 8; ++len) { |
| + Buf_AddByte(&buf, hexdigits[h & 15]); |
| + h >>= 4; |
| + } |
| + |
| + return Buf_Destroy(&buf, FALSE); |
| } |
| @@ -2432,4 +2462,3 @@ VarHash(char *str) |
| static char * |
| -VarStrftime(const char *fmt, int zulu, time_t utc) |
| -{ |
| +VarStrftime(const char *fmt, int zulu, time_t utc) { |
| char buf[BUFSIZ]; |
| @@ -2437,7 +2466,7 @@ VarStrftime(const char *fmt, int zulu, time_t utc) |
| if (!utc) |
| - time(&utc); |
| + time(&utc); |
| if (!*fmt) |
| - fmt = "%c"; |
| + fmt = "%c"; |
| strftime(buf, sizeof(buf), fmt, zulu ? gmtime(&utc) : localtime(&utc)); |
| - |
| + |
| buf[sizeof(buf) - 1] = '\0'; |
| @@ -2540,18 +2569,29 @@ static char * |
| ApplyModifiers(char *nstr, const char *tstr, |
| - int startc, int endc, |
| - Var *v, GNode *ctxt, int flags, |
| - int *lengthPtr, void **freePtr) |
| -{ |
| - const char *start; |
| - const char *cp; /* Secondary pointer into str (place marker |
| + int startc, int endc, |
| + Var *v, GNode *ctxt, int flags, |
| + int *lengthPtr, void **freePtr) { |
| + const char *start; |
| + const char *cp; /* Secondary pointer into str (place marker |
| * for tstr) */ |
| - char *newStr; /* New value to return */ |
| - char *ep; |
| - char termc; /* Character which terminated scan */ |
| - int cnt; /* Used to count brace pairs when variable in |
| +#if (defined _WIN32 && ! defined __CYGWIN__) |
| + char *unix_nstr; |
| + char *error; |
| + if (nstr && strlen(nstr) > 0 && nstr[1] == ':' && (nstr[2] == '/' || nstr[2] == '\\')) { |
| + unix_nstr = Cmd_Exec(getUnixPathCmd(nstr), &error); |
| + } |
| + else { |
| + unix_nstr = nstr; |
| + } |
| +#else |
| + char *unix_nstr = nstr; |
| +#endif |
| + char *newStr; /* New value to return */ |
| + char *ep; |
| + char termc; /* Character which terminated scan */ |
| + int cnt; /* Used to count brace pairs when variable in |
| * in parens or braces */ |
| - char delim; |
| - int modifier; /* that we are processing */ |
| + char delim; |
| + int modifier; /* that we are processing */ |
| Var_Parse_State parsestate; /* Flags passed to helper functions */ |
| - time_t utc; /* for VarStrftime */ |
| + time_t utc; /* for VarStrftime */ |
| |
| @@ -2559,3 +2599,3 @@ ApplyModifiers(char *nstr, const char *tstr, |
| parsestate.oneBigWord = FALSE; |
| - parsestate.varSpace = ' '; /* word separator */ |
| + parsestate.varSpace = ' '; /* word separator */ |
| |
| @@ -2565,14 +2605,14 @@ ApplyModifiers(char *nstr, const char *tstr, |
| |
| - if (*tstr == '$') { |
| - /* |
| + if (*tstr == '$') { |
| + /* |
| * We may have some complex modifiers in a variable. |
| */ |
| - void *freeIt; |
| - char *rval; |
| - int rlen; |
| - int c; |
| + void *freeIt; |
| + char *rval; |
| + int rlen; |
| + int c; |
| |
| - rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); |
| + rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); |
| |
| - /* |
| + /* |
| * If we have not parsed up to endc or ':', |
| @@ -2580,68 +2620,67 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - if (rval != NULL && *rval && |
| - (c = tstr[rlen]) != '\0' && |
| - c != ':' && |
| - c != endc) { |
| - free(freeIt); |
| - goto apply_mods; |
| - } |
| - |
| - if (DEBUG(VAR)) { |
| - fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", |
| - rval, rlen, tstr, rlen, tstr + rlen); |
| - } |
| - |
| - tstr += rlen; |
| - |
| - if (rval != NULL && *rval) { |
| - int used; |
| - |
| - nstr = ApplyModifiers(nstr, rval, |
| - 0, 0, v, ctxt, flags, &used, freePtr); |
| - if (nstr == var_Error |
| - || (nstr == varNoError && (flags & VARF_UNDEFERR) == 0) |
| - || strlen(rval) != (size_t) used) { |
| - free(freeIt); |
| - goto out; /* error already reported */ |
| - } |
| - } |
| - free(freeIt); |
| - if (*tstr == ':') |
| - tstr++; |
| - else if (!*tstr && endc) { |
| - Error("Unclosed variable specification after complex modifier (expecting '%c') for %s", endc, v->name); |
| - goto out; |
| - } |
| - continue; |
| - } |
| - apply_mods: |
| - if (DEBUG(VAR)) { |
| - fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", v->name, |
| - *tstr, nstr); |
| - } |
| - newStr = var_Error; |
| - switch ((modifier = *tstr)) { |
| - case ':': |
| - { |
| - if (tstr[1] == '=' || |
| - (tstr[2] == '=' && |
| - (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) { |
| - /* |
| + if (rval != NULL && *rval && |
| + (c = tstr[rlen]) != '\0' && |
| + c != ':' && |
| + c != endc) { |
| + free(freeIt); |
| + goto apply_mods; |
| + } |
| + |
| + if (DEBUG(VAR)) { |
| + fprintf(debug_file, "Got '%s' from '%.*s'%.*s\n", |
| + rval, rlen, tstr, rlen, tstr + rlen); |
| + } |
| + |
| + tstr += rlen; |
| + |
| + if (rval != NULL && *rval) { |
| + int used; |
| + |
| + unix_nstr = ApplyModifiers(unix_nstr, rval, |
| + 0, 0, v, ctxt, flags, &used, freePtr); |
| + if (unix_nstr == var_Error |
| + || (unix_nstr == varNoError && (flags & VARF_UNDEFERR) == 0) |
| + || strlen(rval) != (size_t) used) { |
| + free(freeIt); |
| + goto out; /* error already reported */ |
| + } |
| + } |
| + free(freeIt); |
| + if (*tstr == ':') |
| + tstr++; |
| + else if (!*tstr && endc) { |
| + Error("Unclosed variable specification after complex modifier (expecting '%c') for %s", endc, v->name); |
| + goto out; |
| + } |
| + continue; |
| + } |
| + apply_mods: |
| + if (DEBUG(VAR)) { |
| + fprintf(debug_file, "Applying[%s] :%c to \"%s\"\n", v->name, |
| + *tstr, unix_nstr); |
| + } |
| + newStr = var_Error; |
| + switch ((modifier = *tstr)) { |
| + case ':': { |
| + if (tstr[1] == '=' || |
| + (tstr[2] == '=' && |
| + (tstr[1] == '!' || tstr[1] == '+' || tstr[1] == '?'))) { |
| + /* |
| * "::=", "::!=", "::+=", or "::?=" |
| */ |
| - GNode *v_ctxt; /* context where v belongs */ |
| - const char *emsg; |
| - char *sv_name; |
| - VarPattern pattern; |
| - int how; |
| - int vflags; |
| - |
| - if (v->name[0] == 0) |
| - goto bad_modifier; |
| - |
| - v_ctxt = ctxt; |
| - sv_name = NULL; |
| - ++tstr; |
| - if (v->flags & VAR_JUNK) { |
| - /* |
| + GNode *v_ctxt; /* context where v belongs */ |
| + const char *emsg; |
| + char *sv_name; |
| + VarPattern pattern; |
| + int how; |
| + int vflags; |
| + |
| + if (v->name[0] == 0) |
| + goto bad_modifier; |
| + |
| + v_ctxt = ctxt; |
| + sv_name = NULL; |
| + ++tstr; |
| + if (v->flags & VAR_JUNK) { |
| + /* |
| * We need to bmake_strdup() it incase |
| @@ -2649,140 +2688,138 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - sv_name = v->name; |
| - v->name = bmake_strdup(v->name); |
| - } else if (ctxt != VAR_GLOBAL) { |
| - Var *gv = VarFind(v->name, ctxt, 0); |
| - if (gv == NULL) |
| - v_ctxt = VAR_GLOBAL; |
| - else |
| - VarFreeEnv(gv, TRUE); |
| - } |
| - |
| - switch ((how = *tstr)) { |
| - case '+': |
| - case '?': |
| - case '!': |
| - cp = &tstr[2]; |
| - break; |
| - default: |
| - cp = ++tstr; |
| - break; |
| - } |
| - delim = startc == PROPEN ? PRCLOSE : BRCLOSE; |
| - pattern.flags = 0; |
| - |
| - vflags = (flags & VARF_WANTRES) ? 0 : VAR_NOSUBST; |
| - pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, |
| - &cp, delim, &vflags, |
| - &pattern.rightLen, |
| - NULL); |
| - if (v->flags & VAR_JUNK) { |
| - /* restore original name */ |
| - free(v->name); |
| - v->name = sv_name; |
| - } |
| - if (pattern.rhs == NULL) |
| - goto cleanup; |
| - |
| - termc = *--cp; |
| - delim = '\0'; |
| - |
| - if (flags & VARF_WANTRES) { |
| - switch (how) { |
| - case '+': |
| - Var_Append(v->name, pattern.rhs, v_ctxt); |
| - break; |
| - case '!': |
| - newStr = Cmd_Exec(pattern.rhs, &emsg); |
| - if (emsg) |
| - Error(emsg, nstr); |
| - else |
| - Var_Set(v->name, newStr, v_ctxt, 0); |
| - free(newStr); |
| - break; |
| - case '?': |
| - if ((v->flags & VAR_JUNK) == 0) |
| - break; |
| - /* FALLTHROUGH */ |
| - default: |
| - Var_Set(v->name, pattern.rhs, v_ctxt, 0); |
| - break; |
| - } |
| - } |
| - free(UNCONST(pattern.rhs)); |
| - newStr = varNoError; |
| - break; |
| - } |
| - goto default_case; /* "::<unrecognised>" */ |
| - } |
| - case '@': |
| - { |
| - VarLoop_t loop; |
| - int vflags = VAR_NOSUBST; |
| - |
| - cp = ++tstr; |
| - delim = '@'; |
| - if ((loop.tvar = VarGetPattern(ctxt, &parsestate, flags, |
| - &cp, delim, |
| - &vflags, &loop.tvarLen, |
| - NULL)) == NULL) |
| - goto cleanup; |
| - |
| - if ((loop.str = VarGetPattern(ctxt, &parsestate, flags, |
| - &cp, delim, |
| - &vflags, &loop.strLen, |
| - NULL)) == NULL) |
| - goto cleanup; |
| - |
| - termc = *cp; |
| - delim = '\0'; |
| - |
| - loop.errnum = flags & VARF_UNDEFERR; |
| - loop.ctxt = ctxt; |
| - newStr = VarModify(ctxt, &parsestate, nstr, VarLoopExpand, |
| - &loop); |
| - Var_Delete(loop.tvar, ctxt); |
| - free(loop.tvar); |
| - free(loop.str); |
| - break; |
| - } |
| - case '_': /* remember current value */ |
| - cp = tstr + 1; /* make sure it is set */ |
| - if (STRMOD_MATCHX(tstr, "_", 1)) { |
| - if (tstr[1] == '=') { |
| - char *np; |
| - int n; |
| - |
| - cp++; |
| - n = strcspn(cp, ":)}"); |
| - np = bmake_strndup(cp, n+1); |
| - np[n] = '\0'; |
| - cp = tstr + 2 + n; |
| - Var_Set(np, nstr, ctxt, 0); |
| - free(np); |
| - } else { |
| - Var_Set("_", nstr, ctxt, 0); |
| - } |
| - newStr = nstr; |
| - termc = *cp; |
| - break; |
| - } |
| - goto default_case; |
| - case 'D': |
| - case 'U': |
| - { |
| - Buffer buf; /* Buffer for patterns */ |
| - int nflags; |
| - |
| - if (flags & VARF_WANTRES) { |
| - int wantres; |
| - if (*tstr == 'U') |
| - wantres = ((v->flags & VAR_JUNK) != 0); |
| - else |
| - wantres = ((v->flags & VAR_JUNK) == 0); |
| - nflags = flags & ~VARF_WANTRES; |
| - if (wantres) |
| - nflags |= VARF_WANTRES; |
| - } else |
| - nflags = flags; |
| - /* |
| + sv_name = v->name; |
| + v->name = bmake_strdup(v->name); |
| + } else if (ctxt != VAR_GLOBAL) { |
| + Var *gv = VarFind(v->name, ctxt, 0); |
| + if (gv == NULL) |
| + v_ctxt = VAR_GLOBAL; |
| + else |
| + VarFreeEnv(gv, TRUE); |
| + } |
| + |
| + switch ((how = *tstr)) { |
| + case '+': |
| + case '?': |
| + case '!': |
| + cp = &tstr[2]; |
| + break; |
| + default: |
| + cp = ++tstr; |
| + break; |
| + } |
| + delim = startc == PROPEN ? PRCLOSE : BRCLOSE; |
| + pattern.flags = 0; |
| + |
| + vflags = (flags & VARF_WANTRES) ? 0 : VAR_NOSUBST; |
| + pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, |
| + &cp, delim, &vflags, |
| + &pattern.rightLen, |
| + NULL); |
| + if (v->flags & VAR_JUNK) { |
| + /* restore original name */ |
| + free(v->name); |
| + v->name = sv_name; |
| + } |
| + if (pattern.rhs == NULL) |
| + goto cleanup; |
| + |
| + termc = *--cp; |
| + delim = '\0'; |
| + |
| + if (flags & VARF_WANTRES) { |
| + switch (how) { |
| + case '+': |
| + Var_Append(v->name, pattern.rhs, v_ctxt); |
| + break; |
| + case '!': |
| + newStr = Cmd_Exec(pattern.rhs, &emsg); |
| + if (emsg) |
| + Error(emsg, unix_nstr); |
| + else |
| + Var_Set(v->name, newStr, v_ctxt, 0); |
| + free(newStr); |
| + break; |
| + case '?': |
| + if ((v->flags & VAR_JUNK) == 0) |
| + break; |
| + /* FALLTHROUGH */ |
| + default: |
| + Var_Set(v->name, pattern.rhs, v_ctxt, 0); |
| + break; |
| + } |
| + } |
| + free(UNCONST(pattern.rhs)); |
| + newStr = varNoError; |
| + break; |
| + } |
| + goto default_case; /* "::<unrecognised>" */ |
| + } |
| + case '@': { |
| + VarLoop_t loop; |
| + int vflags = VAR_NOSUBST; |
| + |
| + cp = ++tstr; |
| + delim = '@'; |
| + if ((loop.tvar = VarGetPattern(ctxt, &parsestate, flags, |
| + &cp, delim, |
| + &vflags, &loop.tvarLen, |
| + NULL)) == NULL) |
| + goto cleanup; |
| + |
| + if ((loop.str = VarGetPattern(ctxt, &parsestate, flags, |
| + &cp, delim, |
| + &vflags, &loop.strLen, |
| + NULL)) == NULL) |
| + goto cleanup; |
| + |
| + termc = *cp; |
| + delim = '\0'; |
| + |
| + loop.errnum = flags & VARF_UNDEFERR; |
| + loop.ctxt = ctxt; |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarLoopExpand, |
| + &loop); |
| + Var_Delete(loop.tvar, ctxt); |
| + free(loop.tvar); |
| + free(loop.str); |
| + break; |
| + } |
| + case '_': /* remember current value */ |
| + cp = tstr + 1; /* make sure it is set */ |
| + if (STRMOD_MATCHX(tstr, "_", 1)) { |
| + if (tstr[1] == '=') { |
| + char *np; |
| + int n; |
| + |
| + cp++; |
| + n = strcspn(cp, ":)}"); |
| + np = bmake_strndup(cp, n + 1); |
| + np[n] = '\0'; |
| + cp = tstr + 2 + n; |
| + Var_Set(np, unix_nstr, ctxt, 0); |
| + free(np); |
| + } else { |
| + Var_Set("_", unix_nstr, ctxt, 0); |
| + } |
| + newStr = unix_nstr; |
| + termc = *cp; |
| + break; |
| + } |
| + goto default_case; |
| + case 'D': |
| + case 'U': { |
| + Buffer buf; /* Buffer for patterns */ |
| + int nflags; |
| + |
| + if (flags & VARF_WANTRES) { |
| + int wantres; |
| + if (*tstr == 'U') |
| + wantres = ((v->flags & VAR_JUNK) != 0); |
| + else |
| + wantres = ((v->flags & VAR_JUNK) == 0); |
| + nflags = flags & ~VARF_WANTRES; |
| + if (wantres) |
| + nflags |= VARF_WANTRES; |
| + } else |
| + nflags = flags; |
| + /* |
| * Pass through tstr looking for 1) escaped delimiters, |
| @@ -2793,16 +2830,15 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - Buf_Init(&buf, 0); |
| - for (cp = tstr + 1; |
| - *cp != endc && *cp != ':' && *cp != '\0'; |
| - cp++) { |
| - if ((*cp == '\\') && |
| - ((cp[1] == ':') || |
| - (cp[1] == '$') || |
| - (cp[1] == endc) || |
| - (cp[1] == '\\'))) |
| - { |
| - Buf_AddByte(&buf, cp[1]); |
| - cp++; |
| - } else if (*cp == '$') { |
| - /* |
| + Buf_Init(&buf, 0); |
| + for (cp = tstr + 1; |
| + *cp != endc && *cp != ':' && *cp != '\0'; |
| + cp++) { |
| + if ((*cp == '\\') && |
| + ((cp[1] == ':') || |
| + (cp[1] == '$') || |
| + (cp[1] == endc) || |
| + (cp[1] == '\\'))) { |
| + Buf_AddByte(&buf, cp[1]); |
| + cp++; |
| + } else if (*cp == '$') { |
| + /* |
| * If unescaped dollar sign, assume it's a |
| @@ -2810,88 +2846,84 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - char *cp2; |
| - int len; |
| - void *freeIt; |
| - |
| - cp2 = Var_Parse(cp, ctxt, nflags, &len, &freeIt); |
| - Buf_AddBytes(&buf, strlen(cp2), cp2); |
| - free(freeIt); |
| - cp += len - 1; |
| - } else { |
| - Buf_AddByte(&buf, *cp); |
| - } |
| - } |
| - |
| - termc = *cp; |
| - |
| - if ((v->flags & VAR_JUNK) != 0) |
| - v->flags |= VAR_KEEP; |
| - if (nflags & VARF_WANTRES) { |
| - newStr = Buf_Destroy(&buf, FALSE); |
| - } else { |
| - newStr = nstr; |
| - Buf_Destroy(&buf, TRUE); |
| - } |
| - break; |
| - } |
| - case 'L': |
| - { |
| - if ((v->flags & VAR_JUNK) != 0) |
| - v->flags |= VAR_KEEP; |
| - newStr = bmake_strdup(v->name); |
| - cp = ++tstr; |
| - termc = *tstr; |
| - break; |
| - } |
| - case 'P': |
| - { |
| - GNode *gn; |
| - |
| - if ((v->flags & VAR_JUNK) != 0) |
| - v->flags |= VAR_KEEP; |
| - gn = Targ_FindNode(v->name, TARG_NOCREATE); |
| - if (gn == NULL || gn->type & OP_NOPATH) { |
| - newStr = NULL; |
| - } else if (gn->path) { |
| - newStr = bmake_strdup(gn->path); |
| - } else { |
| - newStr = Dir_FindFile(v->name, Suff_FindPath(gn)); |
| - } |
| - if (!newStr) { |
| - newStr = bmake_strdup(v->name); |
| - } |
| - cp = ++tstr; |
| - termc = *tstr; |
| - break; |
| - } |
| - case '!': |
| - { |
| - const char *emsg; |
| - VarPattern pattern; |
| - pattern.flags = 0; |
| - |
| - delim = '!'; |
| - emsg = NULL; |
| - cp = ++tstr; |
| - if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, |
| - &cp, delim, |
| - NULL, &pattern.rightLen, |
| - NULL)) == NULL) |
| - goto cleanup; |
| - if (flags & VARF_WANTRES) |
| - newStr = Cmd_Exec(pattern.rhs, &emsg); |
| - else |
| - newStr = varNoError; |
| - free(UNCONST(pattern.rhs)); |
| - if (emsg) |
| - Error(emsg, nstr); |
| - termc = *cp; |
| - delim = '\0'; |
| - if (v->flags & VAR_JUNK) { |
| - v->flags |= VAR_KEEP; |
| - } |
| - break; |
| - } |
| - case '[': |
| - { |
| - /* |
| + char *cp2; |
| + int len; |
| + void *freeIt; |
| + |
| + cp2 = Var_Parse(cp, ctxt, nflags, &len, &freeIt); |
| + Buf_AddBytes(&buf, strlen(cp2), cp2); |
| + free(freeIt); |
| + cp += len - 1; |
| + } else { |
| + Buf_AddByte(&buf, *cp); |
| + } |
| + } |
| + |
| + termc = *cp; |
| + |
| + if ((v->flags & VAR_JUNK) != 0) |
| + v->flags |= VAR_KEEP; |
| + if (nflags & VARF_WANTRES) { |
| + newStr = Buf_Destroy(&buf, FALSE); |
| + } else { |
| + newStr = unix_nstr; |
| + Buf_Destroy(&buf, TRUE); |
| + } |
| + break; |
| + } |
| + case 'L': { |
| + if ((v->flags & VAR_JUNK) != 0) |
| + v->flags |= VAR_KEEP; |
| + newStr = bmake_strdup(v->name); |
| + cp = ++tstr; |
| + termc = *tstr; |
| + break; |
| + } |
| + case 'P': { |
| + GNode *gn; |
| + |
| + if ((v->flags & VAR_JUNK) != 0) |
| + v->flags |= VAR_KEEP; |
| + gn = Targ_FindNode(v->name, TARG_NOCREATE); |
| + if (gn == NULL || gn->type & OP_NOPATH) { |
| + newStr = NULL; |
| + } else if (gn->path) { |
| + newStr = bmake_strdup(gn->path); |
| + } else { |
| + newStr = Dir_FindFile(v->name, Suff_FindPath(gn)); |
| + } |
| + if (!newStr) { |
| + newStr = bmake_strdup(v->name); |
| + } |
| + cp = ++tstr; |
| + termc = *tstr; |
| + break; |
| + } |
| + case '!': { |
| + const char *emsg; |
| + VarPattern pattern; |
| + pattern.flags = 0; |
| + |
| + delim = '!'; |
| + emsg = NULL; |
| + cp = ++tstr; |
| + if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, |
| + &cp, delim, |
| + NULL, &pattern.rightLen, |
| + NULL)) == NULL) |
| + goto cleanup; |
| + if (flags & VARF_WANTRES) |
| + newStr = Cmd_Exec(pattern.rhs, &emsg); |
| + else |
| + newStr = varNoError; |
| + free(UNCONST(pattern.rhs)); |
| + if (emsg) |
| + Error(emsg, unix_nstr); |
| + termc = *cp; |
| + delim = '\0'; |
| + if (v->flags & VAR_JUNK) { |
| + v->flags |= VAR_KEEP; |
| + } |
| + break; |
| + } |
| + case '[': { |
| + /* |
| * Look for the closing ']', recursively |
| @@ -2902,26 +2934,26 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - char *estr; |
| - |
| - cp = tstr+1; /* point to char after '[' */ |
| - delim = ']'; /* look for closing ']' */ |
| - estr = VarGetPattern(ctxt, &parsestate, |
| - flags, &cp, delim, |
| - NULL, NULL, NULL); |
| - if (estr == NULL) |
| - goto cleanup; /* report missing ']' */ |
| - /* now cp points just after the closing ']' */ |
| - delim = '\0'; |
| - if (cp[0] != ':' && cp[0] != endc) { |
| - /* Found junk after ']' */ |
| - free(estr); |
| - goto bad_modifier; |
| - } |
| - if (estr[0] == '\0') { |
| - /* Found empty square brackets in ":[]". */ |
| - free(estr); |
| - goto bad_modifier; |
| - } else if (estr[0] == '#' && estr[1] == '\0') { |
| - /* Found ":[#]" */ |
| - |
| - /* |
| + char *estr; |
| + |
| + cp = tstr + 1; /* point to char after '[' */ |
| + delim = ']'; /* look for closing ']' */ |
| + estr = VarGetPattern(ctxt, &parsestate, |
| + flags, &cp, delim, |
| + NULL, NULL, NULL); |
| + if (estr == NULL) |
| + goto cleanup; /* report missing ']' */ |
| + /* now cp points just after the closing ']' */ |
| + delim = '\0'; |
| + if (cp[0] != ':' && cp[0] != endc) { |
| + /* Found junk after ']' */ |
| + free(estr); |
| + goto bad_modifier; |
| + } |
| + if (estr[0] == '\0') { |
| + /* Found empty square brackets in ":[]". */ |
| + free(estr); |
| + goto bad_modifier; |
| + } else if (estr[0] == '#' && estr[1] == '\0') { |
| + /* Found ":[#]" */ |
| + |
| + /* |
| * We will need enough space for the decimal |
| @@ -2933,39 +2965,39 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - int newStrSize = |
| - (sizeof(int) * CHAR_BIT + 2) / 3 + 2; |
| - |
| - newStr = bmake_malloc(newStrSize); |
| - if (parsestate.oneBigWord) { |
| - strncpy(newStr, "1", newStrSize); |
| - } else { |
| - /* XXX: brk_string() is a rather expensive |
| + int newStrSize = |
| + (sizeof(int) * CHAR_BIT + 2) / 3 + 2; |
| + |
| + newStr = bmake_malloc(newStrSize); |
| + if (parsestate.oneBigWord) { |
| + strncpy(newStr, "1", newStrSize); |
| + } else { |
| + /* XXX: brk_string() is a rather expensive |
| * way of counting words. */ |
| - char **av; |
| - char *as; |
| - int ac; |
| - |
| - av = brk_string(nstr, &ac, FALSE, &as); |
| - snprintf(newStr, newStrSize, "%d", ac); |
| - free(as); |
| - free(av); |
| - } |
| - termc = *cp; |
| - free(estr); |
| - break; |
| - } else if (estr[0] == '*' && estr[1] == '\0') { |
| - /* Found ":[*]" */ |
| - parsestate.oneBigWord = TRUE; |
| - newStr = nstr; |
| - termc = *cp; |
| - free(estr); |
| - break; |
| - } else if (estr[0] == '@' && estr[1] == '\0') { |
| - /* Found ":[@]" */ |
| - parsestate.oneBigWord = FALSE; |
| - newStr = nstr; |
| - termc = *cp; |
| - free(estr); |
| - break; |
| - } else { |
| - /* |
| + char **av; |
| + char *as; |
| + int ac; |
| + |
| + av = brk_string(unix_nstr, &ac, FALSE, &as); |
| + snprintf(newStr, newStrSize, "%d", ac); |
| + free(as); |
| + free(av); |
| + } |
| + termc = *cp; |
| + free(estr); |
| + break; |
| + } else if (estr[0] == '*' && estr[1] == '\0') { |
| + /* Found ":[*]" */ |
| + parsestate.oneBigWord = TRUE; |
| + newStr = unix_nstr; |
| + termc = *cp; |
| + free(estr); |
| + break; |
| + } else if (estr[0] == '@' && estr[1] == '\0') { |
| + /* Found ":[@]" */ |
| + parsestate.oneBigWord = FALSE; |
| + newStr = unix_nstr; |
| + termc = *cp; |
| + free(estr); |
| + break; |
| + } else { |
| + /* |
| * We expect estr to contain a single |
| @@ -2974,28 +3006,28 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - VarSelectWords_t seldata = { 0, 0 }; |
| - |
| - seldata.start = strtol(estr, &ep, 0); |
| - if (ep == estr) { |
| - /* Found junk instead of a number */ |
| - free(estr); |
| - goto bad_modifier; |
| - } else if (ep[0] == '\0') { |
| - /* Found only one integer in :[N] */ |
| - seldata.end = seldata.start; |
| - } else if (ep[0] == '.' && ep[1] == '.' && |
| - ep[2] != '\0') { |
| - /* Expecting another integer after ".." */ |
| - ep += 2; |
| - seldata.end = strtol(ep, &ep, 0); |
| - if (ep[0] != '\0') { |
| - /* Found junk after ".." */ |
| - free(estr); |
| - goto bad_modifier; |
| - } |
| - } else { |
| - /* Found junk instead of ".." */ |
| - free(estr); |
| - goto bad_modifier; |
| - } |
| - /* |
| + VarSelectWords_t seldata = {0, 0}; |
| + |
| + seldata.start = strtol(estr, &ep, 0); |
| + if (ep == estr) { |
| + /* Found junk instead of a number */ |
| + free(estr); |
| + goto bad_modifier; |
| + } else if (ep[0] == '\0') { |
| + /* Found only one integer in :[N] */ |
| + seldata.end = seldata.start; |
| + } else if (ep[0] == '.' && ep[1] == '.' && |
| + ep[2] != '\0') { |
| + /* Expecting another integer after ".." */ |
| + ep += 2; |
| + seldata.end = strtol(ep, &ep, 0); |
| + if (ep[0] != '\0') { |
| + /* Found junk after ".." */ |
| + free(estr); |
| + goto bad_modifier; |
| + } |
| + } else { |
| + /* Found junk instead of ".." */ |
| + free(estr); |
| + goto bad_modifier; |
| + } |
| + /* |
| * Now seldata is properly filled in, |
| @@ -3004,16 +3036,16 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - if (seldata.start == 0 && seldata.end == 0) { |
| - /* ":[0]" or perhaps ":[0..0]" */ |
| - parsestate.oneBigWord = TRUE; |
| - newStr = nstr; |
| - termc = *cp; |
| - free(estr); |
| - break; |
| - } else if (seldata.start == 0 || |
| - seldata.end == 0) { |
| - /* ":[0..N]" or ":[N..0]" */ |
| - free(estr); |
| - goto bad_modifier; |
| - } |
| - /* |
| + if (seldata.start == 0 && seldata.end == 0) { |
| + /* ":[0]" or perhaps ":[0..0]" */ |
| + parsestate.oneBigWord = TRUE; |
| + newStr = unix_nstr; |
| + termc = *cp; |
| + free(estr); |
| + break; |
| + } else if (seldata.start == 0 || |
| + seldata.end == 0) { |
| + /* ":[0..N]" or ":[N..0]" */ |
| + free(estr); |
| + goto bad_modifier; |
| + } |
| + /* |
| * Normal case: select the words |
| @@ -3021,59 +3053,58 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - newStr = VarSelectWords(ctxt, &parsestate, |
| - nstr, &seldata); |
| - |
| - termc = *cp; |
| - free(estr); |
| - break; |
| - } |
| - |
| - } |
| - case 'g': |
| - cp = tstr + 1; /* make sure it is set */ |
| - if (STRMOD_MATCHX(tstr, "gmtime", 6)) { |
| - if (tstr[6] == '=') { |
| - utc = strtoul(&tstr[7], &ep, 10); |
| - cp = ep; |
| - } else { |
| - utc = 0; |
| - cp = tstr + 6; |
| - } |
| - newStr = VarStrftime(nstr, 1, utc); |
| - termc = *cp; |
| - } else { |
| - goto default_case; |
| - } |
| - break; |
| - case 'h': |
| - cp = tstr + 1; /* make sure it is set */ |
| - if (STRMOD_MATCH(tstr, "hash", 4)) { |
| - newStr = VarHash(nstr); |
| - cp = tstr + 4; |
| - termc = *cp; |
| - } else { |
| - goto default_case; |
| - } |
| - break; |
| - case 'l': |
| - cp = tstr + 1; /* make sure it is set */ |
| - if (STRMOD_MATCHX(tstr, "localtime", 9)) { |
| - if (tstr[9] == '=') { |
| - utc = strtoul(&tstr[10], &ep, 10); |
| - cp = ep; |
| - } else { |
| - utc = 0; |
| - cp = tstr + 9; |
| - } |
| - newStr = VarStrftime(nstr, 0, utc); |
| - termc = *cp; |
| - } else { |
| - goto default_case; |
| - } |
| - break; |
| - case 't': |
| - { |
| - cp = tstr + 1; /* make sure it is set */ |
| - if (tstr[1] != endc && tstr[1] != ':') { |
| - if (tstr[1] == 's') { |
| - /* |
| + newStr = VarSelectWords(ctxt, &parsestate, |
| + unix_nstr, &seldata); |
| + |
| + termc = *cp; |
| + free(estr); |
| + break; |
| + } |
| + |
| + } |
| + case 'g': |
| + cp = tstr + 1; /* make sure it is set */ |
| + if (STRMOD_MATCHX(tstr, "gmtime", 6)) { |
| + if (tstr[6] == '=') { |
| + utc = strtoul(&tstr[7], &ep, 10); |
| + cp = ep; |
| + } else { |
| + utc = 0; |
| + cp = tstr + 6; |
| + } |
| + newStr = VarStrftime(unix_nstr, 1, utc); |
| + termc = *cp; |
| + } else { |
| + goto default_case; |
| + } |
| + break; |
| + case 'h': |
| + cp = tstr + 1; /* make sure it is set */ |
| + if (STRMOD_MATCH(tstr, "hash", 4)) { |
| + newStr = VarHash(unix_nstr); |
| + cp = tstr + 4; |
| + termc = *cp; |
| + } else { |
| + goto default_case; |
| + } |
| + break; |
| + case 'l': |
| + cp = tstr + 1; /* make sure it is set */ |
| + if (STRMOD_MATCHX(tstr, "localtime", 9)) { |
| + if (tstr[9] == '=') { |
| + utc = strtoul(&tstr[10], &ep, 10); |
| + cp = ep; |
| + } else { |
| + utc = 0; |
| + cp = tstr + 9; |
| + } |
| + newStr = VarStrftime(unix_nstr, 0, utc); |
| + termc = *cp; |
| + } else { |
| + goto default_case; |
| + } |
| + break; |
| + case 't': { |
| + cp = tstr + 1; /* make sure it is set */ |
| + if (tstr[1] != endc && tstr[1] != ':') { |
| + if (tstr[1] == 's') { |
| + /* |
| * Use the char (if any) at tstr[2] |
| @@ -3081,61 +3112,61 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - VarPattern pattern; |
| + VarPattern pattern; |
| |
| - if (tstr[2] != endc && |
| - (tstr[3] == endc || tstr[3] == ':')) { |
| - /* ":ts<unrecognised><endc>" or |
| + if (tstr[2] != endc && |
| + (tstr[3] == endc || tstr[3] == ':')) { |
| + /* ":ts<unrecognised><endc>" or |
| * ":ts<unrecognised>:" */ |
| - parsestate.varSpace = tstr[2]; |
| - cp = tstr + 3; |
| - } else if (tstr[2] == endc || tstr[2] == ':') { |
| - /* ":ts<endc>" or ":ts:" */ |
| - parsestate.varSpace = 0; /* no separator */ |
| - cp = tstr + 2; |
| - } else if (tstr[2] == '\\') { |
| - const char *xp = &tstr[3]; |
| - int base = 8; /* assume octal */ |
| - |
| - switch (tstr[3]) { |
| - case 'n': |
| - parsestate.varSpace = '\n'; |
| - cp = tstr + 4; |
| - break; |
| - case 't': |
| - parsestate.varSpace = '\t'; |
| - cp = tstr + 4; |
| - break; |
| - case 'x': |
| - base = 16; |
| - xp++; |
| - goto get_numeric; |
| - case '0': |
| - base = 0; |
| - goto get_numeric; |
| - default: |
| - if (isdigit((unsigned char)tstr[3])) { |
| - |
| - get_numeric: |
| - parsestate.varSpace = |
| - strtoul(xp, &ep, base); |
| - if (*ep != ':' && *ep != endc) |
| - goto bad_modifier; |
| - cp = ep; |
| - } else { |
| - /* |
| + parsestate.varSpace = tstr[2]; |
| + cp = tstr + 3; |
| + } else if (tstr[2] == endc || tstr[2] == ':') { |
| + /* ":ts<endc>" or ":ts:" */ |
| + parsestate.varSpace = 0; /* no separator */ |
| + cp = tstr + 2; |
| + } else if (tstr[2] == '\\') { |
| + const char *xp = &tstr[3]; |
| + int base = 8; /* assume octal */ |
| + |
| + switch (tstr[3]) { |
| + case 'n': |
| + parsestate.varSpace = '\n'; |
| + cp = tstr + 4; |
| + break; |
| + case 't': |
| + parsestate.varSpace = '\t'; |
| + cp = tstr + 4; |
| + break; |
| + case 'x': |
| + base = 16; |
| + xp++; |
| + goto get_numeric; |
| + case '0': |
| + base = 0; |
| + goto get_numeric; |
| + default: |
| + if (isdigit((unsigned char) tstr[3])) { |
| + |
| + get_numeric: |
| + parsestate.varSpace = |
| + strtoul(xp, &ep, base); |
| + if (*ep != ':' && *ep != endc) |
| + goto bad_modifier; |
| + cp = ep; |
| + } else { |
| + /* |
| * ":ts<backslash><unrecognised>". |
| */ |
| - goto bad_modifier; |
| - } |
| - break; |
| - } |
| - } else { |
| - /* |
| + goto bad_modifier; |
| + } |
| + break; |
| + } |
| + } else { |
| + /* |
| * Found ":ts<unrecognised><unrecognised>". |
| */ |
| - goto bad_modifier; |
| - } |
| + goto bad_modifier; |
| + } |
| |
| - termc = *cp; |
| + termc = *cp; |
| |
| - /* |
| + /* |
| * We cannot be certain that VarModify |
| @@ -3146,11 +3177,11 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - pattern.flags = VAR_SUB_ONE; |
| - pattern.lhs = pattern.rhs = "\032"; |
| - pattern.leftLen = pattern.rightLen = 1; |
| - |
| - newStr = VarModify(ctxt, &parsestate, nstr, |
| - VarSubstitute, |
| - &pattern); |
| - } else if (tstr[2] == endc || tstr[2] == ':') { |
| - /* |
| + pattern.flags = VAR_SUB_ONE; |
| + pattern.lhs = pattern.rhs = "\032"; |
| + pattern.leftLen = pattern.rightLen = 1; |
| + |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, |
| + VarSubstitute, |
| + &pattern); |
| + } else if (tstr[2] == endc || tstr[2] == ':') { |
| + /* |
| * Check for two-character options: |
| @@ -3158,57 +3189,56 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - if (tstr[1] == 'A') { /* absolute path */ |
| - newStr = VarModify(ctxt, &parsestate, nstr, |
| - VarRealpath, NULL); |
| - cp = tstr + 2; |
| - termc = *cp; |
| - } else if (tstr[1] == 'u') { |
| - char *dp = bmake_strdup(nstr); |
| - for (newStr = dp; *dp; dp++) |
| - *dp = toupper((unsigned char)*dp); |
| - cp = tstr + 2; |
| - termc = *cp; |
| - } else if (tstr[1] == 'l') { |
| - char *dp = bmake_strdup(nstr); |
| - for (newStr = dp; *dp; dp++) |
| - *dp = tolower((unsigned char)*dp); |
| - cp = tstr + 2; |
| - termc = *cp; |
| - } else if (tstr[1] == 'W' || tstr[1] == 'w') { |
| - parsestate.oneBigWord = (tstr[1] == 'W'); |
| - newStr = nstr; |
| - cp = tstr + 2; |
| - termc = *cp; |
| - } else { |
| - /* Found ":t<unrecognised>:" or |
| + if (tstr[1] == 'A') { /* absolute path */ |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, |
| + VarRealpath, NULL); |
| + cp = tstr + 2; |
| + termc = *cp; |
| + } else if (tstr[1] == 'u') { |
| + char *dp = bmake_strdup(unix_nstr); |
| + for (newStr = dp; *dp; dp++) |
| + *dp = toupper((unsigned char) *dp); |
| + cp = tstr + 2; |
| + termc = *cp; |
| + } else if (tstr[1] == 'l') { |
| + char *dp = bmake_strdup(unix_nstr); |
| + for (newStr = dp; *dp; dp++) |
| + *dp = tolower((unsigned char) *dp); |
| + cp = tstr + 2; |
| + termc = *cp; |
| + } else if (tstr[1] == 'W' || tstr[1] == 'w') { |
| + parsestate.oneBigWord = (tstr[1] == 'W'); |
| + newStr = unix_nstr; |
| + cp = tstr + 2; |
| + termc = *cp; |
| + } else { |
| + /* Found ":t<unrecognised>:" or |
| * ":t<unrecognised><endc>". */ |
| - goto bad_modifier; |
| - } |
| - } else { |
| - /* |
| + goto bad_modifier; |
| + } |
| + } else { |
| + /* |
| * Found ":t<unrecognised><unrecognised>". |
| */ |
| - goto bad_modifier; |
| - } |
| - } else { |
| - /* |
| + goto bad_modifier; |
| + } |
| + } else { |
| + /* |
| * Found ":t<endc>" or ":t:". |
| */ |
| - goto bad_modifier; |
| - } |
| - break; |
| - } |
| - case 'N': |
| - case 'M': |
| - { |
| - char *pattern; |
| - const char *endpat; /* points just after end of pattern */ |
| - char *cp2; |
| - Boolean copy; /* pattern should be, or has been, copied */ |
| - Boolean needSubst; |
| - int nest; |
| - |
| - copy = FALSE; |
| - needSubst = FALSE; |
| - nest = 1; |
| - /* |
| + goto bad_modifier; |
| + } |
| + break; |
| + } |
| + case 'N': |
| + case 'M': { |
| + char *pattern; |
| + const char *endpat; /* points just after end of pattern */ |
| + char *cp2; |
| + Boolean copy; /* pattern should be, or has been, copied */ |
| + Boolean needSubst; |
| + int nest; |
| + |
| + copy = FALSE; |
| + needSubst = FALSE; |
| + nest = 1; |
| + /* |
| * In the loop below, ignore ':' unless we are at |
| @@ -3218,30 +3248,29 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - for (cp = tstr + 1; |
| - *cp != '\0' && !(*cp == ':' && nest == 1); |
| - cp++) |
| - { |
| - if (*cp == '\\' && |
| - (cp[1] == ':' || |
| - cp[1] == endc || cp[1] == startc)) { |
| - if (!needSubst) { |
| - copy = TRUE; |
| - } |
| - cp++; |
| - continue; |
| - } |
| - if (*cp == '$') { |
| - needSubst = TRUE; |
| - } |
| - if (*cp == '(' || *cp == '{') |
| - ++nest; |
| - if (*cp == ')' || *cp == '}') { |
| - --nest; |
| - if (nest == 0) |
| - break; |
| - } |
| - } |
| - termc = *cp; |
| - endpat = cp; |
| - if (copy) { |
| - /* |
| + for (cp = tstr + 1; |
| + *cp != '\0' && !(*cp == ':' && nest == 1); |
| + cp++) { |
| + if (*cp == '\\' && |
| + (cp[1] == ':' || |
| + cp[1] == endc || cp[1] == startc)) { |
| + if (!needSubst) { |
| + copy = TRUE; |
| + } |
| + cp++; |
| + continue; |
| + } |
| + if (*cp == '$') { |
| + needSubst = TRUE; |
| + } |
| + if (*cp == '(' || *cp == '{') |
| + ++nest; |
| + if (*cp == ')' || *cp == '}') { |
| + --nest; |
| + if (nest == 0) |
| + break; |
| + } |
| + } |
| + termc = *cp; |
| + endpat = cp; |
| + if (copy) { |
| + /* |
| * Need to compress the \:'s out of the pattern, so |
| @@ -3252,17 +3281,16 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - pattern = bmake_malloc(cp - tstr); |
| - for (cp2 = pattern, cp = tstr + 1; |
| - cp < endpat; |
| - cp++, cp2++) |
| - { |
| - if ((*cp == '\\') && (cp+1 < endpat) && |
| - (cp[1] == ':' || cp[1] == endc)) { |
| - cp++; |
| - } |
| - *cp2 = *cp; |
| - } |
| - *cp2 = '\0'; |
| - endpat = cp2; |
| - } else { |
| - /* |
| + pattern = bmake_malloc(cp - tstr); |
| + for (cp2 = pattern, cp = tstr + 1; |
| + cp < endpat; |
| + cp++, cp2++) { |
| + if ((*cp == '\\') && (cp + 1 < endpat) && |
| + (cp[1] == ':' || cp[1] == endc)) { |
| + cp++; |
| + } |
| + *cp2 = *cp; |
| + } |
| + *cp2 = '\0'; |
| + endpat = cp2; |
| + } else { |
| + /* |
| * Either Var_Subst or VarModify will need a |
| @@ -3270,6 +3298,6 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - pattern = bmake_strndup(tstr+1, endpat - (tstr + 1)); |
| - } |
| - if (needSubst) { |
| - /* |
| + pattern = bmake_strndup(tstr + 1, endpat - (tstr + 1)); |
| + } |
| + if (needSubst) { |
| + /* |
| * pattern contains embedded '$', so use Var_Subst to |
| @@ -3277,30 +3305,29 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - cp2 = pattern; |
| - pattern = Var_Subst(NULL, cp2, ctxt, flags | VARF_WANTRES); |
| - free(cp2); |
| - } |
| - if (DEBUG(VAR)) |
| - fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", |
| - v->name, nstr, pattern); |
| - if (*tstr == 'M') { |
| - newStr = VarModify(ctxt, &parsestate, nstr, VarMatch, |
| - pattern); |
| - } else { |
| - newStr = VarModify(ctxt, &parsestate, nstr, VarNoMatch, |
| - pattern); |
| - } |
| - free(pattern); |
| - break; |
| - } |
| - case 'S': |
| - { |
| - VarPattern pattern; |
| - Var_Parse_State tmpparsestate; |
| - |
| - pattern.flags = 0; |
| - tmpparsestate = parsestate; |
| - delim = tstr[1]; |
| - tstr += 2; |
| - |
| - /* |
| + cp2 = pattern; |
| + pattern = Var_Subst(NULL, cp2, ctxt, flags | VARF_WANTRES); |
| + free(cp2); |
| + } |
| + if (DEBUG(VAR)) |
| + fprintf(debug_file, "Pattern[%s] for [%s] is [%s]\n", |
| + v->name, unix_nstr, pattern); |
| + if (*tstr == 'M') { |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarMatch, |
| + pattern); |
| + } else { |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarNoMatch, |
| + pattern); |
| + } |
| + free(pattern); |
| + break; |
| + } |
| + case 'S': { |
| + VarPattern pattern; |
| + Var_Parse_State tmpparsestate; |
| + |
| + pattern.flags = 0; |
| + tmpparsestate = parsestate; |
| + delim = tstr[1]; |
| + tstr += 2; |
| + |
| + /* |
| * If pattern begins with '^', it is anchored to the |
| @@ -3308,22 +3335,22 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - if (*tstr == '^') { |
| - pattern.flags |= VAR_MATCH_START; |
| - tstr += 1; |
| - } |
| - |
| - cp = tstr; |
| - if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, |
| - &cp, delim, |
| - &pattern.flags, |
| - &pattern.leftLen, |
| - NULL)) == NULL) |
| - goto cleanup; |
| - |
| - if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, |
| - &cp, delim, NULL, |
| - &pattern.rightLen, |
| - &pattern)) == NULL) |
| - goto cleanup; |
| - |
| - /* |
| + if (*tstr == '^') { |
| + pattern.flags |= VAR_MATCH_START; |
| + tstr += 1; |
| + } |
| + |
| + cp = tstr; |
| + if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, |
| + &cp, delim, |
| + &pattern.flags, |
| + &pattern.leftLen, |
| + NULL)) == NULL) |
| + goto cleanup; |
| + |
| + if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, |
| + &cp, delim, NULL, |
| + &pattern.rightLen, |
| + &pattern)) == NULL) |
| + goto cleanup; |
| + |
| + /* |
| * Check for global substitution. If 'g' after the final |
| @@ -3332,271 +3359,268 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - for (;; cp++) { |
| - switch (*cp) { |
| - case 'g': |
| - pattern.flags |= VAR_SUB_GLOBAL; |
| - continue; |
| - case '1': |
| - pattern.flags |= VAR_SUB_ONE; |
| - continue; |
| - case 'W': |
| - tmpparsestate.oneBigWord = TRUE; |
| - continue; |
| - } |
| - break; |
| - } |
| - |
| - termc = *cp; |
| - newStr = VarModify(ctxt, &tmpparsestate, nstr, |
| - VarSubstitute, |
| - &pattern); |
| - |
| - /* |
| + for (;; cp++) { |
| + switch (*cp) { |
| + case 'g': |
| + pattern.flags |= VAR_SUB_GLOBAL; |
| + continue; |
| + case '1': |
| + pattern.flags |= VAR_SUB_ONE; |
| + continue; |
| + case 'W': |
| + tmpparsestate.oneBigWord = TRUE; |
| + continue; |
| + } |
| + break; |
| + } |
| + |
| + termc = *cp; |
| + newStr = VarModify(ctxt, &tmpparsestate, unix_nstr, |
| + VarSubstitute, |
| + &pattern); |
| + |
| + /* |
| * Free the two strings. |
| */ |
| - free(UNCONST(pattern.lhs)); |
| - free(UNCONST(pattern.rhs)); |
| - delim = '\0'; |
| - break; |
| - } |
| - case '?': |
| - { |
| - VarPattern pattern; |
| - Boolean value; |
| - int cond_rc; |
| - int lhs_flags, rhs_flags; |
| - |
| - /* find ':', and then substitute accordingly */ |
| - if (flags & VARF_WANTRES) { |
| - cond_rc = Cond_EvalExpression(NULL, v->name, &value, 0, FALSE); |
| - if (cond_rc == COND_INVALID) { |
| - lhs_flags = rhs_flags = VAR_NOSUBST; |
| - } else if (value) { |
| - lhs_flags = 0; |
| - rhs_flags = VAR_NOSUBST; |
| - } else { |
| - lhs_flags = VAR_NOSUBST; |
| - rhs_flags = 0; |
| - } |
| - } else { |
| - /* we are just consuming and discarding */ |
| - cond_rc = value = 0; |
| - lhs_flags = rhs_flags = VAR_NOSUBST; |
| - } |
| - pattern.flags = 0; |
| - |
| - cp = ++tstr; |
| - delim = ':'; |
| - if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, |
| - &cp, delim, &lhs_flags, |
| - &pattern.leftLen, |
| - NULL)) == NULL) |
| - goto cleanup; |
| - |
| - /* BROPEN or PROPEN */ |
| - delim = endc; |
| - if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, |
| - &cp, delim, &rhs_flags, |
| - &pattern.rightLen, |
| - NULL)) == NULL) |
| - goto cleanup; |
| - |
| - termc = *--cp; |
| - delim = '\0'; |
| - if (cond_rc == COND_INVALID) { |
| - Error("Bad conditional expression `%s' in %s?%s:%s", |
| - v->name, v->name, pattern.lhs, pattern.rhs); |
| - goto cleanup; |
| - } |
| - |
| - if (value) { |
| - newStr = UNCONST(pattern.lhs); |
| - free(UNCONST(pattern.rhs)); |
| - } else { |
| - newStr = UNCONST(pattern.rhs); |
| - free(UNCONST(pattern.lhs)); |
| - } |
| - if (v->flags & VAR_JUNK) { |
| - v->flags |= VAR_KEEP; |
| - } |
| - break; |
| - } |
| + free(UNCONST(pattern.lhs)); |
| + free(UNCONST(pattern.rhs)); |
| + delim = '\0'; |
| + break; |
| + } |
| + case '?': { |
| + VarPattern pattern; |
| + Boolean value; |
| + int cond_rc; |
| + int lhs_flags, rhs_flags; |
| + |
| + /* find ':', and then substitute accordingly */ |
| + if (flags & VARF_WANTRES) { |
| + cond_rc = Cond_EvalExpression(NULL, v->name, &value, 0, FALSE); |
| + if (cond_rc == COND_INVALID) { |
| + lhs_flags = rhs_flags = VAR_NOSUBST; |
| + } else if (value) { |
| + lhs_flags = 0; |
| + rhs_flags = VAR_NOSUBST; |
| + } else { |
| + lhs_flags = VAR_NOSUBST; |
| + rhs_flags = 0; |
| + } |
| + } else { |
| + /* we are just consuming and discarding */ |
| + cond_rc = value = 0; |
| + lhs_flags = rhs_flags = VAR_NOSUBST; |
| + } |
| + pattern.flags = 0; |
| + |
| + cp = ++tstr; |
| + delim = ':'; |
| + if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, flags, |
| + &cp, delim, &lhs_flags, |
| + &pattern.leftLen, |
| + NULL)) == NULL) |
| + goto cleanup; |
| + |
| + /* BROPEN or PROPEN */ |
| + delim = endc; |
| + if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, flags, |
| + &cp, delim, &rhs_flags, |
| + &pattern.rightLen, |
| + NULL)) == NULL) |
| + goto cleanup; |
| + |
| + termc = *--cp; |
| + delim = '\0'; |
| + if (cond_rc == COND_INVALID) { |
| + Error("Bad conditional expression `%s' in %s?%s:%s", |
| + v->name, v->name, pattern.lhs, pattern.rhs); |
| + goto cleanup; |
| + } |
| + |
| + if (value) { |
| + newStr = UNCONST(pattern.lhs); |
| + free(UNCONST(pattern.rhs)); |
| + } else { |
| + newStr = UNCONST(pattern.rhs); |
| + free(UNCONST(pattern.lhs)); |
| + } |
| + if (v->flags & VAR_JUNK) { |
| + v->flags |= VAR_KEEP; |
| + } |
| + break; |
| + } |
| #ifndef NO_REGEX |
| - case 'C': |
| - { |
| - VarREPattern pattern; |
| - char *re; |
| - int error; |
| - Var_Parse_State tmpparsestate; |
| - |
| - pattern.flags = 0; |
| - tmpparsestate = parsestate; |
| - delim = tstr[1]; |
| - tstr += 2; |
| - |
| - cp = tstr; |
| - |
| - if ((re = VarGetPattern(ctxt, &parsestate, flags, &cp, delim, |
| - NULL, NULL, NULL)) == NULL) |
| - goto cleanup; |
| - |
| - if ((pattern.replace = VarGetPattern(ctxt, &parsestate, |
| - flags, &cp, delim, NULL, |
| - NULL, NULL)) == NULL){ |
| - free(re); |
| - goto cleanup; |
| - } |
| - |
| - for (;; cp++) { |
| - switch (*cp) { |
| - case 'g': |
| - pattern.flags |= VAR_SUB_GLOBAL; |
| - continue; |
| - case '1': |
| - pattern.flags |= VAR_SUB_ONE; |
| - continue; |
| - case 'W': |
| - tmpparsestate.oneBigWord = TRUE; |
| - continue; |
| - } |
| - break; |
| - } |
| - |
| - termc = *cp; |
| - |
| - error = regcomp(&pattern.re, re, REG_EXTENDED); |
| - free(re); |
| - if (error) { |
| - *lengthPtr = cp - start + 1; |
| - VarREError(error, &pattern.re, "RE substitution error"); |
| - free(pattern.replace); |
| - goto cleanup; |
| - } |
| - |
| - pattern.nsub = pattern.re.re_nsub + 1; |
| - if (pattern.nsub < 1) |
| - pattern.nsub = 1; |
| - if (pattern.nsub > 10) |
| - pattern.nsub = 10; |
| - pattern.matches = bmake_malloc(pattern.nsub * |
| - sizeof(regmatch_t)); |
| - newStr = VarModify(ctxt, &tmpparsestate, nstr, |
| - VarRESubstitute, |
| - &pattern); |
| - regfree(&pattern.re); |
| - free(pattern.replace); |
| - free(pattern.matches); |
| - delim = '\0'; |
| - break; |
| - } |
| + case 'C': { |
| + VarREPattern pattern; |
| + char *re; |
| + int error; |
| + Var_Parse_State tmpparsestate; |
| + |
| + pattern.flags = 0; |
| + tmpparsestate = parsestate; |
| + delim = tstr[1]; |
| + tstr += 2; |
| + |
| + cp = tstr; |
| + |
| + if ((re = VarGetPattern(ctxt, &parsestate, flags, &cp, delim, |
| + NULL, NULL, NULL)) == NULL) |
| + goto cleanup; |
| + |
| + if ((pattern.replace = VarGetPattern(ctxt, &parsestate, |
| + flags, &cp, delim, NULL, |
| + NULL, NULL)) == NULL) { |
| + free(re); |
| + goto cleanup; |
| + } |
| + |
| + for (;; cp++) { |
| + switch (*cp) { |
| + case 'g': |
| + pattern.flags |= VAR_SUB_GLOBAL; |
| + continue; |
| + case '1': |
| + pattern.flags |= VAR_SUB_ONE; |
| + continue; |
| + case 'W': |
| + tmpparsestate.oneBigWord = TRUE; |
| + continue; |
| + } |
| + break; |
| + } |
| + |
| + termc = *cp; |
| + |
| + error = regcomp(&pattern.re, re, REG_EXTENDED); |
| + free(re); |
| + if (error) { |
| + *lengthPtr = cp - start + 1; |
| + VarREError(error, &pattern.re, "RE substitution error"); |
| + free(pattern.replace); |
| + goto cleanup; |
| + } |
| + |
| + pattern.nsub = pattern.re.re_nsub + 1; |
| + if (pattern.nsub < 1) |
| + pattern.nsub = 1; |
| + if (pattern.nsub > 10) |
| + pattern.nsub = 10; |
| + pattern.matches = bmake_malloc(pattern.nsub * |
| + sizeof(regmatch_t)); |
| + newStr = VarModify(ctxt, &tmpparsestate, unix_nstr, |
| + VarRESubstitute, |
| + &pattern); |
| + regfree(&pattern.re); |
| + free(pattern.replace); |
| + free(pattern.matches); |
| + delim = '\0'; |
| + break; |
| + } |
| #endif |
| - case 'q': |
| - case 'Q': |
| - if (tstr[1] == endc || tstr[1] == ':') { |
| - newStr = VarQuote(nstr, modifier == 'q'); |
| - cp = tstr + 1; |
| - termc = *cp; |
| - break; |
| - } |
| - goto default_case; |
| - case 'T': |
| - if (tstr[1] == endc || tstr[1] == ':') { |
| - newStr = VarModify(ctxt, &parsestate, nstr, VarTail, |
| - NULL); |
| - cp = tstr + 1; |
| - termc = *cp; |
| - break; |
| - } |
| - goto default_case; |
| - case 'H': |
| - if (tstr[1] == endc || tstr[1] == ':') { |
| - newStr = VarModify(ctxt, &parsestate, nstr, VarHead, |
| - NULL); |
| - cp = tstr + 1; |
| - termc = *cp; |
| - break; |
| - } |
| - goto default_case; |
| - case 'E': |
| - if (tstr[1] == endc || tstr[1] == ':') { |
| - newStr = VarModify(ctxt, &parsestate, nstr, VarSuffix, |
| - NULL); |
| - cp = tstr + 1; |
| - termc = *cp; |
| - break; |
| - } |
| - goto default_case; |
| - case 'R': |
| - if (tstr[1] == endc || tstr[1] == ':') { |
| - newStr = VarModify(ctxt, &parsestate, nstr, VarRoot, |
| - NULL); |
| - cp = tstr + 1; |
| - termc = *cp; |
| - break; |
| - } |
| - goto default_case; |
| - case 'r': |
| - cp = tstr + 1; /* make sure it is set */ |
| - if (STRMOD_MATCHX(tstr, "range", 5)) { |
| - int n; |
| - |
| - if (tstr[5] == '=') { |
| - n = strtoul(&tstr[6], &ep, 10); |
| - cp = ep; |
| - } else { |
| - n = 0; |
| - cp = tstr + 5; |
| - } |
| - newStr = VarRange(nstr, n); |
| - termc = *cp; |
| - break; |
| - } |
| - goto default_case; |
| - case 'O': |
| - { |
| - char otype; |
| - |
| - cp = tstr + 1; /* skip to the rest in any case */ |
| - if (tstr[1] == endc || tstr[1] == ':') { |
| - otype = 's'; |
| - termc = *cp; |
| - } else if ( (tstr[1] == 'x') && |
| - (tstr[2] == endc || tstr[2] == ':') ) { |
| - otype = tstr[1]; |
| - cp = tstr + 2; |
| - termc = *cp; |
| - } else { |
| - goto bad_modifier; |
| - } |
| - newStr = VarOrder(nstr, otype); |
| - break; |
| - } |
| - case 'u': |
| - if (tstr[1] == endc || tstr[1] == ':') { |
| - newStr = VarUniq(nstr); |
| - cp = tstr + 1; |
| - termc = *cp; |
| - break; |
| - } |
| - goto default_case; |
| + case 'q': |
| + case 'Q': |
| + if (tstr[1] == endc || tstr[1] == ':') { |
| + newStr = VarQuote(unix_nstr, modifier == 'q'); |
| + cp = tstr + 1; |
| + termc = *cp; |
| + break; |
| + } |
| + goto default_case; |
| + case 'T': |
| + if (tstr[1] == endc || tstr[1] == ':') { |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarTail, |
| + NULL); |
| + cp = tstr + 1; |
| + termc = *cp; |
| + break; |
| + } |
| + goto default_case; |
| + case 'H': |
| + if (tstr[1] == endc || tstr[1] == ':') { |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarHead, |
| + NULL); |
| + cp = tstr + 1; |
| + termc = *cp; |
| + break; |
| + } |
| + goto default_case; |
| + case 'E': |
| + if (tstr[1] == endc || tstr[1] == ':') { |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarSuffix, |
| + NULL); |
| + cp = tstr + 1; |
| + termc = *cp; |
| + break; |
| + } |
| + goto default_case; |
| + case 'R': |
| + if (tstr[1] == endc || tstr[1] == ':') { |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, VarRoot, |
| + NULL); |
| + cp = tstr + 1; |
| + termc = *cp; |
| + break; |
| + } |
| + goto default_case; |
| + case 'r': |
| + cp = tstr + 1; /* make sure it is set */ |
| + if (STRMOD_MATCHX(tstr, "range", 5)) { |
| + int n; |
| + |
| + if (tstr[5] == '=') { |
| + n = strtoul(&tstr[6], &ep, 10); |
| + cp = ep; |
| + } else { |
| + n = 0; |
| + cp = tstr + 5; |
| + } |
| + newStr = VarRange(unix_nstr, n); |
| + termc = *cp; |
| + break; |
| + } |
| + goto default_case; |
| + case 'O': { |
| + char otype; |
| + |
| + cp = tstr + 1; /* skip to the rest in any case */ |
| + if (tstr[1] == endc || tstr[1] == ':') { |
| + otype = 's'; |
| + termc = *cp; |
| + } else if ((tstr[1] == 'x') && |
| + (tstr[2] == endc || tstr[2] == ':')) { |
| + otype = tstr[1]; |
| + cp = tstr + 2; |
| + termc = *cp; |
| + } else { |
| + goto bad_modifier; |
| + } |
| + newStr = VarOrder(unix_nstr, otype); |
| + break; |
| + } |
| + case 'u': |
| + if (tstr[1] == endc || tstr[1] == ':') { |
| + newStr = VarUniq(unix_nstr); |
| + cp = tstr + 1; |
| + termc = *cp; |
| + break; |
| + } |
| + goto default_case; |
| #ifdef SUNSHCMD |
| - case 's': |
| - if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { |
| - const char *emsg; |
| - if (flags & VARF_WANTRES) { |
| - newStr = Cmd_Exec(nstr, &emsg); |
| - if (emsg) |
| - Error(emsg, nstr); |
| - } else |
| - newStr = varNoError; |
| - cp = tstr + 2; |
| - termc = *cp; |
| - break; |
| - } |
| - goto default_case; |
| + case 's': |
| + if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { |
| + const char *emsg; |
| + if (flags & VARF_WANTRES) { |
| + newStr = Cmd_Exec(unix_nstr, &emsg); |
| + if (emsg) |
| + Error(emsg, unix_nstr); |
| + } else |
| + newStr = varNoError; |
| + cp = tstr + 2; |
| + termc = *cp; |
| + break; |
| + } |
| + goto default_case; |
| #endif |
| - default: |
| - default_case: |
| - { |
| + default: |
| + default_case: |
| + { |
| #ifdef SYSVVARSUB |
| - /* |
| + /* |
| * This can either be a bogus modifier or a System-V |
| @@ -3604,8 +3628,8 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - VarPattern pattern; |
| - Boolean eqFound; |
| + VarPattern pattern; |
| + Boolean eqFound; |
| |
| - pattern.flags = 0; |
| - eqFound = FALSE; |
| - /* |
| + pattern.flags = 0; |
| + eqFound = FALSE; |
| + /* |
| * First we make a pass through the string trying |
| @@ -3614,19 +3638,18 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - cp = tstr; |
| - cnt = 1; |
| - while (*cp != '\0' && cnt) { |
| - if (*cp == '=') { |
| - eqFound = TRUE; |
| - /* continue looking for endc */ |
| - } |
| - else if (*cp == endc) |
| - cnt--; |
| - else if (*cp == startc) |
| - cnt++; |
| - if (cnt) |
| - cp++; |
| - } |
| - if (*cp == endc && eqFound) { |
| - |
| - /* |
| + cp = tstr; |
| + cnt = 1; |
| + while (*cp != '\0' && cnt) { |
| + if (*cp == '=') { |
| + eqFound = TRUE; |
| + /* continue looking for endc */ |
| + } else if (*cp == endc) |
| + cnt--; |
| + else if (*cp == startc) |
| + cnt++; |
| + if (cnt) |
| + cp++; |
| + } |
| + if (*cp == endc && eqFound) { |
| + |
| + /* |
| * Now we break this sucker into the lhs and |
| @@ -3634,15 +3657,15 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - delim='='; |
| - cp = tstr; |
| - if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, |
| - flags, &cp, delim, &pattern.flags, |
| - &pattern.leftLen, NULL)) == NULL) |
| - goto cleanup; |
| - delim = endc; |
| - if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, |
| - flags, &cp, delim, NULL, &pattern.rightLen, |
| - &pattern)) == NULL) |
| - goto cleanup; |
| - |
| - /* |
| + delim = '='; |
| + cp = tstr; |
| + if ((pattern.lhs = VarGetPattern(ctxt, &parsestate, |
| + flags, &cp, delim, &pattern.flags, |
| + &pattern.leftLen, NULL)) == NULL) |
| + goto cleanup; |
| + delim = endc; |
| + if ((pattern.rhs = VarGetPattern(ctxt, &parsestate, |
| + flags, &cp, delim, NULL, &pattern.rightLen, |
| + &pattern)) == NULL) |
| + goto cleanup; |
| + |
| + /* |
| * SYSV modifications happen through the whole |
| @@ -3650,62 +3673,63 @@ ApplyModifiers(char *nstr, const char *tstr, |
| */ |
| - termc = *--cp; |
| - delim = '\0'; |
| - if (pattern.leftLen == 0 && *nstr == '\0') { |
| - newStr = nstr; /* special case */ |
| - } else { |
| - newStr = VarModify(ctxt, &parsestate, nstr, |
| - VarSYSVMatch, |
| - &pattern); |
| - } |
| - free(UNCONST(pattern.lhs)); |
| - free(UNCONST(pattern.rhs)); |
| - } else |
| + termc = *--cp; |
| + delim = '\0'; |
| + if (pattern.leftLen == 0 && *unix_nstr == '\0') { |
| + newStr = unix_nstr; /* special case */ |
| + } else { |
| + newStr = VarModify(ctxt, &parsestate, unix_nstr, |
| + VarSYSVMatch, |
| + &pattern); |
| + } |
| + free(UNCONST(pattern.lhs)); |
| + free(UNCONST(pattern.rhs)); |
| + } else |
| #endif |
| - { |
| - Error("Unknown modifier '%c'", *tstr); |
| - for (cp = tstr+1; |
| - *cp != ':' && *cp != endc && *cp != '\0'; |
| - cp++) |
| - continue; |
| - termc = *cp; |
| - newStr = var_Error; |
| - } |
| - } |
| - } |
| - if (DEBUG(VAR)) { |
| - fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", |
| - v->name, modifier, newStr); |
| - } |
| - |
| - if (newStr != nstr) { |
| - if (*freePtr) { |
| - free(nstr); |
| - *freePtr = NULL; |
| - } |
| - nstr = newStr; |
| - if (nstr != var_Error && nstr != varNoError) { |
| - *freePtr = nstr; |
| - } |
| - } |
| - if (termc == '\0' && endc != '\0') { |
| - Error("Unclosed variable specification (expecting '%c') for \"%s\" (value \"%s\") modifier %c", endc, v->name, nstr, modifier); |
| - } else if (termc == ':') { |
| - cp++; |
| - } |
| - tstr = cp; |
| - } |
| - out: |
| + { |
| + Error("Unknown modifier '%c'", *tstr); |
| + for (cp = tstr + 1; |
| + *cp != ':' && *cp != endc && *cp != '\0'; |
| + cp++) |
| + continue; |
| + termc = *cp; |
| + newStr = var_Error; |
| + } |
| + } |
| + } |
| + if (DEBUG(VAR)) { |
| + fprintf(debug_file, "Result[%s] of :%c is \"%s\"\n", |
| + v->name, modifier, newStr); |
| + } |
| + |
| + if (newStr != unix_nstr) { |
| + if (*freePtr) { |
| + free(unix_nstr); |
| + *freePtr = NULL; |
| + } |
| + unix_nstr = newStr; |
| + if (unix_nstr != var_Error && unix_nstr != varNoError) { |
| + *freePtr = unix_nstr; |
| + } |
| + } |
| + if (termc == '\0' && endc != '\0') { |
| + Error("Unclosed variable specification (expecting '%c') for \"%s\" (value \"%s\") modifier %c", endc, |
| + v->name, unix_nstr, modifier); |
| + } else if (termc == ':') { |
| + cp++; |
| + } |
| + tstr = cp; |
| + } |
| + out: |
| *lengthPtr = tstr - start; |
| - return (nstr); |
| + return (unix_nstr); |
| |
| - bad_modifier: |
| + bad_modifier: |
| /* "{(" */ |
| - Error("Bad modifier `:%.*s' for %s", (int)strcspn(tstr, ":)}"), tstr, |
| - v->name); |
| + Error("Bad modifier `:%.*s' for %s", (int) strcspn(tstr, ":)}"), tstr, |
| + v->name); |
| |
| - cleanup: |
| + cleanup: |
| *lengthPtr = cp - start; |
| if (delim != '\0') |
| - Error("Unclosed substitution for %s (%c missing)", |
| - v->name, delim); |
| + Error("Unclosed substitution for %s (%c missing)", |
| + v->name, delim); |
| free(*freePtr); |
| @@ -3747,15 +3771,14 @@ char * |
| Var_Parse(const char *str, GNode *ctxt, int flags, |
| - int *lengthPtr, void **freePtr) |
| -{ |
| - const char *tstr; /* Pointer into str */ |
| - Var *v; /* Variable in invocation */ |
| - Boolean haveModifier;/* TRUE if have modifiers for the variable */ |
| - char endc; /* Ending character when variable in parens |
| + int *lengthPtr, void **freePtr) { |
| + const char *tstr; /* Pointer into str */ |
| + Var *v; /* Variable in invocation */ |
| + Boolean haveModifier;/* TRUE if have modifiers for the variable */ |
| + char endc; /* Ending character when variable in parens |
| * or braces */ |
| - char startc; /* Starting character when variable in parens |
| + char startc; /* Starting character when variable in parens |
| * or braces */ |
| - int vlen; /* Length of variable name */ |
| - const char *start; /* Points to original start of str */ |
| - char *nstr; /* New string, used during expansion */ |
| - Boolean dynamic; /* TRUE if the variable is local and we're |
| + int vlen; /* Length of variable name */ |
| + const char *start; /* Points to original start of str */ |
| + char *nstr; /* New string, used during expansion */ |
| + Boolean dynamic; /* TRUE if the variable is local and we're |
| * expanding it in a non-local context. This |
| @@ -3763,4 +3786,4 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| * result is just the invocation, unaltered */ |
| - const char *extramodifiers; /* extra modifiers to apply first */ |
| - char name[2]; |
| + const char *extramodifiers; /* extra modifiers to apply first */ |
| + char name[2]; |
| |
| @@ -3773,3 +3796,3 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| if (startc != PROPEN && startc != BROPEN) { |
| - /* |
| + /* |
| * If it's not bounded by braces of some sort, life is much simpler. |
| @@ -3779,16 +3802,16 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| |
| - /* Error out some really stupid names */ |
| - if (startc == '\0' || strchr(")}:$", startc)) { |
| - *lengthPtr = 1; |
| - return var_Error; |
| - } |
| - name[0] = startc; |
| - name[1] = '\0'; |
| + /* Error out some really stupid names */ |
| + if (startc == '\0' || strchr(")}:$", startc)) { |
| + *lengthPtr = 1; |
| + return var_Error; |
| + } |
| + name[0] = startc; |
| + name[1] = '\0'; |
| |
| - v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); |
| - if (v == NULL) { |
| - *lengthPtr = 2; |
| + v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); |
| + if (v == NULL) { |
| + *lengthPtr = 2; |
| |
| - if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { |
| - /* |
| + if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { |
| + /* |
| * If substituting a local variable in a non-local context, |
| @@ -3801,69 +3824,67 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| */ |
| - switch (str[1]) { |
| - case '@': |
| - return UNCONST("$(.TARGET)"); |
| - case '%': |
| - return UNCONST("$(.MEMBER)"); |
| - case '*': |
| - return UNCONST("$(.PREFIX)"); |
| - case '!': |
| - return UNCONST("$(.ARCHIVE)"); |
| - } |
| - } |
| - /* |
| + switch (str[1]) { |
| + case '@': |
| + return UNCONST("$(.TARGET)"); |
| + case '%': |
| + return UNCONST("$(.MEMBER)"); |
| + case '*': |
| + return UNCONST("$(.PREFIX)"); |
| + case '!': |
| + return UNCONST("$(.ARCHIVE)"); |
| + } |
| + } |
| + /* |
| * Error |
| */ |
| - return (flags & VARF_UNDEFERR) ? var_Error : varNoError; |
| - } else { |
| - haveModifier = FALSE; |
| - tstr = &str[1]; |
| - endc = str[1]; |
| - } |
| + return (flags & VARF_UNDEFERR) ? var_Error : varNoError; |
| + } else { |
| + haveModifier = FALSE; |
| + tstr = &str[1]; |
| + endc = str[1]; |
| + } |
| } else { |
| - Buffer buf; /* Holds the variable name */ |
| - int depth = 1; |
| + Buffer buf; /* Holds the variable name */ |
| + int depth = 1; |
| |
| - endc = startc == PROPEN ? PRCLOSE : BRCLOSE; |
| - Buf_Init(&buf, 0); |
| + endc = startc == PROPEN ? PRCLOSE : BRCLOSE; |
| + Buf_Init(&buf, 0); |
| |
| - /* |
| + /* |
| * Skip to the end character or a colon, whichever comes first. |
| */ |
| - for (tstr = str + 2; *tstr != '\0'; tstr++) |
| - { |
| - /* |
| + for (tstr = str + 2; *tstr != '\0'; tstr++) { |
| + /* |
| * Track depth so we can spot parse errors. |
| */ |
| - if (*tstr == startc) { |
| - depth++; |
| - } |
| - if (*tstr == endc) { |
| - if (--depth == 0) |
| - break; |
| - } |
| - if (depth == 1 && *tstr == ':') { |
| - break; |
| - } |
| - /* |
| + if (*tstr == startc) { |
| + depth++; |
| + } |
| + if (*tstr == endc) { |
| + if (--depth == 0) |
| + break; |
| + } |
| + if (depth == 1 && *tstr == ':') { |
| + break; |
| + } |
| + /* |
| * A variable inside a variable, expand |
| */ |
| - if (*tstr == '$') { |
| - int rlen; |
| - void *freeIt; |
| - char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); |
| - if (rval != NULL) { |
| - Buf_AddBytes(&buf, strlen(rval), rval); |
| - } |
| - free(freeIt); |
| - tstr += rlen - 1; |
| - } |
| - else |
| - Buf_AddByte(&buf, *tstr); |
| - } |
| - if (*tstr == ':') { |
| - haveModifier = TRUE; |
| - } else if (*tstr == endc) { |
| - haveModifier = FALSE; |
| - } else { |
| - /* |
| + if (*tstr == '$') { |
| + int rlen; |
| + void *freeIt; |
| + char *rval = Var_Parse(tstr, ctxt, flags, &rlen, &freeIt); |
| + if (rval != NULL) { |
| + Buf_AddBytes(&buf, strlen(rval), rval); |
| + } |
| + free(freeIt); |
| + tstr += rlen - 1; |
| + } else |
| + Buf_AddByte(&buf, *tstr); |
| + } |
| + if (*tstr == ':') { |
| + haveModifier = TRUE; |
| + } else if (*tstr == endc) { |
| + haveModifier = FALSE; |
| + } else { |
| + /* |
| * If we never did find the end character, return NULL |
| @@ -3872,9 +3893,9 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| */ |
| - *lengthPtr = tstr - str; |
| - Buf_Destroy(&buf, TRUE); |
| - return (var_Error); |
| - } |
| - str = Buf_GetAll(&buf, &vlen); |
| + *lengthPtr = tstr - str; |
| + Buf_Destroy(&buf, TRUE); |
| + return (var_Error); |
| + } |
| + str = Buf_GetAll(&buf, &vlen); |
| |
| - /* |
| + /* |
| * At this point, str points into newly allocated memory from |
| @@ -3889,4 +3910,4 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| |
| - v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); |
| - /* |
| + v = VarFind(str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); |
| + /* |
| * Check also for bogus D and F forms of local variables since we're |
| @@ -3894,28 +3915,26 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| */ |
| - if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && |
| - (vlen == 2) && (str[1] == 'F' || str[1] == 'D') && |
| - strchr("@%?*!<>", str[0]) != NULL) { |
| - /* |
| + if ((v == NULL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && |
| + (vlen == 2) && (str[1] == 'F' || str[1] == 'D') && |
| + strchr("@%?*!<>", str[0]) != NULL) { |
| + /* |
| * Well, it's local -- go look for it. |
| */ |
| - name[0] = *str; |
| - name[1] = '\0'; |
| - v = VarFind(name, ctxt, 0); |
| - |
| - if (v != NULL) { |
| - if (str[1] == 'D') { |
| - extramodifiers = "H:"; |
| - } |
| - else { /* F */ |
| - extramodifiers = "T:"; |
| - } |
| - } |
| - } |
| - |
| - if (v == NULL) { |
| - if (((vlen == 1) || |
| - (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) && |
| - ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) |
| - { |
| - /* |
| + name[0] = *str; |
| + name[1] = '\0'; |
| + v = VarFind(name, ctxt, 0); |
| + |
| + if (v != NULL) { |
| + if (str[1] == 'D') { |
| + extramodifiers = "H:"; |
| + } else { /* F */ |
| + extramodifiers = "T:"; |
| + } |
| + } |
| + } |
| + |
| + if (v == NULL) { |
| + if (((vlen == 1) || |
| + (((vlen == 2) && (str[1] == 'F' || str[1] == 'D')))) && |
| + ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) { |
| + /* |
| * If substituting a local variable in a non-local context, |
| @@ -3928,28 +3947,26 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| */ |
| - switch (*str) { |
| - case '@': |
| - case '%': |
| - case '*': |
| - case '!': |
| - dynamic = TRUE; |
| - break; |
| - } |
| - } else if ((vlen > 2) && (*str == '.') && |
| - isupper((unsigned char) str[1]) && |
| - ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) |
| - { |
| - int len; |
| - |
| - len = vlen - 1; |
| - if ((strncmp(str, ".TARGET", len) == 0) || |
| - (strncmp(str, ".ARCHIVE", len) == 0) || |
| - (strncmp(str, ".PREFIX", len) == 0) || |
| - (strncmp(str, ".MEMBER", len) == 0)) |
| - { |
| - dynamic = TRUE; |
| - } |
| - } |
| - |
| - if (!haveModifier) { |
| - /* |
| + switch (*str) { |
| + case '@': |
| + case '%': |
| + case '*': |
| + case '!': |
| + dynamic = TRUE; |
| + break; |
| + } |
| + } else if ((vlen > 2) && (*str == '.') && |
| + isupper((unsigned char) str[1]) && |
| + ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) { |
| + int len; |
| + |
| + len = vlen - 1; |
| + if ((strncmp(str, ".TARGET", len) == 0) || |
| + (strncmp(str, ".ARCHIVE", len) == 0) || |
| + (strncmp(str, ".PREFIX", len) == 0) || |
| + (strncmp(str, ".MEMBER", len) == 0)) { |
| + dynamic = TRUE; |
| + } |
| + } |
| + |
| + if (!haveModifier) { |
| + /* |
| * No modifiers -- have specification length so we can return |
| @@ -3957,14 +3974,14 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| */ |
| - *lengthPtr = tstr - start + 1; |
| - if (dynamic) { |
| - char *pstr = bmake_strndup(start, *lengthPtr); |
| - *freePtr = pstr; |
| - Buf_Destroy(&buf, TRUE); |
| - return(pstr); |
| - } else { |
| - Buf_Destroy(&buf, TRUE); |
| - return (flags & VARF_UNDEFERR) ? var_Error : varNoError; |
| - } |
| - } else { |
| - /* |
| + *lengthPtr = tstr - start + 1; |
| + if (dynamic) { |
| + char *pstr = bmake_strndup(start, *lengthPtr); |
| + *freePtr = pstr; |
| + Buf_Destroy(&buf, TRUE); |
| + return (pstr); |
| + } else { |
| + Buf_Destroy(&buf, TRUE); |
| + return (flags & VARF_UNDEFERR) ? var_Error : varNoError; |
| + } |
| + } else { |
| + /* |
| * Still need to get to the end of the variable specification, |
| @@ -3972,10 +3989,10 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| */ |
| - v = bmake_malloc(sizeof(Var)); |
| - v->name = UNCONST(str); |
| - Buf_Init(&v->val, 1); |
| - v->flags = VAR_JUNK; |
| - Buf_Destroy(&buf, FALSE); |
| - } |
| - } else |
| - Buf_Destroy(&buf, TRUE); |
| + v = bmake_malloc(sizeof(Var)); |
| + v->name = UNCONST(str); |
| + Buf_Init(&v->val, 1); |
| + v->flags = VAR_JUNK; |
| + Buf_Destroy(&buf, FALSE); |
| + } |
| + } else |
| + Buf_Destroy(&buf, TRUE); |
| } |
| @@ -3983,6 +4000,6 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| if (v->flags & VAR_IN_USE) { |
| - Fatal("Variable %s is recursive.", v->name); |
| - /*NOTREACHED*/ |
| + Fatal("Variable %s is recursive.", v->name); |
| + /*NOTREACHED*/ |
| } else { |
| - v->flags |= VAR_IN_USE; |
| + v->flags |= VAR_IN_USE; |
| } |
| @@ -3999,4 +4016,4 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| if (strchr(nstr, '$') != NULL) { |
| - nstr = Var_Subst(NULL, nstr, ctxt, flags); |
| - *freePtr = nstr; |
| + nstr = Var_Subst(NULL, nstr, ctxt, flags); |
| + *freePtr = nstr; |
| } |
| @@ -4006,27 +4023,27 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| if ((nstr != NULL) && (haveModifier || extramodifiers != NULL)) { |
| - void *extraFree; |
| - int used; |
| - |
| - extraFree = NULL; |
| - if (extramodifiers != NULL) { |
| - nstr = ApplyModifiers(nstr, extramodifiers, '(', ')', |
| - v, ctxt, flags, &used, &extraFree); |
| - } |
| - |
| - if (haveModifier) { |
| - /* Skip initial colon. */ |
| - tstr++; |
| - |
| - nstr = ApplyModifiers(nstr, tstr, startc, endc, |
| - v, ctxt, flags, &used, freePtr); |
| - tstr += used; |
| - free(extraFree); |
| - } else { |
| - *freePtr = extraFree; |
| - } |
| + void *extraFree; |
| + int used; |
| + |
| + extraFree = NULL; |
| + if (extramodifiers != NULL) { |
| + nstr = ApplyModifiers(nstr, extramodifiers, '(', ')', |
| + v, ctxt, flags, &used, &extraFree); |
| + } |
| + |
| + if (haveModifier) { |
| + /* Skip initial colon. */ |
| + tstr++; |
| + |
| + nstr = ApplyModifiers(nstr, tstr, startc, endc, |
| + v, ctxt, flags, &used, freePtr); |
| + tstr += used; |
| + free(extraFree); |
| + } else { |
| + *freePtr = extraFree; |
| + } |
| } |
| if (*tstr) { |
| - *lengthPtr = tstr - start + 1; |
| + *lengthPtr = tstr - start + 1; |
| } else { |
| - *lengthPtr = tstr - start; |
| + *lengthPtr = tstr - start; |
| } |
| @@ -4034,8 +4051,8 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| if (v->flags & VAR_FROM_ENV) { |
| - Boolean destroy = FALSE; |
| + Boolean destroy = FALSE; |
| |
| - if (nstr != Buf_GetAll(&v->val, NULL)) { |
| - destroy = TRUE; |
| - } else { |
| - /* |
| + if (nstr != Buf_GetAll(&v->val, NULL)) { |
| + destroy = TRUE; |
| + } else { |
| + /* |
| * Returning the value unmodified, so tell the caller to free |
| @@ -4043,7 +4060,7 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| */ |
| - *freePtr = nstr; |
| - } |
| - VarFreeEnv(v, destroy); |
| + *freePtr = nstr; |
| + } |
| + VarFreeEnv(v, destroy); |
| } else if (v->flags & VAR_JUNK) { |
| - /* |
| + /* |
| * Perform any free'ing needed and set *freePtr to NULL so the caller |
| @@ -4052,18 +4069,18 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| */ |
| - if (!(v->flags & VAR_KEEP)) { |
| - if (*freePtr) { |
| - free(nstr); |
| - *freePtr = NULL; |
| - } |
| - if (dynamic) { |
| - nstr = bmake_strndup(start, *lengthPtr); |
| - *freePtr = nstr; |
| - } else { |
| - nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError; |
| - } |
| - } |
| - if (nstr != Buf_GetAll(&v->val, NULL)) |
| - Buf_Destroy(&v->val, TRUE); |
| - free(v->name); |
| - free(v); |
| + if (!(v->flags & VAR_KEEP)) { |
| + if (*freePtr) { |
| + free(nstr); |
| + *freePtr = NULL; |
| + } |
| + if (dynamic) { |
| + nstr = bmake_strndup(start, *lengthPtr); |
| + *freePtr = nstr; |
| + } else { |
| + nstr = (flags & VARF_UNDEFERR) ? var_Error : varNoError; |
| + } |
| + } |
| + if (nstr != Buf_GetAll(&v->val, NULL)) |
| + Buf_Destroy(&v->val, TRUE); |
| + free(v->name); |
| + free(v); |
| } |
| @@ -4095,9 +4112,8 @@ Var_Parse(const char *str, GNode *ctxt, int flags, |
| char * |
| -Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| -{ |
| - Buffer buf; /* Buffer for forming things */ |
| - char *val; /* Value to substitute for a variable */ |
| - int length; /* Length of the variable invocation */ |
| - Boolean trailingBslash; /* variable ends in \ */ |
| - void *freeIt = NULL; /* Set if it should be freed */ |
| +Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) { |
| + Buffer buf; /* Buffer for forming things */ |
| + char *val; /* Value to substitute for a variable */ |
| + int length; /* Length of the variable invocation */ |
| + Boolean trailingBslash; /* variable ends in \ */ |
| + void *freeIt = NULL; /* Set if it should be freed */ |
| static Boolean errorReported; /* Set true if an error has already |
| @@ -4111,6 +4127,6 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| while (*str) { |
| - if (*str == '\n' && trailingBslash) |
| - Buf_AddByte(&buf, ' '); |
| - if (var == NULL && (*str == '$') && (str[1] == '$')) { |
| - /* |
| + if (*str == '\n' && trailingBslash) |
| + Buf_AddByte(&buf, ' '); |
| + if (var == NULL && (*str == '$') && (str[1] == '$')) { |
| + /* |
| * A dollar sign may be escaped either with another dollar sign. |
| @@ -4119,9 +4135,9 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| */ |
| - if (save_dollars && (flags & VARF_ASSIGN)) |
| - Buf_AddByte(&buf, *str); |
| - str++; |
| - Buf_AddByte(&buf, *str); |
| - str++; |
| - } else if (*str != '$') { |
| - /* |
| + if (save_dollars && (flags & VARF_ASSIGN)) |
| + Buf_AddByte(&buf, *str); |
| + str++; |
| + Buf_AddByte(&buf, *str); |
| + str++; |
| + } else if (*str != '$') { |
| + /* |
| * Skip as many characters as possible -- either to the end of |
| @@ -4129,37 +4145,35 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| */ |
| - const char *cp; |
| - |
| - for (cp = str++; *str != '$' && *str != '\0'; str++) |
| - continue; |
| - Buf_AddBytes(&buf, str - cp, cp); |
| - } else { |
| - if (var != NULL) { |
| - int expand; |
| - for (;;) { |
| - if (str[1] == '\0') { |
| - /* A trailing $ is kind of a special case */ |
| - Buf_AddByte(&buf, str[0]); |
| - str++; |
| - expand = FALSE; |
| - } else if (str[1] != PROPEN && str[1] != BROPEN) { |
| - if (str[1] != *var || strlen(var) > 1) { |
| - Buf_AddBytes(&buf, 2, str); |
| - str += 2; |
| - expand = FALSE; |
| - } |
| - else |
| - expand = TRUE; |
| - break; |
| - } |
| - else { |
| - const char *p; |
| - |
| - /* |
| + const char *cp; |
| + |
| + for (cp = str++; *str != '$' && *str != '\0'; str++) |
| + continue; |
| + Buf_AddBytes(&buf, str - cp, cp); |
| + } else { |
| + if (var != NULL) { |
| + int expand; |
| + for (;;) { |
| + if (str[1] == '\0') { |
| + /* A trailing $ is kind of a special case */ |
| + Buf_AddByte(&buf, str[0]); |
| + str++; |
| + expand = FALSE; |
| + } else if (str[1] != PROPEN && str[1] != BROPEN) { |
| + if (str[1] != *var || strlen(var) > 1) { |
| + Buf_AddBytes(&buf, 2, str); |
| + str += 2; |
| + expand = FALSE; |
| + } else |
| + expand = TRUE; |
| + break; |
| + } else { |
| + const char *p; |
| + |
| + /* |
| * Scan up to the end of the variable name. |
| */ |
| - for (p = &str[2]; *p && |
| - *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++) |
| - if (*p == '$') |
| - break; |
| - /* |
| + for (p = &str[2]; *p && |
| + *p != ':' && *p != PRCLOSE && *p != BRCLOSE; p++) |
| + if (*p == '$') |
| + break; |
| + /* |
| * A variable inside the variable. We cannot expand |
| @@ -4168,11 +4182,11 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| */ |
| - if (*p == '$') { |
| - Buf_AddBytes(&buf, p - str, str); |
| - str = p; |
| - continue; |
| - } |
| - |
| - if (strncmp(var, str + 2, p - str - 2) != 0 || |
| - var[p - str - 2] != '\0') { |
| - /* |
| + if (*p == '$') { |
| + Buf_AddBytes(&buf, p - str, str); |
| + str = p; |
| + continue; |
| + } |
| + |
| + if (strncmp(var, str + 2, p - str - 2) != 0 || |
| + var[p - str - 2] != '\0') { |
| + /* |
| * Not the variable we want to expand, scan |
| @@ -4180,20 +4194,19 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| */ |
| - for (;*p != '$' && *p != '\0'; p++) |
| - continue; |
| - Buf_AddBytes(&buf, p - str, str); |
| - str = p; |
| - expand = FALSE; |
| - } |
| - else |
| - expand = TRUE; |
| - break; |
| - } |
| - } |
| - if (!expand) |
| - continue; |
| - } |
| - |
| - val = Var_Parse(str, ctxt, flags, &length, &freeIt); |
| - |
| - /* |
| + for (; *p != '$' && *p != '\0'; p++) |
| + continue; |
| + Buf_AddBytes(&buf, p - str, str); |
| + str = p; |
| + expand = FALSE; |
| + } else |
| + expand = TRUE; |
| + break; |
| + } |
| + } |
| + if (!expand) |
| + continue; |
| + } |
| + |
| + val = Var_Parse(str, ctxt, flags, &length, &freeIt); |
| + |
| + /* |
| * When we come down here, val should either point to the |
| @@ -4203,4 +4216,4 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| */ |
| - if (val == var_Error || val == varNoError) { |
| - /* |
| + if (val == var_Error || val == varNoError) { |
| + /* |
| * If performing old-time variable substitution, skip over |
| @@ -4210,6 +4223,6 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| */ |
| - if (oldVars) { |
| - str += length; |
| - } else if ((flags & VARF_UNDEFERR) || val == var_Error) { |
| - /* |
| + if (oldVars) { |
| + str += length; |
| + } else if ((flags & VARF_UNDEFERR) || val == var_Error) { |
| + /* |
| * If variable is undefined, complain and skip the |
| @@ -4218,14 +4231,14 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| */ |
| - if (!errorReported) { |
| - Parse_Error(PARSE_FATAL, |
| - "Undefined variable \"%.*s\"",length,str); |
| - } |
| - str += length; |
| - errorReported = TRUE; |
| - } else { |
| - Buf_AddByte(&buf, *str); |
| - str += 1; |
| - } |
| - } else { |
| - /* |
| + if (!errorReported) { |
| + Parse_Error(PARSE_FATAL, |
| + "Undefined variable \"%.*s\"", length, str); |
| + } |
| + str += length; |
| + errorReported = TRUE; |
| + } else { |
| + Buf_AddByte(&buf, *str); |
| + str += 1; |
| + } |
| + } else { |
| + /* |
| * We've now got a variable structure to store in. But first, |
| @@ -4233,5 +4246,5 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| */ |
| - str += length; |
| + str += length; |
| |
| - /* |
| + /* |
| * Copy all the characters from the variable value straight |
| @@ -4239,9 +4252,9 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| */ |
| - length = strlen(val); |
| - Buf_AddBytes(&buf, length, val); |
| - trailingBslash = length > 0 && val[length - 1] == '\\'; |
| - } |
| - free(freeIt); |
| - freeIt = NULL; |
| - } |
| + length = strlen(val); |
| + Buf_AddBytes(&buf, length, val); |
| + trailingBslash = length > 0 && val[length - 1] == '\\'; |
| + } |
| + free(freeIt); |
| + freeIt = NULL; |
| + } |
| } |
| @@ -4269,3 +4282,3 @@ Var_Subst(const char *var, const char *str, GNode *ctxt, int flags) |
| #if 0 |
| -char * |
| + char * |
| Var_GetTail(char *file) |
| @@ -4313,4 +4326,3 @@ Var_GetHead(char *file) |
| void |
| -Var_Init(void) |
| -{ |
| +Var_Init(void) { |
| VAR_INTERNAL = Targ_NewGN("Internal"); |
| @@ -4323,4 +4335,3 @@ Var_Init(void) |
| void |
| -Var_End(void) |
| -{ |
| +Var_End(void) { |
| } |
| @@ -4330,5 +4341,4 @@ Var_End(void) |
| static void |
| -VarPrintVar(void *vp) |
| -{ |
| - Var *v = (Var *)vp; |
| +VarPrintVar(void *vp) { |
| + Var *v = (Var *) vp; |
| fprintf(debug_file, "%-16s = %s\n", v->name, Buf_GetAll(&v->val, NULL)); |
| @@ -4343,4 +4353,3 @@ VarPrintVar(void *vp) |
| void |
| -Var_Dump(GNode *ctxt) |
| -{ |
| +Var_Dump(GNode *ctxt) { |
| Hash_Search search; |
| @@ -4349,6 +4358,6888 @@ Var_Dump(GNode *ctxt) |
| for (h = Hash_EnumFirst(&ctxt->context, &search); |
| - h != NULL; |
| - h = Hash_EnumNext(&search)) { |
| - VarPrintVar(Hash_GetValue(h)); |
| + h != NULL; |
| + h = Hash_EnumNext(&search)) { |
| + VarPrintVar(Hash_GetValue(h)); |
| + } |
| +} |
| + |
| +#if (!defined(HAVE_REGCOMP) || !defined(HAVE_REGERROR) || !defined(HAVE_REGEXEC) || !defined(HAVE_REGFREE)) |
| + |
| +extern char * nl_langinfo(nl_item item); |
| + |
| +/* Extended regular expression matching and search library. |
| + Copyright (C) 2002-2018 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, see |
| + <https://www.gnu.org/licenses/>. */ |
| + |
| +static void re_string_construct_common(const char *str, Idx len, |
| + re_string_t *pstr, |
| + RE_TRANSLATE_TYPE trans, bool icase, |
| + const re_dfa_t *dfa); |
| + |
| +static re_dfastate_t *create_ci_newstate(const re_dfa_t *dfa, |
| + const re_node_set *nodes, |
| + re_hashval_t hash); |
| + |
| +static re_dfastate_t *create_cd_newstate(const re_dfa_t *dfa, |
| + const re_node_set *nodes, |
| + unsigned int context, |
| + re_hashval_t hash); |
| + |
| +static reg_errcode_t re_string_realloc_buffers(re_string_t *pstr, |
| + Idx new_buf_len); |
| + |
| +static void build_upper_buffer(re_string_t *pstr); |
| + |
| +static void re_string_translate_buffer(re_string_t *pstr); |
| + |
| +static unsigned int re_string_context_at(const re_string_t *input, Idx idx, |
| + int eflags) __attribute__ ((pure)); |
| + |
| +static reg_errcode_t match_ctx_init(re_match_context_t *cache, int eflags, |
| + Idx n); |
| + |
| +static void match_ctx_clean(re_match_context_t *mctx); |
| + |
| +static void match_ctx_free(re_match_context_t *cache); |
| + |
| +static reg_errcode_t match_ctx_add_entry(re_match_context_t *cache, Idx node, |
| + Idx str_idx, Idx from, Idx to); |
| + |
| +static Idx search_cur_bkref_entry(const re_match_context_t *mctx, Idx str_idx); |
| + |
| +static reg_errcode_t match_ctx_add_subtop(re_match_context_t *mctx, Idx node, |
| + Idx str_idx); |
| + |
| +static re_sub_match_last_t *match_ctx_add_sublast(re_sub_match_top_t *subtop, |
| + Idx node, Idx str_idx); |
| + |
| +static void sift_ctx_init(re_sift_context_t *sctx, re_dfastate_t **sifted_sts, |
| + re_dfastate_t **limited_sts, Idx last_node, |
| + Idx last_str_idx); |
| + |
| +static reg_errcode_t re_search_internal(const regex_t *preg, |
| + const char *string, Idx length, |
| + Idx start, Idx last_start, Idx stop, |
| + size_t nmatch, regmatch_t pmatch[], |
| + int eflags); |
| + |
| +static regoff_t re_search_2_stub(struct re_pattern_buffer *bufp, |
| + const char *string1, Idx length1, |
| + const char *string2, Idx length2, |
| + Idx start, regoff_t range, |
| + struct re_registers *regs, |
| + Idx stop, bool ret_len); |
| + |
| +static regoff_t re_search_stub(struct re_pattern_buffer *bufp, |
| + const char *string, Idx length, Idx start, |
| + regoff_t range, Idx stop, |
| + struct re_registers *regs, |
| + bool ret_len); |
| + |
| +static unsigned re_copy_regs(struct re_registers *regs, regmatch_t *pmatch, |
| + Idx nregs, int regs_allocated); |
| + |
| +static reg_errcode_t prune_impossible_nodes(re_match_context_t *mctx); |
| + |
| +static Idx check_matching(re_match_context_t *mctx, bool fl_longest_match, |
| + Idx *p_match_first); |
| + |
| +static Idx check_halt_state_context(const re_match_context_t *mctx, |
| + const re_dfastate_t *state, Idx idx); |
| + |
| +static void update_regs(const re_dfa_t *dfa, regmatch_t *pmatch, |
| + regmatch_t *prev_idx_match, Idx cur_node, |
| + Idx cur_idx, Idx nmatch); |
| + |
| +static reg_errcode_t push_fail_stack(struct re_fail_stack_t *fs, |
| + Idx str_idx, Idx dest_node, Idx nregs, |
| + regmatch_t *regs, |
| + re_node_set *eps_via_nodes); |
| + |
| +static reg_errcode_t set_regs(const regex_t *preg, |
| + const re_match_context_t *mctx, |
| + size_t nmatch, regmatch_t *pmatch, |
| + bool fl_backtrack); |
| + |
| +static reg_errcode_t free_fail_stack_return(struct re_fail_stack_t *fs); |
| + |
| +static reg_errcode_t sift_states_backward(const re_match_context_t *mctx, |
| + re_sift_context_t *sctx); |
| + |
| +static reg_errcode_t build_sifted_states(const re_match_context_t *mctx, |
| + re_sift_context_t *sctx, Idx str_idx, |
| + re_node_set *cur_dest); |
| + |
| +static reg_errcode_t update_cur_sifted_state(const re_match_context_t *mctx, |
| + re_sift_context_t *sctx, |
| + Idx str_idx, |
| + re_node_set *dest_nodes); |
| + |
| +static reg_errcode_t add_epsilon_src_nodes(const re_dfa_t *dfa, |
| + re_node_set *dest_nodes, |
| + const re_node_set *candidates); |
| + |
| +static bool check_dst_limits(const re_match_context_t *mctx, |
| + const re_node_set *limits, |
| + Idx dst_node, Idx dst_idx, Idx src_node, |
| + Idx src_idx); |
| + |
| +static int check_dst_limits_calc_pos_1(const re_match_context_t *mctx, |
| + int boundaries, Idx subexp_idx, |
| + Idx from_node, Idx bkref_idx); |
| + |
| +static int check_dst_limits_calc_pos(const re_match_context_t *mctx, |
| + Idx limit, Idx subexp_idx, |
| + Idx node, Idx str_idx, |
| + Idx bkref_idx); |
| + |
| +static reg_errcode_t check_subexp_limits(const re_dfa_t *dfa, |
| + re_node_set *dest_nodes, |
| + const re_node_set *candidates, |
| + re_node_set *limits, |
| + struct re_backref_cache_entry *bkref_ents, |
| + Idx str_idx); |
| + |
| +static reg_errcode_t sift_states_bkref(const re_match_context_t *mctx, |
| + re_sift_context_t *sctx, |
| + Idx str_idx, const re_node_set *candidates); |
| + |
| +static reg_errcode_t merge_state_array(const re_dfa_t *dfa, |
| + re_dfastate_t **dst, |
| + re_dfastate_t **src, Idx num); |
| + |
| +static re_dfastate_t *find_recover_state(reg_errcode_t *err, |
| + re_match_context_t *mctx); |
| + |
| +static re_dfastate_t *transit_state(reg_errcode_t *err, |
| + re_match_context_t *mctx, |
| + re_dfastate_t *state); |
| + |
| +static re_dfastate_t *merge_state_with_log(reg_errcode_t *err, |
| + re_match_context_t *mctx, |
| + re_dfastate_t *next_state); |
| + |
| +static reg_errcode_t check_subexp_matching_top(re_match_context_t *mctx, |
| + re_node_set *cur_nodes, |
| + Idx str_idx); |
| + |
| +static reg_errcode_t transit_state_bkref(re_match_context_t *mctx, |
| + const re_node_set *nodes); |
| + |
| +static reg_errcode_t get_subexp(re_match_context_t *mctx, |
| + Idx bkref_node, Idx bkref_str_idx); |
| + |
| +static reg_errcode_t get_subexp_sub(re_match_context_t *mctx, |
| + const re_sub_match_top_t *sub_top, |
| + re_sub_match_last_t *sub_last, |
| + Idx bkref_node, Idx bkref_str); |
| + |
| +static Idx find_subexp_node(const re_dfa_t *dfa, const re_node_set *nodes, |
| + Idx subexp_idx, int type); |
| + |
| +static reg_errcode_t check_arrival(re_match_context_t *mctx, |
| + state_array_t *path, Idx top_node, |
| + Idx top_str, Idx last_node, Idx last_str, |
| + int type); |
| + |
| +static reg_errcode_t check_arrival_add_next_nodes(re_match_context_t *mctx, |
| + Idx str_idx, |
| + re_node_set *cur_nodes, |
| + re_node_set *next_nodes); |
| + |
| +static reg_errcode_t check_arrival_expand_ecl(const re_dfa_t *dfa, |
| + re_node_set *cur_nodes, |
| + Idx ex_subexp, int type); |
| + |
| +static reg_errcode_t check_arrival_expand_ecl_sub(const re_dfa_t *dfa, |
| + re_node_set *dst_nodes, |
| + Idx target, Idx ex_subexp, |
| + int type); |
| + |
| +static reg_errcode_t expand_bkref_cache(re_match_context_t *mctx, |
| + re_node_set *cur_nodes, Idx cur_str, |
| + Idx subexp_num, int type); |
| + |
| +static bool build_trtable(const re_dfa_t *dfa, re_dfastate_t *state); |
| + |
| +static Idx group_nodes_into_DFAstates(const re_dfa_t *dfa, |
| + const re_dfastate_t *state, |
| + re_node_set *states_node, |
| + bitset_t *states_ch); |
| + |
| +static bool check_node_accept(const re_match_context_t *mctx, |
| + const re_token_t *node, Idx idx); |
| + |
| +static reg_errcode_t extend_buffers(re_match_context_t *mctx, int min_len); |
| + |
| +/* Check NODE match the current context. */ |
| + |
| +static bool |
| +check_halt_node_context(const re_dfa_t *dfa, Idx node, unsigned int context) { |
| + re_token_type_t type = dfa->nodes[node].type; |
| + unsigned int constraint = dfa->nodes[node].constraint; |
| + if (type != END_OF_RE) |
| + return false; |
| + if (!constraint) |
| + return true; |
| + if (NOT_SATISFY_NEXT_CONSTRAINT(constraint, context)) |
| + return false; |
| + return true; |
| +} |
| + |
| +/* Check the halt state STATE match the current context. |
| + Return 0 if not match, if the node, STATE has, is a halt node and |
| + match the context, return the node. */ |
| + |
| +static Idx |
| +check_halt_state_context(const re_match_context_t *mctx, |
| + const re_dfastate_t *state, Idx idx) { |
| + Idx i; |
| + unsigned int context; |
| + context = re_string_context_at(&mctx->input, idx, mctx->eflags); |
| + for (i = 0; i < state->nodes.nelem; ++i) |
| + if (check_halt_node_context(mctx->dfa, state->nodes.elems[i], context)) |
| + return state->nodes.elems[i]; |
| + return 0; |
| +} |
| + |
| +/* Functions for string operation. */ |
| + |
| +/* This function allocate the buffers. It is necessary to call |
| + re_string_reconstruct before using the object. */ |
| + |
| +static reg_errcode_t |
| + |
| +re_string_allocate(re_string_t *pstr, const char *str, Idx len, Idx init_len, |
| + RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) { |
| + reg_errcode_t ret; |
| + Idx init_buf_len; |
| + |
| +/* Ensure at least one character fits into the buffers. */ |
| + if (init_len < dfa->mb_cur_max) |
| + init_len = dfa->mb_cur_max; |
| + init_buf_len = (len + 1 < init_len) ? len + 1 : init_len; |
| + re_string_construct_common(str, len, pstr, trans, icase, dfa); |
| + |
| + ret = re_string_realloc_buffers(pstr, init_buf_len); |
| + if ((ret != REG_NOERROR)) |
| + return ret; |
| + |
| + pstr->word_char = dfa->word_char; |
| + pstr->word_ops_used = dfa->word_ops_used; |
| + pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; |
| + pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len; |
| + pstr->valid_raw_len = pstr->valid_len; |
| + return REG_NOERROR; |
| +} |
| + |
| +/* This function allocate the buffers, and initialize them. */ |
| + |
| +static reg_errcode_t |
| + |
| +re_string_construct(re_string_t *pstr, const char *str, Idx len, |
| + RE_TRANSLATE_TYPE trans, bool icase, const re_dfa_t *dfa) { |
| + reg_errcode_t ret; |
| + memset(pstr, '\0', sizeof(re_string_t)); |
| + re_string_construct_common(str, len, pstr, trans, icase, dfa); |
| + |
| + if (len > 0) { |
| + ret = re_string_realloc_buffers(pstr, len + 1); |
| + if ((ret != REG_NOERROR)) |
| + return ret; |
| + } |
| + pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str; |
| + |
| + if (icase) { |
| + |
| + build_upper_buffer(pstr); |
| + } else { |
| + |
| + { |
| + if (trans != NULL) |
| + re_string_translate_buffer(pstr); |
| + else { |
| + pstr->valid_len = pstr->bufs_len; |
| + pstr->valid_raw_len = pstr->bufs_len; |
| + } |
| + } |
| + } |
| + |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Helper functions for re_string_allocate, and re_string_construct. */ |
| + |
| +static reg_errcode_t |
| + |
| +re_string_realloc_buffers(re_string_t *pstr, Idx new_buf_len) { |
| + |
| + if (pstr->mbs_allocated) { |
| + unsigned char *new_mbs = re_realloc(pstr->mbs, |
| + unsigned char, |
| + new_buf_len); |
| + if ((new_mbs == NULL)) |
| + return REG_ESPACE; |
| + pstr->mbs = new_mbs; |
| } |
| + pstr->bufs_len = new_buf_len; |
| + return REG_NOERROR; |
| } |
| + |
| + |
| +static void |
| +re_string_construct_common(const char *str, Idx len, re_string_t *pstr, |
| + RE_TRANSLATE_TYPE trans, bool icase, |
| + const re_dfa_t *dfa) { |
| + pstr->raw_mbs = (const unsigned char *) str; |
| + pstr->len = len; |
| + pstr->raw_len = len; |
| + pstr->trans = trans; |
| + pstr->icase = icase; |
| + pstr->mbs_allocated = (trans != NULL || icase); |
| + pstr->mb_cur_max = dfa->mb_cur_max; |
| + pstr->is_utf8 = dfa->is_utf8; |
| + pstr->map_notascii = dfa->map_notascii; |
| + pstr->stop = pstr->len; |
| + pstr->raw_stop = pstr->stop; |
| +} |
| + |
| +/* Build the buffer PSTR->MBS, and apply the translation if we need. |
| + This function is used in case of REG_ICASE. */ |
| + |
| +static void |
| +build_upper_buffer(re_string_t *pstr) { |
| + Idx char_idx, end_idx; |
| + end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; |
| + |
| + for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx) { |
| + int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; |
| + if ((pstr->trans != NULL)) |
| + ch = pstr->trans[ch]; |
| + pstr->mbs[char_idx] = toupper(ch); |
| + } |
| + pstr->valid_len = char_idx; |
| + pstr->valid_raw_len = char_idx; |
| +} |
| + |
| +/* Apply TRANS to the buffer in PSTR. */ |
| + |
| +static void |
| +re_string_translate_buffer(re_string_t *pstr) { |
| + Idx buf_idx, end_idx; |
| + end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; |
| + |
| + for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx) { |
| + int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; |
| + pstr->mbs[buf_idx] = pstr->trans[ch]; |
| + } |
| + |
| + pstr->valid_len = buf_idx; |
| + pstr->valid_raw_len = buf_idx; |
| +} |
| + |
| +/* This function re-construct the buffers. |
| + Concretely, convert to wide character in case of pstr->mb_cur_max > 1, |
| + convert to upper case in case of REG_ICASE, apply translation. */ |
| + |
| +static reg_errcode_t |
| + |
| +re_string_reconstruct(re_string_t *pstr, Idx idx, int eflags) { |
| + Idx offset; |
| + |
| + if ((pstr->raw_mbs_idx <= idx)) |
| + offset = idx - pstr->raw_mbs_idx; |
| + else { |
| +/* Reset buffer. */ |
| + |
| + pstr->len = pstr->raw_len; |
| + pstr->stop = pstr->raw_stop; |
| + pstr->valid_len = 0; |
| + pstr->raw_mbs_idx = 0; |
| + pstr->valid_raw_len = 0; |
| + pstr->offsets_needed = 0; |
| + pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF |
| + : CONTEXT_NEWLINE | CONTEXT_BEGBUF); |
| + if (!pstr->mbs_allocated) |
| + pstr->mbs = (unsigned char *) pstr->raw_mbs; |
| + offset = idx; |
| + } |
| + |
| + if ((offset != 0)) { |
| +/* Should the already checked characters be kept? */ |
| + if ((offset < pstr->valid_raw_len)) { |
| +/* Yes, move them to the front of the buffer. */ |
| + |
| + { |
| + pstr->tip_context = re_string_context_at(pstr, offset - 1, |
| + eflags); |
| + |
| + if ((pstr->mbs_allocated)) |
| + memmove(pstr->mbs, pstr->mbs + offset, |
| + pstr->valid_len - offset); |
| + pstr->valid_len -= offset; |
| + pstr->valid_raw_len -= offset; |
| + |
| + } |
| + } else { |
| + |
| + pstr->valid_len = 0; |
| + |
| + { |
| + int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; |
| + pstr->valid_raw_len = 0; |
| + if (pstr->trans) |
| + c = pstr->trans[c]; |
| + pstr->tip_context = (bitset_contain(pstr->word_char, c) |
| + ? CONTEXT_WORD |
| + : ((IS_NEWLINE(c) && pstr->newline_anchor) |
| + ? CONTEXT_NEWLINE : 0)); |
| + } |
| + } |
| + if (!(pstr->mbs_allocated)) |
| + pstr->mbs += offset; |
| + } |
| + pstr->raw_mbs_idx = idx; |
| + pstr->len -= offset; |
| + pstr->stop -= offset; |
| + |
| +/* Then build the buffers. */ |
| + |
| + if ((pstr->mbs_allocated)) { |
| + if (pstr->icase) |
| + build_upper_buffer(pstr); |
| + else if (pstr->trans != NULL) |
| + re_string_translate_buffer(pstr); |
| + } else |
| + pstr->valid_len = pstr->len; |
| + |
| + pstr->cur_idx = 0; |
| + return REG_NOERROR; |
| +} |
| + |
| +static unsigned char |
| +__attribute__ ((pure)) |
| +re_string_peek_byte_case(const re_string_t *pstr, Idx idx) { |
| + int ch; |
| + Idx off; |
| + |
| + /* Handle the common (easiest) cases first. */ |
| + if ((!pstr->mbs_allocated)) |
| + return re_string_peek_byte(pstr, idx); |
| + |
| + off = pstr->cur_idx + idx; |
| + |
| + ch = pstr->raw_mbs[pstr->raw_mbs_idx + off]; |
| + |
| + return ch; |
| +} |
| + |
| +static unsigned char |
| +re_string_fetch_byte_case(re_string_t *pstr) { |
| + if ((!pstr->mbs_allocated)) |
| + return re_string_fetch_byte(pstr); |
| + |
| + return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++]; |
| +} |
| + |
| +static void |
| +re_string_destruct(re_string_t *pstr) { |
| + |
| + if (pstr->mbs_allocated) |
| + re_free(pstr->mbs); |
| +} |
| + |
| +/* Return the context at IDX in INPUT. */ |
| + |
| +static unsigned int |
| +re_string_context_at(const re_string_t *input, Idx idx, int eflags) { |
| + int c; |
| + if ((idx < 0)) |
| + /* In this case, we use the value stored in input->tip_context, |
| + since we can't know the character in input->mbs[-1] here. */ |
| + return input->tip_context; |
| + if ((idx == input->len)) |
| + return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF |
| + : CONTEXT_NEWLINE | CONTEXT_ENDBUF); |
| + |
| + { |
| + c = re_string_byte_at(input, idx); |
| + if (bitset_contain(input->word_char, c)) |
| + return CONTEXT_WORD; |
| + return IS_NEWLINE(c) && input->newline_anchor ? CONTEXT_NEWLINE : 0; |
| + } |
| +} |
| + |
| +/* Functions for set operation. */ |
| + |
| +static reg_errcode_t |
| + |
| +re_node_set_alloc(re_node_set *set, Idx size) { |
| + set->alloc = size; |
| + set->nelem = 0; |
| + set->elems = re_malloc(Idx, size); |
| + if ((set->elems == NULL) |
| + && (MALLOC_0_IS_NONNULL || size != 0)) |
| + return REG_ESPACE; |
| + return REG_NOERROR; |
| +} |
| + |
| +static reg_errcode_t |
| + |
| +re_node_set_init_1(re_node_set *set, Idx elem) { |
| + set->alloc = 1; |
| + set->nelem = 1; |
| + set->elems = re_malloc(Idx, 1); |
| + if ((set->elems == NULL)) { |
| + set->alloc = set->nelem = 0; |
| + return REG_ESPACE; |
| + } |
| + set->elems[0] = elem; |
| + return REG_NOERROR; |
| +} |
| + |
| +static reg_errcode_t |
| + |
| +re_node_set_init_2(re_node_set *set, Idx elem1, Idx elem2) { |
| + set->alloc = 2; |
| + set->elems = re_malloc(Idx, 2); |
| + if ((set->elems == NULL)) |
| + return REG_ESPACE; |
| + if (elem1 == elem2) { |
| + set->nelem = 1; |
| + set->elems[0] = elem1; |
| + } else { |
| + set->nelem = 2; |
| + if (elem1 < elem2) { |
| + set->elems[0] = elem1; |
| + set->elems[1] = elem2; |
| + } else { |
| + set->elems[0] = elem2; |
| + set->elems[1] = elem1; |
| + } |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +static reg_errcode_t |
| + |
| +re_node_set_init_copy(re_node_set *dest, const re_node_set *src) { |
| + dest->nelem = src->nelem; |
| + if (src->nelem > 0) { |
| + dest->alloc = dest->nelem; |
| + dest->elems = re_malloc(Idx, dest->alloc); |
| + if ((dest->elems == NULL)) { |
| + dest->alloc = dest->nelem = 0; |
| + return REG_ESPACE; |
| + } |
| + memcpy(dest->elems, src->elems, src->nelem * sizeof(Idx)); |
| + } else |
| + re_node_set_init_empty(dest); |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to |
| + DEST. Return value indicate the error code or REG_NOERROR if succeeded. |
| + Note: We assume dest->elems is NULL, when dest->alloc is 0. */ |
| + |
| +static reg_errcode_t |
| + |
| +re_node_set_add_intersect(re_node_set *dest, const re_node_set *src1, |
| + const re_node_set *src2) { |
| + Idx i1, i2, is, id, delta, sbase; |
| + if (src1->nelem == 0 || src2->nelem == 0) |
| + return REG_NOERROR; |
| + |
| +/* We need dest->nelem + 2 * elems_in_intersection; this is a |
| + conservative estimate. */ |
| + if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) { |
| + Idx new_alloc = src1->nelem + src2->nelem + dest->alloc; |
| + Idx *new_elems = re_realloc(dest->elems, Idx, new_alloc); |
| + if ((new_elems == NULL)) |
| + return REG_ESPACE; |
| + dest->elems = new_elems; |
| + dest->alloc = new_alloc; |
| + } |
| + |
| +/* Find the items in the intersection of SRC1 and SRC2, and copy |
| + into the top of DEST those that are not already in DEST itself. */ |
| + sbase = dest->nelem + src1->nelem + src2->nelem; |
| + i1 = src1->nelem - 1; |
| + i2 = src2->nelem - 1; |
| + id = dest->nelem - 1; |
| + for (;;) { |
| + if (src1->elems[i1] == src2->elems[i2]) { |
| +/* Try to find the item in DEST. Maybe we could binary search? */ |
| + while (id >= 0 && dest->elems[id] > src1->elems[i1]) |
| + --id; |
| + |
| + if (id < 0 || dest->elems[id] != src1->elems[i1]) |
| + dest->elems[--sbase] = src1->elems[i1]; |
| + |
| + if (--i1 < 0 || --i2 < 0) |
| + break; |
| + } |
| + |
| +/* Lower the highest of the two items. */ |
| + else if (src1->elems[i1] < src2->elems[i2]) { |
| + if (--i2 < 0) |
| + break; |
| + } else { |
| + if (--i1 < 0) |
| + break; |
| + } |
| + } |
| + |
| + id = dest->nelem - 1; |
| + is = dest->nelem + src1->nelem + src2->nelem - 1; |
| + delta = is - sbase + 1; |
| + |
| +/* Now copy. When DELTA becomes zero, the remaining |
| + DEST elements are already in place; this is more or |
| + less the same loop that is in re_node_set_merge. */ |
| + dest->nelem += delta; |
| + if (delta > 0 && id >= 0) |
| + for (;;) { |
| + if (dest->elems[is] > dest->elems[id]) { |
| +/* Copy from the top. */ |
| + dest->elems[id + delta--] = dest->elems[is--]; |
| + if (delta == 0) |
| + break; |
| + } else { |
| +/* Slide from the bottom. */ |
| + dest->elems[id + delta] = dest->elems[id]; |
| + if (--id < 0) |
| + break; |
| + } |
| + } |
| + |
| +/* Copy remaining SRC elements. */ |
| + memcpy(dest->elems, dest->elems + sbase, delta * sizeof(Idx)); |
| + |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Calculate the union set of the sets SRC1 and SRC2. And store it to |
| + DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ |
| + |
| +static reg_errcode_t |
| + |
| +re_node_set_init_union(re_node_set *dest, const re_node_set *src1, |
| + const re_node_set *src2) { |
| + Idx i1, i2, id; |
| + if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) { |
| + dest->alloc = src1->nelem + src2->nelem; |
| + dest->elems = re_malloc(Idx, dest->alloc); |
| + if ((dest->elems == NULL)) |
| + return REG_ESPACE; |
| + } else { |
| + if (src1 != NULL && src1->nelem > 0) |
| + return re_node_set_init_copy(dest, src1); |
| + else if (src2 != NULL && src2->nelem > 0) |
| + return re_node_set_init_copy(dest, src2); |
| + else |
| + re_node_set_init_empty(dest); |
| + return REG_NOERROR; |
| + } |
| + for (i1 = i2 = id = 0; i1 < src1->nelem && i2 < src2->nelem;) { |
| + if (src1->elems[i1] > src2->elems[i2]) { |
| + dest->elems[id++] = src2->elems[i2++]; |
| + continue; |
| + } |
| + if (src1->elems[i1] == src2->elems[i2]) |
| + ++i2; |
| + dest->elems[id++] = src1->elems[i1++]; |
| + } |
| + if (i1 < src1->nelem) { |
| + memcpy(dest->elems + id, src1->elems + i1, |
| + (src1->nelem - i1) * sizeof(Idx)); |
| + id += src1->nelem - i1; |
| + } else if (i2 < src2->nelem) { |
| + memcpy(dest->elems + id, src2->elems + i2, |
| + (src2->nelem - i2) * sizeof(Idx)); |
| + id += src2->nelem - i2; |
| + } |
| + dest->nelem = id; |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Calculate the union set of the sets DEST and SRC. And store it to |
| + DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ |
| + |
| +static reg_errcode_t |
| + |
| +re_node_set_merge(re_node_set *dest, const re_node_set *src) { |
| + Idx is, id, sbase, delta; |
| + if (src == NULL || src->nelem == 0) |
| + return REG_NOERROR; |
| + if (dest->alloc < 2 * src->nelem + dest->nelem) { |
| + Idx new_alloc = 2 * (src->nelem + dest->alloc); |
| + Idx *new_buffer = re_realloc(dest->elems, Idx, new_alloc); |
| + if ((new_buffer == NULL)) |
| + return REG_ESPACE; |
| + dest->elems = new_buffer; |
| + dest->alloc = new_alloc; |
| + } |
| + |
| + if ((dest->nelem == 0)) { |
| + dest->nelem = src->nelem; |
| + memcpy(dest->elems, src->elems, src->nelem * sizeof(Idx)); |
| + return REG_NOERROR; |
| + } |
| + |
| +/* Copy into the top of DEST the items of SRC that are not |
| + found in DEST. Maybe we could binary search in DEST? */ |
| + for (sbase = dest->nelem + 2 * src->nelem, |
| + is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0;) { |
| + if (dest->elems[id] == src->elems[is]) |
| + is--, id--; |
| + else if (dest->elems[id] < src->elems[is]) |
| + dest->elems[--sbase] = src->elems[is--]; |
| + else /* if (dest->elems[id] > src->elems[is]) */ |
| + --id; |
| + } |
| + |
| + if (is >= 0) { |
| +/* If DEST is exhausted, the remaining items of SRC must be unique. */ |
| + sbase -= is + 1; |
| + memcpy(dest->elems + sbase, src->elems, (is + 1) * sizeof(Idx)); |
| + } |
| + |
| + id = dest->nelem - 1; |
| + is = dest->nelem + 2 * src->nelem - 1; |
| + delta = is - sbase + 1; |
| + if (delta == 0) |
| + return REG_NOERROR; |
| + |
| +/* Now copy. When DELTA becomes zero, the remaining |
| + DEST elements are already in place. */ |
| + dest->nelem += delta; |
| + for (;;) { |
| + if (dest->elems[is] > dest->elems[id]) { |
| +/* Copy from the top. */ |
| + dest->elems[id + delta--] = dest->elems[is--]; |
| + if (delta == 0) |
| + break; |
| + } else { |
| +/* Slide from the bottom. */ |
| + dest->elems[id + delta] = dest->elems[id]; |
| + if (--id < 0) { |
| +/* Copy remaining SRC elements. */ |
| + memcpy(dest->elems, dest->elems + sbase, |
| + delta * sizeof(Idx)); |
| + break; |
| + } |
| + } |
| + } |
| + |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Insert the new element ELEM to the re_node_set* SET. |
| + SET should not already have ELEM. |
| + Return true if successful. */ |
| + |
| +static bool |
| + |
| +re_node_set_insert(re_node_set *set, Idx elem) { |
| + Idx idx; |
| +/* In case the set is empty. */ |
| + if (set->alloc == 0) |
| + return (re_node_set_init_1(set, elem) == REG_NOERROR); |
| + |
| + if ((set->nelem) == 0) { |
| +/* We already guaranteed above that set->alloc != 0. */ |
| + set->elems[0] = elem; |
| + ++set->nelem; |
| + return true; |
| + } |
| + |
| +/* Realloc if we need. */ |
| + if (set->alloc == set->nelem) { |
| + Idx *new_elems; |
| + set->alloc = set->alloc * 2; |
| + new_elems = re_realloc(set->elems, Idx, set->alloc); |
| + if ((new_elems == NULL)) |
| + return false; |
| + set->elems = new_elems; |
| + } |
| + |
| +/* Move the elements which follows the new element. Test the |
| + first element separately to skip a check in the inner loop. */ |
| + if (elem < set->elems[0]) { |
| + idx = 0; |
| + for (idx = set->nelem; idx > 0; idx--) |
| + set->elems[idx] = set->elems[idx - 1]; |
| + } else { |
| + for (idx = set->nelem; set->elems[idx - 1] > elem; idx--) |
| + set->elems[idx] = set->elems[idx - 1]; |
| + } |
| + |
| +/* Insert the new element. */ |
| + set->elems[idx] = elem; |
| + ++set->nelem; |
| + return true; |
| +} |
| + |
| +/* Insert the new element ELEM to the re_node_set* SET. |
| + SET should not already have any element greater than or equal to ELEM. |
| + Return true if successful. */ |
| + |
| +static bool |
| + |
| +re_node_set_insert_last(re_node_set *set, Idx elem) { |
| +/* Realloc if we need. */ |
| + if (set->alloc == set->nelem) { |
| + Idx *new_elems; |
| + set->alloc = (set->alloc + 1) * 2; |
| + new_elems = re_realloc(set->elems, Idx, set->alloc); |
| + if ((new_elems == NULL)) |
| + return false; |
| + set->elems = new_elems; |
| + } |
| + |
| +/* Insert the new element. */ |
| + set->elems[set->nelem++] = elem; |
| + return true; |
| +} |
| + |
| +/* Compare two node sets SET1 and SET2. |
| + Return true if SET1 and SET2 are equivalent. */ |
| + |
| +static bool |
| +__attribute__ ((pure)) |
| +re_node_set_compare(const re_node_set *set1, const re_node_set *set2) { |
| + Idx i; |
| + if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) |
| + return false; |
| + for (i = set1->nelem; --i >= 0;) |
| + if (set1->elems[i] != set2->elems[i]) |
| + return false; |
| + return true; |
| +} |
| + |
| +/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ |
| + |
| +static Idx |
| +__attribute__ ((pure)) |
| +re_node_set_contains(const re_node_set *set, Idx elem) { |
| + __re_size_t idx, right, mid; |
| + if (set->nelem <= 0) |
| + return 0; |
| + |
| + /* Binary search the element. */ |
| + idx = 0; |
| + right = set->nelem - 1; |
| + while (idx < right) { |
| + mid = (idx + right) / 2; |
| + if (set->elems[mid] < elem) |
| + idx = mid + 1; |
| + else |
| + right = mid; |
| + } |
| + return set->elems[idx] == elem ? idx + 1 : 0; |
| +} |
| + |
| +static void |
| +re_node_set_remove_at(re_node_set *set, Idx idx) { |
| + if (idx < 0 || idx >= set->nelem) |
| + return; |
| + --set->nelem; |
| + for (; idx < set->nelem; idx++) |
| + set->elems[idx] = set->elems[idx + 1]; |
| +} |
| + |
| + |
| +/* Add the token TOKEN to dfa->nodes, and return the index of the token. |
| + Or return -1 if an error occurred. */ |
| + |
| +static Idx |
| +re_dfa_add_node(re_dfa_t *dfa, re_token_t token) { |
| + if ((dfa->nodes_len >= dfa->nodes_alloc)) { |
| + size_t new_nodes_alloc = dfa->nodes_alloc * 2; |
| + Idx *new_nexts, *new_indices; |
| + re_node_set *new_edests, *new_eclosures; |
| + re_token_t *new_nodes; |
| + |
| + /* Avoid overflows in realloc. */ |
| + const size_t max_object_size = MAX (sizeof(re_token_t), |
| + MAX(sizeof(re_node_set), |
| + sizeof(Idx))); |
| + if ((MIN (IDX_MAX, SIZE_MAX / max_object_size) |
| + < new_nodes_alloc)) |
| + return -1; |
| + |
| + new_nodes = re_realloc(dfa->nodes, re_token_t, new_nodes_alloc); |
| + if ((new_nodes == NULL)) |
| + return -1; |
| + dfa->nodes = new_nodes; |
| + new_nexts = re_realloc(dfa->nexts, Idx, new_nodes_alloc); |
| + new_indices = re_realloc(dfa->org_indices, Idx, new_nodes_alloc); |
| + new_edests = re_realloc(dfa->edests, re_node_set, new_nodes_alloc); |
| + new_eclosures = re_realloc(dfa->eclosures, re_node_set, new_nodes_alloc); |
| + if ((new_nexts == NULL || new_indices == NULL |
| + || new_edests == NULL || new_eclosures == NULL)) { |
| + re_free(new_nexts); |
| + re_free(new_indices); |
| + re_free(new_edests); |
| + re_free(new_eclosures); |
| + return -1; |
| + } |
| + dfa->nexts = new_nexts; |
| + dfa->org_indices = new_indices; |
| + dfa->edests = new_edests; |
| + dfa->eclosures = new_eclosures; |
| + dfa->nodes_alloc = new_nodes_alloc; |
| + } |
| + dfa->nodes[dfa->nodes_len] = token; |
| + dfa->nodes[dfa->nodes_len].constraint = 0; |
| + dfa->nexts[dfa->nodes_len] = -1; |
| + re_node_set_init_empty(dfa->edests + dfa->nodes_len); |
| + re_node_set_init_empty(dfa->eclosures + dfa->nodes_len); |
| + return dfa->nodes_len++; |
| +} |
| + |
| +static re_hashval_t |
| +calc_state_hash(const re_node_set *nodes, unsigned int context) { |
| + re_hashval_t hash = nodes->nelem + context; |
| + Idx i; |
| + for (i = 0; i < nodes->nelem; i++) |
| + hash += nodes->elems[i]; |
| + return hash; |
| +} |
| + |
| +/* Search for the state whose node_set is equivalent to NODES. |
| + Return the pointer to the state, if we found it in the DFA. |
| + Otherwise create the new one and return it. In case of an error |
| + return NULL and set the error code in ERR. |
| + Note: - We assume NULL as the invalid state, then it is possible that |
| + return value is NULL and ERR is REG_NOERROR. |
| + - We never return non-NULL value in case of any errors, it is for |
| + optimization. */ |
| + |
| +static re_dfastate_t * |
| + |
| +re_acquire_state(reg_errcode_t *err, const re_dfa_t *dfa, |
| + const re_node_set *nodes) { |
| + re_hashval_t hash; |
| + re_dfastate_t *new_state; |
| + struct re_state_table_entry *spot; |
| + Idx i; |
| +#if defined GCC_LINT || defined lint |
| + /* Suppress bogus uninitialized-variable warnings. */ |
| + *err = REG_NOERROR; |
| +#endif |
| + if ((nodes->nelem == 0)) { |
| + *err = REG_NOERROR; |
| + return NULL; |
| + } |
| + hash = calc_state_hash(nodes, 0); |
| + spot = dfa->state_table + (hash & dfa->state_hash_mask); |
| + |
| + for (i = 0; i < spot->num; i++) { |
| + re_dfastate_t *state = spot->array[i]; |
| + if (hash != state->hash) |
| + continue; |
| + if (re_node_set_compare(&state->nodes, nodes)) |
| + return state; |
| + } |
| + |
| +/* There are no appropriate state in the dfa, create the new one. */ |
| + new_state = create_ci_newstate(dfa, nodes, hash); |
| + if ((new_state == NULL)) |
| + *err = REG_ESPACE; |
| + |
| + return new_state; |
| +} |
| + |
| +/* Search for the state whose node_set is equivalent to NODES and |
| + whose context is equivalent to CONTEXT. |
| + Return the pointer to the state, if we found it in the DFA. |
| + Otherwise create the new one and return it. In case of an error |
| + return NULL and set the error code in ERR. |
| + Note: - We assume NULL as the invalid state, then it is possible that |
| + return value is NULL and ERR is REG_NOERROR. |
| + - We never return non-NULL value in case of any errors, it is for |
| + optimization. */ |
| + |
| +static re_dfastate_t * |
| + |
| +re_acquire_state_context(reg_errcode_t *err, const re_dfa_t *dfa, |
| + const re_node_set *nodes, unsigned int context) { |
| + re_hashval_t hash; |
| + re_dfastate_t *new_state; |
| + struct re_state_table_entry *spot; |
| + Idx i; |
| +#if defined GCC_LINT || defined lint |
| + /* Suppress bogus uninitialized-variable warnings. */ |
| + *err = REG_NOERROR; |
| +#endif |
| + if (nodes->nelem == 0) { |
| + *err = REG_NOERROR; |
| + return NULL; |
| + } |
| + hash = calc_state_hash(nodes, context); |
| + spot = dfa->state_table + (hash & dfa->state_hash_mask); |
| + |
| + for (i = 0; i < spot->num; i++) { |
| + re_dfastate_t *state = spot->array[i]; |
| + if (state->hash == hash |
| + && state->context == context |
| + && re_node_set_compare(state->entrance_nodes, nodes)) |
| + return state; |
| + } |
| +/* There are no appropriate state in 'dfa', create the new one. */ |
| + new_state = create_cd_newstate(dfa, nodes, context, hash); |
| + if ((new_state == NULL)) |
| + *err = REG_ESPACE; |
| + |
| + return new_state; |
| +} |
| + |
| +/* Finish initialization of the new state NEWSTATE, and using its hash value |
| + HASH put in the appropriate bucket of DFA's state table. Return value |
| + indicates the error code if failed. */ |
| + |
| +static reg_errcode_t |
| + |
| +register_state(const re_dfa_t *dfa, re_dfastate_t *newstate, |
| + re_hashval_t hash) { |
| + struct re_state_table_entry *spot; |
| + reg_errcode_t err; |
| + Idx i; |
| + |
| + newstate->hash = hash; |
| + err = re_node_set_alloc(&newstate->non_eps_nodes, newstate->nodes.nelem); |
| + if ((err != REG_NOERROR)) |
| + return REG_ESPACE; |
| + for (i = 0; i < newstate->nodes.nelem; i++) { |
| + Idx elem = newstate->nodes.elems[i]; |
| + if (!IS_EPSILON_NODE(dfa->nodes[elem].type)) |
| + if (!re_node_set_insert_last(&newstate->non_eps_nodes, elem)) |
| + return REG_ESPACE; |
| + } |
| + |
| + spot = dfa->state_table + (hash & dfa->state_hash_mask); |
| + if ((spot->alloc <= spot->num)) { |
| + Idx new_alloc = 2 * spot->num + 2; |
| + re_dfastate_t **new_array = re_realloc(spot->array, re_dfastate_t * , |
| + new_alloc); |
| + if ((new_array == NULL)) |
| + return REG_ESPACE; |
| + spot->array = new_array; |
| + spot->alloc = new_alloc; |
| + } |
| + spot->array[spot->num++] = newstate; |
| + return REG_NOERROR; |
| +} |
| + |
| +static void |
| +free_state(re_dfastate_t *state) { |
| + re_node_set_free(&state->non_eps_nodes); |
| + re_node_set_free(&state->inveclosure); |
| + if (state->entrance_nodes != &state->nodes) { |
| + re_node_set_free(state->entrance_nodes); |
| + re_free(state->entrance_nodes); |
| + } |
| + re_node_set_free(&state->nodes); |
| + re_free(state->word_trtable); |
| + re_free(state->trtable); |
| + re_free(state); |
| +} |
| + |
| +/* Create the new state which is independent of contexts. |
| + Return the new state if succeeded, otherwise return NULL. */ |
| + |
| +static re_dfastate_t * |
| + |
| +create_ci_newstate(const re_dfa_t *dfa, const re_node_set *nodes, |
| + re_hashval_t hash) { |
| + Idx i; |
| + reg_errcode_t err; |
| + re_dfastate_t *newstate; |
| + |
| + newstate = (re_dfastate_t *) calloc(sizeof(re_dfastate_t), 1); |
| + if ((newstate == NULL)) |
| + return NULL; |
| + err = re_node_set_init_copy(&newstate->nodes, nodes); |
| + if ((err != REG_NOERROR)) { |
| + re_free(newstate); |
| + return NULL; |
| + } |
| + |
| + newstate->entrance_nodes = &newstate->nodes; |
| + for (i = 0; i < nodes->nelem; i++) { |
| + re_token_t *node = dfa->nodes + nodes->elems[i]; |
| + re_token_type_t type = node->type; |
| + if (type == CHARACTER && !node->constraint) |
| + continue; |
| + |
| + /* If the state has the halt node, the state is a halt state. */ |
| + if (type == END_OF_RE) |
| + newstate->halt = 1; |
| + else if (type == OP_BACK_REF) |
| + newstate->has_backref = 1; |
| + else if (type == ANCHOR || node->constraint) |
| + newstate->has_constraint = 1; |
| + } |
| + err = register_state(dfa, newstate, hash); |
| + if ((err != REG_NOERROR)) { |
| + free_state(newstate); |
| + newstate = NULL; |
| + } |
| + return newstate; |
| +} |
| + |
| +/* Create the new state which is depend on the context CONTEXT. |
| + Return the new state if succeeded, otherwise return NULL. */ |
| + |
| +static re_dfastate_t * |
| + |
| +create_cd_newstate(const re_dfa_t *dfa, const re_node_set *nodes, |
| + unsigned int context, re_hashval_t hash) { |
| + Idx i, nctx_nodes = 0; |
| + reg_errcode_t err; |
| + re_dfastate_t *newstate; |
| + |
| + newstate = (re_dfastate_t *) calloc(sizeof(re_dfastate_t), 1); |
| + if ((newstate == NULL)) |
| + return NULL; |
| + err = re_node_set_init_copy(&newstate->nodes, nodes); |
| + if ((err != REG_NOERROR)) { |
| + re_free(newstate); |
| + return NULL; |
| + } |
| + |
| + newstate->context = context; |
| + newstate->entrance_nodes = &newstate->nodes; |
| + |
| + for (i = 0; i < nodes->nelem; i++) { |
| + re_token_t *node = dfa->nodes + nodes->elems[i]; |
| + re_token_type_t type = node->type; |
| + unsigned int constraint = node->constraint; |
| + |
| + if (type == CHARACTER && !constraint) |
| + continue; |
| + |
| + /* If the state has the halt node, the state is a halt state. */ |
| + if (type == END_OF_RE) |
| + newstate->halt = 1; |
| + else if (type == OP_BACK_REF) |
| + newstate->has_backref = 1; |
| + |
| + if (constraint) { |
| + if (newstate->entrance_nodes == &newstate->nodes) { |
| + newstate->entrance_nodes = re_malloc(re_node_set, 1); |
| + if ((newstate->entrance_nodes == NULL)) { |
| + free_state(newstate); |
| + return NULL; |
| + } |
| + if (re_node_set_init_copy(newstate->entrance_nodes, nodes) |
| + != REG_NOERROR) |
| + return NULL; |
| + nctx_nodes = 0; |
| + newstate->has_constraint = 1; |
| + } |
| + |
| + if (NOT_SATISFY_PREV_CONSTRAINT(constraint, context)) { |
| + re_node_set_remove_at(&newstate->nodes, i - nctx_nodes); |
| + ++nctx_nodes; |
| + } |
| + } |
| + } |
| + err = register_state(dfa, newstate, hash); |
| + if ((err != REG_NOERROR)) { |
| + free_state(newstate); |
| + newstate = NULL; |
| + } |
| + return newstate; |
| +} |
| + |
| +/* Extended regular expression matching and search library. |
| + Copyright (C) 2002-2018 Free Software Foundation, Inc. |
| + This file is part of the GNU C Library. |
| + Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. |
| + |
| + The GNU C Library is free software; you can redistribute it and/or |
| + modify it under the terms of the GNU Lesser General Public |
| + License as published by the Free Software Foundation; either |
| + version 2.1 of the License, or (at your option) any later version. |
| + |
| + The GNU C Library is distributed in the hope that it will be useful, |
| + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + Lesser General Public License for more details. |
| + |
| + You should have received a copy of the GNU Lesser General Public |
| + License along with the GNU C Library; if not, see |
| + <https://www.gnu.org/licenses/>. */ |
| + |
| +#ifndef RE_TRANSLATE_TYPE |
| +# define __RE_TRANSLATE_TYPE unsigned char * |
| +# ifdef __USE_GNU |
| +# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE |
| +# endif |
| +#endif |
| + |
| +# define __REPB_PREFIX(name) name |
| + |
| + |
| +static reg_errcode_t re_compile_internal(regex_t *preg, const char *pattern, |
| + size_t length, reg_syntax_t syntax); |
| + |
| +static void re_compile_fastmap_iter(regex_t *bufp, |
| + const re_dfastate_t *init_state, |
| + char *fastmap); |
| + |
| +static reg_errcode_t init_dfa(re_dfa_t *dfa, size_t pat_len); |
| + |
| +static void free_workarea_compile(regex_t *preg); |
| + |
| +static reg_errcode_t create_initial_state(re_dfa_t *dfa); |
| + |
| +static reg_errcode_t analyze(regex_t *preg); |
| + |
| +static reg_errcode_t preorder(bin_tree_t *root, |
| + reg_errcode_t (fn(void *, bin_tree_t *)), |
| + void *extra); |
| + |
| +static reg_errcode_t postorder(bin_tree_t *root, |
| + reg_errcode_t (fn(void *, bin_tree_t *)), |
| + void *extra); |
| + |
| +static reg_errcode_t optimize_subexps(void *extra, bin_tree_t *node); |
| + |
| +static reg_errcode_t lower_subexps(void *extra, bin_tree_t *node); |
| + |
| +static bin_tree_t *lower_subexp(reg_errcode_t *err, regex_t *preg, |
| + bin_tree_t *node); |
| + |
| +static reg_errcode_t calc_first(void *extra, bin_tree_t *node); |
| + |
| +static reg_errcode_t calc_next(void *extra, bin_tree_t *node); |
| + |
| +static reg_errcode_t link_nfa_nodes(void *extra, bin_tree_t *node); |
| + |
| +static Idx duplicate_node(re_dfa_t *dfa, Idx org_idx, unsigned int constraint); |
| + |
| +static Idx search_duplicated_node(const re_dfa_t *dfa, Idx org_node, |
| + unsigned int constraint); |
| + |
| +static reg_errcode_t calc_eclosure(re_dfa_t *dfa); |
| + |
| +static reg_errcode_t calc_eclosure_iter(re_node_set *new_set, re_dfa_t *dfa, |
| + Idx node, bool root); |
| + |
| +static reg_errcode_t calc_inveclosure(re_dfa_t *dfa); |
| + |
| +static Idx fetch_number(re_string_t *input, re_token_t *token, |
| + reg_syntax_t syntax); |
| + |
| +static int peek_token(re_token_t *token, re_string_t *input, |
| + reg_syntax_t syntax); |
| + |
| +static bin_tree_t *parse(re_string_t *regexp, regex_t *preg, |
| + reg_syntax_t syntax, reg_errcode_t *err); |
| + |
| +static bin_tree_t *parse_reg_exp(re_string_t *regexp, regex_t *preg, |
| + re_token_t *token, reg_syntax_t syntax, |
| + Idx nest, reg_errcode_t *err); |
| + |
| +static bin_tree_t *parse_branch(re_string_t *regexp, regex_t *preg, |
| + re_token_t *token, reg_syntax_t syntax, |
| + Idx nest, reg_errcode_t *err); |
| + |
| +static bin_tree_t *parse_expression(re_string_t *regexp, regex_t *preg, |
| + re_token_t *token, reg_syntax_t syntax, |
| + Idx nest, reg_errcode_t *err); |
| + |
| +static bin_tree_t *parse_sub_exp(re_string_t *regexp, regex_t *preg, |
| + re_token_t *token, reg_syntax_t syntax, |
| + Idx nest, reg_errcode_t *err); |
| + |
| +static bin_tree_t *parse_dup_op(bin_tree_t *dup_elem, re_string_t *regexp, |
| + re_dfa_t *dfa, re_token_t *token, |
| + reg_syntax_t syntax, reg_errcode_t *err); |
| + |
| +static bin_tree_t *parse_bracket_exp(re_string_t *regexp, re_dfa_t *dfa, |
| + re_token_t *token, reg_syntax_t syntax, |
| + reg_errcode_t *err); |
| + |
| +static reg_errcode_t parse_bracket_element(bracket_elem_t *elem, |
| + re_string_t *regexp, |
| + re_token_t *token, int token_len, |
| + re_dfa_t *dfa, |
| + reg_syntax_t syntax, |
| + bool accept_hyphen); |
| + |
| +static reg_errcode_t parse_bracket_symbol(bracket_elem_t *elem, |
| + re_string_t *regexp, |
| + re_token_t *token); |
| + |
| +static reg_errcode_t build_equiv_class(bitset_t sbcset, |
| + const unsigned char *name); |
| + |
| +static reg_errcode_t build_charclass(RE_TRANSLATE_TYPE trans, |
| + bitset_t sbcset, |
| + const char *class_name, |
| + reg_syntax_t syntax); |
| + |
| +static bin_tree_t *build_charclass_op(re_dfa_t *dfa, |
| + RE_TRANSLATE_TYPE trans, |
| + const char *class_name, |
| + const char *extra, |
| + bool non_match, reg_errcode_t *err); |
| + |
| +static bin_tree_t *create_tree(re_dfa_t *dfa, |
| + bin_tree_t *left, bin_tree_t *right, |
| + re_token_type_t type); |
| + |
| +static bin_tree_t *create_token_tree(re_dfa_t *dfa, |
| + bin_tree_t *left, bin_tree_t *right, |
| + const re_token_t *token); |
| + |
| +static bin_tree_t *duplicate_tree(const bin_tree_t *src, re_dfa_t *dfa); |
| + |
| +static void free_token(re_token_t *node); |
| + |
| +static reg_errcode_t free_tree(void *extra, bin_tree_t *node); |
| + |
| +static reg_errcode_t mark_opt_subexp(void *extra, bin_tree_t *node); |
| + |
| +/* This table gives an error message for each of the error codes listed |
| + in regex.h. Obviously the order here has to be same as there. |
| + POSIX doesn't require that we do anything for REG_NOERROR, |
| + but why not be nice? */ |
| + |
| +static const char __re_error_msgid[] = |
| + { |
| +#define REG_NOERROR_IDX 0 |
| + gettext_noop("Success") /* REG_NOERROR */ |
| + "\0" |
| +#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") |
| + gettext_noop ("No match") /* REG_NOMATCH */ |
| + "\0" |
| +#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") |
| + gettext_noop ("Invalid regular expression") /* REG_BADPAT */ |
| + "\0" |
| +#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") |
| + gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ |
| + "\0" |
| +#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") |
| + gettext_noop ("Invalid character class name") /* REG_ECTYPE */ |
| + "\0" |
| +#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") |
| + gettext_noop ("Trailing backslash") /* REG_EESCAPE */ |
| + "\0" |
| +#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") |
| + gettext_noop ("Invalid back reference") /* REG_ESUBREG */ |
| + "\0" |
| +#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") |
| + gettext_noop ("Unmatched [, [^, [:, [., or [=") /* REG_EBRACK */ |
| + "\0" |
| +#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [, [^, [:, [., or [=") |
| + gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ |
| + "\0" |
| +#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") |
| + gettext_noop ("Unmatched \\{") /* REG_EBRACE */ |
| + "\0" |
| +#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") |
| + gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ |
| + "\0" |
| +#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") |
| + gettext_noop ("Invalid range end") /* REG_ERANGE */ |
| + "\0" |
| +#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") |
| + gettext_noop ("Memory exhausted") /* REG_ESPACE */ |
| + "\0" |
| +#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") |
| + gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ |
| + "\0" |
| +#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") |
| + gettext_noop ("Premature end of regular expression") /* REG_EEND */ |
| + "\0" |
| +#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") |
| + gettext_noop ("Regular expression too big") /* REG_ESIZE */ |
| + "\0" |
| +#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") |
| + gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ |
| + }; |
| + |
| +static const size_t __re_error_msgid_idx[] = |
| + { |
| + REG_NOERROR_IDX, |
| + REG_NOMATCH_IDX, |
| + REG_BADPAT_IDX, |
| + REG_ECOLLATE_IDX, |
| + REG_ECTYPE_IDX, |
| + REG_EESCAPE_IDX, |
| + REG_ESUBREG_IDX, |
| + REG_EBRACK_IDX, |
| + REG_EPAREN_IDX, |
| + REG_EBRACE_IDX, |
| + REG_BADBR_IDX, |
| + REG_ERANGE_IDX, |
| + REG_ESPACE_IDX, |
| + REG_BADRPT_IDX, |
| + REG_EEND_IDX, |
| + REG_ESIZE_IDX, |
| + REG_ERPAREN_IDX |
| + }; |
| + |
| +/* Entry points for GNU code. */ |
| + |
| +/* re_compile_pattern is the GNU regular expression compiler: it |
| + compiles PATTERN (of length LENGTH) and puts the result in BUFP. |
| + Returns 0 if the pattern was valid, otherwise an error string. |
| + |
| + Assumes the 'allocated' (and perhaps 'buffer') and 'translate' fields |
| + are set in BUFP on entry. */ |
| + |
| +const char * |
| +re_compile_pattern(const char *pattern, size_t length, |
| + struct re_pattern_buffer *bufp) { |
| + reg_errcode_t ret; |
| + |
| + /* And GNU code determines whether or not to get register information |
| + by passing null for the REGS argument to re_match, etc., not by |
| + setting no_sub, unless RE_NO_SUB is set. */ |
| + bufp->no_sub = !!(re_syntax_options & RE_NO_SUB); |
| + |
| + /* Match anchors at newline. */ |
| + bufp->newline_anchor = 1; |
| + |
| + ret = re_compile_internal(bufp, pattern, length, re_syntax_options); |
| + |
| + if (!ret) |
| + return NULL; |
| + return gettext(__re_error_msgid + __re_error_msgid_idx[(int) ret]); |
| +} |
| + |
| + |
| +/* Set by 're_set_syntax' to the current regexp syntax to recognize. Can |
| + also be assigned to arbitrarily: each pattern buffer stores its own |
| + syntax, so it can be changed between regex compilations. */ |
| +/* This has no initializer because initialized variables in Emacs |
| + become read-only after dumping. */ |
| +reg_syntax_t re_syntax_options; |
| + |
| + |
| +/* Specify the precise syntax of regexps for compilation. This provides |
| + for compatibility for various utilities which historically have |
| + different, incompatible syntaxes. |
| + |
| + The argument SYNTAX is a bit mask comprised of the various bits |
| + defined in regex.h. We return the old syntax. */ |
| + |
| +reg_syntax_t |
| +re_set_syntax(reg_syntax_t syntax) { |
| + reg_syntax_t ret = re_syntax_options; |
| + |
| + re_syntax_options = syntax; |
| + return ret; |
| +} |
| + |
| +int |
| +re_compile_fastmap(struct re_pattern_buffer *bufp) { |
| + re_dfa_t *dfa = bufp->buffer; |
| + char *fastmap = bufp->fastmap; |
| + |
| + memset(fastmap, '\0', sizeof(char) * SBC_MAX); |
| + re_compile_fastmap_iter(bufp, dfa->init_state, fastmap); |
| + if (dfa->init_state != dfa->init_state_word) |
| + re_compile_fastmap_iter(bufp, dfa->init_state_word, fastmap); |
| + if (dfa->init_state != dfa->init_state_nl) |
| + re_compile_fastmap_iter(bufp, dfa->init_state_nl, fastmap); |
| + if (dfa->init_state != dfa->init_state_begbuf) |
| + re_compile_fastmap_iter(bufp, dfa->init_state_begbuf, fastmap); |
| + bufp->fastmap_accurate = 1; |
| + return 0; |
| +} |
| + |
| + |
| +static inline void |
| +__attribute__ ((always_inline)) |
| +re_set_fastmap(char *fastmap, bool icase, int ch) { |
| + fastmap[ch] = 1; |
| + if (icase) |
| + fastmap[tolower(ch)] = 1; |
| +} |
| + |
| +/* Helper function for re_compile_fastmap. |
| + Compile fastmap for the initial_state INIT_STATE. */ |
| + |
| +static void |
| +re_compile_fastmap_iter(regex_t *bufp, const re_dfastate_t *init_state, |
| + char *fastmap) { |
| + re_dfa_t *dfa = bufp->buffer; |
| + Idx node_cnt; |
| + bool icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE)); |
| + for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) { |
| + Idx node = init_state->nodes.elems[node_cnt]; |
| + re_token_type_t type = dfa->nodes[node].type; |
| + |
| + if (type == CHARACTER) { |
| + re_set_fastmap(fastmap, icase, dfa->nodes[node].opr.c); |
| + } else if (type == SIMPLE_BRACKET) { |
| + int i, ch; |
| + for (i = 0, ch = 0; i < BITSET_WORDS; ++i) { |
| + int j; |
| + bitset_word_t w = dfa->nodes[node].opr.sbcset[i]; |
| + for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch) |
| + if (w & ((bitset_word_t) 1 << j)) |
| + re_set_fastmap(fastmap, icase, ch); |
| + } |
| + } else if (type == OP_PERIOD |
| + || type == END_OF_RE) { |
| + memset(fastmap, '\1', sizeof(char) * SBC_MAX); |
| + if (type == END_OF_RE) |
| + bufp->can_be_null = 1; |
| + return; |
| + } |
| + } |
| +} |
| + |
| +/* Entry point for POSIX code. */ |
| +/* regcomp takes a regular expression as a string and compiles it. |
| + |
| + PREG is a regex_t *. We do not expect any fields to be initialized, |
| + since POSIX says we shouldn't. Thus, we set |
| + |
| + 'buffer' to the compiled pattern; |
| + 'used' to the length of the compiled pattern; |
| + 'syntax' to RE_SYNTAX_POSIX_EXTENDED if the |
| + REG_EXTENDED bit in CFLAGS is set; otherwise, to |
| + RE_SYNTAX_POSIX_BASIC; |
| + 'newline_anchor' to REG_NEWLINE being set in CFLAGS; |
| + 'fastmap' to an allocated space for the fastmap; |
| + 'fastmap_accurate' to zero; |
| + 're_nsub' to the number of subexpressions in PATTERN. |
| + |
| + PATTERN is the address of the pattern string. |
| + |
| + CFLAGS is a series of bits which affect compilation. |
| + |
| + If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we |
| + use POSIX basic syntax. |
| + |
| + If REG_NEWLINE is set, then . and [^...] don't match newline. |
| + Also, regexec will try a match beginning after every newline. |
| + |
| + If REG_ICASE is set, then we considers upper- and lowercase |
| + versions of letters to be equivalent when matching. |
| + |
| + If REG_NOSUB is set, then when PREG is passed to regexec, that |
| + routine will report only success or failure, and nothing about the |
| + registers. |
| + |
| + It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for |
| + the return codes and their meanings.) */ |
| + |
| +int |
| +regcomp(regex_t *_Restrict_ preg, const char *_Restrict_ pattern, int cflags) { |
| + reg_errcode_t ret; |
| + reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED |
| + : RE_SYNTAX_POSIX_BASIC); |
| + |
| + preg->buffer = NULL; |
| + preg->allocated = 0; |
| + preg->used = 0; |
| + |
| + /* Try to allocate space for the fastmap. */ |
| + preg->fastmap = re_malloc( |
| + char, SBC_MAX); |
| + if ((preg->fastmap == NULL)) |
| + return REG_ESPACE; |
| + |
| + syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; |
| + |
| + /* If REG_NEWLINE is set, newlines are treated differently. */ |
| + if (cflags & REG_NEWLINE) { /* REG_NEWLINE implies neither . nor [^...] match newline. */ |
| + syntax &= ~RE_DOT_NEWLINE; |
| + syntax |= RE_HAT_LISTS_NOT_NEWLINE; |
| + /* It also changes the matching behavior. */ |
| + preg->newline_anchor = 1; |
| + } else |
| + preg->newline_anchor = 0; |
| + preg->no_sub = !!(cflags & REG_NOSUB); |
| + preg->translate = NULL; |
| + |
| + ret = re_compile_internal(preg, pattern, strlen(pattern), syntax); |
| + |
| + /* POSIX doesn't distinguish between an unmatched open-group and an |
| + unmatched close-group: both are REG_EPAREN. */ |
| + if (ret == REG_ERPAREN) |
| + ret = REG_EPAREN; |
| + |
| + /* We have already checked preg->fastmap != NULL. */ |
| + if ((ret == REG_NOERROR)) |
| + /* Compute the fastmap now, since regexec cannot modify the pattern |
| + buffer. This function never fails in this implementation. */ |
| + (void) re_compile_fastmap(preg); |
| + else { |
| + /* Some error occurred while compiling the expression. */ |
| + re_free(preg->fastmap); |
| + preg->fastmap = NULL; |
| + } |
| + |
| + return (int) ret; |
| +} |
| + |
| +/* Returns a message corresponding to an error code, ERRCODE, returned |
| + from either regcomp or regexec. We don't use PREG here. */ |
| + |
| +size_t |
| +regerror(int errcode, const regex_t *_Restrict_ preg, char *_Restrict_ errbuf, |
| + size_t errbuf_size) { |
| + const char *msg; |
| + size_t msg_size; |
| + int nerrcodes = sizeof __re_error_msgid_idx / sizeof __re_error_msgid_idx[0]; |
| + |
| + if ((errcode < 0 || errcode >= nerrcodes)) |
| + /* Only error codes returned by the rest of the code should be passed |
| + to this routine. If we are given anything else, or if other regex |
| + code generates an invalid error code, then the program has a bug. |
| + Dump core so we can fix it. */ |
| + abort(); |
| + |
| + msg = gettext(__re_error_msgid + __re_error_msgid_idx[errcode]); |
| + |
| + msg_size = strlen(msg) + 1; /* Includes the null. */ |
| + |
| + if ((errbuf_size != 0)) { |
| + size_t cpy_size = msg_size; |
| + if ((msg_size > errbuf_size)) { |
| + cpy_size = errbuf_size - 1; |
| + errbuf[cpy_size] = '\0'; |
| + } |
| + memcpy(errbuf, msg, cpy_size); |
| + } |
| + |
| + return msg_size; |
| +} |
| + |
| +static void |
| +free_dfa_content(re_dfa_t *dfa) { |
| + Idx i, j; |
| + |
| + if (dfa->nodes) |
| + for (i = 0; i < dfa->nodes_len; ++i) |
| + free_token(dfa->nodes + i); |
| + re_free(dfa->nexts); |
| + for (i = 0; i < dfa->nodes_len; ++i) { |
| + if (dfa->eclosures != NULL) |
| + re_node_set_free(dfa->eclosures + i); |
| + if (dfa->inveclosures != NULL) |
| + re_node_set_free(dfa->inveclosures + i); |
| + if (dfa->edests != NULL) |
| + re_node_set_free(dfa->edests + i); |
| + } |
| + re_free(dfa->edests); |
| + re_free(dfa->eclosures); |
| + re_free(dfa->inveclosures); |
| + re_free(dfa->nodes); |
| + |
| + if (dfa->state_table) |
| + for (i = 0; i <= dfa->state_hash_mask; ++i) { |
| + struct re_state_table_entry *entry = dfa->state_table + i; |
| + for (j = 0; j < entry->num; ++j) { |
| + re_dfastate_t *state = entry->array[j]; |
| + free_state(state); |
| + } |
| + re_free(entry->array); |
| + } |
| + re_free(dfa->state_table); |
| + re_free(dfa->subexp_map); |
| + re_free(dfa); |
| +} |
| + |
| + |
| +/* Free dynamically allocated space used by PREG. */ |
| + |
| +void |
| +regfree(regex_t *preg) { |
| + re_dfa_t *dfa = preg->buffer; |
| + if ((dfa != NULL)) { |
| + lock_fini(dfa->lock); |
| + free_dfa_content(dfa); |
| + } |
| + preg->buffer = NULL; |
| + preg->allocated = 0; |
| + |
| + re_free(preg->fastmap); |
| + preg->fastmap = NULL; |
| + |
| + re_free(preg->translate); |
| + preg->translate = NULL; |
| +} |
| + |
| +/* Internal entry point. |
| + Compile the regular expression PATTERN, whose length is LENGTH. |
| + SYNTAX indicate regular expression's syntax. */ |
| + |
| +static reg_errcode_t |
| +re_compile_internal(regex_t *preg, const char *pattern, size_t length, |
| + reg_syntax_t syntax) { |
| + reg_errcode_t err = REG_NOERROR; |
| + re_dfa_t *dfa; |
| + re_string_t regexp; |
| + |
| + /* Initialize the pattern buffer. */ |
| + preg->fastmap_accurate = 0; |
| + preg->syntax = syntax; |
| + preg->not_bol = preg->not_eol = 0; |
| + preg->used = 0; |
| + preg->re_nsub = 0; |
| + preg->can_be_null = 0; |
| + preg->regs_allocated = REGS_UNALLOCATED; |
| + |
| + /* Initialize the dfa. */ |
| + dfa = preg->buffer; |
| + if ((preg->allocated < sizeof(re_dfa_t))) { |
| + /* If zero allocated, but buffer is non-null, try to realloc |
| + enough space. This loses if buffer's address is bogus, but |
| + that is the user's responsibility. If ->buffer is NULL this |
| + is a simple allocation. */ |
| + dfa = re_realloc(preg->buffer, re_dfa_t, 1); |
| + if (dfa == NULL) |
| + return REG_ESPACE; |
| + preg->allocated = sizeof(re_dfa_t); |
| + preg->buffer = dfa; |
| + } |
| + preg->used = sizeof(re_dfa_t); |
| + |
| + err = init_dfa(dfa, length); |
| + if ((err == REG_NOERROR && lock_init(dfa->lock) != 0)) |
| + err = REG_ESPACE; |
| + if ((err != REG_NOERROR)) { |
| + free_dfa_content(dfa); |
| + preg->buffer = NULL; |
| + preg->allocated = 0; |
| + return err; |
| + } |
| + err = re_string_construct(®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 <reg_exp>: |
| + CAT |
| + / \ |
| + / \ |
| + <reg_exp> EOR |
| + |
| + CAT means concatenation. |
| + EOR means end of regular expression. */ |
| + |
| +static bin_tree_t * |
| +parse(re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, |
| + reg_errcode_t *err) { |
| + re_dfa_t *dfa = preg->buffer; |
| + bin_tree_t *tree, *eor, *root; |
| + re_token_t current_token; |
| + dfa->syntax = syntax; |
| + fetch_token(¤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 |
| + <branch1>|<branch2>: |
| + ALT |
| + / \ |
| + / \ |
| + <branch1> <branch2> |
| + |
| + ALT means alternative, which represents the operator '|'. */ |
| + |
| +static bin_tree_t * |
| +parse_reg_exp(re_string_t *regexp, regex_t *preg, re_token_t *token, |
| + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { |
| + re_dfa_t *dfa = preg->buffer; |
| + bin_tree_t *tree, *branch = NULL; |
| + bitset_word_t initial_bkref_map = dfa->completed_bkref_map; |
| + tree = parse_branch(regexp, preg, token, syntax, nest, err); |
| + if ((*err != REG_NOERROR && tree == NULL)) |
| + return NULL; |
| + |
| + while (token->type == OP_ALT) { |
| + fetch_token(token, regexp, syntax | RE_CARET_ANCHORS_HERE); |
| + if (token->type != OP_ALT && token->type != END_OF_RE |
| + && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { |
| + bitset_word_t accumulated_bkref_map = dfa->completed_bkref_map; |
| + dfa->completed_bkref_map = initial_bkref_map; |
| + branch = parse_branch(regexp, preg, token, syntax, nest, err); |
| + if ((*err != REG_NOERROR && branch == NULL)) { |
| + if (tree != NULL) |
| + postorder(tree, free_tree, NULL); |
| + return NULL; |
| + } |
| + dfa->completed_bkref_map |= accumulated_bkref_map; |
| + } else |
| + branch = NULL; |
| + tree = create_tree(dfa, tree, branch, OP_ALT); |
| + if ((tree == NULL)) { |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + } |
| + return tree; |
| +} |
| + |
| +/* This function build the following tree, from regular expression |
| + <exp1><exp2>: |
| + CAT |
| + / \ |
| + / \ |
| + <exp1> <exp2> |
| + |
| + CAT means concatenation. */ |
| + |
| +static bin_tree_t * |
| +parse_branch(re_string_t *regexp, regex_t *preg, re_token_t *token, |
| + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { |
| + bin_tree_t *tree, *expr; |
| + re_dfa_t *dfa = preg->buffer; |
| + tree = parse_expression(regexp, preg, token, syntax, nest, err); |
| + if ((*err != REG_NOERROR && tree == NULL)) |
| + return NULL; |
| + |
| + while (token->type != OP_ALT && token->type != END_OF_RE |
| + && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { |
| + expr = parse_expression(regexp, preg, token, syntax, nest, err); |
| + if ((*err != REG_NOERROR && expr == NULL)) { |
| + if (tree != NULL) |
| + postorder(tree, free_tree, NULL); |
| + return NULL; |
| + } |
| + if (tree != NULL && expr != NULL) { |
| + bin_tree_t *newtree = create_tree(dfa, tree, expr, CONCAT); |
| + if (newtree == NULL) { |
| + postorder(expr, free_tree, NULL); |
| + postorder(tree, free_tree, NULL); |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + tree = newtree; |
| + } else if (tree == NULL) |
| + tree = expr; |
| + /* Otherwise expr == NULL, we don't need to create new tree. */ |
| + } |
| + return tree; |
| +} |
| + |
| +/* This function build the following tree, from regular expression a*: |
| + * |
| + | |
| + a |
| +*/ |
| + |
| +static bin_tree_t * |
| +parse_expression(re_string_t *regexp, regex_t *preg, re_token_t *token, |
| + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { |
| + re_dfa_t *dfa = preg->buffer; |
| + bin_tree_t *tree; |
| + switch (token->type) { |
| + case CHARACTER: |
| + tree = create_token_tree(dfa, NULL, NULL, token); |
| + if ((tree == NULL)) { |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + break; |
| + |
| + case OP_OPEN_SUBEXP: |
| + tree = parse_sub_exp(regexp, preg, token, syntax, nest + 1, err); |
| + if ((*err != REG_NOERROR && tree == NULL)) |
| + return NULL; |
| + break; |
| + |
| + case OP_OPEN_BRACKET: |
| + tree = parse_bracket_exp(regexp, dfa, token, syntax, err); |
| + if ((*err != REG_NOERROR && tree == NULL)) |
| + return NULL; |
| + break; |
| + |
| + case OP_BACK_REF: |
| + if (!(dfa->completed_bkref_map & (1 << token->opr.idx))) { |
| + *err = REG_ESUBREG; |
| + return NULL; |
| + } |
| + dfa->used_bkref_map |= 1 << token->opr.idx; |
| + tree = create_token_tree(dfa, NULL, NULL, token); |
| + if ((tree == NULL)) { |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + ++dfa->nbackref; |
| + dfa->has_mb_node = 1; |
| + break; |
| + |
| + case OP_OPEN_DUP_NUM: |
| + if (syntax & RE_CONTEXT_INVALID_DUP) { |
| + *err = REG_BADRPT; |
| + return NULL; |
| + } |
| + FALLTHROUGH; |
| + case OP_DUP_ASTERISK: |
| + case OP_DUP_PLUS: |
| + case OP_DUP_QUESTION: |
| + if (syntax & RE_CONTEXT_INVALID_OPS) { |
| + *err = REG_BADRPT; |
| + return NULL; |
| + } else if (syntax & RE_CONTEXT_INDEP_OPS) { |
| + fetch_token(token, regexp, syntax); |
| + return parse_expression(regexp, preg, token, syntax, nest, err); |
| + } |
| + FALLTHROUGH; |
| + case OP_CLOSE_SUBEXP: |
| + if ((token->type == OP_CLOSE_SUBEXP) && |
| + !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) { |
| + *err = REG_ERPAREN; |
| + return NULL; |
| + } |
| + FALLTHROUGH; |
| + case OP_CLOSE_DUP_NUM: |
| + /* We treat it as a normal character. */ |
| + |
| + /* Then we can these characters as normal characters. */ |
| + token->type = CHARACTER; |
| + /* mb_partial and word_char bits should be initialized already |
| + by peek_token. */ |
| + tree = create_token_tree(dfa, NULL, NULL, token); |
| + if ((tree == NULL)) { |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + break; |
| + |
| + case ANCHOR: |
| + if ((token->opr.ctx_type |
| + & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST)) |
| + && dfa->word_ops_used == 0) |
| + init_word_char(dfa); |
| + if (token->opr.ctx_type == WORD_DELIM |
| + || token->opr.ctx_type == NOT_WORD_DELIM) { |
| + bin_tree_t *tree_first, *tree_last; |
| + if (token->opr.ctx_type == WORD_DELIM) { |
| + token->opr.ctx_type = WORD_FIRST; |
| + tree_first = create_token_tree(dfa, NULL, NULL, token); |
| + token->opr.ctx_type = WORD_LAST; |
| + } else { |
| + token->opr.ctx_type = INSIDE_WORD; |
| + tree_first = create_token_tree(dfa, NULL, NULL, token); |
| + token->opr.ctx_type = INSIDE_NOTWORD; |
| + } |
| + tree_last = create_token_tree(dfa, NULL, NULL, token); |
| + tree = create_tree(dfa, tree_first, tree_last, OP_ALT); |
| + if ((tree_first == NULL || tree_last == NULL |
| + || tree == NULL)) { |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + } else { |
| + tree = create_token_tree(dfa, NULL, NULL, token); |
| + if ((tree == NULL)) { |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + } |
| + /* We must return here, since ANCHORs can't be followed |
| + by repetition operators. |
| + eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>", |
| + it must not be "<ANCHOR(^)><REPEAT(*)>". */ |
| + fetch_token(token, regexp, syntax); |
| + return tree; |
| + |
| + case OP_PERIOD: |
| + tree = create_token_tree(dfa, NULL, NULL, token); |
| + if ((tree == NULL)) { |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + if (dfa->mb_cur_max > 1) |
| + dfa->has_mb_node = 1; |
| + break; |
| + |
| + case OP_WORD: |
| + case OP_NOTWORD: |
| + tree = build_charclass_op(dfa, regexp->trans, |
| + "alnum", |
| + "_", |
| + token->type == OP_NOTWORD, err); |
| + if ((*err != REG_NOERROR && tree == NULL)) |
| + return NULL; |
| + break; |
| + |
| + case OP_SPACE: |
| + case OP_NOTSPACE: |
| + tree = build_charclass_op(dfa, regexp->trans, |
| + "space", |
| + "", |
| + token->type == OP_NOTSPACE, err); |
| + if ((*err != REG_NOERROR && tree == NULL)) |
| + return NULL; |
| + break; |
| + |
| + case OP_ALT: |
| + case END_OF_RE: |
| + return NULL; |
| + |
| + case BACK_SLASH: |
| + *err = REG_EESCAPE; |
| + return NULL; |
| + |
| + default: |
| + /* Must not happen? */ |
| + return NULL; |
| + } |
| + fetch_token(token, regexp, syntax); |
| + |
| + while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS |
| + || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) { |
| + bin_tree_t *dup_tree = parse_dup_op(tree, regexp, dfa, token, |
| + syntax, err); |
| + if ((*err != REG_NOERROR && dup_tree == NULL)) { |
| + if (tree != NULL) |
| + postorder(tree, free_tree, NULL); |
| + return NULL; |
| + } |
| + tree = dup_tree; |
| + /* In BRE consecutive duplications are not allowed. */ |
| + if ((syntax & RE_CONTEXT_INVALID_DUP) |
| + && (token->type == OP_DUP_ASTERISK |
| + || token->type == OP_OPEN_DUP_NUM)) { |
| + if (tree != NULL) |
| + postorder(tree, free_tree, NULL); |
| + *err = REG_BADRPT; |
| + return NULL; |
| + } |
| + } |
| + |
| + return tree; |
| +} |
| + |
| +/* This function build the following tree, from regular expression |
| + (<reg_exp>): |
| + SUBEXP |
| + | |
| + <reg_exp> |
| +*/ |
| + |
| +static bin_tree_t * |
| +parse_sub_exp(re_string_t *regexp, regex_t *preg, re_token_t *token, |
| + reg_syntax_t syntax, Idx nest, reg_errcode_t *err) { |
| + re_dfa_t *dfa = preg->buffer; |
| + bin_tree_t *tree; |
| + size_t cur_nsub; |
| + cur_nsub = preg->re_nsub++; |
| + |
| + fetch_token(token, regexp, syntax | RE_CARET_ANCHORS_HERE); |
| + |
| + /* The subexpression may be a null string. */ |
| + if (token->type == OP_CLOSE_SUBEXP) |
| + tree = NULL; |
| + else { |
| + tree = parse_reg_exp(regexp, preg, token, syntax, nest, err); |
| + if ((*err == REG_NOERROR |
| + && token->type != OP_CLOSE_SUBEXP)) { |
| + if (tree != NULL) |
| + postorder(tree, free_tree, NULL); |
| + *err = REG_EPAREN; |
| + } |
| + if ((*err != REG_NOERROR)) |
| + return NULL; |
| + } |
| + |
| + if (cur_nsub <= '9' - '1') |
| + dfa->completed_bkref_map |= 1 << cur_nsub; |
| + |
| + tree = create_tree(dfa, tree, NULL, SUBEXP); |
| + if ((tree == NULL)) { |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + tree->token.opr.idx = cur_nsub; |
| + return tree; |
| +} |
| + |
| +/* This function parse repetition operators like "*", "+", "{1,3}" etc. */ |
| + |
| +static bin_tree_t * |
| +parse_dup_op(bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa, |
| + re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err) { |
| + bin_tree_t *tree = NULL, *old_tree = NULL; |
| + Idx i, start, end, start_idx = re_string_cur_idx(regexp); |
| + re_token_t start_token = *token; |
| + |
| + if (token->type == OP_OPEN_DUP_NUM) { |
| + end = 0; |
| + start = fetch_number(regexp, token, syntax); |
| + if (start == -1) { |
| + if (token->type == CHARACTER && token->opr.c == ',') |
| + start = 0; /* We treat "{,m}" as "{0,m}". */ |
| + else { |
| + *err = REG_BADBR; /* <re>{} is invalid. */ |
| + return NULL; |
| + } |
| + } |
| + if ((start != -2)) { |
| + /* We treat "{n}" as "{n,n}". */ |
| + end = ((token->type == OP_CLOSE_DUP_NUM) ? start |
| + : ((token->type == CHARACTER && token->opr.c == ',') |
| + ? fetch_number(regexp, token, syntax) : -2)); |
| + } |
| + if ((start == -2 || end == -2)) { |
| + /* Invalid sequence. */ |
| + if ((!(syntax & RE_INVALID_INTERVAL_ORD))) { |
| + if (token->type == END_OF_RE) |
| + *err = REG_EBRACE; |
| + else |
| + *err = REG_BADBR; |
| + |
| + return NULL; |
| + } |
| + |
| + /* If the syntax bit is set, rollback. */ |
| + re_string_set_index(regexp, start_idx); |
| + *token = start_token; |
| + token->type = CHARACTER; |
| + /* mb_partial and word_char bits should be already initialized by |
| + peek_token. */ |
| + return elem; |
| + } |
| + |
| + if (((end != -1 && start > end) |
| + || token->type != OP_CLOSE_DUP_NUM)) { |
| + /* First number greater than second. */ |
| + *err = REG_BADBR; |
| + return NULL; |
| + } |
| + |
| + if ((RE_DUP_MAX < (end == -1 ? start : end))) { |
| + *err = REG_ESIZE; |
| + return NULL; |
| + } |
| + } else { |
| + start = (token->type == OP_DUP_PLUS) ? 1 : 0; |
| + end = (token->type == OP_DUP_QUESTION) ? 1 : -1; |
| + } |
| + |
| + fetch_token(token, regexp, syntax); |
| + |
| + if ((elem == NULL)) |
| + return NULL; |
| + if ((start == 0 && end == 0)) { |
| + postorder(elem, free_tree, NULL); |
| + return NULL; |
| + } |
| + |
| + /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */ |
| + if ((start > 0)) { |
| + tree = elem; |
| + for (i = 2; i <= start; ++i) { |
| + elem = duplicate_tree(elem, dfa); |
| + tree = create_tree(dfa, tree, elem, CONCAT); |
| + if ((elem == NULL || tree == NULL)) |
| + goto parse_dup_op_espace; |
| + } |
| + |
| + if (start == end) |
| + return tree; |
| + |
| + /* Duplicate ELEM before it is marked optional. */ |
| + elem = duplicate_tree(elem, dfa); |
| + if ((elem == NULL)) |
| + goto parse_dup_op_espace; |
| + old_tree = tree; |
| + } else |
| + old_tree = NULL; |
| + |
| + if (elem->token.type == SUBEXP) { |
| + uintptr_t subidx = elem->token.opr.idx; |
| + postorder(elem, mark_opt_subexp, (void *) subidx); |
| + } |
| + |
| + tree = create_tree(dfa, elem, NULL, |
| + (end == -1 ? OP_DUP_ASTERISK : OP_ALT)); |
| + if ((tree == NULL)) |
| + goto parse_dup_op_espace; |
| + |
| + /* This loop is actually executed only when end != -1, |
| + to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have |
| + already created the start+1-th copy. */ |
| + if (TYPE_SIGNED(Idx) || end != -1) |
| + for (i = start + 2; i <= end; ++i) { |
| + elem = duplicate_tree(elem, dfa); |
| + tree = create_tree(dfa, tree, elem, CONCAT); |
| + if ((elem == NULL || tree == NULL)) |
| + goto parse_dup_op_espace; |
| + |
| + tree = create_tree(dfa, tree, NULL, OP_ALT); |
| + if ((tree == NULL)) |
| + goto parse_dup_op_espace; |
| + } |
| + |
| + if (old_tree) |
| + tree = create_tree(dfa, old_tree, tree, CONCAT); |
| + |
| + return tree; |
| + |
| + parse_dup_op_espace: |
| + *err = REG_ESPACE; |
| + return NULL; |
| +} |
| + |
| +/* Size of the names for collating symbol/equivalence_class/character_class. |
| + I'm not sure, but maybe enough. */ |
| +#define BRACKET_NAME_BUF_SIZE 32 |
| + |
| +/* Local function for parse_bracket_exp only used in case of NOT _LIBC. |
| + Build the range expression which starts from START_ELEM, and ends |
| + at END_ELEM. The result are written to MBCSET and SBCSET. |
| + RANGE_ALLOC is the allocated size of mbcset->range_starts, and |
| + mbcset->range_ends, is a pointer argument since we may |
| + update it. */ |
| + |
| +static reg_errcode_t |
| +build_range_exp(const reg_syntax_t syntax, |
| + bitset_t sbcset, |
| + const bracket_elem_t *start_elem, |
| + const bracket_elem_t *end_elem) { |
| + unsigned int start_ch, end_ch; |
| + /* Equivalence Classes and Character Classes can't be a range start/end. */ |
| + if ((start_elem->type == EQUIV_CLASS |
| + || start_elem->type == CHAR_CLASS |
| + || end_elem->type == EQUIV_CLASS |
| + || end_elem->type == CHAR_CLASS)) |
| + return REG_ERANGE; |
| + |
| + /* We can handle no multi character collating elements without libc |
| + support. */ |
| + if (((start_elem->type == COLL_SYM |
| + && strlen((char *) start_elem->opr.name) > 1) |
| + || (end_elem->type == COLL_SYM |
| + && strlen((char *) end_elem->opr.name) > 1))) |
| + return REG_ECOLLATE; |
| + |
| + { |
| + unsigned int ch; |
| + start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch |
| + : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] |
| + : 0)); |
| + end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch |
| + : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] |
| + : 0)); |
| + if (start_ch > end_ch) |
| + return REG_ERANGE; |
| + /* Build the table for single byte characters. */ |
| + for (ch = 0; ch < SBC_MAX; ++ch) |
| + if (start_ch <= ch && ch <= end_ch) |
| + bitset_set(sbcset, ch); |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Helper function for parse_bracket_exp only used in case of NOT _LIBC.. |
| + Build the collating element which is represented by NAME. |
| + The result are written to MBCSET and SBCSET. |
| + COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a |
| + pointer argument since we may update it. */ |
| + |
| +static reg_errcode_t |
| +build_collating_symbol(bitset_t sbcset, const unsigned char *name) { |
| + size_t name_len = strlen((const char *) name); |
| + if ((name_len != 1)) |
| + return REG_ECOLLATE; |
| + else { |
| + bitset_set(sbcset, name[0]); |
| + return REG_NOERROR; |
| + } |
| +} |
| + |
| + |
| +/* This function parse bracket expression like "[abc]", "[a-c]", |
| + "[[.a-a.]]" etc. */ |
| + |
| +static bin_tree_t * |
| +parse_bracket_exp(re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, |
| + reg_syntax_t syntax, reg_errcode_t *err) { |
| + re_token_t br_token; |
| + re_bitset_ptr_t sbcset; |
| + bool non_match = false; |
| + bin_tree_t *work_tree; |
| + int token_len; |
| + bool first_round = true; |
| + sbcset = (re_bitset_ptr_t) calloc(sizeof(bitset_t), 1); |
| + if ((sbcset == NULL)) { |
| + re_free(sbcset); |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + |
| + token_len = peek_token_bracket(token, regexp, syntax); |
| + if ((token->type == END_OF_RE)) { |
| + *err = REG_BADPAT; |
| + goto parse_bracket_exp_free_return; |
| + } |
| + if (token->type == OP_NON_MATCH_LIST) { |
| + non_match = true; |
| + if (syntax & RE_HAT_LISTS_NOT_NEWLINE) |
| + bitset_set(sbcset, '\n'); |
| + re_string_skip_bytes(regexp, token_len); /* Skip a token. */ |
| + token_len = peek_token_bracket(token, regexp, syntax); |
| + if ((token->type == END_OF_RE)) { |
| + *err = REG_BADPAT; |
| + goto parse_bracket_exp_free_return; |
| + } |
| + } |
| + |
| + /* We treat the first ']' as a normal character. */ |
| + if (token->type == OP_CLOSE_BRACKET) |
| + token->type = CHARACTER; |
| + |
| + while (1) { |
| + bracket_elem_t start_elem, end_elem; |
| + unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; |
| + unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; |
| + reg_errcode_t ret; |
| + int token_len2 = 0; |
| + bool is_range_exp = false; |
| + re_token_t token2; |
| + |
| + start_elem.opr.name = start_name_buf; |
| + start_elem.type = COLL_SYM; |
| + ret = parse_bracket_element(&start_elem, regexp, token, token_len, dfa, |
| + syntax, first_round); |
| + if ((ret != REG_NOERROR)) { |
| + *err = ret; |
| + goto parse_bracket_exp_free_return; |
| + } |
| + first_round = false; |
| + |
| + /* Get information about the next token. We need it in any case. */ |
| + token_len = peek_token_bracket(token, regexp, syntax); |
| + |
| + /* Do not check for ranges if we know they are not allowed. */ |
| + if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS) { |
| + if ((token->type == END_OF_RE)) { |
| + *err = REG_EBRACK; |
| + goto parse_bracket_exp_free_return; |
| + } |
| + if (token->type == OP_CHARSET_RANGE) { |
| + re_string_skip_bytes(regexp, token_len); /* Skip '-'. */ |
| + token_len2 = peek_token_bracket(&token2, regexp, syntax); |
| + if ((token2.type == END_OF_RE)) { |
| + *err = REG_EBRACK; |
| + goto parse_bracket_exp_free_return; |
| + } |
| + if (token2.type == OP_CLOSE_BRACKET) { |
| + /* We treat the last '-' as a normal character. */ |
| + re_string_skip_bytes(regexp, -token_len); |
| + token->type = CHARACTER; |
| + } else |
| + is_range_exp = true; |
| + } |
| + } |
| + |
| + if (is_range_exp == true) { |
| + end_elem.opr.name = end_name_buf; |
| + end_elem.type = COLL_SYM; |
| + ret = parse_bracket_element(&end_elem, regexp, &token2, token_len2, |
| + dfa, syntax, true); |
| + if ((ret != REG_NOERROR)) { |
| + *err = ret; |
| + goto parse_bracket_exp_free_return; |
| + } |
| + |
| + token_len = peek_token_bracket(token, regexp, syntax); |
| + |
| + *err = build_range_exp(syntax, sbcset, &start_elem, &end_elem); |
| + |
| + if ((*err != REG_NOERROR)) |
| + goto parse_bracket_exp_free_return; |
| + } else { |
| + switch (start_elem.type) { |
| + case SB_CHAR: |
| + bitset_set(sbcset, start_elem.opr.ch); |
| + break; |
| + case EQUIV_CLASS: |
| + *err = build_equiv_class(sbcset, |
| + start_elem.opr.name); |
| + if ((*err != REG_NOERROR)) |
| + goto parse_bracket_exp_free_return; |
| + break; |
| + case COLL_SYM: |
| + *err = build_collating_symbol(sbcset, |
| + start_elem.opr.name); |
| + if ((*err != REG_NOERROR)) |
| + goto parse_bracket_exp_free_return; |
| + break; |
| + case CHAR_CLASS: |
| + *err = build_charclass(regexp->trans, sbcset, |
| + (const char *) start_elem.opr.name, |
| + syntax); |
| + if ((*err != REG_NOERROR)) |
| + goto parse_bracket_exp_free_return; |
| + break; |
| + default: |
| + assert(0); |
| + break; |
| + } |
| + } |
| + if ((token->type == END_OF_RE)) { |
| + *err = REG_EBRACK; |
| + goto parse_bracket_exp_free_return; |
| + } |
| + if (token->type == OP_CLOSE_BRACKET) |
| + break; |
| + } |
| + |
| + re_string_skip_bytes(regexp, token_len); /* Skip a token. */ |
| + |
| + /* If it is non-matching list. */ |
| + if (non_match) |
| + bitset_not(sbcset); |
| + |
| + { |
| + /* Build a tree for simple bracket. */ |
| + br_token.type = SIMPLE_BRACKET; |
| + br_token.opr.sbcset = sbcset; |
| + work_tree = create_token_tree(dfa, NULL, NULL, &br_token); |
| + if ((work_tree == NULL)) |
| + goto parse_bracket_exp_espace; |
| + } |
| + return work_tree; |
| + |
| + parse_bracket_exp_espace: |
| + *err = REG_ESPACE; |
| + parse_bracket_exp_free_return: |
| + re_free(sbcset); |
| + return NULL; |
| +} |
| + |
| +/* Parse an element in the bracket expression. */ |
| + |
| +static reg_errcode_t |
| +parse_bracket_element(bracket_elem_t *elem, re_string_t *regexp, |
| + re_token_t *token, int token_len, re_dfa_t *dfa, |
| + reg_syntax_t syntax, bool accept_hyphen) { |
| + re_string_skip_bytes(regexp, token_len); /* Skip a token. */ |
| + if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS |
| + || token->type == OP_OPEN_EQUIV_CLASS) |
| + return parse_bracket_symbol(elem, regexp, token); |
| + if ((token->type == OP_CHARSET_RANGE) && !accept_hyphen) { |
| + /* A '-' must only appear as anything but a range indicator before |
| + the closing bracket. Everything else is an error. */ |
| + re_token_t token2; |
| + (void) peek_token_bracket(&token2, regexp, syntax); |
| + if (token2.type != OP_CLOSE_BRACKET) |
| + /* The actual error value is not standardized since this whole |
| + case is undefined. But ERANGE makes good sense. */ |
| + return REG_ERANGE; |
| + } |
| + elem->type = SB_CHAR; |
| + elem->opr.ch = token->opr.c; |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Parse a bracket symbol in the bracket expression. Bracket symbols are |
| + such as [:<character_class>:], [.<collating_element>.], and |
| + [=<equivalent_class>=]. */ |
| + |
| +static reg_errcode_t |
| +parse_bracket_symbol(bracket_elem_t *elem, re_string_t *regexp, |
| + re_token_t *token) { |
| + unsigned char ch, delim = token->opr.c; |
| + int i = 0; |
| + if (re_string_eoi(regexp)) |
| + return REG_EBRACK; |
| + for (;; ++i) { |
| + if (i >= BRACKET_NAME_BUF_SIZE) |
| + return REG_EBRACK; |
| + if (token->type == OP_OPEN_CHAR_CLASS) |
| + ch = re_string_fetch_byte_case(regexp); |
| + else |
| + ch = re_string_fetch_byte(regexp); |
| + if (re_string_eoi(regexp)) |
| + return REG_EBRACK; |
| + if (ch == delim && re_string_peek_byte(regexp, 0) == ']') |
| + break; |
| + elem->opr.name[i] = ch; |
| + } |
| + re_string_skip_bytes(regexp, 1); |
| + elem->opr.name[i] = '\0'; |
| + switch (token->type) { |
| + case OP_OPEN_COLL_ELEM: |
| + elem->type = COLL_SYM; |
| + break; |
| + case OP_OPEN_EQUIV_CLASS: |
| + elem->type = EQUIV_CLASS; |
| + break; |
| + case OP_OPEN_CHAR_CLASS: |
| + elem->type = CHAR_CLASS; |
| + break; |
| + default: |
| + break; |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Helper function for parse_bracket_exp. |
| + Build the equivalence class which is represented by NAME. |
| + The result are written to MBCSET and SBCSET. |
| + EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes, |
| + is a pointer argument since we may update it. */ |
| + |
| +static reg_errcode_t |
| +build_equiv_class(bitset_t sbcset, const unsigned char *name) { |
| + { |
| + if ((strlen((const char *) name) != 1)) |
| + return REG_ECOLLATE; |
| + bitset_set(sbcset, *name); |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Helper function for parse_bracket_exp. |
| + Build the character class which is represented by NAME. |
| + The result are written to MBCSET and SBCSET. |
| + CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes, |
| + is a pointer argument since we may update it. */ |
| + |
| +static reg_errcode_t |
| +build_charclass(RE_TRANSLATE_TYPE trans, bitset_t sbcset, |
| + const char *class_name, reg_syntax_t syntax) { |
| + int i; |
| + const char *name = class_name; |
| + |
| + /* In case of REG_ICASE "upper" and "lower" match the both of |
| + upper and lower cases. */ |
| + if ((syntax & RE_ICASE) |
| + && (strcmp(name, "upper") == 0 || strcmp(name, "lower") == 0)) |
| + name = "alpha"; |
| + |
| +#define BUILD_CHARCLASS_LOOP(ctype_func) \ |
| + do { \ |
| + if ( (trans != NULL)) \ |
| + { \ |
| + for (i = 0; i < SBC_MAX; ++i) \ |
| + if (ctype_func (i)) \ |
| + bitset_set (sbcset, trans[i]); \ |
| + } \ |
| + else \ |
| + { \ |
| + for (i = 0; i < SBC_MAX; ++i) \ |
| + if (ctype_func (i)) \ |
| + bitset_set (sbcset, i); \ |
| + } \ |
| + } while (0) |
| + |
| + if (strcmp(name, "alnum") == 0) |
| + BUILD_CHARCLASS_LOOP (isalnum); |
| + else if (strcmp(name, "cntrl") == 0) |
| + BUILD_CHARCLASS_LOOP (iscntrl); |
| + else if (strcmp(name, "lower") == 0) |
| + BUILD_CHARCLASS_LOOP (islower); |
| + else if (strcmp(name, "space") == 0) |
| + BUILD_CHARCLASS_LOOP (isspace); |
| + else if (strcmp(name, "alpha") == 0) |
| + BUILD_CHARCLASS_LOOP (isalpha); |
| + else if (strcmp(name, "digit") == 0) |
| + BUILD_CHARCLASS_LOOP (isdigit); |
| + else if (strcmp(name, "print") == 0) |
| + BUILD_CHARCLASS_LOOP (isprint); |
| + else if (strcmp(name, "upper") == 0) |
| + BUILD_CHARCLASS_LOOP (isupper); |
| + else if (strcmp(name, "blank") == 0) |
| + BUILD_CHARCLASS_LOOP (isblank); |
| + else if (strcmp(name, "graph") == 0) |
| + BUILD_CHARCLASS_LOOP (isgraph); |
| + else if (strcmp(name, "punct") == 0) |
| + BUILD_CHARCLASS_LOOP (ispunct); |
| + else if (strcmp(name, "xdigit") == 0) |
| + BUILD_CHARCLASS_LOOP (isxdigit); |
| + else |
| + return REG_ECTYPE; |
| + |
| + return REG_NOERROR; |
| +} |
| + |
| +static bin_tree_t * |
| +build_charclass_op(re_dfa_t *dfa, RE_TRANSLATE_TYPE trans, |
| + const char *class_name, |
| + const char *extra, bool non_match, |
| + reg_errcode_t *err) { |
| + re_bitset_ptr_t sbcset; |
| + reg_errcode_t ret; |
| + re_token_t br_token; |
| + bin_tree_t *tree; |
| + |
| + sbcset = (re_bitset_ptr_t) calloc(sizeof(bitset_t), 1); |
| + if ((sbcset == NULL)) { |
| + *err = REG_ESPACE; |
| + return NULL; |
| + } |
| + |
| + /* We don't care the syntax in this case. */ |
| + ret = build_charclass(trans, sbcset, |
| + class_name, 0); |
| + |
| + if ((ret != REG_NOERROR)) { |
| + re_free(sbcset); |
| + *err = ret; |
| + return NULL; |
| + } |
| + /* \w match '_' also. */ |
| + for (; *extra; extra++) |
| + bitset_set(sbcset, *extra); |
| + |
| + /* If it is non-matching list. */ |
| + if (non_match) |
| + bitset_not(sbcset); |
| + |
| + /* Build a tree for simple bracket. */ |
| + br_token.type = SIMPLE_BRACKET; |
| + br_token.opr.sbcset = sbcset; |
| + tree = create_token_tree(dfa, NULL, NULL, &br_token); |
| + if ((tree == NULL)) |
| + goto build_word_op_espace; |
| + |
| + return tree; |
| + |
| + build_word_op_espace: |
| + re_free(sbcset); |
| + *err = REG_ESPACE; |
| + return NULL; |
| +} |
| + |
| +/* This is intended for the expressions like "a{1,3}". |
| + Fetch a number from 'input', and return the number. |
| + Return -1 if the number field is empty like "{,1}". |
| + Return RE_DUP_MAX + 1 if the number field is too large. |
| + Return -2 if an error occurred. */ |
| + |
| +static Idx |
| +fetch_number(re_string_t *input, re_token_t *token, reg_syntax_t syntax) { |
| + Idx num = -1; |
| + unsigned char c; |
| + while (1) { |
| + fetch_token(token, input, syntax); |
| + c = token->opr.c; |
| + if ((token->type == END_OF_RE)) |
| + return -2; |
| + if (token->type == OP_CLOSE_DUP_NUM || c == ',') |
| + break; |
| + num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2) |
| + ? -2 |
| + : num == -1 |
| + ? c - '0' |
| + : MIN (RE_DUP_MAX + 1, num * 10 + c - '0')); |
| + } |
| + return num; |
| +} |
| + |
| +/* Functions for binary tree operation. */ |
| + |
| +/* Create a tree node. */ |
| + |
| +static bin_tree_t * |
| +create_tree(re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, |
| + re_token_type_t type) { |
| + re_token_t t; |
| + t.type = type; |
| + return create_token_tree(dfa, left, right, &t); |
| +} |
| + |
| +static bin_tree_t * |
| +create_token_tree(re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, |
| + const re_token_t *token) { |
| + bin_tree_t *tree; |
| + if ((dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE)) { |
| + bin_tree_storage_t *storage = re_malloc(bin_tree_storage_t, 1); |
| + |
| + if (storage == NULL) |
| + return NULL; |
| + storage->next = dfa->str_tree_storage; |
| + dfa->str_tree_storage = storage; |
| + dfa->str_tree_storage_idx = 0; |
| + } |
| + tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++]; |
| + |
| + tree->parent = NULL; |
| + tree->left = left; |
| + tree->right = right; |
| + tree->token = *token; |
| + tree->token.duplicated = 0; |
| + tree->token.opt_subexp = 0; |
| + tree->first = NULL; |
| + tree->next = NULL; |
| + tree->node_idx = -1; |
| + |
| + if (left != NULL) |
| + left->parent = tree; |
| + if (right != NULL) |
| + right->parent = tree; |
| + return tree; |
| +} |
| + |
| +/* Mark the tree SRC as an optional subexpression. |
| + To be called from preorder or postorder. */ |
| + |
| +static reg_errcode_t |
| +mark_opt_subexp(void *extra, bin_tree_t *node) { |
| + Idx idx = (uintptr_t) extra; |
| + if (node->token.type == SUBEXP && node->token.opr.idx == idx) |
| + node->token.opt_subexp = 1; |
| + |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Free the allocated memory inside NODE. */ |
| + |
| +static void |
| +free_token(re_token_t *node) { |
| + if (node->type == SIMPLE_BRACKET && node->duplicated == 0) |
| + re_free(node->opr.sbcset); |
| +} |
| + |
| +/* Worker function for tree walking. Free the allocated memory inside NODE |
| + and its children. */ |
| + |
| +static reg_errcode_t |
| +free_tree(void *extra, bin_tree_t *node) { |
| + free_token(&node->token); |
| + return REG_NOERROR; |
| +} |
| + |
| + |
| +/* Duplicate the node SRC, and return new node. This is a preorder |
| + visit similar to the one implemented by the generic visitor, but |
| + we need more infrastructure to maintain two parallel trees --- so, |
| + it's easier to duplicate. */ |
| + |
| +static bin_tree_t * |
| +duplicate_tree(const bin_tree_t *root, re_dfa_t *dfa) { |
| + const bin_tree_t *node; |
| + bin_tree_t *dup_root; |
| + bin_tree_t **p_new = &dup_root, *dup_node = root->parent; |
| + |
| + for (node = root;;) { |
| + /* Create a new tree and link it back to the current parent. */ |
| + *p_new = create_token_tree(dfa, NULL, NULL, &node->token); |
| + if (*p_new == NULL) |
| + return NULL; |
| + (*p_new)->parent = dup_node; |
| + (*p_new)->token.duplicated = 1; |
| + dup_node = *p_new; |
| + |
| + /* Go to the left node, or up and to the right. */ |
| + if (node->left) { |
| + node = node->left; |
| + p_new = &dup_node->left; |
| + } else { |
| + const bin_tree_t *prev = NULL; |
| + while (node->right == prev || node->right == NULL) { |
| + prev = node; |
| + node = node->parent; |
| + dup_node = dup_node->parent; |
| + if (!node) |
| + return dup_root; |
| + } |
| + node = node->right; |
| + p_new = &dup_node->right; |
| + } |
| + } |
| +} |
| + |
| +static reg_errcode_t |
| +prune_impossible_nodes(re_match_context_t *mctx) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + Idx halt_node, match_last; |
| + reg_errcode_t ret; |
| + re_dfastate_t **sifted_states; |
| + re_dfastate_t **lim_states = NULL; |
| + re_sift_context_t sctx; |
| + match_last = mctx->match_last; |
| + halt_node = mctx->last_node; |
| + |
| +/* Avoid overflow. */ |
| + if ((MIN (IDX_MAX, SIZE_MAX / sizeof(re_dfastate_t * )) |
| + <= match_last)) |
| + return REG_ESPACE; |
| + |
| + sifted_states = re_malloc(re_dfastate_t * , match_last + 1); |
| + if ((sifted_states == NULL)) { |
| + ret = REG_ESPACE; |
| + goto free_return; |
| + } |
| + if (dfa->nbackref) { |
| + lim_states = re_malloc(re_dfastate_t * , match_last + 1); |
| + if ((lim_states == NULL)) { |
| + ret = REG_ESPACE; |
| + goto free_return; |
| + } |
| + while (1) { |
| + memset(lim_states, '\0', |
| + sizeof(re_dfastate_t * ) * (match_last + 1)); |
| + sift_ctx_init(&sctx, sifted_states, lim_states, halt_node, |
| + match_last); |
| + ret = sift_states_backward(mctx, &sctx); |
| + re_node_set_free(&sctx.limits); |
| + if ((ret != REG_NOERROR)) |
| + goto free_return; |
| + if (sifted_states[0] != NULL || lim_states[0] != NULL) |
| + break; |
| + do { |
| + --match_last; |
| + if (match_last < 0) { |
| + ret = REG_NOMATCH; |
| + goto free_return; |
| + } |
| + } while (mctx->state_log[match_last] == NULL |
| + || !mctx->state_log[match_last]->halt); |
| + halt_node = check_halt_state_context(mctx, |
| + mctx->state_log[match_last], |
| + match_last); |
| + } |
| + ret = merge_state_array(dfa, sifted_states, lim_states, |
| + match_last + 1); |
| + re_free(lim_states); |
| + lim_states = NULL; |
| + if ((ret != REG_NOERROR)) |
| + goto free_return; |
| + } else { |
| + sift_ctx_init(&sctx, sifted_states, lim_states, halt_node, match_last); |
| + ret = sift_states_backward(mctx, &sctx); |
| + re_node_set_free(&sctx.limits); |
| + if ((ret != REG_NOERROR)) |
| + goto free_return; |
| + if (sifted_states[0] == NULL) { |
| + ret = REG_NOMATCH; |
| + goto free_return; |
| + } |
| + } |
| + re_free(mctx->state_log); |
| + mctx->state_log = sifted_states; |
| + sifted_states = NULL; |
| + mctx->last_node = halt_node; |
| + mctx->match_last = match_last; |
| + ret = REG_NOERROR; |
| + free_return: |
| + re_free(sifted_states); |
| + re_free(lim_states); |
| + return ret; |
| +} |
| + |
| +/* Acquire an initial state and return it. |
| + We must select appropriate initial state depending on the context, |
| + since initial states may have constraints like "\<", "^", etc.. */ |
| + |
| +static inline re_dfastate_t * |
| +acquire_init_state_context(reg_errcode_t *err, const re_match_context_t *mctx, |
| + Idx idx) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + if (dfa->init_state->has_constraint) { |
| + unsigned int context; |
| + context = re_string_context_at(&mctx->input, idx - 1, mctx->eflags); |
| + if (IS_WORD_CONTEXT(context)) |
| + return dfa->init_state_word; |
| + else if (IS_ORDINARY_CONTEXT(context)) |
| + return dfa->init_state; |
| + else if (IS_BEGBUF_CONTEXT(context) && IS_NEWLINE_CONTEXT(context)) |
| + return dfa->init_state_begbuf; |
| + else if (IS_NEWLINE_CONTEXT(context)) |
| + return dfa->init_state_nl; |
| + else if (IS_BEGBUF_CONTEXT(context)) { |
| + /* It is relatively rare case, then calculate on demand. */ |
| + return re_acquire_state_context(err, dfa, |
| + dfa->init_state->entrance_nodes, |
| + context); |
| + } else |
| + /* Must not happen? */ |
| + return dfa->init_state; |
| + } else |
| + return dfa->init_state; |
| +} |
| + |
| +/* Check whether the node accepts the byte which is IDX-th |
| + byte of the INPUT. */ |
| + |
| +static bool |
| +check_node_accept(const re_match_context_t *mctx, const re_token_t *node, |
| + Idx idx) { |
| + unsigned char ch; |
| + ch = re_string_byte_at(&mctx->input, idx); |
| + switch (node->type) { |
| + case CHARACTER: |
| + if (node->opr.c != ch) |
| + return false; |
| + break; |
| + |
| + case SIMPLE_BRACKET: |
| + if (!bitset_contain(node->opr.sbcset, ch)) |
| + return false; |
| + break; |
| + |
| + case OP_PERIOD: |
| + if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE)) |
| + || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL))) |
| + return false; |
| + break; |
| + |
| + default: |
| + return false; |
| + } |
| + |
| + if (node->constraint) { |
| + /* The node has constraints. Check whether the current context |
| + satisfies the constraints. */ |
| + unsigned int context = re_string_context_at(&mctx->input, idx, |
| + mctx->eflags); |
| + if (NOT_SATISFY_NEXT_CONSTRAINT(node->constraint, context)) |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| + |
| +/* Extend the buffers, if the buffers have run out. */ |
| + |
| +static reg_errcode_t |
| +extend_buffers(re_match_context_t |
| + *mctx, |
| + int min_len |
| +) { |
| + reg_errcode_t ret; |
| + re_string_t *pstr = &mctx->input; |
| + |
| +/* Avoid overflow. */ |
| + if ( |
| + (MIN (IDX_MAX, SIZE_MAX / sizeof(re_dfastate_t * )) / 2 |
| + <= pstr->bufs_len)) |
| + return |
| + REG_ESPACE; |
| + |
| +/* Double the lengths of the buffers, but allocate at least MIN_LEN. */ |
| + ret = re_string_realloc_buffers(pstr, |
| + MAX (min_len, |
| + MIN(pstr->len, pstr->bufs_len * 2))); |
| + if ( |
| + (ret |
| + != REG_NOERROR)) |
| + return |
| + ret; |
| + |
| + if (mctx->state_log != NULL) { |
| +/* And double the length of state_log. */ |
| +/* XXX We have no indication of the size of this buffer. If this |
| +allocation fail we have no indication that the state_log array |
| +does not have the right size. */ |
| + re_dfastate_t **new_array = re_realloc(mctx->state_log, re_dfastate_t * , |
| + pstr->bufs_len + 1); |
| + if ( |
| + (new_array |
| + == NULL)) |
| + return |
| + REG_ESPACE; |
| + mctx-> |
| + state_log = new_array; |
| + } |
| + |
| +/* Then reconstruct the buffers. */ |
| + if (pstr->icase) { |
| + build_upper_buffer(pstr); |
| + } else { |
| + { |
| + if (pstr->trans != NULL) |
| + re_string_translate_buffer(pstr); |
| + } |
| + } |
| + return |
| + REG_NOERROR; |
| +} |
| + |
| +/* Functions for state transition. */ |
| + |
| +/* Helper functions for transit_state. */ |
| + |
| +/* Return the first entry with the same str_idx, or -1 if none is |
| + found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ |
| + |
| +static Idx |
| +search_cur_bkref_entry (const re_match_context_t *mctx, Idx str_idx) |
| +{ |
| + Idx left, right, mid, last; |
| + last = right = mctx->nbkref_ents; |
| + for (left = 0; left < right;) |
| + { |
| + mid = (left + right) / 2; |
| + if (mctx->bkref_ents[mid].str_idx < str_idx) |
| + left = mid + 1; |
| + else |
| + right = mid; |
| + } |
| + if (left < last && mctx->bkref_ents[left].str_idx == str_idx) |
| + return left; |
| + else |
| + return -1; |
| +} |
| + |
| +/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches |
| + at STR_IDX. */ |
| + |
| +static reg_errcode_t |
| +match_ctx_add_subtop(re_match_context_t *mctx, Idx node, Idx str_idx) { |
| + if ((mctx->nsub_tops == mctx->asub_tops)) { |
| + Idx new_asub_tops = mctx->asub_tops * 2; |
| + re_sub_match_top_t **new_array = re_realloc(mctx->sub_tops, |
| + re_sub_match_top_t * , |
| + new_asub_tops); |
| + if ((new_array == NULL)) |
| + return REG_ESPACE; |
| + mctx->sub_tops = new_array; |
| + mctx->asub_tops = new_asub_tops; |
| + } |
| + mctx->sub_tops[mctx->nsub_tops] = calloc(1, sizeof(re_sub_match_top_t)); |
| + if ((mctx->sub_tops[mctx->nsub_tops] == NULL)) |
| + return REG_ESPACE; |
| + mctx->sub_tops[mctx->nsub_tops]->node = node; |
| + mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx; |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches |
| + at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ |
| + |
| +static re_sub_match_last_t * |
| +match_ctx_add_sublast (re_sub_match_top_t *subtop, Idx node, Idx str_idx) |
| +{ |
| + re_sub_match_last_t *new_entry; |
| + if ( (subtop->nlasts == subtop->alasts)) |
| + { |
| + Idx new_alasts = 2 * subtop->alasts + 1; |
| + re_sub_match_last_t **new_array = re_realloc (subtop->lasts, |
| + re_sub_match_last_t *, |
| + new_alasts); |
| + if ( (new_array == NULL)) |
| + return NULL; |
| + subtop->lasts = new_array; |
| + subtop->alasts = new_alasts; |
| + } |
| + new_entry = calloc (1, sizeof (re_sub_match_last_t)); |
| + if ( (new_entry != NULL)) |
| + { |
| + subtop->lasts[subtop->nlasts] = new_entry; |
| + new_entry->node = node; |
| + new_entry->str_idx = str_idx; |
| + ++subtop->nlasts; |
| + } |
| + return new_entry; |
| +} |
| + |
| + |
| +/* From the node set CUR_NODES, pick up the nodes whose types are |
| + OP_OPEN_SUBEXP and which have corresponding back references in the regular |
| + expression. And register them to use them later for evaluating the |
| + corresponding back references. */ |
| + |
| +static reg_errcode_t |
| +check_subexp_matching_top(re_match_context_t *mctx, re_node_set *cur_nodes, |
| + Idx str_idx) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + Idx node_idx; |
| + reg_errcode_t err; |
| + |
| + /* TODO: This isn't efficient. |
| + Because there might be more than one nodes whose types are |
| + OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all |
| + nodes. |
| + E.g. RE: (a){2} */ |
| + for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx) { |
| + Idx node = cur_nodes->elems[node_idx]; |
| + if (dfa->nodes[node].type == OP_OPEN_SUBEXP |
| + && dfa->nodes[node].opr.idx < BITSET_WORD_BITS |
| + && (dfa->used_bkref_map |
| + & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx))) { |
| + err = match_ctx_add_subtop(mctx, node, str_idx); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + } |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA |
| + corresponding to the DFA). |
| + Return the destination node, and update EPS_VIA_NODES; |
| + return -1 in case of errors. */ |
| + |
| +static Idx |
| +proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs, |
| + Idx *pidx, Idx node, re_node_set *eps_via_nodes, |
| + struct re_fail_stack_t *fs) |
| +{ |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + Idx i; |
| + bool ok; |
| + if (IS_EPSILON_NODE (dfa->nodes[node].type)) |
| + { |
| + re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; |
| + re_node_set *edests = &dfa->edests[node]; |
| + Idx dest_node; |
| + ok = re_node_set_insert (eps_via_nodes, node); |
| + if ( (! ok)) |
| + return -2; |
| + /* Pick up a valid destination, or return -1 if none |
| + is found. */ |
| + for (dest_node = -1, i = 0; i < edests->nelem; ++i) |
| + { |
| + Idx candidate = edests->elems[i]; |
| + if (!re_node_set_contains (cur_nodes, candidate)) |
| + continue; |
| + if (dest_node == -1) |
| + dest_node = candidate; |
| + |
| + else |
| + { |
| + /* In order to avoid infinite loop like "(a*)*", return the second |
| + epsilon-transition if the first was already considered. */ |
| + if (re_node_set_contains (eps_via_nodes, dest_node)) |
| + return candidate; |
| + |
| + /* Otherwise, push the second epsilon-transition on the fail stack. */ |
| + else if (fs != NULL |
| + && push_fail_stack (fs, *pidx, candidate, nregs, regs, |
| + eps_via_nodes)) |
| + return -2; |
| + |
| + /* We know we are going to exit. */ |
| + break; |
| + } |
| + } |
| + return dest_node; |
| + } |
| + else |
| + { |
| + Idx naccepted = 0; |
| + re_token_type_t type = dfa->nodes[node].type; |
| + |
| + if (type == OP_BACK_REF) |
| + { |
| + Idx subexp_idx = dfa->nodes[node].opr.idx + 1; |
| + naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; |
| + if (fs != NULL) |
| + { |
| + if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) |
| + return -1; |
| + else if (naccepted) |
| + { |
| + char *buf = (char *) re_string_get_buffer (&mctx->input); |
| + if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, |
| + naccepted) != 0) |
| + return -1; |
| + } |
| + } |
| + |
| + if (naccepted == 0) |
| + { |
| + Idx dest_node; |
| + ok = re_node_set_insert (eps_via_nodes, node); |
| + if ( (! ok)) |
| + return -2; |
| + dest_node = dfa->edests[node].elems[0]; |
| + if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, |
| + dest_node)) |
| + return dest_node; |
| + } |
| + } |
| + |
| + if (naccepted != 0 |
| + || check_node_accept (mctx, dfa->nodes + node, *pidx)) |
| + { |
| + Idx dest_node = dfa->nexts[node]; |
| + *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; |
| + if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL |
| + || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, |
| + dest_node))) |
| + return -1; |
| + re_node_set_empty (eps_via_nodes); |
| + return dest_node; |
| + } |
| + } |
| + return -1; |
| +} |
| + |
| +static reg_errcode_t |
| + |
| +push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, |
| + Idx nregs, regmatch_t *regs, re_node_set *eps_via_nodes) |
| +{ |
| + reg_errcode_t err; |
| + Idx num = fs->num++; |
| + if (fs->num == fs->alloc) |
| + { |
| + struct re_fail_stack_ent_t *new_array; |
| + new_array = re_realloc (fs->stack, struct re_fail_stack_ent_t, |
| + fs->alloc * 2); |
| + if (new_array == NULL) |
| + return REG_ESPACE; |
| + fs->alloc *= 2; |
| + fs->stack = new_array; |
| + } |
| + fs->stack[num].idx = str_idx; |
| + fs->stack[num].node = dest_node; |
| + fs->stack[num].regs = re_malloc (regmatch_t, nregs); |
| + if (fs->stack[num].regs == NULL) |
| + return REG_ESPACE; |
| + memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); |
| + err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); |
| + return err; |
| +} |
| + |
| +static Idx |
| +pop_fail_stack (struct re_fail_stack_t *fs, Idx *pidx, Idx nregs, |
| + regmatch_t *regs, re_node_set *eps_via_nodes) |
| +{ |
| + Idx num = --fs->num; |
| + assert (num >= 0); |
| + *pidx = fs->stack[num].idx; |
| + memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); |
| + re_node_set_free (eps_via_nodes); |
| + re_free (fs->stack[num].regs); |
| + *eps_via_nodes = fs->stack[num].eps_via_nodes; |
| + return fs->stack[num].node; |
| +} |
| + |
| +/* Set the positions where the subexpressions are starts/ends to registers |
| + PMATCH. |
| + Note: We assume that pmatch[0] is already set, and |
| + pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */ |
| + |
| +static reg_errcode_t |
| + |
| +set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, |
| + regmatch_t *pmatch, bool fl_backtrack) |
| +{ |
| + const re_dfa_t *dfa = preg->buffer; |
| + Idx idx, cur_node; |
| + re_node_set eps_via_nodes; |
| + struct re_fail_stack_t *fs; |
| + struct re_fail_stack_t fs_body = { 0, 2, NULL }; |
| + regmatch_t *prev_idx_match; |
| + bool prev_idx_match_malloced = false; |
| + if (fl_backtrack) |
| + { |
| + fs = &fs_body; |
| + fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); |
| + if (fs->stack == NULL) |
| + return REG_ESPACE; |
| + } |
| + else |
| + fs = NULL; |
| + |
| + cur_node = dfa->init_node; |
| + re_node_set_init_empty (&eps_via_nodes); |
| + |
| + if (__libc_use_alloca (nmatch * sizeof (regmatch_t))) |
| + prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t)); |
| + else |
| + { |
| + prev_idx_match = re_malloc (regmatch_t, nmatch); |
| + if (prev_idx_match == NULL) |
| + { |
| + free_fail_stack_return (fs); |
| + return REG_ESPACE; |
| + } |
| + prev_idx_match_malloced = true; |
| + } |
| + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); |
| + |
| + for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) |
| + { |
| + update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch); |
| + |
| + if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) |
| + { |
| + Idx reg_idx; |
| + if (fs) |
| + { |
| + for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) |
| + if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) |
| + break; |
| + if (reg_idx == nmatch) |
| + { |
| + re_node_set_free (&eps_via_nodes); |
| + if (prev_idx_match_malloced) |
| + re_free (prev_idx_match); |
| + return free_fail_stack_return (fs); |
| + } |
| + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, |
| + &eps_via_nodes); |
| + } |
| + else |
| + { |
| + re_node_set_free (&eps_via_nodes); |
| + if (prev_idx_match_malloced) |
| + re_free (prev_idx_match); |
| + return REG_NOERROR; |
| + } |
| + } |
| + |
| + /* Proceed to next node. */ |
| + cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node, |
| + &eps_via_nodes, fs); |
| + |
| + if ( (cur_node < 0)) |
| + { |
| + if ( (cur_node == -2)) |
| + { |
| + re_node_set_free (&eps_via_nodes); |
| + if (prev_idx_match_malloced) |
| + re_free (prev_idx_match); |
| + free_fail_stack_return (fs); |
| + return REG_ESPACE; |
| + } |
| + if (fs) |
| + cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, |
| + &eps_via_nodes); |
| + else |
| + { |
| + re_node_set_free (&eps_via_nodes); |
| + if (prev_idx_match_malloced) |
| + re_free (prev_idx_match); |
| + return REG_NOMATCH; |
| + } |
| + } |
| + } |
| + re_node_set_free (&eps_via_nodes); |
| + if (prev_idx_match_malloced) |
| + re_free (prev_idx_match); |
| + return free_fail_stack_return (fs); |
| +} |
| + |
| +static reg_errcode_t |
| +free_fail_stack_return (struct re_fail_stack_t *fs) |
| +{ |
| + if (fs) |
| + { |
| + Idx fs_idx; |
| + for (fs_idx = 0; fs_idx < fs->num; ++fs_idx) |
| + { |
| + re_node_set_free (&fs->stack[fs_idx].eps_via_nodes); |
| + re_free (fs->stack[fs_idx].regs); |
| + } |
| + re_free (fs->stack); |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +static void |
| +update_regs (const re_dfa_t *dfa, regmatch_t *pmatch, |
| + regmatch_t *prev_idx_match, Idx cur_node, Idx cur_idx, Idx nmatch) |
| +{ |
| + int type = dfa->nodes[cur_node].type; |
| + if (type == OP_OPEN_SUBEXP) |
| + { |
| + Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; |
| + |
| + /* We are at the first node of this sub expression. */ |
| + if (reg_num < nmatch) |
| + { |
| + pmatch[reg_num].rm_so = cur_idx; |
| + pmatch[reg_num].rm_eo = -1; |
| + } |
| + } |
| + else if (type == OP_CLOSE_SUBEXP) |
| + { |
| + Idx reg_num = dfa->nodes[cur_node].opr.idx + 1; |
| + if (reg_num < nmatch) |
| + { |
| + /* We are at the last node of this sub expression. */ |
| + if (pmatch[reg_num].rm_so < cur_idx) |
| + { |
| + pmatch[reg_num].rm_eo = cur_idx; |
| + /* This is a non-empty match or we are not inside an optional |
| + subexpression. Accept this right away. */ |
| + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); |
| + } |
| + else |
| + { |
| + if (dfa->nodes[cur_node].opt_subexp |
| + && prev_idx_match[reg_num].rm_so != -1) |
| + /* We transited through an empty match for an optional |
| + subexpression, like (a?)*, and this is not the subexp's |
| + first match. Copy back the old content of the registers |
| + so that matches of an inner subexpression are undone as |
| + well, like in ((a?))*. */ |
| + memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch); |
| + else |
| + /* We completed a subexpression, but it may be part of |
| + an optional one, so do not update PREV_IDX_MATCH. */ |
| + pmatch[reg_num].rm_eo = cur_idx; |
| + } |
| + } |
| + } |
| +} |
| + |
| +/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 |
| + and sift the nodes in each states according to the following rules. |
| + Updated state_log will be wrote to STATE_LOG. |
| + |
| + Rules: We throw away the Node 'a' in the STATE_LOG[STR_IDX] if... |
| + 1. When STR_IDX == MATCH_LAST(the last index in the state_log): |
| + If 'a' isn't the LAST_NODE and 'a' can't epsilon transit to |
| + the LAST_NODE, we throw away the node 'a'. |
| + 2. When 0 <= STR_IDX < MATCH_LAST and 'a' accepts |
| + string 's' and transit to 'b': |
| + i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw |
| + away the node 'a'. |
| + ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is |
| + thrown away, we throw away the node 'a'. |
| + 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b': |
| + i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the |
| + node 'a'. |
| + ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away, |
| + we throw away the node 'a'. */ |
| + |
| +#define STATE_NODE_CONTAINS(state,node) \ |
| + ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) |
| + |
| +static reg_errcode_t |
| +sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx) |
| +{ |
| + reg_errcode_t err; |
| + int null_cnt = 0; |
| + Idx str_idx = sctx->last_str_idx; |
| + re_node_set cur_dest; |
| + |
| + /* Build sifted state_log[str_idx]. It has the nodes which can epsilon |
| + transit to the last_node and the last_node itself. */ |
| + err = re_node_set_init_1 (&cur_dest, sctx->last_node); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); |
| + if ( (err != REG_NOERROR)) |
| + goto free_return; |
| + |
| + /* Then check each states in the state_log. */ |
| + while (str_idx > 0) |
| + { |
| + /* Update counters. */ |
| + null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; |
| + if (null_cnt > mctx->max_mb_elem_len) |
| + { |
| + memset (sctx->sifted_states, '\0', |
| + sizeof (re_dfastate_t *) * str_idx); |
| + re_node_set_free (&cur_dest); |
| + return REG_NOERROR; |
| + } |
| + re_node_set_empty (&cur_dest); |
| + --str_idx; |
| + |
| + if (mctx->state_log[str_idx]) |
| + { |
| + err = build_sifted_states (mctx, sctx, str_idx, &cur_dest); |
| + if ( (err != REG_NOERROR)) |
| + goto free_return; |
| + } |
| + |
| + /* Add all the nodes which satisfy the following conditions: |
| + - It can epsilon transit to a node in CUR_DEST. |
| + - It is in CUR_SRC. |
| + And update state_log. */ |
| + err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest); |
| + if ( (err != REG_NOERROR)) |
| + goto free_return; |
| + } |
| + err = REG_NOERROR; |
| + free_return: |
| + re_node_set_free (&cur_dest); |
| + return err; |
| +} |
| + |
| +static reg_errcode_t |
| +build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx, |
| + Idx str_idx, re_node_set *cur_dest) |
| +{ |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes; |
| + Idx i; |
| + |
| + /* Then build the next sifted state. |
| + We build the next sifted state on 'cur_dest', and update |
| + 'sifted_states[str_idx]' with 'cur_dest'. |
| + Note: |
| + 'cur_dest' is the sifted state from 'state_log[str_idx + 1]'. |
| + 'cur_src' points the node_set of the old 'state_log[str_idx]' |
| + (with the epsilon nodes pre-filtered out). */ |
| + for (i = 0; i < cur_src->nelem; i++) |
| + { |
| + Idx prev_node = cur_src->elems[i]; |
| + int naccepted = 0; |
| + bool ok; |
| + |
| + /* We don't check backreferences here. |
| + See update_cur_sifted_state(). */ |
| + if (!naccepted |
| + && check_node_accept (mctx, dfa->nodes + prev_node, str_idx) |
| + && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], |
| + dfa->nexts[prev_node])) |
| + naccepted = 1; |
| + |
| + if (naccepted == 0) |
| + continue; |
| + |
| + if (sctx->limits.nelem) |
| + { |
| + Idx to_idx = str_idx + naccepted; |
| + if (check_dst_limits (mctx, &sctx->limits, |
| + dfa->nexts[prev_node], to_idx, |
| + prev_node, str_idx)) |
| + continue; |
| + } |
| + ok = re_node_set_insert (cur_dest, prev_node); |
| + if ( (! ok)) |
| + return REG_ESPACE; |
| + } |
| + |
| + return REG_NOERROR; |
| +} |
| + |
| +static reg_errcode_t |
| +clean_state_log_if_needed (re_match_context_t *mctx, Idx next_state_log_idx) |
| +{ |
| + Idx top = mctx->state_log_top; |
| + |
| + if ((next_state_log_idx >= mctx->input.bufs_len |
| + && mctx->input.bufs_len < mctx->input.len) |
| + || (next_state_log_idx >= mctx->input.valid_len |
| + && mctx->input.valid_len < mctx->input.len)) |
| + { |
| + reg_errcode_t err; |
| + err = extend_buffers (mctx, next_state_log_idx + 1); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + } |
| + |
| + if (top < next_state_log_idx) |
| + { |
| + memset (mctx->state_log + top + 1, '\0', |
| + sizeof (re_dfastate_t *) * (next_state_log_idx - top)); |
| + mctx->state_log_top = next_state_log_idx; |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Enumerate all the candidates which the backreference BKREF_NODE can match |
| + at BKREF_STR_IDX, and register them by match_ctx_add_entry(). |
| + Note that we might collect inappropriate candidates here. |
| + However, the cost of checking them strictly here is too high, then we |
| + delay these checking for prune_impossible_nodes(). */ |
| + |
| +static reg_errcode_t |
| + |
| +get_subexp(re_match_context_t *mctx, Idx bkref_node, Idx bkref_str_idx) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + Idx subexp_num, sub_top_idx; |
| + const char *buf = (const char *) re_string_get_buffer(&mctx->input); |
| +/* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ |
| + Idx cache_idx = search_cur_bkref_entry(mctx, bkref_str_idx); |
| + if (cache_idx != -1) { |
| + const struct re_backref_cache_entry *entry |
| + = mctx->bkref_ents + cache_idx; |
| + do |
| + if (entry->node == bkref_node) |
| + return REG_NOERROR; /* We already checked it. */ |
| + while (entry++->more); |
| + } |
| + |
| + subexp_num = dfa->nodes[bkref_node].opr.idx; |
| + |
| +/* For each sub expression */ |
| + for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) { |
| + reg_errcode_t err; |
| + re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx]; |
| + re_sub_match_last_t *sub_last; |
| + Idx sub_last_idx, sl_str, bkref_str_off; |
| + |
| + if (dfa->nodes[sub_top->node].opr.idx != subexp_num) |
| + continue; /* It isn't related. */ |
| + |
| + sl_str = sub_top->str_idx; |
| + bkref_str_off = bkref_str_idx; |
| +/* At first, check the last node of sub expressions we already |
| +evaluated. */ |
| + for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx) { |
| + regoff_t sl_str_diff; |
| + sub_last = sub_top->lasts[sub_last_idx]; |
| + sl_str_diff = sub_last->str_idx - sl_str; |
| +/* The matched string by the sub expression match with the substring |
| + at the back reference? */ |
| + if (sl_str_diff > 0) { |
| + if ((bkref_str_off + sl_str_diff |
| + > mctx->input.valid_len)) { |
| +/* Not enough chars for a successful match. */ |
| + if (bkref_str_off + sl_str_diff > mctx->input.len) |
| + break; |
| + |
| + err = clean_state_log_if_needed(mctx, |
| + bkref_str_off |
| + + sl_str_diff); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + buf = (const char *) re_string_get_buffer(&mctx->input); |
| + } |
| + if (memcmp(buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0) |
| +/* We don't need to search this sub expression any more. */ |
| + break; |
| + } |
| + bkref_str_off += sl_str_diff; |
| + sl_str += sl_str_diff; |
| + err = get_subexp_sub(mctx, sub_top, sub_last, bkref_node, |
| + bkref_str_idx); |
| + |
| +/* Reload buf, since the preceding call might have reallocated |
| + the buffer. */ |
| + buf = (const char *) re_string_get_buffer(&mctx->input); |
| + |
| + if (err == REG_NOMATCH) |
| + continue; |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + } |
| + |
| + if (sub_last_idx < sub_top->nlasts) |
| + continue; |
| + if (sub_last_idx > 0) |
| + ++sl_str; |
| +/* Then, search for the other last nodes of the sub expression. */ |
| + for (; sl_str <= bkref_str_idx; ++sl_str) { |
| + Idx cls_node; |
| + regoff_t sl_str_off; |
| + const re_node_set *nodes; |
| + sl_str_off = sl_str - sub_top->str_idx; |
| +/* The matched string by the sub expression match with the substring |
| + at the back reference? */ |
| + if (sl_str_off > 0) { |
| + if ((bkref_str_off >= mctx->input.valid_len)) { |
| +/* If we are at the end of the input, we cannot match. */ |
| + if (bkref_str_off >= mctx->input.len) |
| + break; |
| + |
| + err = extend_buffers(mctx, bkref_str_off + 1); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + |
| + buf = (const char *) re_string_get_buffer(&mctx->input); |
| + } |
| + if (buf[bkref_str_off++] != buf[sl_str - 1]) |
| + break; /* We don't need to search this sub expression |
| + any more. */ |
| + } |
| + if (mctx->state_log[sl_str] == NULL) |
| + continue; |
| +/* Does this state have a ')' of the sub expression? */ |
| + nodes = &mctx->state_log[sl_str]->nodes; |
| + cls_node = find_subexp_node(dfa, nodes, subexp_num, |
| + OP_CLOSE_SUBEXP); |
| + if (cls_node == -1) |
| + continue; /* No. */ |
| + if (sub_top->path == NULL) { |
| + sub_top->path = calloc(sizeof(state_array_t), |
| + sl_str - sub_top->str_idx + 1); |
| + if (sub_top->path == NULL) |
| + return REG_ESPACE; |
| + } |
| +/* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node |
| + in the current context? */ |
| + err = check_arrival(mctx, sub_top->path, sub_top->node, |
| + sub_top->str_idx, cls_node, sl_str, |
| + OP_CLOSE_SUBEXP); |
| + if (err == REG_NOMATCH) |
| + continue; |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + sub_last = match_ctx_add_sublast(sub_top, cls_node, sl_str); |
| + if ((sub_last == NULL)) |
| + return REG_ESPACE; |
| + err = get_subexp_sub(mctx, sub_top, sub_last, bkref_node, |
| + bkref_str_idx); |
| + if (err == REG_NOMATCH) |
| + continue; |
| + } |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Helper functions for get_subexp(). */ |
| + |
| +/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR. |
| + If it can arrive, register the sub expression expressed with SUB_TOP |
| + and SUB_LAST. */ |
| + |
| +static reg_errcode_t |
| +get_subexp_sub(re_match_context_t *mctx, const re_sub_match_top_t *sub_top, |
| + re_sub_match_last_t *sub_last, Idx bkref_node, Idx bkref_str) { |
| + reg_errcode_t err; |
| + Idx to_idx; |
| + /* Can the subexpression arrive the back reference? */ |
| + err = check_arrival(mctx, &sub_last->path, sub_last->node, |
| + sub_last->str_idx, bkref_node, bkref_str, |
| + OP_OPEN_SUBEXP); |
| + if (err != REG_NOERROR) |
| + return err; |
| + err = match_ctx_add_entry(mctx, bkref_node, bkref_str, sub_top->str_idx, |
| + sub_last->str_idx); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx; |
| + return clean_state_log_if_needed(mctx, to_idx); |
| +} |
| + |
| +/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX. |
| + Search '(' if FL_OPEN, or search ')' otherwise. |
| + TODO: This function isn't efficient... |
| + Because there might be more than one nodes whose types are |
| + OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all |
| + nodes. |
| + E.g. RE: (a){2} */ |
| + |
| +static Idx |
| +find_subexp_node(const re_dfa_t *dfa, const re_node_set *nodes, |
| + Idx subexp_idx, int type) { |
| + Idx cls_idx; |
| + for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) { |
| + Idx cls_node = nodes->elems[cls_idx]; |
| + const re_token_t *node = dfa->nodes + cls_node; |
| + if (node->type == type |
| + && node->opr.idx == subexp_idx) |
| + return cls_node; |
| + } |
| + return -1; |
| +} |
| + |
| +/* Check whether the node TOP_NODE at TOP_STR can arrive to the node |
| + LAST_NODE at LAST_STR. We record the path onto PATH since it will be |
| + heavily reused. |
| + Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ |
| + |
| +static reg_errcode_t |
| + |
| +check_arrival(re_match_context_t *mctx, state_array_t *path, Idx top_node, |
| + Idx top_str, Idx last_node, Idx last_str, int type) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + reg_errcode_t err = REG_NOERROR; |
| + Idx subexp_num, backup_cur_idx, str_idx, null_cnt; |
| + re_dfastate_t *cur_state = NULL; |
| + re_node_set *cur_nodes, next_nodes; |
| + re_dfastate_t **backup_state_log; |
| + unsigned int context; |
| + |
| + subexp_num = dfa->nodes[top_node].opr.idx; |
| +/* Extend the buffer if we need. */ |
| + if ((path->alloc < last_str + mctx->max_mb_elem_len + 1)) { |
| + re_dfastate_t **new_array; |
| + Idx old_alloc = path->alloc; |
| + Idx incr_alloc = last_str + mctx->max_mb_elem_len + 1; |
| + Idx new_alloc; |
| + if ((IDX_MAX - old_alloc < incr_alloc)) |
| + return REG_ESPACE; |
| + new_alloc = old_alloc + incr_alloc; |
| + if ((SIZE_MAX / sizeof(re_dfastate_t * ) < new_alloc)) |
| + return REG_ESPACE; |
| + new_array = re_realloc(path->array, re_dfastate_t * , new_alloc); |
| + if ((new_array == NULL)) |
| + return REG_ESPACE; |
| + path->array = new_array; |
| + path->alloc = new_alloc; |
| + memset(new_array + old_alloc, '\0', |
| + sizeof(re_dfastate_t * ) * (path->alloc - old_alloc)); |
| + } |
| + |
| + str_idx = path->next_idx ? path->next_idx : top_str; |
| + |
| +/* Temporary modify MCTX. */ |
| + backup_state_log = mctx->state_log; |
| + backup_cur_idx = mctx->input.cur_idx; |
| + mctx->state_log = path->array; |
| + mctx->input.cur_idx = str_idx; |
| + |
| +/* Setup initial node set. */ |
| + context = re_string_context_at(&mctx->input, str_idx - 1, mctx->eflags); |
| + if (str_idx == top_str) { |
| + err = re_node_set_init_1(&next_nodes, top_node); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + err = check_arrival_expand_ecl(dfa, &next_nodes, subexp_num, type); |
| + if ((err != REG_NOERROR)) { |
| + re_node_set_free(&next_nodes); |
| + return err; |
| + } |
| + } else { |
| + cur_state = mctx->state_log[str_idx]; |
| + if (cur_state && cur_state->has_backref) { |
| + err = re_node_set_init_copy(&next_nodes, &cur_state->nodes); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + } else |
| + re_node_set_init_empty(&next_nodes); |
| + } |
| + if (str_idx == top_str || (cur_state && cur_state->has_backref)) { |
| + if (next_nodes.nelem) { |
| + err = expand_bkref_cache(mctx, &next_nodes, str_idx, |
| + subexp_num, type); |
| + if ((err != REG_NOERROR)) { |
| + re_node_set_free(&next_nodes); |
| + return err; |
| + } |
| + } |
| + cur_state = re_acquire_state_context(&err, dfa, &next_nodes, context); |
| + if ((cur_state == NULL && err != REG_NOERROR)) { |
| + re_node_set_free(&next_nodes); |
| + return err; |
| + } |
| + mctx->state_log[str_idx] = cur_state; |
| + } |
| + |
| + for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;) { |
| + re_node_set_empty(&next_nodes); |
| + if (mctx->state_log[str_idx + 1]) { |
| + err = re_node_set_merge(&next_nodes, |
| + &mctx->state_log[str_idx + 1]->nodes); |
| + if ((err != REG_NOERROR)) { |
| + re_node_set_free(&next_nodes); |
| + return err; |
| + } |
| + } |
| + if (cur_state) { |
| + err = check_arrival_add_next_nodes(mctx, str_idx, |
| + &cur_state->non_eps_nodes, |
| + &next_nodes); |
| + if ((err != REG_NOERROR)) { |
| + re_node_set_free(&next_nodes); |
| + return err; |
| + } |
| + } |
| + ++str_idx; |
| + if (next_nodes.nelem) { |
| + err = check_arrival_expand_ecl(dfa, &next_nodes, subexp_num, type); |
| + if ((err != REG_NOERROR)) { |
| + re_node_set_free(&next_nodes); |
| + return err; |
| + } |
| + err = expand_bkref_cache(mctx, &next_nodes, str_idx, |
| + subexp_num, type); |
| + if ((err != REG_NOERROR)) { |
| + re_node_set_free(&next_nodes); |
| + return err; |
| + } |
| + } |
| + context = re_string_context_at(&mctx->input, str_idx - 1, mctx->eflags); |
| + cur_state = re_acquire_state_context(&err, dfa, &next_nodes, context); |
| + if ((cur_state == NULL && err != REG_NOERROR)) { |
| + re_node_set_free(&next_nodes); |
| + return err; |
| + } |
| + mctx->state_log[str_idx] = cur_state; |
| + null_cnt = cur_state == NULL ? null_cnt + 1 : 0; |
| + } |
| + re_node_set_free(&next_nodes); |
| + cur_nodes = (mctx->state_log[last_str] == NULL ? NULL |
| + : &mctx->state_log[last_str]->nodes); |
| + path->next_idx = str_idx; |
| + |
| +/* Fix MCTX. */ |
| + mctx->state_log = backup_state_log; |
| + mctx->input.cur_idx = backup_cur_idx; |
| + |
| +/* Then check the current node set has the node LAST_NODE. */ |
| + if (cur_nodes != NULL && re_node_set_contains(cur_nodes, last_node)) |
| + return REG_NOERROR; |
| + |
| + return REG_NOMATCH; |
| +} |
| + |
| +/* Helper functions for check_arrival. */ |
| + |
| +/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them |
| + to NEXT_NODES. |
| + TODO: This function is similar to the functions transit_state*(), |
| + however this function has many additional works. |
| + Can't we unify them? */ |
| + |
| +static reg_errcode_t |
| + |
| +check_arrival_add_next_nodes(re_match_context_t *mctx, Idx str_idx, |
| + re_node_set *cur_nodes, re_node_set *next_nodes) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + bool ok; |
| + Idx cur_idx; |
| + re_node_set union_set; |
| + re_node_set_init_empty(&union_set); |
| + for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) { |
| + int naccepted = 0; |
| + Idx cur_node = cur_nodes->elems[cur_idx]; |
| + if (naccepted |
| + || check_node_accept(mctx, dfa->nodes + cur_node, str_idx)) { |
| + ok = re_node_set_insert(next_nodes, dfa->nexts[cur_node]); |
| + if ((!ok)) { |
| + re_node_set_free(&union_set); |
| + return REG_ESPACE; |
| + } |
| + } |
| + } |
| + re_node_set_free(&union_set); |
| + return REG_NOERROR; |
| +} |
| + |
| +/* For all the nodes in CUR_NODES, add the epsilon closures of them to |
| + CUR_NODES, however exclude the nodes which are: |
| + - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN. |
| + - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN. |
| +*/ |
| + |
| +static reg_errcode_t |
| +check_arrival_expand_ecl(const re_dfa_t *dfa, re_node_set *cur_nodes, |
| + Idx ex_subexp, int type) { |
| + reg_errcode_t err; |
| + Idx idx, outside_node; |
| + re_node_set new_nodes; |
| + err = re_node_set_alloc(&new_nodes, cur_nodes->nelem); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + /* Create a new node set NEW_NODES with the nodes which are epsilon |
| + closures of the node in CUR_NODES. */ |
| + |
| + for (idx = 0; idx < cur_nodes->nelem; ++idx) { |
| + Idx cur_node = cur_nodes->elems[idx]; |
| + const re_node_set *eclosure = dfa->eclosures + cur_node; |
| + outside_node = find_subexp_node(dfa, eclosure, ex_subexp, type); |
| + if (outside_node == -1) { |
| + /* There are no problematic nodes, just merge them. */ |
| + err = re_node_set_merge(&new_nodes, eclosure); |
| + if ((err != REG_NOERROR)) { |
| + re_node_set_free(&new_nodes); |
| + return err; |
| + } |
| + } else { |
| + /* There are problematic nodes, re-calculate incrementally. */ |
| + err = check_arrival_expand_ecl_sub(dfa, &new_nodes, cur_node, |
| + ex_subexp, type); |
| + if ((err != REG_NOERROR)) { |
| + re_node_set_free(&new_nodes); |
| + return err; |
| + } |
| + } |
| + } |
| + re_node_set_free(cur_nodes); |
| + *cur_nodes = new_nodes; |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Helper function for check_arrival_expand_ecl. |
| + Check incrementally the epsilon closure of TARGET, and if it isn't |
| + problematic append it to DST_NODES. */ |
| + |
| +static reg_errcode_t |
| + |
| +check_arrival_expand_ecl_sub(const re_dfa_t *dfa, re_node_set *dst_nodes, |
| + Idx target, Idx ex_subexp, int type) { |
| + Idx cur_node; |
| + for (cur_node = target; !re_node_set_contains(dst_nodes, cur_node);) { |
| + bool ok; |
| + |
| + if (dfa->nodes[cur_node].type == type |
| + && dfa->nodes[cur_node].opr.idx == ex_subexp) { |
| + if (type == OP_CLOSE_SUBEXP) { |
| + ok = re_node_set_insert(dst_nodes, cur_node); |
| + if ((!ok)) |
| + return REG_ESPACE; |
| + } |
| + break; |
| + } |
| + ok = re_node_set_insert(dst_nodes, cur_node); |
| + if ((!ok)) |
| + return REG_ESPACE; |
| + if (dfa->edests[cur_node].nelem == 0) |
| + break; |
| + if (dfa->edests[cur_node].nelem == 2) { |
| + reg_errcode_t err; |
| + err = check_arrival_expand_ecl_sub(dfa, dst_nodes, |
| + dfa->edests[cur_node].elems[1], |
| + ex_subexp, type); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + } |
| + cur_node = dfa->edests[cur_node].elems[0]; |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +/* For all the back references in the current state, calculate the |
| + destination of the back references by the appropriate entry |
| + in MCTX->BKREF_ENTS. */ |
| + |
| +static reg_errcode_t |
| +expand_bkref_cache(re_match_context_t *mctx, re_node_set *cur_nodes, |
| + Idx cur_str, Idx subexp_num, int type) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + reg_errcode_t err; |
| + Idx cache_idx_start = search_cur_bkref_entry(mctx, cur_str); |
| + struct re_backref_cache_entry *ent; |
| + |
| + if (cache_idx_start == -1) |
| + return REG_NOERROR; |
| + |
| + restart: |
| + ent = mctx->bkref_ents + cache_idx_start; |
| + do { |
| + Idx to_idx, next_node; |
| + |
| +/* Is this entry ENT is appropriate? */ |
| + if (!re_node_set_contains(cur_nodes, ent->node)) |
| + continue; /* No. */ |
| + |
| + to_idx = cur_str + ent->subexp_to - ent->subexp_from; |
| +/* Calculate the destination of the back reference, and append it |
| +to MCTX->STATE_LOG. */ |
| + if (to_idx == cur_str) { |
| +/* The backreference did epsilon transit, we must re-check all the |
| + node in the current state. */ |
| + re_node_set new_dests; |
| + reg_errcode_t err2, err3; |
| + next_node = dfa->edests[ent->node].elems[0]; |
| + if (re_node_set_contains(cur_nodes, next_node)) |
| + continue; |
| + err = re_node_set_init_1(&new_dests, next_node); |
| + err2 = check_arrival_expand_ecl(dfa, &new_dests, subexp_num, type); |
| + err3 = re_node_set_merge(cur_nodes, &new_dests); |
| + re_node_set_free(&new_dests); |
| + if ((err != REG_NOERROR || err2 != REG_NOERROR |
| + || err3 != REG_NOERROR)) { |
| + err = (err != REG_NOERROR ? err |
| + : (err2 != REG_NOERROR ? err2 : err3)); |
| + return err; |
| + } |
| +/* TODO: It is still inefficient... */ |
| + goto restart; |
| + } else { |
| + re_node_set union_set; |
| + next_node = dfa->nexts[ent->node]; |
| + if (mctx->state_log[to_idx]) { |
| + bool ok; |
| + if (re_node_set_contains(&mctx->state_log[to_idx]->nodes, |
| + next_node)) |
| + continue; |
| + err = re_node_set_init_copy(&union_set, |
| + &mctx->state_log[to_idx]->nodes); |
| + ok = re_node_set_insert(&union_set, next_node); |
| + if ((err != REG_NOERROR || !ok)) { |
| + re_node_set_free(&union_set); |
| + err = err != REG_NOERROR ? err : REG_ESPACE; |
| + return err; |
| + } |
| + } else { |
| + err = re_node_set_init_1(&union_set, next_node); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + } |
| + mctx->state_log[to_idx] = re_acquire_state(&err, dfa, &union_set); |
| + re_node_set_free(&union_set); |
| + if ((mctx->state_log[to_idx] == NULL |
| + && err != REG_NOERROR)) |
| + return err; |
| + } |
| + } while (ent++->more); |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Build transition table for the state. |
| + Return true if successful. */ |
| + |
| +static bool |
| +build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) |
| +{ |
| + reg_errcode_t err; |
| + Idx i, j; |
| + int ch; |
| + bool need_word_trtable = false; |
| + bitset_word_t elem, mask; |
| + bool dests_node_malloced = false; |
| + bool dest_states_malloced = false; |
| + Idx ndests; /* Number of the destination states from 'state'. */ |
| + re_dfastate_t **trtable; |
| + re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; |
| + re_node_set follows, *dests_node; |
| + bitset_t *dests_ch; |
| + bitset_t acceptable; |
| + |
| + struct dests_alloc |
| + { |
| + re_node_set dests_node[SBC_MAX]; |
| + bitset_t dests_ch[SBC_MAX]; |
| + } *dests_alloc; |
| + |
| + /* We build DFA states which corresponds to the destination nodes |
| + from 'state'. 'dests_node[i]' represents the nodes which i-th |
| + destination state contains, and 'dests_ch[i]' represents the |
| + characters which i-th destination state accepts. */ |
| + if (__libc_use_alloca (sizeof (struct dests_alloc))) |
| + dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc)); |
| + else |
| + { |
| + dests_alloc = re_malloc (struct dests_alloc, 1); |
| + if ( (dests_alloc == NULL)) |
| + return false; |
| + dests_node_malloced = true; |
| + } |
| + dests_node = dests_alloc->dests_node; |
| + dests_ch = dests_alloc->dests_ch; |
| + |
| + /* Initialize transition table. */ |
| + state->word_trtable = state->trtable = NULL; |
| + |
| + /* At first, group all nodes belonging to 'state' into several |
| + destinations. */ |
| + ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch); |
| + if ( (ndests <= 0)) |
| + { |
| + if (dests_node_malloced) |
| + re_free (dests_alloc); |
| + /* Return false in case of an error, true otherwise. */ |
| + if (ndests == 0) |
| + { |
| + state->trtable = (re_dfastate_t **) |
| + calloc (sizeof (re_dfastate_t *), SBC_MAX); |
| + if ( (state->trtable == NULL)) |
| + return false; |
| + return true; |
| + } |
| + return false; |
| + } |
| + |
| + err = re_node_set_alloc (&follows, ndests + 1); |
| + if ( (err != REG_NOERROR)) |
| + goto out_free; |
| + |
| + /* Avoid arithmetic overflow in size calculation. */ |
| + size_t ndests_max |
| + = ((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX) |
| + / (3 * sizeof (re_dfastate_t *))); |
| + if ( (ndests_max < ndests)) |
| + goto out_free; |
| + |
| + if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX |
| + + ndests * 3 * sizeof (re_dfastate_t *))) |
| + dest_states = (re_dfastate_t **) |
| + alloca (ndests * 3 * sizeof (re_dfastate_t *)); |
| + else |
| + { |
| + dest_states = re_malloc (re_dfastate_t *, ndests * 3); |
| + if ( (dest_states == NULL)) |
| + { |
| + out_free: |
| + if (dest_states_malloced) |
| + re_free (dest_states); |
| + re_node_set_free (&follows); |
| + for (i = 0; i < ndests; ++i) |
| + re_node_set_free (dests_node + i); |
| + if (dests_node_malloced) |
| + re_free (dests_alloc); |
| + return false; |
| + } |
| + dest_states_malloced = true; |
| + } |
| + dest_states_word = dest_states + ndests; |
| + dest_states_nl = dest_states_word + ndests; |
| + bitset_empty (acceptable); |
| + |
| + /* Then build the states for all destinations. */ |
| + for (i = 0; i < ndests; ++i) |
| + { |
| + Idx next_node; |
| + re_node_set_empty (&follows); |
| + /* Merge the follows of this destination states. */ |
| + for (j = 0; j < dests_node[i].nelem; ++j) |
| + { |
| + next_node = dfa->nexts[dests_node[i].elems[j]]; |
| + if (next_node != -1) |
| + { |
| + err = re_node_set_merge (&follows, dfa->eclosures + next_node); |
| + if ( (err != REG_NOERROR)) |
| + goto out_free; |
| + } |
| + } |
| + dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); |
| + if ( (dest_states[i] == NULL && err != REG_NOERROR)) |
| + goto out_free; |
| + /* If the new state has context constraint, |
| + build appropriate states for these contexts. */ |
| + if (dest_states[i]->has_constraint) |
| + { |
| + dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, |
| + CONTEXT_WORD); |
| + if ( (dest_states_word[i] == NULL |
| + && err != REG_NOERROR)) |
| + goto out_free; |
| + |
| + if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1) |
| + need_word_trtable = true; |
| + |
| + dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, |
| + CONTEXT_NEWLINE); |
| + if ( (dest_states_nl[i] == NULL && err != REG_NOERROR)) |
| + goto out_free; |
| + } |
| + else |
| + { |
| + dest_states_word[i] = dest_states[i]; |
| + dest_states_nl[i] = dest_states[i]; |
| + } |
| + bitset_merge (acceptable, dests_ch[i]); |
| + } |
| + |
| + if (! (need_word_trtable)) |
| + { |
| + /* We don't care about whether the following character is a word |
| + character, or we are in a single-byte character set so we can |
| + discern by looking at the character code: allocate a |
| + 256-entry transition table. */ |
| + trtable = state->trtable = |
| + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); |
| + if ( (trtable == NULL)) |
| + goto out_free; |
| + |
| + /* For all characters ch...: */ |
| + for (i = 0; i < BITSET_WORDS; ++i) |
| + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; |
| + elem; |
| + mask <<= 1, elem >>= 1, ++ch) |
| + if ( (elem & 1)) |
| + { |
| + /* There must be exactly one destination which accepts |
| + character ch. See group_nodes_into_DFAstates. */ |
| + for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) |
| + ; |
| + |
| + /* j-th destination accepts the word character ch. */ |
| + if (dfa->word_char[i] & mask) |
| + trtable[ch] = dest_states_word[j]; |
| + else |
| + trtable[ch] = dest_states[j]; |
| + } |
| + } |
| + else |
| + { |
| + /* We care about whether the following character is a word |
| + character, and we are in a multi-byte character set: discern |
| + by looking at the character code: build two 256-entry |
| + transition tables, one starting at trtable[0] and one |
| + starting at trtable[SBC_MAX]. */ |
| + trtable = state->word_trtable = |
| + (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX); |
| + if ( (trtable == NULL)) |
| + goto out_free; |
| + |
| + /* For all characters ch...: */ |
| + for (i = 0; i < BITSET_WORDS; ++i) |
| + for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1; |
| + elem; |
| + mask <<= 1, elem >>= 1, ++ch) |
| + if ( (elem & 1)) |
| + { |
| + /* There must be exactly one destination which accepts |
| + character ch. See group_nodes_into_DFAstates. */ |
| + for (j = 0; (dests_ch[j][i] & mask) == 0; ++j) |
| + ; |
| + |
| + /* j-th destination accepts the word character ch. */ |
| + trtable[ch] = dest_states[j]; |
| + trtable[ch + SBC_MAX] = dest_states_word[j]; |
| + } |
| + } |
| + |
| + /* new line */ |
| + if (bitset_contain (acceptable, NEWLINE_CHAR)) |
| + { |
| + /* The current state accepts newline character. */ |
| + for (j = 0; j < ndests; ++j) |
| + if (bitset_contain (dests_ch[j], NEWLINE_CHAR)) |
| + { |
| + /* k-th destination accepts newline character. */ |
| + trtable[NEWLINE_CHAR] = dest_states_nl[j]; |
| + if (need_word_trtable) |
| + trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j]; |
| + /* There must be only one destination which accepts |
| + newline. See group_nodes_into_DFAstates. */ |
| + break; |
| + } |
| + } |
| + |
| + if (dest_states_malloced) |
| + re_free (dest_states); |
| + |
| + re_node_set_free (&follows); |
| + for (i = 0; i < ndests; ++i) |
| + re_node_set_free (dests_node + i); |
| + |
| + if (dests_node_malloced) |
| + re_free (dests_alloc); |
| + |
| + return true; |
| +} |
| + |
| +/* Group all nodes belonging to STATE into several destinations. |
| + Then for all destinations, set the nodes belonging to the destination |
| + to DESTS_NODE[i] and set the characters accepted by the destination |
| + to DEST_CH[i]. This function return the number of destinations. */ |
| + |
| +static Idx |
| +group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state, |
| + re_node_set *dests_node, bitset_t *dests_ch) |
| +{ |
| + reg_errcode_t err; |
| + bool ok; |
| + Idx i, j, k; |
| + Idx ndests; /* Number of the destinations from 'state'. */ |
| + bitset_t accepts; /* Characters a node can accept. */ |
| + const re_node_set *cur_nodes = &state->nodes; |
| + bitset_empty (accepts); |
| + ndests = 0; |
| + |
| + /* For all the nodes belonging to 'state', */ |
| + for (i = 0; i < cur_nodes->nelem; ++i) |
| + { |
| + re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; |
| + re_token_type_t type = node->type; |
| + unsigned int constraint = node->constraint; |
| + |
| + /* Enumerate all single byte character this node can accept. */ |
| + if (type == CHARACTER) |
| + bitset_set (accepts, node->opr.c); |
| + else if (type == SIMPLE_BRACKET) |
| + { |
| + bitset_merge (accepts, node->opr.sbcset); |
| + } |
| + else if (type == OP_PERIOD) |
| + { |
| + bitset_set_all (accepts); |
| + if (!(dfa->syntax & RE_DOT_NEWLINE)) |
| + bitset_clear (accepts, '\n'); |
| + if (dfa->syntax & RE_DOT_NOT_NULL) |
| + bitset_clear (accepts, '\0'); |
| + } |
| + else |
| + continue; |
| + |
| + /* Check the 'accepts' and sift the characters which are not |
| + match it the context. */ |
| + if (constraint) |
| + { |
| + if (constraint & NEXT_NEWLINE_CONSTRAINT) |
| + { |
| + bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); |
| + bitset_empty (accepts); |
| + if (accepts_newline) |
| + bitset_set (accepts, NEWLINE_CHAR); |
| + else |
| + continue; |
| + } |
| + if (constraint & NEXT_ENDBUF_CONSTRAINT) |
| + { |
| + bitset_empty (accepts); |
| + continue; |
| + } |
| + |
| + if (constraint & NEXT_WORD_CONSTRAINT) |
| + { |
| + bitset_word_t any_set = 0; |
| + if (type == CHARACTER && !node->word_char) |
| + { |
| + bitset_empty (accepts); |
| + continue; |
| + } |
| + for (j = 0; j < BITSET_WORDS; ++j) |
| + any_set |= (accepts[j] &= dfa->word_char[j]); |
| + if (!any_set) |
| + continue; |
| + } |
| + if (constraint & NEXT_NOTWORD_CONSTRAINT) |
| + { |
| + bitset_word_t any_set = 0; |
| + if (type == CHARACTER && node->word_char) |
| + { |
| + bitset_empty (accepts); |
| + continue; |
| + } |
| + for (j = 0; j < BITSET_WORDS; ++j) |
| + any_set |= (accepts[j] &= ~dfa->word_char[j]); |
| + if (!any_set) |
| + continue; |
| + } |
| + } |
| + |
| + /* Then divide 'accepts' into DFA states, or create a new |
| + state. Above, we make sure that accepts is not empty. */ |
| + for (j = 0; j < ndests; ++j) |
| + { |
| + bitset_t intersec; /* Intersection sets, see below. */ |
| + bitset_t remains; |
| + /* Flags, see below. */ |
| + bitset_word_t has_intersec, not_subset, not_consumed; |
| + |
| + /* Optimization, skip if this state doesn't accept the character. */ |
| + if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) |
| + continue; |
| + |
| + /* Enumerate the intersection set of this state and 'accepts'. */ |
| + has_intersec = 0; |
| + for (k = 0; k < BITSET_WORDS; ++k) |
| + has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; |
| + /* And skip if the intersection set is empty. */ |
| + if (!has_intersec) |
| + continue; |
| + |
| + /* Then check if this state is a subset of 'accepts'. */ |
| + not_subset = not_consumed = 0; |
| + for (k = 0; k < BITSET_WORDS; ++k) |
| + { |
| + not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; |
| + not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; |
| + } |
| + |
| + /* If this state isn't a subset of 'accepts', create a |
| + new group state, which has the 'remains'. */ |
| + if (not_subset) |
| + { |
| + bitset_copy (dests_ch[ndests], remains); |
| + bitset_copy (dests_ch[j], intersec); |
| + err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); |
| + if ( (err != REG_NOERROR)) |
| + goto error_return; |
| + ++ndests; |
| + } |
| + |
| + /* Put the position in the current group. */ |
| + ok = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); |
| + if ( (! ok)) |
| + goto error_return; |
| + |
| + /* If all characters are consumed, go to next node. */ |
| + if (!not_consumed) |
| + break; |
| + } |
| + /* Some characters remain, create a new group. */ |
| + if (j == ndests) |
| + { |
| + bitset_copy (dests_ch[ndests], accepts); |
| + err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); |
| + if ( (err != REG_NOERROR)) |
| + goto error_return; |
| + ++ndests; |
| + bitset_empty (accepts); |
| + } |
| + } |
| + return ndests; |
| + error_return: |
| + for (j = 0; j < ndests; ++j) |
| + re_node_set_free (dests_node + j); |
| + return -1; |
| +} |
| + |
| + |
| +static reg_errcode_t |
| +update_cur_sifted_state (const re_match_context_t *mctx, |
| + re_sift_context_t *sctx, Idx str_idx, |
| + re_node_set *dest_nodes) |
| +{ |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + reg_errcode_t err = REG_NOERROR; |
| + const re_node_set *candidates; |
| + candidates = ((mctx->state_log[str_idx] == NULL) ? NULL |
| + : &mctx->state_log[str_idx]->nodes); |
| + |
| + if (dest_nodes->nelem == 0) |
| + sctx->sifted_states[str_idx] = NULL; |
| + else |
| + { |
| + if (candidates) |
| + { |
| + /* At first, add the nodes which can epsilon transit to a node in |
| + DEST_NODE. */ |
| + err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + |
| + /* Then, check the limitations in the current sift_context. */ |
| + if (sctx->limits.nelem) |
| + { |
| + err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, |
| + mctx->bkref_ents, str_idx); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + } |
| + } |
| + |
| + sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + } |
| + |
| + if (candidates && mctx->state_log[str_idx]->has_backref) |
| + { |
| + err = sift_states_bkref (mctx, sctx, str_idx, candidates); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +static reg_errcode_t |
| + |
| +add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes, |
| + const re_node_set *candidates) |
| +{ |
| + reg_errcode_t err = REG_NOERROR; |
| + Idx i; |
| + |
| + re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + |
| + if (!state->inveclosure.alloc) |
| + { |
| + err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem); |
| + if ( (err != REG_NOERROR)) |
| + return REG_ESPACE; |
| + for (i = 0; i < dest_nodes->nelem; i++) |
| + { |
| + err = re_node_set_merge (&state->inveclosure, |
| + dfa->inveclosures + dest_nodes->elems[i]); |
| + if ( (err != REG_NOERROR)) |
| + return REG_ESPACE; |
| + } |
| + } |
| + return re_node_set_add_intersect (dest_nodes, candidates, |
| + &state->inveclosure); |
| +} |
| + |
| +static reg_errcode_t |
| +sub_epsilon_src_nodes (const re_dfa_t *dfa, Idx node, re_node_set *dest_nodes, |
| + const re_node_set *candidates) |
| +{ |
| + Idx ecl_idx; |
| + reg_errcode_t err; |
| + re_node_set *inv_eclosure = dfa->inveclosures + node; |
| + re_node_set except_nodes; |
| + re_node_set_init_empty (&except_nodes); |
| + for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) |
| + { |
| + Idx cur_node = inv_eclosure->elems[ecl_idx]; |
| + if (cur_node == node) |
| + continue; |
| + if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) |
| + { |
| + Idx edst1 = dfa->edests[cur_node].elems[0]; |
| + Idx edst2 = ((dfa->edests[cur_node].nelem > 1) |
| + ? dfa->edests[cur_node].elems[1] : -1); |
| + if ((!re_node_set_contains (inv_eclosure, edst1) |
| + && re_node_set_contains (dest_nodes, edst1)) |
| + || (edst2 > 0 |
| + && !re_node_set_contains (inv_eclosure, edst2) |
| + && re_node_set_contains (dest_nodes, edst2))) |
| + { |
| + err = re_node_set_add_intersect (&except_nodes, candidates, |
| + dfa->inveclosures + cur_node); |
| + if ( (err != REG_NOERROR)) |
| + { |
| + re_node_set_free (&except_nodes); |
| + return err; |
| + } |
| + } |
| + } |
| + } |
| + for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) |
| + { |
| + Idx cur_node = inv_eclosure->elems[ecl_idx]; |
| + if (!re_node_set_contains (&except_nodes, cur_node)) |
| + { |
| + Idx idx = re_node_set_contains (dest_nodes, cur_node) - 1; |
| + re_node_set_remove_at (dest_nodes, idx); |
| + } |
| + } |
| + re_node_set_free (&except_nodes); |
| + return REG_NOERROR; |
| +} |
| + |
| +static bool |
| +check_dst_limits (const re_match_context_t *mctx, const re_node_set *limits, |
| + Idx dst_node, Idx dst_idx, Idx src_node, Idx src_idx) |
| +{ |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + Idx lim_idx, src_pos, dst_pos; |
| + |
| + Idx dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx); |
| + Idx src_bkref_idx = search_cur_bkref_entry (mctx, src_idx); |
| + for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) |
| + { |
| + Idx subexp_idx; |
| + struct re_backref_cache_entry *ent; |
| + ent = mctx->bkref_ents + limits->elems[lim_idx]; |
| + subexp_idx = dfa->nodes[ent->node].opr.idx; |
| + |
| + dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], |
| + subexp_idx, dst_node, dst_idx, |
| + dst_bkref_idx); |
| + src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx], |
| + subexp_idx, src_node, src_idx, |
| + src_bkref_idx); |
| + |
| + /* In case of: |
| + <src> <dst> ( <subexp> ) |
| + ( <subexp> ) <src> <dst> |
| + ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */ |
| + if (src_pos == dst_pos) |
| + continue; /* This is unrelated limitation. */ |
| + else |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +static int |
| +check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries, |
| + Idx subexp_idx, Idx from_node, Idx bkref_idx) |
| +{ |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + const re_node_set *eclosures = dfa->eclosures + from_node; |
| + Idx node_idx; |
| + |
| + /* Else, we are on the boundary: examine the nodes on the epsilon |
| + closure. */ |
| + for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) |
| + { |
| + Idx node = eclosures->elems[node_idx]; |
| + switch (dfa->nodes[node].type) |
| + { |
| + case OP_BACK_REF: |
| + if (bkref_idx != -1) |
| + { |
| + struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx; |
| + do |
| + { |
| + Idx dst; |
| + int cpos; |
| + |
| + if (ent->node != node) |
| + continue; |
| + |
| + if (subexp_idx < BITSET_WORD_BITS |
| + && !(ent->eps_reachable_subexps_map |
| + & ((bitset_word_t) 1 << subexp_idx))) |
| + continue; |
| + |
| + /* Recurse trying to reach the OP_OPEN_SUBEXP and |
| + OP_CLOSE_SUBEXP cases below. But, if the |
| + destination node is the same node as the source |
| + node, don't recurse because it would cause an |
| + infinite loop: a regex that exhibits this behavior |
| + is ()\1*\1* */ |
| + dst = dfa->edests[node].elems[0]; |
| + if (dst == from_node) |
| + { |
| + if (boundaries & 1) |
| + return -1; |
| + else /* if (boundaries & 2) */ |
| + return 0; |
| + } |
| + |
| + cpos = |
| + check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, |
| + dst, bkref_idx); |
| + if (cpos == -1 /* && (boundaries & 1) */) |
| + return -1; |
| + if (cpos == 0 && (boundaries & 2)) |
| + return 0; |
| + |
| + if (subexp_idx < BITSET_WORD_BITS) |
| + ent->eps_reachable_subexps_map |
| + &= ~((bitset_word_t) 1 << subexp_idx); |
| + } |
| + while (ent++->more); |
| + } |
| + break; |
| + |
| + case OP_OPEN_SUBEXP: |
| + if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx) |
| + return -1; |
| + break; |
| + |
| + case OP_CLOSE_SUBEXP: |
| + if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx) |
| + return 0; |
| + break; |
| + |
| + default: |
| + break; |
| + } |
| + } |
| + |
| + return (boundaries & 2) ? 1 : 0; |
| +} |
| + |
| +static int |
| +check_dst_limits_calc_pos (const re_match_context_t *mctx, Idx limit, |
| + Idx subexp_idx, Idx from_node, Idx str_idx, |
| + Idx bkref_idx) |
| +{ |
| + struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; |
| + int boundaries; |
| + |
| + /* If we are outside the range of the subexpression, return -1 or 1. */ |
| + if (str_idx < lim->subexp_from) |
| + return -1; |
| + |
| + if (lim->subexp_to < str_idx) |
| + return 1; |
| + |
| + /* If we are within the subexpression, return 0. */ |
| + boundaries = (str_idx == lim->subexp_from); |
| + boundaries |= (str_idx == lim->subexp_to) << 1; |
| + if (boundaries == 0) |
| + return 0; |
| + |
| + /* Else, examine epsilon closure. */ |
| + return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx, |
| + from_node, bkref_idx); |
| +} |
| + |
| +/* Check the limitations of sub expressions LIMITS, and remove the nodes |
| + which are against limitations from DEST_NODES. */ |
| + |
| +static reg_errcode_t |
| +check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes, |
| + const re_node_set *candidates, re_node_set *limits, |
| + struct re_backref_cache_entry *bkref_ents, Idx str_idx) |
| +{ |
| + reg_errcode_t err; |
| + Idx node_idx, lim_idx; |
| + |
| + for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) |
| + { |
| + Idx subexp_idx; |
| + struct re_backref_cache_entry *ent; |
| + ent = bkref_ents + limits->elems[lim_idx]; |
| + |
| + if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) |
| + continue; /* This is unrelated limitation. */ |
| + |
| + subexp_idx = dfa->nodes[ent->node].opr.idx; |
| + if (ent->subexp_to == str_idx) |
| + { |
| + Idx ops_node = -1; |
| + Idx cls_node = -1; |
| + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) |
| + { |
| + Idx node = dest_nodes->elems[node_idx]; |
| + re_token_type_t type = dfa->nodes[node].type; |
| + if (type == OP_OPEN_SUBEXP |
| + && subexp_idx == dfa->nodes[node].opr.idx) |
| + ops_node = node; |
| + else if (type == OP_CLOSE_SUBEXP |
| + && subexp_idx == dfa->nodes[node].opr.idx) |
| + cls_node = node; |
| + } |
| + |
| + /* Check the limitation of the open subexpression. */ |
| + /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ |
| + if (ops_node >= 0) |
| + { |
| + err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes, |
| + candidates); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + } |
| + |
| + /* Check the limitation of the close subexpression. */ |
| + if (cls_node >= 0) |
| + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) |
| + { |
| + Idx node = dest_nodes->elems[node_idx]; |
| + if (!re_node_set_contains (dfa->inveclosures + node, |
| + cls_node) |
| + && !re_node_set_contains (dfa->eclosures + node, |
| + cls_node)) |
| + { |
| + /* It is against this limitation. |
| + Remove it form the current sifted state. */ |
| + err = sub_epsilon_src_nodes (dfa, node, dest_nodes, |
| + candidates); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + --node_idx; |
| + } |
| + } |
| + } |
| + else /* (ent->subexp_to != str_idx) */ |
| + { |
| + for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) |
| + { |
| + Idx node = dest_nodes->elems[node_idx]; |
| + re_token_type_t type = dfa->nodes[node].type; |
| + if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) |
| + { |
| + if (subexp_idx != dfa->nodes[node].opr.idx) |
| + continue; |
| + /* It is against this limitation. |
| + Remove it form the current sifted state. */ |
| + err = sub_epsilon_src_nodes (dfa, node, dest_nodes, |
| + candidates); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + } |
| + } |
| + } |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +static reg_errcode_t |
| + |
| +sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx, |
| + Idx str_idx, const re_node_set *candidates) |
| +{ |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + reg_errcode_t err; |
| + Idx node_idx, node; |
| + re_sift_context_t local_sctx; |
| + Idx first_idx = search_cur_bkref_entry (mctx, str_idx); |
| + |
| + if (first_idx == -1) |
| + return REG_NOERROR; |
| + |
| + local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ |
| + |
| + for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) |
| + { |
| + Idx enabled_idx; |
| + re_token_type_t type; |
| + struct re_backref_cache_entry *entry; |
| + node = candidates->elems[node_idx]; |
| + type = dfa->nodes[node].type; |
| + /* Avoid infinite loop for the REs like "()\1+". */ |
| + if (node == sctx->last_node && str_idx == sctx->last_str_idx) |
| + continue; |
| + if (type != OP_BACK_REF) |
| + continue; |
| + |
| + entry = mctx->bkref_ents + first_idx; |
| + enabled_idx = first_idx; |
| + do |
| + { |
| + Idx subexp_len; |
| + Idx to_idx; |
| + Idx dst_node; |
| + bool ok; |
| + re_dfastate_t *cur_state; |
| + |
| + if (entry->node != node) |
| + continue; |
| + subexp_len = entry->subexp_to - entry->subexp_from; |
| + to_idx = str_idx + subexp_len; |
| + dst_node = (subexp_len ? dfa->nexts[node] |
| + : dfa->edests[node].elems[0]); |
| + |
| + if (to_idx > sctx->last_str_idx |
| + || sctx->sifted_states[to_idx] == NULL |
| + || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node) |
| + || check_dst_limits (mctx, &sctx->limits, node, |
| + str_idx, dst_node, to_idx)) |
| + continue; |
| + |
| + if (local_sctx.sifted_states == NULL) |
| + { |
| + local_sctx = *sctx; |
| + err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); |
| + if ( (err != REG_NOERROR)) |
| + goto free_return; |
| + } |
| + local_sctx.last_node = node; |
| + local_sctx.last_str_idx = str_idx; |
| + ok = re_node_set_insert (&local_sctx.limits, enabled_idx); |
| + if ( (! ok)) |
| + { |
| + err = REG_ESPACE; |
| + goto free_return; |
| + } |
| + cur_state = local_sctx.sifted_states[str_idx]; |
| + err = sift_states_backward (mctx, &local_sctx); |
| + if ( (err != REG_NOERROR)) |
| + goto free_return; |
| + if (sctx->limited_states != NULL) |
| + { |
| + err = merge_state_array (dfa, sctx->limited_states, |
| + local_sctx.sifted_states, |
| + str_idx + 1); |
| + if ( (err != REG_NOERROR)) |
| + goto free_return; |
| + } |
| + local_sctx.sifted_states[str_idx] = cur_state; |
| + re_node_set_remove (&local_sctx.limits, enabled_idx); |
| + |
| + /* mctx->bkref_ents may have changed, reload the pointer. */ |
| + entry = mctx->bkref_ents + enabled_idx; |
| + } |
| + while (enabled_idx++, entry++->more); |
| + } |
| + err = REG_NOERROR; |
| + free_return: |
| + if (local_sctx.sifted_states != NULL) |
| + { |
| + re_node_set_free (&local_sctx.limits); |
| + } |
| + |
| + return err; |
| +} |
| + |
| + |
| +static reg_errcode_t |
| +transit_state_bkref(re_match_context_t *mctx, const re_node_set *nodes) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + reg_errcode_t err; |
| + Idx i; |
| + Idx cur_str_idx = re_string_cur_idx(&mctx->input); |
| + |
| + for (i = 0; i < nodes->nelem; ++i) { |
| + Idx dest_str_idx, prev_nelem, bkc_idx; |
| + Idx node_idx = nodes->elems[i]; |
| + unsigned int context; |
| + const re_token_t *node = dfa->nodes + node_idx; |
| + re_node_set *new_dest_nodes; |
| + |
| + /* Check whether 'node' is a backreference or not. */ |
| + if (node->type != OP_BACK_REF) |
| + continue; |
| + |
| + if (node->constraint) { |
| + context = re_string_context_at(&mctx->input, cur_str_idx, |
| + mctx->eflags); |
| + if (NOT_SATISFY_NEXT_CONSTRAINT(node->constraint, context)) |
| + continue; |
| + } |
| + |
| + /* 'node' is a backreference. |
| + Check the substring which the substring matched. */ |
| + bkc_idx = mctx->nbkref_ents; |
| + err = get_subexp(mctx, node_idx, cur_str_idx); |
| + if ((err != REG_NOERROR)) |
| + goto free_return; |
| + |
| + /* And add the epsilon closures (which is 'new_dest_nodes') of |
| + the backreference to appropriate state_log. */ |
| + |
| + for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) { |
| + Idx subexp_len; |
| + re_dfastate_t *dest_state; |
| + struct re_backref_cache_entry *bkref_ent; |
| + bkref_ent = mctx->bkref_ents + bkc_idx; |
| + if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) |
| + continue; |
| + subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; |
| + new_dest_nodes = (subexp_len == 0 |
| + ? dfa->eclosures + dfa->edests[node_idx].elems[0] |
| + : dfa->eclosures + dfa->nexts[node_idx]); |
| + dest_str_idx = (cur_str_idx + bkref_ent->subexp_to |
| + - bkref_ent->subexp_from); |
| + context = re_string_context_at(&mctx->input, dest_str_idx - 1, |
| + mctx->eflags); |
| + dest_state = mctx->state_log[dest_str_idx]; |
| + prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 |
| + : mctx->state_log[cur_str_idx]->nodes.nelem); |
| + /* Add 'new_dest_node' to state_log. */ |
| + if (dest_state == NULL) { |
| + mctx->state_log[dest_str_idx] |
| + = re_acquire_state_context(&err, dfa, new_dest_nodes, |
| + context); |
| + if ((mctx->state_log[dest_str_idx] == NULL |
| + && err != REG_NOERROR)) |
| + goto free_return; |
| + } else { |
| + re_node_set dest_nodes; |
| + err = re_node_set_init_union(&dest_nodes, |
| + dest_state->entrance_nodes, |
| + new_dest_nodes); |
| + if ((err != REG_NOERROR)) { |
| + re_node_set_free(&dest_nodes); |
| + goto free_return; |
| + } |
| + mctx->state_log[dest_str_idx] |
| + = re_acquire_state_context(&err, dfa, &dest_nodes, context); |
| + re_node_set_free(&dest_nodes); |
| + if ((mctx->state_log[dest_str_idx] == NULL |
| + && err != REG_NOERROR)) |
| + goto free_return; |
| + } |
| + /* We need to check recursively if the backreference can epsilon |
| + transit. */ |
| + if (subexp_len == 0 |
| + && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) { |
| + err = check_subexp_matching_top(mctx, new_dest_nodes, |
| + cur_str_idx); |
| + if ((err != REG_NOERROR)) |
| + goto free_return; |
| + err = transit_state_bkref(mctx, new_dest_nodes); |
| + if ((err != REG_NOERROR)) |
| + goto free_return; |
| + } |
| + } |
| + } |
| + err = REG_NOERROR; |
| + free_return: |
| + return err; |
| +} |
| + |
| +/* Return the next state to which the current state STATE will transit by |
| + accepting the current input byte, and update STATE_LOG if necessary. |
| + If STATE can accept a multibyte char/collating element/back reference |
| + update the destination of STATE_LOG. */ |
| + |
| +static re_dfastate_t * |
| + |
| +transit_state(reg_errcode_t |
| + *err, |
| + re_match_context_t *mctx, |
| + re_dfastate_t |
| + *state) { |
| + re_dfastate_t **trtable; |
| + unsigned char ch; |
| + |
| +/* Use transition table */ |
| + ch = re_string_fetch_byte(&mctx->input); |
| + for (;;) { |
| + trtable = state->trtable; |
| + if ((trtable != NULL)) |
| + return trtable[ch]; |
| + |
| + trtable = state->word_trtable; |
| + if ((trtable != NULL)) { |
| + unsigned int context; |
| + context |
| + = re_string_context_at(&mctx->input, |
| + re_string_cur_idx(&mctx->input) - 1, |
| + mctx->eflags); |
| + if ( |
| + IS_WORD_CONTEXT(context) |
| + ) |
| + return trtable[ch + SBC_MAX]; |
| + else |
| + return trtable[ch]; |
| + } |
| + |
| + if (! |
| + build_trtable(mctx |
| + ->dfa, state)) { |
| + * |
| + err = REG_ESPACE; |
| + return |
| + NULL; |
| + } |
| + |
| +/* Retry, we now have a transition table. */ |
| + } |
| +} |
| + |
| +/* Update the state_log if we need */ |
| +static re_dfastate_t * |
| +merge_state_with_log(reg_errcode_t *err, re_match_context_t *mctx, |
| + re_dfastate_t *next_state) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + Idx cur_idx = re_string_cur_idx(&mctx->input); |
| + |
| + if (cur_idx > mctx->state_log_top) { |
| + mctx->state_log[cur_idx] = next_state; |
| + mctx->state_log_top = cur_idx; |
| + } else if (mctx->state_log[cur_idx] == 0) { |
| + mctx->state_log[cur_idx] = next_state; |
| + } else { |
| + re_dfastate_t *pstate; |
| + unsigned int context; |
| + re_node_set next_nodes, *log_nodes, *table_nodes = NULL; |
| + /* If (state_log[cur_idx] != 0), it implies that cur_idx is |
| + the destination of a multibyte char/collating element/ |
| + back reference. Then the next state is the union set of |
| + these destinations and the results of the transition table. */ |
| + pstate = mctx->state_log[cur_idx]; |
| + log_nodes = pstate->entrance_nodes; |
| + if (next_state != NULL) { |
| + table_nodes = next_state->entrance_nodes; |
| + *err = re_node_set_init_union(&next_nodes, table_nodes, |
| + log_nodes); |
| + if ((*err != REG_NOERROR)) |
| + return NULL; |
| + } else |
| + next_nodes = *log_nodes; |
| + /* Note: We already add the nodes of the initial state, |
| + then we don't need to add them here. */ |
| + |
| + context = re_string_context_at(&mctx->input, |
| + re_string_cur_idx(&mctx->input) - 1, |
| + mctx->eflags); |
| + next_state = mctx->state_log[cur_idx] |
| + = re_acquire_state_context(err, dfa, &next_nodes, context); |
| + /* We don't need to check errors here, since the return value of |
| + this function is next_state and ERR is already set. */ |
| + |
| + if (table_nodes != NULL) |
| + re_node_set_free(&next_nodes); |
| + } |
| + |
| + if ((dfa->nbackref) && next_state != NULL) { |
| + /* Check OP_OPEN_SUBEXP in the current state in case that we use them |
| + later. We must check them here, since the back references in the |
| + next state might use them. */ |
| + *err = check_subexp_matching_top(mctx, &next_state->nodes, |
| + cur_idx); |
| + if ((*err != REG_NOERROR)) |
| + return NULL; |
| + |
| + /* If the next state has back references. */ |
| + if (next_state->has_backref) { |
| + *err = transit_state_bkref(mctx, &next_state->nodes); |
| + if ((*err != REG_NOERROR)) |
| + return NULL; |
| + next_state = mctx->state_log[cur_idx]; |
| + } |
| + } |
| + |
| + return next_state; |
| +} |
| + |
| +/* Skip bytes in the input that correspond to part of a |
| + multi-byte match, then look in the log for a state |
| + from which to restart matching. */ |
| +static re_dfastate_t * |
| +find_recover_state(reg_errcode_t *err, re_match_context_t *mctx) { |
| + re_dfastate_t *cur_state; |
| + do { |
| + Idx max = mctx->state_log_top; |
| + Idx cur_str_idx = re_string_cur_idx(&mctx->input); |
| + |
| + do { |
| + if (++cur_str_idx > max) |
| + return NULL; |
| + re_string_skip_bytes(&mctx->input, 1); |
| + } while (mctx->state_log[cur_str_idx] == NULL); |
| + |
| + cur_state = merge_state_with_log(err, mctx, NULL); |
| + } while (*err == REG_NOERROR && cur_state == NULL); |
| + return cur_state; |
| +} |
| + |
| +/* Functions for matching context. */ |
| + |
| +/* Initialize MCTX. */ |
| + |
| +static reg_errcode_t |
| +match_ctx_init(re_match_context_t *mctx, int eflags, Idx n) { |
| + mctx->eflags = eflags; |
| + mctx->match_last = -1; |
| + if (n > 0) { |
| +/* Avoid overflow. */ |
| + size_t max_object_size = |
| + MAX (sizeof(struct re_backref_cache_entry), |
| + sizeof(re_sub_match_top_t * )); |
| + if ((MIN (IDX_MAX, SIZE_MAX / max_object_size) < n)) |
| + return REG_ESPACE; |
| + |
| + mctx->bkref_ents = re_malloc( |
| + struct re_backref_cache_entry, n); |
| + mctx->sub_tops = re_malloc(re_sub_match_top_t * , n); |
| + if ((mctx->bkref_ents == NULL || mctx->sub_tops == NULL)) |
| + return REG_ESPACE; |
| + } |
| +/* Already zero-ed by the caller. |
| + else |
| + mctx->bkref_ents = NULL; |
| + mctx->nbkref_ents = 0; |
| + mctx->nsub_tops = 0; */ |
| + mctx->abkref_ents = n; |
| + mctx->max_mb_elem_len = 1; |
| + mctx->asub_tops = n; |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Clean the entries which depend on the current input in MCTX. |
| + This function must be invoked when the matcher changes the start index |
| + of the input, or changes the input string. */ |
| + |
| +static void |
| +match_ctx_clean(re_match_context_t *mctx) { |
| + Idx st_idx; |
| + for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) { |
| + Idx sl_idx; |
| + re_sub_match_top_t *top = mctx->sub_tops[st_idx]; |
| + for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx) { |
| + re_sub_match_last_t *last = top->lasts[sl_idx]; |
| + re_free(last->path.array); |
| + re_free(last); |
| + } |
| + re_free(top->lasts); |
| + if (top->path) { |
| + re_free(top->path->array); |
| + re_free(top->path); |
| + } |
| + re_free(top); |
| + } |
| + |
| + mctx->nsub_tops = 0; |
| + mctx->nbkref_ents = 0; |
| +} |
| + |
| +/* Free all the memory associated with MCTX. */ |
| + |
| +static void |
| +match_ctx_free(re_match_context_t *mctx) { |
| + /* First, free all the memory associated with MCTX->SUB_TOPS. */ |
| + match_ctx_clean(mctx); |
| + re_free(mctx->sub_tops); |
| + re_free(mctx->bkref_ents); |
| +} |
| + |
| +/* Add a new backreference entry to MCTX. |
| + Note that we assume that caller never call this function with duplicate |
| + entry, and call with STR_IDX which isn't smaller than any existing entry. |
| +*/ |
| + |
| +static reg_errcode_t |
| + |
| +match_ctx_add_entry(re_match_context_t *mctx, Idx node, Idx str_idx, Idx from, |
| + Idx to) { |
| + if (mctx->nbkref_ents >= mctx->abkref_ents) { |
| + struct re_backref_cache_entry *new_entry; |
| + new_entry = re_realloc(mctx->bkref_ents, |
| + struct re_backref_cache_entry, |
| + mctx->abkref_ents * 2); |
| + if ((new_entry == NULL)) { |
| + re_free(mctx->bkref_ents); |
| + return REG_ESPACE; |
| + } |
| + mctx->bkref_ents = new_entry; |
| + memset(mctx->bkref_ents + mctx->nbkref_ents, '\0', |
| + sizeof(struct re_backref_cache_entry) * mctx->abkref_ents); |
| + mctx->abkref_ents *= 2; |
| + } |
| + if (mctx->nbkref_ents > 0 |
| + && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx) |
| + mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1; |
| + |
| + mctx->bkref_ents[mctx->nbkref_ents].node = node; |
| + mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; |
| + mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; |
| + mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; |
| + |
| +/* This is a cache that saves negative results of check_dst_limits_calc_pos. |
| + If bit N is clear, means that this entry won't epsilon-transition to |
| + an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If |
| + it is set, check_dst_limits_calc_pos_1 will recurse and try to find one |
| + such node. |
| + |
| + A backreference does not epsilon-transition unless it is empty, so set |
| + to all zeros if FROM != TO. */ |
| + mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map |
| + = (from == to ? -1 : 0); |
| + |
| + mctx->bkref_ents[mctx->nbkref_ents++].more = 0; |
| + if (mctx->max_mb_elem_len < to - from) |
| + mctx->max_mb_elem_len = to - from; |
| + return REG_NOERROR; |
| +} |
| + |
| +/* Check whether the regular expression match input string INPUT or not, |
| + and return the index where the matching end. Return -1 if |
| + there is no match, and return -2 in case of an error. |
| + FL_LONGEST_MATCH means we want the POSIX longest matching. |
| + If P_MATCH_FIRST is not NULL, and the match fails, it is set to the |
| + next place where we may want to try matching. |
| + Note that the matcher assumes that the matching starts from the current |
| + index of the buffer. */ |
| + |
| +static Idx |
| +check_matching(re_match_context_t *mctx, bool fl_longest_match, |
| + Idx *p_match_first) { |
| + const re_dfa_t *const dfa = mctx->dfa; |
| + reg_errcode_t err; |
| + Idx match = 0; |
| + Idx match_last = -1; |
| + Idx cur_str_idx = re_string_cur_idx(&mctx->input); |
| + re_dfastate_t *cur_state; |
| + bool at_init_state = p_match_first != NULL; |
| + Idx next_start_idx = cur_str_idx; |
| + |
| + err = REG_NOERROR; |
| + cur_state = acquire_init_state_context(&err, mctx, cur_str_idx); |
| +/* An initial state must not be NULL (invalid). */ |
| + if ((cur_state == NULL)) { |
| + assert(err == REG_ESPACE); |
| + return -2; |
| + } |
| + |
| + if (mctx->state_log != NULL) { |
| + mctx->state_log[cur_str_idx] = cur_state; |
| + |
| +/* Check OP_OPEN_SUBEXP in the initial state in case that we use them |
| +later. E.g. Processing back references. */ |
| + if ((dfa->nbackref)) { |
| + at_init_state = false; |
| + err = check_subexp_matching_top(mctx, &cur_state->nodes, 0); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + |
| + if (cur_state->has_backref) { |
| + err = transit_state_bkref(mctx, &cur_state->nodes); |
| + if ((err != REG_NOERROR)) |
| + return err; |
| + } |
| + } |
| + } |
| + |
| +/* If the RE accepts NULL string. */ |
| + if ((cur_state->halt)) { |
| + if (!cur_state->has_constraint |
| + || check_halt_state_context(mctx, cur_state, cur_str_idx)) { |
| + if (!fl_longest_match) |
| + return cur_str_idx; |
| + else { |
| + match_last = cur_str_idx; |
| + match = 1; |
| + } |
| + } |
| + } |
| + |
| + while (!re_string_eoi(&mctx->input)) { |
| + re_dfastate_t *old_state = cur_state; |
| + Idx next_char_idx = re_string_cur_idx(&mctx->input) + 1; |
| + |
| + if (((next_char_idx >= mctx->input.bufs_len) |
| + && mctx->input.bufs_len < mctx->input.len) |
| + || ((next_char_idx >= mctx->input.valid_len) |
| + && mctx->input.valid_len < mctx->input.len)) { |
| + err = extend_buffers(mctx, next_char_idx + 1); |
| + if ((err != REG_NOERROR)) { |
| + assert(err == REG_ESPACE); |
| + return -2; |
| + } |
| + } |
| + |
| + cur_state = transit_state(&err, mctx, cur_state); |
| + if (mctx->state_log != NULL) |
| + cur_state = merge_state_with_log(&err, mctx, cur_state); |
| + |
| + if (cur_state == NULL) { |
| +/* Reached the invalid state or an error. Try to recover a valid |
| + state using the state log, if available and if we have not |
| + already found a valid (even if not the longest) match. */ |
| + if ((err != REG_NOERROR)) |
| + return -2; |
| + |
| + if (mctx->state_log == NULL |
| + || (match && !fl_longest_match) |
| + || (cur_state = find_recover_state(&err, mctx)) == NULL) |
| + break; |
| + } |
| + |
| + if ((at_init_state)) { |
| + if (old_state == cur_state) |
| + next_start_idx = next_char_idx; |
| + else |
| + at_init_state = false; |
| + } |
| + |
| + if (cur_state->halt) { |
| +/* Reached a halt state. |
| + Check the halt state can satisfy the current context. */ |
| + if (!cur_state->has_constraint |
| + || check_halt_state_context(mctx, cur_state, |
| + re_string_cur_idx(&mctx->input))) { |
| +/* We found an appropriate halt state. */ |
| + match_last = re_string_cur_idx(&mctx->input); |
| + match = 1; |
| + |
| +/* We found a match, do not modify match_first below. */ |
| + p_match_first = NULL; |
| + if (!fl_longest_match) |
| + break; |
| + } |
| + } |
| + } |
| + |
| + if (p_match_first) |
| + *p_match_first += next_start_idx; |
| + |
| + return match_last; |
| +} |
| + |
| +/* Searches for a compiled pattern PREG in the string STRING, whose |
| + length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same |
| + meaning as with regexec. LAST_START is START + RANGE, where |
| + START and RANGE have the same meaning as with re_search. |
| + Return REG_NOERROR if we find a match, and REG_NOMATCH if not, |
| + otherwise return the error code. |
| + Note: We assume front end functions already check ranges. |
| + (0 <= LAST_START && LAST_START <= LENGTH) */ |
| + |
| +static reg_errcode_t |
| +re_search_internal(const regex_t *preg, const char *string, Idx length, |
| + Idx start, Idx last_start, Idx stop, size_t nmatch, |
| + regmatch_t pmatch[], int eflags) { |
| + reg_errcode_t err; |
| + const re_dfa_t *dfa = preg->buffer; |
| + Idx left_lim, right_lim; |
| + int incr; |
| + bool fl_longest_match; |
| + int match_kind; |
| + Idx match_first; |
| + Idx match_last = -1; |
| + Idx extra_nmatch; |
| + bool sb; |
| + int ch; |
| + re_match_context_t mctx; |
| + char *fastmap = ((preg->fastmap != NULL && preg->fastmap_accurate |
| + && start != last_start && !preg->can_be_null) |
| + ? preg->fastmap : NULL); |
| + RE_TRANSLATE_TYPE t = preg->translate; |
| + |
| + memset(&mctx, '\0', sizeof(re_match_context_t)); |
| + mctx.dfa = dfa; |
| + |
| + |
| + extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0; |
| + nmatch -= extra_nmatch; |
| + |
| + /* Check if the DFA haven't been compiled. */ |
| + if ((preg->used == 0 || dfa->init_state == NULL |
| + || dfa->init_state_word == NULL |
| + || dfa->init_state_nl == NULL |
| + || dfa->init_state_begbuf == NULL)) |
| + return REG_NOMATCH; |
| + |
| + /* If initial states with non-begbuf contexts have no elements, |
| + the regex must be anchored. If preg->newline_anchor is set, |
| + we'll never use init_state_nl, so do not check it. */ |
| + if (dfa->init_state->nodes.nelem == 0 |
| + && dfa->init_state_word->nodes.nelem == 0 |
| + && (dfa->init_state_nl->nodes.nelem == 0 |
| + || !preg->newline_anchor)) { |
| + if (start != 0 && last_start != 0) |
| + return REG_NOMATCH; |
| + start = last_start = 0; |
| + } |
| + |
| + /* We must check the longest matching, if nmatch > 0. */ |
| + fl_longest_match = (nmatch != 0 || dfa->nbackref); |
| + |
| + err = re_string_allocate(&mctx.input, string, length, dfa->nodes_len + 1, |
| + preg->translate, (preg->syntax & RE_ICASE) != 0, |
| + dfa); |
| + if ((err != REG_NOERROR)) |
| + goto free_return; |
| + mctx.input.stop = stop; |
| + mctx.input.raw_stop = stop; |
| + mctx.input.newline_anchor = preg->newline_anchor; |
| + |
| + err = match_ctx_init(&mctx, eflags, dfa->nbackref * 2); |
| + if ((err != REG_NOERROR)) |
| + goto free_return; |
| + |
| + /* We will log all the DFA states through which the dfa pass, |
| + if nmatch > 1, or this dfa has "multibyte node", which is a |
| + back-reference or a node which can accept multibyte character or |
| + multi character collating element. */ |
| + if (nmatch > 1 || dfa->has_mb_node) { |
| + /* Avoid overflow. */ |
| + if (((MIN (IDX_MAX, SIZE_MAX / sizeof(re_dfastate_t * )) |
| + <= mctx.input.bufs_len))) { |
| + err = REG_ESPACE; |
| + goto free_return; |
| + } |
| + |
| + mctx.state_log = re_malloc(re_dfastate_t * , mctx.input.bufs_len + 1); |
| + if ((mctx.state_log == NULL)) { |
| + err = REG_ESPACE; |
| + goto free_return; |
| + } |
| + } else |
| + mctx.state_log = NULL; |
| + |
| + match_first = start; |
| + mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF |
| + : CONTEXT_NEWLINE | CONTEXT_BEGBUF; |
| + |
| + /* Check incrementally whether the input string matches. */ |
| + incr = (last_start < start) ? -1 : 1; |
| + left_lim = (last_start < start) ? last_start : start; |
| + right_lim = (last_start < start) ? start : last_start; |
| + sb = dfa->mb_cur_max == 1; |
| + match_kind = |
| + (fastmap |
| + ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0) |
| + | (start <= last_start ? 2 : 0) |
| + | (t != NULL ? 1 : 0)) |
| + : 8); |
| + |
| + for (;; match_first += incr) { |
| + err = REG_NOMATCH; |
| + if (match_first < left_lim || right_lim < match_first) |
| + goto free_return; |
| + |
| + /* Advance as rapidly as possible through the string, until we |
| + find a plausible place to start matching. This may be done |
| + with varying efficiency, so there are various possibilities: |
| + only the most common of them are specialized, in order to |
| + save on code size. We use a switch statement for speed. */ |
| + switch (match_kind) { |
| + case 8: |
| + /* No fastmap. */ |
| + break; |
| + |
| + case 7: |
| + /* Fastmap with single-byte translation, match forward. */ |
| + while ((match_first < right_lim) |
| + && !fastmap[t[(unsigned char) string[match_first]]]) |
| + ++match_first; |
| + goto forward_match_found_start_or_reached_end; |
| + |
| + case 6: |
| + /* Fastmap without translation, match forward. */ |
| + while ((match_first < right_lim) |
| + && !fastmap[(unsigned char) string[match_first]]) |
| + ++match_first; |
| + |
| + forward_match_found_start_or_reached_end: |
| + if ((match_first == right_lim)) { |
| + ch = match_first >= length |
| + ? 0 : (unsigned char) string[match_first]; |
| + if (!fastmap[t ? t[ch] : ch]) |
| + goto free_return; |
| + } |
| + break; |
| + |
| + case 4: |
| + case 5: |
| + /* Fastmap without multi-byte translation, match backwards. */ |
| + while (match_first >= left_lim) { |
| + ch = match_first >= length |
| + ? 0 : (unsigned char) string[match_first]; |
| + if (fastmap[t ? t[ch] : ch]) |
| + break; |
| + --match_first; |
| + } |
| + if (match_first < left_lim) |
| + goto free_return; |
| + break; |
| + |
| + default: |
| + /* In this case, we can't determine easily the current byte, |
| + since it might be a component byte of a multibyte |
| + character. Then we use the constructed buffer instead. */ |
| + for (;;) { |
| + /* If MATCH_FIRST is out of the valid range, reconstruct the |
| + buffers. */ |
| + __re_size_t offset = match_first - mctx.input.raw_mbs_idx; |
| + if ((offset |
| + >= (__re_size_t) mctx.input.valid_raw_len)) { |
| + err = re_string_reconstruct(&mctx.input, match_first, |
| + eflags); |
| + if ((err != REG_NOERROR)) |
| + goto free_return; |
| + |
| + offset = match_first - mctx.input.raw_mbs_idx; |
| + } |
| + /* If MATCH_FIRST is out of the buffer, leave it as '\0'. |
| + Note that MATCH_FIRST must not be smaller than 0. */ |
| + ch = (match_first >= length |
| + ? 0 : re_string_byte_at(&mctx.input, offset)); |
| + if (fastmap[ch]) |
| + break; |
| + match_first += incr; |
| + if (match_first < left_lim || match_first > right_lim) { |
| + err = REG_NOMATCH; |
| + goto free_return; |
| + } |
| + } |
| + break; |
| + } |
| + |
| + /* Reconstruct the buffers so that the matcher can assume that |
| + the matching starts from the beginning of the buffer. */ |
| + err = re_string_reconstruct(&mctx.input, match_first, eflags); |
| + if ((err != REG_NOERROR)) |
| + goto free_return; |
| + |
| + /* It seems to be appropriate one, then use the matcher. */ |
| + /* We assume that the matching starts from 0. */ |
| + mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; |
| + match_last = check_matching(&mctx, fl_longest_match, |
| + start <= last_start ? &match_first : NULL); |
| + if (match_last != -1) { |
| + if ((match_last == -2)) { |
| + err = REG_ESPACE; |
| + goto free_return; |
| + } else { |
| + mctx.match_last = match_last; |
| + if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) { |
| + re_dfastate_t *pstate = mctx.state_log[match_last]; |
| + mctx.last_node = check_halt_state_context(&mctx, pstate, |
| + match_last); |
| + } |
| + if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) |
| + || dfa->nbackref) { |
| + err = prune_impossible_nodes(&mctx); |
| + if (err == REG_NOERROR) |
| + break; |
| + if ((err != REG_NOMATCH)) |
| + goto free_return; |
| + match_last = -1; |
| + } else |
| + break; /* We found a match. */ |
| + } |
| + } |
| + |
| + match_ctx_clean(&mctx); |
| + } |
| + |
| + /* Set pmatch[] if we need. */ |
| + if (nmatch > 0) { |
| + Idx reg_idx; |
| + |
| + /* Initialize registers. */ |
| + for (reg_idx = 1; reg_idx < nmatch; ++reg_idx) |
| + pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; |
| + |
| + /* Set the points where matching start/end. */ |
| + pmatch[0].rm_so = 0; |
| + pmatch[0].rm_eo = mctx.match_last; |
| + /* FIXME: This function should fail if mctx.match_last exceeds |
| + the maximum possible regoff_t value. We need a new error |
| + code REG_OVERFLOW. */ |
| + |
| + if (!preg->no_sub && nmatch > 1) { |
| + err = set_regs(preg, &mctx, nmatch, pmatch, |
| + dfa->has_plural_match && dfa->nbackref > 0); |
| + if ((err != REG_NOERROR)) |
| + goto free_return; |
| + } |
| + |
| + /* At last, add the offset to each register, since we slid |
| + the buffers so that we could assume that the matching starts |
| + from 0. */ |
| + for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) |
| + if (pmatch[reg_idx].rm_so != -1) { |
| + pmatch[reg_idx].rm_so += match_first; |
| + pmatch[reg_idx].rm_eo += match_first; |
| + } |
| + for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx) { |
| + pmatch[nmatch + reg_idx].rm_so = -1; |
| + pmatch[nmatch + reg_idx].rm_eo = -1; |
| + } |
| + |
| + if (dfa->subexp_map) |
| + for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++) |
| + if (dfa->subexp_map[reg_idx] != reg_idx) { |
| + pmatch[reg_idx + 1].rm_so |
| + = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so; |
| + pmatch[reg_idx + 1].rm_eo |
| + = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo; |
| + } |
| + } |
| + |
| + free_return: |
| + re_free(mctx.state_log); |
| + if (dfa->nbackref) |
| + match_ctx_free(&mctx); |
| + re_string_destruct(&mctx.input); |
| + return err; |
| +} |
| + |
| +/* Helper functions. */ |
| + |
| +static reg_errcode_t |
| +merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst, |
| + re_dfastate_t **src, Idx num) |
| +{ |
| + Idx st_idx; |
| + reg_errcode_t err; |
| + for (st_idx = 0; st_idx < num; ++st_idx) |
| + { |
| + if (dst[st_idx] == NULL) |
| + dst[st_idx] = src[st_idx]; |
| + else if (src[st_idx] != NULL) |
| + { |
| + re_node_set merged_set; |
| + err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, |
| + &src[st_idx]->nodes); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); |
| + re_node_set_free (&merged_set); |
| + if ( (err != REG_NOERROR)) |
| + return err; |
| + } |
| + } |
| + return REG_NOERROR; |
| +} |
| + |
| +static void |
| +sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, |
| + re_dfastate_t **limited_sts, Idx last_node, Idx last_str_idx) |
| +{ |
| + sctx->sifted_states = sifted_sts; |
| + sctx->limited_states = limited_sts; |
| + sctx->last_node = last_node; |
| + sctx->last_str_idx = last_str_idx; |
| + re_node_set_init_empty (&sctx->limits); |
| +} |
| + |
| + |
| +/* regexec searches for a given pattern, specified by PREG, in the |
| + string STRING. |
| + |
| + If NMATCH is zero or REG_NOSUB was set in the cflags argument to |
| + 'regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at |
| + least NMATCH elements, and we set them to the offsets of the |
| + corresponding matched substrings. |
| + |
| + EFLAGS specifies "execution flags" which affect matching: if |
| + REG_NOTBOL is set, then ^ does not match at the beginning of the |
| + string; if REG_NOTEOL is set, then $ does not match at the end. |
| + |
| + We return 0 if we find a match and REG_NOMATCH if not. */ |
| + |
| +int |
| +regexec(const regex_t *_Restrict_ preg, const char *_Restrict_ string, |
| + size_t nmatch, regmatch_t pmatch[], int eflags) { |
| + reg_errcode_t err; |
| + Idx start, length; |
| + re_dfa_t *dfa = preg->buffer; |
| + |
| + if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND)) |
| + return REG_BADPAT; |
| + |
| + if (eflags & REG_STARTEND) { |
| + start = pmatch[0].rm_so; |
| + length = pmatch[0].rm_eo; |
| + } else { |
| + start = 0; |
| + length = strlen(string); |
| + } |
| + |
| + lock_lock(dfa->lock); |
| + if (preg->no_sub) |
| + err = re_search_internal(preg, string, length, start, length, |
| + length, 0, NULL, eflags); |
| + else |
| + err = re_search_internal(preg, string, length, start, length, |
| + length, nmatch, pmatch, eflags); |
| + lock_unlock(dfa->lock); |
| + return err != REG_NOERROR; |
| +} |
| + |
| +#endif |
| diff --git a/wait.h b/wait.h |
| index 7408d15..3bea227 100644 |
| --- a/wait.h |
| +++ b/wait.h |
| @@ -26,3 +26,7 @@ |
| |
| +#ifdef HAVE_SYS_WAIT_H |
| #include <sys/wait.h> |
| +#else |
| +#include "headers-mingw/sys_wait.h" |
| +#endif |
| |