summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Config.in25
-rw-r--r--Makefile12
-rw-r--r--Makefile.flags7
-rw-r--r--README1
-rw-r--r--README.md19
-rw-r--r--archival/bbunzip.c2
-rw-r--r--archival/libarchive/decompress_gunzip.c3
-rw-r--r--archival/libarchive/open_transformer.c4
-rw-r--r--archival/tar.c2
-rw-r--r--archival/unzip.c3
-rw-r--r--configs/mingw32_defconfig1041
-rw-r--r--coreutils/Config.src1
-rw-r--r--coreutils/dd.c20
-rw-r--r--coreutils/od_bloaty.c18
-rw-r--r--coreutils/test.c19
-rw-r--r--coreutils/uname.c10
-rw-r--r--debianutils/which.c20
-rw-r--r--editors/awk.c4
-rw-r--r--editors/vi.c65
-rw-r--r--findutils/grep.c8
-rw-r--r--findutils/xargs.c13
-rw-r--r--include/libbb.h27
-rw-r--r--include/mingw.h438
-rw-r--r--include/platform.h40
-rw-r--r--libbb/Kbuild.src20
-rw-r--r--libbb/appletlib.c44
-rw-r--r--libbb/copy_file.c3
-rw-r--r--libbb/executable.c16
-rw-r--r--libbb/find_mount_point.c37
-rw-r--r--libbb/find_pid_by_name.c4
-rw-r--r--libbb/get_last_path_component.c5
-rw-r--r--libbb/get_line_from_file.c4
-rw-r--r--libbb/getopt32.c2
-rw-r--r--libbb/inode_hash.c2
-rw-r--r--libbb/lineedit.c65
-rw-r--r--libbb/make_directory.c25
-rw-r--r--libbb/messages.c2
-rw-r--r--libbb/printable_string.c2
-rw-r--r--libbb/procps.c3
-rw-r--r--libbb/read_printf.c5
-rw-r--r--libbb/setup_environment.c11
-rw-r--r--libbb/vfork_daemon_rexec.c5
-rw-r--r--libbb/xreadlink.c2
-rw-r--r--miscutils/man.c4
-rw-r--r--networking/ftpgetput.c6
-rw-r--r--networking/wget.c12
-rw-r--r--procps/ps.c16
-rw-r--r--scripts/basic/fixdep.c51
-rw-r--r--shell/ash.c1197
-rw-r--r--shell/shell_common.c13
-rw-r--r--util-linux/rev.c10
-rw-r--r--win32/Kbuild23
-rw-r--r--win32/env.c130
-rw-r--r--win32/fnmatch.c488
-rw-r--r--win32/fnmatch.h84
-rw-r--r--win32/grp.h0
-rw-r--r--win32/ioctl.c24
-rw-r--r--win32/mempcpy.c27
-rw-r--r--win32/mingw.c990
-rw-r--r--win32/mntent.c67
-rw-r--r--win32/mntent.h19
-rw-r--r--win32/net.c54
-rw-r--r--win32/net/if.h0
-rw-r--r--win32/netdb.h0
-rw-r--r--win32/netinet/in.h0
-rw-r--r--win32/paths.h0
-rw-r--r--win32/poll.c606
-rw-r--r--win32/poll.h53
-rw-r--r--win32/popen.c208
-rw-r--r--win32/process.c381
-rw-r--r--win32/pwd.h0
-rw-r--r--win32/regex.c4929
-rw-r--r--win32/regex.h490
-rw-r--r--win32/sched.h1
-rw-r--r--win32/statfs.c80
-rw-r--r--win32/strptime.c646
-rw-r--r--win32/sys/ioctl.h0
-rw-r--r--win32/sys/mman.h0
-rw-r--r--win32/sys/resource.h0
-rw-r--r--win32/sys/socket.h0
-rw-r--r--win32/sys/statfs.h23
-rw-r--r--win32/sys/syscall.h0
-rw-r--r--win32/sys/sysmacros.h0
-rw-r--r--win32/sys/times.h0
-rw-r--r--win32/sys/un.h0
-rw-r--r--win32/sys/utsname.h66
-rw-r--r--win32/sys/vfs.h1
-rw-r--r--win32/sys/wait.h0
-rw-r--r--win32/system.c77
-rw-r--r--win32/termios.c88
-rw-r--r--win32/termios.h129
-rw-r--r--win32/uname.c48
-rw-r--r--win32/winansi.c685
94 files changed, 13724 insertions, 62 deletions
diff --git a/.gitignore b/.gitignore
index 73e88fb5b..01400a678 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ Config.in
18# Normal output 18# Normal output
19# 19#
20/busybox 20/busybox
21/busybox.exe
21/busybox_old 22/busybox_old
22/busybox_unstripped* 23/busybox_unstripped*
23 24
diff --git a/Config.in b/Config.in
index 07b4bf36b..c6aad4210 100644
--- a/Config.in
+++ b/Config.in
@@ -9,6 +9,20 @@ config HAVE_DOT_CONFIG
9 bool 9 bool
10 default y 10 default y
11 11
12choice
13 prompt "Target platform"
14 default PLATFORM_POSIX
15 help
16 Target platform you are building busybox for
17
18config PLATFORM_POSIX
19 bool "POSIX"
20
21config PLATFORM_MINGW32
22 bool "MS Windows (MinGW port)"
23
24endchoice
25
12menu "Busybox Settings" 26menu "Busybox Settings"
13 27
14menu "General Configuration" 28menu "General Configuration"
@@ -616,6 +630,17 @@ config LFS
616 cp, mount, tar, and many others. If you want to access files larger 630 cp, mount, tar, and many others. If you want to access files larger
617 than 2 Gigabytes, enable this option. Otherwise, leave it set to 'N'. 631 than 2 Gigabytes, enable this option. Otherwise, leave it set to 'N'.
618 632
633config NOGLOB
634 bool "Turn off MSVCRT argument processing"
635 default y
636 depends on PLATFORM_MINGW32
637 help
638 The Microsoft C Runtime handles the expansion of wildcards on the
639 command line while the BusyBox shell does its own wildcard expansion.
640 For best results when using the shell MSVCRT globbing should be
641 turned off. If you want the BusyBox binary to handle wildcard
642 expansion using the Microsoft C Runtime set this to 'N'.
643
619config CROSS_COMPILER_PREFIX 644config CROSS_COMPILER_PREFIX
620 string "Cross Compiler prefix" 645 string "Cross Compiler prefix"
621 default "" 646 default ""
diff --git a/Makefile b/Makefile
index b487f0457..a64b0c926 100644
--- a/Makefile
+++ b/Makefile
@@ -312,6 +312,7 @@ AFLAGS_MODULE = $(MODFLAGS)
312LDFLAGS_MODULE = -r 312LDFLAGS_MODULE = -r
313CFLAGS_KERNEL = 313CFLAGS_KERNEL =
314AFLAGS_KERNEL = 314AFLAGS_KERNEL =
315EXEEXT =
315 316
316 317
317# Use LINUXINCLUDE when you must reference the include/ directory. 318# Use LINUXINCLUDE when you must reference the include/ directory.
@@ -491,6 +492,7 @@ libs-y := \
491 sysklogd/ \ 492 sysklogd/ \
492 util-linux/ \ 493 util-linux/ \
493 util-linux/volume_id/ \ 494 util-linux/volume_id/ \
495 win32/ \
494 496
495endif # KBUILD_EXTMOD 497endif # KBUILD_EXTMOD
496 498
@@ -529,7 +531,7 @@ endif
529# command line. 531# command line.
530# This allow a user to issue only 'make' to build a kernel including modules 532# This allow a user to issue only 'make' to build a kernel including modules
531# Defaults busybox but it is usually overridden in the arch makefile 533# Defaults busybox but it is usually overridden in the arch makefile
532all: busybox doc 534all: busybox$(EXEEXT) doc
533 535
534-include $(srctree)/arch/$(ARCH)/Makefile 536-include $(srctree)/arch/$(ARCH)/Makefile
535 537
@@ -712,16 +714,16 @@ debug_kallsyms: .tmp_map$(last_kallsyms)
712endif # ifdef CONFIG_KALLSYMS 714endif # ifdef CONFIG_KALLSYMS
713 715
714# busybox image - including updated kernel symbols 716# busybox image - including updated kernel symbols
715busybox_unstripped: $(busybox-all) FORCE 717busybox_unstripped$(EXEEXT): $(busybox-all) FORCE
716 $(call if_changed_rule,busybox__) 718 $(call if_changed_rule,busybox__)
717 $(Q)rm -f .old_version 719 $(Q)rm -f .old_version
718 720
719busybox: busybox_unstripped 721busybox$(EXEEXT): busybox_unstripped$(EXEEXT)
720ifeq ($(SKIP_STRIP),y) 722ifeq ($(SKIP_STRIP),y)
721 $(Q)cp $< $@ 723 $(Q)cp $< $@
722else 724else
723 $(Q)$(STRIP) -s --remove-section=.note --remove-section=.comment \ 725 $(Q)$(STRIP) -s --remove-section=.note --remove-section=.comment \
724 busybox_unstripped -o $@ 726 busybox_unstripped$(EXEEXT) -o $@
725# strip is confused by PIE executable and does not set exec bits 727# strip is confused by PIE executable and does not set exec bits
726 $(Q)chmod a+x $@ 728 $(Q)chmod a+x $@
727endif 729endif
@@ -957,7 +959,7 @@ endif # CONFIG_MODULES
957 959
958# Directories & files removed with 'make clean' 960# Directories & files removed with 'make clean'
959CLEAN_DIRS += $(MODVERDIR) _install 0_lib 961CLEAN_DIRS += $(MODVERDIR) _install 0_lib
960CLEAN_FILES += busybox busybox_unstripped* busybox.links \ 962CLEAN_FILES += busybox$(EXEEXT) busybox_unstripped* busybox.links \
961 System.map .kernelrelease \ 963 System.map .kernelrelease \
962 .tmp_kallsyms* .tmp_version .tmp_busybox* .tmp_System.map 964 .tmp_kallsyms* .tmp_version .tmp_busybox* .tmp_System.map
963 965
diff --git a/Makefile.flags b/Makefile.flags
index 307afa7f5..d9122ce94 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -115,6 +115,13 @@ CFLAGS += --sysroot=$(CONFIG_SYSROOT)
115export SYSROOT=$(CONFIG_SYSROOT) 115export SYSROOT=$(CONFIG_SYSROOT)
116endif 116endif
117 117
118ifeq ($(CONFIG_PLATFORM_MINGW32),y)
119# These defintions are not strictly needed, but they help shut up fnmatch.c warnings
120CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy
121EXEEXT = .exe
122LDLIBS += userenv ws2_32
123endif
124
118# Android has no separate crypt library 125# Android has no separate crypt library
119# gcc-4.2.1 fails if we try to feed C source on stdin: 126# gcc-4.2.1 fails if we try to feed C source on stdin:
120# echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc - 127# echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc -
diff --git a/README b/README
index b940e357a..82f72e5a8 100644
--- a/README
+++ b/README
@@ -1,3 +1,4 @@
1Please see README.md for Windows-specific info.
1Please see the LICENSE file for details on copying and usage. 2Please see the LICENSE file for details on copying and usage.
2Please refer to the INSTALL file for instructions on how to build. 3Please refer to the INSTALL file for instructions on how to build.
3 4
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..1ef735a74
--- /dev/null
+++ b/README.md
@@ -0,0 +1,19 @@
1### Status
2
3This port is used in production at Tigress. Things may work for you, or may not. Things may never work because of huge differences between Linux and Windows. Or things may work in future, if you report the problem to https://github.com/rmyorston/busybox-w32.
4
5### Building
6
7You need a MinGW compiler and a POSIX environment (so that `make menuconfig` works). I cross compile from Linux, but MSYS or Cygwin should be OK.
8
9To start, run `make mingw32_defconfig`. You can then customize your build with `make menuconfig`.
10
11In particular you may need to adjust the compiler by going to Busybox Settings -> Build Options -> Cross Compiler Prefix
12
13Then just `make`.
14
15### Limitations
16
17 - Use forward slashes in paths: Windows doesn't mind and the shell will be happier.
18 - Don't do wild things with Windows drive or UNC notation.
19 - tar doesn't support seamless compression/decompression: use a pipeline to a compressor/decompressor.
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 90aac1427..a859ef201 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -177,6 +177,8 @@ int FAST_FUNC bbunpack(char **argv,
177 /* Delete _source_ file */ 177 /* Delete _source_ file */
178 del = filename; 178 del = filename;
179 } 179 }
180 if (ENABLE_PLATFORM_MINGW32)
181 xclose(STDIN_FILENO);
180 xunlink(del); 182 xunlink(del);
181 free_name: 183 free_name:
182 if (new_name != filename) 184 if (new_name != filename)
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index 1360abef7..dced609e5 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -36,6 +36,9 @@
36#include <setjmp.h> 36#include <setjmp.h>
37#include "libbb.h" 37#include "libbb.h"
38#include "bb_archive.h" 38#include "bb_archive.h"
39#if ENABLE_PLATFORM_MINGW32 && __GNUC__
40#pragma pack(2)
41#endif
39 42
40typedef struct huft_t { 43typedef struct huft_t {
41 unsigned char e; /* number of extra bits or operation */ 44 unsigned char e; /* number of extra bits or operation */
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index ab6aa3afc..0a8c657b7 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -68,6 +68,7 @@ ssize_t FAST_FUNC xtransformer_write(transformer_state_t *xstate, const void *bu
68 return nwrote; 68 return nwrote;
69} 69}
70 70
71#if SEAMLESS_COMPRESSION
71void check_errors_in_children(int signo) 72void check_errors_in_children(int signo)
72{ 73{
73 int status; 74 int status;
@@ -155,9 +156,6 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
155 xmove_fd(fd_pipe.rd, fd); 156 xmove_fd(fd_pipe.rd, fd);
156} 157}
157 158
158
159#if SEAMLESS_COMPRESSION
160
161/* Used by e.g. rpm which gives us a fd without filename, 159/* Used by e.g. rpm which gives us a fd without filename,
162 * thus we can't guess the format from filename's extension. 160 * thus we can't guess the format from filename's extension.
163 */ 161 */
diff --git a/archival/tar.c b/archival/tar.c
index aa03ba990..85551684b 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -549,6 +549,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
549 } 549 }
550 } 550 }
551 551
552#if !ENABLE_PLATFORM_MINGW32
552 /* It is a bad idea to store the archive we are in the process of creating, 553 /* It is a bad idea to store the archive we are in the process of creating,
553 * so check the device and inode to be sure that this particular file isn't 554 * so check the device and inode to be sure that this particular file isn't
554 * the new tarball */ 555 * the new tarball */
@@ -558,6 +559,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
558 bb_error_msg("%s: file is the archive; skipping", fileName); 559 bb_error_msg("%s: file is the archive; skipping", fileName);
559 return TRUE; 560 return TRUE;
560 } 561 }
562#endif
561 563
562 if (exclude_file(tbInfo->excludeList, header_name)) 564 if (exclude_file(tbInfo->excludeList, header_name))
563 return SKIP; 565 return SKIP;
diff --git a/archival/unzip.c b/archival/unzip.c
index 38a07e212..1ef026a9f 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -44,6 +44,9 @@
44 44
45#include "libbb.h" 45#include "libbb.h"
46#include "bb_archive.h" 46#include "bb_archive.h"
47#if ENABLE_PLATFORM_MINGW32 && __GNUC__
48#pragma pack(2)
49#endif
47 50
48enum { 51enum {
49#if BB_BIG_ENDIAN 52#if BB_BIG_ENDIAN
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
new file mode 100644
index 000000000..4a3303b9e
--- /dev/null
+++ b/configs/mingw32_defconfig
@@ -0,0 +1,1041 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.23.0-TIG-1656-g6d6d18d
4# Sun Dec 14 14:24:44 2014
5#
6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set
8CONFIG_PLATFORM_MINGW32=y
9
10#
11# Busybox Settings
12#
13
14#
15# General Configuration
16#
17CONFIG_DESKTOP=y
18CONFIG_EXTRA_COMPAT=y
19# CONFIG_INCLUDE_SUSv2 is not set
20CONFIG_USE_PORTABLE_CODE=y
21# CONFIG_PLATFORM_LINUX is not set
22CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
23# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
24# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
25CONFIG_SHOW_USAGE=y
26CONFIG_FEATURE_VERBOSE_USAGE=y
27CONFIG_FEATURE_COMPRESS_USAGE=y
28# CONFIG_FEATURE_INSTALLER is not set
29# CONFIG_INSTALL_NO_USR is not set
30# CONFIG_LOCALE_SUPPORT is not set
31# CONFIG_UNICODE_SUPPORT is not set
32# CONFIG_UNICODE_USING_LOCALE is not set
33# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
34CONFIG_SUBST_WCHAR=0
35CONFIG_LAST_SUPPORTED_WCHAR=0
36# CONFIG_UNICODE_COMBINING_WCHARS is not set
37# CONFIG_UNICODE_WIDE_WCHARS is not set
38# CONFIG_UNICODE_BIDI_SUPPORT is not set
39# CONFIG_UNICODE_NEUTRAL_TABLE is not set
40# CONFIG_UNICODE_PRESERVE_BROKEN is not set
41# CONFIG_PAM is not set
42# CONFIG_FEATURE_USE_SENDFILE is not set
43CONFIG_LONG_OPTS=y
44# CONFIG_FEATURE_DEVPTS is not set
45# CONFIG_FEATURE_CLEAN_UP is not set
46# CONFIG_FEATURE_UTMP is not set
47# CONFIG_FEATURE_WTMP is not set
48# CONFIG_FEATURE_PIDFILE is not set
49CONFIG_PID_FILE_PATH=""
50# CONFIG_FEATURE_SUID is not set
51# CONFIG_FEATURE_SUID_CONFIG is not set
52# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
53# CONFIG_SELINUX is not set
54CONFIG_FEATURE_PREFER_APPLETS=y
55CONFIG_BUSYBOX_EXEC_PATH=""
56# CONFIG_FEATURE_SYSLOG is not set
57# CONFIG_FEATURE_HAVE_RPC is not set
58
59#
60# Build Options
61#
62# CONFIG_STATIC is not set
63# CONFIG_PIE is not set
64# CONFIG_NOMMU is not set
65# CONFIG_BUILD_LIBBUSYBOX is not set
66# CONFIG_FEATURE_INDIVIDUAL is not set
67# CONFIG_FEATURE_SHARED_BUSYBOX is not set
68CONFIG_LFS=y
69CONFIG_NOGLOB=y
70CONFIG_CROSS_COMPILER_PREFIX="i686-w64-mingw32-"
71CONFIG_SYSROOT=""
72CONFIG_EXTRA_CFLAGS=""
73CONFIG_EXTRA_LDFLAGS=""
74CONFIG_EXTRA_LDLIBS=""
75
76#
77# Debugging Options
78#
79CONFIG_DEBUG=y
80# CONFIG_DEBUG_PESSIMIZE is not set
81# CONFIG_UNIT_TEST is not set
82# CONFIG_WERROR is not set
83CONFIG_NO_DEBUG_LIB=y
84# CONFIG_DMALLOC is not set
85# CONFIG_EFENCE is not set
86
87#
88# Installation Options ("make install" behavior)
89#
90CONFIG_INSTALL_APPLET_SYMLINKS=y
91# CONFIG_INSTALL_APPLET_HARDLINKS is not set
92# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
93# CONFIG_INSTALL_APPLET_DONT is not set
94# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
95# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
96# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
97CONFIG_PREFIX=""
98
99#
100# Busybox Library Tuning
101#
102# CONFIG_FEATURE_SYSTEMD is not set
103CONFIG_FEATURE_RTMINMAX=y
104CONFIG_PASSWORD_MINLEN=6
105CONFIG_MD5_SMALL=1
106CONFIG_SHA3_SMALL=1
107# CONFIG_FEATURE_FAST_TOP is not set
108# CONFIG_FEATURE_ETC_NETWORKS is not set
109# CONFIG_FEATURE_USE_TERMIOS is not set
110CONFIG_FEATURE_EDITING=y
111CONFIG_FEATURE_EDITING_MAX_LEN=1024
112CONFIG_FEATURE_EDITING_VI=y
113CONFIG_FEATURE_EDITING_HISTORY=255
114CONFIG_FEATURE_EDITING_SAVEHISTORY=y
115# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
116CONFIG_FEATURE_REVERSE_SEARCH=y
117CONFIG_FEATURE_TAB_COMPLETION=y
118CONFIG_FEATURE_USERNAME_COMPLETION=y
119CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
120# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
121CONFIG_FEATURE_NON_POSIX_CP=y
122# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
123CONFIG_FEATURE_COPYBUF_KB=4
124CONFIG_FEATURE_SKIP_ROOTFS=y
125# CONFIG_MONOTONIC_SYSCALL is not set
126CONFIG_IOCTL_HEX2STR_ERROR=y
127# CONFIG_FEATURE_HWIB is not set
128
129#
130# Applets
131#
132
133#
134# Archival Utilities
135#
136# CONFIG_FEATURE_SEAMLESS_XZ is not set
137# CONFIG_FEATURE_SEAMLESS_LZMA is not set
138# CONFIG_FEATURE_SEAMLESS_BZ2 is not set
139# CONFIG_FEATURE_SEAMLESS_GZ is not set
140# CONFIG_FEATURE_SEAMLESS_Z is not set
141CONFIG_AR=y
142CONFIG_FEATURE_AR_LONG_FILENAMES=y
143CONFIG_FEATURE_AR_CREATE=y
144CONFIG_UNCOMPRESS=y
145CONFIG_GUNZIP=y
146CONFIG_BUNZIP2=y
147CONFIG_UNLZMA=y
148CONFIG_FEATURE_LZMA_FAST=y
149CONFIG_LZMA=y
150CONFIG_UNXZ=y
151CONFIG_XZ=y
152CONFIG_BZIP2=y
153CONFIG_CPIO=y
154CONFIG_FEATURE_CPIO_O=y
155CONFIG_FEATURE_CPIO_P=y
156# CONFIG_DPKG is not set
157# CONFIG_DPKG_DEB is not set
158# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set
159CONFIG_GZIP=y
160CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
161CONFIG_GZIP_FAST=2
162CONFIG_LZOP=y
163# CONFIG_LZOP_COMPR_HIGH is not set
164# CONFIG_RPM2CPIO is not set
165# CONFIG_RPM is not set
166CONFIG_TAR=y
167CONFIG_FEATURE_TAR_CREATE=y
168# CONFIG_FEATURE_TAR_AUTODETECT is not set
169CONFIG_FEATURE_TAR_FROM=y
170CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
171# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
172CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
173CONFIG_FEATURE_TAR_LONG_OPTIONS=y
174# CONFIG_FEATURE_TAR_TO_COMMAND is not set
175# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
176CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
177# CONFIG_FEATURE_TAR_SELINUX is not set
178CONFIG_UNZIP=y
179
180#
181# Coreutils
182#
183CONFIG_BASENAME=y
184CONFIG_CAT=y
185CONFIG_DATE=y
186CONFIG_FEATURE_DATE_ISOFMT=y
187# CONFIG_FEATURE_DATE_NANO is not set
188CONFIG_FEATURE_DATE_COMPAT=y
189# CONFIG_HOSTID is not set
190# CONFIG_ID is not set
191# CONFIG_GROUPS is not set
192CONFIG_SHUF=y
193CONFIG_TEST=y
194CONFIG_FEATURE_TEST_64=y
195CONFIG_TOUCH=y
196# CONFIG_FEATURE_TOUCH_NODEREF is not set
197CONFIG_FEATURE_TOUCH_SUSV3=y
198CONFIG_TR=y
199CONFIG_FEATURE_TR_CLASSES=y
200CONFIG_FEATURE_TR_EQUIV=y
201CONFIG_UNLINK=y
202CONFIG_BASE64=y
203# CONFIG_WHO is not set
204# CONFIG_USERS is not set
205CONFIG_CAL=y
206CONFIG_CATV=y
207# CONFIG_CHGRP is not set
208CONFIG_CHMOD=y
209# CONFIG_CHOWN is not set
210# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
211# CONFIG_CHROOT is not set
212CONFIG_CKSUM=y
213CONFIG_COMM=y
214CONFIG_CP=y
215CONFIG_FEATURE_CP_LONG_OPTIONS=y
216CONFIG_CUT=y
217CONFIG_DD=y
218# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
219# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
220CONFIG_FEATURE_DD_IBS_OBS=y
221CONFIG_DF=y
222# CONFIG_FEATURE_DF_FANCY is not set
223CONFIG_DIRNAME=y
224CONFIG_DOS2UNIX=y
225CONFIG_UNIX2DOS=y
226CONFIG_DU=y
227CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
228CONFIG_ECHO=y
229CONFIG_FEATURE_FANCY_ECHO=y
230CONFIG_ENV=y
231CONFIG_FEATURE_ENV_LONG_OPTIONS=y
232CONFIG_EXPAND=y
233CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
234CONFIG_EXPR=y
235CONFIG_EXPR_MATH_SUPPORT_64=y
236CONFIG_FALSE=y
237CONFIG_FOLD=y
238# CONFIG_FSYNC is not set
239CONFIG_HEAD=y
240CONFIG_FEATURE_FANCY_HEAD=y
241# CONFIG_INSTALL is not set
242# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
243# CONFIG_LN is not set
244# CONFIG_LOGNAME is not set
245CONFIG_LS=y
246CONFIG_FEATURE_LS_FILETYPES=y
247CONFIG_FEATURE_LS_FOLLOWLINKS=y
248CONFIG_FEATURE_LS_RECURSIVE=y
249CONFIG_FEATURE_LS_SORTFILES=y
250CONFIG_FEATURE_LS_TIMESTAMPS=y
251CONFIG_FEATURE_LS_USERNAME=y
252CONFIG_FEATURE_LS_COLOR=y
253CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
254CONFIG_MD5SUM=y
255CONFIG_MKDIR=y
256CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
257# CONFIG_MKFIFO is not set
258# CONFIG_MKNOD is not set
259CONFIG_MV=y
260CONFIG_FEATURE_MV_LONG_OPTIONS=y
261# CONFIG_NICE is not set
262# CONFIG_NOHUP is not set
263CONFIG_OD=y
264CONFIG_PRINTENV=y
265CONFIG_PRINTF=y
266CONFIG_PWD=y
267# CONFIG_READLINK is not set
268# CONFIG_FEATURE_READLINK_FOLLOW is not set
269# CONFIG_REALPATH is not set
270CONFIG_RM=y
271CONFIG_RMDIR=y
272CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
273CONFIG_SEQ=y
274CONFIG_SHA1SUM=y
275CONFIG_SHA256SUM=y
276CONFIG_SHA512SUM=y
277CONFIG_SHA3SUM=y
278CONFIG_SLEEP=y
279CONFIG_FEATURE_FANCY_SLEEP=y
280# CONFIG_FEATURE_FLOAT_SLEEP is not set
281CONFIG_SORT=y
282CONFIG_FEATURE_SORT_BIG=y
283CONFIG_SPLIT=y
284CONFIG_FEATURE_SPLIT_FANCY=y
285CONFIG_STAT=y
286CONFIG_FEATURE_STAT_FORMAT=y
287# CONFIG_STTY is not set
288CONFIG_SUM=y
289# CONFIG_SYNC is not set
290CONFIG_TAC=y
291CONFIG_TAIL=y
292CONFIG_FEATURE_FANCY_TAIL=y
293CONFIG_TEE=y
294CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
295CONFIG_TRUE=y
296# CONFIG_TTY is not set
297CONFIG_UNAME=y
298CONFIG_UNEXPAND=y
299CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
300CONFIG_UNIQ=y
301CONFIG_USLEEP=y
302CONFIG_UUDECODE=y
303CONFIG_UUENCODE=y
304CONFIG_WC=y
305CONFIG_FEATURE_WC_LARGE=y
306CONFIG_WHOAMI=y
307CONFIG_YES=y
308
309#
310# Common options
311#
312CONFIG_FEATURE_VERBOSE=y
313
314#
315# Common options for cp and mv
316#
317# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
318
319#
320# Common options for ls, more and telnet
321#
322CONFIG_FEATURE_AUTOWIDTH=y
323
324#
325# Common options for df, du, ls
326#
327CONFIG_FEATURE_HUMAN_READABLE=y
328
329#
330# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
331#
332CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
333
334#
335# Console Utilities
336#
337# CONFIG_CHVT is not set
338# CONFIG_FGCONSOLE is not set
339CONFIG_CLEAR=y
340# CONFIG_DEALLOCVT is not set
341# CONFIG_DUMPKMAP is not set
342# CONFIG_KBD_MODE is not set
343# CONFIG_LOADFONT is not set
344# CONFIG_LOADKMAP is not set
345# CONFIG_OPENVT is not set
346# CONFIG_RESET is not set
347# CONFIG_RESIZE is not set
348# CONFIG_FEATURE_RESIZE_PRINT is not set
349# CONFIG_SETCONSOLE is not set
350# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
351# CONFIG_SETFONT is not set
352# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
353CONFIG_DEFAULT_SETFONT_DIR=""
354# CONFIG_SETKEYCODES is not set
355# CONFIG_SETLOGCONS is not set
356# CONFIG_SHOWKEY is not set
357# CONFIG_FEATURE_LOADFONT_PSF2 is not set
358# CONFIG_FEATURE_LOADFONT_RAW is not set
359
360#
361# Debian Utilities
362#
363CONFIG_MKTEMP=y
364# CONFIG_PIPE_PROGRESS is not set
365# CONFIG_RUN_PARTS is not set
366# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
367# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
368# CONFIG_START_STOP_DAEMON is not set
369# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
370# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
371CONFIG_WHICH=y
372
373#
374# Editors
375#
376CONFIG_AWK=y
377CONFIG_FEATURE_AWK_LIBM=y
378CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
379CONFIG_CMP=y
380CONFIG_DIFF=y
381CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
382CONFIG_FEATURE_DIFF_DIR=y
383CONFIG_ED=y
384CONFIG_PATCH=y
385CONFIG_SED=y
386CONFIG_VI=y
387CONFIG_FEATURE_VI_MAX_LEN=4096
388CONFIG_FEATURE_VI_8BIT=y
389CONFIG_FEATURE_VI_COLON=y
390CONFIG_FEATURE_VI_YANKMARK=y
391CONFIG_FEATURE_VI_SEARCH=y
392# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
393# CONFIG_FEATURE_VI_USE_SIGNALS is not set
394CONFIG_FEATURE_VI_DOT_CMD=y
395CONFIG_FEATURE_VI_READONLY=y
396CONFIG_FEATURE_VI_SETOPTS=y
397CONFIG_FEATURE_VI_SET=y
398CONFIG_FEATURE_VI_WIN_RESIZE=y
399CONFIG_FEATURE_VI_ASK_TERMINAL=y
400CONFIG_FEATURE_VI_UNDO=y
401CONFIG_FEATURE_VI_UNDO_QUEUE=y
402CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
403CONFIG_FEATURE_ALLOW_EXEC=y
404
405#
406# Finding Utilities
407#
408CONFIG_FIND=y
409CONFIG_FEATURE_FIND_PRINT0=y
410CONFIG_FEATURE_FIND_MTIME=y
411CONFIG_FEATURE_FIND_MMIN=y
412# CONFIG_FEATURE_FIND_PERM is not set
413CONFIG_FEATURE_FIND_TYPE=y
414# CONFIG_FEATURE_FIND_XDEV is not set
415CONFIG_FEATURE_FIND_MAXDEPTH=y
416CONFIG_FEATURE_FIND_NEWER=y
417# CONFIG_FEATURE_FIND_INUM is not set
418# CONFIG_FEATURE_FIND_EXEC is not set
419# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
420# CONFIG_FEATURE_FIND_USER is not set
421# CONFIG_FEATURE_FIND_GROUP is not set
422CONFIG_FEATURE_FIND_NOT=y
423CONFIG_FEATURE_FIND_DEPTH=y
424CONFIG_FEATURE_FIND_PAREN=y
425CONFIG_FEATURE_FIND_SIZE=y
426CONFIG_FEATURE_FIND_PRUNE=y
427CONFIG_FEATURE_FIND_DELETE=y
428CONFIG_FEATURE_FIND_PATH=y
429CONFIG_FEATURE_FIND_REGEX=y
430# CONFIG_FEATURE_FIND_CONTEXT is not set
431# CONFIG_FEATURE_FIND_LINKS is not set
432CONFIG_GREP=y
433CONFIG_FEATURE_GREP_EGREP_ALIAS=y
434CONFIG_FEATURE_GREP_FGREP_ALIAS=y
435CONFIG_FEATURE_GREP_CONTEXT=y
436CONFIG_XARGS=y
437CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
438CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
439CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
440CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
441CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
442
443#
444# Init Utilities
445#
446# CONFIG_BOOTCHARTD is not set
447# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
448# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
449# CONFIG_HALT is not set
450# CONFIG_FEATURE_CALL_TELINIT is not set
451CONFIG_TELINIT_PATH=""
452# CONFIG_INIT is not set
453# CONFIG_FEATURE_USE_INITTAB is not set
454# CONFIG_FEATURE_KILL_REMOVED is not set
455CONFIG_FEATURE_KILL_DELAY=0
456# CONFIG_FEATURE_INIT_SCTTY is not set
457# CONFIG_FEATURE_INIT_SYSLOG is not set
458# CONFIG_FEATURE_EXTRA_QUIET is not set
459# CONFIG_FEATURE_INIT_COREDUMPS is not set
460# CONFIG_FEATURE_INITRD is not set
461CONFIG_INIT_TERMINAL_TYPE=""
462# CONFIG_MESG is not set
463# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
464
465#
466# Login/Password Management Utilities
467#
468# CONFIG_ADD_SHELL is not set
469# CONFIG_REMOVE_SHELL is not set
470# CONFIG_FEATURE_SHADOWPASSWDS is not set
471# CONFIG_USE_BB_PWD_GRP is not set
472# CONFIG_USE_BB_SHADOW is not set
473# CONFIG_USE_BB_CRYPT is not set
474# CONFIG_USE_BB_CRYPT_SHA is not set
475# CONFIG_ADDUSER is not set
476# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
477# CONFIG_FEATURE_CHECK_NAMES is not set
478CONFIG_LAST_ID=0
479CONFIG_FIRST_SYSTEM_ID=0
480CONFIG_LAST_SYSTEM_ID=0
481# CONFIG_ADDGROUP is not set
482# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
483# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
484# CONFIG_DELUSER is not set
485# CONFIG_DELGROUP is not set
486# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
487# CONFIG_GETTY is not set
488# CONFIG_LOGIN is not set
489# CONFIG_LOGIN_SESSION_AS_CHILD is not set
490# CONFIG_LOGIN_SCRIPTS is not set
491# CONFIG_FEATURE_NOLOGIN is not set
492# CONFIG_FEATURE_SECURETTY is not set
493# CONFIG_PASSWD is not set
494# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
495# CONFIG_CRYPTPW is not set
496# CONFIG_CHPASSWD is not set
497CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
498# CONFIG_SU is not set
499# CONFIG_FEATURE_SU_SYSLOG is not set
500# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
501# CONFIG_SULOGIN is not set
502# CONFIG_VLOCK is not set
503
504#
505# Linux Ext2 FS Progs
506#
507# CONFIG_CHATTR is not set
508# CONFIG_FSCK is not set
509# CONFIG_LSATTR is not set
510# CONFIG_TUNE2FS is not set
511
512#
513# Linux Module Utilities
514#
515# CONFIG_MODINFO is not set
516# CONFIG_MODPROBE_SMALL is not set
517# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set
518# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
519# CONFIG_INSMOD is not set
520# CONFIG_RMMOD is not set
521# CONFIG_LSMOD is not set
522# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
523# CONFIG_MODPROBE is not set
524# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
525# CONFIG_DEPMOD is not set
526
527#
528# Options common to multiple modutils
529#
530# CONFIG_FEATURE_2_4_MODULES is not set
531# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
532# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
533# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
534# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
535# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
536# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
537# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
538# CONFIG_FEATURE_MODUTILS_ALIAS is not set
539# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
540CONFIG_DEFAULT_MODULES_DIR=""
541CONFIG_DEFAULT_DEPMOD_FILE=""
542
543#
544# Linux System Utilities
545#
546# CONFIG_BLOCKDEV is not set
547# CONFIG_FATATTR is not set
548# CONFIG_FSTRIM is not set
549# CONFIG_MDEV is not set
550# CONFIG_FEATURE_MDEV_CONF is not set
551# CONFIG_FEATURE_MDEV_RENAME is not set
552# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
553# CONFIG_FEATURE_MDEV_EXEC is not set
554# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
555CONFIG_REV=y
556# CONFIG_ACPID is not set
557# CONFIG_FEATURE_ACPID_COMPAT is not set
558# CONFIG_BLKID is not set
559# CONFIG_FEATURE_BLKID_TYPE is not set
560# CONFIG_DMESG is not set
561# CONFIG_FEATURE_DMESG_PRETTY is not set
562# CONFIG_FBSET is not set
563# CONFIG_FEATURE_FBSET_FANCY is not set
564# CONFIG_FEATURE_FBSET_READMODE is not set
565# CONFIG_FDFLUSH is not set
566# CONFIG_FDFORMAT is not set
567# CONFIG_FDISK is not set
568# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
569# CONFIG_FEATURE_FDISK_WRITABLE is not set
570# CONFIG_FEATURE_AIX_LABEL is not set
571# CONFIG_FEATURE_SGI_LABEL is not set
572# CONFIG_FEATURE_SUN_LABEL is not set
573# CONFIG_FEATURE_OSF_LABEL is not set
574# CONFIG_FEATURE_GPT_LABEL is not set
575# CONFIG_FEATURE_FDISK_ADVANCED is not set
576# CONFIG_FINDFS is not set
577# CONFIG_FLOCK is not set
578# CONFIG_FREERAMDISK is not set
579# CONFIG_FSCK_MINIX is not set
580# CONFIG_MKFS_EXT2 is not set
581# CONFIG_MKFS_MINIX is not set
582# CONFIG_FEATURE_MINIX2 is not set
583# CONFIG_MKFS_REISER is not set
584# CONFIG_MKFS_VFAT is not set
585CONFIG_GETOPT=y
586CONFIG_FEATURE_GETOPT_LONG=y
587CONFIG_HEXDUMP=y
588CONFIG_FEATURE_HEXDUMP_REVERSE=y
589CONFIG_HD=y
590# CONFIG_HWCLOCK is not set
591# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
592# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
593# CONFIG_IPCRM is not set
594# CONFIG_IPCS is not set
595# CONFIG_LOSETUP is not set
596# CONFIG_LSPCI is not set
597# CONFIG_LSUSB is not set
598# CONFIG_MKSWAP is not set
599# CONFIG_FEATURE_MKSWAP_UUID is not set
600# CONFIG_MORE is not set
601# CONFIG_MOUNT is not set
602# CONFIG_FEATURE_MOUNT_FAKE is not set
603# CONFIG_FEATURE_MOUNT_VERBOSE is not set
604# CONFIG_FEATURE_MOUNT_HELPERS is not set
605# CONFIG_FEATURE_MOUNT_LABEL is not set
606# CONFIG_FEATURE_MOUNT_NFS is not set
607# CONFIG_FEATURE_MOUNT_CIFS is not set
608# CONFIG_FEATURE_MOUNT_FLAGS is not set
609# CONFIG_FEATURE_MOUNT_FSTAB is not set
610# CONFIG_PIVOT_ROOT is not set
611# CONFIG_RDATE is not set
612# CONFIG_RDEV is not set
613# CONFIG_READPROFILE is not set
614# CONFIG_RTCWAKE is not set
615# CONFIG_SCRIPT is not set
616# CONFIG_SCRIPTREPLAY is not set
617# CONFIG_SETARCH is not set
618# CONFIG_SWAPONOFF is not set
619# CONFIG_FEATURE_SWAPON_DISCARD is not set
620# CONFIG_FEATURE_SWAPON_PRI is not set
621# CONFIG_SWITCH_ROOT is not set
622# CONFIG_UMOUNT is not set
623# CONFIG_FEATURE_UMOUNT_ALL is not set
624# CONFIG_FEATURE_MOUNT_LOOP is not set
625# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
626# CONFIG_FEATURE_MTAB_SUPPORT is not set
627# CONFIG_VOLUMEID is not set
628# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
629# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
630# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
631# CONFIG_FEATURE_VOLUMEID_EXT is not set
632# CONFIG_FEATURE_VOLUMEID_F2FS is not set
633# CONFIG_FEATURE_VOLUMEID_FAT is not set
634# CONFIG_FEATURE_VOLUMEID_HFS is not set
635# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
636# CONFIG_FEATURE_VOLUMEID_JFS is not set
637# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
638# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
639# CONFIG_FEATURE_VOLUMEID_LUKS is not set
640# CONFIG_FEATURE_VOLUMEID_NILFS is not set
641# CONFIG_FEATURE_VOLUMEID_NTFS is not set
642# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
643# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
644# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
645# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
646# CONFIG_FEATURE_VOLUMEID_SYSV is not set
647# CONFIG_FEATURE_VOLUMEID_UDF is not set
648# CONFIG_FEATURE_VOLUMEID_XFS is not set
649
650#
651# Miscellaneous Utilities
652#
653# CONFIG_CONSPY is not set
654# CONFIG_CROND is not set
655# CONFIG_FEATURE_CROND_D is not set
656# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
657CONFIG_FEATURE_CROND_DIR=""
658# CONFIG_LESS is not set
659CONFIG_FEATURE_LESS_MAXLINES=0
660# CONFIG_FEATURE_LESS_BRACKETS is not set
661# CONFIG_FEATURE_LESS_FLAGS is not set
662# CONFIG_FEATURE_LESS_MARKS is not set
663# CONFIG_FEATURE_LESS_REGEXP is not set
664# CONFIG_FEATURE_LESS_WINCH is not set
665# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
666# CONFIG_FEATURE_LESS_DASHCMD is not set
667# CONFIG_FEATURE_LESS_LINENUMS is not set
668# CONFIG_NANDWRITE is not set
669# CONFIG_NANDDUMP is not set
670# CONFIG_RFKILL is not set
671# CONFIG_SETSERIAL is not set
672# CONFIG_TASKSET is not set
673# CONFIG_FEATURE_TASKSET_FANCY is not set
674# CONFIG_UBIATTACH is not set
675# CONFIG_UBIDETACH is not set
676# CONFIG_UBIMKVOL is not set
677# CONFIG_UBIRMVOL is not set
678# CONFIG_UBIRSVOL is not set
679# CONFIG_UBIUPDATEVOL is not set
680# CONFIG_WALL is not set
681# CONFIG_ADJTIMEX is not set
682CONFIG_BBCONFIG=y
683CONFIG_FEATURE_COMPRESS_BBCONFIG=y
684# CONFIG_BEEP is not set
685CONFIG_FEATURE_BEEP_FREQ=0
686CONFIG_FEATURE_BEEP_LENGTH_MS=0
687# CONFIG_CHAT is not set
688# CONFIG_FEATURE_CHAT_NOFAIL is not set
689# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
690# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
691# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
692# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
693# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
694# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
695# CONFIG_CHRT is not set
696# CONFIG_CRONTAB is not set
697CONFIG_DC=y
698CONFIG_FEATURE_DC_LIBM=y
699# CONFIG_DEVFSD is not set
700# CONFIG_DEVFSD_MODLOAD is not set
701# CONFIG_DEVFSD_FG_NP is not set
702# CONFIG_DEVFSD_VERBOSE is not set
703# CONFIG_FEATURE_DEVFS is not set
704# CONFIG_DEVMEM is not set
705# CONFIG_EJECT is not set
706# CONFIG_FEATURE_EJECT_SCSI is not set
707# CONFIG_FBSPLASH is not set
708# CONFIG_FLASHCP is not set
709# CONFIG_FLASH_LOCK is not set
710# CONFIG_FLASH_UNLOCK is not set
711# CONFIG_FLASH_ERASEALL is not set
712# CONFIG_IONICE is not set
713# CONFIG_INOTIFYD is not set
714# CONFIG_LAST is not set
715# CONFIG_FEATURE_LAST_SMALL is not set
716# CONFIG_FEATURE_LAST_FANCY is not set
717# CONFIG_HDPARM is not set
718# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
719# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
720# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
721# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
722# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
723# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
724# CONFIG_MAKEDEVS is not set
725# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
726# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
727CONFIG_MAN=y
728# CONFIG_MICROCOM is not set
729# CONFIG_MOUNTPOINT is not set
730# CONFIG_MT is not set
731# CONFIG_RAIDAUTORUN is not set
732# CONFIG_READAHEAD is not set
733# CONFIG_RUNLEVEL is not set
734# CONFIG_RX is not set
735# CONFIG_SETSID is not set
736CONFIG_STRINGS=y
737# CONFIG_TIME is not set
738# CONFIG_TIMEOUT is not set
739# CONFIG_TTYSIZE is not set
740# CONFIG_VOLNAME is not set
741# CONFIG_WATCHDOG is not set
742
743#
744# Networking Utilities
745#
746# CONFIG_NAMEIF is not set
747# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
748# CONFIG_NBDCLIENT is not set
749# CONFIG_NC is not set
750# CONFIG_NC_SERVER is not set
751# CONFIG_NC_EXTRA is not set
752# CONFIG_NC_110_COMPAT is not set
753# CONFIG_PING is not set
754# CONFIG_PING6 is not set
755# CONFIG_FEATURE_FANCY_PING is not set
756# CONFIG_WHOIS is not set
757# CONFIG_FEATURE_IPV6 is not set
758# CONFIG_FEATURE_UNIX_LOCAL is not set
759# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set
760# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
761# CONFIG_ARP is not set
762# CONFIG_ARPING is not set
763# CONFIG_BRCTL is not set
764# CONFIG_FEATURE_BRCTL_FANCY is not set
765# CONFIG_FEATURE_BRCTL_SHOW is not set
766# CONFIG_DNSD is not set
767# CONFIG_ETHER_WAKE is not set
768# CONFIG_FAKEIDENTD is not set
769# CONFIG_FTPD is not set
770# CONFIG_FEATURE_FTP_WRITE is not set
771# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
772# CONFIG_FEATURE_FTP_AUTHENTICATION is not set
773CONFIG_FTPGET=y
774CONFIG_FTPPUT=y
775CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
776# CONFIG_HOSTNAME is not set
777# CONFIG_HTTPD is not set
778# CONFIG_FEATURE_HTTPD_RANGES is not set
779# CONFIG_FEATURE_HTTPD_SETUID is not set
780# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
781# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
782# CONFIG_FEATURE_HTTPD_CGI is not set
783# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
784# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
785# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
786# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
787# CONFIG_FEATURE_HTTPD_PROXY is not set
788# CONFIG_FEATURE_HTTPD_GZIP is not set
789# CONFIG_IFCONFIG is not set
790# CONFIG_FEATURE_IFCONFIG_STATUS is not set
791# CONFIG_FEATURE_IFCONFIG_SLIP is not set
792# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
793# CONFIG_FEATURE_IFCONFIG_HW is not set
794# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
795# CONFIG_IFENSLAVE is not set
796# CONFIG_IFPLUGD is not set
797# CONFIG_IFUPDOWN is not set
798CONFIG_IFUPDOWN_IFSTATE_PATH=""
799# CONFIG_FEATURE_IFUPDOWN_IP is not set
800# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set
801# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
802# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
803# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
804# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
805# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
806# CONFIG_INETD is not set
807# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
808# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
809# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
810# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
811# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
812# CONFIG_FEATURE_INETD_RPC is not set
813# CONFIG_IP is not set
814# CONFIG_FEATURE_IP_ADDRESS is not set
815# CONFIG_FEATURE_IP_LINK is not set
816# CONFIG_FEATURE_IP_ROUTE is not set
817# CONFIG_FEATURE_IP_TUNNEL is not set
818# CONFIG_FEATURE_IP_RULE is not set
819# CONFIG_FEATURE_IP_SHORT_FORMS is not set
820# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
821# CONFIG_IPADDR is not set
822# CONFIG_IPLINK is not set
823# CONFIG_IPROUTE is not set
824# CONFIG_IPTUNNEL is not set
825# CONFIG_IPRULE is not set
826# CONFIG_IPCALC is not set
827# CONFIG_FEATURE_IPCALC_FANCY is not set
828# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
829# CONFIG_NETSTAT is not set
830# CONFIG_FEATURE_NETSTAT_WIDE is not set
831# CONFIG_FEATURE_NETSTAT_PRG is not set
832# CONFIG_NSLOOKUP is not set
833# CONFIG_NTPD is not set
834# CONFIG_FEATURE_NTPD_SERVER is not set
835# CONFIG_FEATURE_NTPD_CONF is not set
836# CONFIG_PSCAN is not set
837# CONFIG_ROUTE is not set
838# CONFIG_SLATTACH is not set
839# CONFIG_TCPSVD is not set
840# CONFIG_TELNET is not set
841# CONFIG_FEATURE_TELNET_TTYPE is not set
842# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
843# CONFIG_TELNETD is not set
844# CONFIG_FEATURE_TELNETD_STANDALONE is not set
845# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
846# CONFIG_TFTP is not set
847# CONFIG_TFTPD is not set
848# CONFIG_FEATURE_TFTP_GET is not set
849# CONFIG_FEATURE_TFTP_PUT is not set
850# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
851# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
852# CONFIG_TFTP_DEBUG is not set
853# CONFIG_TRACEROUTE is not set
854# CONFIG_TRACEROUTE6 is not set
855# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
856# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set
857# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
858# CONFIG_TUNCTL is not set
859# CONFIG_FEATURE_TUNCTL_UG is not set
860# CONFIG_UDHCPC6 is not set
861# CONFIG_UDHCPD is not set
862# CONFIG_DHCPRELAY is not set
863# CONFIG_DUMPLEASES is not set
864# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
865# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
866CONFIG_DHCPD_LEASES_FILE=""
867# CONFIG_UDHCPC is not set
868# CONFIG_FEATURE_UDHCPC_ARPING is not set
869# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
870# CONFIG_FEATURE_UDHCP_PORT is not set
871CONFIG_UDHCP_DEBUG=0
872# CONFIG_FEATURE_UDHCP_RFC3397 is not set
873# CONFIG_FEATURE_UDHCP_8021Q is not set
874CONFIG_UDHCPC_DEFAULT_SCRIPT=""
875CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
876CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
877# CONFIG_UDPSVD is not set
878# CONFIG_VCONFIG is not set
879CONFIG_WGET=y
880# CONFIG_FEATURE_WGET_STATUSBAR is not set
881# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
882CONFIG_FEATURE_WGET_LONG_OPTIONS=y
883# CONFIG_FEATURE_WGET_TIMEOUT is not set
884# CONFIG_ZCIP is not set
885
886#
887# Print Utilities
888#
889# CONFIG_LPD is not set
890# CONFIG_LPR is not set
891# CONFIG_LPQ is not set
892
893#
894# Mail Utilities
895#
896# CONFIG_MAKEMIME is not set
897CONFIG_FEATURE_MIME_CHARSET=""
898# CONFIG_POPMAILDIR is not set
899# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
900# CONFIG_REFORMIME is not set
901# CONFIG_FEATURE_REFORMIME_COMPAT is not set
902# CONFIG_SENDMAIL is not set
903
904#
905# Process Utilities
906#
907# CONFIG_IOSTAT is not set
908# CONFIG_LSOF is not set
909# CONFIG_MPSTAT is not set
910# CONFIG_NMETER is not set
911# CONFIG_PMAP is not set
912# CONFIG_POWERTOP is not set
913# CONFIG_PSTREE is not set
914# CONFIG_PWDX is not set
915# CONFIG_SMEMCAP is not set
916# CONFIG_TOP is not set
917# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
918# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
919# CONFIG_FEATURE_TOP_SMP_CPU is not set
920# CONFIG_FEATURE_TOP_DECIMALS is not set
921# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
922# CONFIG_FEATURE_TOPMEM is not set
923# CONFIG_UPTIME is not set
924# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
925# CONFIG_FREE is not set
926# CONFIG_FUSER is not set
927CONFIG_KILL=y
928CONFIG_KILLALL=y
929# CONFIG_KILLALL5 is not set
930CONFIG_PGREP=y
931CONFIG_PIDOF=y
932CONFIG_FEATURE_PIDOF_SINGLE=y
933CONFIG_FEATURE_PIDOF_OMIT=y
934# CONFIG_PKILL is not set
935CONFIG_PS=y
936# CONFIG_FEATURE_PS_WIDE is not set
937# CONFIG_FEATURE_PS_LONG is not set
938# CONFIG_FEATURE_PS_TIME is not set
939# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
940# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
941# CONFIG_RENICE is not set
942# CONFIG_BB_SYSCTL is not set
943# CONFIG_FEATURE_SHOW_THREADS is not set
944# CONFIG_WATCH is not set
945
946#
947# Runit Utilities
948#
949# CONFIG_RUNSV is not set
950# CONFIG_RUNSVDIR is not set
951# CONFIG_FEATURE_RUNSVDIR_LOG is not set
952# CONFIG_SV is not set
953CONFIG_SV_DEFAULT_SERVICE_DIR=""
954# CONFIG_SVLOGD is not set
955# CONFIG_CHPST is not set
956# CONFIG_SETUIDGID is not set
957# CONFIG_ENVUIDGID is not set
958# CONFIG_ENVDIR is not set
959# CONFIG_SOFTLIMIT is not set
960# CONFIG_CHCON is not set
961# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
962# CONFIG_GETENFORCE is not set
963# CONFIG_GETSEBOOL is not set
964# CONFIG_LOAD_POLICY is not set
965# CONFIG_MATCHPATHCON is not set
966# CONFIG_RESTORECON is not set
967# CONFIG_RUNCON is not set
968# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
969# CONFIG_SELINUXENABLED is not set
970# CONFIG_SETENFORCE is not set
971# CONFIG_SETFILES is not set
972# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
973# CONFIG_SETSEBOOL is not set
974# CONFIG_SESTATUS is not set
975
976#
977# Shells
978#
979CONFIG_ASH=y
980CONFIG_ASH_BASH_COMPAT=y
981# CONFIG_ASH_IDLE_TIMEOUT is not set
982# CONFIG_ASH_JOB_CONTROL is not set
983CONFIG_ASH_ALIAS=y
984CONFIG_ASH_GETOPTS=y
985CONFIG_ASH_BUILTIN_ECHO=y
986CONFIG_ASH_BUILTIN_PRINTF=y
987CONFIG_ASH_BUILTIN_TEST=y
988CONFIG_ASH_HELP=y
989CONFIG_ASH_CMDCMD=y
990# CONFIG_ASH_MAIL is not set
991CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
992CONFIG_ASH_RANDOM_SUPPORT=y
993CONFIG_ASH_EXPAND_PRMT=y
994# CONFIG_CTTYHACK is not set
995# CONFIG_HUSH is not set
996# CONFIG_HUSH_BASH_COMPAT is not set
997# CONFIG_HUSH_BRACE_EXPANSION is not set
998# CONFIG_HUSH_HELP is not set
999# CONFIG_HUSH_INTERACTIVE is not set
1000# CONFIG_HUSH_SAVEHISTORY is not set
1001# CONFIG_HUSH_JOB is not set
1002# CONFIG_HUSH_TICK is not set
1003# CONFIG_HUSH_IF is not set
1004# CONFIG_HUSH_LOOPS is not set
1005# CONFIG_HUSH_CASE is not set
1006# CONFIG_HUSH_FUNCTIONS is not set
1007# CONFIG_HUSH_LOCAL is not set
1008# CONFIG_HUSH_RANDOM_SUPPORT is not set
1009# CONFIG_HUSH_EXPORT_N is not set
1010# CONFIG_HUSH_MODE_X is not set
1011# CONFIG_MSH is not set
1012CONFIG_FEATURE_SH_IS_ASH=y
1013# CONFIG_FEATURE_SH_IS_HUSH is not set
1014# CONFIG_FEATURE_SH_IS_NONE is not set
1015CONFIG_FEATURE_BASH_IS_ASH=y
1016# CONFIG_FEATURE_BASH_IS_HUSH is not set
1017# CONFIG_FEATURE_BASH_IS_NONE is not set
1018CONFIG_SH_MATH_SUPPORT=y
1019CONFIG_SH_MATH_SUPPORT_64=y
1020CONFIG_FEATURE_SH_EXTRA_QUIET=y
1021CONFIG_FEATURE_SH_STANDALONE=y
1022CONFIG_FEATURE_SH_NOFORK=y
1023CONFIG_FEATURE_SH_HISTFILESIZE=y
1024
1025#
1026# System Logging Utilities
1027#
1028# CONFIG_SYSLOGD is not set
1029# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1030# CONFIG_FEATURE_REMOTE_LOG is not set
1031# CONFIG_FEATURE_SYSLOGD_DUP is not set
1032# CONFIG_FEATURE_SYSLOGD_CFG is not set
1033CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1034# CONFIG_FEATURE_IPC_SYSLOG is not set
1035CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1036# CONFIG_LOGREAD is not set
1037# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1038# CONFIG_FEATURE_KMSG_SYSLOG is not set
1039# CONFIG_KLOGD is not set
1040# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1041# CONFIG_LOGGER is not set
diff --git a/coreutils/Config.src b/coreutils/Config.src
index 68c717883..2914fc36a 100644
--- a/coreutils/Config.src
+++ b/coreutils/Config.src
@@ -584,7 +584,6 @@ config FEATURE_SPLIT_FANCY
584config STAT 584config STAT
585 bool "stat" 585 bool "stat"
586 default y 586 default y
587 select PLATFORM_LINUX # statfs()
588 help 587 help
589 display file or filesystem status. 588 display file or filesystem status.
590 589
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 2838f6341..db61f665e 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -203,6 +203,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
203#endif 203#endif
204 }; 204 };
205 smallint exitcode = EXIT_FAILURE; 205 smallint exitcode = EXIT_FAILURE;
206 int devzero = 0;
206 int i; 207 int i;
207 size_t ibs = 512; 208 size_t ibs = 512;
208 char *ibuf; 209 char *ibuf;
@@ -334,7 +335,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
334#endif 335#endif
335 336
336 if (infile) { 337 if (infile) {
337 xmove_fd(xopen(infile, O_RDONLY), ifd); 338 if (ENABLE_PLATFORM_MINGW32 && !strcmp(infile, "/dev/zero")) {
339 flags |= FLAG_NOERROR;
340 devzero = 1;
341 } else {
342 xmove_fd(xopen(infile, O_RDONLY), ifd);
343 }
338 } else { 344 } else {
339 infile = bb_msg_standard_input; 345 infile = bb_msg_standard_input;
340 } 346 }
@@ -361,7 +367,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
361 } else { 367 } else {
362 outfile = bb_msg_standard_output; 368 outfile = bb_msg_standard_output;
363 } 369 }
364 if (skip) { 370 if (skip && !devzero) {
365 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) { 371 if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) {
366 do { 372 do {
367 ssize_t n = safe_read(ifd, ibuf, ibs); 373 ssize_t n = safe_read(ifd, ibuf, ibs);
@@ -380,7 +386,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
380 while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { 386 while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
381 ssize_t n; 387 ssize_t n;
382 388
383 n = safe_read(ifd, ibuf, ibs); 389 if (devzero) {
390 memset(ibuf, 0, ibs);
391 n = ibs;
392 }
393 else
394 n = safe_read(ifd, ibuf, ibs);
384 if (n == 0) 395 if (n == 0)
385 break; 396 break;
386 if (n < 0) { 397 if (n < 0) {
@@ -456,7 +467,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
456 if (write_and_stats(obuf, oc, obs, outfile)) 467 if (write_and_stats(obuf, oc, obs, outfile))
457 goto out_status; 468 goto out_status;
458 } 469 }
459 if (close(ifd) < 0) { 470
471 if (!devzero && close(ifd) < 0) {
460 die_infile: 472 die_infile:
461 bb_simple_perror_msg_and_die(infile); 473 bb_simple_perror_msg_and_die(infile);
462 } 474 }
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index 2c26dda16..34ceefb1c 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -100,6 +100,13 @@ typedef long long llong;
100# define LDBL_DIG DBL_DIG 100# define LDBL_DIG DBL_DIG
101#endif 101#endif
102 102
103#if ENABLE_PLATFORM_MINGW32
104/* symbol conflict */
105#define CHAR SIZE_CHAR
106#define SHORT SIZE_SHORT
107#define LONG SIZE_LONG
108#define INT SIZE_INT
109#endif
103enum size_spec { 110enum size_spec {
104 NO_SIZE, 111 NO_SIZE,
105 CHAR, 112 CHAR,
@@ -387,8 +394,8 @@ print_named_ascii(size_t n_bytes, const char *block,
387 " sp" 394 " sp"
388 }; 395 };
389 // buf[N] pos: 01234 56789 396 // buf[N] pos: 01234 56789
390 char buf[12] = " x\0 0xx\0"; 397 char buf[12] = " x\0 xxx\0";
391 // actually " x\0 xxx\0", but want to share string with print_ascii. 398 // share string with print_ascii.
392 // [12] because we take three 32bit stack slots anyway, and 399 // [12] because we take three 32bit stack slots anyway, and
393 // gcc is too dumb to initialize with constant stores, 400 // gcc is too dumb to initialize with constant stores,
394 // it copies initializer from rodata. Oh well. 401 // it copies initializer from rodata. Oh well.
@@ -419,7 +426,7 @@ print_ascii(size_t n_bytes, const char *block,
419 const char *unused_fmt_string UNUSED_PARAM) 426 const char *unused_fmt_string UNUSED_PARAM)
420{ 427{
421 // buf[N] pos: 01234 56789 428 // buf[N] pos: 01234 56789
422 char buf[12] = " x\0 0xx\0"; 429 char buf[12] = " x\0 xxx\0";
423 430
424 while (n_bytes--) { 431 while (n_bytes--) {
425 const char *s; 432 const char *s;
@@ -458,8 +465,9 @@ print_ascii(size_t n_bytes, const char *block,
458 case '\x7f': 465 case '\x7f':
459 s = " 177"; 466 s = " 177";
460 break; 467 break;
461 default: /* c is never larger than 040 */ 468 default:
462 buf[7] = (c >> 3) + '0'; 469 buf[6] = (c >> 6 & 3) + '0';
470 buf[7] = (c >> 3 & 7) + '0';
463 buf[8] = (c & 7) + '0'; 471 buf[8] = (c & 7) + '0';
464 s = buf + 5; 472 s = buf + 5;
465 } 473 }
diff --git a/coreutils/test.c b/coreutils/test.c
index 88cc55050..6b16ffeb1 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -642,6 +642,25 @@ static int filstat(char *nm, enum token mode)
642 return 0; 642 return 0;
643 } 643 }
644 644
645#if ENABLE_PLATFORM_MINGW32
646#undef R_OK
647#define R_OK S_IREAD
648#undef W_OK
649#define W_OK S_IWRITE
650 if (mode == FILEX) {
651 char *p;
652
653 if (file_is_executable(nm)) {
654 return 1;
655 }
656 else if ((p=file_is_win32_executable(nm))) {
657 free(p);
658 return 1;
659 }
660 return 0;
661 }
662#endif
663
645 if (stat(nm, &s) != 0) 664 if (stat(nm, &s) != 0)
646 return 0; 665 return 0;
647 if (mode == FILEXIST) 666 if (mode == FILEXIST)
diff --git a/coreutils/uname.c b/coreutils/uname.c
index 1c6aa5f79..56d985eb0 100644
--- a/coreutils/uname.c
+++ b/coreutils/uname.c
@@ -70,11 +70,17 @@
70/* After libbb.h, since it needs sys/types.h on some systems */ 70/* After libbb.h, since it needs sys/types.h on some systems */
71#include <sys/utsname.h> 71#include <sys/utsname.h>
72 72
73#if ENABLE_PLATFORM_MINGW32
74# define OSNAME "MS/Windows"
75#else
76# define OSNAME "GNU/Linux"
77#endif
78
73typedef struct { 79typedef struct {
74 struct utsname name; 80 struct utsname name;
75 char processor[sizeof(((struct utsname*)NULL)->machine)]; 81 char processor[sizeof(((struct utsname*)NULL)->machine)];
76 char platform[sizeof(((struct utsname*)NULL)->machine)]; 82 char platform[sizeof(((struct utsname*)NULL)->machine)];
77 char os[sizeof("GNU/Linux")]; 83 char os[sizeof(OSNAME)];
78} uname_info_t; 84} uname_info_t;
79 85
80static const char options[] ALIGN1 = "snrvmpioa"; 86static const char options[] ALIGN1 = "snrvmpioa";
@@ -141,7 +147,7 @@ int uname_main(int argc UNUSED_PARAM, char **argv)
141#endif 147#endif
142 strcpy(uname_info.processor, unknown_str); 148 strcpy(uname_info.processor, unknown_str);
143 strcpy(uname_info.platform, unknown_str); 149 strcpy(uname_info.platform, unknown_str);
144 strcpy(uname_info.os, "GNU/Linux"); 150 strcpy(uname_info.os, OSNAME);
145#if 0 151#if 0
146 /* Fedora does something like this */ 152 /* Fedora does something like this */
147 strcpy(uname_info.processor, uname_info.name.machine); 153 strcpy(uname_info.processor, uname_info.name.machine);
diff --git a/debianutils/which.c b/debianutils/which.c
index d50e7a0d3..ace5b82dd 100644
--- a/debianutils/which.c
+++ b/debianutils/which.c
@@ -33,17 +33,33 @@ int which_main(int argc UNUSED_PARAM, char **argv)
33 33
34 do { 34 do {
35 int missing = 1; 35 int missing = 1;
36 char *p;
37
38#if ENABLE_FEATURE_PREFER_APPLETS
39 if ( find_applet_by_name(*argv) >= 0 ) {
40 missing = 0;
41 puts(*argv);
42 if (!option_mask32) /* -a not set */
43 break;
44 }
45#endif
36 46
37 /* If file contains a slash don't use PATH */ 47 /* If file contains a slash don't use PATH */
38 if (strchr(*argv, '/')) { 48 if (strchr(*argv, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(*argv, '\\'))) {
39 if (file_is_executable(*argv)) { 49 if (file_is_executable(*argv)) {
40 missing = 0; 50 missing = 0;
41 puts(*argv); 51 puts(*argv);
42 } 52 }
53#if ENABLE_PLATFORM_MINGW32
54 else if ((p=file_is_win32_executable(*argv)) != NULL) {
55 missing = 0;
56 puts(p);
57 free(p);
58 }
59#endif
43 } else { 60 } else {
44 char *path; 61 char *path;
45 char *tmp; 62 char *tmp;
46 char *p;
47 63
48 path = tmp = xstrdup(env_path); 64 path = tmp = xstrdup(env_path);
49 while ((p = find_executable(*argv, &tmp)) != NULL) { 65 while ((p = find_executable(*argv, &tmp)) != NULL) {
diff --git a/editors/awk.c b/editors/awk.c
index f487163af..5b8e484a7 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -723,7 +723,11 @@ static char *skip_spaces(char *p)
723 if (*p == '\\' && p[1] == '\n') { 723 if (*p == '\\' && p[1] == '\n') {
724 p++; 724 p++;
725 t_lineno++; 725 t_lineno++;
726#if !ENABLE_PLATFORM_MINGW32
726 } else if (*p != ' ' && *p != '\t') { 727 } else if (*p != ' ' && *p != '\t') {
728#else
729 } else if (*p != ' ' && *p != '\t' && *p != '\r') {
730#endif
727 break; 731 break;
728 } 732 }
729 p++; 733 p++;
diff --git a/editors/vi.c b/editors/vi.c
index 70bdbab07..1fa97b568 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -542,9 +542,6 @@ static void cookmode(void); // return to "cooked" mode on tty
542static int mysleep(int); 542static int mysleep(int);
543static int readit(void); // read (maybe cursor) key from stdin 543static int readit(void); // read (maybe cursor) key from stdin
544static int get_one_char(void); // read 1 char from stdin 544static int get_one_char(void); // read 1 char from stdin
545#if !ENABLE_FEATURE_VI_READONLY
546#define file_insert(fn, p, update_ro_status) file_insert(fn, p)
547#endif
548// file_insert might reallocate text[]! 545// file_insert might reallocate text[]!
549static int file_insert(const char *, char *, int); 546static int file_insert(const char *, char *, int);
550static int file_write(char *, char *, char *); 547static int file_write(char *, char *, char *);
@@ -1321,11 +1318,15 @@ static void colon(char *buf)
1321 q = begin_line(dot); // assume "dot" 1318 q = begin_line(dot); // assume "dot"
1322 } 1319 }
1323 // read after current line- unless user said ":0r foo" 1320 // read after current line- unless user said ":0r foo"
1324 if (b != 0) 1321 if (b != 0) {
1325 q = next_line(q); 1322 q = next_line(q);
1323 // read after last line
1324 if (q == end-1)
1325 ++q;
1326 }
1326 { // dance around potentially-reallocated text[] 1327 { // dance around potentially-reallocated text[]
1327 uintptr_t ofs = q - text; 1328 uintptr_t ofs = q - text;
1328 size = file_insert(fn, q, /*update_ro:*/ 0); 1329 size = file_insert(fn, q, 0);
1329 q = text + ofs; 1330 q = text + ofs;
1330 } 1331 }
1331 if (size < 0) 1332 if (size < 0)
@@ -2803,6 +2804,14 @@ static void catch_sig(int sig)
2803 2804
2804static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready 2805static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
2805{ 2806{
2807#if ENABLE_PLATFORM_MINGW32
2808 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
2809 DWORD ret;
2810
2811 fflush(stdout);
2812 ret = WaitForSingleObject(h, hund*10);
2813 return ret != WAIT_TIMEOUT;
2814#else
2806 struct pollfd pfd[1]; 2815 struct pollfd pfd[1];
2807 2816
2808 if (hund != 0) 2817 if (hund != 0)
@@ -2811,6 +2820,7 @@ static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
2811 pfd[0].fd = STDIN_FILENO; 2820 pfd[0].fd = STDIN_FILENO;
2812 pfd[0].events = POLLIN; 2821 pfd[0].events = POLLIN;
2813 return safe_poll(pfd, 1, hund*10) > 0; 2822 return safe_poll(pfd, 1, hund*10) > 0;
2823#endif
2814} 2824}
2815 2825
2816//----- IO Routines -------------------------------------------- 2826//----- IO Routines --------------------------------------------
@@ -2905,7 +2915,7 @@ static char *get_input_line(const char *prompt)
2905} 2915}
2906 2916
2907// might reallocate text[]! 2917// might reallocate text[]!
2908static int file_insert(const char *fn, char *p, int update_ro_status) 2918static int file_insert(const char *fn, char *p, int initial)
2909{ 2919{
2910 int cnt = -1; 2920 int cnt = -1;
2911 int fd, size; 2921 int fd, size;
@@ -2918,7 +2928,8 @@ static int file_insert(const char *fn, char *p, int update_ro_status)
2918 2928
2919 fd = open(fn, O_RDONLY); 2929 fd = open(fn, O_RDONLY);
2920 if (fd < 0) { 2930 if (fd < 0) {
2921 status_line_bold_errno(fn); 2931 if (!initial)
2932 status_line_bold_errno(fn);
2922 return cnt; 2933 return cnt;
2923 } 2934 }
2924 2935
@@ -2931,6 +2942,9 @@ static int file_insert(const char *fn, char *p, int update_ro_status)
2931 status_line_bold("'%s' is not a regular file", fn); 2942 status_line_bold("'%s' is not a regular file", fn);
2932 goto fi; 2943 goto fi;
2933 } 2944 }
2945#if ENABLE_PLATFORM_MINGW32
2946 _setmode(fd, _O_TEXT);
2947#endif
2934 size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX); 2948 size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX);
2935 p += text_hole_make(p, size); 2949 p += text_hole_make(p, size);
2936 cnt = full_read(fd, p, size); 2950 cnt = full_read(fd, p, size);
@@ -2939,14 +2953,31 @@ static int file_insert(const char *fn, char *p, int update_ro_status)
2939 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert 2953 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert
2940 } else if (cnt < size) { 2954 } else if (cnt < size) {
2941 // There was a partial read, shrink unused space 2955 // There was a partial read, shrink unused space
2956#if ENABLE_PLATFORM_MINGW32
2957 int i, newline;
2958
2959 newline = 0;
2960 for ( i=0; i<cnt; ++i ) {
2961 if ( p[i] == '\n' ) {
2962 ++newline;
2963 }
2964 }
2965#endif
2942 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO); 2966 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO);
2967#if ENABLE_PLATFORM_MINGW32
2968 // on WIN32 a partial read might just mean CRs have been removed
2969 if ( cnt+newline != size ) {
2970 status_line_bold("can't read '%s'", fn);
2971 }
2972#else
2943 status_line_bold("can't read '%s'", fn); 2973 status_line_bold("can't read '%s'", fn);
2974#endif
2944 } 2975 }
2945 fi: 2976 fi:
2946 close(fd); 2977 close(fd);
2947 2978
2948#if ENABLE_FEATURE_VI_READONLY 2979#if ENABLE_FEATURE_VI_READONLY
2949 if (update_ro_status 2980 if (initial
2950 && ((access(fn, W_OK) < 0) || 2981 && ((access(fn, W_OK) < 0) ||
2951 /* root will always have access() 2982 /* root will always have access()
2952 * so we check fileperms too */ 2983 * so we check fileperms too */
@@ -2962,6 +2993,9 @@ static int file_insert(const char *fn, char *p, int update_ro_status)
2962static int file_write(char *fn, char *first, char *last) 2993static int file_write(char *fn, char *first, char *last)
2963{ 2994{
2964 int fd, cnt, charcnt; 2995 int fd, cnt, charcnt;
2996#if ENABLE_PLATFORM_MINGW32
2997 int i, newline;
2998#endif
2965 2999
2966 if (fn == 0) { 3000 if (fn == 0) {
2967 status_line_bold("No current filename"); 3001 status_line_bold("No current filename");
@@ -2975,8 +3009,23 @@ static int file_write(char *fn, char *first, char *last)
2975 if (fd < 0) 3009 if (fd < 0)
2976 return -1; 3010 return -1;
2977 cnt = last - first + 1; 3011 cnt = last - first + 1;
3012#if ENABLE_PLATFORM_MINGW32
3013 /* write file in text mode; this makes it bigger so adjust
3014 * the truncation to match
3015 */
3016 _setmode(fd, _O_TEXT);
3017 newline = 0;
3018 for ( i=0; i<cnt; ++i ) {
3019 if ( first[i] == '\n' ) {
3020 ++newline;
3021 }
3022 }
3023 charcnt = full_write(fd, first, cnt);
3024 ftruncate(fd, charcnt+newline);
3025#else
2978 charcnt = full_write(fd, first, cnt); 3026 charcnt = full_write(fd, first, cnt);
2979 ftruncate(fd, charcnt); 3027 ftruncate(fd, charcnt);
3028#endif
2980 if (charcnt == cnt) { 3029 if (charcnt == cnt) {
2981 // good write 3030 // good write
2982 //modified_count = FALSE; 3031 //modified_count = FALSE;
diff --git a/findutils/grep.c b/findutils/grep.c
index b9621384e..0336b2927 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -179,6 +179,14 @@ enum {
179#define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L) 179#define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L)
180#define NUL_DELIMITED (option_mask32 & OPT_z) 180#define NUL_DELIMITED (option_mask32 & OPT_z)
181 181
182#if ENABLE_PLATFORM_MINGW32
183# define RE_TRANSLATE_TYPE unsigned char*
184# undef ENABLE_EXTRA_COMPAT
185# define ENABLE_EXTRA_COMPAT 0
186# undef IF_EXTRA_COMPAT
187# define IF_EXTRA_COMPAT(x)
188#endif
189
182struct globals { 190struct globals {
183 int max_matches; 191 int max_matches;
184#if !ENABLE_EXTRA_COMPAT 192#if !ENABLE_EXTRA_COMPAT
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 76c4747fe..e0fb369e8 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -65,6 +65,9 @@
65 65
66//kbuild:lib-$(CONFIG_XARGS) += xargs.o 66//kbuild:lib-$(CONFIG_XARGS) += xargs.o
67 67
68#if ENABLE_PLATFORM_MINGW32
69#include <conio.h>
70#endif
68#include "libbb.h" 71#include "libbb.h"
69 72
70/* This is a NOEXEC applet. Be very careful! */ 73/* This is a NOEXEC applet. Be very careful! */
@@ -403,13 +406,23 @@ static int xargs_ask_confirmation(void)
403 FILE *tty_stream; 406 FILE *tty_stream;
404 int c, savec; 407 int c, savec;
405 408
409#if !ENABLE_PLATFORM_MINGW32
406 tty_stream = xfopen_for_read(CURRENT_TTY); 410 tty_stream = xfopen_for_read(CURRENT_TTY);
411#endif
407 fputs(" ?...", stderr); 412 fputs(" ?...", stderr);
408 fflush_all(); 413 fflush_all();
414#if !ENABLE_PLATFORM_MINGW32
409 c = savec = getc(tty_stream); 415 c = savec = getc(tty_stream);
410 while (c != EOF && c != '\n') 416 while (c != EOF && c != '\n')
411 c = getc(tty_stream); 417 c = getc(tty_stream);
412 fclose(tty_stream); 418 fclose(tty_stream);
419#else
420 c = savec = getche();
421 while (c != EOF && c != '\r')
422 c = getche();
423 fputs("\n", stderr);
424 fflush_all();
425#endif
413 return (savec == 'y' || savec == 'Y'); 426 return (savec == 'y' || savec == 'Y');
414} 427}
415#else 428#else
diff --git a/include/libbb.h b/include/libbb.h
index 68a7cf002..2850b1d5a 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -112,6 +112,13 @@
112# include <arpa/inet.h> 112# include <arpa/inet.h>
113#elif defined __APPLE__ 113#elif defined __APPLE__
114# include <netinet/in.h> 114# include <netinet/in.h>
115#elif ENABLE_PLATFORM_MINGW32
116# ifndef WINVER
117# define WINVER 0x0501
118# endif
119# include <winsock2.h>
120# include <ws2tcpip.h>
121# undef s_addr
115#else 122#else
116# include <arpa/inet.h> 123# include <arpa/inet.h>
117# if !defined(__socklen_t_defined) && !defined(_SOCKLEN_T_DECLARED) 124# if !defined(__socklen_t_defined) && !defined(_SOCKLEN_T_DECLARED)
@@ -136,7 +143,9 @@
136 143
137/* Some libc's forget to declare these, do it ourself */ 144/* Some libc's forget to declare these, do it ourself */
138 145
146#if !ENABLE_PLATFORM_MINGW32
139extern char **environ; 147extern char **environ;
148#endif
140#if defined(__GLIBC__) && __GLIBC__ < 2 149#if defined(__GLIBC__) && __GLIBC__ < 2
141int vdprintf(int d, const char *format, va_list ap); 150int vdprintf(int d, const char *format, va_list ap);
142#endif 151#endif
@@ -149,6 +158,10 @@ int klogctl(int type, char *b, int len);
149# define BUFSIZ 4096 158# define BUFSIZ 4096
150#endif 159#endif
151 160
161/* Can't use ENABLE_PLATFORM_MINGW32 because it's also called by host compiler */
162#if ENABLE_PLATFORM_MINGW32
163# include "mingw.h"
164#endif
152 165
153/* Busybox does not use threads, we can speed up stdio. */ 166/* Busybox does not use threads, we can speed up stdio. */
154#ifdef HAVE_UNLOCKED_STDIO 167#ifdef HAVE_UNLOCKED_STDIO
@@ -830,6 +843,9 @@ char *safe_gethostname(void) FAST_FUNC;
830char* str_tolower(char *str) FAST_FUNC; 843char* str_tolower(char *str) FAST_FUNC;
831 844
832char *utoa(unsigned n) FAST_FUNC; 845char *utoa(unsigned n) FAST_FUNC;
846#if ENABLE_PLATFORM_MINGW32
847# define itoa bb_itoa
848#endif
833char *itoa(int n) FAST_FUNC; 849char *itoa(int n) FAST_FUNC;
834/* Returns a pointer past the formatted number, does NOT null-terminate */ 850/* Returns a pointer past the formatted number, does NOT null-terminate */
835char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; 851char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC;
@@ -1596,6 +1612,9 @@ typedef struct procps_status_t {
1596#if ENABLE_FEATURE_TOP_SMP_PROCESS 1612#if ENABLE_FEATURE_TOP_SMP_PROCESS
1597 int last_seen_on_cpu; 1613 int last_seen_on_cpu;
1598#endif 1614#endif
1615#if ENABLE_PLATFORM_MINGW32
1616 HANDLE snapshot;
1617#endif
1599} procps_status_t; 1618} procps_status_t;
1600/* flag bits for procps_scan(xx, flags) calls */ 1619/* flag bits for procps_scan(xx, flags) calls */
1601enum { 1620enum {
@@ -1634,7 +1653,11 @@ void free_procps_scan(procps_status_t* sp) FAST_FUNC;
1634procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; 1653procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC;
1635/* Format cmdline (up to col chars) into char buf[size] */ 1654/* Format cmdline (up to col chars) into char buf[size] */
1636/* Puts [comm] if cmdline is empty (-> process is a kernel thread) */ 1655/* Puts [comm] if cmdline is empty (-> process is a kernel thread) */
1656#if !ENABLE_PLATFORM_MINGW32
1637void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; 1657void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC;
1658#else
1659#define read_cmdline(buf, size, pid, comm) snprintf(buf, size, "[%s]", comm)
1660#endif
1638pid_t *find_pid_by_name(const char* procName) FAST_FUNC; 1661pid_t *find_pid_by_name(const char* procName) FAST_FUNC;
1639pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; 1662pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC;
1640int starts_with_cpu(const char *str) FAST_FUNC; 1663int starts_with_cpu(const char *str) FAST_FUNC;
@@ -1770,7 +1793,11 @@ extern const char bb_path_wtmp_file[] ALIGN1;
1770#define bb_path_motd_file "/etc/motd" 1793#define bb_path_motd_file "/etc/motd"
1771 1794
1772#define bb_dev_null "/dev/null" 1795#define bb_dev_null "/dev/null"
1796#if ENABLE_PLATFORM_MINGW32
1797#define bb_busybox_exec_path get_busybox_exec_path()
1798#else
1773extern const char bb_busybox_exec_path[] ALIGN1; 1799extern const char bb_busybox_exec_path[] ALIGN1;
1800#endif
1774/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 1801/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
1775 * but I want to save a few bytes here */ 1802 * but I want to save a few bytes here */
1776extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ 1803extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */
diff --git a/include/mingw.h b/include/mingw.h
new file mode 100644
index 000000000..090dd1776
--- /dev/null
+++ b/include/mingw.h
@@ -0,0 +1,438 @@
1
2#define NOIMPL(name,...) static inline int name(__VA_ARGS__) { errno = ENOSYS; return -1; }
3#define IMPL(name,ret,retval,...) static inline ret name(__VA_ARGS__) { return retval; }
4
5/*
6 * sys/types.h
7 */
8typedef int gid_t;
9typedef int uid_t;
10#ifndef _WIN64
11typedef int pid_t;
12#else
13typedef __int64 pid_t;
14#endif
15
16/*
17 * arpa/inet.h
18 */
19static inline unsigned int git_ntohl(unsigned int x) { return (unsigned int)ntohl(x); }
20#define ntohl git_ntohl
21int inet_aton(const char *cp, struct in_addr *inp);
22
23/*
24 * fcntl.h
25 */
26#define F_DUPFD 0
27#define F_GETFD 1
28#define F_SETFD 2
29#define F_GETFL 3
30#define F_SETFL 3
31#define FD_CLOEXEC 0x1
32#define O_NONBLOCK 04000
33
34/*
35 * grp.h
36 */
37
38struct group {
39 char *gr_name;
40 char *gr_passwd;
41 gid_t gr_gid;
42 char **gr_mem;
43};
44IMPL(getgrnam,struct group *,NULL,const char *name UNUSED_PARAM);
45IMPL(getgrgid,struct group *,NULL,gid_t gid UNUSED_PARAM);
46NOIMPL(initgroups,const char *group UNUSED_PARAM,gid_t gid UNUSED_PARAM);
47static inline void endgrent(void) {}
48
49/*
50 * limits.h
51 */
52#define NAME_MAX 255
53#define MAXSYMLINKS 20
54
55/*
56 * netdb.h
57 */
58
59typedef int sa_family_t;
60
61/*
62 * linux/un.h
63 */
64struct sockaddr_un {
65 sa_family_t sun_family;
66 char sun_path[1]; /* to make compiler happy, don't bother */
67};
68
69/*
70 * pwd.h
71 */
72struct passwd {
73 char *pw_name;
74 char *pw_gecos;
75 char *pw_dir;
76 char *pw_shell;
77 uid_t pw_uid;
78 gid_t pw_gid;
79};
80
81IMPL(getpwnam,struct passwd *,NULL,const char *name UNUSED_PARAM);
82struct passwd *getpwuid(int uid);
83static inline void setpwent(void) {}
84static inline void endpwent(void) {}
85IMPL(getpwent_r,int,ENOENT,struct passwd *pwbuf UNUSED_PARAM,char *buf UNUSED_PARAM,size_t buflen UNUSED_PARAM,struct passwd **pwbufp UNUSED_PARAM);
86
87/*
88 * signal.h
89 */
90#define SIGHUP 1
91#define SIGQUIT 3
92#define SIGKILL 9
93#define SIGUSR1 10
94#define SIGUSR2 12
95#define SIGPIPE 13
96#define SIGALRM 14
97#define SIGCHLD 17
98#define SIGCONT 18
99#define SIGSTOP 19
100#define SIGTSTP 20
101#define SIGTTIN 21
102#define SIGTTOU 22
103#define SIGXCPU 24
104#define SIGXFSZ 25
105#define SIGVTALRM 26
106#define SIGWINCH 28
107
108#define SIG_UNBLOCK 1
109
110typedef void (__cdecl *sighandler_t)(int);
111struct sigaction {
112 sighandler_t sa_handler;
113 unsigned sa_flags;
114 int sa_mask;
115};
116#define sigemptyset(x) (void)0
117#define SA_RESTART 0
118
119int sigaction(int sig, struct sigaction *in, struct sigaction *out);
120sighandler_t mingw_signal(int sig, sighandler_t handler);
121NOIMPL(sigfillset,int *mask UNUSED_PARAM);
122NOIMPL(FAST_FUNC sigprocmask_allsigs, int how UNUSED_PARAM);
123NOIMPL(FAST_FUNC sigaction_set,int signo UNUSED_PARAM, const struct sigaction *sa UNUSED_PARAM);
124
125#define signal mingw_signal
126/*
127 * stdio.h
128 */
129#undef fseeko
130#define fseeko(f,o,w) fseek(f,o,w)
131
132int fdprintf(int fd, const char *format, ...);
133FILE* mingw_fopen(const char *filename, const char *mode);
134int mingw_rename(const char*, const char*);
135#define fopen mingw_fopen
136#define rename mingw_rename
137
138FILE *mingw_popen(const char *cmd, const char *mode);
139int mingw_pclose(FILE *fd);
140#undef popen
141#undef pclose
142#define popen mingw_popen
143#define pclose mingw_pclose
144
145#define setlinebuf(fd) setvbuf(fd, (char *) NULL, _IOLBF, 0)
146
147/*
148 * ANSI emulation wrappers
149 */
150
151int winansi_putchar(int c);
152int winansi_puts(const char *s);
153size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
154int winansi_fputs(const char *str, FILE *stream);
155int winansi_vfprintf(FILE *stream, const char *format, va_list list);
156int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
157int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
158int winansi_write(int fd, const void *buf, size_t count);
159int winansi_read(int fd, void *buf, size_t count);
160int winansi_getc(FILE *stream);
161#define putchar winansi_putchar
162#define puts winansi_puts
163#define fwrite winansi_fwrite
164#define fputs winansi_fputs
165#define vprintf(...) winansi_vfprintf(stdout, __VA_ARGS__)
166#define printf(...) winansi_printf(__VA_ARGS__)
167#define fprintf(...) winansi_fprintf(__VA_ARGS__)
168#define write winansi_write
169#define read winansi_read
170#define getc winansi_getc
171
172int winansi_get_terminal_width_height(struct winsize *win);
173
174/*
175 * stdlib.h
176 */
177#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */
178#define WEXITSTATUS(x) ((x) & 0xff)
179#define WIFSIGNALED(x) ((unsigned)(x) > 259)
180#define WTERMSIG(x) ((x) & 0x7f)
181#define WCOREDUMP(x) 0
182
183int mingw_system(const char *cmd);
184#define system mingw_system
185
186int clearenv(void);
187char *mingw_getenv(const char *name);
188char *mingw_mktemp(char *template);
189int mkstemp(char *template);
190char *realpath(const char *path, char *resolved_path);
191int setenv(const char *name, const char *value, int replace);
192void unsetenv(const char *env);
193
194#define getenv mingw_getenv
195#define mktemp mingw_mktemp
196
197/*
198 * string.h
199 */
200void *mempcpy(void *dest, const void *src, size_t n);
201
202/*
203 * sys/ioctl.h
204 */
205
206#define TIOCGWINSZ 0x5413
207
208int ioctl(int fd, int code, ...);
209
210/*
211 * sys/socket.h
212 */
213#define hstrerror strerror
214
215int mingw_socket(int domain, int type, int protocol);
216int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
217
218NOIMPL(mingw_sendto,SOCKET s UNUSED_PARAM, const char *buf UNUSED_PARAM, int len UNUSED_PARAM, int flags UNUSED_PARAM, const struct sockaddr *sa UNUSED_PARAM, int salen UNUSED_PARAM);
219NOIMPL(mingw_listen,SOCKET s UNUSED_PARAM,int backlog UNUSED_PARAM);
220NOIMPL(mingw_bind,SOCKET s UNUSED_PARAM,const struct sockaddr* sa UNUSED_PARAM,int salen UNUSED_PARAM);
221
222#define socket mingw_socket
223#define connect mingw_connect
224#define sendto mingw_sendto
225#define listen mingw_listen
226#define bind mingw_bind
227
228/*
229 * sys/stat.h
230 */
231#define S_ISUID 04000
232#define S_ISGID 02000
233#define S_ISVTX 01000
234#ifndef S_IRWXU
235#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
236#endif
237#define S_IRWXG (S_IRWXU >> 3)
238#define S_IRWXO (S_IRWXG >> 3)
239
240#define S_IFSOCK 0140000
241#define S_IFLNK 0120000 /* Symbolic link */
242#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
243#define S_ISSOCK(x) 0
244
245#define S_IRGRP (S_IRUSR >> 3)
246#define S_IWGRP (S_IWUSR >> 3)
247#define S_IXGRP (S_IXUSR >> 3)
248#define S_IROTH (S_IRGRP >> 3)
249#define S_IWOTH (S_IWGRP >> 3)
250#define S_IXOTH (S_IXGRP >> 3)
251
252IMPL(fchmod,int,0,int fildes UNUSED_PARAM, mode_t mode UNUSED_PARAM);
253NOIMPL(fchown,int fd UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
254int mingw_mkdir(const char *path, int mode);
255#define mkdir mingw_mkdir
256
257#if ENABLE_LFS
258# define off_t off64_t
259#endif
260#undef lseek
261#define lseek _lseeki64
262
263typedef int nlink_t;
264typedef int blksize_t;
265typedef off_t blkcnt_t;
266
267struct mingw_stat {
268 dev_t st_dev;
269 ino_t st_ino;
270 mode_t st_mode;
271 nlink_t st_nlink;
272 uid_t st_uid;
273 gid_t st_gid;
274 dev_t st_rdev;
275 off_t st_size;
276 time_t st_atime;
277 time_t st_mtime;
278 time_t st_ctime;
279 blksize_t st_blksize;
280 blkcnt_t st_blocks;
281};
282
283int mingw_lstat(const char *file_name, struct mingw_stat *buf);
284int mingw_stat(const char *file_name, struct mingw_stat *buf);
285int mingw_fstat(int fd, struct mingw_stat *buf);
286#undef lstat
287#undef stat
288#undef fstat
289#define lstat mingw_lstat
290#define stat mingw_stat
291#define fstat mingw_fstat
292
293/*
294 * sys/sysmacros.h
295 */
296#define makedev(a,b) 0*(a)*(b) /* avoid unused warning */
297#define minor(x) 0
298#define major(x) 0
299
300/*
301 * sys/time.h
302 */
303#ifndef _TIMESPEC_DEFINED
304#define _TIMESPEC_DEFINED
305struct timespec {
306 time_t tv_sec;
307 long int tv_nsec;
308};
309#endif
310struct itimerval {
311 struct timeval it_value, it_interval;
312};
313#define ITIMER_REAL 0
314
315int setitimer(int type, struct itimerval *in, struct itimerval *out);
316
317/*
318 * sys/wait.h
319 */
320#define WNOHANG 1
321#define WUNTRACED 2
322int waitpid(pid_t pid, int *status, unsigned options);
323
324/*
325 * time.h
326 */
327struct tm *gmtime_r(const time_t *timep, struct tm *result);
328struct tm *localtime_r(const time_t *timep, struct tm *result);
329char *strptime(const char *s, const char *format, struct tm *tm);
330size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm);
331int stime(time_t *t);
332
333#define strftime mingw_strftime
334
335/*
336 * times.h
337 */
338#define clock_t long
339
340struct tms {
341 clock_t tms_utime; /* user CPU time */
342 clock_t tms_stime; /* system CPU time */
343 clock_t tms_cutime; /* user CPU time of children */
344 clock_t tms_cstime; /* system CPU time of children */
345};
346
347clock_t times(struct tms *buf);
348
349/*
350 * unistd.h
351 */
352#define PIPE_BUF 8192
353
354#define _SC_CLK_TCK 2
355
356IMPL(alarm,unsigned int,0,unsigned int seconds UNUSED_PARAM);
357IMPL(chown,int,0,const char *path UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
358NOIMPL(chroot,const char *root UNUSED_PARAM);
359int mingw_dup2 (int fd, int fdto);
360char *mingw_getcwd(char *pointer, int len);
361
362
363IMPL(getgid,int,1,void);
364NOIMPL(getgroups,int n UNUSED_PARAM,gid_t *groups UNUSED_PARAM);
365IMPL(getppid,int,1,void);
366IMPL(getegid,int,1,void);
367IMPL(geteuid,int,1,void);
368NOIMPL(getsid,pid_t pid UNUSED_PARAM);
369IMPL(getuid,int,1,void);
370int fcntl(int fd, int cmd, ...);
371#define fork() -1
372IMPL(fsync,int,0,int fd UNUSED_PARAM);
373int kill(pid_t pid, int sig);
374int link(const char *oldpath, const char *newpath);
375NOIMPL(mknod,const char *name UNUSED_PARAM, mode_t mode UNUSED_PARAM, dev_t device UNUSED_PARAM);
376int mingw_open (const char *filename, int oflags, ...);
377int pipe(int filedes[2]);
378NOIMPL(readlink,const char *path UNUSED_PARAM, char *buf UNUSED_PARAM, size_t bufsiz UNUSED_PARAM);
379NOIMPL(setgid,gid_t gid UNUSED_PARAM);
380NOIMPL(setegid,gid_t gid UNUSED_PARAM);
381NOIMPL(setsid,void);
382NOIMPL(setuid,uid_t gid UNUSED_PARAM);
383NOIMPL(seteuid,uid_t gid UNUSED_PARAM);
384unsigned int sleep(unsigned int seconds);
385NOIMPL(symlink,const char *oldpath UNUSED_PARAM, const char *newpath UNUSED_PARAM);
386static inline void sync(void) {}
387long sysconf(int name);
388NOIMPL(ttyname_r,int fd UNUSED_PARAM, char *buf UNUSED_PARAM, int sz UNUSED_PARAM);
389int mingw_unlink(const char *pathname);
390NOIMPL(vfork,void);
391int mingw_access(const char *name, int mode);
392
393#define dup2 mingw_dup2
394#define getcwd mingw_getcwd
395#define lchown chown
396#define open mingw_open
397#define unlink mingw_unlink
398
399#undef access
400#define access mingw_access
401
402/*
403 * utime.h
404 */
405int utimes(const char *file_name, const struct timeval times[2]);
406
407/*
408 * MinGW specific
409 */
410#define is_dir_sep(c) ((c) == '/' || (c) == '\\')
411#define PRIuMAX "I64u"
412
413pid_t mingw_spawn(char **argv);
414int mingw_execv(const char *cmd, const char *const *argv);
415int mingw_execvp(const char *cmd, const char *const *argv);
416int mingw_execve(const char *cmd, const char *const *argv, const char *const *envp);
417pid_t mingw_spawn_applet(int mode, const char *applet, const char *const *argv, const char *const *envp);
418pid_t mingw_spawn_1(int mode, const char *cmd, const char *const *argv, const char *const *envp);
419#define execvp mingw_execvp
420#define execve mingw_execve
421#define execv mingw_execv
422
423const char * next_path_sep(const char *path);
424#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
425#define is_absolute_path(path) ((path)[0] == '/' || has_dos_drive_prefix(path))
426
427/*
428 * helpers
429 */
430
431char **copy_environ(const char *const *env);
432void free_environ(char **env);
433char **env_setenv(char **env, const char *name);
434
435const char *get_busybox_exec_path(void);
436void init_winsock(void);
437
438char *file_is_win32_executable(const char *p);
diff --git a/include/platform.h b/include/platform.h
index 09c7ccd9c..e2b61592e 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -7,6 +7,15 @@
7#ifndef BB_PLATFORM_H 7#ifndef BB_PLATFORM_H
8#define BB_PLATFORM_H 1 8#define BB_PLATFORM_H 1
9 9
10#if ENABLE_PLATFORM_MINGW32
11# if !defined(__MINGW32__) /* HOSTCC is called */
12# undef ENABLE_PLATFORM_MINGW32
13# endif
14#else
15# if defined(__MINGW32__)
16# error "You must select target platform MS Windows, or it won't build"
17# endif
18#endif
10 19
11/* Convenience macros to test the version of gcc. */ 20/* Convenience macros to test the version of gcc. */
12#undef __GNUC_PREREQ 21#undef __GNUC_PREREQ
@@ -119,7 +128,7 @@
119 128
120/* Make all declarations hidden (-fvisibility flag only affects definitions) */ 129/* Make all declarations hidden (-fvisibility flag only affects definitions) */
121/* (don't include system headers after this until corresponding pop!) */ 130/* (don't include system headers after this until corresponding pop!) */
122#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) 131#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) && !ENABLE_PLATFORM_MINGW32
123# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)") 132# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)")
124# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop") 133# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop")
125#else 134#else
@@ -148,6 +157,14 @@
148# define bswap_64 __bswap64 157# define bswap_64 __bswap64
149# define bswap_32 __bswap32 158# define bswap_32 __bswap32
150# define bswap_16 __bswap16 159# define bswap_16 __bswap16
160# define __BIG_ENDIAN__ (_BYTE_ORDER == _BIG_ENDIAN)
161#elif ENABLE_PLATFORM_MINGW32
162# define __BIG_ENDIAN 0
163# define __LITTLE_ENDIAN 1
164# define __BYTE_ORDER __LITTLE_ENDIAN
165# define bswap_16(x) ((((x) & 0xFF00) >> 8) | (((x) & 0xFF) << 8))
166# define bswap_32(x) ((bswap_16(((x) & 0xFFFF0000L) >> 16)) | (bswap_16((x) & 0xFFFFL) << 16))
167# define bswap_64(x) ((bswap_32(((x) & 0xFFFFFFFF00000000LL) >> 32)) | (bswap_32((x) & 0xFFFFFFFFLL) << 32))
151#else 168#else
152# include <byteswap.h> 169# include <byteswap.h>
153# include <endian.h> 170# include <endian.h>
@@ -396,6 +413,25 @@ typedef unsigned smalluint;
396# endif 413# endif
397#endif 414#endif
398 415
416#if ENABLE_PLATFORM_MINGW32
417# undef HAVE_DPRINTF
418# undef HAVE_GETLINE
419# undef HAVE_MEMRCHR
420# undef HAVE_MKDTEMP
421# undef HAVE_SETBIT
422# undef HAVE_STPCPY
423# undef HAVE_STRCASESTR
424# undef HAVE_STRCHRNUL
425# undef HAVE_STRSEP
426# undef HAVE_STRSIGNAL
427# undef HAVE_STRVERSCMP
428#if !defined(__MINGW64_VERSION_MAJOR)
429# undef HAVE_VASPRINTF
430#endif
431# undef HAVE_UNLOCKED_STDIO
432# undef HAVE_UNLOCKED_LINE_OPS
433#endif
434
399#if defined(__WATCOMC__) 435#if defined(__WATCOMC__)
400# undef HAVE_DPRINTF 436# undef HAVE_DPRINTF
401# undef HAVE_GETLINE 437# undef HAVE_GETLINE
@@ -493,6 +529,7 @@ extern int dprintf(int fd, const char *format, ...);
493#endif 529#endif
494 530
495#ifndef HAVE_MEMRCHR 531#ifndef HAVE_MEMRCHR
532#include <stddef.h>
496extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC; 533extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC;
497#endif 534#endif
498 535
@@ -535,6 +572,7 @@ extern int usleep(unsigned) FAST_FUNC;
535#endif 572#endif
536 573
537#ifndef HAVE_VASPRINTF 574#ifndef HAVE_VASPRINTF
575# include <stdarg.h>
538extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC; 576extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC;
539#endif 577#endif
540 578
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index 7fb687227..d94b65008 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -37,25 +37,19 @@ lib-y += fgets_str.o
37lib-y += find_pid_by_name.o 37lib-y += find_pid_by_name.o
38lib-y += find_root_device.o 38lib-y += find_root_device.o
39lib-y += full_write.o 39lib-y += full_write.o
40lib-y += get_console.o
41lib-y += get_last_path_component.o 40lib-y += get_last_path_component.o
42lib-y += get_line_from_file.o 41lib-y += get_line_from_file.o
43lib-y += getopt32.o 42lib-y += getopt32.o
44lib-y += getpty.o
45lib-y += get_volsize.o 43lib-y += get_volsize.o
46lib-y += herror_msg.o 44lib-y += herror_msg.o
47lib-y += human_readable.o 45lib-y += human_readable.o
48lib-y += inet_common.o
49lib-y += info_msg.o 46lib-y += info_msg.o
50lib-y += inode_hash.o 47lib-y += inode_hash.o
51lib-y += isdirectory.o 48lib-y += isdirectory.o
52lib-y += kernel_version.o
53lib-y += last_char_is.o 49lib-y += last_char_is.o
54lib-y += lineedit.o lineedit_ptr_hack.o 50lib-y += lineedit.o lineedit_ptr_hack.o
55lib-y += llist.o 51lib-y += llist.o
56lib-y += login.o
57lib-y += make_directory.o 52lib-y += make_directory.o
58lib-y += makedev.o
59lib-y += hash_md5_sha.o 53lib-y += hash_md5_sha.o
60# Alternative (disabled) MD5 implementation 54# Alternative (disabled) MD5 implementation
61#lib-y += hash_md5prime.o 55#lib-y += hash_md5prime.o
@@ -76,7 +70,6 @@ lib-y += progress.o
76lib-y += ptr_to_globals.o 70lib-y += ptr_to_globals.o
77lib-y += read.o 71lib-y += read.o
78lib-y += read_printf.o 72lib-y += read_printf.o
79lib-y += read_key.o
80lib-y += recursive_action.o 73lib-y += recursive_action.o
81lib-y += remove_file.o 74lib-y += remove_file.o
82lib-y += run_shell.o 75lib-y += run_shell.o
@@ -85,7 +78,6 @@ lib-y += safe_poll.o
85lib-y += safe_strncpy.o 78lib-y += safe_strncpy.o
86lib-y += safe_write.o 79lib-y += safe_write.o
87lib-y += setup_environment.o 80lib-y += setup_environment.o
88lib-y += signals.o
89lib-y += simplify_path.o 81lib-y += simplify_path.o
90lib-y += single_argv.o 82lib-y += single_argv.o
91lib-y += skip_whitespace.o 83lib-y += skip_whitespace.o
@@ -110,10 +102,20 @@ lib-y += xfuncs.o
110lib-y += xfuncs_printf.o 102lib-y += xfuncs_printf.o
111lib-y += xfunc_die.o 103lib-y += xfunc_die.o
112lib-y += xgetcwd.o 104lib-y += xgetcwd.o
113lib-y += xgethostbyname.o
114lib-y += xreadlink.o 105lib-y += xreadlink.o
115lib-y += xrealloc_vector.o 106lib-y += xrealloc_vector.o
116 107
108lib-$(CONFIG_PLATFORM_POSIX) += get_console.o
109lib-$(CONFIG_PLATFORM_POSIX) += getpty.o
110lib-$(CONFIG_PLATFORM_POSIX) += inet_common.o
111lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o
112lib-$(CONFIG_PLATFORM_POSIX) += login.o
113lib-$(CONFIG_PLATFORM_POSIX) += makedev.o
114lib-$(CONFIG_PLATFORM_POSIX) += read_key.o
115lib-$(CONFIG_PLATFORM_POSIX) += signals.o
116lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o
117lib-$(CONFIG_PLATFORM_POSIX) += xgethostbyname.o
118
117lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o 119lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o
118 120
119lib-$(CONFIG_FEATURE_UTMP) += utmp.o 121lib-$(CONFIG_FEATURE_UTMP) += utmp.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 54300bd87..dba66cc93 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -187,6 +187,10 @@ void lbb_prepare(const char *applet
187 if (ENABLE_LOCALE_SUPPORT) 187 if (ENABLE_LOCALE_SUPPORT)
188 setlocale(LC_ALL, ""); 188 setlocale(LC_ALL, "");
189 189
190#if ENABLE_PLATFORM_MINGW32
191 init_winsock();
192#endif
193
190#if ENABLE_FEATURE_INDIVIDUAL 194#if ENABLE_FEATURE_INDIVIDUAL
191 /* Redundant for busybox (run_applet_and_exit covers that case) 195 /* Redundant for busybox (run_applet_and_exit covers that case)
192 * but needed for "individual applet" mode */ 196 * but needed for "individual applet" mode */
@@ -642,10 +646,19 @@ static int busybox_main(char **argv)
642 ) 646 )
643 " or: function [arguments]...\n" 647 " or: function [arguments]...\n"
644 "\n" 648 "\n"
649 IF_NOT_FEATURE_SH_STANDALONE(
645 "\tBusyBox is a multi-call binary that combines many common Unix\n" 650 "\tBusyBox is a multi-call binary that combines many common Unix\n"
646 "\tutilities into a single executable. Most people will create a\n" 651 "\tutilities into a single executable. Most people will create a\n"
647 "\tlink to busybox for each function they wish to use and BusyBox\n" 652 "\tlink to busybox for each function they wish to use and BusyBox\n"
648 "\twill act like whatever it was invoked as.\n" 653 "\twill act like whatever it was invoked as.\n"
654 )
655 IF_FEATURE_SH_STANDALONE(
656 "\tBusyBox is a multi-call binary that combines many common Unix\n"
657 "\tutilities into a single executable. This version has been\n"
658 "\tconfigured to prefer built-in utilities to external binaries.\n"
659 "\tThis avoids having to install a link to busybox for each\n"
660 "\tfunction to be invoked.\n"
661 )
649 "\n" 662 "\n"
650 "Currently defined functions:\n" 663 "Currently defined functions:\n"
651 ); 664 );
@@ -815,6 +828,18 @@ int main(int argc UNUSED_PARAM, char **argv)
815 } 828 }
816#endif 829#endif
817 830
831#if defined(__MINGW64_VERSION_MAJOR)
832 if ( stdin ) {
833 _setmode(fileno(stdin), _O_BINARY);
834 }
835 if ( stdout ) {
836 _setmode(fileno(stdout), _O_BINARY);
837 }
838 if ( stderr ) {
839 _setmode(fileno(stderr), _O_BINARY);
840 }
841#endif
842
818#if defined(SINGLE_APPLET_MAIN) 843#if defined(SINGLE_APPLET_MAIN)
819 /* Only one applet is selected in .config */ 844 /* Only one applet is selected in .config */
820 if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) { 845 if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) {
@@ -830,6 +855,25 @@ int main(int argc UNUSED_PARAM, char **argv)
830 applet_name = argv[0]; 855 applet_name = argv[0];
831 if (applet_name[0] == '-') 856 if (applet_name[0] == '-')
832 applet_name++; 857 applet_name++;
858 if (ENABLE_PLATFORM_MINGW32) {
859 const char *applet_name_env = getenv("BUSYBOX_APPLET_NAME");
860 if (applet_name_env && *applet_name_env) {
861 applet_name = applet_name_env;
862 unsetenv("BUSYBOX_APPLET_NAME");
863 }
864 else {
865 char *s = argv[0];
866 int i, len = strlen(s);
867
868 for ( i=0; i < len; ++i ) {
869 s[i] = tolower(s[i]);
870 }
871 if (len > 4 && !strcmp(s+len-4, ".exe")) {
872 len -= 4;
873 s[len] = '\0';
874 }
875 }
876 }
833 applet_name = bb_basename(applet_name); 877 applet_name = bb_basename(applet_name);
834 878
835 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */ 879 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index a4be875d2..a427c441f 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -100,12 +100,15 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
100 return -1; 100 return -1;
101 } 101 }
102 } else { 102 } else {
103#if !ENABLE_PLATFORM_MINGW32
104 /* MinGW does not have inode, and does not use device */
103 if (source_stat.st_dev == dest_stat.st_dev 105 if (source_stat.st_dev == dest_stat.st_dev
104 && source_stat.st_ino == dest_stat.st_ino 106 && source_stat.st_ino == dest_stat.st_ino
105 ) { 107 ) {
106 bb_error_msg("'%s' and '%s' are the same file", source, dest); 108 bb_error_msg("'%s' and '%s' are the same file", source, dest);
107 return -1; 109 return -1;
108 } 110 }
111#endif
109 dest_exists = 1; 112 dest_exists = 1;
110 } 113 }
111 114
diff --git a/libbb/executable.c b/libbb/executable.c
index 85ecc3e6c..12a48cea3 100644
--- a/libbb/executable.c
+++ b/libbb/executable.c
@@ -28,6 +28,10 @@ int FAST_FUNC file_is_executable(const char *name)
28 * return NULL otherwise; (PATHp is undefined) 28 * return NULL otherwise; (PATHp is undefined)
29 * in all cases (*PATHp) contents will be trashed (s/:/NUL/). 29 * in all cases (*PATHp) contents will be trashed (s/:/NUL/).
30 */ 30 */
31#if !ENABLE_PLATFORM_MINGW32
32#define next_path_sep(s) strchr(s, ':')
33#endif
34
31char* FAST_FUNC find_executable(const char *filename, char **PATHp) 35char* FAST_FUNC find_executable(const char *filename, char **PATHp)
32{ 36{
33 /* About empty components in $PATH: 37 /* About empty components in $PATH:
@@ -39,10 +43,13 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp)
39 * following the rest of the list. 43 * following the rest of the list.
40 */ 44 */
41 char *p, *n; 45 char *p, *n;
46#if ENABLE_PLATFORM_MINGW32
47 char *w;
48#endif
42 49
43 p = *PATHp; 50 p = *PATHp;
44 while (p) { 51 while (p) {
45 n = strchr(p, ':'); 52 n = (char*)next_path_sep(p);
46 if (n) 53 if (n)
47 *n++ = '\0'; 54 *n++ = '\0';
48 p = concat_path_file( 55 p = concat_path_file(
@@ -53,6 +60,13 @@ char* FAST_FUNC find_executable(const char *filename, char **PATHp)
53 *PATHp = n; 60 *PATHp = n;
54 return p; 61 return p;
55 } 62 }
63#if ENABLE_PLATFORM_MINGW32
64 else if ((w=file_is_win32_executable(p))) {
65 *PATHp = n;
66 free(p);
67 return w;
68 }
69#endif
56 free(p); 70 free(p);
57 p = n; 71 p = n;
58 } /* on loop exit p == NULL */ 72 } /* on loop exit p == NULL */
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
index 9676b5f52..b9bc1dd76 100644
--- a/libbb/find_mount_point.c
+++ b/libbb/find_mount_point.c
@@ -24,10 +24,18 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
24 struct mntent *mountEntry; 24 struct mntent *mountEntry;
25 dev_t devno_of_name; 25 dev_t devno_of_name;
26 bool block_dev; 26 bool block_dev;
27#if ENABLE_PLATFORM_MINGW32
28 static char mnt_fsname[4];
29 static char mnt_dir[4];
30 struct mntent my_mount_entry = { mnt_fsname, mnt_dir, "", "", 0, 0 };
31 char *current, *path;
32 DWORD len;
33#endif
27 34
28 if (stat(name, &s) != 0) 35 if (stat(name, &s) != 0)
29 return NULL; 36 return NULL;
30 37
38#if !ENABLE_PLATFORM_MINGW32
31 devno_of_name = s.st_dev; 39 devno_of_name = s.st_dev;
32 block_dev = 0; 40 block_dev = 0;
33 /* Why S_ISCHR? - UBI volumes use char devices, not block */ 41 /* Why S_ISCHR? - UBI volumes use char devices, not block */
@@ -64,6 +72,35 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
64 break; 72 break;
65 } 73 }
66 endmntent(mtab_fp); 74 endmntent(mtab_fp);
75#else
76 mountEntry = NULL;
77 path = NULL;
78 current = NULL;
79
80 if ( isalpha(name[0]) && name[1] == ':' ) {
81 path = name;
82 }
83 else {
84 if ( (len=GetCurrentDirectory(0, NULL)) > 0 &&
85 (current=malloc(len+1)) != NULL &&
86 GetCurrentDirectory(len, current) ) {
87 path = current;
88 }
89 }
90
91 if ( path && isalpha(path[0]) && path[1] == ':' ) {
92 mnt_fsname[0] = path[0];
93 mnt_fsname[1] = path[1];
94 mnt_fsname[2] = '\0';
95 mnt_dir[0] = path[0];
96 mnt_dir[1] = path[1];
97 mnt_dir[2] = '\\';
98 mnt_dir[3] = '\0';
99
100 mountEntry = &my_mount_entry;
101 }
102 free(current);
103#endif
67 104
68 return mountEntry; 105 return mountEntry;
69} 106}
diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c
index db823d05b..d4bea8ab5 100644
--- a/libbb/find_pid_by_name.c
+++ b/libbb/find_pid_by_name.c
@@ -56,6 +56,7 @@ static int comm_match(procps_status_t *p, const char *procName)
56 * This can be crazily_long_script_name.sh! 56 * This can be crazily_long_script_name.sh!
57 * The telltale sign is basename(argv[1]) == procName */ 57 * The telltale sign is basename(argv[1]) == procName */
58 58
59#if !ENABLE_PLATFORM_MINGW32
59 if (!p->argv0) 60 if (!p->argv0)
60 return 0; 61 return 0;
61 62
@@ -66,6 +67,7 @@ static int comm_match(procps_status_t *p, const char *procName)
66 67
67 if (strcmp(bb_basename(argv1), procName) != 0) 68 if (strcmp(bb_basename(argv1), procName) != 0)
68 return 0; 69 return 0;
70#endif
69 71
70 return 1; 72 return 1;
71} 73}
@@ -88,10 +90,12 @@ pid_t* FAST_FUNC find_pid_by_name(const char *procName)
88 pidList = xzalloc(sizeof(*pidList)); 90 pidList = xzalloc(sizeof(*pidList));
89 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN|PSSCAN_EXE))) { 91 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN|PSSCAN_EXE))) {
90 if (comm_match(p, procName) 92 if (comm_match(p, procName)
93#if !ENABLE_PLATFORM_MINGW32
91 /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/ 94 /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
92 || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0) 95 || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
93 /* or we require /proc/PID/exe link to match */ 96 /* or we require /proc/PID/exe link to match */
94 || (p->exe && strcmp(bb_basename(p->exe), procName) == 0) 97 || (p->exe && strcmp(bb_basename(p->exe), procName) == 0)
98#endif
95 ) { 99 ) {
96 pidList = xrealloc_vector(pidList, 2, i); 100 pidList = xrealloc_vector(pidList, 2, i);
97 pidList[i++] = p->pid; 101 pidList[i++] = p->pid;
diff --git a/libbb/get_last_path_component.c b/libbb/get_last_path_component.c
index 04fdf2a3e..db4be68ad 100644
--- a/libbb/get_last_path_component.c
+++ b/libbb/get_last_path_component.c
@@ -13,6 +13,11 @@ const char* FAST_FUNC bb_basename(const char *name)
13 const char *cp = strrchr(name, '/'); 13 const char *cp = strrchr(name, '/');
14 if (cp) 14 if (cp)
15 return cp + 1; 15 return cp + 1;
16#if ENABLE_PLATFORM_MINGW32
17 cp = strrchr(name, '\\');
18 if (cp)
19 return cp + 1;
20#endif
16 return name; 21 return name;
17} 22}
18 23
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
index a98dd35eb..2038fac7d 100644
--- a/libbb/get_line_from_file.c
+++ b/libbb/get_line_from_file.c
@@ -57,6 +57,10 @@ char* FAST_FUNC xmalloc_fgetline(FILE *file)
57 57
58 if (i && c[--i] == '\n') 58 if (i && c[--i] == '\n')
59 c[i] = '\0'; 59 c[i] = '\0';
60#if ENABLE_PLATFORM_MINGW32
61 if (i && c[--i] == '\r')
62 c[i] = '\0';
63#endif
60 64
61 return c; 65 return c;
62} 66}
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index d0e83d88e..ae019b26b 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -540,7 +540,7 @@ getopt32(char **argv, const char *applet_opts, ...)
540 * run_nofork_applet() does this, but we might end up here 540 * run_nofork_applet() does this, but we might end up here
541 * also via gunzip_main() -> gzip_main(). Play safe. 541 * also via gunzip_main() -> gzip_main(). Play safe.
542 */ 542 */
543#ifdef __GLIBC__ 543#if defined(__GLIBC__) || ENABLE_PLATFORM_MINGW32
544 optind = 0; 544 optind = 0;
545#else /* BSD style */ 545#else /* BSD style */
546 optind = 1; 546 optind = 1;
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
index f11c2afb2..64f43b885 100644
--- a/libbb/inode_hash.c
+++ b/libbb/inode_hash.c
@@ -59,6 +59,7 @@ char* FAST_FUNC is_in_ino_dev_hashtable(const struct stat *statbuf)
59/* Add statbuf to statbuf hash table */ 59/* Add statbuf to statbuf hash table */
60void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) 60void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
61{ 61{
62#if !ENABLE_PLATFORM_MINGW32
62 int i; 63 int i;
63 ino_dev_hashtable_bucket_t *bucket; 64 ino_dev_hashtable_bucket_t *bucket;
64 65
@@ -76,6 +77,7 @@ void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *
76 i = hash_inode(statbuf->st_ino); 77 i = hash_inode(statbuf->st_ino);
77 bucket->next = ino_dev_hashtable[i]; 78 bucket->next = ino_dev_hashtable[i];
78 ino_dev_hashtable[i] = bucket; 79 ino_dev_hashtable[i] = bucket;
80#endif
79} 81}
80 82
81#if ENABLE_DU || ENABLE_FEATURE_CLEAN_UP 83#if ENABLE_DU || ENABLE_FEATURE_CLEAN_UP
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 720a4951e..3d96a8e9f 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -346,7 +346,7 @@ int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
346/* Put 'command_ps[cursor]', cursor++. 346/* Put 'command_ps[cursor]', cursor++.
347 * Advance cursor on screen. If we reached right margin, scroll text up 347 * Advance cursor on screen. If we reached right margin, scroll text up
348 * and remove terminal margin effect by printing 'next_char' */ 348 * and remove terminal margin effect by printing 'next_char' */
349#define HACK_FOR_WRONG_WIDTH 1 349#define HACK_FOR_WRONG_WIDTH 1 && !ENABLE_PLATFORM_MINGW32
350static void put_cur_glyph_and_inc_cursor(void) 350static void put_cur_glyph_and_inc_cursor(void)
351{ 351{
352 CHAR_T c = command_ps[cursor]; 352 CHAR_T c = command_ps[cursor];
@@ -409,6 +409,42 @@ static void put_cur_glyph_and_inc_cursor(void)
409 } 409 }
410} 410}
411 411
412#if ENABLE_PLATFORM_MINGW32
413static void inc_cursor(void)
414{
415 CHAR_T c = command_ps[cursor];
416 unsigned width = 0;
417 int ofs_to_right;
418
419 /* advance cursor */
420 cursor++;
421 if (unicode_status == UNICODE_ON) {
422 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
423 c = adjust_width_and_validate_wc(&cmdedit_x, c);
424 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
425 } else {
426 cmdedit_x++;
427 }
428
429 ofs_to_right = cmdedit_x - cmdedit_termw;
430 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
431 /* cursor remains on this line */
432 printf(ESC"[1C");
433 }
434
435 if (ofs_to_right >= 0) {
436 /* we go to the next line */
437 printf(ESC"[1B");
438 bb_putchar('\r');
439 cmdedit_y++;
440 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
441 width = 0;
442 }
443 cmdedit_x = width;
444 }
445}
446#endif
447
412/* Move to end of line (by printing all chars till the end) */ 448/* Move to end of line (by printing all chars till the end) */
413static void put_till_end_and_adv_cursor(void) 449static void put_till_end_and_adv_cursor(void)
414{ 450{
@@ -465,6 +501,7 @@ static void input_backward(unsigned num)
465 501
466 if (cmdedit_x >= num) { 502 if (cmdedit_x >= num) {
467 cmdedit_x -= num; 503 cmdedit_x -= num;
504#if !ENABLE_PLATFORM_MINGW32
468 if (num <= 4) { 505 if (num <= 4) {
469 /* This is longer by 5 bytes on x86. 506 /* This is longer by 5 bytes on x86.
470 * Also gets miscompiled for ARM users 507 * Also gets miscompiled for ARM users
@@ -477,6 +514,7 @@ static void input_backward(unsigned num)
477 } while (--num); 514 } while (--num);
478 return; 515 return;
479 } 516 }
517#endif
480 printf(ESC"[%uD", num); 518 printf(ESC"[%uD", num);
481 return; 519 return;
482 } 520 }
@@ -608,7 +646,11 @@ static void input_backspace(void)
608static void input_forward(void) 646static void input_forward(void)
609{ 647{
610 if (cursor < command_len) 648 if (cursor < command_len)
649#if !ENABLE_PLATFORM_MINGW32
611 put_cur_glyph_and_inc_cursor(); 650 put_cur_glyph_and_inc_cursor();
651#else
652 inc_cursor();
653#endif
612} 654}
613 655
614#if ENABLE_FEATURE_TAB_COMPLETION 656#if ENABLE_FEATURE_TAB_COMPLETION
@@ -719,7 +761,11 @@ static int path_parse(char ***p)
719 tmp = (char*)pth; 761 tmp = (char*)pth;
720 npth = 1; /* path component count */ 762 npth = 1; /* path component count */
721 while (1) { 763 while (1) {
764#if ENABLE_PLATFORM_MINGW32
765 tmp = next_path_sep(tmp);
766#else
722 tmp = strchr(tmp, ':'); 767 tmp = strchr(tmp, ':');
768#endif
723 if (!tmp) 769 if (!tmp)
724 break; 770 break;
725 tmp++; 771 tmp++;
@@ -732,7 +778,11 @@ static int path_parse(char ***p)
732 res[0] = tmp = xstrdup(pth); 778 res[0] = tmp = xstrdup(pth);
733 npth = 1; 779 npth = 1;
734 while (1) { 780 while (1) {
781#if ENABLE_PLATFORM_MINGW32
782 tmp = next_path_sep(tmp);
783#else
735 tmp = strchr(tmp, ':'); 784 tmp = strchr(tmp, ':');
785#endif
736 if (!tmp) 786 if (!tmp)
737 break; 787 break;
738 *tmp++ = '\0'; /* ':' -> '\0' */ 788 *tmp++ = '\0'; /* ':' -> '\0' */
@@ -1886,7 +1936,11 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1886 /* /home/user[/something] -> ~[/something] */ 1936 /* /home/user[/something] -> ~[/something] */
1887 l = strlen(home_pwd_buf); 1937 l = strlen(home_pwd_buf);
1888 if (l != 0 1938 if (l != 0
1939#if !ENABLE_PLATFORM_MINGW32
1889 && strncmp(home_pwd_buf, cwd_buf, l) == 0 1940 && strncmp(home_pwd_buf, cwd_buf, l) == 0
1941#else
1942 && strncasecmp(home_pwd_buf, cwd_buf, l) == 0
1943#endif
1890 && (cwd_buf[l] == '/' || cwd_buf[l] == '\0') 1944 && (cwd_buf[l] == '/' || cwd_buf[l] == '\0')
1891 ) { 1945 ) {
1892 cwd_buf[0] = '~'; 1946 cwd_buf[0] = '~';
@@ -2255,9 +2309,16 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2255 2309
2256 INIT_S(); 2310 INIT_S();
2257 2311
2312#if ENABLE_PLATFORM_MINGW32
2313 memset(initial_settings.c_cc, sizeof(initial_settings.c_cc), 0);
2314 initial_settings.c_cc[VINTR] = CTRL('C');
2315 initial_settings.c_cc[VEOF] = CTRL('D');
2316 if (!isatty(0) || !isatty(1)) {
2317#else
2258 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0 2318 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
2259 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON 2319 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON
2260 ) { 2320 ) {
2321#endif
2261 /* Happens when e.g. stty -echo was run before. 2322 /* Happens when e.g. stty -echo was run before.
2262 * But if ICANON is not set, we don't come here. 2323 * But if ICANON is not set, we don't come here.
2263 * (example: interactive python ^Z-backgrounded, 2324 * (example: interactive python ^Z-backgrounded,
@@ -2611,7 +2672,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2611 * standard readline bindings (IOW: bash) do. 2672 * standard readline bindings (IOW: bash) do.
2612 * Often, Alt-<key> generates ESC-<key>. 2673 * Often, Alt-<key> generates ESC-<key>.
2613 */ 2674 */
2614 ic = lineedit_read_key(read_key_buffer, 50); 2675 ic = lineedit_read_key(read_key_buffer, 20);
2615 switch (ic) { 2676 switch (ic) {
2616 //case KEYCODE_LEFT: - bash doesn't do this 2677 //case KEYCODE_LEFT: - bash doesn't do this
2617 case 'b': 2678 case 'b':
diff --git a/libbb/make_directory.c b/libbb/make_directory.c
index 89352ca1f..3980376ec 100644
--- a/libbb/make_directory.c
+++ b/libbb/make_directory.c
@@ -45,6 +45,31 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
45 c = '\0'; 45 c = '\0';
46 46
47 if (flags & FILEUTILS_RECUR) { /* Get the parent */ 47 if (flags & FILEUTILS_RECUR) { /* Get the parent */
48#if ENABLE_PLATFORM_MINGW32
49 if (s == path && *s && s[1] == ':') {
50 /* skip drive letter */
51 s += 2;
52 }
53 else if (s == path && s[0] == '/' && s[1] == '/' ) {
54 /* skip UNC server and share */
55 int count = 0;
56 s += 2;
57 while (*s) {
58 if (*s == '/') {
59 do {
60 ++s;
61 } while (*s == '/');
62 if (++count == 2) {
63 --s;
64 break;
65 }
66 }
67 else {
68 ++s;
69 }
70 }
71 }
72#endif
48 /* Bypass leading non-'/'s and then subsequent '/'s */ 73 /* Bypass leading non-'/'s and then subsequent '/'s */
49 while (*s) { 74 while (*s) {
50 if (*s == '/') { 75 if (*s == '/') {
diff --git a/libbb/messages.c b/libbb/messages.c
index fad82c9da..ef42b30d7 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -35,7 +35,9 @@ const char bb_msg_standard_output[] ALIGN1 = "standard output";
35 35
36const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; 36const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
37 37
38#if !ENABLE_PLATFORM_MINGW32
38const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; 39const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
40#endif
39const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; 41const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
40/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 42/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
41 * but I want to save a few bytes here. Check libbb.h before changing! */ 43 * but I want to save a few bytes here. Check libbb.h before changing! */
diff --git a/libbb/printable_string.c b/libbb/printable_string.c
index a316f60de..3e768d0b9 100644
--- a/libbb/printable_string.c
+++ b/libbb/printable_string.c
@@ -45,7 +45,7 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
45 unsigned char c = *d; 45 unsigned char c = *d;
46 if (c == '\0') 46 if (c == '\0')
47 break; 47 break;
48 if (c < ' ' || c >= 0x7f) 48 if (c < ' ' || (c >= 0x7f && !ENABLE_PLATFORM_MINGW32))
49 *d = '?'; 49 *d = '?';
50 d++; 50 d++;
51 } 51 }
diff --git a/libbb/procps.c b/libbb/procps.c
index 5b68d3431..3c99ac6e7 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -75,6 +75,7 @@ const char* FAST_FUNC get_cached_groupname(gid_t gid)
75 return get_cached(&groupname, gid, gid2group_utoa); 75 return get_cached(&groupname, gid, gid2group_utoa);
76} 76}
77 77
78#if !ENABLE_PLATFORM_MINGW32
78 79
79#define PROCPS_BUFSIZE 1024 80#define PROCPS_BUFSIZE 1024
80 81
@@ -620,6 +621,8 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
620 } 621 }
621} 622}
622 623
624#endif /* ENABLE_PLATFORM_MINGW32 */
625
623/* from kernel: 626/* from kernel:
624 // pid comm S ppid pgid sid tty_nr tty_pgrp flg 627 // pid comm S ppid pgid sid tty_nr tty_pgrp flg
625 sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ 628 sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index 5ed6e3632..ef4911cd5 100644
--- a/libbb/read_printf.c
+++ b/libbb/read_printf.c
@@ -93,6 +93,11 @@ char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p)
93 break; 93 break;
94 p++; 94 p++;
95 } 95 }
96#if ENABLE_PLATFORM_MINGW32
97 if ( p != buf && *(p-1) == '\r' ) {
98 --p;
99 }
100#endif
96 *p = '\0'; 101 *p = '\0';
97 if (maxsz_p) 102 if (maxsz_p)
98 *maxsz_p = p - buf; 103 *maxsz_p = p - buf;
diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c
index 4258656fe..944ac5538 100644
--- a/libbb/setup_environment.c
+++ b/libbb/setup_environment.c
@@ -30,6 +30,14 @@
30 30
31#include "libbb.h" 31#include "libbb.h"
32 32
33#if ENABLE_PLATFORM_MINGW32
34static void xsetenv_if_unset(const char *key, const char *value)
35{
36 if (!getenv(key))
37 xsetenv(key, value);
38}
39#endif
40
33void FAST_FUNC setup_environment(const char *shell, int flags, const struct passwd *pw) 41void FAST_FUNC setup_environment(const char *shell, int flags, const struct passwd *pw)
34{ 42{
35 if (!shell || !shell[0]) 43 if (!shell || !shell[0])
@@ -61,6 +69,9 @@ void FAST_FUNC setup_environment(const char *shell, int flags, const struct pass
61 //xsetenv("HOME", pw->pw_dir); 69 //xsetenv("HOME", pw->pw_dir);
62 //xsetenv("SHELL", shell); 70 //xsetenv("SHELL", shell);
63 } else if (flags & SETUP_ENV_CHANGEENV) { 71 } else if (flags & SETUP_ENV_CHANGEENV) {
72#if ENABLE_PLATFORM_MINGW32
73#define xsetenv(k, v) xsetenv_if_unset(k, v)
74#endif
64 /* Set HOME, SHELL, and if not becoming a super-user, 75 /* Set HOME, SHELL, and if not becoming a super-user,
65 * USER and LOGNAME. */ 76 * USER and LOGNAME. */
66 if (pw->pw_uid) { 77 if (pw->pw_uid) {
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index ed1f86f0c..6611dabfa 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -25,6 +25,9 @@ pid_t FAST_FUNC spawn(char **argv)
25 volatile int failed; 25 volatile int failed;
26 pid_t pid; 26 pid_t pid;
27 27
28 if (ENABLE_PLATFORM_MINGW32)
29 return mingw_spawn(argv);
30
28 fflush_all(); 31 fflush_all();
29 32
30 /* Be nice to nommu machines. */ 33 /* Be nice to nommu machines. */
@@ -183,7 +186,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
183 { 186 {
184 return run_nofork_applet(a, argv); 187 return run_nofork_applet(a, argv);
185 } 188 }
186# if BB_MMU 189# if BB_MMU && !ENABLE_PLATFORM_MINGW32
187 /* MMU only */ 190 /* MMU only */
188 /* a->noexec is true */ 191 /* a->noexec is true */
189 rc = fork(); 192 rc = fork();
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
index 7d4cb60a5..2c5a9ef39 100644
--- a/libbb/xreadlink.c
+++ b/libbb/xreadlink.c
@@ -65,7 +65,7 @@ char* FAST_FUNC xmalloc_follow_symlinks(const char *path)
65 linkpath = xmalloc_readlink(buf); 65 linkpath = xmalloc_readlink(buf);
66 if (!linkpath) { 66 if (!linkpath) {
67 /* not a symlink, or doesn't exist */ 67 /* not a symlink, or doesn't exist */
68 if (errno == EINVAL || errno == ENOENT) 68 if (errno == EINVAL || errno == ENOENT || (ENABLE_PLATFORM_MINGW32 && errno == ENOSYS))
69 return buf; 69 return buf;
70 goto free_buf_ret_null; 70 goto free_buf_ret_null;
71 } 71 }
diff --git a/miscutils/man.c b/miscutils/man.c
index c39870e67..3f389b435 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -153,7 +153,11 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path)
153 char *next_path; 153 char *next_path;
154 char **path_element; 154 char **path_element;
155 155
156#if ENABLE_PLATFORM_MINGW32
157 next_path = next_path_sep(path);
158#else
156 next_path = strchr(path, ':'); 159 next_path = strchr(path, ':');
160#endif
157 if (next_path) { 161 if (next_path) {
158 if (next_path == path) /* "::"? */ 162 if (next_path == path) /* "::"? */
159 goto next; 163 goto next;
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 8283366cc..0670b2141 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -100,6 +100,9 @@ static int ftpcmd(const char *s1, const char *s2)
100 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3), 100 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3),
101 s1, s2); 101 s1, s2);
102 fflush(control_stream); 102 fflush(control_stream);
103#if ENABLE_PLATFORM_MINGW32
104 fseek(control_stream, 0L, SEEK_CUR);
105#endif
103 } 106 }
104 107
105 do { 108 do {
@@ -108,6 +111,9 @@ static int ftpcmd(const char *s1, const char *s2)
108 ftp_die(NULL); 111 ftp_die(NULL);
109 } 112 }
110 } while (!isdigit(buf[0]) || buf[3] != ' '); 113 } while (!isdigit(buf[0]) || buf[3] != ' ');
114#if ENABLE_PLATFORM_MINGW32
115 fseek(control_stream, 0L, SEEK_CUR);
116#endif
111 117
112 buf[3] = '\0'; 118 buf[3] = '\0';
113 n = xatou(buf); 119 n = xatou(buf);
diff --git a/networking/wget.c b/networking/wget.c
index 1013f66cb..774accf7a 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -258,11 +258,17 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp)
258 fprintf(fp, "%s%s\r\n", s1, s2); 258 fprintf(fp, "%s%s\r\n", s1, s2);
259 fflush(fp); 259 fflush(fp);
260 log_io("> %s%s", s1, s2); 260 log_io("> %s%s", s1, s2);
261#if ENABLE_PLATFORM_MINGW32
262 fseek(fp, 0L, SEEK_CUR);
263#endif
261 } 264 }
262 265
263 do { 266 do {
264 fgets_and_trim(fp); 267 fgets_and_trim(fp);
265 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); 268 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
269#if ENABLE_PLATFORM_MINGW32
270 fseek(fp, 0L, SEEK_CUR);
271#endif
266 272
267 G.wget_buf[3] = '\0'; 273 G.wget_buf[3] = '\0';
268 result = xatoi_positive(G.wget_buf); 274 result = xatoi_positive(G.wget_buf);
@@ -285,10 +291,12 @@ static void parse_url(const char *src_url, struct host_info *h)
285 if (strcmp(url, P_FTP) == 0) { 291 if (strcmp(url, P_FTP) == 0) {
286 h->port = bb_lookup_port(P_FTP, "tcp", 21); 292 h->port = bb_lookup_port(P_FTP, "tcp", 21);
287 } else 293 } else
294#if !ENABLE_PLATFORM_MINGW32
288 if (strcmp(url, P_HTTPS) == 0) { 295 if (strcmp(url, P_HTTPS) == 0) {
289 h->port = bb_lookup_port(P_HTTPS, "tcp", 443); 296 h->port = bb_lookup_port(P_HTTPS, "tcp", 443);
290 h->protocol = P_HTTPS; 297 h->protocol = P_HTTPS;
291 } else 298 } else
299#endif
292 if (strcmp(url, P_HTTP) == 0) { 300 if (strcmp(url, P_HTTP) == 0) {
293 http: 301 http:
294 h->port = bb_lookup_port(P_HTTP, "tcp", 80); 302 h->port = bb_lookup_port(P_HTTP, "tcp", 80);
@@ -483,6 +491,7 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
483 return sfp; 491 return sfp;
484} 492}
485 493
494#if !ENABLE_PLATFORM_MINGW32
486static int spawn_https_helper(const char *host, unsigned port) 495static int spawn_https_helper(const char *host, unsigned port)
487{ 496{
488 char *allocated = NULL; 497 char *allocated = NULL;
@@ -532,6 +541,7 @@ static int spawn_https_helper(const char *host, unsigned port)
532 close(sp[1]); 541 close(sp[1]);
533 return sp[0]; 542 return sp[0];
534} 543}
544#endif
535 545
536/* See networking/ssl_helper/README */ 546/* See networking/ssl_helper/README */
537#define SSL_HELPER 0 547#define SSL_HELPER 0
@@ -814,6 +824,7 @@ static void download_one_url(const char *url)
814 int status; 824 int status;
815 825
816 /* Open socket to http(s) server */ 826 /* Open socket to http(s) server */
827#if !ENABLE_PLATFORM_MINGW32
817 if (target.protocol == P_HTTPS) { 828 if (target.protocol == P_HTTPS) {
818/* openssl-based helper 829/* openssl-based helper
819 * Inconvenient API since we can't give it an open fd 830 * Inconvenient API since we can't give it an open fd
@@ -823,6 +834,7 @@ static void download_one_url(const char *url)
823 if (!sfp) 834 if (!sfp)
824 bb_perror_msg_and_die(bb_msg_memory_exhausted); 835 bb_perror_msg_and_die(bb_msg_memory_exhausted);
825 } else 836 } else
837#endif
826 sfp = open_socket(lsa); 838 sfp = open_socket(lsa);
827#if SSL_HELPER 839#if SSL_HELPER
828 if (target.protocol == P_HTTPS) 840 if (target.protocol == P_HTTPS)
diff --git a/procps/ps.c b/procps/ps.c
index c65fa012a..9fca3524e 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -240,6 +240,7 @@ static unsigned get_kernel_HZ(void)
240 240
241/* Print value to buf, max size+1 chars (including trailing '\0') */ 241/* Print value to buf, max size+1 chars (including trailing '\0') */
242 242
243#if !ENABLE_PLATFORM_MINGW32
243static void func_user(char *buf, int size, const procps_status_t *ps) 244static void func_user(char *buf, int size, const procps_status_t *ps)
244{ 245{
245#if 1 246#if 1
@@ -263,12 +264,14 @@ static void func_group(char *buf, int size, const procps_status_t *ps)
263{ 264{
264 safe_strncpy(buf, get_cached_groupname(ps->gid), size+1); 265 safe_strncpy(buf, get_cached_groupname(ps->gid), size+1);
265} 266}
267#endif
266 268
267static void func_comm(char *buf, int size, const procps_status_t *ps) 269static void func_comm(char *buf, int size, const procps_status_t *ps)
268{ 270{
269 safe_strncpy(buf, ps->comm, size+1); 271 safe_strncpy(buf, ps->comm, size+1);
270} 272}
271 273
274#if !ENABLE_PLATFORM_MINGW32
272static void func_state(char *buf, int size, const procps_status_t *ps) 275static void func_state(char *buf, int size, const procps_status_t *ps)
273{ 276{
274 safe_strncpy(buf, ps->state, size+1); 277 safe_strncpy(buf, ps->state, size+1);
@@ -278,12 +281,14 @@ static void func_args(char *buf, int size, const procps_status_t *ps)
278{ 281{
279 read_cmdline(buf, size+1, ps->pid, ps->comm); 282 read_cmdline(buf, size+1, ps->pid, ps->comm);
280} 283}
284#endif
281 285
282static void func_pid(char *buf, int size, const procps_status_t *ps) 286static void func_pid(char *buf, int size, const procps_status_t *ps)
283{ 287{
284 sprintf(buf, "%*u", size, ps->pid); 288 sprintf(buf, "%*u", size, ps->pid);
285} 289}
286 290
291#if !ENABLE_PLATFORM_MINGW32
287static void func_ppid(char *buf, int size, const procps_status_t *ps) 292static void func_ppid(char *buf, int size, const procps_status_t *ps)
288{ 293{
289 sprintf(buf, "%*u", size, ps->ppid); 294 sprintf(buf, "%*u", size, ps->ppid);
@@ -320,6 +325,7 @@ static void func_tty(char *buf, int size, const procps_status_t *ps)
320 if (ps->tty_major) /* tty field of "0" means "no tty" */ 325 if (ps->tty_major) /* tty field of "0" means "no tty" */
321 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor); 326 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
322} 327}
328#endif
323 329
324#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 330#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
325 331
@@ -390,13 +396,19 @@ static void func_pcpu(char *buf, int size, const procps_status_t *ps)
390 396
391static const ps_out_t out_spec[] = { 397static const ps_out_t out_spec[] = {
392/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */ 398/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */
399#if !ENABLE_PLATFORM_MINGW32
393 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, 400 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID },
394 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, 401 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID },
402#endif
395 { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, 403 { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM },
404#if !ENABLE_PLATFORM_MINGW32
396 { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM }, 405 { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM },
406#endif
397 { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID }, 407 { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID },
408#if !ENABLE_PLATFORM_MINGW32
398 { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID }, 409 { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID },
399 { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID }, 410 { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID },
411#endif
400#if ENABLE_FEATURE_PS_TIME 412#if ENABLE_FEATURE_PS_TIME
401 { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME }, 413 { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME },
402#endif 414#endif
@@ -409,11 +421,13 @@ static const ps_out_t out_spec[] = {
409#if ENABLE_FEATURE_PS_TIME 421#if ENABLE_FEATURE_PS_TIME
410 { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, 422 { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME },
411#endif 423#endif
424#if !ENABLE_PLATFORM_MINGW32
412 { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, 425 { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY },
413 { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, 426 { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ },
414/* Not mandated, but useful: */ 427/* Not mandated, but useful: */
415 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE }, 428 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE },
416 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, 429 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS },
430#endif
417#if ENABLE_SELINUX 431#if ENABLE_SELINUX
418 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, 432 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT },
419#endif 433#endif
@@ -552,6 +566,8 @@ static void format_process(const procps_status_t *ps)
552#if ENABLE_SELINUX 566#if ENABLE_SELINUX
553# define SELINUX_O_PREFIX "label," 567# define SELINUX_O_PREFIX "label,"
554# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") 568# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args")
569#elif ENABLE_PLATFORM_MINGW32
570# define DEFAULT_O_STR ("pid,comm")
555#else 571#else
556# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") 572# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args")
557#endif 573#endif
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 19f82df09..f012551af 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -104,7 +104,9 @@
104 104
105#include <sys/types.h> 105#include <sys/types.h>
106#include <sys/stat.h> 106#include <sys/stat.h>
107#ifndef __MINGW32__
107#include <sys/mman.h> 108#include <sys/mman.h>
109#endif
108#include <unistd.h> 110#include <unistd.h>
109#include <fcntl.h> 111#include <fcntl.h>
110#include <string.h> 112#include <string.h>
@@ -112,7 +114,9 @@
112#include <stdio.h> 114#include <stdio.h>
113#include <limits.h> 115#include <limits.h>
114#include <ctype.h> 116#include <ctype.h>
117#ifndef __MINGW32__
115#include <arpa/inet.h> 118#include <arpa/inet.h>
119#endif
116//bbox disabled: #include <alloca.h> 120//bbox disabled: #include <alloca.h>
117 121
118/* bbox: not needed 122/* bbox: not needed
@@ -122,6 +126,53 @@
122#define INT_FIG_ ntohl(0x4649475f) 126#define INT_FIG_ ntohl(0x4649475f)
123*/ 127*/
124 128
129#ifdef __MINGW32__
130#define UNUSED __attribute__ ((__unused__))
131
132/* Workaround specifically for fixdep */
133#define PROT_READ 0
134#define MAP_PRIVATE 0
135void *mmap(void *start UNUSED, size_t size, int prot UNUSED,
136 int flags UNUSED, int fd, off_t offset UNUSED)
137{
138 void *p;
139 void *curP;
140 ssize_t readB;
141
142 p = malloc(size);
143 if (!p)
144 return (void*)((long)-1);
145
146 curP = p;
147
148 while (size > 0)
149 {
150 readB = read(fd, curP, size);
151
152 if (readB == 0)
153 {
154 /* EOF reached */
155 break;
156 }
157 else if (readB < 0)
158 {
159 perror("fixdep: read config");
160 free(p);
161 return (void*)((long)-1);
162 }
163
164 size -= readB;
165 curP += readB;
166 }
167
168 return p;
169}
170void munmap(void *p, size_t size UNUSED)
171{
172 free(p);
173}
174#endif
175
125char *target; 176char *target;
126char *depfile; 177char *depfile;
127char *cmdline; 178char *cmdline;
diff --git a/shell/ash.c b/shell/ash.c
index 90fb00fbd..b95356034 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -17,6 +17,20 @@
17 */ 17 */
18 18
19/* 19/*
20 * MinGW notes
21 *
22 * - Environment variables from Windows will all be turned to uppercase.
23 * - PATH accepts both ; and : as separator, but can't be mixed
24 * - command without ".exe" extension is still understood as executable
25 * - shell scripts on the path are detected by the presence of '#!';
26 * the path to the interpreter is ignored, PATH is searched to find it
27 * - both / and \ are supported in PATH. Usually you must use /
28 * - trap/job does not work
29 * - /dev/null is supported for redirection
30 * - fake $PPID
31 */
32
33/*
20 * The following should be set to reflect the type of system you have: 34 * The following should be set to reflect the type of system you have:
21 * JOBS -> 1 if you have Berkeley job control, 0 otherwise. 35 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22 * define SYSV if you are running under System V. 36 * define SYSV if you are running under System V.
@@ -72,6 +86,10 @@
72# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 86# define PIPE_BUF 4096 /* amount of buffering in a pipe */
73#endif 87#endif
74 88
89#if !ENABLE_PLATFORM_MINGW32
90# define is_absolute_path(path) ((path)[0] == '/')
91#endif
92
75#if !BB_MMU 93#if !BB_MMU
76# error "Do not even bother, ash will not run on NOMMU machine" 94# error "Do not even bother, ash will not run on NOMMU machine"
77#endif 95#endif
@@ -201,6 +219,50 @@
201//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 219//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
202//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 220//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
203 221
222#if ENABLE_PLATFORM_MINGW32
223union node;
224struct strlist;
225struct job;
226
227struct forkshell {
228 /* filled by forkshell_copy() */
229 struct globals_var *gvp;
230 struct globals_misc *gmp;
231 struct tblentry **cmdtable;
232 /* struct alias **atab; */
233 /* struct parsefile *g_parsefile; */
234 HANDLE hMapFile;
235 void *old_base;
236 int nodeptr_offset;
237 int size;
238
239 /* type of forkshell */
240 int fpid;
241
242 /* optional data, used by forkshell_child */
243 int flags;
244 int fd[10];
245 union node *n;
246 char **argv;
247 char *string;
248 struct strlist *strlist;
249};
250
251enum {
252 FS_OPENHERE,
253 FS_EVALBACKCMD,
254 FS_EVALSUBSHELL,
255 FS_EVALPIPE,
256 FS_SHELLEXEC
257};
258
259static struct forkshell* forkshell_prepare(struct forkshell *fs);
260static void forkshell_init(const char *idstr);
261static void forkshell_child(struct forkshell *fs);
262static void sticky_free(void *p);
263#define free(p) sticky_free(p)
264static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
265#endif
204 266
205/* ============ Hash table sizes. Configurable. */ 267/* ============ Hash table sizes. Configurable. */
206 268
@@ -233,6 +295,9 @@ static const char *const optletters_optnames[] = {
233 ,"\0" "nolog" 295 ,"\0" "nolog"
234 ,"\0" "debug" 296 ,"\0" "debug"
235#endif 297#endif
298#if ENABLE_PLATFORM_MINGW32
299 ,"\0" "noconsole"
300#endif
236}; 301};
237 302
238#define optletters(n) optletters_optnames[n][0] 303#define optletters(n) optletters_optnames[n][0]
@@ -313,6 +378,9 @@ struct globals_misc {
313# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] 378# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
314# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] 379# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
315#endif 380#endif
381#if ENABLE_PLATFORM_MINGW32
382# define noconsole optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
383#endif
316 384
317 /* trap handler commands */ 385 /* trap handler commands */
318 /* 386 /*
@@ -2393,10 +2461,22 @@ path_advance(const char **path, const char *name)
2393 if (*path == NULL) 2461 if (*path == NULL)
2394 return NULL; 2462 return NULL;
2395 start = *path; 2463 start = *path;
2464#if ENABLE_PLATFORM_MINGW32
2465 p = next_path_sep(start);
2466 q = strchr(start, '%');
2467 if ((p && q && q < p) || (!p && q))
2468 p = q;
2469 if (!p)
2470 for (p = start; *p; p++)
2471 continue;
2472#else
2396 for (p = start; *p && *p != ':' && *p != '%'; p++) 2473 for (p = start; *p && *p != ':' && *p != '%'; p++)
2397 continue; 2474 continue;
2475#endif
2398 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2476 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2399 while (stackblocksize() < len) 2477
2478 /* preserve space for .exe too */
2479 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2400 growstackblock(); 2480 growstackblock();
2401 q = stackblock(); 2481 q = stackblock();
2402 if (p != start) { 2482 if (p != start) {
@@ -2408,10 +2488,19 @@ path_advance(const char **path, const char *name)
2408 pathopt = NULL; 2488 pathopt = NULL;
2409 if (*p == '%') { 2489 if (*p == '%') {
2410 pathopt = ++p; 2490 pathopt = ++p;
2491#if ENABLE_PLATFORM_MINGW32
2492 p = next_path_sep(start);
2493
2494 /* *p != ':' and '*' would suffice */
2495 if (!p)
2496 p = pathopt - 1;
2497#else
2411 while (*p && *p != ':') 2498 while (*p && *p != ':')
2412 p++; 2499 p++;
2500#endif
2413 } 2501 }
2414 if (*p == ':') 2502 if (*p == ':' ||
2503 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2415 *path = p + 1; 2504 *path = p + 1;
2416 else 2505 else
2417 *path = NULL; 2506 *path = NULL;
@@ -2513,6 +2602,106 @@ cdopt(void)
2513static const char * 2602static const char *
2514updatepwd(const char *dir) 2603updatepwd(const char *dir)
2515{ 2604{
2605#if ENABLE_PLATFORM_MINGW32
2606#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2607#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1]))
2608 /*
2609 * Due to Windows drive notion, getting pwd is a completely
2610 * different thing. Handle it in a separate routine
2611 */
2612
2613 char *new;
2614 char *p;
2615 char *cdcomppath;
2616 const char *lim;
2617 /*
2618 * There are five cases that make some kind of sense
2619 * absdrive + abspath: c:/path
2620 * absdrive + !abspath: c:path
2621 * !absdrive + abspath: /path
2622 * !absdrive + uncpath: //host/share
2623 * !absdrive + !abspath: path
2624 *
2625 * Damn DOS!
2626 * c:path behaviour is "undefined"
2627 * To properly handle this case, I have to keep track of cwd
2628 * of every drive, which is too painful to do.
2629 * So when c:path is given, I assume it's c:${curdir}path
2630 * with ${curdir} comes from the current drive
2631 */
2632 int absdrive = *dir && dir[1] == ':';
2633 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2634
2635 cdcomppath = ststrdup(dir);
2636 STARTSTACKSTR(new);
2637 if (!absdrive && curdir == nullstr)
2638 return 0;
2639 if (!abspath) {
2640 if (curdir == nullstr)
2641 return 0;
2642 new = stack_putstr(curdir, new);
2643 }
2644 new = makestrspace(strlen(dir) + 2, new);
2645
2646 if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) {
2647 lim = (char *)stackblock() + 1;
2648 }
2649 else {
2650 char *drive = stackblock();
2651 if (absdrive) {
2652 *drive = *dir;
2653 cdcomppath += 2;
2654 dir += 2;
2655 } else {
2656 *drive = *curdir;
2657 }
2658 drive[1] = ':'; /* in case of absolute drive+path */
2659
2660 if (abspath)
2661 new = drive + 2;
2662 lim = drive + 3;
2663 }
2664
2665 if (!abspath) {
2666 if (!is_path_sep(new[-1]))
2667 USTPUTC('/', new);
2668 if (new > lim && is_path_sep(*lim))
2669 lim++;
2670 } else {
2671 USTPUTC('/', new);
2672 cdcomppath ++;
2673 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2674 USTPUTC('/', new);
2675 cdcomppath++;
2676 lim++;
2677 }
2678 }
2679 p = strtok(cdcomppath, "/\\");
2680 while (p) {
2681 switch (*p) {
2682 case '.':
2683 if (p[1] == '.' && p[2] == '\0') {
2684 while (new > lim) {
2685 STUNPUTC(new);
2686 if (is_path_sep(new[-1]))
2687 break;
2688 }
2689 break;
2690 }
2691 if (p[1] == '\0')
2692 break;
2693 /* fall through */
2694 default:
2695 new = stack_putstr(p, new);
2696 USTPUTC('/', new);
2697 }
2698 p = strtok(0, "/\\");
2699 }
2700 if (new > lim)
2701 STUNPUTC(new);
2702 *new = 0;
2703 return stackblock();
2704#else
2516 char *new; 2705 char *new;
2517 char *p; 2706 char *p;
2518 char *cdcomppath; 2707 char *cdcomppath;
@@ -2566,6 +2755,7 @@ updatepwd(const char *dir)
2566 STUNPUTC(new); 2755 STUNPUTC(new);
2567 *new = 0; 2756 *new = 0;
2568 return stackblock(); 2757 return stackblock();
2758#endif
2569} 2759}
2570 2760
2571/* 2761/*
@@ -2660,7 +2850,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2660 } 2850 }
2661 if (!dest) 2851 if (!dest)
2662 dest = nullstr; 2852 dest = nullstr;
2663 if (*dest == '/') 2853 if (is_absolute_path(dest))
2664 goto step7; 2854 goto step7;
2665 if (*dest == '.') { 2855 if (*dest == '.') {
2666 c = dest[1]; 2856 c = dest[1];
@@ -3377,7 +3567,9 @@ struct job {
3377}; 3567};
3378 3568
3379static struct job *makejob(/*union node *,*/ int); 3569static struct job *makejob(/*union node *,*/ int);
3570#if !ENABLE_PLATFORM_MINGW32
3380static int forkshell(struct job *, union node *, int); 3571static int forkshell(struct job *, union node *, int);
3572#endif
3381static int waitforjob(struct job *); 3573static int waitforjob(struct job *);
3382 3574
3383#if !JOBS 3575#if !JOBS
@@ -3432,6 +3624,8 @@ setsignal(int signo)
3432 char cur_act, new_act; 3624 char cur_act, new_act;
3433 struct sigaction act; 3625 struct sigaction act;
3434 3626
3627 if (ENABLE_PLATFORM_MINGW32)
3628 return;
3435 t = trap[signo]; 3629 t = trap[signo];
3436 new_act = S_DFL; 3630 new_act = S_DFL;
3437 if (t != NULL) { /* trap for this sig is set */ 3631 if (t != NULL) { /* trap for this sig is set */
@@ -3953,6 +4147,79 @@ sprint_status(char *s, int status, int sigonly)
3953 return col; 4147 return col;
3954} 4148}
3955 4149
4150#if ENABLE_PLATFORM_MINGW32
4151
4152HANDLE hSIGINT; /* Ctrl-C is pressed */
4153
4154static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4155{
4156 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4157 SetEvent(hSIGINT);
4158 return TRUE;
4159 }
4160 return FALSE;
4161}
4162
4163/*
4164 * Windows does not know about parent-child relationship
4165 * They don't support waitpid(-1)
4166 */
4167static pid_t
4168waitpid_child(int *status, int wait_flags)
4169{
4170 HANDLE *pidlist, *pidp;
4171 int pid_nr = 0;
4172 pid_t pid;
4173 DWORD win_status, idx;
4174 struct job *jb;
4175
4176 #define LOOP(stmt) \
4177 for (jb = curjob; jb; jb = jb->prev_job) { \
4178 struct procstat *ps, *psend; \
4179 if (jb->state == JOBDONE) \
4180 continue; \
4181 ps = jb->ps; \
4182 psend = ps + jb->nprocs; \
4183 while (ps < psend) { \
4184 if (ps->ps_pid != -1) { \
4185 stmt; \
4186 } \
4187 ps++; \
4188 } \
4189 }
4190
4191 LOOP(pid_nr++);
4192 if (!pid_nr)
4193 return -1;
4194 pid_nr++;
4195 pidp = pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4196 *pidp++ = hSIGINT;
4197 LOOP(*pidp++ = (HANDLE)ps->ps_pid);
4198 #undef LOOP
4199
4200 idx = WaitForMultipleObjects(pid_nr, pidlist, FALSE,
4201 wait_flags|WNOHANG ? 1 : INFINITE);
4202 if (idx >= pid_nr) {
4203 free(pidlist);
4204 return -1;
4205 }
4206 if (!idx) { /* hSIGINT */
4207 int i;
4208 ResetEvent(hSIGINT);
4209 for (i = 1; i < pid_nr; i++)
4210 TerminateProcess(pidlist[i], 1);
4211 free(pidlist);
4212 *status = 260; /* terminated by a signal */
4213 return pidlist[1];
4214 }
4215 GetExitCodeProcess(pidlist[idx], &win_status);
4216 pid = (int)pidlist[idx];
4217 free(pidlist);
4218 *status = (int)win_status;
4219 return pid;
4220}
4221#endif
4222
3956static int 4223static int
3957dowait(int wait_flags, struct job *job) 4224dowait(int wait_flags, struct job *job)
3958{ 4225{
@@ -3969,7 +4236,11 @@ dowait(int wait_flags, struct job *job)
3969 * NB: _not_ safe_waitpid, we need to detect EINTR */ 4236 * NB: _not_ safe_waitpid, we need to detect EINTR */
3970 if (doing_jobctl) 4237 if (doing_jobctl)
3971 wait_flags |= WUNTRACED; 4238 wait_flags |= WUNTRACED;
4239#if ENABLE_PLATFORM_MINGW32
4240 pid = waitpid_child(&status, wait_flags);
4241#else
3972 pid = waitpid(-1, &status, wait_flags); 4242 pid = waitpid(-1, &status, wait_flags);
4243#endif
3973 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", 4244 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3974 pid, status, errno, strerror(errno))); 4245 pid, status, errno, strerror(errno)));
3975 if (pid <= 0) 4246 if (pid <= 0)
@@ -3992,6 +4263,8 @@ dowait(int wait_flags, struct job *job)
3992 jobno(jp), pid, ps->ps_status, status)); 4263 jobno(jp), pid, ps->ps_status, status));
3993 ps->ps_status = status; 4264 ps->ps_status = status;
3994 thisjob = jp; 4265 thisjob = jp;
4266 if (ENABLE_PLATFORM_MINGW32)
4267 ps->ps_pid = -1;
3995 } 4268 }
3996 if (ps->ps_status == -1) 4269 if (ps->ps_status == -1)
3997 state = JOBRUNNING; 4270 state = JOBRUNNING;
@@ -4223,6 +4496,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4223 int retval; 4496 int retval;
4224 struct job *jp; 4497 struct job *jp;
4225 4498
4499 if (ENABLE_PLATFORM_MINGW32)
4500 return 0;
4501
4226 if (pending_sig) 4502 if (pending_sig)
4227 raise_exception(EXSIG); 4503 raise_exception(EXSIG);
4228 4504
@@ -4678,6 +4954,7 @@ commandtext(union node *n)
4678 * 4954 *
4679 * Called with interrupts off. 4955 * Called with interrupts off.
4680 */ 4956 */
4957#if !ENABLE_PLATFORM_MINGW32
4681/* 4958/*
4682 * Clear traps on a fork. 4959 * Clear traps on a fork.
4683 */ 4960 */
@@ -4826,6 +5103,7 @@ forkchild(struct job *jp, union node *n, int mode)
4826 freejob(jp); 5103 freejob(jp);
4827 jobless = 0; 5104 jobless = 0;
4828} 5105}
5106#endif
4829 5107
4830/* Called after fork(), in parent */ 5108/* Called after fork(), in parent */
4831#if !JOBS 5109#if !JOBS
@@ -4835,7 +5113,7 @@ static void
4835forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5113forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4836{ 5114{
4837 TRACE(("In parent shell: child = %d\n", pid)); 5115 TRACE(("In parent shell: child = %d\n", pid));
4838 if (!jp) { 5116 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
4839 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5117 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4840 continue; 5118 continue;
4841 jobless++; 5119 jobless++;
@@ -4869,12 +5147,14 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4869 } 5147 }
4870} 5148}
4871 5149
5150#if !ENABLE_PLATFORM_MINGW32
4872static int 5151static int
4873forkshell(struct job *jp, union node *n, int mode) 5152forkshell(struct job *jp, union node *n, int mode)
4874{ 5153{
4875 int pid; 5154 int pid;
4876 5155
4877 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); 5156 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
5157
4878 pid = fork(); 5158 pid = fork();
4879 if (pid < 0) { 5159 if (pid < 0) {
4880 TRACE(("Fork failed, errno=%d", errno)); 5160 TRACE(("Fork failed, errno=%d", errno));
@@ -4890,6 +5170,7 @@ forkshell(struct job *jp, union node *n, int mode)
4890 } 5170 }
4891 return pid; 5171 return pid;
4892} 5172}
5173#endif
4893 5174
4894/* 5175/*
4895 * Wait for job to finish. 5176 * Wait for job to finish.
@@ -5082,6 +5363,7 @@ openhere(union node *redir)
5082{ 5363{
5083 int pip[2]; 5364 int pip[2];
5084 size_t len = 0; 5365 size_t len = 0;
5366 IF_PLATFORM_MINGW32(struct forkshell fs);
5085 5367
5086 if (pipe(pip) < 0) 5368 if (pipe(pip) < 0)
5087 ash_msg_and_raise_error("pipe call failed"); 5369 ash_msg_and_raise_error("pipe call failed");
@@ -5092,6 +5374,15 @@ openhere(union node *redir)
5092 goto out; 5374 goto out;
5093 } 5375 }
5094 } 5376 }
5377#if ENABLE_PLATFORM_MINGW32
5378 memset(&fs, 0, sizeof(fs));
5379 fs.fpid = FS_OPENHERE;
5380 fs.n = redir;
5381 fs.fd[0] = pip[0];
5382 fs.fd[1] = pip[1];
5383 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5384 ash_msg_and_raise_error("unable to spawn shell");
5385#else
5095 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5386 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5096 /* child */ 5387 /* child */
5097 close(pip[0]); 5388 close(pip[0]);
@@ -5106,6 +5397,7 @@ openhere(union node *redir)
5106 expandhere(redir->nhere.doc, pip[1]); 5397 expandhere(redir->nhere.doc, pip[1]);
5107 _exit(EXIT_SUCCESS); 5398 _exit(EXIT_SUCCESS);
5108 } 5399 }
5400#endif
5109 out: 5401 out:
5110 close(pip[1]); 5402 close(pip[1]);
5111 return pip[0]; 5403 return pip[0];
@@ -5118,6 +5410,31 @@ openredirect(union node *redir)
5118 int f; 5410 int f;
5119 5411
5120 fname = redir->nfile.expfname; 5412 fname = redir->nfile.expfname;
5413#if ENABLE_PLATFORM_MINGW32
5414 /* Support for /dev/null */
5415 switch (redir->nfile.type) {
5416 case NFROM:
5417 if (!strcmp(fname, "/dev/null"))
5418 return open("nul",O_RDWR);
5419 if (!strncmp(fname, "/dev/", 5)) {
5420 ash_msg("Unhandled device %s\n", fname);
5421 return -1;
5422 }
5423 break;
5424
5425 case NFROMTO:
5426 case NTO:
5427 case NCLOBBER:
5428 case NAPPEND:
5429 if (!strcmp(fname, "/dev/null"))
5430 return open("nul",O_RDWR);
5431 if (!strncmp(fname, "/dev/", 5)) {
5432 ash_msg("Unhandled device %s\n", fname);
5433 return -1;
5434 }
5435 break;
5436 }
5437#endif
5121 switch (redir->nfile.type) { 5438 switch (redir->nfile.type) {
5122 case NFROM: 5439 case NFROM:
5123 f = open(fname, O_RDONLY); 5440 f = open(fname, O_RDONLY);
@@ -5842,6 +6159,7 @@ struct backcmd { /* result of evalbackcmd */
5842 int fd; /* file descriptor to read from */ 6159 int fd; /* file descriptor to read from */
5843 int nleft; /* number of chars in buffer */ 6160 int nleft; /* number of chars in buffer */
5844 char *buf; /* buffer */ 6161 char *buf; /* buffer */
6162 IF_PLATFORM_MINGW32(struct forkshell fs);
5845 struct job *jp; /* job structure for command */ 6163 struct job *jp; /* job structure for command */
5846}; 6164};
5847 6165
@@ -5858,6 +6176,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5858 result->fd = -1; 6176 result->fd = -1;
5859 result->buf = NULL; 6177 result->buf = NULL;
5860 result->nleft = 0; 6178 result->nleft = 0;
6179 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
5861 result->jp = NULL; 6180 result->jp = NULL;
5862 if (n == NULL) 6181 if (n == NULL)
5863 goto out; 6182 goto out;
@@ -5872,6 +6191,14 @@ evalbackcmd(union node *n, struct backcmd *result)
5872 if (pipe(pip) < 0) 6191 if (pipe(pip) < 0)
5873 ash_msg_and_raise_error("pipe call failed"); 6192 ash_msg_and_raise_error("pipe call failed");
5874 jp = makejob(/*n,*/ 1); 6193 jp = makejob(/*n,*/ 1);
6194#if ENABLE_PLATFORM_MINGW32
6195 result->fs.fpid = FS_EVALBACKCMD;
6196 result->fs.n = n;
6197 result->fs.fd[0] = pip[0];
6198 result->fs.fd[1] = pip[1];
6199 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6200 ash_msg_and_raise_error("unable to spawn shell");
6201#else
5875 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6202 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5876 FORCE_INT_ON; 6203 FORCE_INT_ON;
5877 close(pip[0]); 6204 close(pip[0]);
@@ -5884,6 +6211,7 @@ evalbackcmd(union node *n, struct backcmd *result)
5884 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 6211 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5885 /* NOTREACHED */ 6212 /* NOTREACHED */
5886 } 6213 }
6214#endif
5887 close(pip[1]); 6215 close(pip[1]);
5888 result->fd = pip[0]; 6216 result->fd = pip[0];
5889 result->jp = jp; 6217 result->jp = jp;
@@ -5942,7 +6270,8 @@ expbackq(union node *cmd, int quoted, int quotes)
5942 6270
5943 /* Eat all trailing newlines */ 6271 /* Eat all trailing newlines */
5944 dest = expdest; 6272 dest = expdest;
5945 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6273 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6274 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
5946 STUNPUTC(dest); 6275 STUNPUTC(dest);
5947 expdest = dest; 6276 expdest = dest;
5948 6277
@@ -7505,7 +7834,7 @@ shellexec(char **argv, const char *path, int idx)
7505 7834
7506 clearredir(/*drop:*/ 1); 7835 clearredir(/*drop:*/ 1);
7507 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7836 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7508 if (strchr(argv[0], '/') != NULL 7837 if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\')))
7509#if ENABLE_FEATURE_SH_STANDALONE 7838#if ENABLE_FEATURE_SH_STANDALONE
7510 || (applet_no = find_applet_by_name(argv[0])) >= 0 7839 || (applet_no = find_applet_by_name(argv[0])) >= 0
7511#endif 7840#endif
@@ -8016,6 +8345,10 @@ static int funcblocksize; /* size of structures in function */
8016static int funcstringsize; /* size of strings in node */ 8345static int funcstringsize; /* size of strings in node */
8017static void *funcblock; /* block to allocate function from */ 8346static void *funcblock; /* block to allocate function from */
8018static char *funcstring; /* block to allocate strings from */ 8347static char *funcstring; /* block to allocate strings from */
8348#if ENABLE_PLATFORM_MINGW32
8349static int nodeptrsize;
8350static int *nodeptr;
8351#endif
8019 8352
8020/* flags in argument to evaltree */ 8353/* flags in argument to evaltree */
8021#define EV_EXIT 01 /* exit after evaluating tree */ 8354#define EV_EXIT 01 /* exit after evaluating tree */
@@ -8061,6 +8394,7 @@ sizenodelist(struct nodelist *lp)
8061{ 8394{
8062 while (lp) { 8395 while (lp) {
8063 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8396 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8397 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8064 calcsize(lp->n); 8398 calcsize(lp->n);
8065 lp = lp->next; 8399 lp = lp->next;
8066 } 8400 }
@@ -8077,15 +8411,18 @@ calcsize(union node *n)
8077 calcsize(n->ncmd.redirect); 8411 calcsize(n->ncmd.redirect);
8078 calcsize(n->ncmd.args); 8412 calcsize(n->ncmd.args);
8079 calcsize(n->ncmd.assign); 8413 calcsize(n->ncmd.assign);
8414 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8080 break; 8415 break;
8081 case NPIPE: 8416 case NPIPE:
8082 sizenodelist(n->npipe.cmdlist); 8417 sizenodelist(n->npipe.cmdlist);
8418 IF_PLATFORM_MINGW32(nodeptrsize++);
8083 break; 8419 break;
8084 case NREDIR: 8420 case NREDIR:
8085 case NBACKGND: 8421 case NBACKGND:
8086 case NSUBSHELL: 8422 case NSUBSHELL:
8087 calcsize(n->nredir.redirect); 8423 calcsize(n->nredir.redirect);
8088 calcsize(n->nredir.n); 8424 calcsize(n->nredir.n);
8425 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8089 break; 8426 break;
8090 case NAND: 8427 case NAND:
8091 case NOR: 8428 case NOR:
@@ -8094,31 +8431,37 @@ calcsize(union node *n)
8094 case NUNTIL: 8431 case NUNTIL:
8095 calcsize(n->nbinary.ch2); 8432 calcsize(n->nbinary.ch2);
8096 calcsize(n->nbinary.ch1); 8433 calcsize(n->nbinary.ch1);
8434 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8097 break; 8435 break;
8098 case NIF: 8436 case NIF:
8099 calcsize(n->nif.elsepart); 8437 calcsize(n->nif.elsepart);
8100 calcsize(n->nif.ifpart); 8438 calcsize(n->nif.ifpart);
8101 calcsize(n->nif.test); 8439 calcsize(n->nif.test);
8440 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8102 break; 8441 break;
8103 case NFOR: 8442 case NFOR:
8104 funcstringsize += strlen(n->nfor.var) + 1; 8443 funcstringsize += strlen(n->nfor.var) + 1;
8105 calcsize(n->nfor.body); 8444 calcsize(n->nfor.body);
8106 calcsize(n->nfor.args); 8445 calcsize(n->nfor.args);
8446 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8107 break; 8447 break;
8108 case NCASE: 8448 case NCASE:
8109 calcsize(n->ncase.cases); 8449 calcsize(n->ncase.cases);
8110 calcsize(n->ncase.expr); 8450 calcsize(n->ncase.expr);
8451 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8111 break; 8452 break;
8112 case NCLIST: 8453 case NCLIST:
8113 calcsize(n->nclist.body); 8454 calcsize(n->nclist.body);
8114 calcsize(n->nclist.pattern); 8455 calcsize(n->nclist.pattern);
8115 calcsize(n->nclist.next); 8456 calcsize(n->nclist.next);
8457 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8116 break; 8458 break;
8117 case NDEFUN: 8459 case NDEFUN:
8118 case NARG: 8460 case NARG:
8119 sizenodelist(n->narg.backquote); 8461 sizenodelist(n->narg.backquote);
8120 funcstringsize += strlen(n->narg.text) + 1; 8462 funcstringsize += strlen(n->narg.text) + 1;
8121 calcsize(n->narg.next); 8463 calcsize(n->narg.next);
8464 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8122 break; 8465 break;
8123 case NTO: 8466 case NTO:
8124#if ENABLE_ASH_BASH_COMPAT 8467#if ENABLE_ASH_BASH_COMPAT
@@ -8130,28 +8473,34 @@ calcsize(union node *n)
8130 case NAPPEND: 8473 case NAPPEND:
8131 calcsize(n->nfile.fname); 8474 calcsize(n->nfile.fname);
8132 calcsize(n->nfile.next); 8475 calcsize(n->nfile.next);
8476 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8133 break; 8477 break;
8134 case NTOFD: 8478 case NTOFD:
8135 case NFROMFD: 8479 case NFROMFD:
8136 calcsize(n->ndup.vname); 8480 calcsize(n->ndup.vname);
8137 calcsize(n->ndup.next); 8481 calcsize(n->ndup.next);
8482 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8138 break; 8483 break;
8139 case NHERE: 8484 case NHERE:
8140 case NXHERE: 8485 case NXHERE:
8141 calcsize(n->nhere.doc); 8486 calcsize(n->nhere.doc);
8142 calcsize(n->nhere.next); 8487 calcsize(n->nhere.next);
8488 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8143 break; 8489 break;
8144 case NNOT: 8490 case NNOT:
8145 calcsize(n->nnot.com); 8491 calcsize(n->nnot.com);
8492 IF_PLATFORM_MINGW32(nodeptrsize++);
8146 break; 8493 break;
8147 }; 8494 };
8148} 8495}
8149 8496
8150static char * 8497static char *
8151nodeckstrdup(char *s) 8498nodeckstrdup(const char *s)
8152{ 8499{
8153 char *rtn = funcstring; 8500 char *rtn = funcstring;
8154 8501
8502 if (!s)
8503 return NULL;
8155 strcpy(funcstring, s); 8504 strcpy(funcstring, s);
8156 funcstring += strlen(s) + 1; 8505 funcstring += strlen(s) + 1;
8157 return rtn; 8506 return rtn;
@@ -8159,6 +8508,18 @@ nodeckstrdup(char *s)
8159 8508
8160static union node *copynode(union node *); 8509static union node *copynode(union node *);
8161 8510
8511#if ENABLE_PLATFORM_MINGW32
8512# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (int)&(dst);}
8513# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);}}
8514# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);}}
8515# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (int)&(dst1);*nodeptr++ = (int)&(dst2);*nodeptr++ = (int)&(dst3);*nodeptr++ = (int)&(dst4);}}
8516#else
8517# define SAVE_PTR(dst)
8518# define SAVE_PTR2(dst,dst2)
8519# define SAVE_PTR3(dst,dst2,dst3)
8520# define SAVE_PTR4(dst,dst2,dst3,dst4)
8521#endif
8522
8162static struct nodelist * 8523static struct nodelist *
8163copynodelist(struct nodelist *lp) 8524copynodelist(struct nodelist *lp)
8164{ 8525{
@@ -8170,6 +8531,7 @@ copynodelist(struct nodelist *lp)
8170 *lpp = funcblock; 8531 *lpp = funcblock;
8171 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 8532 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8172 (*lpp)->n = copynode(lp->n); 8533 (*lpp)->n = copynode(lp->n);
8534 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8173 lp = lp->next; 8535 lp = lp->next;
8174 lpp = &(*lpp)->next; 8536 lpp = &(*lpp)->next;
8175 } 8537 }
@@ -8192,16 +8554,19 @@ copynode(union node *n)
8192 new->ncmd.redirect = copynode(n->ncmd.redirect); 8554 new->ncmd.redirect = copynode(n->ncmd.redirect);
8193 new->ncmd.args = copynode(n->ncmd.args); 8555 new->ncmd.args = copynode(n->ncmd.args);
8194 new->ncmd.assign = copynode(n->ncmd.assign); 8556 new->ncmd.assign = copynode(n->ncmd.assign);
8557 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8195 break; 8558 break;
8196 case NPIPE: 8559 case NPIPE:
8197 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8560 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8198 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 8561 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8562 SAVE_PTR(new->npipe.cmdlist);
8199 break; 8563 break;
8200 case NREDIR: 8564 case NREDIR:
8201 case NBACKGND: 8565 case NBACKGND:
8202 case NSUBSHELL: 8566 case NSUBSHELL:
8203 new->nredir.redirect = copynode(n->nredir.redirect); 8567 new->nredir.redirect = copynode(n->nredir.redirect);
8204 new->nredir.n = copynode(n->nredir.n); 8568 new->nredir.n = copynode(n->nredir.n);
8569 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8205 break; 8570 break;
8206 case NAND: 8571 case NAND:
8207 case NOR: 8572 case NOR:
@@ -8210,31 +8575,37 @@ copynode(union node *n)
8210 case NUNTIL: 8575 case NUNTIL:
8211 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8576 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8212 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8577 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8578 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8213 break; 8579 break;
8214 case NIF: 8580 case NIF:
8215 new->nif.elsepart = copynode(n->nif.elsepart); 8581 new->nif.elsepart = copynode(n->nif.elsepart);
8216 new->nif.ifpart = copynode(n->nif.ifpart); 8582 new->nif.ifpart = copynode(n->nif.ifpart);
8217 new->nif.test = copynode(n->nif.test); 8583 new->nif.test = copynode(n->nif.test);
8584 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8218 break; 8585 break;
8219 case NFOR: 8586 case NFOR:
8220 new->nfor.var = nodeckstrdup(n->nfor.var); 8587 new->nfor.var = nodeckstrdup(n->nfor.var);
8221 new->nfor.body = copynode(n->nfor.body); 8588 new->nfor.body = copynode(n->nfor.body);
8222 new->nfor.args = copynode(n->nfor.args); 8589 new->nfor.args = copynode(n->nfor.args);
8590 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8223 break; 8591 break;
8224 case NCASE: 8592 case NCASE:
8225 new->ncase.cases = copynode(n->ncase.cases); 8593 new->ncase.cases = copynode(n->ncase.cases);
8226 new->ncase.expr = copynode(n->ncase.expr); 8594 new->ncase.expr = copynode(n->ncase.expr);
8595 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8227 break; 8596 break;
8228 case NCLIST: 8597 case NCLIST:
8229 new->nclist.body = copynode(n->nclist.body); 8598 new->nclist.body = copynode(n->nclist.body);
8230 new->nclist.pattern = copynode(n->nclist.pattern); 8599 new->nclist.pattern = copynode(n->nclist.pattern);
8231 new->nclist.next = copynode(n->nclist.next); 8600 new->nclist.next = copynode(n->nclist.next);
8601 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8232 break; 8602 break;
8233 case NDEFUN: 8603 case NDEFUN:
8234 case NARG: 8604 case NARG:
8235 new->narg.backquote = copynodelist(n->narg.backquote); 8605 new->narg.backquote = copynodelist(n->narg.backquote);
8236 new->narg.text = nodeckstrdup(n->narg.text); 8606 new->narg.text = nodeckstrdup(n->narg.text);
8237 new->narg.next = copynode(n->narg.next); 8607 new->narg.next = copynode(n->narg.next);
8608 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8238 break; 8609 break;
8239 case NTO: 8610 case NTO:
8240#if ENABLE_ASH_BASH_COMPAT 8611#if ENABLE_ASH_BASH_COMPAT
@@ -8247,6 +8618,7 @@ copynode(union node *n)
8247 new->nfile.fname = copynode(n->nfile.fname); 8618 new->nfile.fname = copynode(n->nfile.fname);
8248 new->nfile.fd = n->nfile.fd; 8619 new->nfile.fd = n->nfile.fd;
8249 new->nfile.next = copynode(n->nfile.next); 8620 new->nfile.next = copynode(n->nfile.next);
8621 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8250 break; 8622 break;
8251 case NTOFD: 8623 case NTOFD:
8252 case NFROMFD: 8624 case NFROMFD:
@@ -8254,15 +8626,18 @@ copynode(union node *n)
8254 new->ndup.dupfd = n->ndup.dupfd; 8626 new->ndup.dupfd = n->ndup.dupfd;
8255 new->ndup.fd = n->ndup.fd; 8627 new->ndup.fd = n->ndup.fd;
8256 new->ndup.next = copynode(n->ndup.next); 8628 new->ndup.next = copynode(n->ndup.next);
8629 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8257 break; 8630 break;
8258 case NHERE: 8631 case NHERE:
8259 case NXHERE: 8632 case NXHERE:
8260 new->nhere.doc = copynode(n->nhere.doc); 8633 new->nhere.doc = copynode(n->nhere.doc);
8261 new->nhere.fd = n->nhere.fd; 8634 new->nhere.fd = n->nhere.fd;
8262 new->nhere.next = copynode(n->nhere.next); 8635 new->nhere.next = copynode(n->nhere.next);
8636 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8263 break; 8637 break;
8264 case NNOT: 8638 case NNOT:
8265 new->nnot.com = copynode(n->nnot.com); 8639 new->nnot.com = copynode(n->nnot.com);
8640 SAVE_PTR(new->nnot.com);
8266 break; 8641 break;
8267 }; 8642 };
8268 new->type = n->type; 8643 new->type = n->type;
@@ -8285,6 +8660,7 @@ copyfunc(union node *n)
8285 f = ckmalloc(blocksize + funcstringsize); 8660 f = ckmalloc(blocksize + funcstringsize);
8286 funcblock = (char *) f + offsetof(struct funcnode, n); 8661 funcblock = (char *) f + offsetof(struct funcnode, n);
8287 funcstring = (char *) f + blocksize; 8662 funcstring = (char *) f + blocksize;
8663 IF_PLATFORM_MINGW32(nodeptr = NULL);
8288 copynode(n); 8664 copynode(n);
8289 f->count = 0; 8665 f->count = 0;
8290 return f; 8666 return f;
@@ -8644,6 +9020,7 @@ evalcase(union node *n, int flags)
8644static void 9020static void
8645evalsubshell(union node *n, int flags) 9021evalsubshell(union node *n, int flags)
8646{ 9022{
9023 IF_PLATFORM_MINGW32(struct forkshell fs;)
8647 struct job *jp; 9024 struct job *jp;
8648 int backgnd = (n->type == NBACKGND); 9025 int backgnd = (n->type == NBACKGND);
8649 int status; 9026 int status;
@@ -8653,12 +9030,22 @@ evalsubshell(union node *n, int flags)
8653 goto nofork; 9030 goto nofork;
8654 INT_OFF; 9031 INT_OFF;
8655 jp = makejob(/*n,*/ 1); 9032 jp = makejob(/*n,*/ 1);
9033#if ENABLE_PLATFORM_MINGW32
9034 memset(&fs, 0, sizeof(fs));
9035 fs.fpid = FS_EVALSUBSHELL;
9036 fs.n = n;
9037 fs.flags = flags;
9038 if (spawn_forkshell(jp, &fs, backgnd) < 0)
9039 ash_msg_and_raise_error("unable to spawn shell");
9040 if ( 0 ) {
9041#else
8656 if (forkshell(jp, n, backgnd) == 0) { 9042 if (forkshell(jp, n, backgnd) == 0) {
8657 /* child */ 9043 /* child */
8658 INT_ON; 9044 INT_ON;
8659 flags |= EV_EXIT; 9045 flags |= EV_EXIT;
8660 if (backgnd) 9046 if (backgnd)
8661 flags &= ~EV_TESTED; 9047 flags &= ~EV_TESTED;
9048#endif
8662 nofork: 9049 nofork:
8663 redirect(n->nredir.redirect, 0); 9050 redirect(n->nredir.redirect, 0);
8664 evaltreenr(n->nredir.n, flags); 9051 evaltreenr(n->nredir.n, flags);
@@ -8744,6 +9131,7 @@ expredir(union node *n)
8744static void 9131static void
8745evalpipe(union node *n, int flags) 9132evalpipe(union node *n, int flags)
8746{ 9133{
9134 IF_PLATFORM_MINGW32(struct forkshell fs;)
8747 struct job *jp; 9135 struct job *jp;
8748 struct nodelist *lp; 9136 struct nodelist *lp;
8749 int pipelen; 9137 int pipelen;
@@ -8767,6 +9155,17 @@ evalpipe(union node *n, int flags)
8767 ash_msg_and_raise_error("pipe call failed"); 9155 ash_msg_and_raise_error("pipe call failed");
8768 } 9156 }
8769 } 9157 }
9158#if ENABLE_PLATFORM_MINGW32
9159 memset(&fs, 0, sizeof(fs));
9160 fs.fpid = FS_EVALPIPE;
9161 fs.flags = flags;
9162 fs.n = lp->n;
9163 fs.fd[0] = pip[0];
9164 fs.fd[1] = pip[1];
9165 fs.fd[2] = prevfd;
9166 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9167 ash_msg_and_raise_error("unable to spawn shell");
9168#else
8770 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9169 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8771 INT_ON; 9170 INT_ON;
8772 if (pip[1] >= 0) { 9171 if (pip[1] >= 0) {
@@ -8783,6 +9182,7 @@ evalpipe(union node *n, int flags)
8783 evaltreenr(lp->n, flags); 9182 evaltreenr(lp->n, flags);
8784 /* never returns */ 9183 /* never returns */
8785 } 9184 }
9185#endif
8786 if (prevfd >= 0) 9186 if (prevfd >= 0)
8787 close(prevfd); 9187 close(prevfd);
8788 prevfd = pip[0]; 9188 prevfd = pip[0];
@@ -9244,6 +9644,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9244 * as POSIX mandates */ 9644 * as POSIX mandates */
9245 return back_exitstatus; 9645 return back_exitstatus;
9246} 9646}
9647
9247static void 9648static void
9248evalcommand(union node *cmd, int flags) 9649evalcommand(union node *cmd, int flags)
9249{ 9650{
@@ -9421,6 +9822,27 @@ evalcommand(union node *cmd, int flags)
9421 * in a script or a subshell does not need forking, 9822 * in a script or a subshell does not need forking,
9422 * we can just exec it. 9823 * we can just exec it.
9423 */ 9824 */
9825#if ENABLE_PLATFORM_MINGW32
9826 if (!(flags & EV_EXIT) || trap[0]) {
9827 /* No, forking off a child is necessary */
9828 struct forkshell fs;
9829
9830 memset(&fs, 0, sizeof(fs));
9831 fs.fpid = FS_SHELLEXEC;
9832 fs.argv = argv;
9833 fs.string = (char*)path;
9834 fs.fd[0] = cmdentry.u.index;
9835 fs.strlist = varlist.list;
9836 jp = makejob(/*cmd,*/ 1);
9837 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
9838 ash_msg_and_raise_error("unable to spawn shell");
9839 exitstatus = waitforjob(jp);
9840 INT_ON;
9841 TRACE(("forked child exited with %d\n", exitstatus));
9842 break;
9843 }
9844 /* goes through to shellexec() */
9845#else
9424 if (!(flags & EV_EXIT) || may_have_traps) { 9846 if (!(flags & EV_EXIT) || may_have_traps) {
9425 /* No, forking off a child is necessary */ 9847 /* No, forking off a child is necessary */
9426 INT_OFF; 9848 INT_OFF;
@@ -9436,6 +9858,7 @@ evalcommand(union node *cmd, int flags)
9436 FORCE_INT_ON; 9858 FORCE_INT_ON;
9437 /* fall through to exec'ing external program */ 9859 /* fall through to exec'ing external program */
9438 } 9860 }
9861#endif
9439 listsetvar(varlist.list, VEXPORT|VSTACK); 9862 listsetvar(varlist.list, VEXPORT|VSTACK);
9440 shellexec(argv, path, cmdentry.u.index); 9863 shellexec(argv, path, cmdentry.u.index);
9441 /* NOTREACHED */ 9864 /* NOTREACHED */
@@ -9824,7 +10247,7 @@ preadbuffer(void)
9824 more--; 10247 more--;
9825 10248
9826 c = *q; 10249 c = *q;
9827 if (c == '\0') { 10250 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
9828 memmove(q, q + 1, more); 10251 memmove(q, q + 1, more);
9829 } else { 10252 } else {
9830 q++; 10253 q++;
@@ -9980,6 +10403,7 @@ popallfiles(void)
9980 popfile(); 10403 popfile();
9981} 10404}
9982 10405
10406#if !ENABLE_PLATFORM_MINGW32
9983/* 10407/*
9984 * Close the file(s) that the shell is reading commands from. Called 10408 * Close the file(s) that the shell is reading commands from. Called
9985 * after a fork is done. 10409 * after a fork is done.
@@ -9993,6 +10417,7 @@ closescript(void)
9993 g_parsefile->pf_fd = 0; 10417 g_parsefile->pf_fd = 0;
9994 } 10418 }
9995} 10419}
10420#endif
9996 10421
9997/* 10422/*
9998 * Like setinputfile, but takes an open file descriptor. Call this with 10423 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -12256,7 +12681,7 @@ find_dot_file(char *name)
12256 struct stat statb; 12681 struct stat statb;
12257 12682
12258 /* don't try this for absolute or relative paths */ 12683 /* don't try this for absolute or relative paths */
12259 if (strchr(name, '/')) 12684 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12260 return name; 12685 return name;
12261 12686
12262 /* IIRC standards do not say whether . is to be searched. 12687 /* IIRC standards do not say whether . is to be searched.
@@ -12371,10 +12796,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12371 struct stat statb; 12796 struct stat statb;
12372 int e; 12797 int e;
12373 int updatetbl; 12798 int updatetbl;
12799 IF_PLATFORM_MINGW32(int len;)
12374 struct builtincmd *bcmd; 12800 struct builtincmd *bcmd;
12375 12801
12376 /* If name contains a slash, don't use PATH or hash table */ 12802 /* If name contains a slash, don't use PATH or hash table */
12377 if (strchr(name, '/') != NULL) { 12803 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12378 entry->u.index = -1; 12804 entry->u.index = -1;
12379 if (act & DO_ABS) { 12805 if (act & DO_ABS) {
12380 while (stat(name, &statb) < 0) { 12806 while (stat(name, &statb) < 0) {
@@ -12481,12 +12907,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12481 } 12907 }
12482 } 12908 }
12483 /* if rehash, don't redo absolute path names */ 12909 /* if rehash, don't redo absolute path names */
12484 if (fullname[0] == '/' && idx <= prev) { 12910 if (is_absolute_path(fullname) && idx <= prev) {
12485 if (idx < prev) 12911 if (idx < prev)
12486 continue; 12912 continue;
12487 TRACE(("searchexec \"%s\": no change\n", name)); 12913 TRACE(("searchexec \"%s\": no change\n", name));
12488 goto success; 12914 goto success;
12489 } 12915 }
12916#if ENABLE_PLATFORM_MINGW32
12917 len = strlen(fullname);
12918 if (len > 4 &&
12919 (!strcasecmp(fullname+len-4, ".exe") ||
12920 !strcasecmp(fullname+len-4, ".com"))) {
12921 if (stat(fullname, &statb) < 0) {
12922 if (errno != ENOENT && errno != ENOTDIR)
12923 e = errno;
12924 goto loop;
12925 }
12926 }
12927 else {
12928 /* path_advance() has reserved space for .exe */
12929 memcpy(fullname+len, ".exe", 5);
12930 if (stat(fullname, &statb) < 0) {
12931 if (errno != ENOENT && errno != ENOTDIR)
12932 e = errno;
12933 memcpy(fullname+len, ".com", 5);
12934 if (stat(fullname, &statb) < 0) {
12935 if (errno != ENOENT && errno != ENOTDIR)
12936 e = errno;
12937 fullname[len] = '\0';
12938 if (stat(fullname, &statb) < 0) {
12939 if (errno != ENOENT && errno != ENOTDIR)
12940 e = errno;
12941 goto loop;
12942 }
12943 if (!file_is_executable(fullname)) {
12944 e = ENOEXEC;
12945 goto loop;
12946 }
12947 }
12948 }
12949 fullname[len] = '\0';
12950 }
12951#else
12490 while (stat(fullname, &statb) < 0) { 12952 while (stat(fullname, &statb) < 0) {
12491#ifdef SYSV 12953#ifdef SYSV
12492 if (errno == EINTR) 12954 if (errno == EINTR)
@@ -12496,6 +12958,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12496 e = errno; 12958 e = errno;
12497 goto loop; 12959 goto loop;
12498 } 12960 }
12961#endif
12499 e = EACCES; /* if we fail, this will be the error */ 12962 e = EACCES; /* if we fail, this will be the error */
12500 if (!S_ISREG(statb.st_mode)) 12963 if (!S_ISREG(statb.st_mode))
12501 continue; 12964 continue;
@@ -13036,6 +13499,57 @@ init(void)
13036 struct stat st1, st2; 13499 struct stat st1, st2;
13037 13500
13038 initvar(); 13501 initvar();
13502
13503#if ENABLE_PLATFORM_MINGW32
13504 /*
13505 * case insensitive env names from Windows world
13506 *
13507 * Some standard env names such as PATH is named Path and so on
13508 * ash itself is case sensitive, so "Path" will confuse it, as
13509 * MSVC getenv() is case insensitive.
13510 *
13511 * We may end up having both Path and PATH. Then Path will be chosen
13512 * because it appears first.
13513 */
13514 for (envp = environ; envp && *envp; envp++) {
13515 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
13516 strncmp(*envp, "PATH=", 5) != 0) {
13517 break;
13518 }
13519 }
13520
13521 if (envp && *envp) {
13522 /*
13523 * If we get here it's because the environment contains a path
13524 * variable called something other than PATH. This suggests we
13525 * haven't been invoked from an earlier instance of BusyBox.
13526 */
13527 char *start, *end;
13528 struct passwd *pw;
13529
13530 for (envp = environ; envp && *envp; envp++) {
13531 end = strchr(*envp, '=');
13532 if (!end)
13533 continue;
13534
13535 /* make all variable names uppercase */
13536 for (start = *envp;start < end;start++)
13537 *start = toupper(*start);
13538
13539 /* convert backslashes to forward slashes */
13540 for ( ++end; *end; ++end ) {
13541 if ( *end == '\\' ) {
13542 *end = '/';
13543 }
13544 }
13545 }
13546
13547 /* some initialisation normally performed at login */
13548 pw = xgetpwuid(getuid());
13549 setup_environment(pw->pw_shell,
13550 SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw);
13551 }
13552#endif
13039 for (envp = environ; envp && *envp; envp++) { 13553 for (envp = environ; envp && *envp; envp++) {
13040 if (strchr(*envp, '=')) { 13554 if (strchr(*envp, '=')) {
13041 setvareq(*envp, VEXPORT|VTEXTFIXED); 13555 setvareq(*envp, VEXPORT|VTEXTFIXED);
@@ -13253,13 +13767,38 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13253 13767
13254 init(); 13768 init();
13255 setstackmark(&smark); 13769 setstackmark(&smark);
13770
13771#if ENABLE_PLATFORM_MINGW32
13772 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
13773 SetConsoleCtrlHandler(ctrl_handler, TRUE);
13774 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
13775 forkshell_init(argv[2]);
13776
13777 /* NOTREACHED */
13778 bb_error_msg_and_die("subshell ended unexpectedly");
13779 }
13780#endif
13256 procargs(argv); 13781 procargs(argv);
13782#if ENABLE_PLATFORM_MINGW32
13783 if ( noconsole ) {
13784 DWORD dummy;
13785
13786 if ( GetConsoleProcessList(&dummy, 1) == 1 ) {
13787 ShowWindow(GetConsoleWindow(), SW_HIDE);
13788 }
13789 }
13790#endif
13257 13791
13258 if (argv[0] && argv[0][0] == '-') 13792 if (argv[0] && argv[0][0] == '-')
13259 isloginsh = 1; 13793 isloginsh = 1;
13260 if (isloginsh) { 13794 if (isloginsh) {
13261 const char *hp; 13795 const char *hp;
13262 13796
13797#if ENABLE_PLATFORM_MINGW32
13798 chdir(xgetpwuid(getuid())->pw_dir);
13799 setpwd(NULL, 0);
13800#endif
13801
13263 state = 1; 13802 state = 1;
13264 read_profile("/etc/profile"); 13803 read_profile("/etc/profile");
13265 state1: 13804 state1:
@@ -13335,6 +13874,642 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13335 /* NOTREACHED */ 13874 /* NOTREACHED */
13336} 13875}
13337 13876
13877#if ENABLE_PLATFORM_MINGW32
13878static void
13879forkshell_openhere(struct forkshell *fs)
13880{
13881 union node *redir = fs->n;
13882 int pip[2];
13883
13884 pip[0] = fs->fd[0];
13885 pip[1] = fs->fd[1];
13886
13887 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
13888
13889 close(pip[0]);
13890 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
13891 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
13892 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
13893 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
13894 signal(SIGPIPE, SIG_DFL);
13895 if (redir->type == NHERE) {
13896 size_t len = strlen(redir->nhere.doc->narg.text);
13897 full_write(pip[1], redir->nhere.doc->narg.text, len);
13898 } else /* NXHERE */
13899 expandhere(redir->nhere.doc, pip[1]);
13900 _exit(EXIT_SUCCESS);
13901}
13902
13903static void
13904forkshell_evalbackcmd(struct forkshell *fs)
13905{
13906 union node *n = fs->n;
13907 int pip[2] = {fs->fd[0], fs->fd[1]};
13908
13909 FORCE_INT_ON;
13910 close(pip[0]);
13911 if (pip[1] != 1) {
13912 /*close(1);*/
13913 copyfd(pip[1], 1 | COPYFD_EXACT);
13914 close(pip[1]);
13915 }
13916 eflag = 0;
13917 evaltree(n, EV_EXIT); /* actually evaltreenr... */
13918 /* NOTREACHED */
13919}
13920
13921static void
13922forkshell_evalsubshell(struct forkshell *fs)
13923{
13924 union node *n = fs->n;
13925 int flags = fs->flags;
13926
13927 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
13928 INT_ON;
13929 flags |= EV_EXIT;
13930 expredir(n->nredir.redirect);
13931 redirect(n->nredir.redirect, 0);
13932 evaltreenr(n->nredir.n, flags);
13933 /* never returns */
13934}
13935
13936static void
13937forkshell_evalpipe(struct forkshell *fs)
13938{
13939 union node *n = fs->n;
13940 int flags = fs->flags;
13941 int prevfd = fs->fd[2];
13942 int pip[2] = {fs->fd[0], fs->fd[1]};
13943
13944 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
13945 INT_ON;
13946 if (pip[1] >= 0) {
13947 close(pip[0]);
13948 }
13949 if (prevfd > 0) {
13950 dup2(prevfd, 0);
13951 close(prevfd);
13952 }
13953 if (pip[1] > 1) {
13954 dup2(pip[1], 1);
13955 close(pip[1]);
13956 }
13957 evaltreenr(n, flags);
13958}
13959
13960static void
13961forkshell_shellexec(struct forkshell *fs)
13962{
13963 int idx = fs->fd[0];
13964 struct strlist *varlist = fs->strlist;
13965 char **argv = fs->argv;
13966 char *path = fs->string;
13967
13968 listsetvar(varlist, VEXPORT|VSTACK);
13969 shellexec(argv, path, idx);
13970}
13971
13972static void
13973forkshell_child(struct forkshell *fs)
13974{
13975 switch ( fs->fpid ) {
13976 case FS_OPENHERE:
13977 forkshell_openhere(fs);
13978 break;
13979 case FS_EVALBACKCMD:
13980 forkshell_evalbackcmd(fs);
13981 break;
13982 case FS_EVALSUBSHELL:
13983 forkshell_evalsubshell(fs);
13984 break;
13985 case FS_EVALPIPE:
13986 forkshell_evalpipe(fs);
13987 break;
13988 case FS_SHELLEXEC:
13989 forkshell_shellexec(fs);
13990 break;
13991 }
13992}
13993
13994/*
13995 * Reset the pointers to the builtin environment variables in the hash
13996 * table to point to varinit rather than the bogus copy created during
13997 * forkshell_prepare.
13998 */
13999static void
14000reinitvar(void)
14001{
14002 struct var *vp;
14003 struct var *end;
14004 struct var **vpp;
14005 struct var **old;
14006
14007 vp = varinit;
14008 end = vp + ARRAY_SIZE(varinit);
14009 do {
14010 vpp = hashvar(vp->var_text);
14011 if ( (old=findvar(vpp, vp->var_text)) != NULL ) {
14012 vp->next = (*old)->next;
14013 *old = vp;
14014 }
14015 } while (++vp < end);
14016}
14017
14018/* FIXME: should consider running forkparent() and forkchild() */
14019static int
14020spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
14021{
14022 struct forkshell *new;
14023 char buf[16];
14024 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
14025 pid_t pid;
14026
14027 new = forkshell_prepare(fs);
14028 sprintf(buf, "%x", (unsigned int)new->hMapFile);
14029 argv[2] = buf;
14030 pid = mingw_spawn_applet(P_NOWAIT, "sh", argv,
14031 (const char *const *)environ);
14032 CloseHandle(new->hMapFile);
14033 UnmapViewOfFile(new);
14034 if (pid == -1) {
14035 free(jp);
14036 return -1;
14037 }
14038 forkparent(jp, fs->node, mode, pid);
14039 return pid;
14040}
14041
14042/*
14043 * forkshell_prepare() and friends
14044 *
14045 * The sequence is as follows:
14046 * - funcblocksize, funcstringsize, nodeptrsize are initialized
14047 * - forkshell_size(fs) is called to calculate the exact memory needed
14048 * - a new struct is allocated
14049 * - funcblock, funcstring, nodeptr are initialized from the new block
14050 * - forkshell_copy(fs) is called to copy recursively everything over
14051 * it will record all pointers along the way, to nodeptr
14052 *
14053 * When this memory is mapped elsewhere, pointer fixup will be needed
14054 */
14055#define SLIST_SIZE_BEGIN(name,type) \
14056static void \
14057name(type *p) \
14058{ \
14059 while (p) { \
14060 funcblocksize += sizeof(type);
14061 /* do something here with p */
14062#define SLIST_SIZE_END() \
14063 nodeptrsize++; \
14064 p = p->next; \
14065 } \
14066}
14067
14068#define SLIST_COPY_BEGIN(name,type) \
14069static type * \
14070name(type *vp) \
14071{ \
14072 type *start; \
14073 type **vpp; \
14074 vpp = &start; \
14075 while (vp) { \
14076 *vpp = funcblock; \
14077 funcblock = (char *) funcblock + sizeof(type);
14078 /* do something here with vpp and vp */
14079#define SLIST_COPY_END() \
14080 SAVE_PTR((*vpp)->next); \
14081 vp = vp->next; \
14082 vpp = &(*vpp)->next; \
14083 } \
14084 *vpp = NULL; \
14085 return start; \
14086}
14087
14088/*
14089 * struct var
14090 */
14091SLIST_SIZE_BEGIN(var_size,struct var)
14092funcstringsize += strlen(p->var_text) + 1;
14093nodeptrsize++; /* p->text */
14094SLIST_SIZE_END()
14095
14096SLIST_COPY_BEGIN(var_copy,struct var)
14097(*vpp)->var_text = nodeckstrdup(vp->var_text);
14098(*vpp)->flags = vp->flags;
14099/*
14100 * The only place that can set struct var#func is varinit[],
14101 * which will be fixed by forkshell_init()
14102 */
14103(*vpp)->var_func = NULL;
14104SAVE_PTR((*vpp)->var_text);
14105SLIST_COPY_END()
14106
14107/*
14108 * struct strlist
14109 */
14110SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14111funcstringsize += strlen(p->text) + 1;
14112nodeptrsize++; /* p->text */
14113SLIST_SIZE_END()
14114
14115SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14116(*vpp)->text = nodeckstrdup(vp->text);
14117SAVE_PTR((*vpp)->text);
14118SLIST_COPY_END()
14119
14120/*
14121 * struct tblentry
14122 */
14123static void
14124tblentry_size(struct tblentry *tep)
14125{
14126 while (tep) {
14127 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14128 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14129 if (tep->cmdtype == CMDFUNCTION) {
14130 funcblocksize += offsetof(struct funcnode, n);
14131 calcsize(&tep->param.func->n);
14132 nodeptrsize++; /* tep->param.func */
14133 }
14134 nodeptrsize++; /* tep->next */
14135 tep = tep->next;
14136 }
14137}
14138
14139static struct tblentry *
14140tblentry_copy(struct tblentry *tep)
14141{
14142 struct tblentry *start;
14143 struct tblentry **newp;
14144 int size;
14145
14146 newp = &start;
14147 while (tep) {
14148 *newp = funcblock;
14149 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14150
14151 funcblock = (char *) funcblock + size;
14152 memcpy(*newp, tep, size);
14153 switch (tep->cmdtype) {
14154 case CMDBUILTIN:
14155 /* No pointer saving, this field must be fixed by forkshell_init() */
14156 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14157 break;
14158 case CMDFUNCTION:
14159 (*newp)->param.func = funcblock;
14160 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14161 copynode(&tep->param.func->n);
14162 SAVE_PTR((*newp)->param.func);
14163 break;
14164 default:
14165 break;
14166 }
14167 SAVE_PTR((*newp)->next);
14168 tep = tep->next;
14169 newp = &(*newp)->next;
14170 }
14171 *newp = NULL;
14172 return start;
14173}
14174
14175static void
14176cmdtable_size(struct tblentry **cmdtablep)
14177{
14178 int i;
14179 nodeptrsize += CMDTABLESIZE;
14180 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14181 for (i = 0; i < CMDTABLESIZE; i++)
14182 tblentry_size(cmdtablep[i]);
14183}
14184
14185static struct tblentry **
14186cmdtable_copy(struct tblentry **cmdtablep)
14187{
14188 struct tblentry **new = funcblock;
14189 int i;
14190
14191 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14192 for (i = 0; i < CMDTABLESIZE; i++) {
14193 new[i] = tblentry_copy(cmdtablep[i]);
14194 SAVE_PTR(new[i]);
14195 }
14196 return new;
14197}
14198
14199/*
14200 * char **
14201 */
14202static void
14203argv_size(char **p)
14204{
14205 while (p && *p) {
14206 funcblocksize += sizeof(char *);
14207 funcstringsize += strlen(*p)+1;
14208 nodeptrsize++;
14209 p++;
14210 }
14211 funcblocksize += sizeof(char *);
14212}
14213
14214static char **
14215argv_copy(char **p)
14216{
14217 char **new, **start = funcblock;
14218
14219 while (p && *p) {
14220 new = funcblock;
14221 funcblock = (char *) funcblock + sizeof(char *);
14222 *new = nodeckstrdup(*p);
14223 SAVE_PTR(*new);
14224 p++;
14225 new++;
14226 }
14227 new = funcblock;
14228 funcblock = (char *) funcblock + sizeof(char *);
14229 *new = NULL;
14230 return start;
14231}
14232
14233/*
14234 * struct redirtab
14235 */
14236static void
14237redirtab_size(struct redirtab *rdtp)
14238{
14239 while (rdtp) {
14240 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14241 rdtp = rdtp->next;
14242 nodeptrsize++; /* rdtp->next */
14243 }
14244}
14245
14246static struct redirtab *
14247redirtab_copy(struct redirtab *rdtp)
14248{
14249 struct redirtab *start;
14250 struct redirtab **vpp;
14251
14252 vpp = &start;
14253 while (rdtp) {
14254 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14255 *vpp = funcblock;
14256 funcblock = (char *) funcblock + size;
14257 memcpy(*vpp, rdtp, size);
14258 SAVE_PTR((*vpp)->next);
14259 rdtp = rdtp->next;
14260 vpp = &(*vpp)->next;
14261 }
14262 *vpp = NULL;
14263 return start;
14264}
14265
14266#undef shellparam
14267#undef redirlist
14268#undef varinit
14269#undef vartab
14270static void
14271globals_var_size(struct globals_var *gvp)
14272{
14273 int i;
14274
14275 funcblocksize += sizeof(struct globals_var);
14276 argv_size(gvp->shellparam.p);
14277 redirtab_size(gvp->redirlist);
14278 for (i = 0; i < VTABSIZE; i++)
14279 var_size(gvp->vartab[i]);
14280 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14281 var_size(gvp->varinit+i);
14282 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14283}
14284
14285#undef g_nullredirs
14286#undef preverrout_fd
14287static struct globals_var *
14288globals_var_copy(struct globals_var *gvp)
14289{
14290 int i;
14291 struct globals_var *new;
14292
14293 new = funcblock;
14294 funcblock = (char *) funcblock + sizeof(struct globals_var);
14295
14296 /* shparam */
14297 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14298 new->shellparam.malloced = 0;
14299 new->shellparam.p = argv_copy(gvp->shellparam.p);
14300 SAVE_PTR(new->shellparam.p);
14301
14302 new->redirlist = redirtab_copy(gvp->redirlist);
14303 SAVE_PTR(new->redirlist);
14304
14305 new->g_nullredirs = gvp->g_nullredirs;
14306 new->preverrout_fd = gvp->preverrout_fd;
14307 for (i = 0; i < VTABSIZE; i++) {
14308 new->vartab[i] = var_copy(gvp->vartab[i]);
14309 SAVE_PTR(new->vartab[i]);
14310 }
14311
14312 /* Can't use var_copy because varinit is already allocated */
14313 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14314 new->varinit[i].next = NULL;
14315 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14316 SAVE_PTR(new->varinit[i].var_text);
14317 new->varinit[i].flags = gvp->varinit[i].flags;
14318 new->varinit[i].var_func = gvp->varinit[i].var_func;
14319 }
14320 return new;
14321}
14322
14323#undef minusc
14324#undef curdir
14325#undef physdir
14326#undef arg0
14327#undef nullstr
14328static void
14329globals_misc_size(struct globals_misc *p)
14330{
14331 funcblocksize += sizeof(struct globals_misc);
14332 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14333 if (p->curdir != p->nullstr)
14334 funcstringsize += strlen(p->curdir) + 1;
14335 if (p->physdir != p->nullstr)
14336 funcstringsize += strlen(p->physdir) + 1;
14337 funcstringsize += strlen(p->arg0) + 1;
14338 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14339}
14340
14341static struct globals_misc *
14342globals_misc_copy(struct globals_misc *p)
14343{
14344 struct globals_misc *new = funcblock;
14345
14346 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14347 memcpy(new, p, sizeof(struct globals_misc));
14348
14349 new->minusc = nodeckstrdup(p->minusc);
14350 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14351 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14352 new->arg0 = nodeckstrdup(p->arg0);
14353 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14354 return new;
14355}
14356
14357static void
14358forkshell_size(struct forkshell *fs)
14359{
14360 funcblocksize += sizeof(struct forkshell);
14361 globals_var_size(fs->gvp);
14362 globals_misc_size(fs->gmp);
14363 cmdtable_size(fs->cmdtable);
14364 /* optlist_transfer(sending, fd); */
14365 /* misc_transfer(sending, fd); */
14366
14367 calcsize(fs->n);
14368 argv_size(fs->argv);
14369 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14370 strlist_size(fs->strlist);
14371
14372 nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */
14373}
14374
14375static struct forkshell *
14376forkshell_copy(struct forkshell *fs)
14377{
14378 struct forkshell *new;
14379
14380 new = funcblock;
14381 funcblock = (char *) funcblock + sizeof(struct forkshell);
14382
14383 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
14384 new->gvp = globals_var_copy(fs->gvp);
14385 new->gmp = globals_misc_copy(fs->gmp);
14386 new->cmdtable = cmdtable_copy(fs->cmdtable);
14387 SAVE_PTR3(new->gvp, new->gmp, new->cmdtable);
14388
14389 new->n = copynode(fs->n);
14390 new->argv = argv_copy(fs->argv);
14391 new->string = nodeckstrdup(fs->string);
14392 new->strlist = strlist_copy(fs->strlist);
14393 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
14394 return new;
14395}
14396
14397static struct forkshell *
14398forkshell_prepare(struct forkshell *fs)
14399{
14400 struct forkshell *new;
14401 int size, nodeptr_offset;
14402 HANDLE h;
14403 SECURITY_ATTRIBUTES sa;
14404
14405 /* Calculate size of "new" */
14406 fs->gvp = ash_ptr_to_globals_var;
14407 fs->gmp = ash_ptr_to_globals_misc;
14408 fs->cmdtable = cmdtable;
14409
14410 nodeptrsize = 1; /* NULL terminated */
14411 funcblocksize = 0;
14412 funcstringsize = 0;
14413 forkshell_size(fs);
14414 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(int);
14415
14416 /* Allocate, initialize pointers */
14417 memset(&sa, 0, sizeof(sa));
14418 sa.nLength = sizeof(sa);
14419 sa.lpSecurityDescriptor = NULL;
14420 sa.bInheritHandle = TRUE;
14421 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
14422 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14423 /* new = ckmalloc(size); */
14424 funcblock = new;
14425 funcstring = (char *) funcblock + funcblocksize;
14426 nodeptr = (int*)((char *) funcstring + funcstringsize);
14427 nodeptr_offset = (int) nodeptr - (int) new;
14428
14429 /* Now pack them all */
14430 forkshell_copy(fs);
14431
14432 /* Finish it up */
14433 *nodeptr = 0;
14434 new->size = size;
14435 new->nodeptr_offset = nodeptr_offset;
14436 new->old_base = new;
14437 new->hMapFile = h;
14438 return new;
14439}
14440
14441#undef exception_handler
14442#undef trap
14443#undef trap_ptr
14444static void *sticky_mem_start, *sticky_mem_end;
14445static void
14446forkshell_init(const char *idstr)
14447{
14448 struct forkshell *fs;
14449 int map_handle;
14450 HANDLE h;
14451 struct globals_var **gvpp;
14452 struct globals_misc **gmpp;
14453 int i;
14454
14455 if (sscanf(idstr, "%x", &map_handle) != 1)
14456 bb_error_msg_and_die("invalid forkshell ID");
14457
14458 h = (HANDLE)map_handle;
14459 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14460 if (!fs)
14461 bb_error_msg_and_die("Invalid forkshell memory");
14462
14463 /* this memory can't be freed */
14464 sticky_mem_start = fs;
14465 sticky_mem_end = (char *) fs + fs->size;
14466 /* pointer fixup */
14467 nodeptr = (int*)((char*)fs + fs->nodeptr_offset);
14468 while (*nodeptr) {
14469 int *ptr = (int*)((char*)fs + (*nodeptr - (int)fs->old_base));
14470 if (*ptr)
14471 *ptr -= ((int)fs->old_base - (int)fs);
14472 nodeptr++;
14473 }
14474 /* Now fix up stuff that can't be transferred */
14475 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14476 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
14477 for (i = 0; i < CMDTABLESIZE; i++) {
14478 struct tblentry *e = fs->cmdtable[i];
14479 while (e) {
14480 if (e->cmdtype == CMDBUILTIN)
14481 e->param.cmd = builtintab + (int)e->param.cmd;
14482 e = e->next;
14483 }
14484 }
14485 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
14486 for (i = 0; i < NSIG; i++)
14487 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
14488 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
14489
14490 /* Switch global variables */
14491 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
14492 *gvpp = fs->gvp;
14493 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
14494 *gmpp = fs->gmp;
14495 cmdtable = fs->cmdtable;
14496
14497 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
14498
14499 reinitvar();
14500
14501 forkshell_child(fs);
14502}
14503
14504#undef free
14505static void
14506sticky_free(void *base)
14507{
14508 if (base >= sticky_mem_start && base < sticky_mem_end)
14509 return;
14510 free(base);
14511}
14512#endif
13338 14513
13339/*- 14514/*-
13340 * Copyright (c) 1989, 1991, 1993, 1994 14515 * Copyright (c) 1989, 1991, 1993, 1994
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 57297155e..4c870fab8 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -20,7 +20,11 @@
20#include "shell_common.h" 20#include "shell_common.h"
21#include <sys/resource.h> /* getrlimit */ 21#include <sys/resource.h> /* getrlimit */
22 22
23#if !ENABLE_PLATFORM_MINGW32
23const char defifsvar[] ALIGN1 = "IFS= \t\n"; 24const char defifsvar[] ALIGN1 = "IFS= \t\n";
25#else
26const char defifsvar[] ALIGN1 = "IFS= \t\n\r";
27#endif
24 28
25 29
26int FAST_FUNC is_well_formed_var_name(const char *s, char terminator) 30int FAST_FUNC is_well_formed_var_name(const char *s, char terminator)
@@ -201,7 +205,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
201 } 205 }
202 206
203 c = buffer[bufpos]; 207 c = buffer[bufpos];
204 if (c == '\0') 208 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r'))
205 continue; 209 continue;
206 if (backslash) { 210 if (backslash) {
207 backslash = 0; 211 backslash = 0;
@@ -273,6 +277,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
273 277
274/* ulimit builtin */ 278/* ulimit builtin */
275 279
280#if !ENABLE_PLATFORM_MINGW32
276struct limits { 281struct limits {
277 uint8_t cmd; /* RLIMIT_xxx fit into it */ 282 uint8_t cmd; /* RLIMIT_xxx fit into it */
278 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 283 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
@@ -498,3 +503,9 @@ shell_builtin_ulimit(char **argv)
498 503
499 return 0; 504 return 0;
500} 505}
506#else
507int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM)
508{
509 return 1;
510}
511#endif
diff --git a/util-linux/rev.c b/util-linux/rev.c
index 3c1b22f09..f952447e4 100644
--- a/util-linux/rev.c
+++ b/util-linux/rev.c
@@ -32,7 +32,7 @@
32#endif 32#endif
33 33
34/* In-place invert */ 34/* In-place invert */
35static void strrev(CHAR_T *s, int len) 35static void bb_strrev(CHAR_T *s, int len)
36{ 36{
37 int i; 37 int i;
38 38
@@ -40,6 +40,10 @@ static void strrev(CHAR_T *s, int len)
40 len--; 40 len--;
41 if (len != 0 && s[len] == '\n') 41 if (len != 0 && s[len] == '\n')
42 len--; 42 len--;
43#if ENABLE_PLATFORM_MINGW32
44 if (len != 0 && s[len] == '\r')
45 len--;
46#endif
43 } 47 }
44 48
45 for (i = 0; i < len; i++, len--) { 49 for (i = 0; i < len; i++, len--) {
@@ -100,14 +104,14 @@ int rev_main(int argc UNUSED_PARAM, char **argv)
100 /* Convert to wchar_t (might error out!) */ 104 /* Convert to wchar_t (might error out!) */
101 int len = mbstowcs(tmp, buf, bufsize); 105 int len = mbstowcs(tmp, buf, bufsize);
102 if (len >= 0) { 106 if (len >= 0) {
103 strrev(tmp, len); 107 bb_strrev(tmp, len);
104 /* Convert back to char */ 108 /* Convert back to char */
105 wcstombs(buf, tmp, bufsize); 109 wcstombs(buf, tmp, bufsize);
106 } 110 }
107 free(tmp); 111 free(tmp);
108 } 112 }
109#else 113#else
110 strrev(buf, strlen(buf)); 114 bb_strrev(buf, strlen(buf));
111#endif 115#endif
112 fputs(buf, stdout); 116 fputs(buf, stdout);
113 } 117 }
diff --git a/win32/Kbuild b/win32/Kbuild
new file mode 100644
index 000000000..ca44a4134
--- /dev/null
+++ b/win32/Kbuild
@@ -0,0 +1,23 @@
1# Makefile for busybox
2#
3# Licensed under the GPL v2, see the file LICENSE in this tarball.
4
5lib-y:=
6
7lib-$(CONFIG_PLATFORM_MINGW32) += env.o
8lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o
9lib-$(CONFIG_PLATFORM_MINGW32) += ioctl.o
10lib-$(CONFIG_PLATFORM_MINGW32) += mingw.o
11lib-$(CONFIG_PLATFORM_MINGW32) += process.o
12lib-$(CONFIG_PLATFORM_MINGW32) += regex.o
13lib-$(CONFIG_PLATFORM_MINGW32) += net.o
14lib-$(CONFIG_PLATFORM_MINGW32) += poll.o
15lib-$(CONFIG_PLATFORM_MINGW32) += popen.o
16lib-$(CONFIG_PLATFORM_MINGW32) += statfs.o
17lib-$(CONFIG_PLATFORM_MINGW32) += mempcpy.o
18lib-$(CONFIG_PLATFORM_MINGW32) += mntent.o
19lib-$(CONFIG_PLATFORM_MINGW32) += strptime.o
20lib-$(CONFIG_PLATFORM_MINGW32) += system.o
21lib-$(CONFIG_PLATFORM_MINGW32) += termios.o
22lib-$(CONFIG_PLATFORM_MINGW32) += uname.o
23lib-$(CONFIG_PLATFORM_MINGW32) += winansi.o
diff --git a/win32/env.c b/win32/env.c
new file mode 100644
index 000000000..f8d231a8f
--- /dev/null
+++ b/win32/env.c
@@ -0,0 +1,130 @@
1#include "libbb.h"
2
3char **copy_environ(const char *const *envp)
4{
5 char **env;
6 int i = 0;
7 while (envp[i])
8 i++;
9 env = xmalloc((i+1)*sizeof(*env));
10 for (i = 0; envp[i]; i++)
11 env[i] = xstrdup(envp[i]);
12 env[i] = NULL;
13 return env;
14}
15
16void free_environ(char **env)
17{
18 int i;
19 for (i = 0; env[i]; i++)
20 free(env[i]);
21 free(env);
22}
23
24static int lookup_env(char **env, const char *name, size_t nmln)
25{
26 int i;
27
28 for (i = 0; env[i]; i++) {
29 if (0 == strncmp(env[i], name, nmln)
30 && '=' == env[i][nmln])
31 /* matches */
32 return i;
33 }
34 return -1;
35}
36
37#undef getenv
38char *mingw_getenv(const char *name)
39{
40 char *result = getenv(name);
41 if (!result && !strcmp(name, "TMPDIR")) {
42 /* on Windows it is TMP and TEMP */
43 result = getenv("TMP");
44 if (!result)
45 result = getenv("TEMP");
46 }
47 return result;
48}
49
50int setenv(const char *name, const char *value, int replace)
51{
52 int out;
53 size_t namelen, valuelen;
54 char *envstr;
55
56 if (!name || !value) return -1;
57 if (!replace) {
58 char *oldval = NULL;
59 oldval = getenv(name);
60 if (oldval) return 0;
61 }
62
63 namelen = strlen(name);
64 valuelen = strlen(value);
65 envstr = malloc((namelen + valuelen + 2));
66 if (!envstr) return -1;
67
68 memcpy(envstr, name, namelen);
69 envstr[namelen] = '=';
70 memcpy(envstr + namelen + 1, value, valuelen);
71 envstr[namelen + valuelen + 1] = 0;
72
73 out = putenv(envstr);
74 /* putenv(3) makes the argument string part of the environment,
75 * and changing that string modifies the environment --- which
76 * means we do not own that storage anymore. Do not free
77 * envstr.
78 */
79
80 return out;
81}
82
83/*
84 * If name contains '=', then sets the variable, otherwise it unsets it
85 */
86char **env_setenv(char **env, const char *name)
87{
88 char *eq = strchrnul(name, '=');
89 int i = lookup_env(env, name, eq-name);
90
91 if (i < 0) {
92 if (*eq) {
93 for (i = 0; env[i]; i++)
94 ;
95 env = xrealloc(env, (i+2)*sizeof(*env));
96 env[i] = xstrdup(name);
97 env[i+1] = NULL;
98 }
99 }
100 else {
101 free(env[i]);
102 if (*eq)
103 env[i] = xstrdup(name);
104 else {
105 for (; env[i]; i++)
106 env[i] = env[i+1];
107 SetEnvironmentVariable(name, NULL);
108 }
109 }
110 return env;
111}
112
113void unsetenv(const char *env)
114{
115 env_setenv(environ, env);
116}
117
118int clearenv(void)
119{
120 char **env = environ;
121 if (!env)
122 return 0;
123 while (*env) {
124 free(*env);
125 env++;
126 }
127 free(env);
128 environ = NULL;
129 return 0;
130}
diff --git a/win32/fnmatch.c b/win32/fnmatch.c
new file mode 100644
index 000000000..1f4ead5f9
--- /dev/null
+++ b/win32/fnmatch.c
@@ -0,0 +1,488 @@
1/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
18
19#if HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23/* Enable GNU extensions in fnmatch.h. */
24#ifndef _GNU_SOURCE
25# define _GNU_SOURCE 1
26#endif
27
28#include <errno.h>
29#include <fnmatch.h>
30#include <ctype.h>
31
32#if HAVE_STRING_H || defined _LIBC
33# include <string.h>
34#else
35# include <strings.h>
36#endif
37
38#if defined STDC_HEADERS || defined _LIBC
39# include <stdlib.h>
40#endif
41
42/* For platform which support the ISO C amendement 1 functionality we
43 support user defined character classes. */
44#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
45/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
46# include <wchar.h>
47# include <wctype.h>
48#endif
49
50/* Comment out all this code if we are using the GNU C Library, and are not
51 actually compiling the library itself. This code is part of the GNU C
52 Library, but also included in many other GNU distributions. Compiling
53 and linking in this code is a waste when using the GNU C library
54 (especially if it is a shared library). Rather than having every GNU
55 program understand `configure --with-gnu-libc' and omit the object files,
56 it is simpler to just do this in the source for each such file. */
57
58#if defined _LIBC || !defined __GNU_LIBRARY__
59
60
61# if defined STDC_HEADERS || !defined isascii
62# define ISASCII(c) 1
63# else
64# define ISASCII(c) isascii(c)
65# endif
66
67# ifdef isblank
68# define ISBLANK(c) (ISASCII (c) && isblank (c))
69# else
70# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
71# endif
72# ifdef isgraph
73# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
74# else
75# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
76# endif
77
78# define ISPRINT(c) (ISASCII (c) && isprint (c))
79# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
80# define ISALNUM(c) (ISASCII (c) && isalnum (c))
81# define ISALPHA(c) (ISASCII (c) && isalpha (c))
82# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
83# define ISLOWER(c) (ISASCII (c) && islower (c))
84# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
85# define ISSPACE(c) (ISASCII (c) && isspace (c))
86# define ISUPPER(c) (ISASCII (c) && isupper (c))
87# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
88
89# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
90
91# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
92/* The GNU C library provides support for user-defined character classes
93 and the functions from ISO C amendement 1. */
94# ifdef CHARCLASS_NAME_MAX
95# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
96# else
97/* This shouldn't happen but some implementation might still have this
98 problem. Use a reasonable default value. */
99# define CHAR_CLASS_MAX_LENGTH 256
100# endif
101
102# ifdef _LIBC
103# define IS_CHAR_CLASS(string) __wctype (string)
104# else
105# define IS_CHAR_CLASS(string) wctype (string)
106# endif
107# else
108# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
109
110# define IS_CHAR_CLASS(string) \
111 (STREQ (string, "alpha") || STREQ (string, "upper") \
112 || STREQ (string, "lower") || STREQ (string, "digit") \
113 || STREQ (string, "alnum") || STREQ (string, "xdigit") \
114 || STREQ (string, "space") || STREQ (string, "print") \
115 || STREQ (string, "punct") || STREQ (string, "graph") \
116 || STREQ (string, "cntrl") || STREQ (string, "blank"))
117# endif
118
119/* Avoid depending on library functions or files
120 whose names are inconsistent. */
121
122# if !defined _LIBC && !defined getenv
123extern char *getenv ();
124# endif
125
126# ifndef errno
127extern int errno;
128# endif
129
130/* This function doesn't exist on most systems. */
131
132# if !defined HAVE___STRCHRNUL && !defined _LIBC
133static char *
134__strchrnul (s, c)
135 const char *s;
136 int c;
137{
138 char *result = strchr (s, c);
139 if (result == NULL)
140 result = strchr (s, '\0');
141 return result;
142}
143# endif
144
145# ifndef internal_function
146/* Inside GNU libc we mark some function in a special way. In other
147 environments simply ignore the marking. */
148# define internal_function
149# endif
150
151/* Match STRING against the filename pattern PATTERN, returning zero if
152 it matches, nonzero if not. */
153static int internal_fnmatch __P ((const char *pattern, const char *string,
154 int no_leading_period, int flags))
155 internal_function;
156static int
157internal_function
158internal_fnmatch (pattern, string, no_leading_period, flags)
159 const char *pattern;
160 const char *string;
161 int no_leading_period;
162 int flags;
163{
164 register const char *p = pattern, *n = string;
165 register unsigned char c;
166
167/* Note that this evaluates C many times. */
168# ifdef _LIBC
169# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
170# else
171# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
172# endif
173
174 while ((c = *p++) != '\0')
175 {
176 c = FOLD (c);
177
178 switch (c)
179 {
180 case '?':
181 if (*n == '\0')
182 return FNM_NOMATCH;
183 else if (*n == '/' && (flags & FNM_FILE_NAME))
184 return FNM_NOMATCH;
185 else if (*n == '.' && no_leading_period
186 && (n == string
187 || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
188 return FNM_NOMATCH;
189 break;
190
191 case '\\':
192 if (!(flags & FNM_NOESCAPE))
193 {
194 c = *p++;
195 if (c == '\0')
196 /* Trailing \ loses. */
197 return FNM_NOMATCH;
198 c = FOLD (c);
199 }
200 if (FOLD ((unsigned char) *n) != c)
201 return FNM_NOMATCH;
202 break;
203
204 case '*':
205 if (*n == '.' && no_leading_period
206 && (n == string
207 || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
208 return FNM_NOMATCH;
209
210 for (c = *p++; c == '?' || c == '*'; c = *p++)
211 {
212 if (*n == '/' && (flags & FNM_FILE_NAME))
213 /* A slash does not match a wildcard under FNM_FILE_NAME. */
214 return FNM_NOMATCH;
215 else if (c == '?')
216 {
217 /* A ? needs to match one character. */
218 if (*n == '\0')
219 /* There isn't another character; no match. */
220 return FNM_NOMATCH;
221 else
222 /* One character of the string is consumed in matching
223 this ? wildcard, so *??? won't match if there are
224 less than three characters. */
225 ++n;
226 }
227 }
228
229 if (c == '\0')
230 /* The wildcard(s) is/are the last element of the pattern.
231 If the name is a file name and contains another slash
232 this does mean it cannot match. */
233 return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
234 ? FNM_NOMATCH : 0);
235 else
236 {
237 const char *endp;
238
239 endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
240
241 if (c == '[')
242 {
243 int flags2 = ((flags & FNM_FILE_NAME)
244 ? flags : (flags & ~FNM_PERIOD));
245
246 for (--p; n < endp; ++n)
247 if (internal_fnmatch (p, n,
248 (no_leading_period
249 && (n == string
250 || (n[-1] == '/'
251 && (flags
252 & FNM_FILE_NAME)))),
253 flags2)
254 == 0)
255 return 0;
256 }
257 else if (c == '/' && (flags & FNM_FILE_NAME))
258 {
259 while (*n != '\0' && *n != '/')
260 ++n;
261 if (*n == '/'
262 && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
263 flags) == 0))
264 return 0;
265 }
266 else
267 {
268 int flags2 = ((flags & FNM_FILE_NAME)
269 ? flags : (flags & ~FNM_PERIOD));
270
271 if (c == '\\' && !(flags & FNM_NOESCAPE))
272 c = *p;
273 c = FOLD (c);
274 for (--p; n < endp; ++n)
275 if (FOLD ((unsigned char) *n) == c
276 && (internal_fnmatch (p, n,
277 (no_leading_period
278 && (n == string
279 || (n[-1] == '/'
280 && (flags
281 & FNM_FILE_NAME)))),
282 flags2) == 0))
283 return 0;
284 }
285 }
286
287 /* If we come here no match is possible with the wildcard. */
288 return FNM_NOMATCH;
289
290 case '[':
291 {
292 /* Nonzero if the sense of the character class is inverted. */
293 static int posixly_correct;
294 register int not;
295 char cold;
296
297 if (posixly_correct == 0)
298 posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
299
300 if (*n == '\0')
301 return FNM_NOMATCH;
302
303 if (*n == '.' && no_leading_period && (n == string
304 || (n[-1] == '/'
305 && (flags
306 & FNM_FILE_NAME))))
307 return FNM_NOMATCH;
308
309 if (*n == '/' && (flags & FNM_FILE_NAME))
310 /* `/' cannot be matched. */
311 return FNM_NOMATCH;
312
313 not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
314 if (not)
315 ++p;
316
317 c = *p++;
318 for (;;)
319 {
320 unsigned char fn = FOLD ((unsigned char) *n);
321
322 if (!(flags & FNM_NOESCAPE) && c == '\\')
323 {
324 if (*p == '\0')
325 return FNM_NOMATCH;
326 c = FOLD ((unsigned char) *p);
327 ++p;
328
329 if (c == fn)
330 goto matched;
331 }
332 else if (c == '[' && *p == ':')
333 {
334 /* Leave room for the null. */
335 char str[CHAR_CLASS_MAX_LENGTH + 1];
336 size_t c1 = 0;
337# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
338 wctype_t wt;
339# endif
340 const char *startp = p;
341
342 for (;;)
343 {
344 if (c1 == CHAR_CLASS_MAX_LENGTH)
345 /* The name is too long and therefore the pattern
346 is ill-formed. */
347 return FNM_NOMATCH;
348
349 c = *++p;
350 if (c == ':' && p[1] == ']')
351 {
352 p += 2;
353 break;
354 }
355 if (c < 'a' || c >= 'z')
356 {
357 /* This cannot possibly be a character class name.
358 Match it as a normal range. */
359 p = startp;
360 c = '[';
361 goto normal_bracket;
362 }
363 str[c1++] = c;
364 }
365 str[c1] = '\0';
366
367# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
368 wt = IS_CHAR_CLASS (str);
369 if (wt == 0)
370 /* Invalid character class name. */
371 return FNM_NOMATCH;
372
373 if (__iswctype (__btowc ((unsigned char) *n), wt))
374 goto matched;
375# else
376 if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
377 || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
378 || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
379 || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
380 || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
381 || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
382 || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
383 || (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
384 || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
385 || (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
386 || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
387 || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
388 goto matched;
389# endif
390 }
391 else if (c == '\0')
392 /* [ (unterminated) loses. */
393 return FNM_NOMATCH;
394 else
395 {
396 normal_bracket:
397 if (FOLD (c) == fn)
398 goto matched;
399
400 cold = c;
401 c = *p++;
402
403 if (c == '-' && *p != ']')
404 {
405 /* It is a range. */
406 unsigned char cend = *p++;
407 if (!(flags & FNM_NOESCAPE) && cend == '\\')
408 cend = *p++;
409 if (cend == '\0')
410 return FNM_NOMATCH;
411
412 if (cold <= fn && fn <= FOLD (cend))
413 goto matched;
414
415 c = *p++;
416 }
417 }
418
419 if (c == ']')
420 break;
421 }
422
423 if (!not)
424 return FNM_NOMATCH;
425 break;
426
427 matched:
428 /* Skip the rest of the [...] that already matched. */
429 while (c != ']')
430 {
431 if (c == '\0')
432 /* [... (unterminated) loses. */
433 return FNM_NOMATCH;
434
435 c = *p++;
436 if (!(flags & FNM_NOESCAPE) && c == '\\')
437 {
438 if (*p == '\0')
439 return FNM_NOMATCH;
440 /* XXX 1003.2d11 is unclear if this is right. */
441 ++p;
442 }
443 else if (c == '[' && *p == ':')
444 {
445 do
446 if (*++p == '\0')
447 return FNM_NOMATCH;
448 while (*p != ':' || p[1] == ']');
449 p += 2;
450 c = *p;
451 }
452 }
453 if (not)
454 return FNM_NOMATCH;
455 }
456 break;
457
458 default:
459 if (c != FOLD ((unsigned char) *n))
460 return FNM_NOMATCH;
461 }
462
463 ++n;
464 }
465
466 if (*n == '\0')
467 return 0;
468
469 if ((flags & FNM_LEADING_DIR) && *n == '/')
470 /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
471 return 0;
472
473 return FNM_NOMATCH;
474
475# undef FOLD
476}
477
478
479int
480fnmatch (pattern, string, flags)
481 const char *pattern;
482 const char *string;
483 int flags;
484{
485 return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
486}
487
488#endif /* _LIBC or not __GNU_LIBRARY__. */
diff --git a/win32/fnmatch.h b/win32/fnmatch.h
new file mode 100644
index 000000000..cc3ec3794
--- /dev/null
+++ b/win32/fnmatch.h
@@ -0,0 +1,84 @@
1/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If not,
16 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
18
19#ifndef _FNMATCH_H
20#define _FNMATCH_H 1
21
22#ifdef __cplusplus
23extern "C" {
24#endif
25
26#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
27# if !defined __GLIBC__ || !defined __P
28# undef __P
29# define __P(protos) protos
30# endif
31#else /* Not C++ or ANSI C. */
32# undef __P
33# define __P(protos) ()
34/* We can get away without defining `const' here only because in this file
35 it is used only inside the prototype for `fnmatch', which is elided in
36 non-ANSI C where `const' is problematical. */
37#endif /* C++ or ANSI C. */
38
39#ifndef const
40# if (defined __STDC__ && __STDC__) || defined __cplusplus
41# define __const const
42# else
43# define __const
44# endif
45#endif
46
47/* We #undef these before defining them because some losing systems
48 (HP-UX A.08.07 for example) define these in <unistd.h>. */
49#undef FNM_PATHNAME
50#undef FNM_NOESCAPE
51#undef FNM_PERIOD
52
53/* Bits set in the FLAGS argument to `fnmatch'. */
54#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
55#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
56#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
57
58#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
59# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
60# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
61# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
62#endif
63
64/* Value returned by `fnmatch' if STRING does not match PATTERN. */
65#define FNM_NOMATCH 1
66
67/* This value is returned if the implementation does not support
68 `fnmatch'. Since this is not the case here it will never be
69 returned but the conformance test suites still require the symbol
70 to be defined. */
71#ifdef _XOPEN_SOURCE
72# define FNM_NOSYS (-1)
73#endif
74
75/* Match NAME against the filename pattern PATTERN,
76 returning zero if it matches, FNM_NOMATCH if not. */
77extern int fnmatch __P ((__const char *__pattern, __const char *__name,
78 int __flags));
79
80#ifdef __cplusplus
81}
82#endif
83
84#endif /* fnmatch.h */
diff --git a/win32/grp.h b/win32/grp.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/grp.h
diff --git a/win32/ioctl.c b/win32/ioctl.c
new file mode 100644
index 000000000..73ceeedec
--- /dev/null
+++ b/win32/ioctl.c
@@ -0,0 +1,24 @@
1#include "libbb.h"
2
3int ioctl(int fd UNUSED_PARAM, int code, ...)
4{
5 va_list ap;
6 void *arg;
7 int ret = -1;
8
9 va_start(ap, code);
10
11 switch (code) {
12 case TIOCGWINSZ:
13 arg = va_arg(ap, void *);
14 ret = winansi_get_terminal_width_height((struct winsize *)arg);
15 break;
16 default:
17 ret = -1;
18 errno = EINVAL;
19 break;
20 }
21
22 va_end(ap);
23 return ret;
24}
diff --git a/win32/mempcpy.c b/win32/mempcpy.c
new file mode 100644
index 000000000..732a6f4b2
--- /dev/null
+++ b/win32/mempcpy.c
@@ -0,0 +1,27 @@
1/* Copy memory area and return pointer after last written byte.
2 Copyright (C) 2003, 2007, 2009-2014 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>. */
16
17#include "libbb.h"
18/* Specification. */
19#include <string.h>
20
21/* Copy N bytes of SRC to DEST, return pointer to bytes after the
22 last written byte. */
23void *
24mempcpy (void *dest, const void *src, size_t n)
25{
26 return (char *) memcpy (dest, src, n) + n;
27}
diff --git a/win32/mingw.c b/win32/mingw.c
new file mode 100644
index 000000000..83a7ab3a7
--- /dev/null
+++ b/win32/mingw.c
@@ -0,0 +1,990 @@
1#include "libbb.h"
2#include <userenv.h>
3
4#if ENABLE_NOGLOB
5/* disable MSVCRT command line globbing */
6int _CRT_glob = 0;
7#endif
8
9#if !defined(__MINGW64_VERSION_MAJOR)
10unsigned int _CRT_fmode = _O_BINARY;
11#else
12#undef _fmode
13int _fmode = _O_BINARY;
14#endif
15
16smallint bb_got_signal;
17
18static int err_win_to_posix(DWORD winerr)
19{
20 int error = ENOSYS;
21 switch(winerr) {
22 case ERROR_ACCESS_DENIED: error = EACCES; break;
23 case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
24 case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
25 case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
26 case ERROR_ALREADY_EXISTS: error = EEXIST; break;
27 case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
28 case ERROR_BAD_COMMAND: error = EIO; break;
29 case ERROR_BAD_DEVICE: error = ENODEV; break;
30 case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
31 case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
32 case ERROR_BAD_FORMAT: error = ENOEXEC; break;
33 case ERROR_BAD_LENGTH: error = EINVAL; break;
34 case ERROR_BAD_PATHNAME: error = ENOENT; break;
35 case ERROR_BAD_PIPE: error = EPIPE; break;
36 case ERROR_BAD_UNIT: error = ENODEV; break;
37 case ERROR_BAD_USERNAME: error = EINVAL; break;
38 case ERROR_BROKEN_PIPE: error = EPIPE; break;
39 case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
40 case ERROR_BUSY: error = EBUSY; break;
41 case ERROR_BUSY_DRIVE: error = EBUSY; break;
42 case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
43 case ERROR_CANNOT_MAKE: error = EACCES; break;
44 case ERROR_CANTOPEN: error = EIO; break;
45 case ERROR_CANTREAD: error = EIO; break;
46 case ERROR_CANTWRITE: error = EIO; break;
47 case ERROR_CRC: error = EIO; break;
48 case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
49 case ERROR_DEVICE_IN_USE: error = EBUSY; break;
50 case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
51 case ERROR_DIRECTORY: error = EINVAL; break;
52 case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
53 case ERROR_DISK_CHANGE: error = EIO; break;
54 case ERROR_DISK_FULL: error = ENOSPC; break;
55 case ERROR_DRIVE_LOCKED: error = EBUSY; break;
56 case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
57 case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
58 case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
59 case ERROR_FILE_EXISTS: error = EEXIST; break;
60 case ERROR_FILE_INVALID: error = ENODEV; break;
61 case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
62 case ERROR_GEN_FAILURE: error = EIO; break;
63 case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
64 case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
65 case ERROR_INVALID_ACCESS: error = EACCES; break;
66 case ERROR_INVALID_ADDRESS: error = EFAULT; break;
67 case ERROR_INVALID_BLOCK: error = EFAULT; break;
68 case ERROR_INVALID_DATA: error = EINVAL; break;
69 case ERROR_INVALID_DRIVE: error = ENODEV; break;
70 case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
71 case ERROR_INVALID_FLAGS: error = EINVAL; break;
72 case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
73 case ERROR_INVALID_HANDLE: error = EBADF; break;
74 case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
75 case ERROR_INVALID_NAME: error = EINVAL; break;
76 case ERROR_INVALID_OWNER: error = EINVAL; break;
77 case ERROR_INVALID_PARAMETER: error = EINVAL; break;
78 case ERROR_INVALID_PASSWORD: error = EPERM; break;
79 case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
80 case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
81 case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
82 case ERROR_INVALID_WORKSTATION: error = EACCES; break;
83 case ERROR_IO_DEVICE: error = EIO; break;
84 case ERROR_IO_INCOMPLETE: error = EINTR; break;
85 case ERROR_LOCKED: error = EBUSY; break;
86 case ERROR_LOCK_VIOLATION: error = EACCES; break;
87 case ERROR_LOGON_FAILURE: error = EACCES; break;
88 case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
89 case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
90 case ERROR_MORE_DATA: error = EPIPE; break;
91 case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
92 case ERROR_NOACCESS: error = EFAULT; break;
93 case ERROR_NONE_MAPPED: error = EINVAL; break;
94 case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
95 case ERROR_NOT_READY: error = EAGAIN; break;
96 case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
97 case ERROR_NO_DATA: error = EPIPE; break;
98 case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
99 case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
100 case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
101 case ERROR_OPEN_FAILED: error = EIO; break;
102 case ERROR_OPEN_FILES: error = EBUSY; break;
103 case ERROR_OPERATION_ABORTED: error = EINTR; break;
104 case ERROR_OUTOFMEMORY: error = ENOMEM; break;
105 case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
106 case ERROR_PATH_BUSY: error = EBUSY; break;
107 case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
108 case ERROR_PIPE_BUSY: error = EBUSY; break;
109 case ERROR_PIPE_CONNECTED: error = EPIPE; break;
110 case ERROR_PIPE_LISTENING: error = EPIPE; break;
111 case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
112 case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
113 case ERROR_READ_FAULT: error = EIO; break;
114 case ERROR_SEEK: error = EIO; break;
115 case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
116 case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
117 case ERROR_SHARING_VIOLATION: error = EACCES; break;
118 case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
119 case ERROR_SWAPERROR: error = ENOENT; break;
120 case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
121 case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
122 case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
123 case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
124 case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
125 case ERROR_WRITE_FAULT: error = EIO; break;
126 case ERROR_WRITE_PROTECT: error = EROFS; break;
127 }
128 return error;
129}
130
131#undef open
132int mingw_open (const char *filename, int oflags, ...)
133{
134 va_list args;
135 unsigned mode;
136 int fd;
137
138 va_start(args, oflags);
139 mode = va_arg(args, int);
140 va_end(args);
141
142 if (oflags & O_NONBLOCK) {
143 errno = ENOSYS;
144 return -1;
145 }
146 if (filename && !strcmp(filename, "/dev/null"))
147 filename = "nul";
148 fd = open(filename, oflags, mode);
149 if (fd < 0 && (oflags & O_CREAT) && errno == EACCES) {
150 DWORD attrs = GetFileAttributes(filename);
151 if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
152 errno = EISDIR;
153 }
154 return fd;
155}
156
157#undef fopen
158FILE *mingw_fopen (const char *filename, const char *otype)
159{
160 if (filename && !strcmp(filename, "/dev/null"))
161 filename = "nul";
162 return fopen(filename, otype);
163}
164
165#undef dup2
166int mingw_dup2 (int fd, int fdto)
167{
168 int ret = dup2(fd, fdto);
169 return ret != -1 ? fdto : -1;
170}
171
172/*
173 * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
174 * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
175 */
176static inline long long filetime_to_hnsec(const FILETIME *ft)
177{
178 long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
179 /* Windows to Unix Epoch conversion */
180 return winTime - 116444736000000000LL;
181}
182
183static inline time_t filetime_to_time_t(const FILETIME *ft)
184{
185 return (time_t)(filetime_to_hnsec(ft) / 10000000);
186}
187
188static inline int file_attr_to_st_mode (DWORD attr)
189{
190 int fMode = S_IREAD;
191 if (attr & FILE_ATTRIBUTE_DIRECTORY)
192 fMode |= S_IFDIR|S_IWRITE|S_IEXEC;
193 else
194 fMode |= S_IFREG;
195 if (!(attr & FILE_ATTRIBUTE_READONLY))
196 fMode |= S_IWRITE;
197 return fMode;
198}
199
200static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
201{
202 if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
203 return 0;
204
205 switch (GetLastError()) {
206 case ERROR_ACCESS_DENIED:
207 case ERROR_SHARING_VIOLATION:
208 case ERROR_LOCK_VIOLATION:
209 case ERROR_SHARING_BUFFER_EXCEEDED:
210 return EACCES;
211 case ERROR_BUFFER_OVERFLOW:
212 return ENAMETOOLONG;
213 case ERROR_NOT_ENOUGH_MEMORY:
214 return ENOMEM;
215 default:
216 return ENOENT;
217 }
218}
219
220/* We keep the do_lstat code in a separate function to avoid recursion.
221 * When a path ends with a slash, the stat will fail with ENOENT. In
222 * this case, we strip the trailing slashes and stat again.
223 *
224 * If follow is true then act like stat() and report on the link
225 * target. Otherwise report on the link itself.
226 */
227static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf)
228{
229 int err;
230 WIN32_FILE_ATTRIBUTE_DATA fdata;
231
232 if (!(err = get_file_attr(file_name, &fdata))) {
233 int len = strlen(file_name);
234
235 buf->st_ino = 0;
236 buf->st_gid = 0;
237 buf->st_uid = 0;
238 buf->st_nlink = 1;
239 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
240 if (len > 4 && (!strcasecmp(file_name+len-4, ".exe") ||
241 !strcasecmp(file_name+len-4, ".com")))
242 buf->st_mode |= S_IEXEC;
243 buf->st_size = fdata.nFileSizeLow |
244 (((off64_t)fdata.nFileSizeHigh)<<32);
245 buf->st_dev = buf->st_rdev = 0; /* not used by Git */
246 buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
247 buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
248 buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
249 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
250 WIN32_FIND_DATAA findbuf;
251 HANDLE handle = FindFirstFileA(file_name, &findbuf);
252 if (handle != INVALID_HANDLE_VALUE) {
253 if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
254 (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
255 if (follow) {
256 char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
257 buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
258 } else {
259 buf->st_mode = S_IFLNK;
260 }
261 buf->st_mode |= S_IREAD;
262 if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
263 buf->st_mode |= S_IWRITE;
264 }
265 FindClose(handle);
266 }
267 }
268
269 /*
270 * Assume a block is 4096 bytes and calculate number of 512 byte
271 * sectors.
272 */
273 buf->st_blksize = 4096;
274 buf->st_blocks = ((buf->st_size+4095)>>12)<<3;
275 return 0;
276 }
277 errno = err;
278 return -1;
279}
280
281/* We provide our own lstat/fstat functions, since the provided
282 * lstat/fstat functions are so slow. These stat functions are
283 * tailored for Git's usage (read: fast), and are not meant to be
284 * complete. Note that Git stat()s are redirected to mingw_lstat()
285 * too, since Windows doesn't really handle symlinks that well.
286 */
287static int do_stat_internal(int follow, const char *file_name, struct mingw_stat *buf)
288{
289 int namelen;
290 static char alt_name[PATH_MAX];
291
292 if (!do_lstat(follow, file_name, buf))
293 return 0;
294
295 /* if file_name ended in a '/', Windows returned ENOENT;
296 * try again without trailing slashes
297 */
298 if (errno != ENOENT)
299 return -1;
300
301 namelen = strlen(file_name);
302 if (namelen && file_name[namelen-1] != '/')
303 return -1;
304 while (namelen && file_name[namelen-1] == '/')
305 --namelen;
306 if (!namelen || namelen >= PATH_MAX)
307 return -1;
308
309 memcpy(alt_name, file_name, namelen);
310 alt_name[namelen] = 0;
311 return do_lstat(follow, alt_name, buf);
312}
313
314int mingw_lstat(const char *file_name, struct mingw_stat *buf)
315{
316 return do_stat_internal(0, file_name, buf);
317}
318int mingw_stat(const char *file_name, struct mingw_stat *buf)
319{
320 return do_stat_internal(1, file_name, buf);
321}
322
323int mingw_fstat(int fd, struct mingw_stat *buf)
324{
325 HANDLE fh = (HANDLE)_get_osfhandle(fd);
326 BY_HANDLE_FILE_INFORMATION fdata;
327
328 if (fh == INVALID_HANDLE_VALUE) {
329 errno = EBADF;
330 return -1;
331 }
332 /* direct non-file handles to MS's fstat() */
333 if (GetFileType(fh) != FILE_TYPE_DISK) {
334 struct _stati64 buf64;
335
336 if ( _fstati64(fd, &buf64) != 0 ) {
337 return -1;
338 }
339 buf->st_dev = 0;
340 buf->st_ino = 0;
341 buf->st_mode = S_IREAD|S_IWRITE;
342 buf->st_nlink = 1;
343 buf->st_uid = 0;
344 buf->st_gid = 0;
345 buf->st_rdev = 0;
346 buf->st_size = buf64.st_size;
347 buf->st_atime = buf64.st_atime;
348 buf->st_mtime = buf64.st_mtime;
349 buf->st_ctime = buf64.st_ctime;
350 buf->st_blksize = 4096;
351 buf->st_blocks = ((buf64.st_size+4095)>>12)<<3;
352 }
353
354 if (GetFileInformationByHandle(fh, &fdata)) {
355 buf->st_ino = 0;
356 buf->st_gid = 0;
357 buf->st_uid = 0;
358 buf->st_nlink = 1;
359 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
360 buf->st_size = fdata.nFileSizeLow |
361 (((off64_t)fdata.nFileSizeHigh)<<32);
362 buf->st_dev = buf->st_rdev = 0; /* not used by Git */
363 buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
364 buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
365 buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
366 buf->st_blksize = 4096;
367 buf->st_blocks = ((buf->st_size+4095)>>12)<<3;
368 return 0;
369 }
370 errno = EBADF;
371 return -1;
372}
373
374static inline void timeval_to_filetime(const struct timeval tv, FILETIME *ft)
375{
376 long long winTime = ((tv.tv_sec * 1000000LL) + tv.tv_usec) * 10LL + 116444736000000000LL;
377 ft->dwLowDateTime = winTime;
378 ft->dwHighDateTime = winTime >> 32;
379}
380
381int utimes(const char *file_name, const struct timeval tims[2])
382{
383 FILETIME mft, aft;
384 HANDLE fh;
385 DWORD flags, attrs;
386 int rc;
387
388 flags = FILE_ATTRIBUTE_NORMAL;
389
390 /* must have write permission */
391 attrs = GetFileAttributes(file_name);
392 if ( attrs != INVALID_FILE_ATTRIBUTES ) {
393 if ( attrs & FILE_ATTRIBUTE_READONLY ) {
394 /* ignore errors here; open() will report them */
395 SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
396 }
397
398 if ( attrs & FILE_ATTRIBUTE_DIRECTORY ) {
399 flags = FILE_FLAG_BACKUP_SEMANTICS;
400 }
401 }
402
403 fh = CreateFile(file_name, GENERIC_READ|GENERIC_WRITE,
404 FILE_SHARE_READ|FILE_SHARE_WRITE,
405 NULL, OPEN_EXISTING, flags, NULL);
406 if ( fh == INVALID_HANDLE_VALUE ) {
407 errno = err_win_to_posix(GetLastError());
408 rc = -1;
409 goto revert_attrs;
410 }
411
412 if (tims) {
413 timeval_to_filetime(tims[0], &aft);
414 timeval_to_filetime(tims[1], &mft);
415 }
416 else {
417 GetSystemTimeAsFileTime(&mft);
418 aft = mft;
419 }
420 if (!SetFileTime(fh, NULL, &aft, &mft)) {
421 errno = EINVAL;
422 rc = -1;
423 } else
424 rc = 0;
425 CloseHandle(fh);
426
427revert_attrs:
428 if (attrs != INVALID_FILE_ATTRIBUTES &&
429 (attrs & FILE_ATTRIBUTE_READONLY)) {
430 /* ignore errors again */
431 SetFileAttributes(file_name, attrs);
432 }
433 return rc;
434}
435
436unsigned int sleep (unsigned int seconds)
437{
438 Sleep(seconds*1000);
439 return 0;
440}
441
442/*
443 * Windows' mktemp returns NULL on error whereas POSIX always returns the
444 * template and signals an error by making it an empty string.
445 */
446#undef mktemp
447char *mingw_mktemp(char *template)
448{
449 if ( mktemp(template) == NULL ) {
450 template[0] = '\0';
451 }
452
453 return template;
454}
455
456int mkstemp(char *template)
457{
458 char *filename = mktemp(template);
459 if (filename == NULL)
460 return -1;
461 return open(filename, O_RDWR | O_CREAT, 0600);
462}
463
464int gettimeofday(struct timeval *tv, void *tz UNUSED_PARAM)
465{
466 FILETIME ft;
467 long long hnsec;
468
469 GetSystemTimeAsFileTime(&ft);
470 hnsec = filetime_to_hnsec(&ft);
471 tv->tv_sec = hnsec / 10000000;
472 tv->tv_usec = (hnsec % 10000000) / 10;
473 return 0;
474}
475
476int pipe(int filedes[2])
477{
478 if (_pipe(filedes, PIPE_BUF, 0) < 0)
479 return -1;
480 return 0;
481}
482
483struct tm *gmtime_r(const time_t *timep, struct tm *result)
484{
485 /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
486 memcpy(result, gmtime(timep), sizeof(struct tm));
487 return result;
488}
489
490struct tm *localtime_r(const time_t *timep, struct tm *result)
491{
492 /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */
493 memcpy(result, localtime(timep), sizeof(struct tm));
494 return result;
495}
496
497#undef getcwd
498char *mingw_getcwd(char *pointer, int len)
499{
500 int i;
501 char *ret = getcwd(pointer, len);
502 if (!ret)
503 return ret;
504 for (i = 0; ret[i]; i++)
505 if (ret[i] == '\\')
506 ret[i] = '/';
507 return ret;
508}
509
510#undef rename
511int mingw_rename(const char *pold, const char *pnew)
512{
513 DWORD attrs;
514
515 /*
516 * Try native rename() first to get errno right.
517 * It is based on MoveFile(), which cannot overwrite existing files.
518 */
519 if (!rename(pold, pnew))
520 return 0;
521 if (errno != EEXIST)
522 return -1;
523 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
524 return 0;
525 /* TODO: translate more errors */
526 if (GetLastError() == ERROR_ACCESS_DENIED &&
527 (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
528 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
529 errno = EISDIR;
530 return -1;
531 }
532 if ((attrs & FILE_ATTRIBUTE_READONLY) &&
533 SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
534 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
535 return 0;
536 /* revert file attributes on failure */
537 SetFileAttributes(pnew, attrs);
538 }
539 }
540 errno = EACCES;
541 return -1;
542}
543
544static char *gethomedir(void)
545{
546 static char buf[PATH_MAX];
547 DWORD len = sizeof(buf);
548 HANDLE h;
549 char *s;
550
551 buf[0] = '\0';
552 if ( !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h) )
553 return buf;
554
555 if ( !GetUserProfileDirectory(h, buf, &len) ) {
556 CloseHandle(h);
557 return buf;
558 }
559
560 CloseHandle(h);
561
562 for ( s=buf; *s; ++s ) {
563 if ( *s == '\\' ) {
564 *s = '/';
565 }
566 }
567
568 return buf;
569}
570
571struct passwd *getpwuid(int uid UNUSED_PARAM)
572{
573 static char user_name[100];
574 static struct passwd p;
575 DWORD len = sizeof(user_name);
576
577 user_name[0] = '\0';
578 if (!GetUserName(user_name, &len))
579 return NULL;
580 p.pw_name = user_name;
581 p.pw_gecos = (char *)"unknown";
582 p.pw_dir = gethomedir();
583 p.pw_shell = NULL;
584 p.pw_uid = 1000;
585 p.pw_gid = 1000;
586
587 return &p;
588}
589
590long sysconf(int name)
591{
592 if ( name == _SC_CLK_TCK ) {
593 return 100;
594 }
595 errno = EINVAL;
596 return -1;
597}
598
599clock_t times(struct tms *buf)
600{
601 buf->tms_utime = 0;
602 buf->tms_stime = 0;
603 buf->tms_cutime = 0;
604 buf->tms_cstime = 0;
605
606 return 0;
607}
608
609static HANDLE timer_event;
610static HANDLE timer_thread;
611static int timer_interval;
612static int one_shot;
613static sighandler_t timer_fn = SIG_DFL;
614
615/* The timer works like this:
616 * The thread, ticktack(), is a trivial routine that most of the time
617 * only waits to receive the signal to terminate. The main thread tells
618 * the thread to terminate by setting the timer_event to the signalled
619 * state.
620 * But ticktack() interrupts the wait state after the timer's interval
621 * length to call the signal handler.
622 */
623
624static __stdcall unsigned ticktack(void *dummy UNUSED_PARAM)
625{
626 while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
627 if (timer_fn == SIG_DFL)
628 bb_error_msg_and_die("Alarm");
629 if (timer_fn != SIG_IGN)
630 timer_fn(SIGALRM);
631 if (one_shot)
632 break;
633 }
634 return 0;
635}
636
637static int start_timer_thread(void)
638{
639 timer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
640 if (timer_event) {
641 timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL);
642 if (!timer_thread ) {
643 errno = ENOMEM;
644 return -1;
645 }
646 } else {
647 errno = ENOMEM;
648 return -1;
649 }
650 return 0;
651}
652
653static void stop_timer_thread(void)
654{
655 if (timer_event)
656 SetEvent(timer_event); /* tell thread to terminate */
657 if (timer_thread) {
658 int rc = WaitForSingleObject(timer_thread, 1000);
659 if (rc == WAIT_TIMEOUT)
660 fprintf(stderr, "timer thread did not terminate timely");
661 else if (rc != WAIT_OBJECT_0)
662 fprintf(stderr, "waiting for timer thread failed: %lu",
663 GetLastError());
664 CloseHandle(timer_thread);
665 }
666 if (timer_event)
667 CloseHandle(timer_event);
668 timer_event = NULL;
669 timer_thread = NULL;
670}
671
672static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2)
673{
674 return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
675}
676
677int setitimer(int type UNUSED_PARAM, struct itimerval *in, struct itimerval *out)
678{
679 static const struct timeval zero;
680 static int atexit_done;
681
682 if (out != NULL) {
683 errno = EINVAL;
684 return -1;
685 }
686 if (!is_timeval_eq(&in->it_interval, &zero) &&
687 !is_timeval_eq(&in->it_interval, &in->it_value)) {
688 errno = EINVAL;
689 return -1;
690 }
691
692 if (timer_thread)
693 stop_timer_thread();
694
695 if (is_timeval_eq(&in->it_value, &zero) &&
696 is_timeval_eq(&in->it_interval, &zero))
697 return 0;
698
699 timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000;
700 one_shot = is_timeval_eq(&in->it_interval, &zero);
701 if (!atexit_done) {
702 atexit(stop_timer_thread);
703 atexit_done = 1;
704 }
705 return start_timer_thread();
706}
707
708int sigaction(int sig, struct sigaction *in, struct sigaction *out)
709{
710 if (sig != SIGALRM) {
711 errno = EINVAL;
712 return -1;
713 }
714 if (out != NULL) {
715 errno = EINVAL;
716 return -1;
717 }
718
719 timer_fn = in->sa_handler;
720 return 0;
721}
722
723#undef signal
724sighandler_t mingw_signal(int sig, sighandler_t handler)
725{
726 sighandler_t old = timer_fn;
727 if (sig != SIGALRM)
728 return signal(sig, handler);
729 timer_fn = handler;
730 return old;
731}
732
733int link(const char *oldpath, const char *newpath)
734{
735 typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
736 static T create_hard_link = NULL;
737 if (!create_hard_link) {
738 create_hard_link = (T) GetProcAddress(
739 GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
740 if (!create_hard_link)
741 create_hard_link = (T)-1;
742 }
743 if (create_hard_link == (T)-1) {
744 errno = ENOSYS;
745 return -1;
746 }
747 if (!create_hard_link(newpath, oldpath, NULL)) {
748 errno = err_win_to_posix(GetLastError());
749 return -1;
750 }
751 return 0;
752}
753
754char *realpath(const char *path, char *resolved_path)
755{
756 /* FIXME: need normalization */
757 return strcpy(resolved_path, path);
758}
759
760const char *get_busybox_exec_path(void)
761{
762 static char path[PATH_MAX] = "";
763
764 if (!*path)
765 GetModuleFileName(NULL, path, PATH_MAX);
766 return path;
767}
768
769#undef mkdir
770int mingw_mkdir(const char *path, int mode UNUSED_PARAM)
771{
772 int ret;
773 struct stat st;
774 int lerrno = 0;
775
776 if ( (ret=mkdir(path)) < 0 ) {
777 lerrno = errno;
778 if ( lerrno == EACCES && stat(path, &st) == 0 ) {
779 ret = 0;
780 lerrno = 0;
781 }
782 }
783
784 errno = lerrno;
785 return ret;
786}
787
788int fcntl(int fd, int cmd, ...)
789{
790 va_list arg;
791 int result = -1;
792 char *fds;
793 int target, i, newfd;
794
795 va_start(arg, cmd);
796
797 switch (cmd) {
798 case F_GETFD:
799 case F_SETFD:
800 case F_GETFL:
801 /*
802 * Our fake F_GETFL won't matter if the return value is used as
803 * fcntl(fd, F_SETFL, ret|something);
804 * because F_SETFL isn't supported either.
805 */
806 result = 0;
807 break;
808 case F_DUPFD:
809 target = va_arg(arg, int);
810 fds = xzalloc(target);
811 while ((newfd = dup(fd)) < target && newfd >= 0) {
812 fds[newfd] = 1;
813 }
814 for (i = 0; i < target; ++i) {
815 if (fds[i]) {
816 close(i);
817 }
818 }
819 free(fds);
820 result = newfd;
821 break;
822 default:
823 errno = ENOSYS;
824 break;
825 }
826
827 va_end(arg);
828 return result;
829}
830
831#undef unlink
832int mingw_unlink(const char *pathname)
833{
834 /* read-only files cannot be removed */
835 chmod(pathname, 0666);
836 return unlink(pathname);
837}
838
839#undef strftime
840size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm)
841{
842 size_t ret;
843 char day[3];
844 char *t;
845 char *fmt, *newfmt;
846 struct tm tm2;
847 int m;
848
849 /*
850 * Emulate the '%e' and '%s' formats that Windows' strftime lacks.
851 * Happily, the string that replaces '%e' is two characters long.
852 * '%s' is a bit more complicated.
853 */
854 fmt = xstrdup(format);
855 for ( t=fmt; *t; ++t ) {
856 if ( *t == '%' ) {
857 if ( t[1] == 'e' ) {
858 if ( tm->tm_mday >= 0 && tm->tm_mday <= 99 ) {
859 sprintf(day, "%2d", tm->tm_mday);
860 }
861 else {
862 strcpy(day, " ");
863 }
864 memcpy(t++, day, 2);
865 }
866 else if ( t[1] == 's' ) {
867 *t = '\0';
868 m = t - fmt;
869 tm2 = *tm;
870 newfmt = xasprintf("%s%d%s", fmt, (int)mktime(&tm2), t+2);
871 free(fmt);
872 t = newfmt + m + 1;
873 fmt = newfmt;
874 }
875 else if ( t[1] != '\0' ) {
876 ++t;
877 }
878 }
879 }
880
881 ret = strftime(buf, max, fmt, tm);
882 free(fmt);
883
884 return ret;
885}
886
887int stime(time_t *t UNUSED_PARAM)
888{
889 errno = EPERM;
890 return -1;
891}
892
893#undef access
894int mingw_access(const char *name, int mode)
895{
896 int ret;
897 struct stat s;
898 int fd, n, offset, sig;
899 unsigned char buf[1024];
900
901 /* Windows can only handle test for existence, read or write */
902 if (mode == F_OK || (mode & ~X_OK)) {
903 ret = _access(name, mode & ~X_OK);
904 if (ret < 0 || !(mode & X_OK)) {
905 return ret;
906 }
907 }
908
909 if (!mingw_stat(name, &s) && S_ISREG(s.st_mode)) {
910
911 /* stat marks .exe and .com files as executable */
912 if ((s.st_mode&S_IEXEC)) {
913 return 0;
914 }
915
916 fd = open(name, O_RDONLY);
917 if (fd < 0)
918 return -1;
919 n = read(fd, buf, sizeof(buf)-1);
920 close(fd);
921 if (n < 4) /* at least '#!/x' and not error */
922 return -1;
923
924 /* shell script */
925 if (buf[0] == '#' && buf[1] == '!') {
926 return 0;
927 }
928
929 /*
930 * Poke about in file to see if it's a PE binary. I've just copied
931 * the magic from the file command.
932 */
933 if (buf[0] == 'M' && buf[1] == 'Z') {
934 offset = (buf[0x19] << 8) + buf[0x18];
935 if (offset > 0x3f) {
936 offset = (buf[0x3f] << 24) + (buf[0x3e] << 16) +
937 (buf[0x3d] << 8) + buf[0x3c];
938 if (offset < sizeof(buf)-100) {
939 if (memcmp(buf+offset, "PE\0\0", 4) == 0) {
940 sig = (buf[offset+25] << 8) + buf[offset+24];
941 if (sig == 0x10b || sig == 0x20b) {
942 sig = (buf[offset+23] << 8) + buf[offset+22];
943 if ((sig & 0x2000) != 0) {
944 /* DLL */
945 return -1;
946 }
947 sig = buf[offset+92];
948 return !(sig == 1 || sig == 2 ||
949 sig == 3 || sig == 7);
950 }
951 }
952 }
953 }
954 }
955 }
956
957 return -1;
958}
959
960/* check if path can be made into an executable by adding a suffix;
961 * return an allocated string containing the path if it can;
962 * return NULL if not.
963 *
964 * if path already has a suffix don't even bother trying
965 */
966char *file_is_win32_executable(const char *p)
967{
968 char *path;
969 int len = strlen(p);
970
971 if (len > 4 && (!strcasecmp(p+len-4, ".exe") ||
972 !strcasecmp(p+len-4, ".com"))) {
973 return NULL;
974 }
975
976 if ( (path=malloc(len+5)) != NULL ) {
977 memcpy(path, p, len);
978 memcpy(path+len, ".exe", 5);
979 if (file_is_executable(path)) {
980 return path;
981 }
982 memcpy(path+len, ".com", 5);
983 if (file_is_executable(path)) {
984 return path;
985 }
986 free(path);
987 }
988
989 return NULL;
990}
diff --git a/win32/mntent.c b/win32/mntent.c
new file mode 100644
index 000000000..d39ceb4a6
--- /dev/null
+++ b/win32/mntent.c
@@ -0,0 +1,67 @@
1/*
2 * A simple WIN32 implementation of mntent routines. It only handles
3 * fixed logical drives.
4 */
5#include "libbb.h"
6
7struct mntdata {
8 DWORD flags;
9 int index;
10};
11
12FILE *setmntent(const char *file UNUSED_PARAM, const char *mode UNUSED_PARAM)
13{
14 struct mntdata *data;
15
16 if ( (data=malloc(sizeof(struct mntdata))) == NULL ) {
17 return NULL;
18 }
19
20 data->flags = GetLogicalDrives();
21 data->index = -1;
22
23 return (FILE *)data;
24}
25
26struct mntent *getmntent(FILE *stream)
27{
28 struct mntdata *data = (struct mntdata *)stream;
29 static char mnt_fsname[4];
30 static char mnt_dir[4];
31 static struct mntent my_mount_entry =
32 { mnt_fsname, mnt_dir, (char *)"", (char *)"", 0, 0 };
33 struct mntent *entry;
34 static char fsname[100];
35
36 entry = NULL;
37 while ( ++data->index < 26 ) {
38 if ( (data->flags & 1<<data->index) != 0 ) {
39 mnt_fsname[0] = 'A' + data->index;
40 mnt_fsname[1] = ':';
41 mnt_fsname[2] = '\0';
42 mnt_dir[0] = 'A' + data->index;
43 mnt_dir[1] = ':';
44 mnt_dir[2] = '\\';
45 mnt_dir[3] = '\0';
46
47 if ( GetDriveType(mnt_dir) == DRIVE_FIXED ) {
48 my_mount_entry.mnt_type = "";
49 if ( GetVolumeInformation(mnt_dir, NULL, 0, NULL, NULL,
50 NULL, fsname, 100) ) {
51 my_mount_entry.mnt_type = fsname;
52 }
53
54 entry = &my_mount_entry;
55 break;
56 }
57 }
58 }
59
60 return entry;
61}
62
63int endmntent(FILE *stream)
64{
65 free(stream);
66 return 0;
67}
diff --git a/win32/mntent.h b/win32/mntent.h
new file mode 100644
index 000000000..b035bfa9c
--- /dev/null
+++ b/win32/mntent.h
@@ -0,0 +1,19 @@
1#ifndef MNTENT_H
2#define MNTENT_H
3
4#include <stdio.h>
5
6struct mntent {
7 char *mnt_fsname; /* Device or server for filesystem. */
8 char *mnt_dir; /* Directory mounted on. */
9 char *mnt_type; /* Type of filesystem: ufs, nfs, etc. */
10 char *mnt_opts; /* Comma-separated options for fs. */
11 int mnt_freq; /* Dump frequency (in days). */
12 int mnt_passno; /* Pass number for `fsck'. */
13};
14
15extern FILE *setmntent(const char *file, const char *mode);
16extern struct mntent *getmntent(FILE *stream);
17extern int endmntent(FILE *stream);
18
19#endif
diff --git a/win32/net.c b/win32/net.c
new file mode 100644
index 000000000..eadda6b69
--- /dev/null
+++ b/win32/net.c
@@ -0,0 +1,54 @@
1#include "libbb.h"
2
3int inet_aton(const char *cp, struct in_addr *inp)
4{
5 unsigned long val = inet_addr(cp);
6
7 if (val == INADDR_NONE)
8 return 0;
9 inp->S_un.S_addr = val;
10 return 1;
11}
12
13void init_winsock(void)
14{
15 WSADATA wsa;
16 if (WSAStartup(MAKEWORD(2,2), &wsa))
17 bb_error_msg_and_die("unable to initialize winsock subsystem, error %d",
18 WSAGetLastError());
19 atexit((void(*)(void)) WSACleanup); /* may conflict with other atexit? */
20}
21
22int mingw_socket(int domain, int type, int protocol)
23{
24 int sockfd;
25 SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0);
26 if (s == INVALID_SOCKET) {
27 /*
28 * WSAGetLastError() values are regular BSD error codes
29 * biased by WSABASEERR.
30 * However, strerror() does not know about networking
31 * specific errors, which are values beginning at 38 or so.
32 * Therefore, we choose to leave the biased error code
33 * in errno so that _if_ someone looks up the code somewhere,
34 * then it is at least the number that are usually listed.
35 */
36 errno = WSAGetLastError();
37 return -1;
38 }
39 /* convert into a file descriptor */
40 if ((sockfd = _open_osfhandle(s, O_RDWR|O_BINARY)) < 0) {
41 closesocket(s);
42 bb_error_msg("unable to make a socket file descriptor: %s",
43 strerror(errno));
44 return -1;
45 }
46 return sockfd;
47}
48
49#undef connect
50int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
51{
52 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
53 return connect(s, sa, sz);
54}
diff --git a/win32/net/if.h b/win32/net/if.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/net/if.h
diff --git a/win32/netdb.h b/win32/netdb.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/netdb.h
diff --git a/win32/netinet/in.h b/win32/netinet/in.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/netinet/in.h
diff --git a/win32/paths.h b/win32/paths.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/paths.h
diff --git a/win32/poll.c b/win32/poll.c
new file mode 100644
index 000000000..403eaa7a3
--- /dev/null
+++ b/win32/poll.c
@@ -0,0 +1,606 @@
1/* Emulation for poll(2)
2 Contributed by Paolo Bonzini.
3
4 Copyright 2001-2003, 2006-2011 Free Software Foundation, Inc.
5
6 This file is part of gnulib.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation,
20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
21
22/* Tell gcc not to warn about the (nfd < 0) tests, below. */
23#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
24# pragma GCC diagnostic ignored "-Wtype-limits"
25#endif
26
27#include <malloc.h>
28
29#include <sys/types.h>
30
31/* Specification. */
32#include <poll.h>
33
34#include <errno.h>
35#include <limits.h>
36#include <assert.h>
37
38#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
39# define WIN32_NATIVE
40# if defined (_MSC_VER)
41# define _WIN32_WINNT 0x0502
42# endif
43# include <winsock2.h>
44# include <windows.h>
45# include <io.h>
46# include <stdio.h>
47# include <conio.h>
48#else
49# include <sys/time.h>
50# include <sys/socket.h>
51# include <sys/select.h>
52# include <unistd.h>
53#endif
54
55#ifdef HAVE_SYS_IOCTL_H
56# include <sys/ioctl.h>
57#endif
58#ifdef HAVE_SYS_FILIO_H
59# include <sys/filio.h>
60#endif
61
62#include <time.h>
63
64#ifndef INFTIM
65# define INFTIM (-1)
66#endif
67
68/* BeOS does not have MSG_PEEK. */
69#ifndef MSG_PEEK
70# define MSG_PEEK 0
71#endif
72
73#ifdef WIN32_NATIVE
74
75#define IsConsoleHandle(h) (((long) (h) & 3) == 3)
76
77static BOOL
78IsSocketHandle (HANDLE h)
79{
80 WSANETWORKEVENTS ev;
81
82 if (IsConsoleHandle (h))
83 return FALSE;
84
85 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
86 WSAEnumNetworkEvents instead distinguishes the two correctly. */
87 ev.lNetworkEvents = 0xDEADBEEF;
88 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
89 return ev.lNetworkEvents != 0xDEADBEEF;
90}
91
92/* Declare data structures for ntdll functions. */
93typedef struct _FILE_PIPE_LOCAL_INFORMATION {
94 ULONG NamedPipeType;
95 ULONG NamedPipeConfiguration;
96 ULONG MaximumInstances;
97 ULONG CurrentInstances;
98 ULONG InboundQuota;
99 ULONG ReadDataAvailable;
100 ULONG OutboundQuota;
101 ULONG WriteQuotaAvailable;
102 ULONG NamedPipeState;
103 ULONG NamedPipeEnd;
104} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
105
106typedef struct _IO_STATUS_BLOCK
107{
108 union {
109 DWORD Status;
110 PVOID Pointer;
111 } u;
112 ULONG_PTR Information;
113} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
114
115typedef enum _FILE_INFORMATION_CLASS {
116 FilePipeLocalInformation = 24
117} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
118
119typedef DWORD (WINAPI *PNtQueryInformationFile)
120 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
121
122# ifndef PIPE_BUF
123# define PIPE_BUF 512
124# endif
125
126/* Compute revents values for file handle H. If some events cannot happen
127 for the handle, eliminate them from *P_SOUGHT. */
128
129static int
130win32_compute_revents (HANDLE h, int *p_sought)
131{
132 int i, ret, happened;
133 INPUT_RECORD *irbuffer;
134 DWORD avail, nbuffer;
135 BOOL bRet;
136 IO_STATUS_BLOCK iosb;
137 FILE_PIPE_LOCAL_INFORMATION fpli;
138 static PNtQueryInformationFile NtQueryInformationFile;
139 static BOOL once_only;
140
141 switch (GetFileType (h))
142 {
143 case FILE_TYPE_PIPE:
144 if (!once_only)
145 {
146 NtQueryInformationFile = (PNtQueryInformationFile)
147 GetProcAddress (GetModuleHandle ("ntdll.dll"),
148 "NtQueryInformationFile");
149 once_only = TRUE;
150 }
151
152 happened = 0;
153 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
154 {
155 if (avail)
156 happened |= *p_sought & (POLLIN | POLLRDNORM);
157 }
158 else if (GetLastError () == ERROR_BROKEN_PIPE)
159 happened |= POLLHUP;
160
161 else
162 {
163 /* It was the write-end of the pipe. Check if it is writable.
164 If NtQueryInformationFile fails, optimistically assume the pipe is
165 writable. This could happen on Win9x, where NtQueryInformationFile
166 is not available, or if we inherit a pipe that doesn't permit
167 FILE_READ_ATTRIBUTES access on the write end (I think this should
168 not happen since WinXP SP2; WINE seems fine too). Otherwise,
169 ensure that enough space is available for atomic writes. */
170 memset (&iosb, 0, sizeof (iosb));
171 memset (&fpli, 0, sizeof (fpli));
172
173 if (!NtQueryInformationFile
174 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
175 FilePipeLocalInformation)
176 || fpli.WriteQuotaAvailable >= PIPE_BUF
177 || (fpli.OutboundQuota < PIPE_BUF &&
178 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
179 happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
180 }
181 return happened;
182
183 case FILE_TYPE_CHAR:
184 ret = WaitForSingleObject (h, 0);
185 if (!IsConsoleHandle (h))
186 return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
187
188 nbuffer = avail = 0;
189 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
190 if (bRet)
191 {
192 /* Input buffer. */
193 *p_sought &= POLLIN | POLLRDNORM;
194 if (nbuffer == 0)
195 return POLLHUP;
196 if (!*p_sought)
197 return 0;
198
199 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
200 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
201 if (!bRet || avail == 0)
202 return POLLHUP;
203
204 for (i = 0; i < avail; i++)
205 if (irbuffer[i].EventType == KEY_EVENT)
206 return *p_sought;
207 return 0;
208 }
209 else
210 {
211 /* Screen buffer. */
212 *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
213 return *p_sought;
214 }
215
216 default:
217 ret = WaitForSingleObject (h, 0);
218 if (ret == WAIT_OBJECT_0)
219 return *p_sought & ~(POLLPRI | POLLRDBAND);
220
221 return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
222 }
223}
224
225/* Convert fd_sets returned by select into revents values. */
226
227static int
228win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
229{
230 int happened = 0;
231
232 if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
233 happened |= (POLLIN | POLLRDNORM) & sought;
234
235 else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
236 {
237 int r, error;
238
239 char data[64];
240 WSASetLastError (0);
241 r = recv (h, data, sizeof (data), MSG_PEEK);
242 error = WSAGetLastError ();
243 WSASetLastError (0);
244
245 if (r > 0 || error == WSAENOTCONN)
246 happened |= (POLLIN | POLLRDNORM) & sought;
247
248 /* Distinguish hung-up sockets from other errors. */
249 else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
250 || error == WSAECONNABORTED || error == WSAENETRESET)
251 happened |= POLLHUP;
252
253 else
254 happened |= POLLERR;
255 }
256
257 if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
258 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
259
260 if (lNetworkEvents & FD_OOB)
261 happened |= (POLLPRI | POLLRDBAND) & sought;
262
263 return happened;
264}
265
266#else /* !MinGW */
267
268/* Convert select(2) returned fd_sets into poll(2) revents values. */
269static int
270compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
271{
272 int happened = 0;
273 if (FD_ISSET (fd, rfds))
274 {
275 int r;
276 int socket_errno;
277
278# if defined __MACH__ && defined __APPLE__
279 /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
280 for some kinds of descriptors. Detect if this descriptor is a
281 connected socket, a server socket, or something else using a
282 0-byte recv, and use ioctl(2) to detect POLLHUP. */
283 r = recv (fd, NULL, 0, MSG_PEEK);
284 socket_errno = (r < 0) ? errno : 0;
285 if (r == 0 || socket_errno == ENOTSOCK)
286 ioctl (fd, FIONREAD, &r);
287# else
288 char data[64];
289 r = recv (fd, data, sizeof (data), MSG_PEEK);
290 socket_errno = (r < 0) ? errno : 0;
291# endif
292 if (r == 0)
293 happened |= POLLHUP;
294
295 /* If the event happened on an unconnected server socket,
296 that's fine. */
297 else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
298 happened |= (POLLIN | POLLRDNORM) & sought;
299
300 /* Distinguish hung-up sockets from other errors. */
301 else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
302 || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
303 happened |= POLLHUP;
304
305 else
306 happened |= POLLERR;
307 }
308
309 if (FD_ISSET (fd, wfds))
310 happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
311
312 if (FD_ISSET (fd, efds))
313 happened |= (POLLPRI | POLLRDBAND) & sought;
314
315 return happened;
316}
317#endif /* !MinGW */
318
319int
320poll (struct pollfd *pfd, nfds_t nfd, int timeout)
321{
322#ifndef WIN32_NATIVE
323 fd_set rfds, wfds, efds;
324 struct timeval tv;
325 struct timeval *ptv;
326 int maxfd, rc;
327 nfds_t i;
328
329# ifdef _SC_OPEN_MAX
330 static int sc_open_max = -1;
331
332 if (nfd < 0
333 || (nfd > sc_open_max
334 && (sc_open_max != -1
335 || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
336 {
337 errno = EINVAL;
338 return -1;
339 }
340# else /* !_SC_OPEN_MAX */
341# ifdef OPEN_MAX
342 if (nfd < 0 || nfd > OPEN_MAX)
343 {
344 errno = EINVAL;
345 return -1;
346 }
347# endif /* OPEN_MAX -- else, no check is needed */
348# endif /* !_SC_OPEN_MAX */
349
350 /* EFAULT is not necessary to implement, but let's do it in the
351 simplest case. */
352 if (!pfd)
353 {
354 errno = EFAULT;
355 return -1;
356 }
357
358 /* convert timeout number into a timeval structure */
359 if (timeout == 0)
360 {
361 ptv = &tv;
362 ptv->tv_sec = 0;
363 ptv->tv_usec = 0;
364 }
365 else if (timeout > 0)
366 {
367 ptv = &tv;
368 ptv->tv_sec = timeout / 1000;
369 ptv->tv_usec = (timeout % 1000) * 1000;
370 }
371 else if (timeout == INFTIM)
372 /* wait forever */
373 ptv = NULL;
374 else
375 {
376 errno = EINVAL;
377 return -1;
378 }
379
380 /* create fd sets and determine max fd */
381 maxfd = -1;
382 FD_ZERO (&rfds);
383 FD_ZERO (&wfds);
384 FD_ZERO (&efds);
385 for (i = 0; i < nfd; i++)
386 {
387 if (pfd[i].fd < 0)
388 continue;
389
390 if (pfd[i].events & (POLLIN | POLLRDNORM))
391 FD_SET (pfd[i].fd, &rfds);
392
393 /* see select(2): "the only exceptional condition detectable
394 is out-of-band data received on a socket", hence we push
395 POLLWRBAND events onto wfds instead of efds. */
396 if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
397 FD_SET (pfd[i].fd, &wfds);
398 if (pfd[i].events & (POLLPRI | POLLRDBAND))
399 FD_SET (pfd[i].fd, &efds);
400 if (pfd[i].fd >= maxfd
401 && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
402 | POLLRDNORM | POLLRDBAND
403 | POLLWRNORM | POLLWRBAND)))
404 {
405 maxfd = pfd[i].fd;
406 if (maxfd > FD_SETSIZE)
407 {
408 errno = EOVERFLOW;
409 return -1;
410 }
411 }
412 }
413
414 /* examine fd sets */
415 rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
416 if (rc < 0)
417 return rc;
418
419 /* establish results */
420 rc = 0;
421 for (i = 0; i < nfd; i++)
422 if (pfd[i].fd < 0)
423 pfd[i].revents = 0;
424 else
425 {
426 int happened = compute_revents (pfd[i].fd, pfd[i].events,
427 &rfds, &wfds, &efds);
428 if (happened)
429 {
430 pfd[i].revents = happened;
431 rc++;
432 }
433 }
434
435 return rc;
436#else
437 static struct timeval tv0;
438 static HANDLE hEvent;
439 WSANETWORKEVENTS ev;
440 HANDLE h, handle_array[FD_SETSIZE + 2];
441 DWORD ret, wait_timeout, nhandles;
442 fd_set rfds, wfds, xfds;
443 BOOL poll_again;
444 MSG msg;
445 int rc = 0;
446 nfds_t i;
447
448 if (nfd < 0 || timeout < -1)
449 {
450 errno = EINVAL;
451 return -1;
452 }
453
454 if (!hEvent)
455 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
456
457restart:
458 handle_array[0] = hEvent;
459 nhandles = 1;
460 FD_ZERO (&rfds);
461 FD_ZERO (&wfds);
462 FD_ZERO (&xfds);
463
464 /* Classify socket handles and create fd sets. */
465 for (i = 0; i < nfd; i++)
466 {
467 int sought = pfd[i].events;
468 pfd[i].revents = 0;
469 if (pfd[i].fd < 0)
470 continue;
471 if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
472 | POLLPRI | POLLRDBAND)))
473 continue;
474
475 h = (HANDLE) _get_osfhandle (pfd[i].fd);
476 assert (h != NULL);
477 if (IsSocketHandle (h))
478 {
479 int requested = FD_CLOSE;
480
481 /* see above; socket handles are mapped onto select. */
482 if (sought & (POLLIN | POLLRDNORM))
483 {
484 requested |= FD_READ | FD_ACCEPT;
485 FD_SET ((SOCKET) h, &rfds);
486 }
487 if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
488 {
489 requested |= FD_WRITE | FD_CONNECT;
490 FD_SET ((SOCKET) h, &wfds);
491 }
492 if (sought & (POLLPRI | POLLRDBAND))
493 {
494 requested |= FD_OOB;
495 FD_SET ((SOCKET) h, &xfds);
496 }
497
498 if (requested)
499 WSAEventSelect ((SOCKET) h, hEvent, requested);
500 }
501 else
502 {
503 /* Poll now. If we get an event, do not poll again. Also,
504 screen buffer handles are waitable, and they'll block until
505 a character is available. win32_compute_revents eliminates
506 bits for the "wrong" direction. */
507 pfd[i].revents = win32_compute_revents (h, &sought);
508 if (sought)
509 handle_array[nhandles++] = h;
510 if (pfd[i].revents)
511 timeout = 0;
512 }
513 }
514
515 if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
516 {
517 /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
518 no need to call select again. */
519 poll_again = FALSE;
520 wait_timeout = 0;
521 }
522 else
523 {
524 poll_again = TRUE;
525 if (timeout == INFTIM)
526 wait_timeout = INFINITE;
527 else
528 wait_timeout = timeout;
529 }
530
531 for (;;)
532 {
533 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
534 wait_timeout, QS_ALLINPUT);
535
536 if (ret == WAIT_OBJECT_0 + nhandles)
537 {
538 /* new input of some other kind */
539 BOOL bRet;
540 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
541 {
542 TranslateMessage (&msg);
543 DispatchMessage (&msg);
544 }
545 }
546 else
547 break;
548 }
549
550 if (poll_again)
551 select (0, &rfds, &wfds, &xfds, &tv0);
552
553 /* Place a sentinel at the end of the array. */
554 handle_array[nhandles] = NULL;
555 nhandles = 1;
556 for (i = 0; i < nfd; i++)
557 {
558 int happened;
559
560 if (pfd[i].fd < 0)
561 continue;
562 if (!(pfd[i].events & (POLLIN | POLLRDNORM |
563 POLLOUT | POLLWRNORM | POLLWRBAND)))
564 continue;
565
566 h = (HANDLE) _get_osfhandle (pfd[i].fd);
567 if (h != handle_array[nhandles])
568 {
569 /* It's a socket. */
570 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
571 WSAEventSelect ((SOCKET) h, 0, 0);
572
573 /* If we're lucky, WSAEnumNetworkEvents already provided a way
574 to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */
575 if (FD_ISSET ((SOCKET) h, &rfds)
576 && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
577 ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
578 if (FD_ISSET ((SOCKET) h, &wfds))
579 ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
580 if (FD_ISSET ((SOCKET) h, &xfds))
581 ev.lNetworkEvents |= FD_OOB;
582
583 happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
584 ev.lNetworkEvents);
585 }
586 else
587 {
588 /* Not a socket. */
589 int sought = pfd[i].events;
590 happened = win32_compute_revents (h, &sought);
591 nhandles++;
592 }
593
594 if ((pfd[i].revents |= happened) != 0)
595 rc++;
596 }
597
598 if (!rc && timeout == INFTIM)
599 {
600 SwitchToThread();
601 goto restart;
602 }
603
604 return rc;
605#endif
606}
diff --git a/win32/poll.h b/win32/poll.h
new file mode 100644
index 000000000..b7aa59d97
--- /dev/null
+++ b/win32/poll.h
@@ -0,0 +1,53 @@
1/* Header for poll(2) emulation
2 Contributed by Paolo Bonzini.
3
4 Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.
5
6 This file is part of gnulib.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation,
20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
21
22#ifndef _GL_POLL_H
23#define _GL_POLL_H
24
25/* fake a poll(2) environment */
26#define POLLIN 0x0001 /* any readable data available */
27#define POLLPRI 0x0002 /* OOB/Urgent readable data */
28#define POLLOUT 0x0004 /* file descriptor is writeable */
29#define POLLERR 0x0008 /* some poll error occurred */
30#define POLLHUP 0x0010 /* file descriptor was "hung up" */
31#define POLLNVAL 0x0020 /* requested events "invalid" */
32#define POLLRDNORM 0x0040
33#define POLLRDBAND 0x0080
34#define POLLWRNORM 0x0100
35#define POLLWRBAND 0x0200
36
37struct pollfd
38{
39 int fd; /* which file descriptor to poll */
40 short events; /* events we are interested in */
41 short revents; /* events found on return */
42};
43
44typedef unsigned long nfds_t;
45
46extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);
47
48/* Define INFTIM only if doing so conforms to POSIX. */
49#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)
50#define INFTIM (-1)
51#endif
52
53#endif /* _GL_POLL_H */
diff --git a/win32/popen.c b/win32/popen.c
new file mode 100644
index 000000000..a7b2c7ec9
--- /dev/null
+++ b/win32/popen.c
@@ -0,0 +1,208 @@
1#include <fcntl.h>
2#include "libbb.h"
3
4typedef struct {
5 PROCESS_INFORMATION piProcInfo;
6 HANDLE pipe[2];
7 char mode;
8 int fd;
9} pipe_data;
10
11static pipe_data *pipes = NULL;
12static int num_pipes = 0;
13
14static int mingw_pipe(HANDLE *readwrite)
15{
16 SECURITY_ATTRIBUTES sa;
17
18 sa.nLength = sizeof(sa); /* Length in bytes */
19 sa.bInheritHandle = 1; /* the child must inherit these handles */
20 sa.lpSecurityDescriptor = NULL;
21
22 if ( !CreatePipe (&readwrite[0], &readwrite[1], &sa, 1 << 13) ) {
23 return -1;
24 }
25
26 return 0;
27}
28
29FILE *mingw_popen(const char *cmd, const char *mode)
30{
31 int i;
32 pipe_data *p = NULL;
33 FILE *fptr = NULL;
34 STARTUPINFO siStartInfo;
35 int success;
36 int fd;
37 int len, count;
38 int ip, ic;
39 char *cmd_buff = NULL;
40 const char *s;
41 char *t;
42
43 if ( cmd == NULL || *cmd == '\0' || mode == NULL ||
44 (*mode != 'r' && *mode != 'w') ) {
45 return NULL;
46 }
47
48 /* find an unused pipe structure */
49 for ( i=0; i<num_pipes; ++i ) {
50 if ( pipes[i].mode == '\0' ) {
51 p = pipes+i;
52 break;
53 }
54 }
55
56 if ( p == NULL ) {
57 /* need to extend array */
58 if ( (p=realloc(pipes, sizeof(pipe_data)*(num_pipes+10))) == NULL ) {
59 return NULL;
60 }
61
62 pipes = p;
63 for ( i=0; i<10; ++i ) {
64 memset(pipes+num_pipes+i, 0, sizeof(pipe_data));
65 }
66 p = pipes + num_pipes;
67 num_pipes += 10;
68 }
69
70 /* count double quotes */
71 count = 0;
72 for ( s=cmd; *s; ++s ) {
73 if ( *s == '"' ) {
74 ++count;
75 }
76 }
77
78 len = strlen(cmd) + 10 + count;
79 if ( (cmd_buff=malloc(len)) == NULL ) {
80 return NULL;
81 }
82
83 /* escape double quotes */
84 strcpy(cmd_buff, "sh -c \"");
85 for ( s=cmd,t=cmd_buff+strlen(cmd_buff); *s; ++s ) {
86 if ( *s == '"' ) {
87 *t++ = '\\';
88 }
89 *t++ = *s;
90 }
91 *t++ = '"';
92 *t = '\0';
93
94 p->pipe[0] = INVALID_HANDLE_VALUE;
95 p->pipe[1] = INVALID_HANDLE_VALUE;
96
97 /* Create the pipe */
98 if ( mingw_pipe(p->pipe) == -1 ) {
99 goto finito;
100 }
101
102 /* index of parent end of pipe */
103 ip = !(*mode == 'r');
104 /* index of child end of pipe */
105 ic = (*mode == 'r');
106
107 /* Make the parent end of the pipe non-inheritable */
108 SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0);
109
110 /* Now create the child process */
111 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
112 siStartInfo.cb = sizeof(STARTUPINFO);
113 if ( *mode == 'r' ) {
114 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
115 siStartInfo.hStdOutput = p->pipe[ic];
116 }
117 else {
118 siStartInfo.hStdInput = p->pipe[ic];
119 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
120 }
121 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
122 siStartInfo.wShowWindow = SW_HIDE;
123 siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
124
125 success = CreateProcess(NULL,
126 (LPTSTR)cmd_buff, /* command line */
127 NULL, /* process security attributes */
128 NULL, /* primary thread security attributes */
129 TRUE, /* handles are inherited */
130 0, /* creation flags */
131 NULL, /* use parent's environment */
132 NULL, /* use parent's current directory */
133 &siStartInfo, /* STARTUPINFO pointer */
134 &p->piProcInfo); /* receives PROCESS_INFORMATION */
135
136 if ( !success ) {
137 goto finito;
138 }
139
140 /* close child end of pipe */
141 CloseHandle(p->pipe[ic]);
142 p->pipe[ic] = INVALID_HANDLE_VALUE;
143
144 if ( *mode == 'r' ) {
145 fd = _open_osfhandle((long)p->pipe[ip], _O_RDONLY|_O_BINARY);
146 fptr = _fdopen(fd, "rb");
147 }
148 else {
149 fd = _open_osfhandle((long)p->pipe[ip], _O_WRONLY|_O_BINARY);
150 fptr = _fdopen(fd, "wb");
151 }
152
153finito:
154 if ( !fptr ) {
155 if ( p->pipe[0] != INVALID_HANDLE_VALUE ) {
156 CloseHandle(p->pipe[0]);
157 }
158 if ( p->pipe[1] != INVALID_HANDLE_VALUE ) {
159 CloseHandle(p->pipe[1]);
160 }
161 }
162 else {
163 p->mode = *mode;
164 p->fd = fd;
165 }
166 free(cmd_buff);
167
168 return fptr;
169}
170
171int mingw_pclose(FILE *fp)
172{
173 int i, ip, fd;
174 pipe_data *p = NULL;
175 DWORD ret;
176
177 if ( fp == NULL ) {
178 return -1;
179 }
180
181 /* find struct containing fd */
182 fd = fileno(fp);
183 for ( i=0; i<num_pipes; ++i ) {
184 if ( pipes[i].mode && pipes[i].fd == fd ) {
185 p = pipes+i;
186 break;
187 }
188 }
189
190 if ( p == NULL ) {
191 /* no pipe data, maybe fd isn't a pipe? */
192 return -1;
193 }
194
195 fclose(fp);
196
197 ip = !(p->mode == 'r');
198 CloseHandle(p->pipe[ip]);
199
200 ret = WaitForSingleObject(p->piProcInfo.hProcess, INFINITE);
201
202 CloseHandle(p->piProcInfo.hProcess);
203 CloseHandle(p->piProcInfo.hThread);
204
205 p->mode = '\0';
206
207 return (ret == WAIT_OBJECT_0) ? 0 : -1;
208}
diff --git a/win32/process.c b/win32/process.c
new file mode 100644
index 000000000..462731a2d
--- /dev/null
+++ b/win32/process.c
@@ -0,0 +1,381 @@
1#include "libbb.h"
2#include <tlhelp32.h>
3
4int waitpid(pid_t pid, int *status, unsigned options)
5{
6 /* Windows does not understand parent-child */
7 if (options == 0 && pid != -1)
8 return _cwait(status, pid, 0);
9 errno = EINVAL;
10 return -1;
11}
12
13const char *
14next_path_sep(const char *path)
15{
16 static const char *from = NULL, *to;
17 static int has_semicolon;
18 int len = strlen(path);
19
20 if (!from || !(path >= from && path+len <= to)) {
21 from = path;
22 to = from+len;
23 has_semicolon = strchr(path, ';') != NULL;
24 }
25
26 /* Semicolons take precedence, it's Windows PATH */
27 if (has_semicolon)
28 return strchr(path, ';');
29 /* PATH=C:, not really a separator */
30 return strchr(has_dos_drive_prefix(path) ? path+2 : path, ':');
31}
32
33#define MAX_OPT 10
34
35static const char *
36parse_interpreter(const char *cmd, char ***opts, int *nopts)
37{
38 static char buf[100], *opt[MAX_OPT];
39 char *p, *s, *t;
40 int n, fd;
41
42 *nopts = 0;
43 *opts = opt;
44
45 /* don't even try a .exe */
46 n = strlen(cmd);
47 if (n >= 4 &&
48 (!strcasecmp(cmd+n-4, ".exe") ||
49 !strcasecmp(cmd+n-4, ".com")))
50 return NULL;
51
52 fd = open(cmd, O_RDONLY);
53 if (fd < 0)
54 return NULL;
55 n = read(fd, buf, sizeof(buf)-1);
56 close(fd);
57 if (n < 4) /* at least '#!/x' and not error */
58 return NULL;
59
60 /*
61 * See http://www.in-ulm.de/~mascheck/various/shebang/ for trivia
62 * relating to '#!'.
63 */
64 if (buf[0] != '#' || buf[1] != '!')
65 return NULL;
66 buf[n] = '\0';
67 p = strchr(buf, '\n');
68 if (!p)
69 return NULL;
70 *p = '\0';
71
72 /* remove trailing whitespace */
73 while ( isspace(*--p) ) {
74 *p = '\0';
75 }
76
77 /* skip whitespace after '#!' */
78 for ( s=buf+2; *s && isspace(*s); ++s ) {
79 }
80
81 /* move to end of interpreter path (which may not contain spaces) */
82 for ( ; *s && !isspace(*s); ++s ) {
83 }
84
85 n = 0;
86 if ( *s != '\0' ) {
87 /* there are options */
88 *s++ = '\0';
89
90 while ( (t=strtok(s, " \t")) && n < MAX_OPT ) {
91 s = NULL;
92 opt[n++] = t;
93 }
94 }
95
96 /* find interpreter name */
97 if (!(p = strrchr(buf+2, '/')))
98 return NULL;
99
100 *nopts = n;
101 *opts = opt;
102
103 return p+1;
104}
105
106/*
107 * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
108 * (Parsing C++ Command-Line Arguments)
109 */
110static char *
111quote_arg(const char *arg)
112{
113 /* count chars to quote */
114 int len = 0, n = 0;
115 int force_quotes = 0;
116 char *q, *d;
117 const char *p = arg;
118 if (!*p) force_quotes = 1;
119 while (*p) {
120 if (isspace(*p))
121 force_quotes = 1;
122 else if (*p == '"')
123 n++;
124 else if (*p == '\\') {
125 int count = 0;
126 while (*p == '\\') {
127 count++;
128 p++;
129 len++;
130 }
131 if (*p == '"')
132 n += count*2 + 1;
133 continue;
134 }
135 len++;
136 p++;
137 }
138 if (!force_quotes && n == 0)
139 return (char*)arg;
140
141 /* insert \ where necessary */
142 d = q = xmalloc(len+n+3);
143 if (force_quotes)
144 *d++ = '"';
145 while (*arg) {
146 if (*arg == '"')
147 *d++ = '\\';
148 else if (*arg == '\\') {
149 int count = 0;
150 while (*arg == '\\') {
151 count++;
152 *d++ = *arg++;
153 }
154 if (*arg == '"') {
155 while (count-- > 0)
156 *d++ = '\\';
157 *d++ = '\\';
158 }
159 }
160 *d++ = *arg++;
161 }
162 if (force_quotes)
163 *d++ = '"';
164 *d++ = 0;
165 return q;
166}
167
168static pid_t
169spawnveq(int mode, const char *path, const char *const *argv, const char *const *env)
170{
171 char **new_argv;
172 int i, argc = 0;
173 pid_t ret;
174
175 if (!argv) {
176 const char *empty_argv[] = { path, NULL };
177 return spawnve(mode, path, empty_argv, env);
178 }
179
180
181 while (argv[argc])
182 argc++;
183
184 new_argv = malloc(sizeof(*argv)*(argc+1));
185 for (i = 0;i < argc;i++)
186 new_argv[i] = quote_arg(argv[i]);
187 new_argv[argc] = NULL;
188 ret = spawnve(mode, path, (const char *const *)new_argv, env);
189 for (i = 0;i < argc;i++)
190 if (new_argv[i] != argv[i])
191 free(new_argv[i]);
192 free(new_argv);
193 return ret;
194}
195
196pid_t
197mingw_spawn_applet(int mode,
198 const char *applet,
199 const char *const *argv,
200 const char *const *envp)
201{
202 char **env = copy_environ(envp);
203 char path[MAX_PATH+20];
204 int ret;
205
206 sprintf(path, "BUSYBOX_APPLET_NAME=%s", applet);
207 env = env_setenv(env, path);
208 ret = spawnveq(mode, get_busybox_exec_path(), argv, (const char *const *)env);
209 free_environ(env);
210 return ret;
211}
212
213static pid_t
214mingw_spawn_interpreter(int mode, const char *prog, const char *const *argv, const char *const *envp)
215{
216 int ret;
217 char **opts;
218 int nopts;
219 const char *interpr = parse_interpreter(prog, &opts, &nopts);
220 const char **new_argv;
221 int argc = 0;
222
223 if (!interpr)
224 return spawnveq(mode, prog, argv, envp);
225
226
227 while (argv[argc])
228 argc++;
229 new_argv = malloc(sizeof(*argv)*(argc+nopts+2));
230 memcpy(new_argv+1, opts, sizeof(*opts)*nopts);
231 memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc);
232 new_argv[nopts+1] = prog; /* pass absolute path */
233
234 if (ENABLE_FEATURE_PREFER_APPLETS && find_applet_by_name(interpr) >= 0) {
235 new_argv[0] = interpr;
236 ret = mingw_spawn_applet(mode, interpr, new_argv, envp);
237 }
238 else {
239 char *path = xstrdup(getenv("PATH"));
240 char *tmp = path;
241 char *iprog = find_executable(interpr, &tmp);
242 free(path);
243 if (!iprog) {
244 free(new_argv);
245 errno = ENOENT;
246 return -1;
247 }
248 new_argv[0] = iprog;
249 ret = spawnveq(mode, iprog, new_argv, envp);
250 free(iprog);
251 }
252
253 free(new_argv);
254 return ret;
255}
256
257pid_t
258mingw_spawn_1(int mode, const char *cmd, const char *const *argv, const char *const *envp)
259{
260 int ret;
261
262 if (ENABLE_FEATURE_PREFER_APPLETS &&
263 find_applet_by_name(cmd) >= 0)
264 return mingw_spawn_applet(mode, cmd, argv, envp);
265 else if (is_absolute_path(cmd))
266 return mingw_spawn_interpreter(mode, cmd, argv, envp);
267 else {
268 char *tmp, *path = getenv("PATH");
269 char *prog;
270
271 if (!path) {
272 errno = ENOENT;
273 return -1;
274 }
275
276 /* executable_exists() does not return new file name */
277 tmp = path = xstrdup(path);
278 prog = find_executable(cmd, &tmp);
279 free(path);
280 if (!prog) {
281 errno = ENOENT;
282 return -1;
283 }
284 ret = mingw_spawn_interpreter(mode, prog, argv, envp);
285 free(prog);
286 }
287 return ret;
288}
289
290pid_t
291mingw_spawn(char **argv)
292{
293 return mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)argv, (const char *const *)environ);
294}
295
296int
297mingw_execvp(const char *cmd, const char *const *argv)
298{
299 int ret = (int)mingw_spawn_1(P_WAIT, cmd, argv, (const char *const *)environ);
300 if (ret != -1)
301 exit(ret);
302 return ret;
303}
304
305int
306mingw_execve(const char *cmd, const char *const *argv, const char *const *envp)
307{
308 int ret;
309 int mode = P_WAIT;
310
311 if (ENABLE_FEATURE_PREFER_APPLETS &&
312 find_applet_by_name(cmd) >= 0)
313 ret = mingw_spawn_applet(mode, cmd, argv, envp);
314 /*
315 * execve(bb_busybox_exec_path, argv, envp) won't work
316 * because argv[0] will be replaced to bb_busybox_exec_path
317 * by MSVC runtime
318 */
319 else if (argv && cmd != argv[0] && cmd == bb_busybox_exec_path)
320 ret = mingw_spawn_applet(mode, argv[0], argv, envp);
321 else
322 ret = mingw_spawn_interpreter(mode, cmd, argv, envp);
323 if (ret != -1)
324 exit(ret);
325 return ret;
326}
327
328int
329mingw_execv(const char *cmd, const char *const *argv)
330{
331 return mingw_execve(cmd, argv, (const char *const *)environ);
332}
333
334/* POSIX version in libbb/procps.c */
335procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags UNUSED_PARAM)
336{
337 PROCESSENTRY32 pe;
338
339 pe.dwSize = sizeof(pe);
340 if (!sp) {
341 sp = xzalloc(sizeof(struct procps_status_t));
342 sp->snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
343 if (sp->snapshot == INVALID_HANDLE_VALUE) {
344 free(sp);
345 return NULL;
346 }
347 if (!Process32First(sp->snapshot, &pe)) {
348 CloseHandle(sp->snapshot);
349 free(sp);
350 return NULL;
351 }
352 }
353 else {
354 if (!Process32Next(sp->snapshot, &pe)) {
355 CloseHandle(sp->snapshot);
356 free(sp);
357 return NULL;
358 }
359 }
360
361 sp->pid = pe.th32ProcessID;
362 safe_strncpy(sp->comm, pe.szExeFile, COMM_LEN);
363 return sp;
364}
365
366int kill(pid_t pid, int sig)
367{
368 HANDLE h;
369
370 if (sig != SIGTERM) {
371 bb_error_msg("kill only supports SIGTERM");
372 errno = EINVAL;
373 return -1;
374 }
375 h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
376 if (h == NULL)
377 return -1;
378 if (TerminateProcess(h, 0) == 0)
379 return -1;
380 return 0;
381}
diff --git a/win32/pwd.h b/win32/pwd.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/pwd.h
diff --git a/win32/regex.c b/win32/regex.c
new file mode 100644
index 000000000..2cca16934
--- /dev/null
+++ b/win32/regex.c
@@ -0,0 +1,4929 @@
1/* Extended regular expression matching and search library,
2 version 0.12.
3 (Implements POSIX draft P10003.2/D11.2, except for
4 internationalization features.)
5
6 Copyright (C) 1993 Free Software Foundation, Inc.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22/* AIX requires this to be the first thing in the file. */
23#if defined (_AIX) && !defined (REGEX_MALLOC)
24 #pragma alloca
25#endif
26
27#ifndef _GNU_SOURCE
28#define _GNU_SOURCE
29#endif
30
31/* We need this for `regex.h', and perhaps for the Emacs include files. */
32#include <sys/types.h>
33
34/* We used to test for `BSTRING' here, but only GCC and Emacs define
35 `BSTRING', as far as I know, and neither of them use this code. */
36#include <string.h>
37#ifndef bcmp
38#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
39#endif
40#ifndef bcopy
41#define bcopy(s, d, n) memcpy ((d), (s), (n))
42#endif
43#ifndef bzero
44#define bzero(s, n) memset ((s), 0, (n))
45#endif
46
47#include <stdlib.h>
48
49
50/* Define the syntax stuff for \<, \>, etc. */
51
52/* This must be nonzero for the wordchar and notwordchar pattern
53 commands in re_match_2. */
54#ifndef Sword
55#define Sword 1
56#endif
57
58#ifdef SYNTAX_TABLE
59
60extern char *re_syntax_table;
61
62#else /* not SYNTAX_TABLE */
63
64/* How many characters in the character set. */
65#define CHAR_SET_SIZE 256
66
67static char re_syntax_table[CHAR_SET_SIZE];
68
69static void
70init_syntax_once ()
71{
72 register int c;
73 static int done = 0;
74
75 if (done)
76 return;
77
78 bzero (re_syntax_table, sizeof re_syntax_table);
79
80 for (c = 'a'; c <= 'z'; c++)
81 re_syntax_table[c] = Sword;
82
83 for (c = 'A'; c <= 'Z'; c++)
84 re_syntax_table[c] = Sword;
85
86 for (c = '0'; c <= '9'; c++)
87 re_syntax_table[c] = Sword;
88
89 re_syntax_table['_'] = Sword;
90
91 done = 1;
92}
93
94#endif /* not SYNTAX_TABLE */
95
96#define SYNTAX(c) re_syntax_table[c]
97
98
99/* Get the interface, including the syntax bits. */
100#include "regex.h"
101
102/* isalpha etc. are used for the character classes. */
103#include <ctype.h>
104
105#ifndef isascii
106#define isascii(c) 1
107#endif
108
109#ifdef isblank
110#define ISBLANK(c) (isascii (c) && isblank (c))
111#else
112#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
113#endif
114#ifdef isgraph
115#define ISGRAPH(c) (isascii (c) && isgraph (c))
116#else
117#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c))
118#endif
119
120#define ISPRINT(c) (isascii (c) && isprint (c))
121#define ISDIGIT(c) (isascii (c) && isdigit (c))
122#define ISALNUM(c) (isascii (c) && isalnum (c))
123#define ISALPHA(c) (isascii (c) && isalpha (c))
124#define ISCNTRL(c) (isascii (c) && iscntrl (c))
125#define ISLOWER(c) (isascii (c) && islower (c))
126#define ISPUNCT(c) (isascii (c) && ispunct (c))
127#define ISSPACE(c) (isascii (c) && isspace (c))
128#define ISUPPER(c) (isascii (c) && isupper (c))
129#define ISXDIGIT(c) (isascii (c) && isxdigit (c))
130
131#ifndef NULL
132#define NULL 0
133#endif
134
135/* We remove any previous definition of `SIGN_EXTEND_CHAR',
136 since ours (we hope) works properly with all combinations of
137 machines, compilers, `char' and `unsigned char' argument types.
138 (Per Bothner suggested the basic approach.) */
139#undef SIGN_EXTEND_CHAR
140#if __STDC__
141#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
142#else /* not __STDC__ */
143/* As in Harbison and Steele. */
144#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
145#endif
146
147/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
148 use `alloca' instead of `malloc'. This is because using malloc in
149 re_search* or re_match* could cause memory leaks when C-g is used in
150 Emacs; also, malloc is slower and causes storage fragmentation. On
151 the other hand, malloc is more portable, and easier to debug.
152
153 Because we sometimes use alloca, some routines have to be macros,
154 not functions -- `alloca'-allocated space disappears at the end of the
155 function it is called in. */
156
157#ifdef REGEX_MALLOC
158
159#define REGEX_ALLOCATE malloc
160#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
161
162#else /* not REGEX_MALLOC */
163
164/* Emacs already defines alloca, sometimes. */
165#ifndef alloca
166
167/* Make alloca work the best possible way. */
168#ifdef __GNUC__
169#define alloca __builtin_alloca
170#else /* not __GNUC__ */
171#if HAVE_ALLOCA_H
172#include <alloca.h>
173#else /* not __GNUC__ or HAVE_ALLOCA_H */
174#ifndef _AIX /* Already did AIX, up at the top. */
175char *alloca ();
176#endif /* not _AIX */
177#endif /* not HAVE_ALLOCA_H */
178#endif /* not __GNUC__ */
179
180#endif /* not alloca */
181
182#define REGEX_ALLOCATE alloca
183
184/* Assumes a `char *destination' variable. */
185#define REGEX_REALLOCATE(source, osize, nsize) \
186 (destination = (char *) alloca (nsize), \
187 bcopy (source, destination, osize), \
188 destination)
189
190#endif /* not REGEX_MALLOC */
191
192
193/* True if `size1' is non-NULL and PTR is pointing anywhere inside
194 `string1' or just past its end. This works if PTR is NULL, which is
195 a good thing. */
196#define FIRST_STRING_P(ptr) \
197 (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
198
199/* (Re)Allocate N items of type T using malloc, or fail. */
200#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
201#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
202#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
203
204#define BYTEWIDTH 8 /* In bits. */
205
206#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
207
208#define MAX(a, b) ((a) > (b) ? (a) : (b))
209#define MIN(a, b) ((a) < (b) ? (a) : (b))
210
211typedef char boolean;
212#define false 0
213#define true 1
214
215/* These are the command codes that appear in compiled regular
216 expressions. Some opcodes are followed by argument bytes. A
217 command code can specify any interpretation whatsoever for its
218 arguments. Zero bytes may appear in the compiled regular expression.
219
220 The value of `exactn' is needed in search.c (search_buffer) in Emacs.
221 So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of
222 `exactn' we use here must also be 1. */
223
224typedef enum
225{
226 no_op = 0,
227
228 /* Followed by one byte giving n, then by n literal bytes. */
229 exactn = 1,
230
231 /* Matches any (more or less) character. */
232 anychar,
233
234 /* Matches any one char belonging to specified set. First
235 following byte is number of bitmap bytes. Then come bytes
236 for a bitmap saying which chars are in. Bits in each byte
237 are ordered low-bit-first. A character is in the set if its
238 bit is 1. A character too large to have a bit in the map is
239 automatically not in the set. */
240 charset,
241
242 /* Same parameters as charset, but match any character that is
243 not one of those specified. */
244 charset_not,
245
246 /* Start remembering the text that is matched, for storing in a
247 register. Followed by one byte with the register number, in
248 the range 0 to one less than the pattern buffer's re_nsub
249 field. Then followed by one byte with the number of groups
250 inner to this one. (This last has to be part of the
251 start_memory only because we need it in the on_failure_jump
252 of re_match_2.) */
253 start_memory,
254
255 /* Stop remembering the text that is matched and store it in a
256 memory register. Followed by one byte with the register
257 number, in the range 0 to one less than `re_nsub' in the
258 pattern buffer, and one byte with the number of inner groups,
259 just like `start_memory'. (We need the number of inner
260 groups here because we don't have any easy way of finding the
261 corresponding start_memory when we're at a stop_memory.) */
262 stop_memory,
263
264 /* Match a duplicate of something remembered. Followed by one
265 byte containing the register number. */
266 duplicate,
267
268 /* Fail unless at beginning of line. */
269 begline,
270
271 /* Fail unless at end of line. */
272 endline,
273
274 /* Succeeds if at beginning of buffer (if emacs) or at beginning
275 of string to be matched (if not). */
276 begbuf,
277
278 /* Analogously, for end of buffer/string. */
279 endbuf,
280
281 /* Followed by two byte relative address to which to jump. */
282 jump,
283
284 /* Same as jump, but marks the end of an alternative. */
285 jump_past_alt,
286
287 /* Followed by two-byte relative address of place to resume at
288 in case of failure. */
289 on_failure_jump,
290
291 /* Like on_failure_jump, but pushes a placeholder instead of the
292 current string position when executed. */
293 on_failure_keep_string_jump,
294
295 /* Throw away latest failure point and then jump to following
296 two-byte relative address. */
297 pop_failure_jump,
298
299 /* Change to pop_failure_jump if know won't have to backtrack to
300 match; otherwise change to jump. This is used to jump
301 back to the beginning of a repeat. If what follows this jump
302 clearly won't match what the repeat does, such that we can be
303 sure that there is no use backtracking out of repetitions
304 already matched, then we change it to a pop_failure_jump.
305 Followed by two-byte address. */
306 maybe_pop_jump,
307
308 /* Jump to following two-byte address, and push a dummy failure
309 point. This failure point will be thrown away if an attempt
310 is made to use it for a failure. A `+' construct makes this
311 before the first repeat. Also used as an intermediary kind
312 of jump when compiling an alternative. */
313 dummy_failure_jump,
314
315 /* Push a dummy failure point and continue. Used at the end of
316 alternatives. */
317 push_dummy_failure,
318
319 /* Followed by two-byte relative address and two-byte number n.
320 After matching N times, jump to the address upon failure. */
321 succeed_n,
322
323 /* Followed by two-byte relative address, and two-byte number n.
324 Jump to the address N times, then fail. */
325 jump_n,
326
327 /* Set the following two-byte relative address to the
328 subsequent two-byte number. The address *includes* the two
329 bytes of number. */
330 set_number_at,
331
332 wordchar, /* Matches any word-constituent character. */
333 notwordchar, /* Matches any char that is not a word-constituent. */
334
335 wordbeg, /* Succeeds if at word beginning. */
336 wordend, /* Succeeds if at word end. */
337
338 wordbound, /* Succeeds if at a word boundary. */
339 notwordbound /* Succeeds if not at a word boundary. */
340
341#ifdef emacs
342 ,before_dot, /* Succeeds if before point. */
343 at_dot, /* Succeeds if at point. */
344 after_dot, /* Succeeds if after point. */
345
346 /* Matches any character whose syntax is specified. Followed by
347 a byte which contains a syntax code, e.g., Sword. */
348 syntaxspec,
349
350 /* Matches any character whose syntax is not that specified. */
351 notsyntaxspec
352#endif /* emacs */
353} re_opcode_t;
354
355/* Common operations on the compiled pattern. */
356
357/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
358
359#define STORE_NUMBER(destination, number) \
360 do { \
361 (destination)[0] = (number) & 0377; \
362 (destination)[1] = (number) >> 8; \
363 } while (0)
364
365/* Same as STORE_NUMBER, except increment DESTINATION to
366 the byte after where the number is stored. Therefore, DESTINATION
367 must be an lvalue. */
368
369#define STORE_NUMBER_AND_INCR(destination, number) \
370 do { \
371 STORE_NUMBER (destination, number); \
372 (destination) += 2; \
373 } while (0)
374
375/* Put into DESTINATION a number stored in two contiguous bytes starting
376 at SOURCE. */
377
378#define EXTRACT_NUMBER(destination, source) \
379 do { \
380 (destination) = *(source) & 0377; \
381 (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
382 } while (0)
383
384#ifdef DEBUG
385static void
386extract_number (dest, source)
387 int *dest;
388 unsigned char *source;
389{
390 int temp = SIGN_EXTEND_CHAR (*(source + 1));
391 *dest = *source & 0377;
392 *dest += temp << 8;
393}
394
395#ifndef EXTRACT_MACROS /* To debug the macros. */
396#undef EXTRACT_NUMBER
397#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
398#endif /* not EXTRACT_MACROS */
399
400#endif /* DEBUG */
401
402/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
403 SOURCE must be an lvalue. */
404
405#define EXTRACT_NUMBER_AND_INCR(destination, source) \
406 do { \
407 EXTRACT_NUMBER (destination, source); \
408 (source) += 2; \
409 } while (0)
410
411#ifdef DEBUG
412static void
413extract_number_and_incr (destination, source)
414 int *destination;
415 unsigned char **source;
416{
417 extract_number (destination, *source);
418 *source += 2;
419}
420
421#ifndef EXTRACT_MACROS
422#undef EXTRACT_NUMBER_AND_INCR
423#define EXTRACT_NUMBER_AND_INCR(dest, src) \
424 extract_number_and_incr (&dest, &src)
425#endif /* not EXTRACT_MACROS */
426
427#endif /* DEBUG */
428
429/* If DEBUG is defined, Regex prints many voluminous messages about what
430 it is doing (if the variable `debug' is nonzero). If linked with the
431 main program in `iregex.c', you can enter patterns and strings
432 interactively. And if linked with the main program in `main.c' and
433 the other test files, you can run the already-written tests. */
434
435#ifdef DEBUG
436
437/* We use standard I/O for debugging. */
438#include <stdio.h>
439
440/* It is useful to test things that ``must'' be true when debugging. */
441#include <assert.h>
442
443static int debug = 0;
444
445#define DEBUG_STATEMENT(e) e
446#define DEBUG_PRINT1(x) if (debug) printf (x)
447#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
448#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
449#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
450#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
451 if (debug) print_partial_compiled_pattern (s, e)
452#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
453 if (debug) print_double_string (w, s1, sz1, s2, sz2)
454
455
456extern void printchar ();
457
458/* Print the fastmap in human-readable form. */
459
460void
461print_fastmap (fastmap)
462 char *fastmap;
463{
464 unsigned was_a_range = 0;
465 unsigned i = 0;
466
467 while (i < (1 << BYTEWIDTH))
468 {
469 if (fastmap[i++])
470 {
471 was_a_range = 0;
472 printchar (i - 1);
473 while (i < (1 << BYTEWIDTH) && fastmap[i])
474 {
475 was_a_range = 1;
476 i++;
477 }
478 if (was_a_range)
479 {
480 printf ("-");
481 printchar (i - 1);
482 }
483 }
484 }
485 putchar ('\n');
486}
487
488
489/* Print a compiled pattern string in human-readable form, starting at
490 the START pointer into it and ending just before the pointer END. */
491
492void
493print_partial_compiled_pattern (start, end)
494 unsigned char *start;
495 unsigned char *end;
496{
497 int mcnt, mcnt2;
498 unsigned char *p = start;
499 unsigned char *pend = end;
500
501 if (start == NULL)
502 {
503 printf ("(null)\n");
504 return;
505 }
506
507 /* Loop over pattern commands. */
508 while (p < pend)
509 {
510 switch ((re_opcode_t) *p++)
511 {
512 case no_op:
513 printf ("/no_op");
514 break;
515
516 case exactn:
517 mcnt = *p++;
518 printf ("/exactn/%d", mcnt);
519 do
520 {
521 putchar ('/');
522 printchar (*p++);
523 }
524 while (--mcnt);
525 break;
526
527 case start_memory:
528 mcnt = *p++;
529 printf ("/start_memory/%d/%d", mcnt, *p++);
530 break;
531
532 case stop_memory:
533 mcnt = *p++;
534 printf ("/stop_memory/%d/%d", mcnt, *p++);
535 break;
536
537 case duplicate:
538 printf ("/duplicate/%d", *p++);
539 break;
540
541 case anychar:
542 printf ("/anychar");
543 break;
544
545 case charset:
546 case charset_not:
547 {
548 register int c;
549
550 printf ("/charset%s",
551 (re_opcode_t) *(p - 1) == charset_not ? "_not" : "");
552
553 assert (p + *p < pend);
554
555 for (c = 0; c < *p; c++)
556 {
557 unsigned bit;
558 unsigned char map_byte = p[1 + c];
559
560 putchar ('/');
561
562 for (bit = 0; bit < BYTEWIDTH; bit++)
563 if (map_byte & (1 << bit))
564 printchar (c * BYTEWIDTH + bit);
565 }
566 p += 1 + *p;
567 break;
568 }
569
570 case begline:
571 printf ("/begline");
572 break;
573
574 case endline:
575 printf ("/endline");
576 break;
577
578 case on_failure_jump:
579 extract_number_and_incr (&mcnt, &p);
580 printf ("/on_failure_jump/0/%d", mcnt);
581 break;
582
583 case on_failure_keep_string_jump:
584 extract_number_and_incr (&mcnt, &p);
585 printf ("/on_failure_keep_string_jump/0/%d", mcnt);
586 break;
587
588 case dummy_failure_jump:
589 extract_number_and_incr (&mcnt, &p);
590 printf ("/dummy_failure_jump/0/%d", mcnt);
591 break;
592
593 case push_dummy_failure:
594 printf ("/push_dummy_failure");
595 break;
596
597 case maybe_pop_jump:
598 extract_number_and_incr (&mcnt, &p);
599 printf ("/maybe_pop_jump/0/%d", mcnt);
600 break;
601
602 case pop_failure_jump:
603 extract_number_and_incr (&mcnt, &p);
604 printf ("/pop_failure_jump/0/%d", mcnt);
605 break;
606
607 case jump_past_alt:
608 extract_number_and_incr (&mcnt, &p);
609 printf ("/jump_past_alt/0/%d", mcnt);
610 break;
611
612 case jump:
613 extract_number_and_incr (&mcnt, &p);
614 printf ("/jump/0/%d", mcnt);
615 break;
616
617 case succeed_n:
618 extract_number_and_incr (&mcnt, &p);
619 extract_number_and_incr (&mcnt2, &p);
620 printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2);
621 break;
622
623 case jump_n:
624 extract_number_and_incr (&mcnt, &p);
625 extract_number_and_incr (&mcnt2, &p);
626 printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2);
627 break;
628
629 case set_number_at:
630 extract_number_and_incr (&mcnt, &p);
631 extract_number_and_incr (&mcnt2, &p);
632 printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2);
633 break;
634
635 case wordbound:
636 printf ("/wordbound");
637 break;
638
639 case notwordbound:
640 printf ("/notwordbound");
641 break;
642
643 case wordbeg:
644 printf ("/wordbeg");
645 break;
646
647 case wordend:
648 printf ("/wordend");
649
650#ifdef emacs
651 case before_dot:
652 printf ("/before_dot");
653 break;
654
655 case at_dot:
656 printf ("/at_dot");
657 break;
658
659 case after_dot:
660 printf ("/after_dot");
661 break;
662
663 case syntaxspec:
664 printf ("/syntaxspec");
665 mcnt = *p++;
666 printf ("/%d", mcnt);
667 break;
668
669 case notsyntaxspec:
670 printf ("/notsyntaxspec");
671 mcnt = *p++;
672 printf ("/%d", mcnt);
673 break;
674#endif /* emacs */
675
676 case wordchar:
677 printf ("/wordchar");
678 break;
679
680 case notwordchar:
681 printf ("/notwordchar");
682 break;
683
684 case begbuf:
685 printf ("/begbuf");
686 break;
687
688 case endbuf:
689 printf ("/endbuf");
690 break;
691
692 default:
693 printf ("?%d", *(p-1));
694 }
695 }
696 printf ("/\n");
697}
698
699
700void
701print_compiled_pattern (bufp)
702 struct re_pattern_buffer *bufp;
703{
704 unsigned char *buffer = bufp->buffer;
705
706 print_partial_compiled_pattern (buffer, buffer + bufp->used);
707 printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
708
709 if (bufp->fastmap_accurate && bufp->fastmap)
710 {
711 printf ("fastmap: ");
712 print_fastmap (bufp->fastmap);
713 }
714
715 printf ("re_nsub: %d\t", bufp->re_nsub);
716 printf ("regs_alloc: %d\t", bufp->regs_allocated);
717 printf ("can_be_null: %d\t", bufp->can_be_null);
718 printf ("newline_anchor: %d\n", bufp->newline_anchor);
719 printf ("no_sub: %d\t", bufp->no_sub);
720 printf ("not_bol: %d\t", bufp->not_bol);
721 printf ("not_eol: %d\t", bufp->not_eol);
722 printf ("syntax: %d\n", bufp->syntax);
723 /* Perhaps we should print the translate table? */
724}
725
726
727void
728print_double_string (where, string1, size1, string2, size2)
729 const char *where;
730 const char *string1;
731 const char *string2;
732 int size1;
733 int size2;
734{
735 unsigned this_char;
736
737 if (where == NULL)
738 printf ("(null)");
739 else
740 {
741 if (FIRST_STRING_P (where))
742 {
743 for (this_char = where - string1; this_char < size1; this_char++)
744 printchar (string1[this_char]);
745
746 where = string2;
747 }
748
749 for (this_char = where - string2; this_char < size2; this_char++)
750 printchar (string2[this_char]);
751 }
752}
753
754#else /* not DEBUG */
755
756#undef assert
757#define assert(e)
758
759#define DEBUG_STATEMENT(e)
760#define DEBUG_PRINT1(x)
761#define DEBUG_PRINT2(x1, x2)
762#define DEBUG_PRINT3(x1, x2, x3)
763#define DEBUG_PRINT4(x1, x2, x3, x4)
764#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
765#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
766
767#endif /* not DEBUG */
768
769/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
770 also be assigned to arbitrarily: each pattern buffer stores its own
771 syntax, so it can be changed between regex compilations. */
772reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
773
774
775/* Specify the precise syntax of regexps for compilation. This provides
776 for compatibility for various utilities which historically have
777 different, incompatible syntaxes.
778
779 The argument SYNTAX is a bit mask comprised of the various bits
780 defined in regex.h. We return the old syntax. */
781
782reg_syntax_t
783re_set_syntax (syntax)
784 reg_syntax_t syntax;
785{
786 reg_syntax_t ret = re_syntax_options;
787
788 re_syntax_options = syntax;
789 return ret;
790}
791
792/* This table gives an error message for each of the error codes listed
793 in regex.h. Obviously the order here has to be same as there. */
794
795static const char *re_error_msg[] =
796 { NULL, /* REG_NOERROR */
797 "No match", /* REG_NOMATCH */
798 "Invalid regular expression", /* REG_BADPAT */
799 "Invalid collation character", /* REG_ECOLLATE */
800 "Invalid character class name", /* REG_ECTYPE */
801 "Trailing backslash", /* REG_EESCAPE */
802 "Invalid back reference", /* REG_ESUBREG */
803 "Unmatched [ or [^", /* REG_EBRACK */
804 "Unmatched ( or \\(", /* REG_EPAREN */
805 "Unmatched \\{", /* REG_EBRACE */
806 "Invalid content of \\{\\}", /* REG_BADBR */
807 "Invalid range end", /* REG_ERANGE */
808 "Memory exhausted", /* REG_ESPACE */
809 "Invalid preceding regular expression", /* REG_BADRPT */
810 "Premature end of regular expression", /* REG_EEND */
811 "Regular expression too big", /* REG_ESIZE */
812 "Unmatched ) or \\)", /* REG_ERPAREN */
813 };
814
815/* Subroutine declarations and macros for regex_compile. */
816
817static void store_op1 (), store_op2 ();
818static void insert_op1 (), insert_op2 ();
819static boolean at_begline_loc_p (), at_endline_loc_p ();
820static boolean group_in_compile_stack ();
821static reg_errcode_t compile_range ();
822
823/* Fetch the next character in the uncompiled pattern---translating it
824 if necessary. Also cast from a signed character in the constant
825 string passed to us by the user to an unsigned char that we can use
826 as an array index (in, e.g., `translate'). */
827#define PATFETCH(c) \
828 do {if (p == pend) return REG_EEND; \
829 c = (unsigned char) *p++; \
830 if (translate) c = translate[c]; \
831 } while (0)
832
833/* Fetch the next character in the uncompiled pattern, with no
834 translation. */
835#define PATFETCH_RAW(c) \
836 do {if (p == pend) return REG_EEND; \
837 c = (unsigned char) *p++; \
838 } while (0)
839
840/* Go backwards one character in the pattern. */
841#define PATUNFETCH p--
842
843
844/* If `translate' is non-null, return translate[D], else just D. We
845 cast the subscript to translate because some data is declared as
846 `char *', to avoid warnings when a string constant is passed. But
847 when we use a character as a subscript we must make it unsigned. */
848#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
849
850
851/* Macros for outputting the compiled pattern into `buffer'. */
852
853/* If the buffer isn't allocated when it comes in, use this. */
854#define INIT_BUF_SIZE 32
855
856/* Make sure we have at least N more bytes of space in buffer. */
857#define GET_BUFFER_SPACE(n) \
858 while (b - bufp->buffer + (n) > bufp->allocated) \
859 EXTEND_BUFFER ()
860
861/* Make sure we have one more byte of buffer space and then add C to it. */
862#define BUF_PUSH(c) \
863 do { \
864 GET_BUFFER_SPACE (1); \
865 *b++ = (unsigned char) (c); \
866 } while (0)
867
868
869/* Ensure we have two more bytes of buffer space and then append C1 and C2. */
870#define BUF_PUSH_2(c1, c2) \
871 do { \
872 GET_BUFFER_SPACE (2); \
873 *b++ = (unsigned char) (c1); \
874 *b++ = (unsigned char) (c2); \
875 } while (0)
876
877
878/* As with BUF_PUSH_2, except for three bytes. */
879#define BUF_PUSH_3(c1, c2, c3) \
880 do { \
881 GET_BUFFER_SPACE (3); \
882 *b++ = (unsigned char) (c1); \
883 *b++ = (unsigned char) (c2); \
884 *b++ = (unsigned char) (c3); \
885 } while (0)
886
887
888/* Store a jump with opcode OP at LOC to location TO. We store a
889 relative address offset by the three bytes the jump itself occupies. */
890#define STORE_JUMP(op, loc, to) \
891 store_op1 (op, loc, (to) - (loc) - 3)
892
893/* Likewise, for a two-argument jump. */
894#define STORE_JUMP2(op, loc, to, arg) \
895 store_op2 (op, loc, (to) - (loc) - 3, arg)
896
897/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */
898#define INSERT_JUMP(op, loc, to) \
899 insert_op1 (op, loc, (to) - (loc) - 3, b)
900
901/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */
902#define INSERT_JUMP2(op, loc, to, arg) \
903 insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
904
905
906/* This is not an arbitrary limit: the arguments which represent offsets
907 into the pattern are two bytes long. So if 2^16 bytes turns out to
908 be too small, many things would have to change. */
909#define MAX_BUF_SIZE (1L << 16)
910
911
912/* Extend the buffer by twice its current size via realloc and
913 reset the pointers that pointed into the old block to point to the
914 correct places in the new one. If extending the buffer results in it
915 being larger than MAX_BUF_SIZE, then flag memory exhausted. */
916#define EXTEND_BUFFER() \
917 do { \
918 unsigned char *old_buffer = bufp->buffer; \
919 if (bufp->allocated == MAX_BUF_SIZE) \
920 return REG_ESIZE; \
921 bufp->allocated <<= 1; \
922 if (bufp->allocated > MAX_BUF_SIZE) \
923 bufp->allocated = MAX_BUF_SIZE; \
924 bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
925 if (bufp->buffer == NULL) \
926 return REG_ESPACE; \
927 /* If the buffer moved, move all the pointers into it. */ \
928 if (old_buffer != bufp->buffer) \
929 { \
930 b = (b - old_buffer) + bufp->buffer; \
931 begalt = (begalt - old_buffer) + bufp->buffer; \
932 if (fixup_alt_jump) \
933 fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
934 if (laststart) \
935 laststart = (laststart - old_buffer) + bufp->buffer; \
936 if (pending_exact) \
937 pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
938 } \
939 } while (0)
940
941
942/* Since we have one byte reserved for the register number argument to
943 {start,stop}_memory, the maximum number of groups we can report
944 things about is what fits in that byte. */
945#define MAX_REGNUM 255
946
947/* But patterns can have more than `MAX_REGNUM' registers. We just
948 ignore the excess. */
949typedef unsigned regnum_t;
950
951
952/* Macros for the compile stack. */
953
954/* Since offsets can go either forwards or backwards, this type needs to
955 be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */
956typedef int pattern_offset_t;
957
958typedef struct
959{
960 pattern_offset_t begalt_offset;
961 pattern_offset_t fixup_alt_jump;
962 pattern_offset_t inner_group_offset;
963 pattern_offset_t laststart_offset;
964 regnum_t regnum;
965} compile_stack_elt_t;
966
967
968typedef struct
969{
970 compile_stack_elt_t *stack;
971 unsigned size;
972 unsigned avail; /* Offset of next open position. */
973} compile_stack_type;
974
975
976#define INIT_COMPILE_STACK_SIZE 32
977
978#define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
979#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
980
981/* The next available element. */
982#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
983
984
985/* Set the bit for character C in a list. */
986#define SET_LIST_BIT(c) \
987 (b[((unsigned char) (c)) / BYTEWIDTH] \
988 |= 1 << (((unsigned char) c) % BYTEWIDTH))
989
990
991/* Get the next unsigned number in the uncompiled pattern. */
992#define GET_UNSIGNED_NUMBER(num) \
993 { if (p != pend) \
994 { \
995 PATFETCH (c); \
996 while (ISDIGIT (c)) \
997 { \
998 if (num < 0) \
999 num = 0; \
1000 num = num * 10 + c - '0'; \
1001 if (p == pend) \
1002 break; \
1003 PATFETCH (c); \
1004 } \
1005 } \
1006 }
1007
1008#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
1009
1010#define IS_CHAR_CLASS(string) \
1011 (STREQ (string, "alpha") || STREQ (string, "upper") \
1012 || STREQ (string, "lower") || STREQ (string, "digit") \
1013 || STREQ (string, "alnum") || STREQ (string, "xdigit") \
1014 || STREQ (string, "space") || STREQ (string, "print") \
1015 || STREQ (string, "punct") || STREQ (string, "graph") \
1016 || STREQ (string, "cntrl") || STREQ (string, "blank"))
1017
1018/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
1019 Returns one of error codes defined in `regex.h', or zero for success.
1020
1021 Assumes the `allocated' (and perhaps `buffer') and `translate'
1022 fields are set in BUFP on entry.
1023
1024 If it succeeds, results are put in BUFP (if it returns an error, the
1025 contents of BUFP are undefined):
1026 `buffer' is the compiled pattern;
1027 `syntax' is set to SYNTAX;
1028 `used' is set to the length of the compiled pattern;
1029 `fastmap_accurate' is zero;
1030 `re_nsub' is the number of subexpressions in PATTERN;
1031 `not_bol' and `not_eol' are zero;
1032
1033 The `fastmap' and `newline_anchor' fields are neither
1034 examined nor set. */
1035
1036static reg_errcode_t
1037regex_compile (pattern, size, syntax, bufp)
1038 const char *pattern;
1039 int size;
1040 reg_syntax_t syntax;
1041 struct re_pattern_buffer *bufp;
1042{
1043 /* We fetch characters from PATTERN here. Even though PATTERN is
1044 `char *' (i.e., signed), we declare these variables as unsigned, so
1045 they can be reliably used as array indices. */
1046 register unsigned char c, c1;
1047
1048 /* A random tempory spot in PATTERN. */
1049 const char *p1;
1050
1051 /* Points to the end of the buffer, where we should append. */
1052 register unsigned char *b;
1053
1054 /* Keeps track of unclosed groups. */
1055 compile_stack_type compile_stack;
1056
1057 /* Points to the current (ending) position in the pattern. */
1058 const char *p = pattern;
1059 const char *pend = pattern + size;
1060
1061 /* How to translate the characters in the pattern. */
1062 char *translate = bufp->translate;
1063
1064 /* Address of the count-byte of the most recently inserted `exactn'
1065 command. This makes it possible to tell if a new exact-match
1066 character can be added to that command or if the character requires
1067 a new `exactn' command. */
1068 unsigned char *pending_exact = 0;
1069
1070 /* Address of start of the most recently finished expression.
1071 This tells, e.g., postfix * where to find the start of its
1072 operand. Reset at the beginning of groups and alternatives. */
1073 unsigned char *laststart = 0;
1074
1075 /* Address of beginning of regexp, or inside of last group. */
1076 unsigned char *begalt;
1077
1078 /* Place in the uncompiled pattern (i.e., the {) to
1079 which to go back if the interval is invalid. */
1080 const char *beg_interval;
1081
1082 /* Address of the place where a forward jump should go to the end of
1083 the containing expression. Each alternative of an `or' -- except the
1084 last -- ends with a forward jump of this sort. */
1085 unsigned char *fixup_alt_jump = 0;
1086
1087 /* Counts open-groups as they are encountered. Remembered for the
1088 matching close-group on the compile stack, so the same register
1089 number is put in the stop_memory as the start_memory. */
1090 regnum_t regnum = 0;
1091
1092#ifdef DEBUG
1093 DEBUG_PRINT1 ("\nCompiling pattern: ");
1094 if (debug)
1095 {
1096 unsigned debug_count;
1097
1098 for (debug_count = 0; debug_count < size; debug_count++)
1099 printchar (pattern[debug_count]);
1100 putchar ('\n');
1101 }
1102#endif /* DEBUG */
1103
1104 /* Initialize the compile stack. */
1105 compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
1106 if (compile_stack.stack == NULL)
1107 return REG_ESPACE;
1108
1109 compile_stack.size = INIT_COMPILE_STACK_SIZE;
1110 compile_stack.avail = 0;
1111
1112 /* Initialize the pattern buffer. */
1113 bufp->syntax = syntax;
1114 bufp->fastmap_accurate = 0;
1115 bufp->not_bol = bufp->not_eol = 0;
1116
1117 /* Set `used' to zero, so that if we return an error, the pattern
1118 printer (for debugging) will think there's no pattern. We reset it
1119 at the end. */
1120 bufp->used = 0;
1121
1122 /* Always count groups, whether or not bufp->no_sub is set. */
1123 bufp->re_nsub = 0;
1124
1125#if !defined (emacs) && !defined (SYNTAX_TABLE)
1126 /* Initialize the syntax table. */
1127 init_syntax_once ();
1128#endif
1129
1130 if (bufp->allocated == 0)
1131 {
1132 if (bufp->buffer)
1133 { /* If zero allocated, but buffer is non-null, try to realloc
1134 enough space. This loses if buffer's address is bogus, but
1135 that is the user's responsibility. */
1136 RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
1137 }
1138 else
1139 { /* Caller did not allocate a buffer. Do it for them. */
1140 bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
1141 }
1142 if (!bufp->buffer) return REG_ESPACE;
1143
1144 bufp->allocated = INIT_BUF_SIZE;
1145 }
1146
1147 begalt = b = bufp->buffer;
1148
1149 /* Loop through the uncompiled pattern until we're at the end. */
1150 while (p != pend)
1151 {
1152 PATFETCH (c);
1153
1154 switch (c)
1155 {
1156 case '^':
1157 {
1158 if ( /* If at start of pattern, it's an operator. */
1159 p == pattern + 1
1160 /* If context independent, it's an operator. */
1161 || syntax & RE_CONTEXT_INDEP_ANCHORS
1162 /* Otherwise, depends on what's come before. */
1163 || at_begline_loc_p (pattern, p, syntax))
1164 BUF_PUSH (begline);
1165 else
1166 goto normal_char;
1167 }
1168 break;
1169
1170
1171 case '$':
1172 {
1173 if ( /* If at end of pattern, it's an operator. */
1174 p == pend
1175 /* If context independent, it's an operator. */
1176 || syntax & RE_CONTEXT_INDEP_ANCHORS
1177 /* Otherwise, depends on what's next. */
1178 || at_endline_loc_p (p, pend, syntax))
1179 BUF_PUSH (endline);
1180 else
1181 goto normal_char;
1182 }
1183 break;
1184
1185
1186 case '+':
1187 case '?':
1188 if ((syntax & RE_BK_PLUS_QM)
1189 || (syntax & RE_LIMITED_OPS))
1190 goto normal_char;
1191 handle_plus:
1192 case '*':
1193 /* If there is no previous pattern... */
1194 if (!laststart)
1195 {
1196 if (syntax & RE_CONTEXT_INVALID_OPS)
1197 return REG_BADRPT;
1198 else if (!(syntax & RE_CONTEXT_INDEP_OPS))
1199 goto normal_char;
1200 }
1201
1202 {
1203 /* Are we optimizing this jump? */
1204 boolean keep_string_p = false;
1205
1206 /* 1 means zero (many) matches is allowed. */
1207 char zero_times_ok = 0, many_times_ok = 0;
1208
1209 /* If there is a sequence of repetition chars, collapse it
1210 down to just one (the right one). We can't combine
1211 interval operators with these because of, e.g., `a{2}*',
1212 which should only match an even number of `a's. */
1213
1214 for (;;)
1215 {
1216 zero_times_ok |= c != '+';
1217 many_times_ok |= c != '?';
1218
1219 if (p == pend)
1220 break;
1221
1222 PATFETCH (c);
1223
1224 if (c == '*'
1225 || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
1226 ;
1227
1228 else if (syntax & RE_BK_PLUS_QM && c == '\\')
1229 {
1230 if (p == pend) return REG_EESCAPE;
1231
1232 PATFETCH (c1);
1233 if (!(c1 == '+' || c1 == '?'))
1234 {
1235 PATUNFETCH;
1236 PATUNFETCH;
1237 break;
1238 }
1239
1240 c = c1;
1241 }
1242 else
1243 {
1244 PATUNFETCH;
1245 break;
1246 }
1247
1248 /* If we get here, we found another repeat character. */
1249 }
1250
1251 /* Star, etc. applied to an empty pattern is equivalent
1252 to an empty pattern. */
1253 if (!laststart)
1254 break;
1255
1256 /* Now we know whether or not zero matches is allowed
1257 and also whether or not two or more matches is allowed. */
1258 if (many_times_ok)
1259 { /* More than one repetition is allowed, so put in at the
1260 end a backward relative jump from `b' to before the next
1261 jump we're going to put in below (which jumps from
1262 laststart to after this jump).
1263
1264 But if we are at the `*' in the exact sequence `.*\n',
1265 insert an unconditional jump backwards to the .,
1266 instead of the beginning of the loop. This way we only
1267 push a failure point once, instead of every time
1268 through the loop. */
1269 assert (p - 1 > pattern);
1270
1271 /* Allocate the space for the jump. */
1272 GET_BUFFER_SPACE (3);
1273
1274 /* We know we are not at the first character of the pattern,
1275 because laststart was nonzero. And we've already
1276 incremented `p', by the way, to be the character after
1277 the `*'. Do we have to do something analogous here
1278 for null bytes, because of RE_DOT_NOT_NULL? */
1279 if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
1280 && zero_times_ok
1281 && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
1282 && !(syntax & RE_DOT_NEWLINE))
1283 { /* We have .*\n. */
1284 STORE_JUMP (jump, b, laststart);
1285 keep_string_p = true;
1286 }
1287 else
1288 /* Anything else. */
1289 STORE_JUMP (maybe_pop_jump, b, laststart - 3);
1290
1291 /* We've added more stuff to the buffer. */
1292 b += 3;
1293 }
1294
1295 /* On failure, jump from laststart to b + 3, which will be the
1296 end of the buffer after this jump is inserted. */
1297 GET_BUFFER_SPACE (3);
1298 INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
1299 : on_failure_jump,
1300 laststart, b + 3);
1301 pending_exact = 0;
1302 b += 3;
1303
1304 if (!zero_times_ok)
1305 {
1306 /* At least one repetition is required, so insert a
1307 `dummy_failure_jump' before the initial
1308 `on_failure_jump' instruction of the loop. This
1309 effects a skip over that instruction the first time
1310 we hit that loop. */
1311 GET_BUFFER_SPACE (3);
1312 INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
1313 b += 3;
1314 }
1315 }
1316 break;
1317
1318
1319 case '.':
1320 laststart = b;
1321 BUF_PUSH (anychar);
1322 break;
1323
1324
1325 case '[':
1326 {
1327 boolean had_char_class = false;
1328
1329 if (p == pend) return REG_EBRACK;
1330
1331 /* Ensure that we have enough space to push a charset: the
1332 opcode, the length count, and the bitset; 34 bytes in all. */
1333 GET_BUFFER_SPACE (34);
1334
1335 laststart = b;
1336
1337 /* We test `*p == '^' twice, instead of using an if
1338 statement, so we only need one BUF_PUSH. */
1339 BUF_PUSH (*p == '^' ? charset_not : charset);
1340 if (*p == '^')
1341 p++;
1342
1343 /* Remember the first position in the bracket expression. */
1344 p1 = p;
1345
1346 /* Push the number of bytes in the bitmap. */
1347 BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
1348
1349 /* Clear the whole map. */
1350 bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
1351
1352 /* charset_not matches newline according to a syntax bit. */
1353 if ((re_opcode_t) b[-2] == charset_not
1354 && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
1355 SET_LIST_BIT ('\n');
1356
1357 /* Read in characters and ranges, setting map bits. */
1358 for (;;)
1359 {
1360 if (p == pend) return REG_EBRACK;
1361
1362 PATFETCH (c);
1363
1364 /* \ might escape characters inside [...] and [^...]. */
1365 if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
1366 {
1367 if (p == pend) return REG_EESCAPE;
1368
1369 PATFETCH (c1);
1370 SET_LIST_BIT (c1);
1371 continue;
1372 }
1373
1374 /* Could be the end of the bracket expression. If it's
1375 not (i.e., when the bracket expression is `[]' so
1376 far), the ']' character bit gets set way below. */
1377 if (c == ']' && p != p1 + 1)
1378 break;
1379
1380 /* Look ahead to see if it's a range when the last thing
1381 was a character class. */
1382 if (had_char_class && c == '-' && *p != ']')
1383 return REG_ERANGE;
1384
1385 /* Look ahead to see if it's a range when the last thing
1386 was a character: if this is a hyphen not at the
1387 beginning or the end of a list, then it's the range
1388 operator. */
1389 if (c == '-'
1390 && !(p - 2 >= pattern && p[-2] == '[')
1391 && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
1392 && *p != ']')
1393 {
1394 reg_errcode_t ret
1395 = compile_range (&p, pend, translate, syntax, b);
1396 if (ret != REG_NOERROR) return ret;
1397 }
1398
1399 else if (p[0] == '-' && p[1] != ']')
1400 { /* This handles ranges made up of characters only. */
1401 reg_errcode_t ret;
1402
1403 /* Move past the `-'. */
1404 PATFETCH (c1);
1405
1406 ret = compile_range (&p, pend, translate, syntax, b);
1407 if (ret != REG_NOERROR) return ret;
1408 }
1409
1410 /* See if we're at the beginning of a possible character
1411 class. */
1412
1413 else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
1414 { /* Leave room for the null. */
1415 char str[CHAR_CLASS_MAX_LENGTH + 1];
1416
1417 PATFETCH (c);
1418 c1 = 0;
1419
1420 /* If pattern is `[[:'. */
1421 if (p == pend) return REG_EBRACK;
1422
1423 for (;;)
1424 {
1425 PATFETCH (c);
1426 if (c == ':' || c == ']' || p == pend
1427 || c1 == CHAR_CLASS_MAX_LENGTH)
1428 break;
1429 str[c1++] = c;
1430 }
1431 str[c1] = '\0';
1432
1433 /* If isn't a word bracketed by `[:' and:`]':
1434 undo the ending character, the letters, and leave
1435 the leading `:' and `[' (but set bits for them). */
1436 if (c == ':' && *p == ']')
1437 {
1438 int ch;
1439 boolean is_alnum = STREQ (str, "alnum");
1440 boolean is_alpha = STREQ (str, "alpha");
1441 boolean is_blank = STREQ (str, "blank");
1442 boolean is_cntrl = STREQ (str, "cntrl");
1443 boolean is_digit = STREQ (str, "digit");
1444 boolean is_graph = STREQ (str, "graph");
1445 boolean is_lower = STREQ (str, "lower");
1446 boolean is_print = STREQ (str, "print");
1447 boolean is_punct = STREQ (str, "punct");
1448 boolean is_space = STREQ (str, "space");
1449 boolean is_upper = STREQ (str, "upper");
1450 boolean is_xdigit = STREQ (str, "xdigit");
1451
1452 if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
1453
1454 /* Throw away the ] at the end of the character
1455 class. */
1456 PATFETCH (c);
1457
1458 if (p == pend) return REG_EBRACK;
1459
1460 for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
1461 {
1462 if ( (is_alnum && ISALNUM (ch))
1463 || (is_alpha && ISALPHA (ch))
1464 || (is_blank && ISBLANK (ch))
1465 || (is_cntrl && ISCNTRL (ch))
1466 || (is_digit && ISDIGIT (ch))
1467 || (is_graph && ISGRAPH (ch))
1468 || (is_lower && ISLOWER (ch))
1469 || (is_print && ISPRINT (ch))
1470 || (is_punct && ISPUNCT (ch))
1471 || (is_space && ISSPACE (ch))
1472 || (is_upper && ISUPPER (ch))
1473 || (is_xdigit && ISXDIGIT (ch)))
1474 SET_LIST_BIT (ch);
1475 }
1476 had_char_class = true;
1477 }
1478 else
1479 {
1480 c1++;
1481 while (c1--)
1482 PATUNFETCH;
1483 SET_LIST_BIT ('[');
1484 SET_LIST_BIT (':');
1485 had_char_class = false;
1486 }
1487 }
1488 else
1489 {
1490 had_char_class = false;
1491 SET_LIST_BIT (c);
1492 }
1493 }
1494
1495 /* Discard any (non)matching list bytes that are all 0 at the
1496 end of the map. Decrease the map-length byte too. */
1497 while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
1498 b[-1]--;
1499 b += b[-1];
1500 }
1501 break;
1502
1503
1504 case '(':
1505 if (syntax & RE_NO_BK_PARENS)
1506 goto handle_open;
1507 else
1508 goto normal_char;
1509
1510
1511 case ')':
1512 if (syntax & RE_NO_BK_PARENS)
1513 goto handle_close;
1514 else
1515 goto normal_char;
1516
1517
1518 case '\n':
1519 if (syntax & RE_NEWLINE_ALT)
1520 goto handle_alt;
1521 else
1522 goto normal_char;
1523
1524
1525 case '|':
1526 if (syntax & RE_NO_BK_VBAR)
1527 goto handle_alt;
1528 else
1529 goto normal_char;
1530
1531
1532 case '{':
1533 if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
1534 goto handle_interval;
1535 else
1536 goto normal_char;
1537
1538
1539 case '\\':
1540 if (p == pend) return REG_EESCAPE;
1541
1542 /* Do not translate the character after the \, so that we can
1543 distinguish, e.g., \B from \b, even if we normally would
1544 translate, e.g., B to b. */
1545 PATFETCH_RAW (c);
1546
1547 switch (c)
1548 {
1549 case '(':
1550 if (syntax & RE_NO_BK_PARENS)
1551 goto normal_backslash;
1552
1553 handle_open:
1554 bufp->re_nsub++;
1555 regnum++;
1556
1557 if (COMPILE_STACK_FULL)
1558 {
1559 RETALLOC (compile_stack.stack, compile_stack.size << 1,
1560 compile_stack_elt_t);
1561 if (compile_stack.stack == NULL) return REG_ESPACE;
1562
1563 compile_stack.size <<= 1;
1564 }
1565
1566 /* These are the values to restore when we hit end of this
1567 group. They are all relative offsets, so that if the
1568 whole pattern moves because of realloc, they will still
1569 be valid. */
1570 COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
1571 COMPILE_STACK_TOP.fixup_alt_jump
1572 = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
1573 COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
1574 COMPILE_STACK_TOP.regnum = regnum;
1575
1576 /* We will eventually replace the 0 with the number of
1577 groups inner to this one. But do not push a
1578 start_memory for groups beyond the last one we can
1579 represent in the compiled pattern. */
1580 if (regnum <= MAX_REGNUM)
1581 {
1582 COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
1583 BUF_PUSH_3 (start_memory, regnum, 0);
1584 }
1585
1586 compile_stack.avail++;
1587
1588 fixup_alt_jump = 0;
1589 laststart = 0;
1590 begalt = b;
1591 /* If we've reached MAX_REGNUM groups, then this open
1592 won't actually generate any code, so we'll have to
1593 clear pending_exact explicitly. */
1594 pending_exact = 0;
1595 break;
1596
1597
1598 case ')':
1599 if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
1600
1601 if (COMPILE_STACK_EMPTY)
1602 {
1603 if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
1604 goto normal_backslash;
1605 else
1606 return REG_ERPAREN;
1607 }
1608
1609 handle_close:
1610 if (fixup_alt_jump)
1611 { /* Push a dummy failure point at the end of the
1612 alternative for a possible future
1613 `pop_failure_jump' to pop. See comments at
1614 `push_dummy_failure' in `re_match_2'. */
1615 BUF_PUSH (push_dummy_failure);
1616
1617 /* We allocated space for this jump when we assigned
1618 to `fixup_alt_jump', in the `handle_alt' case below. */
1619 STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
1620 }
1621
1622 /* See similar code for backslashed left paren above. */
1623 if (COMPILE_STACK_EMPTY)
1624 {
1625 if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
1626 goto normal_char;
1627 else
1628 return REG_ERPAREN;
1629 }
1630
1631 /* Since we just checked for an empty stack above, this
1632 ``can't happen''. */
1633 assert (compile_stack.avail != 0);
1634 {
1635 /* We don't just want to restore into `regnum', because
1636 later groups should continue to be numbered higher,
1637 as in `(ab)c(de)' -- the second group is #2. */
1638 regnum_t this_group_regnum;
1639
1640 compile_stack.avail--;
1641 begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
1642 fixup_alt_jump
1643 = COMPILE_STACK_TOP.fixup_alt_jump
1644 ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
1645 : 0;
1646 laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
1647 this_group_regnum = COMPILE_STACK_TOP.regnum;
1648 /* If we've reached MAX_REGNUM groups, then this open
1649 won't actually generate any code, so we'll have to
1650 clear pending_exact explicitly. */
1651 pending_exact = 0;
1652
1653 /* We're at the end of the group, so now we know how many
1654 groups were inside this one. */
1655 if (this_group_regnum <= MAX_REGNUM)
1656 {
1657 unsigned char *inner_group_loc
1658 = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
1659
1660 *inner_group_loc = regnum - this_group_regnum;
1661 BUF_PUSH_3 (stop_memory, this_group_regnum,
1662 regnum - this_group_regnum);
1663 }
1664 }
1665 break;
1666
1667
1668 case '|': /* `\|'. */
1669 if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
1670 goto normal_backslash;
1671 handle_alt:
1672 if (syntax & RE_LIMITED_OPS)
1673 goto normal_char;
1674
1675 /* Insert before the previous alternative a jump which
1676 jumps to this alternative if the former fails. */
1677 GET_BUFFER_SPACE (3);
1678 INSERT_JUMP (on_failure_jump, begalt, b + 6);
1679 pending_exact = 0;
1680 b += 3;
1681
1682 /* The alternative before this one has a jump after it
1683 which gets executed if it gets matched. Adjust that
1684 jump so it will jump to this alternative's analogous
1685 jump (put in below, which in turn will jump to the next
1686 (if any) alternative's such jump, etc.). The last such
1687 jump jumps to the correct final destination. A picture:
1688 _____ _____
1689 | | | |
1690 | v | v
1691 a | b | c
1692
1693 If we are at `b', then fixup_alt_jump right now points to a
1694 three-byte space after `a'. We'll put in the jump, set
1695 fixup_alt_jump to right after `b', and leave behind three
1696 bytes which we'll fill in when we get to after `c'. */
1697
1698 if (fixup_alt_jump)
1699 STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
1700
1701 /* Mark and leave space for a jump after this alternative,
1702 to be filled in later either by next alternative or
1703 when know we're at the end of a series of alternatives. */
1704 fixup_alt_jump = b;
1705 GET_BUFFER_SPACE (3);
1706 b += 3;
1707
1708 laststart = 0;
1709 begalt = b;
1710 break;
1711
1712
1713 case '{':
1714 /* If \{ is a literal. */
1715 if (!(syntax & RE_INTERVALS)
1716 /* If we're at `\{' and it's not the open-interval
1717 operator. */
1718 || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
1719 || (p - 2 == pattern && p == pend))
1720 goto normal_backslash;
1721
1722 handle_interval:
1723 {
1724 /* If got here, then the syntax allows intervals. */
1725
1726 /* At least (most) this many matches must be made. */
1727 int lower_bound = -1, upper_bound = -1;
1728
1729 beg_interval = p - 1;
1730
1731 if (p == pend)
1732 {
1733 if (syntax & RE_NO_BK_BRACES)
1734 goto unfetch_interval;
1735 else
1736 return REG_EBRACE;
1737 }
1738
1739 GET_UNSIGNED_NUMBER (lower_bound);
1740
1741 if (c == ',')
1742 {
1743 GET_UNSIGNED_NUMBER (upper_bound);
1744 if (upper_bound < 0) upper_bound = RE_DUP_MAX;
1745 }
1746 else
1747 /* Interval such as `{1}' => match exactly once. */
1748 upper_bound = lower_bound;
1749
1750 if (lower_bound < 0 || upper_bound > RE_DUP_MAX
1751 || lower_bound > upper_bound)
1752 {
1753 if (syntax & RE_NO_BK_BRACES)
1754 goto unfetch_interval;
1755 else
1756 return REG_BADBR;
1757 }
1758
1759 if (!(syntax & RE_NO_BK_BRACES))
1760 {
1761 if (c != '\\') return REG_EBRACE;
1762
1763 PATFETCH (c);
1764 }
1765
1766 if (c != '}')
1767 {
1768 if (syntax & RE_NO_BK_BRACES)
1769 goto unfetch_interval;
1770 else
1771 return REG_BADBR;
1772 }
1773
1774 /* We just parsed a valid interval. */
1775
1776 /* If it's invalid to have no preceding re. */
1777 if (!laststart)
1778 {
1779 if (syntax & RE_CONTEXT_INVALID_OPS)
1780 return REG_BADRPT;
1781 else if (syntax & RE_CONTEXT_INDEP_OPS)
1782 laststart = b;
1783 else
1784 goto unfetch_interval;
1785 }
1786
1787 /* If the upper bound is zero, don't want to succeed at
1788 all; jump from `laststart' to `b + 3', which will be
1789 the end of the buffer after we insert the jump. */
1790 if (upper_bound == 0)
1791 {
1792 GET_BUFFER_SPACE (3);
1793 INSERT_JUMP (jump, laststart, b + 3);
1794 b += 3;
1795 }
1796
1797 /* Otherwise, we have a nontrivial interval. When
1798 we're all done, the pattern will look like:
1799 set_number_at <jump count> <upper bound>
1800 set_number_at <succeed_n count> <lower bound>
1801 succeed_n <after jump addr> <succed_n count>
1802 <body of loop>
1803 jump_n <succeed_n addr> <jump count>
1804 (The upper bound and `jump_n' are omitted if
1805 `upper_bound' is 1, though.) */
1806 else
1807 { /* If the upper bound is > 1, we need to insert
1808 more at the end of the loop. */
1809 unsigned nbytes = 10 + (upper_bound > 1) * 10;
1810
1811 GET_BUFFER_SPACE (nbytes);
1812
1813 /* Initialize lower bound of the `succeed_n', even
1814 though it will be set during matching by its
1815 attendant `set_number_at' (inserted next),
1816 because `re_compile_fastmap' needs to know.
1817 Jump to the `jump_n' we might insert below. */
1818 INSERT_JUMP2 (succeed_n, laststart,
1819 b + 5 + (upper_bound > 1) * 5,
1820 lower_bound);
1821 b += 5;
1822
1823 /* Code to initialize the lower bound. Insert
1824 before the `succeed_n'. The `5' is the last two
1825 bytes of this `set_number_at', plus 3 bytes of
1826 the following `succeed_n'. */
1827 insert_op2 (set_number_at, laststart, 5, lower_bound, b);
1828 b += 5;
1829
1830 if (upper_bound > 1)
1831 { /* More than one repetition is allowed, so
1832 append a backward jump to the `succeed_n'
1833 that starts this interval.
1834
1835 When we've reached this during matching,
1836 we'll have matched the interval once, so
1837 jump back only `upper_bound - 1' times. */
1838 STORE_JUMP2 (jump_n, b, laststart + 5,
1839 upper_bound - 1);
1840 b += 5;
1841
1842 /* The location we want to set is the second
1843 parameter of the `jump_n'; that is `b-2' as
1844 an absolute address. `laststart' will be
1845 the `set_number_at' we're about to insert;
1846 `laststart+3' the number to set, the source
1847 for the relative address. But we are
1848 inserting into the middle of the pattern --
1849 so everything is getting moved up by 5.
1850 Conclusion: (b - 2) - (laststart + 3) + 5,
1851 i.e., b - laststart.
1852
1853 We insert this at the beginning of the loop
1854 so that if we fail during matching, we'll
1855 reinitialize the bounds. */
1856 insert_op2 (set_number_at, laststart, b - laststart,
1857 upper_bound - 1, b);
1858 b += 5;
1859 }
1860 }
1861 pending_exact = 0;
1862 beg_interval = NULL;
1863 }
1864 break;
1865
1866 unfetch_interval:
1867 /* If an invalid interval, match the characters as literals. */
1868 assert (beg_interval);
1869 p = beg_interval;
1870 beg_interval = NULL;
1871
1872 /* normal_char and normal_backslash need `c'. */
1873 PATFETCH (c);
1874
1875 if (!(syntax & RE_NO_BK_BRACES))
1876 {
1877 if (p > pattern && p[-1] == '\\')
1878 goto normal_backslash;
1879 }
1880 goto normal_char;
1881
1882#ifdef emacs
1883 /* There is no way to specify the before_dot and after_dot
1884 operators. rms says this is ok. --karl */
1885 case '=':
1886 BUF_PUSH (at_dot);
1887 break;
1888
1889 case 's':
1890 laststart = b;
1891 PATFETCH (c);
1892 BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
1893 break;
1894
1895 case 'S':
1896 laststart = b;
1897 PATFETCH (c);
1898 BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
1899 break;
1900#endif /* emacs */
1901
1902
1903 case 'w':
1904 laststart = b;
1905 BUF_PUSH (wordchar);
1906 break;
1907
1908
1909 case 'W':
1910 laststart = b;
1911 BUF_PUSH (notwordchar);
1912 break;
1913
1914
1915 case '<':
1916 BUF_PUSH (wordbeg);
1917 break;
1918
1919 case '>':
1920 BUF_PUSH (wordend);
1921 break;
1922
1923 case 'b':
1924 BUF_PUSH (wordbound);
1925 break;
1926
1927 case 'B':
1928 BUF_PUSH (notwordbound);
1929 break;
1930
1931 case '`':
1932 BUF_PUSH (begbuf);
1933 break;
1934
1935 case '\'':
1936 BUF_PUSH (endbuf);
1937 break;
1938
1939 case '1': case '2': case '3': case '4': case '5':
1940 case '6': case '7': case '8': case '9':
1941 if (syntax & RE_NO_BK_REFS)
1942 goto normal_char;
1943
1944 c1 = c - '0';
1945
1946 if (c1 > regnum)
1947 return REG_ESUBREG;
1948
1949 /* Can't back reference to a subexpression if inside of it. */
1950 if (group_in_compile_stack (compile_stack, c1))
1951 goto normal_char;
1952
1953 laststart = b;
1954 BUF_PUSH_2 (duplicate, c1);
1955 break;
1956
1957
1958 case '+':
1959 case '?':
1960 if (syntax & RE_BK_PLUS_QM)
1961 goto handle_plus;
1962 else
1963 goto normal_backslash;
1964
1965 default:
1966 normal_backslash:
1967 /* You might think it would be useful for \ to mean
1968 not to translate; but if we don't translate it
1969 it will never match anything. */
1970 c = TRANSLATE (c);
1971 goto normal_char;
1972 }
1973 break;
1974
1975
1976 default:
1977 /* Expects the character in `c'. */
1978 normal_char:
1979 /* If no exactn currently being built. */
1980 if (!pending_exact
1981
1982 /* If last exactn not at current position. */
1983 || pending_exact + *pending_exact + 1 != b
1984
1985 /* We have only one byte following the exactn for the count. */
1986 || *pending_exact == (1 << BYTEWIDTH) - 1
1987
1988 /* If followed by a repetition operator. */
1989 || *p == '*' || *p == '^'
1990 || ((syntax & RE_BK_PLUS_QM)
1991 ? *p == '\\' && (p[1] == '+' || p[1] == '?')
1992 : (*p == '+' || *p == '?'))
1993 || ((syntax & RE_INTERVALS)
1994 && ((syntax & RE_NO_BK_BRACES)
1995 ? *p == '{'
1996 : (p[0] == '\\' && p[1] == '{'))))
1997 {
1998 /* Start building a new exactn. */
1999
2000 laststart = b;
2001
2002 BUF_PUSH_2 (exactn, 0);
2003 pending_exact = b - 1;
2004 }
2005
2006 BUF_PUSH (c);
2007 (*pending_exact)++;
2008 break;
2009 } /* switch (c) */
2010 } /* while p != pend */
2011
2012
2013 /* Through the pattern now. */
2014
2015 if (fixup_alt_jump)
2016 STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
2017
2018 if (!COMPILE_STACK_EMPTY)
2019 return REG_EPAREN;
2020
2021 free (compile_stack.stack);
2022
2023 /* We have succeeded; set the length of the buffer. */
2024 bufp->used = b - bufp->buffer;
2025
2026#ifdef DEBUG
2027 if (debug)
2028 {
2029 DEBUG_PRINT1 ("\nCompiled pattern: ");
2030 print_compiled_pattern (bufp);
2031 }
2032#endif /* DEBUG */
2033
2034 return REG_NOERROR;
2035} /* regex_compile */
2036
2037/* Subroutines for `regex_compile'. */
2038
2039/* Store OP at LOC followed by two-byte integer parameter ARG. */
2040
2041static void
2042store_op1 (op, loc, arg)
2043 re_opcode_t op;
2044 unsigned char *loc;
2045 int arg;
2046{
2047 *loc = (unsigned char) op;
2048 STORE_NUMBER (loc + 1, arg);
2049}
2050
2051
2052/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
2053
2054static void
2055store_op2 (op, loc, arg1, arg2)
2056 re_opcode_t op;
2057 unsigned char *loc;
2058 int arg1, arg2;
2059{
2060 *loc = (unsigned char) op;
2061 STORE_NUMBER (loc + 1, arg1);
2062 STORE_NUMBER (loc + 3, arg2);
2063}
2064
2065
2066/* Copy the bytes from LOC to END to open up three bytes of space at LOC
2067 for OP followed by two-byte integer parameter ARG. */
2068
2069static void
2070insert_op1 (op, loc, arg, end)
2071 re_opcode_t op;
2072 unsigned char *loc;
2073 int arg;
2074 unsigned char *end;
2075{
2076 register unsigned char *pfrom = end;
2077 register unsigned char *pto = end + 3;
2078
2079 while (pfrom != loc)
2080 *--pto = *--pfrom;
2081
2082 store_op1 (op, loc, arg);
2083}
2084
2085
2086/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
2087
2088static void
2089insert_op2 (op, loc, arg1, arg2, end)
2090 re_opcode_t op;
2091 unsigned char *loc;
2092 int arg1, arg2;
2093 unsigned char *end;
2094{
2095 register unsigned char *pfrom = end;
2096 register unsigned char *pto = end + 5;
2097
2098 while (pfrom != loc)
2099 *--pto = *--pfrom;
2100
2101 store_op2 (op, loc, arg1, arg2);
2102}
2103
2104
2105/* P points to just after a ^ in PATTERN. Return true if that ^ comes
2106 after an alternative or a begin-subexpression. We assume there is at
2107 least one character before the ^. */
2108
2109static boolean
2110at_begline_loc_p (pattern, p, syntax)
2111 const char *pattern, *p;
2112 reg_syntax_t syntax;
2113{
2114 const char *prev = p - 2;
2115 boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
2116
2117 return
2118 /* After a subexpression? */
2119 (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
2120 /* After an alternative? */
2121 || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
2122}
2123
2124
2125/* The dual of at_begline_loc_p. This one is for $. We assume there is
2126 at least one character after the $, i.e., `P < PEND'. */
2127
2128static boolean
2129at_endline_loc_p (p, pend, syntax)
2130 const char *p, *pend;
2131 int syntax;
2132{
2133 const char *next = p;
2134 boolean next_backslash = *next == '\\';
2135 const char *next_next = p + 1 < pend ? p + 1 : NULL;
2136
2137 return
2138 /* Before a subexpression? */
2139 (syntax & RE_NO_BK_PARENS ? *next == ')'
2140 : next_backslash && next_next && *next_next == ')')
2141 /* Before an alternative? */
2142 || (syntax & RE_NO_BK_VBAR ? *next == '|'
2143 : next_backslash && next_next && *next_next == '|');
2144}
2145
2146
2147/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
2148 false if it's not. */
2149
2150static boolean
2151group_in_compile_stack (compile_stack, regnum)
2152 compile_stack_type compile_stack;
2153 regnum_t regnum;
2154{
2155 int this_element;
2156
2157 for (this_element = compile_stack.avail - 1;
2158 this_element >= 0;
2159 this_element--)
2160 if (compile_stack.stack[this_element].regnum == regnum)
2161 return true;
2162
2163 return false;
2164}
2165
2166
2167/* Read the ending character of a range (in a bracket expression) from the
2168 uncompiled pattern *P_PTR (which ends at PEND). We assume the
2169 starting character is in `P[-2]'. (`P[-1]' is the character `-'.)
2170 Then we set the translation of all bits between the starting and
2171 ending characters (inclusive) in the compiled pattern B.
2172
2173 Return an error code.
2174
2175 We use these short variable names so we can use the same macros as
2176 `regex_compile' itself. */
2177
2178static reg_errcode_t
2179compile_range (p_ptr, pend, translate, syntax, b)
2180 const char **p_ptr, *pend;
2181 char *translate;
2182 reg_syntax_t syntax;
2183 unsigned char *b;
2184{
2185 unsigned this_char;
2186
2187 const char *p = *p_ptr;
2188 int range_start, range_end;
2189
2190 if (p == pend)
2191 return REG_ERANGE;
2192
2193 /* Even though the pattern is a signed `char *', we need to fetch
2194 with unsigned char *'s; if the high bit of the pattern character
2195 is set, the range endpoints will be negative if we fetch using a
2196 signed char *.
2197
2198 We also want to fetch the endpoints without translating them; the
2199 appropriate translation is done in the bit-setting loop below. */
2200 range_start = ((unsigned char *) p)[-2];
2201 range_end = ((unsigned char *) p)[0];
2202
2203 /* Have to increment the pointer into the pattern string, so the
2204 caller isn't still at the ending character. */
2205 (*p_ptr)++;
2206
2207 /* If the start is after the end, the range is empty. */
2208 if (range_start > range_end)
2209 return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
2210
2211 /* Here we see why `this_char' has to be larger than an `unsigned
2212 char' -- the range is inclusive, so if `range_end' == 0xff
2213 (assuming 8-bit characters), we would otherwise go into an infinite
2214 loop, since all characters <= 0xff. */
2215 for (this_char = range_start; this_char <= range_end; this_char++)
2216 {
2217 SET_LIST_BIT (TRANSLATE (this_char));
2218 }
2219
2220 return REG_NOERROR;
2221}
2222
2223/* Failure stack declarations and macros; both re_compile_fastmap and
2224 re_match_2 use a failure stack. These have to be macros because of
2225 REGEX_ALLOCATE. */
2226
2227
2228/* Number of failure points for which to initially allocate space
2229 when matching. If this number is exceeded, we allocate more
2230 space, so it is not a hard limit. */
2231#ifndef INIT_FAILURE_ALLOC
2232#define INIT_FAILURE_ALLOC 5
2233#endif
2234
2235/* Roughly the maximum number of failure points on the stack. Would be
2236 exactly that if always used MAX_FAILURE_SPACE each time we failed.
2237 This is a variable only so users of regex can assign to it; we never
2238 change it ourselves. */
2239int re_max_failures = 2000;
2240
2241typedef const unsigned char *fail_stack_elt_t;
2242
2243typedef struct
2244{
2245 fail_stack_elt_t *stack;
2246 unsigned size;
2247 unsigned avail; /* Offset of next open position. */
2248} fail_stack_type;
2249
2250#define FAIL_STACK_EMPTY() (fail_stack.avail == 0)
2251#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
2252#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size)
2253#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail])
2254
2255
2256/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */
2257
2258#define INIT_FAIL_STACK() \
2259 do { \
2260 fail_stack.stack = (fail_stack_elt_t *) \
2261 REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
2262 \
2263 if (fail_stack.stack == NULL) \
2264 return -2; \
2265 \
2266 fail_stack.size = INIT_FAILURE_ALLOC; \
2267 fail_stack.avail = 0; \
2268 } while (0)
2269
2270
2271/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
2272
2273 Return 1 if succeeds, and 0 if either ran out of memory
2274 allocating space for it or it was already too large.
2275
2276 REGEX_REALLOCATE requires `destination' be declared. */
2277
2278#define DOUBLE_FAIL_STACK(fail_stack) \
2279 ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \
2280 ? 0 \
2281 : ((fail_stack).stack = (fail_stack_elt_t *) \
2282 REGEX_REALLOCATE ((fail_stack).stack, \
2283 (fail_stack).size * sizeof (fail_stack_elt_t), \
2284 ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \
2285 \
2286 (fail_stack).stack == NULL \
2287 ? 0 \
2288 : ((fail_stack).size <<= 1, \
2289 1)))
2290
2291
2292/* Push PATTERN_OP on FAIL_STACK.
2293
2294 Return 1 if was able to do so and 0 if ran out of memory allocating
2295 space to do so. */
2296#define PUSH_PATTERN_OP(pattern_op, fail_stack) \
2297 ((FAIL_STACK_FULL () \
2298 && !DOUBLE_FAIL_STACK (fail_stack)) \
2299 ? 0 \
2300 : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \
2301 1))
2302
2303/* This pushes an item onto the failure stack. Must be a four-byte
2304 value. Assumes the variable `fail_stack'. Probably should only
2305 be called from within `PUSH_FAILURE_POINT'. */
2306#define PUSH_FAILURE_ITEM(item) \
2307 fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item
2308
2309/* The complement operation. Assumes `fail_stack' is nonempty. */
2310#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail]
2311
2312/* Used to omit pushing failure point id's when we're not debugging. */
2313#ifdef DEBUG
2314#define DEBUG_PUSH PUSH_FAILURE_ITEM
2315#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM ()
2316#else
2317#define DEBUG_PUSH(item)
2318#define DEBUG_POP(item_addr)
2319#endif
2320
2321
2322/* Push the information about the state we will need
2323 if we ever fail back to it.
2324
2325 Requires variables fail_stack, regstart, regend, reg_info, and
2326 num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be
2327 declared.
2328
2329 Does `return FAILURE_CODE' if runs out of memory. */
2330
2331#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \
2332 do { \
2333 char *destination; \
2334 /* Must be int, so when we don't save any registers, the arithmetic \
2335 of 0 + -1 isn't done as unsigned. */ \
2336 int this_reg; \
2337 \
2338 DEBUG_STATEMENT (failure_id++); \
2339 DEBUG_STATEMENT (nfailure_points_pushed++); \
2340 DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
2341 DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\
2342 DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\
2343 \
2344 DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \
2345 DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \
2346 \
2347 /* Ensure we have enough space allocated for what we will push. */ \
2348 while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \
2349 { \
2350 if (!DOUBLE_FAIL_STACK (fail_stack)) \
2351 return failure_code; \
2352 \
2353 DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
2354 (fail_stack).size); \
2355 DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\
2356 } \
2357 \
2358 /* Push the info, starting with the registers. */ \
2359 DEBUG_PRINT1 ("\n"); \
2360 \
2361 for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
2362 this_reg++) \
2363 { \
2364 DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
2365 DEBUG_STATEMENT (num_regs_pushed++); \
2366 \
2367 DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
2368 PUSH_FAILURE_ITEM (regstart[this_reg]); \
2369 \
2370 DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
2371 PUSH_FAILURE_ITEM (regend[this_reg]); \
2372 \
2373 DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
2374 DEBUG_PRINT2 (" match_null=%d", \
2375 REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
2376 DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
2377 DEBUG_PRINT2 (" matched_something=%d", \
2378 MATCHED_SOMETHING (reg_info[this_reg])); \
2379 DEBUG_PRINT2 (" ever_matched=%d", \
2380 EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
2381 DEBUG_PRINT1 ("\n"); \
2382 PUSH_FAILURE_ITEM (reg_info[this_reg].word); \
2383 } \
2384 \
2385 DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\
2386 PUSH_FAILURE_ITEM (lowest_active_reg); \
2387 \
2388 DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\
2389 PUSH_FAILURE_ITEM (highest_active_reg); \
2390 \
2391 DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \
2392 DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \
2393 PUSH_FAILURE_ITEM (pattern_place); \
2394 \
2395 DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \
2396 DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \
2397 size2); \
2398 DEBUG_PRINT1 ("'\n"); \
2399 PUSH_FAILURE_ITEM (string_place); \
2400 \
2401 DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \
2402 DEBUG_PUSH (failure_id); \
2403 } while (0)
2404
2405/* This is the number of items that are pushed and popped on the stack
2406 for each register. */
2407#define NUM_REG_ITEMS 3
2408
2409/* Individual items aside from the registers. */
2410#ifdef DEBUG
2411#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */
2412#else
2413#define NUM_NONREG_ITEMS 4
2414#endif
2415
2416/* We push at most this many items on the stack. */
2417#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
2418
2419/* We actually push this many items. */
2420#define NUM_FAILURE_ITEMS \
2421 ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \
2422 + NUM_NONREG_ITEMS)
2423
2424/* How many items can still be added to the stack without overflowing it. */
2425#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
2426
2427
2428/* Pops what PUSH_FAIL_STACK pushes.
2429
2430 We restore into the parameters, all of which should be lvalues:
2431 STR -- the saved data position.
2432 PAT -- the saved pattern position.
2433 LOW_REG, HIGH_REG -- the highest and lowest active registers.
2434 REGSTART, REGEND -- arrays of string positions.
2435 REG_INFO -- array of information about each subexpression.
2436
2437 Also assumes the variables `fail_stack' and (if debugging), `bufp',
2438 `pend', `string1', `size1', `string2', and `size2'. */
2439
2440#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
2441{ \
2442 DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \
2443 int this_reg; \
2444 const unsigned char *string_temp; \
2445 \
2446 assert (!FAIL_STACK_EMPTY ()); \
2447 \
2448 /* Remove failure points and point to how many regs pushed. */ \
2449 DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \
2450 DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \
2451 DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \
2452 \
2453 assert (fail_stack.avail >= NUM_NONREG_ITEMS); \
2454 \
2455 DEBUG_POP (&failure_id); \
2456 DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \
2457 \
2458 /* If the saved string location is NULL, it came from an \
2459 on_failure_keep_string_jump opcode, and we want to throw away the \
2460 saved NULL, thus retaining our current position in the string. */ \
2461 string_temp = POP_FAILURE_ITEM (); \
2462 if (string_temp != NULL) \
2463 str = (const char *) string_temp; \
2464 \
2465 DEBUG_PRINT2 (" Popping string 0x%x: `", str); \
2466 DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \
2467 DEBUG_PRINT1 ("'\n"); \
2468 \
2469 pat = (unsigned char *) POP_FAILURE_ITEM (); \
2470 DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \
2471 DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \
2472 \
2473 /* Restore register info. */ \
2474 high_reg = (unsigned) POP_FAILURE_ITEM (); \
2475 DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \
2476 \
2477 low_reg = (unsigned) POP_FAILURE_ITEM (); \
2478 DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \
2479 \
2480 for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
2481 { \
2482 DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
2483 \
2484 reg_info[this_reg].word = POP_FAILURE_ITEM (); \
2485 DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
2486 \
2487 regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \
2488 DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
2489 \
2490 regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \
2491 DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
2492 } \
2493 \
2494 DEBUG_STATEMENT (nfailure_points_popped++); \
2495} /* POP_FAILURE_POINT */
2496
2497/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
2498 BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
2499 characters can start a string that matches the pattern. This fastmap
2500 is used by re_search to skip quickly over impossible starting points.
2501
2502 The caller must supply the address of a (1 << BYTEWIDTH)-byte data
2503 area as BUFP->fastmap.
2504
2505 We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
2506 the pattern buffer.
2507
2508 Returns 0 if we succeed, -2 if an internal error. */
2509
2510int
2511re_compile_fastmap (bufp)
2512 struct re_pattern_buffer *bufp;
2513{
2514 int j, k;
2515 fail_stack_type fail_stack;
2516#ifndef REGEX_MALLOC
2517 char *destination;
2518#endif
2519 /* We don't push any register information onto the failure stack. */
2520 unsigned num_regs = 0;
2521
2522 register char *fastmap = bufp->fastmap;
2523 unsigned char *pattern = bufp->buffer;
2524 unsigned long size = bufp->used;
2525 const unsigned char *p = pattern;
2526 register unsigned char *pend = pattern + size;
2527
2528 /* Assume that each path through the pattern can be null until
2529 proven otherwise. We set this false at the bottom of switch
2530 statement, to which we get only if a particular path doesn't
2531 match the empty string. */
2532 boolean path_can_be_null = true;
2533
2534 /* We aren't doing a `succeed_n' to begin with. */
2535 boolean succeed_n_p = false;
2536
2537 assert (fastmap != NULL && p != NULL);
2538
2539 INIT_FAIL_STACK ();
2540 bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */
2541 bufp->fastmap_accurate = 1; /* It will be when we're done. */
2542 bufp->can_be_null = 0;
2543
2544 while (p != pend || !FAIL_STACK_EMPTY ())
2545 {
2546 if (p == pend)
2547 {
2548 bufp->can_be_null |= path_can_be_null;
2549
2550 /* Reset for next path. */
2551 path_can_be_null = true;
2552
2553 p = fail_stack.stack[--fail_stack.avail];
2554 }
2555
2556 /* We should never be about to go beyond the end of the pattern. */
2557 assert (p < pend);
2558
2559#ifdef SWITCH_ENUM_BUG
2560 switch ((int) ((re_opcode_t) *p++))
2561#else
2562 switch ((re_opcode_t) *p++)
2563#endif
2564 {
2565
2566 /* I guess the idea here is to simply not bother with a fastmap
2567 if a backreference is used, since it's too hard to figure out
2568 the fastmap for the corresponding group. Setting
2569 `can_be_null' stops `re_search_2' from using the fastmap, so
2570 that is all we do. */
2571 case duplicate:
2572 bufp->can_be_null = 1;
2573 return 0;
2574
2575
2576 /* Following are the cases which match a character. These end
2577 with `break'. */
2578
2579 case exactn:
2580 fastmap[p[1]] = 1;
2581 break;
2582
2583
2584 case charset:
2585 for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
2586 if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
2587 fastmap[j] = 1;
2588 break;
2589
2590
2591 case charset_not:
2592 /* Chars beyond end of map must be allowed. */
2593 for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
2594 fastmap[j] = 1;
2595
2596 for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
2597 if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
2598 fastmap[j] = 1;
2599 break;
2600
2601
2602 case wordchar:
2603 for (j = 0; j < (1 << BYTEWIDTH); j++)
2604 if (SYNTAX (j) == Sword)
2605 fastmap[j] = 1;
2606 break;
2607
2608
2609 case notwordchar:
2610 for (j = 0; j < (1 << BYTEWIDTH); j++)
2611 if (SYNTAX (j) != Sword)
2612 fastmap[j] = 1;
2613 break;
2614
2615
2616 case anychar:
2617 /* `.' matches anything ... */
2618 for (j = 0; j < (1 << BYTEWIDTH); j++)
2619 fastmap[j] = 1;
2620
2621 /* ... except perhaps newline. */
2622 if (!(bufp->syntax & RE_DOT_NEWLINE))
2623 fastmap['\n'] = 0;
2624
2625 /* Return if we have already set `can_be_null'; if we have,
2626 then the fastmap is irrelevant. Something's wrong here. */
2627 else if (bufp->can_be_null)
2628 return 0;
2629
2630 /* Otherwise, have to check alternative paths. */
2631 break;
2632
2633
2634#ifdef emacs
2635 case syntaxspec:
2636 k = *p++;
2637 for (j = 0; j < (1 << BYTEWIDTH); j++)
2638 if (SYNTAX (j) == (enum syntaxcode) k)
2639 fastmap[j] = 1;
2640 break;
2641
2642
2643 case notsyntaxspec:
2644 k = *p++;
2645 for (j = 0; j < (1 << BYTEWIDTH); j++)
2646 if (SYNTAX (j) != (enum syntaxcode) k)
2647 fastmap[j] = 1;
2648 break;
2649
2650
2651 /* All cases after this match the empty string. These end with
2652 `continue'. */
2653
2654
2655 case before_dot:
2656 case at_dot:
2657 case after_dot:
2658 continue;
2659#endif /* not emacs */
2660
2661
2662 case no_op:
2663 case begline:
2664 case endline:
2665 case begbuf:
2666 case endbuf:
2667 case wordbound:
2668 case notwordbound:
2669 case wordbeg:
2670 case wordend:
2671 case push_dummy_failure:
2672 continue;
2673
2674
2675 case jump_n:
2676 case pop_failure_jump:
2677 case maybe_pop_jump:
2678 case jump:
2679 case jump_past_alt:
2680 case dummy_failure_jump:
2681 EXTRACT_NUMBER_AND_INCR (j, p);
2682 p += j;
2683 if (j > 0)
2684 continue;
2685
2686 /* Jump backward implies we just went through the body of a
2687 loop and matched nothing. Opcode jumped to should be
2688 `on_failure_jump' or `succeed_n'. Just treat it like an
2689 ordinary jump. For a * loop, it has pushed its failure
2690 point already; if so, discard that as redundant. */
2691 if ((re_opcode_t) *p != on_failure_jump
2692 && (re_opcode_t) *p != succeed_n)
2693 continue;
2694
2695 p++;
2696 EXTRACT_NUMBER_AND_INCR (j, p);
2697 p += j;
2698
2699 /* If what's on the stack is where we are now, pop it. */
2700 if (!FAIL_STACK_EMPTY ()
2701 && fail_stack.stack[fail_stack.avail - 1] == p)
2702 fail_stack.avail--;
2703
2704 continue;
2705
2706
2707 case on_failure_jump:
2708 case on_failure_keep_string_jump:
2709 handle_on_failure_jump:
2710 EXTRACT_NUMBER_AND_INCR (j, p);
2711
2712 /* For some patterns, e.g., `(a?)?', `p+j' here points to the
2713 end of the pattern. We don't want to push such a point,
2714 since when we restore it above, entering the switch will
2715 increment `p' past the end of the pattern. We don't need
2716 to push such a point since we obviously won't find any more
2717 fastmap entries beyond `pend'. Such a pattern can match
2718 the null string, though. */
2719 if (p + j < pend)
2720 {
2721 if (!PUSH_PATTERN_OP (p + j, fail_stack))
2722 return -2;
2723 }
2724 else
2725 bufp->can_be_null = 1;
2726
2727 if (succeed_n_p)
2728 {
2729 EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
2730 succeed_n_p = false;
2731 }
2732
2733 continue;
2734
2735
2736 case succeed_n:
2737 /* Get to the number of times to succeed. */
2738 p += 2;
2739
2740 /* Increment p past the n for when k != 0. */
2741 EXTRACT_NUMBER_AND_INCR (k, p);
2742 if (k == 0)
2743 {
2744 p -= 4;
2745 succeed_n_p = true; /* Spaghetti code alert. */
2746 goto handle_on_failure_jump;
2747 }
2748 continue;
2749
2750
2751 case set_number_at:
2752 p += 4;
2753 continue;
2754
2755
2756 case start_memory:
2757 case stop_memory:
2758 p += 2;
2759 continue;
2760
2761
2762 default:
2763 abort (); /* We have listed all the cases. */
2764 } /* switch *p++ */
2765
2766 /* Getting here means we have found the possible starting
2767 characters for one path of the pattern -- and that the empty
2768 string does not match. We need not follow this path further.
2769 Instead, look at the next alternative (remembered on the
2770 stack), or quit if no more. The test at the top of the loop
2771 does these things. */
2772 path_can_be_null = false;
2773 p = pend;
2774 } /* while p */
2775
2776 /* Set `can_be_null' for the last path (also the first path, if the
2777 pattern is empty). */
2778 bufp->can_be_null |= path_can_be_null;
2779 return 0;
2780} /* re_compile_fastmap */
2781
2782/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
2783 ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
2784 this memory for recording register information. STARTS and ENDS
2785 must be allocated using the malloc library routine, and must each
2786 be at least NUM_REGS * sizeof (regoff_t) bytes long.
2787
2788 If NUM_REGS == 0, then subsequent matches should allocate their own
2789 register data.
2790
2791 Unless this function is called, the first search or match using
2792 PATTERN_BUFFER will allocate its own register data, without
2793 freeing the old data. */
2794
2795void
2796re_set_registers (bufp, regs, num_regs, starts, ends)
2797 struct re_pattern_buffer *bufp;
2798 struct re_registers *regs;
2799 unsigned num_regs;
2800 regoff_t *starts, *ends;
2801{
2802 if (num_regs)
2803 {
2804 bufp->regs_allocated = REGS_REALLOCATE;
2805 regs->num_regs = num_regs;
2806 regs->start = starts;
2807 regs->end = ends;
2808 }
2809 else
2810 {
2811 bufp->regs_allocated = REGS_UNALLOCATED;
2812 regs->num_regs = 0;
2813 regs->start = regs->end = (regoff_t) 0;
2814 }
2815}
2816
2817/* Searching routines. */
2818
2819/* Like re_search_2, below, but only one string is specified, and
2820 doesn't let you say where to stop matching. */
2821
2822int
2823re_search (bufp, string, size, startpos, range, regs)
2824 struct re_pattern_buffer *bufp;
2825 const char *string;
2826 int size, startpos, range;
2827 struct re_registers *regs;
2828{
2829 return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
2830 regs, size);
2831}
2832
2833
2834/* Using the compiled pattern in BUFP->buffer, first tries to match the
2835 virtual concatenation of STRING1 and STRING2, starting first at index
2836 STARTPOS, then at STARTPOS + 1, and so on.
2837
2838 STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
2839
2840 RANGE is how far to scan while trying to match. RANGE = 0 means try
2841 only at STARTPOS; in general, the last start tried is STARTPOS +
2842 RANGE.
2843
2844 In REGS, return the indices of the virtual concatenation of STRING1
2845 and STRING2 that matched the entire BUFP->buffer and its contained
2846 subexpressions.
2847
2848 Do not consider matching one past the index STOP in the virtual
2849 concatenation of STRING1 and STRING2.
2850
2851 We return either the position in the strings at which the match was
2852 found, -1 if no match, or -2 if error (such as failure
2853 stack overflow). */
2854
2855int
2856re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
2857 struct re_pattern_buffer *bufp;
2858 const char *string1, *string2;
2859 int size1, size2;
2860 int startpos;
2861 int range;
2862 struct re_registers *regs;
2863 int stop;
2864{
2865 int val;
2866 register char *fastmap = bufp->fastmap;
2867 register char *translate = bufp->translate;
2868 int total_size = size1 + size2;
2869 int endpos = startpos + range;
2870
2871 /* Check for out-of-range STARTPOS. */
2872 if (startpos < 0 || startpos > total_size)
2873 return -1;
2874
2875 /* Fix up RANGE if it might eventually take us outside
2876 the virtual concatenation of STRING1 and STRING2. */
2877 if (endpos < -1)
2878 range = -1 - startpos;
2879 else if (endpos > total_size)
2880 range = total_size - startpos;
2881
2882 /* If the search isn't to be a backwards one, don't waste time in a
2883 search for a pattern that must be anchored. */
2884 if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
2885 {
2886 if (startpos > 0)
2887 return -1;
2888 else
2889 range = 1;
2890 }
2891
2892 /* Update the fastmap now if not correct already. */
2893 if (fastmap && !bufp->fastmap_accurate)
2894 if (re_compile_fastmap (bufp) == -2)
2895 return -2;
2896
2897 /* Loop through the string, looking for a place to start matching. */
2898 for (;;)
2899 {
2900 /* If a fastmap is supplied, skip quickly over characters that
2901 cannot be the start of a match. If the pattern can match the
2902 null string, however, we don't need to skip characters; we want
2903 the first null string. */
2904 if (fastmap && startpos < total_size && !bufp->can_be_null)
2905 {
2906 if (range > 0) /* Searching forwards. */
2907 {
2908 register const char *d;
2909 register int lim = 0;
2910 int irange = range;
2911
2912 if (startpos < size1 && startpos + range >= size1)
2913 lim = range - (size1 - startpos);
2914
2915 d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
2916
2917 /* Written out as an if-else to avoid testing `translate'
2918 inside the loop. */
2919 if (translate)
2920 while (range > lim
2921 && !fastmap[(unsigned char)
2922 translate[(unsigned char) *d++]])
2923 range--;
2924 else
2925 while (range > lim && !fastmap[(unsigned char) *d++])
2926 range--;
2927
2928 startpos += irange - range;
2929 }
2930 else /* Searching backwards. */
2931 {
2932 register char c = (size1 == 0 || startpos >= size1
2933 ? string2[startpos - size1]
2934 : string1[startpos]);
2935
2936 if (!fastmap[(unsigned char) TRANSLATE (c)])
2937 goto advance;
2938 }
2939 }
2940
2941 /* If can't match the null string, and that's all we have left, fail. */
2942 if (range >= 0 && startpos == total_size && fastmap
2943 && !bufp->can_be_null)
2944 return -1;
2945
2946 val = re_match_2 (bufp, string1, size1, string2, size2,
2947 startpos, regs, stop);
2948 if (val >= 0)
2949 return startpos;
2950
2951 if (val == -2)
2952 return -2;
2953
2954 advance:
2955 if (!range)
2956 break;
2957 else if (range > 0)
2958 {
2959 range--;
2960 startpos++;
2961 }
2962 else
2963 {
2964 range++;
2965 startpos--;
2966 }
2967 }
2968 return -1;
2969} /* re_search_2 */
2970
2971/* Declarations and macros for re_match_2. */
2972
2973static int bcmp_translate ();
2974static boolean alt_match_null_string_p (),
2975 common_op_match_null_string_p (),
2976 group_match_null_string_p ();
2977
2978/* Structure for per-register (a.k.a. per-group) information.
2979 This must not be longer than one word, because we push this value
2980 onto the failure stack. Other register information, such as the
2981 starting and ending positions (which are addresses), and the list of
2982 inner groups (which is a bits list) are maintained in separate
2983 variables.
2984
2985 We are making a (strictly speaking) nonportable assumption here: that
2986 the compiler will pack our bit fields into something that fits into
2987 the type of `word', i.e., is something that fits into one item on the
2988 failure stack. */
2989typedef union
2990{
2991 fail_stack_elt_t word;
2992 struct
2993 {
2994 /* This field is one if this group can match the empty string,
2995 zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */
2996#define MATCH_NULL_UNSET_VALUE 3
2997 unsigned match_null_string_p : 2;
2998 unsigned is_active : 1;
2999 unsigned matched_something : 1;
3000 unsigned ever_matched_something : 1;
3001 } bits;
3002} register_info_type;
3003
3004#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p)
3005#define IS_ACTIVE(R) ((R).bits.is_active)
3006#define MATCHED_SOMETHING(R) ((R).bits.matched_something)
3007#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something)
3008
3009
3010/* Call this when have matched a real character; it sets `matched' flags
3011 for the subexpressions which we are currently inside. Also records
3012 that those subexprs have matched. */
3013#define SET_REGS_MATCHED() \
3014 do \
3015 { \
3016 unsigned r; \
3017 for (r = lowest_active_reg; r <= highest_active_reg; r++) \
3018 { \
3019 MATCHED_SOMETHING (reg_info[r]) \
3020 = EVER_MATCHED_SOMETHING (reg_info[r]) \
3021 = 1; \
3022 } \
3023 } \
3024 while (0)
3025
3026
3027/* This converts PTR, a pointer into one of the search strings `string1'
3028 and `string2' into an offset from the beginning of that string. */
3029#define POINTER_TO_OFFSET(ptr) \
3030 (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1)
3031
3032/* Registers are set to a sentinel when they haven't yet matched. */
3033#define REG_UNSET_VALUE ((char *) -1)
3034#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
3035
3036
3037/* Macros for dealing with the split strings in re_match_2. */
3038
3039#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
3040
3041/* Call before fetching a character with *d. This switches over to
3042 string2 if necessary. */
3043#define PREFETCH() \
3044 while (d == dend) \
3045 { \
3046 /* End of string2 => fail. */ \
3047 if (dend == end_match_2) \
3048 goto fail; \
3049 /* End of string1 => advance to string2. */ \
3050 d = string2; \
3051 dend = end_match_2; \
3052 }
3053
3054
3055/* Test if at very beginning or at very end of the virtual concatenation
3056 of `string1' and `string2'. If only one string, it's `string2'. */
3057#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
3058#define AT_STRINGS_END(d) ((d) == end2)
3059
3060
3061/* Test if D points to a character which is word-constituent. We have
3062 two special cases to check for: if past the end of string1, look at
3063 the first character in string2; and if before the beginning of
3064 string2, look at the last character in string1. */
3065#define WORDCHAR_P(d) \
3066 (SYNTAX ((d) == end1 ? *string2 \
3067 : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \
3068 == Sword)
3069
3070/* Test if the character before D and the one at D differ with respect
3071 to being word-constituent. */
3072#define AT_WORD_BOUNDARY(d) \
3073 (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \
3074 || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
3075
3076
3077/* Free everything we malloc. */
3078#ifdef REGEX_MALLOC
3079#define FREE_VAR(var) if (var) free (var); var = NULL
3080#define FREE_VARIABLES() \
3081 do { \
3082 FREE_VAR (fail_stack.stack); \
3083 FREE_VAR (regstart); \
3084 FREE_VAR (regend); \
3085 FREE_VAR (old_regstart); \
3086 FREE_VAR (old_regend); \
3087 FREE_VAR (best_regstart); \
3088 FREE_VAR (best_regend); \
3089 FREE_VAR (reg_info); \
3090 FREE_VAR (reg_dummy); \
3091 FREE_VAR (reg_info_dummy); \
3092 } while (0)
3093#else /* not REGEX_MALLOC */
3094/* Some MIPS systems (at least) want this to free alloca'd storage. */
3095#define FREE_VARIABLES() alloca (0)
3096#endif /* not REGEX_MALLOC */
3097
3098
3099/* These values must meet several constraints. They must not be valid
3100 register values; since we have a limit of 255 registers (because
3101 we use only one byte in the pattern for the register number), we can
3102 use numbers larger than 255. They must differ by 1, because of
3103 NUM_FAILURE_ITEMS above. And the value for the lowest register must
3104 be larger than the value for the highest register, so we do not try
3105 to actually save any registers when none are active. */
3106#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
3107#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
3108
3109/* Matching routines. */
3110
3111#ifndef emacs /* Emacs never uses this. */
3112/* re_match is like re_match_2 except it takes only a single string. */
3113
3114int
3115re_match (bufp, string, size, pos, regs)
3116 struct re_pattern_buffer *bufp;
3117 const char *string;
3118 int size, pos;
3119 struct re_registers *regs;
3120 {
3121 return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size);
3122}
3123#endif /* not emacs */
3124
3125
3126/* re_match_2 matches the compiled pattern in BUFP against the
3127 the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
3128 and SIZE2, respectively). We start matching at POS, and stop
3129 matching at STOP.
3130
3131 If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
3132 store offsets for the substring each group matched in REGS. See the
3133 documentation for exactly how many groups we fill.
3134
3135 We return -1 if no match, -2 if an internal error (such as the
3136 failure stack overflowing). Otherwise, we return the length of the
3137 matched substring. */
3138
3139int
3140re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
3141 struct re_pattern_buffer *bufp;
3142 const char *string1, *string2;
3143 int size1, size2;
3144 int pos;
3145 struct re_registers *regs;
3146 int stop;
3147{
3148 /* General temporaries. */
3149 int mcnt;
3150 unsigned char *p1;
3151
3152 /* Just past the end of the corresponding string. */
3153 const char *end1, *end2;
3154
3155 /* Pointers into string1 and string2, just past the last characters in
3156 each to consider matching. */
3157 const char *end_match_1, *end_match_2;
3158
3159 /* Where we are in the data, and the end of the current string. */
3160 const char *d, *dend;
3161
3162 /* Where we are in the pattern, and the end of the pattern. */
3163 unsigned char *p = bufp->buffer;
3164 register unsigned char *pend = p + bufp->used;
3165
3166 /* We use this to map every character in the string. */
3167 char *translate = bufp->translate;
3168
3169 /* Failure point stack. Each place that can handle a failure further
3170 down the line pushes a failure point on this stack. It consists of
3171 restart, regend, and reg_info for all registers corresponding to
3172 the subexpressions we're currently inside, plus the number of such
3173 registers, and, finally, two char *'s. The first char * is where
3174 to resume scanning the pattern; the second one is where to resume
3175 scanning the strings. If the latter is zero, the failure point is
3176 a ``dummy''; if a failure happens and the failure point is a dummy,
3177 it gets discarded and the next next one is tried. */
3178 fail_stack_type fail_stack;
3179#ifdef DEBUG
3180 static unsigned failure_id = 0;
3181 unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
3182#endif
3183
3184 /* We fill all the registers internally, independent of what we
3185 return, for use in backreferences. The number here includes
3186 an element for register zero. */
3187 unsigned num_regs = bufp->re_nsub + 1;
3188
3189 /* The currently active registers. */
3190 unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
3191 unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
3192
3193 /* Information on the contents of registers. These are pointers into
3194 the input strings; they record just what was matched (on this
3195 attempt) by a subexpression part of the pattern, that is, the
3196 regnum-th regstart pointer points to where in the pattern we began
3197 matching and the regnum-th regend points to right after where we
3198 stopped matching the regnum-th subexpression. (The zeroth register
3199 keeps track of what the whole pattern matches.) */
3200 const char **regstart = NULL, **regend = NULL;
3201
3202 /* If a group that's operated upon by a repetition operator fails to
3203 match anything, then the register for its start will need to be
3204 restored because it will have been set to wherever in the string we
3205 are when we last see its open-group operator. Similarly for a
3206 register's end. */
3207 const char **old_regstart = NULL, **old_regend = NULL;
3208
3209 /* The is_active field of reg_info helps us keep track of which (possibly
3210 nested) subexpressions we are currently in. The matched_something
3211 field of reg_info[reg_num] helps us tell whether or not we have
3212 matched any of the pattern so far this time through the reg_num-th
3213 subexpression. These two fields get reset each time through any
3214 loop their register is in. */
3215 register_info_type *reg_info = NULL;
3216
3217 /* The following record the register info as found in the above
3218 variables when we find a match better than any we've seen before.
3219 This happens as we backtrack through the failure points, which in
3220 turn happens only if we have not yet matched the entire string. */
3221 unsigned best_regs_set = false;
3222 const char **best_regstart = NULL, **best_regend = NULL;
3223
3224 /* Logically, this is `best_regend[0]'. But we don't want to have to
3225 allocate space for that if we're not allocating space for anything
3226 else (see below). Also, we never need info about register 0 for
3227 any of the other register vectors, and it seems rather a kludge to
3228 treat `best_regend' differently than the rest. So we keep track of
3229 the end of the best match so far in a separate variable. We
3230 initialize this to NULL so that when we backtrack the first time
3231 and need to test it, it's not garbage. */
3232 const char *match_end = NULL;
3233
3234 /* Used when we pop values we don't care about. */
3235 const char **reg_dummy = NULL;
3236 register_info_type *reg_info_dummy = NULL;
3237
3238#ifdef DEBUG
3239 /* Counts the total number of registers pushed. */
3240 unsigned num_regs_pushed = 0;
3241#endif
3242
3243 DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
3244
3245 INIT_FAIL_STACK ();
3246
3247 /* Do not bother to initialize all the register variables if there are
3248 no groups in the pattern, as it takes a fair amount of time. If
3249 there are groups, we include space for register 0 (the whole
3250 pattern), even though we never use it, since it simplifies the
3251 array indexing. We should fix this. */
3252 if (bufp->re_nsub)
3253 {
3254 regstart = REGEX_TALLOC (num_regs, const char *);
3255 regend = REGEX_TALLOC (num_regs, const char *);
3256 old_regstart = REGEX_TALLOC (num_regs, const char *);
3257 old_regend = REGEX_TALLOC (num_regs, const char *);
3258 best_regstart = REGEX_TALLOC (num_regs, const char *);
3259 best_regend = REGEX_TALLOC (num_regs, const char *);
3260 reg_info = REGEX_TALLOC (num_regs, register_info_type);
3261 reg_dummy = REGEX_TALLOC (num_regs, const char *);
3262 reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
3263
3264 if (!(regstart && regend && old_regstart && old_regend && reg_info
3265 && best_regstart && best_regend && reg_dummy && reg_info_dummy))
3266 {
3267 FREE_VARIABLES ();
3268 return -2;
3269 }
3270 }
3271#ifdef REGEX_MALLOC
3272 else
3273 {
3274 /* We must initialize all our variables to NULL, so that
3275 `FREE_VARIABLES' doesn't try to free them. */
3276 regstart = regend = old_regstart = old_regend = best_regstart
3277 = best_regend = reg_dummy = NULL;
3278 reg_info = reg_info_dummy = (register_info_type *) NULL;
3279 }
3280#endif /* REGEX_MALLOC */
3281
3282 /* The starting position is bogus. */
3283 if (pos < 0 || pos > size1 + size2)
3284 {
3285 FREE_VARIABLES ();
3286 return -1;
3287 }
3288
3289 /* Initialize subexpression text positions to -1 to mark ones that no
3290 start_memory/stop_memory has been seen for. Also initialize the
3291 register information struct. */
3292 for (mcnt = 1; mcnt < num_regs; mcnt++)
3293 {
3294 regstart[mcnt] = regend[mcnt]
3295 = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
3296
3297 REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
3298 IS_ACTIVE (reg_info[mcnt]) = 0;
3299 MATCHED_SOMETHING (reg_info[mcnt]) = 0;
3300 EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
3301 }
3302
3303 /* We move `string1' into `string2' if the latter's empty -- but not if
3304 `string1' is null. */
3305 if (size2 == 0 && string1 != NULL)
3306 {
3307 string2 = string1;
3308 size2 = size1;
3309 string1 = 0;
3310 size1 = 0;
3311 }
3312 end1 = string1 + size1;
3313 end2 = string2 + size2;
3314
3315 /* Compute where to stop matching, within the two strings. */
3316 if (stop <= size1)
3317 {
3318 end_match_1 = string1 + stop;
3319 end_match_2 = string2;
3320 }
3321 else
3322 {
3323 end_match_1 = end1;
3324 end_match_2 = string2 + stop - size1;
3325 }
3326
3327 /* `p' scans through the pattern as `d' scans through the data.
3328 `dend' is the end of the input string that `d' points within. `d'
3329 is advanced into the following input string whenever necessary, but
3330 this happens before fetching; therefore, at the beginning of the
3331 loop, `d' can be pointing at the end of a string, but it cannot
3332 equal `string2'. */
3333 if (size1 > 0 && pos <= size1)
3334 {
3335 d = string1 + pos;
3336 dend = end_match_1;
3337 }
3338 else
3339 {
3340 d = string2 + pos - size1;
3341 dend = end_match_2;
3342 }
3343
3344 DEBUG_PRINT1 ("The compiled pattern is: ");
3345 DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
3346 DEBUG_PRINT1 ("The string to match is: `");
3347 DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
3348 DEBUG_PRINT1 ("'\n");
3349
3350 /* This loops over pattern commands. It exits by returning from the
3351 function if the match is complete, or it drops through if the match
3352 fails at this starting point in the input data. */
3353 for (;;)
3354 {
3355 DEBUG_PRINT2 ("\n0x%x: ", p);
3356
3357 if (p == pend)
3358 { /* End of pattern means we might have succeeded. */
3359 DEBUG_PRINT1 ("end of pattern ... ");
3360
3361 /* If we haven't matched the entire string, and we want the
3362 longest match, try backtracking. */
3363 if (d != end_match_2)
3364 {
3365 DEBUG_PRINT1 ("backtracking.\n");
3366
3367 if (!FAIL_STACK_EMPTY ())
3368 { /* More failure points to try. */
3369 boolean same_str_p = (FIRST_STRING_P (match_end)
3370 == MATCHING_IN_FIRST_STRING);
3371
3372 /* If exceeds best match so far, save it. */
3373 if (!best_regs_set
3374 || (same_str_p && d > match_end)
3375 || (!same_str_p && !MATCHING_IN_FIRST_STRING))
3376 {
3377 best_regs_set = true;
3378 match_end = d;
3379
3380 DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
3381
3382 for (mcnt = 1; mcnt < num_regs; mcnt++)
3383 {
3384 best_regstart[mcnt] = regstart[mcnt];
3385 best_regend[mcnt] = regend[mcnt];
3386 }
3387 }
3388 goto fail;
3389 }
3390
3391 /* If no failure points, don't restore garbage. */
3392 else if (best_regs_set)
3393 {
3394 restore_best_regs:
3395 /* Restore best match. It may happen that `dend ==
3396 end_match_1' while the restored d is in string2.
3397 For example, the pattern `x.*y.*z' against the
3398 strings `x-' and `y-z-', if the two strings are
3399 not consecutive in memory. */
3400 DEBUG_PRINT1 ("Restoring best registers.\n");
3401
3402 d = match_end;
3403 dend = ((d >= string1 && d <= end1)
3404 ? end_match_1 : end_match_2);
3405
3406 for (mcnt = 1; mcnt < num_regs; mcnt++)
3407 {
3408 regstart[mcnt] = best_regstart[mcnt];
3409 regend[mcnt] = best_regend[mcnt];
3410 }
3411 }
3412 } /* d != end_match_2 */
3413
3414 DEBUG_PRINT1 ("Accepting match.\n");
3415
3416 /* If caller wants register contents data back, do it. */
3417 if (regs && !bufp->no_sub)
3418 {
3419 /* Have the register data arrays been allocated? */
3420 if (bufp->regs_allocated == REGS_UNALLOCATED)
3421 { /* No. So allocate them with malloc. We need one
3422 extra element beyond `num_regs' for the `-1' marker
3423 GNU code uses. */
3424 regs->num_regs = MAX (RE_NREGS, num_regs + 1);
3425 regs->start = TALLOC (regs->num_regs, regoff_t);
3426 regs->end = TALLOC (regs->num_regs, regoff_t);
3427 if (regs->start == NULL || regs->end == NULL)
3428 return -2;
3429 bufp->regs_allocated = REGS_REALLOCATE;
3430 }
3431 else if (bufp->regs_allocated == REGS_REALLOCATE)
3432 { /* Yes. If we need more elements than were already
3433 allocated, reallocate them. If we need fewer, just
3434 leave it alone. */
3435 if (regs->num_regs < num_regs + 1)
3436 {
3437 regs->num_regs = num_regs + 1;
3438 RETALLOC (regs->start, regs->num_regs, regoff_t);
3439 RETALLOC (regs->end, regs->num_regs, regoff_t);
3440 if (regs->start == NULL || regs->end == NULL)
3441 return -2;
3442 }
3443 }
3444 else
3445 assert (bufp->regs_allocated == REGS_FIXED);
3446
3447 /* Convert the pointer data in `regstart' and `regend' to
3448 indices. Register zero has to be set differently,
3449 since we haven't kept track of any info for it. */
3450 if (regs->num_regs > 0)
3451 {
3452 regs->start[0] = pos;
3453 regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1
3454 : d - string2 + size1);
3455 }
3456
3457 /* Go through the first `min (num_regs, regs->num_regs)'
3458 registers, since that is all we initialized. */
3459 for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
3460 {
3461 if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
3462 regs->start[mcnt] = regs->end[mcnt] = -1;
3463 else
3464 {
3465 regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]);
3466 regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]);
3467 }
3468 }
3469
3470 /* If the regs structure we return has more elements than
3471 were in the pattern, set the extra elements to -1. If
3472 we (re)allocated the registers, this is the case,
3473 because we always allocate enough to have at least one
3474 -1 at the end. */
3475 for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
3476 regs->start[mcnt] = regs->end[mcnt] = -1;
3477 } /* regs && !bufp->no_sub */
3478
3479 FREE_VARIABLES ();
3480 DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
3481 nfailure_points_pushed, nfailure_points_popped,
3482 nfailure_points_pushed - nfailure_points_popped);
3483 DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
3484
3485 mcnt = d - pos - (MATCHING_IN_FIRST_STRING
3486 ? string1
3487 : string2 - size1);
3488
3489 DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
3490
3491 return mcnt;
3492 }
3493
3494 /* Otherwise match next pattern command. */
3495#ifdef SWITCH_ENUM_BUG
3496 switch ((int) ((re_opcode_t) *p++))
3497#else
3498 switch ((re_opcode_t) *p++)
3499#endif
3500 {
3501 /* Ignore these. Used to ignore the n of succeed_n's which
3502 currently have n == 0. */
3503 case no_op:
3504 DEBUG_PRINT1 ("EXECUTING no_op.\n");
3505 break;
3506
3507
3508 /* Match the next n pattern characters exactly. The following
3509 byte in the pattern defines n, and the n bytes after that
3510 are the characters to match. */
3511 case exactn:
3512 mcnt = *p++;
3513 DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
3514
3515 /* This is written out as an if-else so we don't waste time
3516 testing `translate' inside the loop. */
3517 if (translate)
3518 {
3519 do
3520 {
3521 PREFETCH ();
3522 if (translate[(unsigned char) *d++] != (char) *p++)
3523 goto fail;
3524 }
3525 while (--mcnt);
3526 }
3527 else
3528 {
3529 do
3530 {
3531 PREFETCH ();
3532 if (*d++ != (char) *p++) goto fail;
3533 }
3534 while (--mcnt);
3535 }
3536 SET_REGS_MATCHED ();
3537 break;
3538
3539
3540 /* Match any character except possibly a newline or a null. */
3541 case anychar:
3542 DEBUG_PRINT1 ("EXECUTING anychar.\n");
3543
3544 PREFETCH ();
3545
3546 if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
3547 || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
3548 goto fail;
3549
3550 SET_REGS_MATCHED ();
3551 DEBUG_PRINT2 (" Matched `%d'.\n", *d);
3552 d++;
3553 break;
3554
3555
3556 case charset:
3557 case charset_not:
3558 {
3559 register unsigned char c;
3560 boolean not = (re_opcode_t) *(p - 1) == charset_not;
3561
3562 DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
3563
3564 PREFETCH ();
3565 c = TRANSLATE (*d); /* The character to match. */
3566
3567 /* Cast to `unsigned' instead of `unsigned char' in case the
3568 bit list is a full 32 bytes long. */
3569 if (c < (unsigned) (*p * BYTEWIDTH)
3570 && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
3571 not = !not;
3572
3573 p += 1 + *p;
3574
3575 if (!not) goto fail;
3576
3577 SET_REGS_MATCHED ();
3578 d++;
3579 break;
3580 }
3581
3582
3583 /* The beginning of a group is represented by start_memory.
3584 The arguments are the register number in the next byte, and the
3585 number of groups inner to this one in the next. The text
3586 matched within the group is recorded (in the internal
3587 registers data structure) under the register number. */
3588 case start_memory:
3589 DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
3590
3591 /* Find out if this group can match the empty string. */
3592 p1 = p; /* To send to group_match_null_string_p. */
3593
3594 if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
3595 REG_MATCH_NULL_STRING_P (reg_info[*p])
3596 = group_match_null_string_p (&p1, pend, reg_info);
3597
3598 /* Save the position in the string where we were the last time
3599 we were at this open-group operator in case the group is
3600 operated upon by a repetition operator, e.g., with `(a*)*b'
3601 against `ab'; then we want to ignore where we are now in
3602 the string in case this attempt to match fails. */
3603 old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
3604 ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
3605 : regstart[*p];
3606 DEBUG_PRINT2 (" old_regstart: %d\n",
3607 POINTER_TO_OFFSET (old_regstart[*p]));
3608
3609 regstart[*p] = d;
3610 DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
3611
3612 IS_ACTIVE (reg_info[*p]) = 1;
3613 MATCHED_SOMETHING (reg_info[*p]) = 0;
3614
3615 /* This is the new highest active register. */
3616 highest_active_reg = *p;
3617
3618 /* If nothing was active before, this is the new lowest active
3619 register. */
3620 if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
3621 lowest_active_reg = *p;
3622
3623 /* Move past the register number and inner group count. */
3624 p += 2;
3625 break;
3626
3627
3628 /* The stop_memory opcode represents the end of a group. Its
3629 arguments are the same as start_memory's: the register
3630 number, and the number of inner groups. */
3631 case stop_memory:
3632 DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
3633
3634 /* We need to save the string position the last time we were at
3635 this close-group operator in case the group is operated
3636 upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
3637 against `aba'; then we want to ignore where we are now in
3638 the string in case this attempt to match fails. */
3639 old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
3640 ? REG_UNSET (regend[*p]) ? d : regend[*p]
3641 : regend[*p];
3642 DEBUG_PRINT2 (" old_regend: %d\n",
3643 POINTER_TO_OFFSET (old_regend[*p]));
3644
3645 regend[*p] = d;
3646 DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
3647
3648 /* This register isn't active anymore. */
3649 IS_ACTIVE (reg_info[*p]) = 0;
3650
3651 /* If this was the only register active, nothing is active
3652 anymore. */
3653 if (lowest_active_reg == highest_active_reg)
3654 {
3655 lowest_active_reg = NO_LOWEST_ACTIVE_REG;
3656 highest_active_reg = NO_HIGHEST_ACTIVE_REG;
3657 }
3658 else
3659 { /* We must scan for the new highest active register, since
3660 it isn't necessarily one less than now: consider
3661 (a(b)c(d(e)f)g). When group 3 ends, after the f), the
3662 new highest active register is 1. */
3663 unsigned char r = *p - 1;
3664 while (r > 0 && !IS_ACTIVE (reg_info[r]))
3665 r--;
3666
3667 /* If we end up at register zero, that means that we saved
3668 the registers as the result of an `on_failure_jump', not
3669 a `start_memory', and we jumped to past the innermost
3670 `stop_memory'. For example, in ((.)*) we save
3671 registers 1 and 2 as a result of the *, but when we pop
3672 back to the second ), we are at the stop_memory 1.
3673 Thus, nothing is active. */
3674 if (r == 0)
3675 {
3676 lowest_active_reg = NO_LOWEST_ACTIVE_REG;
3677 highest_active_reg = NO_HIGHEST_ACTIVE_REG;
3678 }
3679 else
3680 highest_active_reg = r;
3681 }
3682
3683 /* If just failed to match something this time around with a
3684 group that's operated on by a repetition operator, try to
3685 force exit from the ``loop'', and restore the register
3686 information for this group that we had before trying this
3687 last match. */
3688 if ((!MATCHED_SOMETHING (reg_info[*p])
3689 || (re_opcode_t) p[-3] == start_memory)
3690 && (p + 2) < pend)
3691 {
3692 boolean is_a_jump_n = false;
3693
3694 p1 = p + 2;
3695 mcnt = 0;
3696 switch ((re_opcode_t) *p1++)
3697 {
3698 case jump_n:
3699 is_a_jump_n = true;
3700 case pop_failure_jump:
3701 case maybe_pop_jump:
3702 case jump:
3703 case dummy_failure_jump:
3704 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
3705 if (is_a_jump_n)
3706 p1 += 2;
3707 break;
3708
3709 default:
3710 /* do nothing */ ;
3711 }
3712 p1 += mcnt;
3713
3714 /* If the next operation is a jump backwards in the pattern
3715 to an on_failure_jump right before the start_memory
3716 corresponding to this stop_memory, exit from the loop
3717 by forcing a failure after pushing on the stack the
3718 on_failure_jump's jump in the pattern, and d. */
3719 if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
3720 && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
3721 {
3722 /* If this group ever matched anything, then restore
3723 what its registers were before trying this last
3724 failed match, e.g., with `(a*)*b' against `ab' for
3725 regstart[1], and, e.g., with `((a*)*(b*)*)*'
3726 against `aba' for regend[3].
3727
3728 Also restore the registers for inner groups for,
3729 e.g., `((a*)(b*))*' against `aba' (register 3 would
3730 otherwise get trashed). */
3731
3732 if (EVER_MATCHED_SOMETHING (reg_info[*p]))
3733 {
3734 unsigned r;
3735
3736 EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
3737
3738 /* Restore this and inner groups' (if any) registers. */
3739 for (r = *p; r < *p + *(p + 1); r++)
3740 {
3741 regstart[r] = old_regstart[r];
3742
3743 /* xx why this test? */
3744 if ((int) old_regend[r] >= (int) regstart[r])
3745 regend[r] = old_regend[r];
3746 }
3747 }
3748 p1++;
3749 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
3750 PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
3751
3752 goto fail;
3753 }
3754 }
3755
3756 /* Move past the register number and the inner group count. */
3757 p += 2;
3758 break;
3759
3760
3761 /* \<digit> has been turned into a `duplicate' command which is
3762 followed by the numeric value of <digit> as the register number. */
3763 case duplicate:
3764 {
3765 register const char *d2, *dend2;
3766 int regno = *p++; /* Get which register to match against. */
3767 DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
3768
3769 /* Can't back reference a group which we've never matched. */
3770 if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
3771 goto fail;
3772
3773 /* Where in input to try to start matching. */
3774 d2 = regstart[regno];
3775
3776 /* Where to stop matching; if both the place to start and
3777 the place to stop matching are in the same string, then
3778 set to the place to stop, otherwise, for now have to use
3779 the end of the first string. */
3780
3781 dend2 = ((FIRST_STRING_P (regstart[regno])
3782 == FIRST_STRING_P (regend[regno]))
3783 ? regend[regno] : end_match_1);
3784 for (;;)
3785 {
3786 /* If necessary, advance to next segment in register
3787 contents. */
3788 while (d2 == dend2)
3789 {
3790 if (dend2 == end_match_2) break;
3791 if (dend2 == regend[regno]) break;
3792
3793 /* End of string1 => advance to string2. */
3794 d2 = string2;
3795 dend2 = regend[regno];
3796 }
3797 /* At end of register contents => success */
3798 if (d2 == dend2) break;
3799
3800 /* If necessary, advance to next segment in data. */
3801 PREFETCH ();
3802
3803 /* How many characters left in this segment to match. */
3804 mcnt = dend - d;
3805
3806 /* Want how many consecutive characters we can match in
3807 one shot, so, if necessary, adjust the count. */
3808 if (mcnt > dend2 - d2)
3809 mcnt = dend2 - d2;
3810
3811 /* Compare that many; failure if mismatch, else move
3812 past them. */
3813 if (translate
3814 ? bcmp_translate (d, d2, mcnt, translate)
3815 : bcmp (d, d2, mcnt))
3816 goto fail;
3817 d += mcnt, d2 += mcnt;
3818 }
3819 }
3820 break;
3821
3822
3823 /* begline matches the empty string at the beginning of the string
3824 (unless `not_bol' is set in `bufp'), and, if
3825 `newline_anchor' is set, after newlines. */
3826 case begline:
3827 DEBUG_PRINT1 ("EXECUTING begline.\n");
3828
3829 if (AT_STRINGS_BEG (d))
3830 {
3831 if (!bufp->not_bol) break;
3832 }
3833 else if (d[-1] == '\n' && bufp->newline_anchor)
3834 {
3835 break;
3836 }
3837 /* In all other cases, we fail. */
3838 goto fail;
3839
3840
3841 /* endline is the dual of begline. */
3842 case endline:
3843 DEBUG_PRINT1 ("EXECUTING endline.\n");
3844
3845 if (AT_STRINGS_END (d))
3846 {
3847 if (!bufp->not_eol) break;
3848 }
3849
3850 /* We have to ``prefetch'' the next character. */
3851 else if ((d == end1 ? *string2 : *d) == '\n'
3852 && bufp->newline_anchor)
3853 {
3854 break;
3855 }
3856 goto fail;
3857
3858
3859 /* Match at the very beginning of the data. */
3860 case begbuf:
3861 DEBUG_PRINT1 ("EXECUTING begbuf.\n");
3862 if (AT_STRINGS_BEG (d))
3863 break;
3864 goto fail;
3865
3866
3867 /* Match at the very end of the data. */
3868 case endbuf:
3869 DEBUG_PRINT1 ("EXECUTING endbuf.\n");
3870 if (AT_STRINGS_END (d))
3871 break;
3872 goto fail;
3873
3874
3875 /* on_failure_keep_string_jump is used to optimize `.*\n'. It
3876 pushes NULL as the value for the string on the stack. Then
3877 `pop_failure_point' will keep the current value for the
3878 string, instead of restoring it. To see why, consider
3879 matching `foo\nbar' against `.*\n'. The .* matches the foo;
3880 then the . fails against the \n. But the next thing we want
3881 to do is match the \n against the \n; if we restored the
3882 string value, we would be back at the foo.
3883
3884 Because this is used only in specific cases, we don't need to
3885 check all the things that `on_failure_jump' does, to make
3886 sure the right things get saved on the stack. Hence we don't
3887 share its code. The only reason to push anything on the
3888 stack at all is that otherwise we would have to change
3889 `anychar's code to do something besides goto fail in this
3890 case; that seems worse than this. */
3891 case on_failure_keep_string_jump:
3892 DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
3893
3894 EXTRACT_NUMBER_AND_INCR (mcnt, p);
3895 DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
3896
3897 PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
3898 break;
3899
3900
3901 /* Uses of on_failure_jump:
3902
3903 Each alternative starts with an on_failure_jump that points
3904 to the beginning of the next alternative. Each alternative
3905 except the last ends with a jump that in effect jumps past
3906 the rest of the alternatives. (They really jump to the
3907 ending jump of the following alternative, because tensioning
3908 these jumps is a hassle.)
3909
3910 Repeats start with an on_failure_jump that points past both
3911 the repetition text and either the following jump or
3912 pop_failure_jump back to this on_failure_jump. */
3913 case on_failure_jump:
3914 on_failure:
3915 DEBUG_PRINT1 ("EXECUTING on_failure_jump");
3916
3917 EXTRACT_NUMBER_AND_INCR (mcnt, p);
3918 DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
3919
3920 /* If this on_failure_jump comes right before a group (i.e.,
3921 the original * applied to a group), save the information
3922 for that group and all inner ones, so that if we fail back
3923 to this point, the group's information will be correct.
3924 For example, in \(a*\)*\1, we need the preceding group,
3925 and in \(\(a*\)b*\)\2, we need the inner group. */
3926
3927 /* We can't use `p' to check ahead because we push
3928 a failure point to `p + mcnt' after we do this. */
3929 p1 = p;
3930
3931 /* We need to skip no_op's before we look for the
3932 start_memory in case this on_failure_jump is happening as
3933 the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
3934 against aba. */
3935 while (p1 < pend && (re_opcode_t) *p1 == no_op)
3936 p1++;
3937
3938 if (p1 < pend && (re_opcode_t) *p1 == start_memory)
3939 {
3940 /* We have a new highest active register now. This will
3941 get reset at the start_memory we are about to get to,
3942 but we will have saved all the registers relevant to
3943 this repetition op, as described above. */
3944 highest_active_reg = *(p1 + 1) + *(p1 + 2);
3945 if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
3946 lowest_active_reg = *(p1 + 1);
3947 }
3948
3949 DEBUG_PRINT1 (":\n");
3950 PUSH_FAILURE_POINT (p + mcnt, d, -2);
3951 break;
3952
3953
3954 /* A smart repeat ends with `maybe_pop_jump'.
3955 We change it to either `pop_failure_jump' or `jump'. */
3956 case maybe_pop_jump:
3957 EXTRACT_NUMBER_AND_INCR (mcnt, p);
3958 DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
3959 {
3960 register unsigned char *p2 = p;
3961
3962 /* Compare the beginning of the repeat with what in the
3963 pattern follows its end. If we can establish that there
3964 is nothing that they would both match, i.e., that we
3965 would have to backtrack because of (as in, e.g., `a*a')
3966 then we can change to pop_failure_jump, because we'll
3967 never have to backtrack.
3968
3969 This is not true in the case of alternatives: in
3970 `(a|ab)*' we do need to backtrack to the `ab' alternative
3971 (e.g., if the string was `ab'). But instead of trying to
3972 detect that here, the alternative has put on a dummy
3973 failure point which is what we will end up popping. */
3974
3975 /* Skip over open/close-group commands. */
3976 while (p2 + 2 < pend
3977 && ((re_opcode_t) *p2 == stop_memory
3978 || (re_opcode_t) *p2 == start_memory))
3979 p2 += 3; /* Skip over args, too. */
3980
3981 /* If we're at the end of the pattern, we can change. */
3982 if (p2 == pend)
3983 {
3984 /* Consider what happens when matching ":\(.*\)"
3985 against ":/". I don't really understand this code
3986 yet. */
3987 p[-3] = (unsigned char) pop_failure_jump;
3988 DEBUG_PRINT1
3989 (" End of pattern: change to `pop_failure_jump'.\n");
3990 }
3991
3992 else if ((re_opcode_t) *p2 == exactn
3993 || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
3994 {
3995 register unsigned char c
3996 = *p2 == (unsigned char) endline ? '\n' : p2[2];
3997 p1 = p + mcnt;
3998
3999 /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
4000 to the `maybe_finalize_jump' of this case. Examine what
4001 follows. */
4002 if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
4003 {
4004 p[-3] = (unsigned char) pop_failure_jump;
4005 DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
4006 c, p1[5]);
4007 }
4008
4009 else if ((re_opcode_t) p1[3] == charset
4010 || (re_opcode_t) p1[3] == charset_not)
4011 {
4012 int not = (re_opcode_t) p1[3] == charset_not;
4013
4014 if (c < (unsigned char) (p1[4] * BYTEWIDTH)
4015 && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
4016 not = !not;
4017
4018 /* `not' is equal to 1 if c would match, which means
4019 that we can't change to pop_failure_jump. */
4020 if (!not)
4021 {
4022 p[-3] = (unsigned char) pop_failure_jump;
4023 DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
4024 }
4025 }
4026 }
4027 }
4028 p -= 2; /* Point at relative address again. */
4029 if ((re_opcode_t) p[-1] != pop_failure_jump)
4030 {
4031 p[-1] = (unsigned char) jump;
4032 DEBUG_PRINT1 (" Match => jump.\n");
4033 goto unconditional_jump;
4034 }
4035 /* Note fall through. */
4036
4037
4038 /* The end of a simple repeat has a pop_failure_jump back to
4039 its matching on_failure_jump, where the latter will push a
4040 failure point. The pop_failure_jump takes off failure
4041 points put on by this pop_failure_jump's matching
4042 on_failure_jump; we got through the pattern to here from the
4043 matching on_failure_jump, so didn't fail. */
4044 case pop_failure_jump:
4045 {
4046 /* We need to pass separate storage for the lowest and
4047 highest registers, even though we don't care about the
4048 actual values. Otherwise, we will restore only one
4049 register from the stack, since lowest will == highest in
4050 `pop_failure_point'. */
4051 unsigned dummy_low_reg, dummy_high_reg;
4052 unsigned char *pdummy;
4053 const char *sdummy;
4054
4055 DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
4056 POP_FAILURE_POINT (sdummy, pdummy,
4057 dummy_low_reg, dummy_high_reg,
4058 reg_dummy, reg_dummy, reg_info_dummy);
4059 }
4060 /* Note fall through. */
4061
4062
4063 /* Unconditionally jump (without popping any failure points). */
4064 case jump:
4065 unconditional_jump:
4066 EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
4067 DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
4068 p += mcnt; /* Do the jump. */
4069 DEBUG_PRINT2 ("(to 0x%x).\n", p);
4070 break;
4071
4072
4073 /* We need this opcode so we can detect where alternatives end
4074 in `group_match_null_string_p' et al. */
4075 case jump_past_alt:
4076 DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
4077 goto unconditional_jump;
4078
4079
4080 /* Normally, the on_failure_jump pushes a failure point, which
4081 then gets popped at pop_failure_jump. We will end up at
4082 pop_failure_jump, also, and with a pattern of, say, `a+', we
4083 are skipping over the on_failure_jump, so we have to push
4084 something meaningless for pop_failure_jump to pop. */
4085 case dummy_failure_jump:
4086 DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
4087 /* It doesn't matter what we push for the string here. What
4088 the code at `fail' tests is the value for the pattern. */
4089 PUSH_FAILURE_POINT (0, 0, -2);
4090 goto unconditional_jump;
4091
4092
4093 /* At the end of an alternative, we need to push a dummy failure
4094 point in case we are followed by a `pop_failure_jump', because
4095 we don't want the failure point for the alternative to be
4096 popped. For example, matching `(a|ab)*' against `aab'
4097 requires that we match the `ab' alternative. */
4098 case push_dummy_failure:
4099 DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
4100 /* See comments just above at `dummy_failure_jump' about the
4101 two zeroes. */
4102 PUSH_FAILURE_POINT (0, 0, -2);
4103 break;
4104
4105 /* Have to succeed matching what follows at least n times.
4106 After that, handle like `on_failure_jump'. */
4107 case succeed_n:
4108 EXTRACT_NUMBER (mcnt, p + 2);
4109 DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
4110
4111 assert (mcnt >= 0);
4112 /* Originally, this is how many times we HAVE to succeed. */
4113 if (mcnt > 0)
4114 {
4115 mcnt--;
4116 p += 2;
4117 STORE_NUMBER_AND_INCR (p, mcnt);
4118 DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt);
4119 }
4120 else if (mcnt == 0)
4121 {
4122 DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2);
4123 p[2] = (unsigned char) no_op;
4124 p[3] = (unsigned char) no_op;
4125 goto on_failure;
4126 }
4127 break;
4128
4129 case jump_n:
4130 EXTRACT_NUMBER (mcnt, p + 2);
4131 DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
4132
4133 /* Originally, this is how many times we CAN jump. */
4134 if (mcnt)
4135 {
4136 mcnt--;
4137 STORE_NUMBER (p + 2, mcnt);
4138 goto unconditional_jump;
4139 }
4140 /* If don't have to jump any more, skip over the rest of command. */
4141 else
4142 p += 4;
4143 break;
4144
4145 case set_number_at:
4146 {
4147 DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
4148
4149 EXTRACT_NUMBER_AND_INCR (mcnt, p);
4150 p1 = p + mcnt;
4151 EXTRACT_NUMBER_AND_INCR (mcnt, p);
4152 DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
4153 STORE_NUMBER (p1, mcnt);
4154 break;
4155 }
4156
4157 case wordbound:
4158 DEBUG_PRINT1 ("EXECUTING wordbound.\n");
4159 if (AT_WORD_BOUNDARY (d))
4160 break;
4161 goto fail;
4162
4163 case notwordbound:
4164 DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
4165 if (AT_WORD_BOUNDARY (d))
4166 goto fail;
4167 break;
4168
4169 case wordbeg:
4170 DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
4171 if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
4172 break;
4173 goto fail;
4174
4175 case wordend:
4176 DEBUG_PRINT1 ("EXECUTING wordend.\n");
4177 if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
4178 && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
4179 break;
4180 goto fail;
4181
4182#ifdef emacs
4183#ifdef emacs19
4184 case before_dot:
4185 DEBUG_PRINT1 ("EXECUTING before_dot.\n");
4186 if (PTR_CHAR_POS ((unsigned char *) d) >= point)
4187 goto fail;
4188 break;
4189
4190 case at_dot:
4191 DEBUG_PRINT1 ("EXECUTING at_dot.\n");
4192 if (PTR_CHAR_POS ((unsigned char *) d) != point)
4193 goto fail;
4194 break;
4195
4196 case after_dot:
4197 DEBUG_PRINT1 ("EXECUTING after_dot.\n");
4198 if (PTR_CHAR_POS ((unsigned char *) d) <= point)
4199 goto fail;
4200 break;
4201#else /* not emacs19 */
4202 case at_dot:
4203 DEBUG_PRINT1 ("EXECUTING at_dot.\n");
4204 if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
4205 goto fail;
4206 break;
4207#endif /* not emacs19 */
4208
4209 case syntaxspec:
4210 DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
4211 mcnt = *p++;
4212 goto matchsyntax;
4213
4214 case wordchar:
4215 DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
4216 mcnt = (int) Sword;
4217 matchsyntax:
4218 PREFETCH ();
4219 if (SYNTAX (*d++) != (enum syntaxcode) mcnt)
4220 goto fail;
4221 SET_REGS_MATCHED ();
4222 break;
4223
4224 case notsyntaxspec:
4225 DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
4226 mcnt = *p++;
4227 goto matchnotsyntax;
4228
4229 case notwordchar:
4230 DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
4231 mcnt = (int) Sword;
4232 matchnotsyntax:
4233 PREFETCH ();
4234 if (SYNTAX (*d++) == (enum syntaxcode) mcnt)
4235 goto fail;
4236 SET_REGS_MATCHED ();
4237 break;
4238
4239#else /* not emacs */
4240 case wordchar:
4241 DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
4242 PREFETCH ();
4243 if (!WORDCHAR_P (d))
4244 goto fail;
4245 SET_REGS_MATCHED ();
4246 d++;
4247 break;
4248
4249 case notwordchar:
4250 DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
4251 PREFETCH ();
4252 if (WORDCHAR_P (d))
4253 goto fail;
4254 SET_REGS_MATCHED ();
4255 d++;
4256 break;
4257#endif /* not emacs */
4258
4259 default:
4260 abort ();
4261 }
4262 continue; /* Successfully executed one pattern command; keep going. */
4263
4264
4265 /* We goto here if a matching operation fails. */
4266 fail:
4267 if (!FAIL_STACK_EMPTY ())
4268 { /* A restart point is known. Restore to that state. */
4269 DEBUG_PRINT1 ("\nFAIL:\n");
4270 POP_FAILURE_POINT (d, p,
4271 lowest_active_reg, highest_active_reg,
4272 regstart, regend, reg_info);
4273
4274 /* If this failure point is a dummy, try the next one. */
4275 if (!p)
4276 goto fail;
4277
4278 /* If we failed to the end of the pattern, don't examine *p. */
4279 assert (p <= pend);
4280 if (p < pend)
4281 {
4282 boolean is_a_jump_n = false;
4283
4284 /* If failed to a backwards jump that's part of a repetition
4285 loop, need to pop this failure point and use the next one. */
4286 switch ((re_opcode_t) *p)
4287 {
4288 case jump_n:
4289 is_a_jump_n = true;
4290 case maybe_pop_jump:
4291 case pop_failure_jump:
4292 case jump:
4293 p1 = p + 1;
4294 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4295 p1 += mcnt;
4296
4297 if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
4298 || (!is_a_jump_n
4299 && (re_opcode_t) *p1 == on_failure_jump))
4300 goto fail;
4301 break;
4302 default:
4303 /* do nothing */ ;
4304 }
4305 }
4306
4307 if (d >= string1 && d <= end1)
4308 dend = end_match_1;
4309 }
4310 else
4311 break; /* Matching at this starting point really fails. */
4312 } /* for (;;) */
4313
4314 if (best_regs_set)
4315 goto restore_best_regs;
4316
4317 FREE_VARIABLES ();
4318
4319 return -1; /* Failure to match. */
4320} /* re_match_2 */
4321
4322/* Subroutine definitions for re_match_2. */
4323
4324
4325/* We are passed P pointing to a register number after a start_memory.
4326
4327 Return true if the pattern up to the corresponding stop_memory can
4328 match the empty string, and false otherwise.
4329
4330 If we find the matching stop_memory, sets P to point to one past its number.
4331 Otherwise, sets P to an undefined byte less than or equal to END.
4332
4333 We don't handle duplicates properly (yet). */
4334
4335static boolean
4336group_match_null_string_p (p, end, reg_info)
4337 unsigned char **p, *end;
4338 register_info_type *reg_info;
4339{
4340 int mcnt;
4341 /* Point to after the args to the start_memory. */
4342 unsigned char *p1 = *p + 2;
4343
4344 while (p1 < end)
4345 {
4346 /* Skip over opcodes that can match nothing, and return true or
4347 false, as appropriate, when we get to one that can't, or to the
4348 matching stop_memory. */
4349
4350 switch ((re_opcode_t) *p1)
4351 {
4352 /* Could be either a loop or a series of alternatives. */
4353 case on_failure_jump:
4354 p1++;
4355 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4356
4357 /* If the next operation is not a jump backwards in the
4358 pattern. */
4359
4360 if (mcnt >= 0)
4361 {
4362 /* Go through the on_failure_jumps of the alternatives,
4363 seeing if any of the alternatives cannot match nothing.
4364 The last alternative starts with only a jump,
4365 whereas the rest start with on_failure_jump and end
4366 with a jump, e.g., here is the pattern for `a|b|c':
4367
4368 /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
4369 /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
4370 /exactn/1/c
4371
4372 So, we have to first go through the first (n-1)
4373 alternatives and then deal with the last one separately. */
4374
4375
4376 /* Deal with the first (n-1) alternatives, which start
4377 with an on_failure_jump (see above) that jumps to right
4378 past a jump_past_alt. */
4379
4380 while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
4381 {
4382 /* `mcnt' holds how many bytes long the alternative
4383 is, including the ending `jump_past_alt' and
4384 its number. */
4385
4386 if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
4387 reg_info))
4388 return false;
4389
4390 /* Move to right after this alternative, including the
4391 jump_past_alt. */
4392 p1 += mcnt;
4393
4394 /* Break if it's the beginning of an n-th alternative
4395 that doesn't begin with an on_failure_jump. */
4396 if ((re_opcode_t) *p1 != on_failure_jump)
4397 break;
4398
4399 /* Still have to check that it's not an n-th
4400 alternative that starts with an on_failure_jump. */
4401 p1++;
4402 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4403 if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
4404 {
4405 /* Get to the beginning of the n-th alternative. */
4406 p1 -= 3;
4407 break;
4408 }
4409 }
4410
4411 /* Deal with the last alternative: go back and get number
4412 of the `jump_past_alt' just before it. `mcnt' contains
4413 the length of the alternative. */
4414 EXTRACT_NUMBER (mcnt, p1 - 2);
4415
4416 if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
4417 return false;
4418
4419 p1 += mcnt; /* Get past the n-th alternative. */
4420 } /* if mcnt > 0 */
4421 break;
4422
4423
4424 case stop_memory:
4425 assert (p1[1] == **p);
4426 *p = p1 + 2;
4427 return true;
4428
4429
4430 default:
4431 if (!common_op_match_null_string_p (&p1, end, reg_info))
4432 return false;
4433 }
4434 } /* while p1 < end */
4435
4436 return false;
4437} /* group_match_null_string_p */
4438
4439
4440/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
4441 It expects P to be the first byte of a single alternative and END one
4442 byte past the last. The alternative can contain groups. */
4443
4444static boolean
4445alt_match_null_string_p (p, end, reg_info)
4446 unsigned char *p, *end;
4447 register_info_type *reg_info;
4448{
4449 int mcnt;
4450 unsigned char *p1 = p;
4451
4452 while (p1 < end)
4453 {
4454 /* Skip over opcodes that can match nothing, and break when we get
4455 to one that can't. */
4456
4457 switch ((re_opcode_t) *p1)
4458 {
4459 /* It's a loop. */
4460 case on_failure_jump:
4461 p1++;
4462 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4463 p1 += mcnt;
4464 break;
4465
4466 default:
4467 if (!common_op_match_null_string_p (&p1, end, reg_info))
4468 return false;
4469 }
4470 } /* while p1 < end */
4471
4472 return true;
4473} /* alt_match_null_string_p */
4474
4475
4476/* Deals with the ops common to group_match_null_string_p and
4477 alt_match_null_string_p.
4478
4479 Sets P to one after the op and its arguments, if any. */
4480
4481static boolean
4482common_op_match_null_string_p (p, end, reg_info)
4483 unsigned char **p, *end;
4484 register_info_type *reg_info;
4485{
4486 int mcnt;
4487 boolean ret;
4488 int reg_no;
4489 unsigned char *p1 = *p;
4490
4491 switch ((re_opcode_t) *p1++)
4492 {
4493 case no_op:
4494 case begline:
4495 case endline:
4496 case begbuf:
4497 case endbuf:
4498 case wordbeg:
4499 case wordend:
4500 case wordbound:
4501 case notwordbound:
4502#ifdef emacs
4503 case before_dot:
4504 case at_dot:
4505 case after_dot:
4506#endif
4507 break;
4508
4509 case start_memory:
4510 reg_no = *p1;
4511 assert (reg_no > 0 && reg_no <= MAX_REGNUM);
4512 ret = group_match_null_string_p (&p1, end, reg_info);
4513
4514 /* Have to set this here in case we're checking a group which
4515 contains a group and a back reference to it. */
4516
4517 if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
4518 REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
4519
4520 if (!ret)
4521 return false;
4522 break;
4523
4524 /* If this is an optimized succeed_n for zero times, make the jump. */
4525 case jump:
4526 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4527 if (mcnt >= 0)
4528 p1 += mcnt;
4529 else
4530 return false;
4531 break;
4532
4533 case succeed_n:
4534 /* Get to the number of times to succeed. */
4535 p1 += 2;
4536 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4537
4538 if (mcnt == 0)
4539 {
4540 p1 -= 4;
4541 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4542 p1 += mcnt;
4543 }
4544 else
4545 return false;
4546 break;
4547
4548 case duplicate:
4549 if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
4550 return false;
4551 break;
4552
4553 case set_number_at:
4554 p1 += 4;
4555
4556 default:
4557 /* All other opcodes mean we cannot match the empty string. */
4558 return false;
4559 }
4560
4561 *p = p1;
4562 return true;
4563} /* common_op_match_null_string_p */
4564
4565
4566/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
4567 bytes; nonzero otherwise. */
4568
4569static int
4570bcmp_translate(
4571 unsigned char *s1,
4572 unsigned char *s2,
4573 int len,
4574 char *translate
4575)
4576{
4577 register unsigned char *p1 = s1, *p2 = s2;
4578 while (len)
4579 {
4580 if (translate[*p1++] != translate[*p2++]) return 1;
4581 len--;
4582 }
4583 return 0;
4584}
4585
4586/* Entry points for GNU code. */
4587
4588/* re_compile_pattern is the GNU regular expression compiler: it
4589 compiles PATTERN (of length SIZE) and puts the result in BUFP.
4590 Returns 0 if the pattern was valid, otherwise an error string.
4591
4592 Assumes the `allocated' (and perhaps `buffer') and `translate' fields
4593 are set in BUFP on entry.
4594
4595 We call regex_compile to do the actual compilation. */
4596
4597const char *
4598re_compile_pattern (pattern, length, bufp)
4599 const char *pattern;
4600 int length;
4601 struct re_pattern_buffer *bufp;
4602{
4603 reg_errcode_t ret;
4604
4605 /* GNU code is written to assume at least RE_NREGS registers will be set
4606 (and at least one extra will be -1). */
4607 bufp->regs_allocated = REGS_UNALLOCATED;
4608
4609 /* And GNU code determines whether or not to get register information
4610 by passing null for the REGS argument to re_match, etc., not by
4611 setting no_sub. */
4612 bufp->no_sub = 0;
4613
4614 /* Match anchors at newline. */
4615 bufp->newline_anchor = 1;
4616
4617 ret = regex_compile (pattern, length, re_syntax_options, bufp);
4618
4619 return re_error_msg[(int) ret];
4620}
4621
4622/* Entry points compatible with 4.2 BSD regex library. We don't define
4623 them if this is an Emacs or POSIX compilation. */
4624
4625#if !defined (emacs) && !defined (_POSIX_SOURCE)
4626
4627/* BSD has one and only one pattern buffer. */
4628static struct re_pattern_buffer re_comp_buf;
4629
4630char *
4631re_comp (s)
4632 const char *s;
4633{
4634 reg_errcode_t ret;
4635
4636 if (!s)
4637 {
4638 if (!re_comp_buf.buffer)
4639 return "No previous regular expression";
4640 return 0;
4641 }
4642
4643 if (!re_comp_buf.buffer)
4644 {
4645 re_comp_buf.buffer = (unsigned char *) malloc (200);
4646 if (re_comp_buf.buffer == NULL)
4647 return "Memory exhausted";
4648 re_comp_buf.allocated = 200;
4649
4650 re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
4651 if (re_comp_buf.fastmap == NULL)
4652 return "Memory exhausted";
4653 }
4654
4655 /* Since `re_exec' always passes NULL for the `regs' argument, we
4656 don't need to initialize the pattern buffer fields which affect it. */
4657
4658 /* Match anchors at newlines. */
4659 re_comp_buf.newline_anchor = 1;
4660
4661 ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
4662
4663 /* Yes, we're discarding `const' here. */
4664 return (char *) re_error_msg[(int) ret];
4665}
4666
4667
4668int
4669re_exec (s)
4670 const char *s;
4671{
4672 const int len = strlen (s);
4673 return
4674 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
4675}
4676#endif /* not emacs and not _POSIX_SOURCE */
4677
4678/* POSIX.2 functions. Don't define these for Emacs. */
4679
4680#ifndef emacs
4681
4682/* regcomp takes a regular expression as a string and compiles it.
4683
4684 PREG is a regex_t *. We do not expect any fields to be initialized,
4685 since POSIX says we shouldn't. Thus, we set
4686
4687 `buffer' to the compiled pattern;
4688 `used' to the length of the compiled pattern;
4689 `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
4690 REG_EXTENDED bit in CFLAGS is set; otherwise, to
4691 RE_SYNTAX_POSIX_BASIC;
4692 `newline_anchor' to REG_NEWLINE being set in CFLAGS;
4693 `fastmap' and `fastmap_accurate' to zero;
4694 `re_nsub' to the number of subexpressions in PATTERN.
4695
4696 PATTERN is the address of the pattern string.
4697
4698 CFLAGS is a series of bits which affect compilation.
4699
4700 If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
4701 use POSIX basic syntax.
4702
4703 If REG_NEWLINE is set, then . and [^...] don't match newline.
4704 Also, regexec will try a match beginning after every newline.
4705
4706 If REG_ICASE is set, then we considers upper- and lowercase
4707 versions of letters to be equivalent when matching.
4708
4709 If REG_NOSUB is set, then when PREG is passed to regexec, that
4710 routine will report only success or failure, and nothing about the
4711 registers.
4712
4713 It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
4714 the return codes and their meanings.) */
4715
4716int
4717regcomp (preg, pattern, cflags)
4718 regex_t *preg;
4719 const char *pattern;
4720 int cflags;
4721{
4722 reg_errcode_t ret;
4723 unsigned syntax
4724 = (cflags & REG_EXTENDED) ?
4725 RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
4726
4727 /* regex_compile will allocate the space for the compiled pattern. */
4728 preg->buffer = 0;
4729 preg->allocated = 0;
4730
4731 /* Don't bother to use a fastmap when searching. This simplifies the
4732 REG_NEWLINE case: if we used a fastmap, we'd have to put all the
4733 characters after newlines into the fastmap. This way, we just try
4734 every character. */
4735 preg->fastmap = 0;
4736
4737 if (cflags & REG_ICASE)
4738 {
4739 unsigned i;
4740
4741 preg->translate = (char *) malloc (CHAR_SET_SIZE);
4742 if (preg->translate == NULL)
4743 return (int) REG_ESPACE;
4744
4745 /* Map uppercase characters to corresponding lowercase ones. */
4746 for (i = 0; i < CHAR_SET_SIZE; i++)
4747 preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
4748 }
4749 else
4750 preg->translate = NULL;
4751
4752 /* If REG_NEWLINE is set, newlines are treated differently. */
4753 if (cflags & REG_NEWLINE)
4754 { /* REG_NEWLINE implies neither . nor [^...] match newline. */
4755 syntax &= ~RE_DOT_NEWLINE;
4756 syntax |= RE_HAT_LISTS_NOT_NEWLINE;
4757 /* It also changes the matching behavior. */
4758 preg->newline_anchor = 1;
4759 }
4760 else
4761 preg->newline_anchor = 0;
4762
4763 preg->no_sub = !!(cflags & REG_NOSUB);
4764
4765 /* POSIX says a null character in the pattern terminates it, so we
4766 can use strlen here in compiling the pattern. */
4767 ret = regex_compile (pattern, strlen (pattern), syntax, preg);
4768
4769 /* POSIX doesn't distinguish between an unmatched open-group and an
4770 unmatched close-group: both are REG_EPAREN. */
4771 if (ret == REG_ERPAREN) ret = REG_EPAREN;
4772
4773 return (int) ret;
4774}
4775
4776
4777/* regexec searches for a given pattern, specified by PREG, in the
4778 string STRING.
4779
4780 If NMATCH is zero or REG_NOSUB was set in the cflags argument to
4781 `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
4782 least NMATCH elements, and we set them to the offsets of the
4783 corresponding matched substrings.
4784
4785 EFLAGS specifies `execution flags' which affect matching: if
4786 REG_NOTBOL is set, then ^ does not match at the beginning of the
4787 string; if REG_NOTEOL is set, then $ does not match at the end.
4788
4789 We return 0 if we find a match and REG_NOMATCH if not. */
4790
4791int
4792regexec (preg, string, nmatch, pmatch, eflags)
4793 const regex_t *preg;
4794 const char *string;
4795 size_t nmatch;
4796 regmatch_t pmatch[];
4797 int eflags;
4798{
4799 int ret;
4800 struct re_registers regs;
4801 regex_t private_preg;
4802 int len = strlen (string);
4803 boolean want_reg_info = !preg->no_sub && nmatch > 0;
4804
4805 private_preg = *preg;
4806
4807 private_preg.not_bol = !!(eflags & REG_NOTBOL);
4808 private_preg.not_eol = !!(eflags & REG_NOTEOL);
4809
4810 /* The user has told us exactly how many registers to return
4811 information about, via `nmatch'. We have to pass that on to the
4812 matching routines. */
4813 private_preg.regs_allocated = REGS_FIXED;
4814
4815 if (want_reg_info)
4816 {
4817 regs.num_regs = nmatch;
4818 regs.start = TALLOC (nmatch, regoff_t);
4819 regs.end = TALLOC (nmatch, regoff_t);
4820 if (regs.start == NULL || regs.end == NULL)
4821 return (int) REG_NOMATCH;
4822 }
4823
4824 /* Perform the searching operation. */
4825 ret = re_search (&private_preg, string, len,
4826 /* start: */ 0, /* range: */ len,
4827 want_reg_info ? &regs : (struct re_registers *) 0);
4828
4829 /* Copy the register information to the POSIX structure. */
4830 if (want_reg_info)
4831 {
4832 if (ret >= 0)
4833 {
4834 unsigned r;
4835
4836 for (r = 0; r < nmatch; r++)
4837 {
4838 pmatch[r].rm_so = regs.start[r];
4839 pmatch[r].rm_eo = regs.end[r];
4840 }
4841 }
4842
4843 /* If we needed the temporary register info, free the space now. */
4844 free (regs.start);
4845 free (regs.end);
4846 }
4847
4848 /* We want zero return to mean success, unlike `re_search'. */
4849 return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
4850}
4851
4852
4853/* Returns a message corresponding to an error code, ERRCODE, returned
4854 from either regcomp or regexec. We don't use PREG here. */
4855
4856size_t
4857regerror (errcode, preg, errbuf, errbuf_size)
4858 int errcode;
4859 const regex_t *preg;
4860 char *errbuf;
4861 size_t errbuf_size;
4862{
4863 const char *msg;
4864 size_t msg_size;
4865
4866 if (errcode < 0
4867 || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0])))
4868 /* Only error codes returned by the rest of the code should be passed
4869 to this routine. If we are given anything else, or if other regex
4870 code generates an invalid error code, then the program has a bug.
4871 Dump core so we can fix it. */
4872 abort ();
4873
4874 msg = re_error_msg[errcode];
4875
4876 /* POSIX doesn't require that we do anything in this case, but why
4877 not be nice. */
4878 if (! msg)
4879 msg = "Success";
4880
4881 msg_size = strlen (msg) + 1; /* Includes the null. */
4882
4883 if (errbuf_size != 0)
4884 {
4885 if (msg_size > errbuf_size)
4886 {
4887 strncpy (errbuf, msg, errbuf_size - 1);
4888 errbuf[errbuf_size - 1] = 0;
4889 }
4890 else
4891 strcpy (errbuf, msg);
4892 }
4893
4894 return msg_size;
4895}
4896
4897
4898/* Free dynamically allocated space used by PREG. */
4899
4900void
4901regfree (preg)
4902 regex_t *preg;
4903{
4904 if (preg->buffer != NULL)
4905 free (preg->buffer);
4906 preg->buffer = NULL;
4907
4908 preg->allocated = 0;
4909 preg->used = 0;
4910
4911 if (preg->fastmap != NULL)
4912 free (preg->fastmap);
4913 preg->fastmap = NULL;
4914 preg->fastmap_accurate = 0;
4915
4916 if (preg->translate != NULL)
4917 free (preg->translate);
4918 preg->translate = NULL;
4919}
4920
4921#endif /* not emacs */
4922
4923/*
4924Local variables:
4925make-backup-files: t
4926version-control: t
4927trim-versions-without-asking: nil
4928End:
4929*/
diff --git a/win32/regex.h b/win32/regex.h
new file mode 100644
index 000000000..6eb64f140
--- /dev/null
+++ b/win32/regex.h
@@ -0,0 +1,490 @@
1/* Definitions for data structures and routines for the regular
2 expression library, version 0.12.
3
4 Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#ifndef __REGEXP_LIBRARY_H__
21#define __REGEXP_LIBRARY_H__
22
23/* POSIX says that <sys/types.h> must be included (by the caller) before
24 <regex.h>. */
25
26#ifdef VMS
27/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
28 should be there. */
29#include <stddef.h>
30#endif
31
32
33/* The following bits are used to determine the regexp syntax we
34 recognize. The set/not-set meanings are chosen so that Emacs syntax
35 remains the value 0. The bits are given in alphabetical order, and
36 the definitions shifted by one from the previous bit; thus, when we
37 add or remove a bit, only one other definition need change. */
38typedef unsigned reg_syntax_t;
39
40/* If this bit is not set, then \ inside a bracket expression is literal.
41 If set, then such a \ quotes the following character. */
42#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
43
44/* If this bit is not set, then + and ? are operators, and \+ and \? are
45 literals.
46 If set, then \+ and \? are operators and + and ? are literals. */
47#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
48
49/* If this bit is set, then character classes are supported. They are:
50 [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
51 [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
52 If not set, then character classes are not supported. */
53#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
54
55/* If this bit is set, then ^ and $ are always anchors (outside bracket
56 expressions, of course).
57 If this bit is not set, then it depends:
58 ^ is an anchor if it is at the beginning of a regular
59 expression or after an open-group or an alternation operator;
60 $ is an anchor if it is at the end of a regular expression, or
61 before a close-group or an alternation operator.
62
63 This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
64 POSIX draft 11.2 says that * etc. in leading positions is undefined.
65 We already implemented a previous draft which made those constructs
66 invalid, though, so we haven't changed the code back. */
67#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
68
69/* If this bit is set, then special characters are always special
70 regardless of where they are in the pattern.
71 If this bit is not set, then special characters are special only in
72 some contexts; otherwise they are ordinary. Specifically,
73 * + ? and intervals are only special when not after the beginning,
74 open-group, or alternation operator. */
75#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
76
77/* If this bit is set, then *, +, ?, and { cannot be first in an re or
78 immediately after an alternation or begin-group operator. */
79#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
80
81/* If this bit is set, then . matches newline.
82 If not set, then it doesn't. */
83#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
84
85/* If this bit is set, then . doesn't match NUL.
86 If not set, then it does. */
87#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
88
89/* If this bit is set, nonmatching lists [^...] do not match newline.
90 If not set, they do. */
91#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
92
93/* If this bit is set, either \{...\} or {...} defines an
94 interval, depending on RE_NO_BK_BRACES.
95 If not set, \{, \}, {, and } are literals. */
96#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
97
98/* If this bit is set, +, ? and | aren't recognized as operators.
99 If not set, they are. */
100#define RE_LIMITED_OPS (RE_INTERVALS << 1)
101
102/* If this bit is set, newline is an alternation operator.
103 If not set, newline is literal. */
104#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
105
106/* If this bit is set, then `{...}' defines an interval, and \{ and \}
107 are literals.
108 If not set, then `\{...\}' defines an interval. */
109#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
110
111/* If this bit is set, (...) defines a group, and \( and \) are literals.
112 If not set, \(...\) defines a group, and ( and ) are literals. */
113#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
114
115/* If this bit is set, then \<digit> matches <digit>.
116 If not set, then \<digit> is a back-reference. */
117#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
118
119/* If this bit is set, then | is an alternation operator, and \| is literal.
120 If not set, then \| is an alternation operator, and | is literal. */
121#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
122
123/* If this bit is set, then an ending range point collating higher
124 than the starting range point, as in [z-a], is invalid.
125 If not set, then when ending range point collates higher than the
126 starting range point, the range is ignored. */
127#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
128
129/* If this bit is set, then an unmatched ) is ordinary.
130 If not set, then an unmatched ) is invalid. */
131#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
132
133/* This global variable defines the particular regexp syntax to use (for
134 some interfaces). When a regexp is compiled, the syntax used is
135 stored in the pattern buffer, so changing this does not affect
136 already-compiled regexps. */
137extern reg_syntax_t re_syntax_options;
138
139/* Define combinations of the above bits for the standard possibilities.
140 (The [[[ comments delimit what gets put into the Texinfo file, so
141 don't delete them!) */
142/* [[[begin syntaxes]]] */
143#define RE_SYNTAX_EMACS 0
144
145#define RE_SYNTAX_AWK \
146 (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
147 | RE_NO_BK_PARENS | RE_NO_BK_REFS \
148 | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
149 | RE_UNMATCHED_RIGHT_PAREN_ORD)
150
151#define RE_SYNTAX_POSIX_AWK \
152 (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
153
154#define RE_SYNTAX_GREP \
155 (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
156 | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
157 | RE_NEWLINE_ALT)
158
159#define RE_SYNTAX_EGREP \
160 (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
161 | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
162 | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
163 | RE_NO_BK_VBAR)
164
165#define RE_SYNTAX_POSIX_EGREP \
166 (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
167
168/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
169#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
170
171#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
172
173/* Syntax bits common to both basic and extended POSIX regex syntax. */
174#define _RE_SYNTAX_POSIX_COMMON \
175 (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
176 | RE_INTERVALS | RE_NO_EMPTY_RANGES)
177
178#define RE_SYNTAX_POSIX_BASIC \
179 (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
180
181/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
182 RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
183 isn't minimal, since other operators, such as \`, aren't disabled. */
184#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
185 (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
186
187#define RE_SYNTAX_POSIX_EXTENDED \
188 (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
189 | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
190 | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
191 | RE_UNMATCHED_RIGHT_PAREN_ORD)
192
193/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
194 replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
195#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
196 (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
197 | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
198 | RE_NO_BK_PARENS | RE_NO_BK_REFS \
199 | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
200/* [[[end syntaxes]]] */
201
202/* Maximum number of duplicates an interval can allow. Some systems
203 (erroneously) define this in other header files, but we want our
204 value, so remove any previous define. */
205#ifdef RE_DUP_MAX
206#undef RE_DUP_MAX
207#endif
208#define RE_DUP_MAX ((1 << 15) - 1)
209
210
211/* POSIX `cflags' bits (i.e., information for `regcomp'). */
212
213/* If this bit is set, then use extended regular expression syntax.
214 If not set, then use basic regular expression syntax. */
215#define REG_EXTENDED 1
216
217/* If this bit is set, then ignore case when matching.
218 If not set, then case is significant. */
219#define REG_ICASE (REG_EXTENDED << 1)
220
221/* If this bit is set, then anchors do not match at newline
222 characters in the string.
223 If not set, then anchors do match at newlines. */
224#define REG_NEWLINE (REG_ICASE << 1)
225
226/* If this bit is set, then report only success or fail in regexec.
227 If not set, then returns differ between not matching and errors. */
228#define REG_NOSUB (REG_NEWLINE << 1)
229
230
231/* POSIX `eflags' bits (i.e., information for regexec). */
232
233/* If this bit is set, then the beginning-of-line operator doesn't match
234 the beginning of the string (presumably because it's not the
235 beginning of a line).
236 If not set, then the beginning-of-line operator does match the
237 beginning of the string. */
238#define REG_NOTBOL 1
239
240/* Like REG_NOTBOL, except for the end-of-line. */
241#define REG_NOTEOL (1 << 1)
242
243
244/* If any error codes are removed, changed, or added, update the
245 `re_error_msg' table in regex.c. */
246typedef enum
247{
248 REG_NOERROR = 0, /* Success. */
249 REG_NOMATCH, /* Didn't find a match (for regexec). */
250
251 /* POSIX regcomp return error codes. (In the order listed in the
252 standard.) */
253 REG_BADPAT, /* Invalid pattern. */
254 REG_ECOLLATE, /* Not implemented. */
255 REG_ECTYPE, /* Invalid character class name. */
256 REG_EESCAPE, /* Trailing backslash. */
257 REG_ESUBREG, /* Invalid back reference. */
258 REG_EBRACK, /* Unmatched left bracket. */
259 REG_EPAREN, /* Parenthesis imbalance. */
260 REG_EBRACE, /* Unmatched \{. */
261 REG_BADBR, /* Invalid contents of \{\}. */
262 REG_ERANGE, /* Invalid range end. */
263 REG_ESPACE, /* Ran out of memory. */
264 REG_BADRPT, /* No preceding re for repetition op. */
265
266 /* Error codes we've added. */
267 REG_EEND, /* Premature end. */
268 REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
269 REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
270} reg_errcode_t;
271
272/* This data structure represents a compiled pattern. Before calling
273 the pattern compiler, the fields `buffer', `allocated', `fastmap',
274 `translate', and `no_sub' can be set. After the pattern has been
275 compiled, the `re_nsub' field is available. All other fields are
276 private to the regex routines. */
277
278struct re_pattern_buffer
279{
280/* [[[begin pattern_buffer]]] */
281 /* Space that holds the compiled pattern. It is declared as
282 `unsigned char *' because its elements are
283 sometimes used as array indexes. */
284 unsigned char *buffer;
285
286 /* Number of bytes to which `buffer' points. */
287 unsigned long allocated;
288
289 /* Number of bytes actually used in `buffer'. */
290 unsigned long used;
291
292 /* Syntax setting with which the pattern was compiled. */
293 reg_syntax_t syntax;
294
295 /* Pointer to a fastmap, if any, otherwise zero. re_search uses
296 the fastmap, if there is one, to skip over impossible
297 starting points for matches. */
298 char *fastmap;
299
300 /* Either a translate table to apply to all characters before
301 comparing them, or zero for no translation. The translation
302 is applied to a pattern when it is compiled and to a string
303 when it is matched. */
304 char *translate;
305
306 /* Number of subexpressions found by the compiler. */
307 size_t re_nsub;
308
309 /* Zero if this pattern cannot match the empty string, one else.
310 Well, in truth it's used only in `re_search_2', to see
311 whether or not we should use the fastmap, so we don't set
312 this absolutely perfectly; see `re_compile_fastmap' (the
313 `duplicate' case). */
314 unsigned can_be_null : 1;
315
316 /* If REGS_UNALLOCATED, allocate space in the `regs' structure
317 for `max (RE_NREGS, re_nsub + 1)' groups.
318 If REGS_REALLOCATE, reallocate space if necessary.
319 If REGS_FIXED, use what's there. */
320#define REGS_UNALLOCATED 0
321#define REGS_REALLOCATE 1
322#define REGS_FIXED 2
323 unsigned regs_allocated : 2;
324
325 /* Set to zero when `regex_compile' compiles a pattern; set to one
326 by `re_compile_fastmap' if it updates the fastmap. */
327 unsigned fastmap_accurate : 1;
328
329 /* If set, `re_match_2' does not return information about
330 subexpressions. */
331 unsigned no_sub : 1;
332
333 /* If set, a beginning-of-line anchor doesn't match at the
334 beginning of the string. */
335 unsigned not_bol : 1;
336
337 /* Similarly for an end-of-line anchor. */
338 unsigned not_eol : 1;
339
340 /* If true, an anchor at a newline matches. */
341 unsigned newline_anchor : 1;
342
343/* [[[end pattern_buffer]]] */
344};
345
346typedef struct re_pattern_buffer regex_t;
347
348
349/* search.c (search_buffer) in Emacs needs this one opcode value. It is
350 defined both in `regex.c' and here. */
351#define RE_EXACTN_VALUE 1
352
353/* Type for byte offsets within the string. POSIX mandates this. */
354typedef int regoff_t;
355
356
357/* This is the structure we store register match data in. See
358 regex.texinfo for a full description of what registers match. */
359struct re_registers
360{
361 unsigned num_regs;
362 regoff_t *start;
363 regoff_t *end;
364};
365
366
367/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
368 `re_match_2' returns information about at least this many registers
369 the first time a `regs' structure is passed. */
370#ifndef RE_NREGS
371#define RE_NREGS 30
372#endif
373
374
375/* POSIX specification for registers. Aside from the different names than
376 `re_registers', POSIX uses an array of structures, instead of a
377 structure of arrays. */
378typedef struct
379{
380 regoff_t rm_so; /* Byte offset from string's start to substring's start. */
381 regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
382} regmatch_t;
383
384/* Declarations for routines. */
385
386/* To avoid duplicating every routine declaration -- once with a
387 prototype (if we are ANSI), and once without (if we aren't) -- we
388 use the following macro to declare argument types. This
389 unfortunately clutters up the declarations a bit, but I think it's
390 worth it. */
391
392#if __STDC__
393
394#define _RE_ARGS(args) args
395
396#else /* not __STDC__ */
397
398#define _RE_ARGS(args) ()
399
400#endif /* not __STDC__ */
401
402/* Sets the current default syntax to SYNTAX, and return the old syntax.
403 You can also simply assign to the `re_syntax_options' variable. */
404extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
405
406/* Compile the regular expression PATTERN, with length LENGTH
407 and syntax given by the global `re_syntax_options', into the buffer
408 BUFFER. Return NULL if successful, and an error string if not. */
409extern const char *re_compile_pattern
410 _RE_ARGS ((const char *pattern, int length,
411 struct re_pattern_buffer *buffer));
412
413
414/* Compile a fastmap for the compiled pattern in BUFFER; used to
415 accelerate searches. Return 0 if successful and -2 if was an
416 internal error. */
417extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
418
419
420/* Search in the string STRING (with length LENGTH) for the pattern
421 compiled into BUFFER. Start searching at position START, for RANGE
422 characters. Return the starting position of the match, -1 for no
423 match, or -2 for an internal error. Also return register
424 information in REGS (if REGS and BUFFER->no_sub are nonzero). */
425extern int re_search
426 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
427 int length, int start, int range, struct re_registers *regs));
428
429
430/* Like `re_search', but search in the concatenation of STRING1 and
431 STRING2. Also, stop searching at index START + STOP. */
432extern int re_search_2
433 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
434 int length1, const char *string2, int length2,
435 int start, int range, struct re_registers *regs, int stop));
436
437
438/* Like `re_search', but return how many characters in STRING the regexp
439 in BUFFER matched, starting at position START. */
440extern int re_match
441 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
442 int length, int start, struct re_registers *regs));
443
444
445/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
446extern int re_match_2
447 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
448 int length1, const char *string2, int length2,
449 int start, struct re_registers *regs, int stop));
450
451
452/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
453 ENDS. Subsequent matches using BUFFER and REGS will use this memory
454 for recording register information. STARTS and ENDS must be
455 allocated with malloc, and must each be at least `NUM_REGS * sizeof
456 (regoff_t)' bytes long.
457
458 If NUM_REGS == 0, then subsequent matches should allocate their own
459 register data.
460
461 Unless this function is called, the first search or match using
462 PATTERN_BUFFER will allocate its own register data, without
463 freeing the old data. */
464extern void re_set_registers
465 _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
466 unsigned num_regs, regoff_t *starts, regoff_t *ends));
467
468/* 4.2 bsd compatibility. */
469extern char *re_comp _RE_ARGS ((const char *));
470extern int re_exec _RE_ARGS ((const char *));
471
472/* POSIX compatibility. */
473extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
474extern int regexec
475 _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
476 regmatch_t pmatch[], int eflags));
477extern size_t regerror
478 _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
479 size_t errbuf_size));
480extern void regfree _RE_ARGS ((regex_t *preg));
481
482#endif /* not __REGEXP_LIBRARY_H__ */
483
484/*
485Local variables:
486make-backup-files: t
487version-control: t
488trim-versions-without-asking: nil
489End:
490*/
diff --git a/win32/sched.h b/win32/sched.h
new file mode 100644
index 000000000..128bfe698
--- /dev/null
+++ b/win32/sched.h
@@ -0,0 +1 @@
static inline void sched_yield(void) {}
diff --git a/win32/statfs.c b/win32/statfs.c
new file mode 100644
index 000000000..9e6703849
--- /dev/null
+++ b/win32/statfs.c
@@ -0,0 +1,80 @@
1#include <sys/vfs.h>
2#include "libbb.h"
3
4/*
5 * Code from libguestfs (with addition of GetVolumeInformation call)
6 */
7int statfs(const char *file, struct statfs *buf)
8{
9 ULONGLONG free_bytes_available; /* for user - similar to bavail */
10 ULONGLONG total_number_of_bytes;
11 ULONGLONG total_number_of_free_bytes; /* for everyone - bfree */
12 DWORD serial, namelen, flags;
13 char drive[4], fsname[100];
14
15 if ( !GetDiskFreeSpaceEx(file, (PULARGE_INTEGER) &free_bytes_available,
16 (PULARGE_INTEGER) &total_number_of_bytes,
17 (PULARGE_INTEGER) &total_number_of_free_bytes) ) {
18 return -1;
19 }
20
21 if ( strlen(file) == 2 && file[1] == ':' ) {
22 /* GetVolumeInformation wants a backslash */
23 strcat(strcpy(drive, file), "\\");
24 file = drive;
25 }
26
27 if ( !GetVolumeInformation(file, NULL, 0, &serial, &namelen, &flags,
28 fsname, 100) ) {
29 return -1;
30 }
31
32 /* XXX I couldn't determine how to get block size. MSDN has a
33 * unhelpful hard-coded list here:
34 * http://support.microsoft.com/kb/140365
35 * but this depends on the filesystem type, the size of the disk and
36 * the version of Windows. So this code assumes the disk is NTFS
37 * and the version of Windows is >= Win2K.
38 */
39 if (total_number_of_bytes < UINT64_C(16) * 1024 * 1024 * 1024 * 1024)
40 buf->f_bsize = 4096;
41 else if (total_number_of_bytes < UINT64_C(32) * 1024 * 1024 * 1024 * 1024)
42 buf->f_bsize = 8192;
43 else if (total_number_of_bytes < UINT64_C(64) * 1024 * 1024 * 1024 * 1024)
44 buf->f_bsize = 16384;
45 else if (total_number_of_bytes < UINT64_C(128) * 1024 * 1024 * 1024 * 1024)
46 buf->f_bsize = 32768;
47 else
48 buf->f_bsize = 65536;
49
50 /*
51 * Valid filesystem names don't seem to be documented. The following
52 * are present in Wine.
53 */
54 if ( strcmp(fsname, "NTFS") == 0 ) {
55 buf->f_type = 0x5346544e;
56 }
57 else if ( strcmp(fsname, "FAT") == 0 || strcmp(fsname, "FAT32") == 0 ) {
58 buf->f_type = 0x4006;
59 }
60 else if ( strcmp(fsname, "CDFS") == 0 ) {
61 buf->f_type = 0x9660;
62 }
63 else {
64 buf->f_type = 0;
65 }
66
67 /* As with stat, -1 indicates a field is not known. */
68 buf->f_frsize = buf->f_bsize;
69 buf->f_blocks = total_number_of_bytes / buf->f_bsize;
70 buf->f_bfree = total_number_of_free_bytes / buf->f_bsize;
71 buf->f_bavail = free_bytes_available / buf->f_bsize;
72 buf->f_files = -1;
73 buf->f_ffree = -1;
74 buf->f_favail = -1;
75 buf->f_fsid = serial;
76 buf->f_flag = -1;
77 buf->f_namelen = namelen;
78
79 return 0;
80}
diff --git a/win32/strptime.c b/win32/strptime.c
new file mode 100644
index 000000000..89fb8b736
--- /dev/null
+++ b/win32/strptime.c
@@ -0,0 +1,646 @@
1/* Copyright (C) 2002, 2004-2005, 2007, 2009-2014 Free Software Foundation,
2 Inc.
3 This file is part of the GNU C Library.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, see <http://www.gnu.org/licenses/>. */
17
18/*
19 * File from gnulib (http://www.gnu.org/software/gnulib/), processed with
20 * coan source -U_LIBC -U_NL_CURRENT -UHAVE_TM_GMTOFF strptime.c
21 * and lightly edited.
22 */
23
24#include <time.h>
25
26#include <assert.h>
27#include <ctype.h>
28#include <limits.h>
29#include <string.h>
30#include <stdbool.h>
31
32
33enum ptime_locale_status { not, loc, raw };
34
35
36
37#define match_char(ch1, ch2) if (ch1 != ch2) return NULL
38/* Oh come on. Get a reasonable compiler. */
39# define match_string(cs1, s2) \
40 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
41/* We intentionally do not use isdigit() for testing because this will
42 lead to problems with the wide character version. */
43#define get_number(from, to, n) \
44 do { \
45 int __n = n; \
46 val = 0; \
47 while (*rp == ' ') \
48 ++rp; \
49 if (*rp < '0' || *rp > '9') \
50 return NULL; \
51 do { \
52 val *= 10; \
53 val += *rp++ - '0'; \
54 } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \
55 if (val < from || val > to) \
56 return NULL; \
57 } while (0)
58# define get_alt_number(from, to, n) \
59 /* We don't have the alternate representation. */ \
60 get_number(from, to, n)
61#define recursive(new_fmt) \
62 (*(new_fmt) != '\0' \
63 && (rp = __strptime_internal (rp, (new_fmt), tm, \
64 decided, era_cnt LOCALE_ARG)) != NULL)
65
66
67static char const weekday_name[][10] =
68 {
69 "Sunday", "Monday", "Tuesday", "Wednesday",
70 "Thursday", "Friday", "Saturday"
71 };
72static char const ab_weekday_name[][4] =
73 {
74 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
75 };
76static char const month_name[][10] =
77 {
78 "January", "February", "March", "April", "May", "June",
79 "July", "August", "September", "October", "November", "December"
80 };
81static char const ab_month_name[][4] =
82 {
83 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
84 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
85 };
86# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
87# define HERE_D_FMT "%m/%d/%y"
88# define HERE_AM_STR "AM"
89# define HERE_PM_STR "PM"
90# define HERE_T_FMT_AMPM "%I:%M:%S %p"
91# define HERE_T_FMT "%H:%M:%S"
92
93static const unsigned short int __mon_yday[2][13] =
94 {
95 /* Normal years. */
96 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
97 /* Leap years. */
98 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
99 };
100
101# define LOCALE_PARAM
102# define LOCALE_ARG
103# define LOCALE_PARAM_DECL
104# define LOCALE_PARAM_PROTO
105# define HELPER_LOCALE_ARG
106# define ISSPACE(Ch) isspace (Ch)
107
108
109
110
111#ifndef __isleap
112/* Nonzero if YEAR is a leap year (every 4 years,
113 except every 100th isn't, and every 400th is). */
114# define __isleap(year) \
115 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
116#endif
117
118/* Compute the day of the week. */
119static void
120day_of_the_week (struct tm *tm)
121{
122 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
123 difference between this data in the one on TM and so determine
124 the weekday. */
125 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
126 int wday = (-473
127 + (365 * (tm->tm_year - 70))
128 + (corr_year / 4)
129 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
130 + (((corr_year / 4) / 25) / 4)
131 + __mon_yday[0][tm->tm_mon]
132 + tm->tm_mday - 1);
133 tm->tm_wday = ((wday % 7) + 7) % 7;
134}
135
136/* Compute the day of the year. */
137static void
138day_of_the_year (struct tm *tm)
139{
140 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
141 + (tm->tm_mday - 1));
142}
143
144
145static char *
146__strptime_internal (rp, fmt, tm, decided, era_cnt LOCALE_PARAM)
147 const char *rp;
148 const char *fmt;
149 struct tm *tm;
150 enum ptime_locale_status *decided;
151 int era_cnt;
152 LOCALE_PARAM_DECL
153{
154
155 int cnt;
156 size_t val;
157 int have_I, is_pm;
158 int century, want_century;
159 int want_era;
160 int have_wday, want_xday;
161 int have_yday;
162 int have_mon, have_mday;
163 int have_uweek, have_wweek;
164 int week_no;
165
166 have_I = is_pm = 0;
167 century = -1;
168 want_century = 0;
169 want_era = 0;
170 week_no = 0;
171
172 have_wday = want_xday = have_yday = have_mon = have_mday = have_uweek = 0;
173 have_wweek = 0;
174
175 while (*fmt != '\0')
176 {
177 /* A white space in the format string matches 0 more or white
178 space in the input string. */
179 if (ISSPACE (*fmt))
180 {
181 while (ISSPACE (*rp))
182 ++rp;
183 ++fmt;
184 continue;
185 }
186
187 /* Any character but '%' must be matched by the same character
188 in the iput string. */
189 if (*fmt != '%')
190 {
191 match_char (*fmt++, *rp++);
192 continue;
193 }
194
195 ++fmt;
196 /* We need this for handling the 'E' modifier. */
197 start_over:
198
199 switch (*fmt++)
200 {
201 case '%':
202 /* Match the '%' character itself. */
203 match_char ('%', *rp++);
204 break;
205 case 'a':
206 case 'A':
207 /* Match day of week. */
208 for (cnt = 0; cnt < 7; ++cnt)
209 {
210 if (*decided != loc
211 && (match_string (weekday_name[cnt], rp)
212 || match_string (ab_weekday_name[cnt], rp)))
213 {
214 *decided = raw;
215 break;
216 }
217 }
218 if (cnt == 7)
219 /* Does not match a weekday name. */
220 return NULL;
221 tm->tm_wday = cnt;
222 have_wday = 1;
223 break;
224 case 'b':
225 case 'B':
226 case 'h':
227 /* Match month name. */
228 for (cnt = 0; cnt < 12; ++cnt)
229 {
230 if (match_string (month_name[cnt], rp)
231 || match_string (ab_month_name[cnt], rp))
232 {
233 *decided = raw;
234 break;
235 }
236 }
237 if (cnt == 12)
238 /* Does not match a month name. */
239 return NULL;
240 tm->tm_mon = cnt;
241 want_xday = 1;
242 break;
243 case 'c':
244 /* Match locale's date and time format. */
245 if (!recursive (HERE_D_T_FMT))
246 return NULL;
247 want_xday = 1;
248 break;
249 case 'C':
250 /* Match century number. */
251 get_number (0, 99, 2);
252 century = val;
253 want_xday = 1;
254 break;
255 case 'd':
256 case 'e':
257 /* Match day of month. */
258 get_number (1, 31, 2);
259 tm->tm_mday = val;
260 have_mday = 1;
261 want_xday = 1;
262 break;
263 case 'F':
264 if (!recursive ("%Y-%m-%d"))
265 return NULL;
266 want_xday = 1;
267 break;
268 case 'x':
269 /* Fall through. */
270 case 'D':
271 /* Match standard day format. */
272 if (!recursive (HERE_D_FMT))
273 return NULL;
274 want_xday = 1;
275 break;
276 case 'k':
277 case 'H':
278 /* Match hour in 24-hour clock. */
279 get_number (0, 23, 2);
280 tm->tm_hour = val;
281 have_I = 0;
282 break;
283 case 'l':
284 /* Match hour in 12-hour clock. GNU extension. */
285 case 'I':
286 /* Match hour in 12-hour clock. */
287 get_number (1, 12, 2);
288 tm->tm_hour = val % 12;
289 have_I = 1;
290 break;
291 case 'j':
292 /* Match day number of year. */
293 get_number (1, 366, 3);
294 tm->tm_yday = val - 1;
295 have_yday = 1;
296 break;
297 case 'm':
298 /* Match number of month. */
299 get_number (1, 12, 2);
300 tm->tm_mon = val - 1;
301 have_mon = 1;
302 want_xday = 1;
303 break;
304 case 'M':
305 /* Match minute. */
306 get_number (0, 59, 2);
307 tm->tm_min = val;
308 break;
309 case 'n':
310 case 't':
311 /* Match any white space. */
312 while (ISSPACE (*rp))
313 ++rp;
314 break;
315 case 'p':
316 /* Match locale's equivalent of AM/PM. */
317 if (!match_string (HERE_AM_STR, rp))
318 {
319 if (match_string (HERE_PM_STR, rp))
320 is_pm = 1;
321 else
322 return NULL;
323 }
324 break;
325 case 'r':
326 if (!recursive (HERE_T_FMT_AMPM))
327 return NULL;
328 break;
329 case 'R':
330 if (!recursive ("%H:%M"))
331 return NULL;
332 break;
333 case 's':
334 {
335 /* The number of seconds may be very high so we cannot use
336 the 'get_number' macro. Instead read the number
337 character for character and construct the result while
338 doing this. */
339 time_t secs = 0;
340 if (*rp < '0' || *rp > '9')
341 /* We need at least one digit. */
342 return NULL;
343
344 do
345 {
346 secs *= 10;
347 secs += *rp++ - '0';
348 }
349 while (*rp >= '0' && *rp <= '9');
350
351 if (localtime_r (&secs, tm) == NULL)
352 /* Error in function. */
353 return NULL;
354 }
355 break;
356 case 'S':
357 get_number (0, 61, 2);
358 tm->tm_sec = val;
359 break;
360 case 'X':
361 /* Fall through. */
362 case 'T':
363 if (!recursive (HERE_T_FMT))
364 return NULL;
365 break;
366 case 'u':
367 get_number (1, 7, 1);
368 tm->tm_wday = val % 7;
369 have_wday = 1;
370 break;
371 case 'g':
372 get_number (0, 99, 2);
373 /* XXX This cannot determine any field in TM. */
374 break;
375 case 'G':
376 if (*rp < '0' || *rp > '9')
377 return NULL;
378 /* XXX Ignore the number since we would need some more
379 information to compute a real date. */
380 do
381 ++rp;
382 while (*rp >= '0' && *rp <= '9');
383 break;
384 case 'U':
385 get_number (0, 53, 2);
386 week_no = val;
387 have_uweek = 1;
388 break;
389 case 'W':
390 get_number (0, 53, 2);
391 week_no = val;
392 have_wweek = 1;
393 break;
394 case 'V':
395 get_number (0, 53, 2);
396 /* XXX This cannot determine any field in TM without some
397 information. */
398 break;
399 case 'w':
400 /* Match number of weekday. */
401 get_number (0, 6, 1);
402 tm->tm_wday = val;
403 have_wday = 1;
404 break;
405 case 'y':
406 /* Match year within century. */
407 get_number (0, 99, 2);
408 /* The "Year 2000: The Millennium Rollover" paper suggests that
409 values in the range 69-99 refer to the twentieth century. */
410 tm->tm_year = val >= 69 ? val : val + 100;
411 /* Indicate that we want to use the century, if specified. */
412 want_century = 1;
413 want_xday = 1;
414 break;
415 case 'Y':
416 /* Match year including century number. */
417 get_number (0, 9999, 4);
418 tm->tm_year = val - 1900;
419 want_century = 0;
420 want_xday = 1;
421 break;
422 case 'Z':
423 /* XXX How to handle this? */
424 break;
425 case 'z':
426 /* We recognize two formats: if two digits are given, these
427 specify hours. If fours digits are used, minutes are
428 also specified. */
429 {
430 bool neg;
431 int n;
432
433 val = 0;
434 while (*rp == ' ')
435 ++rp;
436 if (*rp != '+' && *rp != '-')
437 return NULL;
438 neg = *rp++ == '-';
439 n = 0;
440 while (n < 4 && *rp >= '0' && *rp <= '9')
441 {
442 val = val * 10 + *rp++ - '0';
443 ++n;
444 }
445 if (n == 2)
446 val *= 100;
447 else if (n != 4)
448 /* Only two or four digits recognized. */
449 return NULL;
450 else
451 {
452 /* We have to convert the minutes into decimal. */
453 if (val % 100 >= 60)
454 return NULL;
455 val = (val / 100) * 100 + ((val % 100) * 50) / 30;
456 }
457 if (val > 1200)
458 return NULL;
459 }
460 break;
461 case 'E':
462 /* We have no information about the era format. Just use
463 the normal format. */
464 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
465 && *fmt != 'x' && *fmt != 'X')
466 /* This is an illegal format. */
467 return NULL;
468
469 goto start_over;
470 case 'O':
471 switch (*fmt++)
472 {
473 case 'd':
474 case 'e':
475 /* Match day of month using alternate numeric symbols. */
476 get_alt_number (1, 31, 2);
477 tm->tm_mday = val;
478 have_mday = 1;
479 want_xday = 1;
480 break;
481 case 'H':
482 /* Match hour in 24-hour clock using alternate numeric
483 symbols. */
484 get_alt_number (0, 23, 2);
485 tm->tm_hour = val;
486 have_I = 0;
487 break;
488 case 'I':
489 /* Match hour in 12-hour clock using alternate numeric
490 symbols. */
491 get_alt_number (1, 12, 2);
492 tm->tm_hour = val % 12;
493 have_I = 1;
494 break;
495 case 'm':
496 /* Match month using alternate numeric symbols. */
497 get_alt_number (1, 12, 2);
498 tm->tm_mon = val - 1;
499 have_mon = 1;
500 want_xday = 1;
501 break;
502 case 'M':
503 /* Match minutes using alternate numeric symbols. */
504 get_alt_number (0, 59, 2);
505 tm->tm_min = val;
506 break;
507 case 'S':
508 /* Match seconds using alternate numeric symbols. */
509 get_alt_number (0, 61, 2);
510 tm->tm_sec = val;
511 break;
512 case 'U':
513 get_alt_number (0, 53, 2);
514 week_no = val;
515 have_uweek = 1;
516 break;
517 case 'W':
518 get_alt_number (0, 53, 2);
519 week_no = val;
520 have_wweek = 1;
521 break;
522 case 'V':
523 get_alt_number (0, 53, 2);
524 /* XXX This cannot determine any field in TM without
525 further information. */
526 break;
527 case 'w':
528 /* Match number of weekday using alternate numeric symbols. */
529 get_alt_number (0, 6, 1);
530 tm->tm_wday = val;
531 have_wday = 1;
532 break;
533 case 'y':
534 /* Match year within century using alternate numeric symbols. */
535 get_alt_number (0, 99, 2);
536 tm->tm_year = val >= 69 ? val : val + 100;
537 want_xday = 1;
538 break;
539 default:
540 return NULL;
541 }
542 break;
543 default:
544 return NULL;
545 }
546 }
547
548 if (have_I && is_pm)
549 tm->tm_hour += 12;
550
551 if (century != -1)
552 {
553 if (want_century)
554 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
555 else
556 /* Only the century, but not the year. Strange, but so be it. */
557 tm->tm_year = (century - 19) * 100;
558 }
559
560 if (era_cnt != -1)
561 {
562 }
563 else
564 if (want_era)
565 {
566 /* No era found but we have seen an E modifier. Rectify some
567 values. */
568 if (want_century && century == -1 && tm->tm_year < 69)
569 tm->tm_year += 100;
570 }
571
572 if (want_xday && !have_wday)
573 {
574 if ( !(have_mon && have_mday) && have_yday)
575 {
576 /* We don't have tm_mon and/or tm_mday, compute them. */
577 int t_mon = 0;
578 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
579 t_mon++;
580 if (!have_mon)
581 tm->tm_mon = t_mon - 1;
582 if (!have_mday)
583 tm->tm_mday =
584 (tm->tm_yday
585 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
586 }
587 day_of_the_week (tm);
588 }
589
590 if (want_xday && !have_yday)
591 day_of_the_year (tm);
592
593 if ((have_uweek || have_wweek) && have_wday)
594 {
595 int save_wday = tm->tm_wday;
596 int save_mday = tm->tm_mday;
597 int save_mon = tm->tm_mon;
598 int w_offset = have_uweek ? 0 : 1;
599
600 tm->tm_mday = 1;
601 tm->tm_mon = 0;
602 day_of_the_week (tm);
603 if (have_mday)
604 tm->tm_mday = save_mday;
605 if (have_mon)
606 tm->tm_mon = save_mon;
607
608 if (!have_yday)
609 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
610 + (week_no - 1) *7
611 + save_wday - w_offset);
612
613 if (!have_mday || !have_mon)
614 {
615 int t_mon = 0;
616 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon]
617 <= tm->tm_yday)
618 t_mon++;
619 if (!have_mon)
620 tm->tm_mon = t_mon - 1;
621 if (!have_mday)
622 tm->tm_mday =
623 (tm->tm_yday
624 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
625 }
626
627 tm->tm_wday = save_wday;
628 }
629
630 return (char *) rp;
631}
632
633
634char *
635strptime (buf, format, tm LOCALE_PARAM)
636 const char *buf;
637 const char *format;
638 struct tm *tm;
639 LOCALE_PARAM_DECL
640{
641 enum ptime_locale_status decided;
642
643 decided = raw;
644 return __strptime_internal (buf, format, tm, &decided, -1 LOCALE_ARG);
645}
646
diff --git a/win32/sys/ioctl.h b/win32/sys/ioctl.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/ioctl.h
diff --git a/win32/sys/mman.h b/win32/sys/mman.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/mman.h
diff --git a/win32/sys/resource.h b/win32/sys/resource.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/resource.h
diff --git a/win32/sys/socket.h b/win32/sys/socket.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/socket.h
diff --git a/win32/sys/statfs.h b/win32/sys/statfs.h
new file mode 100644
index 000000000..7cef6df73
--- /dev/null
+++ b/win32/sys/statfs.h
@@ -0,0 +1,23 @@
1#ifndef _SYS_STATFS_H
2#define _SYS_STATFS_H 1
3
4#include <stdint.h>
5
6struct statfs {
7 int f_type;
8 uint64_t f_bsize;
9 uint64_t f_frsize;
10 uint64_t f_blocks;
11 uint64_t f_bfree;
12 uint64_t f_bavail;
13 uint64_t f_files;
14 uint64_t f_ffree;
15 uint64_t f_favail;
16 uint64_t f_fsid;
17 uint64_t f_flag;
18 uint64_t f_namelen;
19};
20
21extern int statfs(const char *file, struct statfs *buf);
22
23#endif
diff --git a/win32/sys/syscall.h b/win32/sys/syscall.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/syscall.h
diff --git a/win32/sys/sysmacros.h b/win32/sys/sysmacros.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/sysmacros.h
diff --git a/win32/sys/times.h b/win32/sys/times.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/times.h
diff --git a/win32/sys/un.h b/win32/sys/un.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/un.h
diff --git a/win32/sys/utsname.h b/win32/sys/utsname.h
new file mode 100644
index 000000000..6f12efd58
--- /dev/null
+++ b/win32/sys/utsname.h
@@ -0,0 +1,66 @@
1/* Copyright (C) 1991,92,94,96,97,99,2002 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
18
19/*
20 * POSIX Standard: 4.4 System Identification <sys/utsname.h>
21 */
22
23#ifndef _SYS_UTSNAME_H
24#define _SYS_UTSNAME_H 1
25
26#define _UTSNAME_LENGTH 65
27
28#ifndef _UTSNAME_SYSNAME_LENGTH
29# define _UTSNAME_SYSNAME_LENGTH _UTSNAME_LENGTH
30#endif
31#ifndef _UTSNAME_NODENAME_LENGTH
32# define _UTSNAME_NODENAME_LENGTH _UTSNAME_LENGTH
33#endif
34#ifndef _UTSNAME_RELEASE_LENGTH
35# define _UTSNAME_RELEASE_LENGTH _UTSNAME_LENGTH
36#endif
37#ifndef _UTSNAME_VERSION_LENGTH
38# define _UTSNAME_VERSION_LENGTH _UTSNAME_LENGTH
39#endif
40#ifndef _UTSNAME_MACHINE_LENGTH
41# define _UTSNAME_MACHINE_LENGTH _UTSNAME_LENGTH
42#endif
43
44/* Structure describing the system and machine. */
45struct utsname
46 {
47 /* Name of the implementation of the operating system. */
48 char sysname[_UTSNAME_SYSNAME_LENGTH];
49
50 /* Name of this node on the network. */
51 char nodename[_UTSNAME_NODENAME_LENGTH];
52
53 /* Current release level of this implementation. */
54 char release[_UTSNAME_RELEASE_LENGTH];
55 /* Current version level of this release. */
56 char version[_UTSNAME_VERSION_LENGTH];
57
58 /* Name of the hardware type the system is running on. */
59 char machine[_UTSNAME_MACHINE_LENGTH];
60 };
61
62/* Put information about the system in NAME. */
63extern int uname (struct utsname *__name);
64
65
66#endif /* sys/utsname.h */
diff --git a/win32/sys/vfs.h b/win32/sys/vfs.h
new file mode 100644
index 000000000..a899db276
--- /dev/null
+++ b/win32/sys/vfs.h
@@ -0,0 +1 @@
#include <sys/statfs.h>
diff --git a/win32/sys/wait.h b/win32/sys/wait.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/wait.h
diff --git a/win32/system.c b/win32/system.c
new file mode 100644
index 000000000..c3e2c316e
--- /dev/null
+++ b/win32/system.c
@@ -0,0 +1,77 @@
1#include "libbb.h"
2
3int mingw_system(const char *cmd)
4{
5 STARTUPINFO siStartInfo;
6 PROCESS_INFORMATION piProcInfo;
7 int success;
8 int len, count;
9 char *cmd_buff = NULL;
10 const char *s;
11 char *t;
12 DWORD ret;
13
14 if ( cmd == NULL ) {
15 return 1;
16 }
17
18 /* count double quotes */
19 count = 0;
20 for ( s=cmd; *s; ++s ) {
21 if ( *s == '"' ) {
22 ++count;
23 }
24 }
25
26 len = strlen(cmd) + 10 + count;
27 if ( (cmd_buff=malloc(len)) == NULL ) {
28 return -1;
29 }
30
31 /* escape double quotes */
32 strcpy(cmd_buff, "sh -c \"");
33 for ( s=cmd,t=cmd_buff+strlen(cmd_buff); *s; ++s ) {
34 if ( *s == '"' ) {
35 *t++ = '\\';
36 }
37 *t++ = *s;
38 }
39 *t++ = '"';
40 *t = '\0';
41
42 /* Now create the child process */
43 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
44 siStartInfo.cb = sizeof(STARTUPINFO);
45 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
46 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
47 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
48 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
49
50 success = CreateProcess(NULL,
51 (LPTSTR)cmd_buff, /* command line */
52 NULL, /* process security attributes */
53 NULL, /* primary thread security attributes */
54 TRUE, /* handles are inherited */
55 0, /* creation flags */
56 NULL, /* use parent's environment */
57 NULL, /* use parent's current directory */
58 &siStartInfo, /* STARTUPINFO pointer */
59 &piProcInfo); /* receives PROCESS_INFORMATION */
60
61 if ( !success ) {
62 free(cmd_buff);
63 return 127;
64 }
65
66 free(cmd_buff);
67
68 WaitForSingleObject(piProcInfo.hProcess, INFINITE);
69
70 ret = 0;
71 GetExitCodeProcess(piProcInfo.hProcess, &ret);
72
73 CloseHandle(piProcInfo.hProcess);
74 CloseHandle(piProcInfo.hThread);
75
76 return ret;
77}
diff --git a/win32/termios.c b/win32/termios.c
new file mode 100644
index 000000000..2b1d2c761
--- /dev/null
+++ b/win32/termios.c
@@ -0,0 +1,88 @@
1#include "libbb.h"
2
3int tcsetattr(int fd UNUSED_PARAM, int mode UNUSED_PARAM, const struct termios *t UNUSED_PARAM)
4{
5 return -1;
6}
7
8int tcgetattr(int fd UNUSED_PARAM, struct termios *t UNUSED_PARAM)
9{
10 return -1;
11}
12
13int64_t FAST_FUNC read_key(int fd, char *buf UNUSED_PARAM, int timeout)
14{
15 HANDLE cin = GetStdHandle(STD_INPUT_HANDLE);
16 INPUT_RECORD record;
17 DWORD nevent_out, mode;
18 int ret = -1;
19 char *s;
20
21 if (fd != 0)
22 bb_error_msg_and_die("read_key only works on stdin");
23 if (cin == INVALID_HANDLE_VALUE)
24 return -1;
25 GetConsoleMode(cin, &mode);
26 SetConsoleMode(cin, 0);
27
28 if (timeout > 0) {
29 if (WaitForSingleObject(cin, timeout) != WAIT_OBJECT_0)
30 goto done;
31 }
32 while (1) {
33 if (!ReadConsoleInput(cin, &record, 1, &nevent_out))
34 goto done;
35 if (record.EventType != KEY_EVENT || !record.Event.KeyEvent.bKeyDown)
36 continue;
37 if (!record.Event.KeyEvent.uChar.AsciiChar) {
38 DWORD state = record.Event.KeyEvent.dwControlKeyState;
39
40 if (state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED) &&
41 (record.Event.KeyEvent.wVirtualKeyCode >= 'A' &&
42 record.Event.KeyEvent.wVirtualKeyCode <= 'Z')) {
43 ret = record.Event.KeyEvent.wVirtualKeyCode & ~0x40;
44 break;
45 }
46
47 switch (record.Event.KeyEvent.wVirtualKeyCode) {
48 case VK_DELETE: ret = KEYCODE_DELETE; goto done;
49 case VK_INSERT: ret = KEYCODE_INSERT; goto done;
50 case VK_UP: ret = KEYCODE_UP; goto done;
51 case VK_DOWN: ret = KEYCODE_DOWN; goto done;
52 case VK_RIGHT:
53 if (state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) {
54 ret = KEYCODE_CTRL_RIGHT;
55 goto done;
56 }
57 ret = KEYCODE_RIGHT;
58 goto done;
59 case VK_LEFT:
60 if (state & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) {
61 ret = KEYCODE_CTRL_LEFT;
62 goto done;
63 }
64 ret = KEYCODE_LEFT;
65 goto done;
66 case VK_HOME: ret = KEYCODE_HOME; goto done;
67 case VK_END: ret = KEYCODE_END; goto done;
68 case VK_PRIOR: ret = KEYCODE_PAGEUP; goto done;
69 case VK_NEXT: ret = KEYCODE_PAGEDOWN; goto done;
70 case VK_CAPITAL:
71 case VK_SHIFT:
72 case VK_CONTROL:
73 case VK_MENU:
74 break;
75 }
76 continue;
77 }
78 if ( (record.Event.KeyEvent.uChar.AsciiChar & 0x80) == 0x80 ) {
79 s = &record.Event.KeyEvent.uChar.AsciiChar;
80 OemToCharBuff(s, s, 1);
81 }
82 ret = record.Event.KeyEvent.uChar.AsciiChar;
83 break;
84 }
85 done:
86 SetConsoleMode(cin, mode);
87 return ret;
88}
diff --git a/win32/termios.h b/win32/termios.h
new file mode 100644
index 000000000..011a37eb9
--- /dev/null
+++ b/win32/termios.h
@@ -0,0 +1,129 @@
1/* iflag bits */
2#define IGNBRK 0x00001
3#define BRKINT 0x00002
4#define IGNPAR 0x00004
5#define IMAXBEL 0x00008
6#define INPCK 0x00010
7#define ISTRIP 0x00020
8#define INLCR 0x00040
9#define IGNCR 0x00080
10#define ICRNL 0x00100
11#define IXON 0x00400
12#define IXOFF 0x01000
13#define IUCLC 0x04000
14#define IXANY 0x08000
15#define PARMRK 0x10000
16
17/* oflag bits */
18
19#define OPOST 0x00001
20#define OLCUC 0x00002
21#define OCRNL 0x00004
22#define ONLCR 0x00008
23#define ONOCR 0x00010
24#define ONLRET 0x00020
25#define OFILL 0x00040
26#define CRDLY 0x00180
27#define CR0 0x00000
28#define CR1 0x00080
29#define CR2 0x00100
30#define CR3 0x00180
31#define NLDLY 0x00200
32#define NL0 0x00000
33#define NL1 0x00200
34#define BSDLY 0x00400
35#define BS0 0x00000
36#define BS1 0x00400
37#define TABDLY 0x01800
38#define TAB0 0x00000
39#define TAB1 0x00800
40#define TAB2 0x01000
41#define TAB3 0x01800
42#define XTABS 0x01800
43#define VTDLY 0x02000
44#define VT0 0x00000
45#define VT1 0x02000
46#define FFDLY 0x04000
47#define FF0 0x00000
48#define FF1 0x04000
49#define OFDEL 0x08000
50
51/* lflag bits */
52#define ISIG 0x0001
53#define ICANON 0x0002
54#define ECHO 0x0004
55#define ECHOE 0x0008
56#define ECHOK 0x0010
57#define ECHONL 0x0020
58#define NOFLSH 0x0040
59#define TOSTOP 0x0080
60#define IEXTEN 0x0100
61#define FLUSHO 0x0200
62#define ECHOKE 0x0400
63#define ECHOCTL 0x0800
64
65#define VDISCARD 1
66#define VEOL 2
67#define VEOL2 3
68#define VEOF 4
69#define VERASE 5
70#define VINTR 6
71#define VKILL 7
72#define VLNEXT 8
73#define VMIN 9
74#define VQUIT 10
75#define VREPRINT 11
76#define VSTART 12
77#define VSTOP 13
78#define VSUSP 14
79#define VSWTC 15
80#define VTIME 16
81#define VWERASE 17
82
83#define TCIFLUSH 0
84#define TCSAFLUSH 1
85#define TCSANOW 2
86#define TCSADRAIN 3
87#define TCSADFLUSH 4
88
89#define B0 0000000 /* hang up */
90#define B50 0000001
91#define B75 0000002
92#define B110 0000003
93#define B134 0000004
94#define B150 0000005
95#define B200 0000006
96#define B300 0000007
97#define B600 0000010
98#define B1200 0000011
99#define B1800 0000012
100#define B2400 0000013
101#define B4800 0000014
102#define B9600 0000015
103
104typedef unsigned char cc_t;
105typedef unsigned int tcflag_t;
106typedef unsigned int speed_t;
107typedef unsigned short otcflag_t;
108typedef unsigned char ospeed_t;
109
110#define NCCS 18
111struct termios {
112 tcflag_t c_iflag;
113 tcflag_t c_oflag;
114 tcflag_t c_cflag;
115 tcflag_t c_lflag;
116 char c_line;
117 cc_t c_cc[NCCS];
118 speed_t c_ispeed;
119 speed_t c_ospeed;
120};
121
122struct winsize {
123 unsigned short ws_row, ws_col;
124 unsigned short ws_xpixel, ws_ypixel;
125};
126
127int tcflush(int fd, int queue_selector);
128int tcgetattr(int fd, struct termios *t);
129int tcsetattr(int fd, int mode, const struct termios *t);
diff --git a/win32/uname.c b/win32/uname.c
new file mode 100644
index 000000000..465ba1e28
--- /dev/null
+++ b/win32/uname.c
@@ -0,0 +1,48 @@
1#include "libbb.h"
2/* After libbb.h, since it needs sys/types.h on some systems */
3#include <sys/utsname.h>
4
5int uname(struct utsname *name)
6{
7 const char *unk = "unknown";
8 OSVERSIONINFO os_info;
9 SYSTEM_INFO sys_info;
10
11 strcpy(name->sysname, "Windows_NT");
12
13 if ( gethostname(name->nodename, sizeof(name->nodename)) != 0 ) {
14 strcpy(name->nodename, unk);
15 }
16
17 memset(&os_info, 0, sizeof(OSVERSIONINFO));
18 os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
19
20 strcpy(name->release, unk);
21 strcpy(name->version, unk);
22 if (GetVersionEx(&os_info)) {
23 sprintf(name->release, "%d.%d", os_info.dwMajorVersion,
24 os_info.dwMinorVersion);
25 sprintf(name->version, "%d", os_info.dwBuildNumber);
26 }
27
28 strcpy(name->machine, unk);
29 GetSystemInfo(&sys_info);
30 switch (sys_info.wProcessorArchitecture) {
31 case PROCESSOR_ARCHITECTURE_AMD64:
32 strcpy(name->machine, "x86_64");
33 break;
34 case PROCESSOR_ARCHITECTURE_IA64:
35 strcpy(name->machine, "ia64");
36 break;
37 case PROCESSOR_ARCHITECTURE_INTEL:
38 if (sys_info.wProcessorLevel < 6) {
39 strcpy(name->machine, "i386");
40 }
41 else {
42 strcpy(name->machine, "i686");
43 }
44 break;
45 }
46
47 return 0;
48}
diff --git a/win32/winansi.c b/win32/winansi.c
new file mode 100644
index 000000000..c47e29a28
--- /dev/null
+++ b/win32/winansi.c
@@ -0,0 +1,685 @@
1/*
2 * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
3 */
4
5#include "libbb.h"
6#include <windows.h>
7#undef PACKED
8
9/*
10 Functions to be wrapped:
11*/
12#undef vprintf
13#undef printf
14#undef fprintf
15#undef fputs
16#undef putchar
17#undef fwrite
18#undef puts
19#undef write
20#undef read
21#undef getc
22
23/*
24 ANSI codes used by git: m, K
25
26 This file is git-specific. Therefore, this file does not attempt
27 to implement any codes that are not used by git.
28*/
29
30static HANDLE console;
31static HANDLE console_in;
32static WORD plain_attr;
33static WORD attr;
34static int negative;
35
36static void init(void)
37{
38 CONSOLE_SCREEN_BUFFER_INFO sbi;
39
40 static int initialized = 0;
41 if (initialized)
42 return;
43
44 console_in = GetStdHandle(STD_INPUT_HANDLE);
45 if (console_in == INVALID_HANDLE_VALUE)
46 console_in = NULL;
47
48 console = GetStdHandle(STD_OUTPUT_HANDLE);
49 if (console == INVALID_HANDLE_VALUE)
50 console = NULL;
51
52 if (!console)
53 return;
54
55 GetConsoleScreenBufferInfo(console, &sbi);
56 attr = plain_attr = sbi.wAttributes;
57 negative = 0;
58
59 initialized = 1;
60}
61
62
63#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
64#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
65
66static void set_console_attr(void)
67{
68 WORD attributes = attr;
69 if (negative) {
70 attributes &= ~FOREGROUND_ALL;
71 attributes &= ~BACKGROUND_ALL;
72
73 /* This could probably use a bitmask
74 instead of a series of ifs */
75 if (attr & FOREGROUND_RED)
76 attributes |= BACKGROUND_RED;
77 if (attr & FOREGROUND_GREEN)
78 attributes |= BACKGROUND_GREEN;
79 if (attr & FOREGROUND_BLUE)
80 attributes |= BACKGROUND_BLUE;
81
82 if (attr & BACKGROUND_RED)
83 attributes |= FOREGROUND_RED;
84 if (attr & BACKGROUND_GREEN)
85 attributes |= FOREGROUND_GREEN;
86 if (attr & BACKGROUND_BLUE)
87 attributes |= FOREGROUND_BLUE;
88 }
89 SetConsoleTextAttribute(console, attributes);
90}
91
92static void erase_in_line(void)
93{
94 CONSOLE_SCREEN_BUFFER_INFO sbi;
95 DWORD dummy; /* Needed for Windows 7 (or Vista) regression */
96
97 if (!console)
98 return;
99
100 GetConsoleScreenBufferInfo(console, &sbi);
101 FillConsoleOutputCharacterA(console, ' ',
102 sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
103 &dummy);
104}
105
106static void erase_till_end_of_screen(void)
107{
108 CONSOLE_SCREEN_BUFFER_INFO sbi;
109 COORD pos;
110 DWORD dummy;
111
112 if (!console)
113 return;
114
115 GetConsoleScreenBufferInfo(console, &sbi);
116 FillConsoleOutputCharacterA(console, ' ',
117 sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
118 &dummy);
119
120 pos.X = 0;
121 for (pos.Y = sbi.dwCursorPosition.Y+1; pos.Y < sbi.dwSize.Y; pos.Y++)
122 FillConsoleOutputCharacterA(console, ' ', sbi.dwSize.X,
123 pos, &dummy);
124}
125
126static void move_cursor_row(int n)
127{
128 CONSOLE_SCREEN_BUFFER_INFO sbi;
129
130 if (!console)
131 return;
132
133 GetConsoleScreenBufferInfo(console, &sbi);
134 sbi.dwCursorPosition.Y += n;
135 SetConsoleCursorPosition(console, sbi.dwCursorPosition);
136}
137
138static void move_cursor_column(int n)
139{
140 CONSOLE_SCREEN_BUFFER_INFO sbi;
141
142 if (!console)
143 return;
144
145 GetConsoleScreenBufferInfo(console, &sbi);
146 sbi.dwCursorPosition.X += n;
147 SetConsoleCursorPosition(console, sbi.dwCursorPosition);
148}
149
150static void move_cursor(int x, int y)
151{
152 COORD pos;
153
154 if (!console)
155 return;
156
157 pos.X = x;
158 pos.Y = y;
159 SetConsoleCursorPosition(console, pos);
160}
161
162static const char *set_attr(const char *str)
163{
164 const char *func;
165 size_t len = strspn(str, "0123456789;");
166 func = str + len;
167
168 switch (*func) {
169 case 'm':
170 do {
171 long val = strtol(str, (char **)&str, 10);
172 switch (val) {
173 case 0: /* reset */
174 attr = plain_attr;
175 negative = 0;
176 break;
177 case 1: /* bold */
178 attr |= FOREGROUND_INTENSITY;
179 break;
180 case 2: /* faint */
181 case 22: /* normal */
182 attr &= ~FOREGROUND_INTENSITY;
183 break;
184 case 3: /* italic */
185 /* Unsupported */
186 break;
187 case 4: /* underline */
188 case 21: /* double underline */
189 /* Wikipedia says this flag does nothing */
190 /* Furthermore, mingw doesn't define this flag
191 attr |= COMMON_LVB_UNDERSCORE; */
192 break;
193 case 24: /* no underline */
194 /* attr &= ~COMMON_LVB_UNDERSCORE; */
195 break;
196 case 5: /* slow blink */
197 case 6: /* fast blink */
198 /* We don't have blink, but we do have
199 background intensity */
200 attr |= BACKGROUND_INTENSITY;
201 break;
202 case 25: /* no blink */
203 attr &= ~BACKGROUND_INTENSITY;
204 break;
205 case 7: /* negative */
206 negative = 1;
207 break;
208 case 27: /* positive */
209 negative = 0;
210 break;
211 case 8: /* conceal */
212 case 28: /* reveal */
213 /* Unsupported */
214 break;
215 case 30: /* Black */
216 attr &= ~FOREGROUND_ALL;
217 break;
218 case 31: /* Red */
219 attr &= ~FOREGROUND_ALL;
220 attr |= FOREGROUND_RED;
221 break;
222 case 32: /* Green */
223 attr &= ~FOREGROUND_ALL;
224 attr |= FOREGROUND_GREEN;
225 break;
226 case 33: /* Yellow */
227 attr &= ~FOREGROUND_ALL;
228 attr |= FOREGROUND_RED | FOREGROUND_GREEN;
229 break;
230 case 34: /* Blue */
231 attr &= ~FOREGROUND_ALL;
232 attr |= FOREGROUND_BLUE;
233 break;
234 case 35: /* Magenta */
235 attr &= ~FOREGROUND_ALL;
236 attr |= FOREGROUND_RED | FOREGROUND_BLUE;
237 break;
238 case 36: /* Cyan */
239 attr &= ~FOREGROUND_ALL;
240 attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
241 break;
242 case 37: /* White */
243 attr |= FOREGROUND_RED |
244 FOREGROUND_GREEN |
245 FOREGROUND_BLUE;
246 break;
247 case 38: /* Unknown */
248 break;
249 case 39: /* reset */
250 attr &= ~FOREGROUND_ALL;
251 attr |= (plain_attr & FOREGROUND_ALL);
252 break;
253 case 40: /* Black */
254 attr &= ~BACKGROUND_ALL;
255 break;
256 case 41: /* Red */
257 attr &= ~BACKGROUND_ALL;
258 attr |= BACKGROUND_RED;
259 break;
260 case 42: /* Green */
261 attr &= ~BACKGROUND_ALL;
262 attr |= BACKGROUND_GREEN;
263 break;
264 case 43: /* Yellow */
265 attr &= ~BACKGROUND_ALL;
266 attr |= BACKGROUND_RED | BACKGROUND_GREEN;
267 break;
268 case 44: /* Blue */
269 attr &= ~BACKGROUND_ALL;
270 attr |= BACKGROUND_BLUE;
271 break;
272 case 45: /* Magenta */
273 attr &= ~BACKGROUND_ALL;
274 attr |= BACKGROUND_RED | BACKGROUND_BLUE;
275 break;
276 case 46: /* Cyan */
277 attr &= ~BACKGROUND_ALL;
278 attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
279 break;
280 case 47: /* White */
281 attr |= BACKGROUND_RED |
282 BACKGROUND_GREEN |
283 BACKGROUND_BLUE;
284 break;
285 case 48: /* Unknown */
286 break;
287 case 49: /* reset */
288 attr &= ~BACKGROUND_ALL;
289 attr |= (plain_attr & BACKGROUND_ALL);
290 break;
291 default:
292 /* Unsupported code */
293 break;
294 }
295 str++;
296 } while (*(str-1) == ';');
297
298 set_console_attr();
299 break;
300 case 'A': /* up */
301 move_cursor_row(-strtol(str, (char **)&str, 10));
302 break;
303 case 'B': /* down */
304 move_cursor_row(strtol(str, (char **)&str, 10));
305 break;
306 case 'C': /* forward */
307 move_cursor_column(strtol(str, (char **)&str, 10));
308 break;
309 case 'D': /* back */
310 move_cursor_column(-strtol(str, (char **)&str, 10));
311 break;
312 case 'H':
313 if (!len)
314 move_cursor(0, 0);
315 else {
316 int row = strtol(str, (char **)&str, 10);
317 if (*str == ';') {
318 int col = strtol(str+1, (char **)&str, 10);
319 move_cursor(col-1, row-1);
320 }
321 }
322 break;
323 case 'J':
324 erase_till_end_of_screen();
325 break;
326 case 'K':
327 erase_in_line();
328 break;
329 case '?':
330 /* skip this to avoid ugliness when vi is shut down */
331 ++str;
332 while (isdigit(*str))
333 ++str;
334 func = str;
335 break;
336 default:
337 /* Unsupported code */
338 break;
339 }
340
341 return func + 1;
342}
343
344static int ansi_emulate(const char *s, FILE *stream)
345{
346 int rv = 0;
347 const char *t;
348 char *pos, *str;
349 size_t out_len, cur_len;
350 static size_t max_len = 0;
351 static char *mem = NULL;
352
353 /* if no special treatment is required output the string as-is */
354 for ( t=s; *t; ++t ) {
355 if ( *t == '\033' || *t > 0x7f ) {
356 break;
357 }
358 }
359
360 if ( *t == '\0' ) {
361 return fputs(s, stream) == EOF ? EOF : strlen(s);
362 }
363
364 /* make a writable copy of the string and retain it for reuse */
365 cur_len = strlen(s);
366 if ( cur_len == 0 || cur_len > max_len ) {
367 free(mem);
368 mem = strdup(s);
369 max_len = cur_len;
370 }
371 else {
372 strcpy(mem, s);
373 }
374 pos = str = mem;
375
376 while (*pos) {
377 pos = strstr(str, "\033[");
378 if (pos) {
379 size_t len = pos - str;
380
381 if (len) {
382 CharToOemBuff(str, str, len);
383 out_len = fwrite(str, 1, len, stream);
384 rv += out_len;
385 if (out_len < len)
386 return rv;
387 }
388
389 str = pos + 2;
390 rv += 2;
391
392 fflush(stream);
393
394 pos = (char *)set_attr(str);
395 rv += pos - str;
396 str = pos;
397 } else {
398 rv += strlen(str);
399 CharToOem(str, str);
400 fputs(str, stream);
401 return rv;
402 }
403 }
404 return rv;
405}
406
407int winansi_putchar(int c)
408{
409 char t = c;
410 char *s = &t;
411
412 if (!isatty(STDOUT_FILENO))
413 return putchar(c);
414
415 init();
416
417 if (!console)
418 return putchar(c);
419
420 CharToOemBuff(s, s, 1);
421 return putchar(t) == EOF ? EOF : c;
422}
423
424int winansi_puts(const char *s)
425{
426 int rv;
427
428 if (!isatty(STDOUT_FILENO))
429 return puts(s);
430
431 init();
432
433 if (!console)
434 return puts(s);
435
436 rv = ansi_emulate(s, stdout);
437 putchar('\n');
438
439 return rv;
440}
441
442size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
443{
444 size_t lsize, lmemb;
445 char *str;
446 int rv;
447
448 lsize = MIN(size, nmemb);
449 lmemb = MAX(size, nmemb);
450 if (lsize != 1)
451 return fwrite(ptr, size, nmemb, stream);
452
453 if (!isatty(fileno(stream)))
454 return fwrite(ptr, size, nmemb, stream);
455
456 init();
457
458 if (!console)
459 return fwrite(ptr, size, nmemb, stream);
460
461 str = xmalloc(lmemb+1);
462 memcpy(str, ptr, lmemb);
463 str[lmemb] = '\0';
464
465 rv = ansi_emulate(str, stream);
466 free(str);
467
468 return rv;
469}
470
471int winansi_fputs(const char *str, FILE *stream)
472{
473 int rv;
474
475 if (!isatty(fileno(stream)))
476 return fputs(str, stream);
477
478 init();
479
480 if (!console)
481 return fputs(str, stream);
482
483 rv = ansi_emulate(str, stream);
484
485 if (rv >= 0)
486 return 0;
487 else
488 return EOF;
489}
490
491int winansi_vfprintf(FILE *stream, const char *format, va_list list)
492{
493 int len, rv;
494 char small_buf[256];
495 char *buf = small_buf;
496 va_list cp;
497
498 if (!isatty(fileno(stream)))
499 goto abort;
500
501 init();
502
503 if (!console)
504 goto abort;
505
506 va_copy(cp, list);
507 len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
508 va_end(cp);
509
510 if (len > sizeof(small_buf) - 1) {
511 buf = malloc(len + 1);
512 if (!buf)
513 goto abort;
514
515 len = vsnprintf(buf, len + 1, format, list);
516 }
517
518 rv = ansi_emulate(buf, stream);
519
520 if (buf != small_buf)
521 free(buf);
522 return rv;
523
524abort:
525 rv = vfprintf(stream, format, list);
526 return rv;
527}
528
529int winansi_fprintf(FILE *stream, const char *format, ...)
530{
531 va_list list;
532 int rv;
533
534 va_start(list, format);
535 rv = winansi_vfprintf(stream, format, list);
536 va_end(list);
537
538 return rv;
539}
540
541int winansi_printf(const char *format, ...)
542{
543 va_list list;
544 int rv;
545
546 va_start(list, format);
547 rv = winansi_vfprintf(stdout, format, list);
548 va_end(list);
549
550 return rv;
551}
552
553int winansi_get_terminal_width_height(struct winsize *win)
554{
555 BOOL ret;
556 CONSOLE_SCREEN_BUFFER_INFO sbi;
557
558 init();
559
560 win->ws_row = 0;
561 win->ws_col = 0;
562 if ((ret=GetConsoleScreenBufferInfo(console, &sbi)) != 0) {
563 win->ws_row = sbi.srWindow.Bottom - sbi.srWindow.Top + 1;
564 win->ws_col = sbi.srWindow.Right - sbi.srWindow.Left + 1;
565 }
566
567 return ret ? 0 : -1;
568}
569
570static int ansi_emulate_write(int fd, const void *buf, size_t count)
571{
572 int rv = 0, i;
573 const char *s = (const char *)buf;
574 char *pos, *str;
575 size_t len, out_len;
576 static size_t max_len = 0;
577 static char *mem = NULL;
578
579 /* if no special treatment is required output the string as-is */
580 for ( i=0; i<count; ++i ) {
581 if ( s[i] == '\033' || s[i] > 0x7f ) {
582 break;
583 }
584 }
585
586 if ( i == count ) {
587 return write(fd, buf, count);
588 }
589
590 /* make a writable copy of the data and retain it for reuse */
591 if ( count > max_len ) {
592 free(mem);
593 mem = malloc(count+1);
594 max_len = count;
595 }
596 memcpy(mem, buf, count);
597 mem[count] = '\0';
598 pos = str = mem;
599
600 /* we're writing to the console so we assume the data isn't binary */
601 while (*pos) {
602 pos = strstr(str, "\033[");
603 if (pos) {
604 len = pos - str;
605
606 if (len) {
607 CharToOemBuff(str, str, len);
608 out_len = write(fd, str, len);
609 rv += out_len;
610 if (out_len < len)
611 return rv;
612 }
613
614 str = pos + 2;
615 rv += 2;
616
617 pos = (char *)set_attr(str);
618 rv += pos - str;
619 str = pos;
620 } else {
621 len = strlen(str);
622 rv += len;
623 CharToOem(str, str);
624 write(fd, str, len);
625 return rv;
626 }
627 }
628 return rv;
629}
630
631int winansi_write(int fd, const void *buf, size_t count)
632{
633 if (!isatty(fd))
634 return write(fd, buf, count);
635
636 init();
637
638 if (!console)
639 return write(fd, buf, count);
640
641 return ansi_emulate_write(fd, buf, count);
642}
643
644int winansi_read(int fd, void *buf, size_t count)
645{
646 int rv;
647
648 rv = read(fd, buf, count);
649 if (!isatty(fd))
650 return rv;
651
652 init();
653
654 if (!console_in)
655 return rv;
656
657 if ( rv > 0 ) {
658 OemToCharBuff(buf, buf, rv);
659 }
660
661 return rv;
662}
663
664int winansi_getc(FILE *stream)
665{
666 int rv;
667
668 rv = getc(stream);
669 if (!isatty(fileno(stream)))
670 return rv;
671
672 init();
673
674 if (!console_in)
675 return rv;
676
677 if ( rv != EOF ) {
678 unsigned char c = (unsigned char)rv;
679 char *s = (char *)&c;
680 OemToCharBuff(s, s, 1);
681 rv = (int)c;
682 }
683
684 return rv;
685}