aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Config.in36
-rw-r--r--Makefile12
-rw-r--r--Makefile.flags8
-rw-r--r--README1
-rw-r--r--README.md23
-rw-r--r--applets/applet_tables.c2
-rw-r--r--archival/ar.c16
-rw-r--r--archival/bbunzip.c2
-rw-r--r--archival/libarchive/decompress_gunzip.c6
-rw-r--r--archival/libarchive/open_transformer.c26
-rw-r--r--archival/tar.c31
-rw-r--r--archival/unzip.c5
-rw-r--r--configs/mingw32_defconfig1131
-rw-r--r--configs/mingw64_defconfig1131
-rw-r--r--coreutils/dd.c20
-rw-r--r--coreutils/expr.c2
-rw-r--r--coreutils/factor.c4
-rw-r--r--coreutils/ls.c2
-rw-r--r--coreutils/od_bloaty.c7
-rw-r--r--coreutils/stat.c1
-rw-r--r--coreutils/sum.c4
-rw-r--r--coreutils/test.c15
-rw-r--r--coreutils/yes.c4
-rw-r--r--debianutils/which.c21
-rw-r--r--editors/awk.c6
-rw-r--r--editors/diff.c21
-rw-r--r--editors/sed.c5
-rw-r--r--editors/vi.c59
-rw-r--r--findutils/xargs.c13
-rw-r--r--include/bb_archive.h10
-rw-r--r--include/libbb.h46
-rw-r--r--include/mingw.h484
-rw-r--r--include/platform.h41
-rw-r--r--libbb/Kbuild.src21
-rw-r--r--libbb/appletlib.c107
-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.c26
-rw-r--r--libbb/get_line_from_file.c4
-rw-r--r--libbb/inode_hash.c2
-rw-r--r--libbb/lineedit.c76
-rw-r--r--libbb/make_directory.c33
-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.c4
-rw-r--r--libbb/xatonum_template.c5
-rw-r--r--libbb/xconnect.c12
-rw-r--r--libbb/xreadlink.c2
-rw-r--r--miscutils/bbconfig.c1
-rw-r--r--miscutils/dc.c2
-rw-r--r--miscutils/less.c78
-rw-r--r--miscutils/man.c4
-rw-r--r--networking/ftpgetput.c6
-rw-r--r--networking/nc.c33
-rw-r--r--networking/wget.c6
-rw-r--r--procps/iostat.c2
-rw-r--r--procps/mpstat.c2
-rw-r--r--procps/ps.c16
-rw-r--r--procps/smemcap.c1
-rw-r--r--scripts/basic/docproc.c15
-rw-r--r--scripts/basic/fixdep.c68
-rw-r--r--scripts/basic/split-include.c13
-rw-r--r--scripts/kconfig/conf.c15
-rw-r--r--scripts/kconfig/confdata.c9
-rw-r--r--scripts/kconfig/lkc.h6
-rw-r--r--scripts/kconfig/mconf.c23
-rw-r--r--scripts/kconfig/symbol.c15
-rw-r--r--scripts/kconfig/zconf.hash.c_shipped60
-rw-r--r--scripts/kconfig/zconf.tab.c_shipped1
-rw-r--r--shell/ash.c1407
-rw-r--r--shell/math.h2
-rw-r--r--shell/shell_common.c15
-rw-r--r--util-linux/more.c19
-rw-r--r--util-linux/rev.c10
-rw-r--r--win32/Kbuild25
-rw-r--r--win32/arpa/inet.h0
-rw-r--r--win32/env.c189
-rw-r--r--win32/fnmatch.c488
-rw-r--r--win32/fnmatch.h84
-rw-r--r--win32/grp.h0
-rw-r--r--win32/inet_pton.c255
-rw-r--r--win32/ioctl.c24
-rw-r--r--win32/mempcpy.c27
-rw-r--r--win32/mingw.c1064
-rw-r--r--win32/mntent.c69
-rw-r--r--win32/mntent.h19
-rw-r--r--win32/net.c101
-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.c318
-rw-r--r--win32/process.c425
-rw-r--r--win32/pwd.h0
-rw-r--r--win32/regcomp.c3886
-rw-r--r--win32/regex.c90
-rw-r--r--win32/regex.h582
-rw-r--r--win32/regex_internal.c1744
-rw-r--r--win32/regex_internal.h810
-rw-r--r--win32/regexec.c4369
-rw-r--r--win32/sched.h1
-rw-r--r--win32/select.c573
-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/prctl.h0
-rw-r--r--win32/sys/resource.h0
-rw-r--r--win32/sys/socket.h0
-rw-r--r--win32/sys/statfs.h22
-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.c22
-rw-r--r--win32/termios.c83
-rw-r--r--win32/termios.h129
-rw-r--r--win32/uname.c48
-rw-r--r--win32/winansi.c735
130 files changed, 22848 insertions, 186 deletions
diff --git a/.gitignore b/.gitignore
index be1d46199..2a7f2f79b 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 acd3cb883..e131dafaf 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 "Settings" 26menu "Settings"
13 27
14config DESKTOP 28config DESKTOP
@@ -95,6 +109,28 @@ config LFS
95 programs that can benefit from large file support include dd, gzip, 109 programs that can benefit from large file support include dd, gzip,
96 cp, mount, tar. 110 cp, mount, tar.
97 111
112config GLOBBING
113 bool "Allow busybox.exe to expand wildcards"
114 default n
115 depends on PLATFORM_MINGW32
116 help
117 In Microsoft Windows expansion of wildcards on the command line
118 ('globbing') is handled by the C runtime while the BusyBox shell
119 does its own wildcard expansion. For best results when using the
120 shell globbing by the C runtime should be turned off. If you want
121 the BusyBox binary to handle wildcard expansion using the C runtime
122 set this to 'Y'.
123
124config SAFE_ENV
125 bool "Manipulate the environment through safe API calls"
126 default n
127 depends on PLATFORM_MINGW32
128 help
129 Enable this option to use safe API calls when clearing environment
130 variables. This is necessary if BusyBox is to run on ReactOS or
131 64-bit Windows. The default is 'N', which must be used if BusyBox
132 is to run on Windows XP.
133
98config PAM 134config PAM
99 bool "Support PAM (Pluggable Authentication Modules)" 135 bool "Support PAM (Pluggable Authentication Modules)"
100 default n 136 default n
diff --git a/Makefile b/Makefile
index c756dfeaf..47bdaf7ad 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
@@ -531,7 +533,7 @@ endif
531# command line. 533# command line.
532# This allow a user to issue only 'make' to build a kernel including modules 534# This allow a user to issue only 'make' to build a kernel including modules
533# Defaults busybox but it is usually overridden in the arch makefile 535# Defaults busybox but it is usually overridden in the arch makefile
534all: busybox doc 536all: busybox$(EXEEXT) doc
535 537
536# arch Makefile may override CC so keep this after arch Makefile is included 538# arch Makefile may override CC so keep this after arch Makefile is included
537#bbox# NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) 539#bbox# NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
@@ -713,16 +715,16 @@ debug_kallsyms: .tmp_map$(last_kallsyms)
713endif # ifdef CONFIG_KALLSYMS 715endif # ifdef CONFIG_KALLSYMS
714 716
715# busybox image - including updated kernel symbols 717# busybox image - including updated kernel symbols
716busybox_unstripped: $(busybox-all) FORCE 718busybox_unstripped$(EXEEXT): $(busybox-all) FORCE
717 $(call if_changed_rule,busybox__) 719 $(call if_changed_rule,busybox__)
718 $(Q)rm -f .old_version 720 $(Q)rm -f .old_version
719 721
720busybox: busybox_unstripped 722busybox$(EXEEXT): busybox_unstripped$(EXEEXT)
721ifeq ($(SKIP_STRIP),y) 723ifeq ($(SKIP_STRIP),y)
722 $(Q)cp $< $@ 724 $(Q)cp $< $@
723else 725else
724 $(Q)$(STRIP) -s --remove-section=.note --remove-section=.comment \ 726 $(Q)$(STRIP) -s --remove-section=.note --remove-section=.comment \
725 busybox_unstripped -o $@ 727 busybox_unstripped$(EXEEXT) -o $@
726# strip is confused by PIE executable and does not set exec bits 728# strip is confused by PIE executable and does not set exec bits
727 $(Q)chmod a+x $@ 729 $(Q)chmod a+x $@
728endif 730endif
@@ -961,7 +963,7 @@ endif # CONFIG_MODULES
961 963
962# Directories & files removed with 'make clean' 964# Directories & files removed with 'make clean'
963CLEAN_DIRS += $(MODVERDIR) _install 0_lib 965CLEAN_DIRS += $(MODVERDIR) _install 0_lib
964CLEAN_FILES += busybox busybox_unstripped* busybox.links \ 966CLEAN_FILES += busybox$(EXEEXT) busybox_unstripped* busybox.links \
965 System.map .kernelrelease \ 967 System.map .kernelrelease \
966 .tmp_kallsyms* .tmp_version .tmp_busybox* .tmp_System.map 968 .tmp_kallsyms* .tmp_version .tmp_busybox* .tmp_System.map
967 969
diff --git a/Makefile.flags b/Makefile.flags
index f3c897b06..6bb6a8fb1 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -15,7 +15,7 @@ CPPFLAGS += \
15 -include include/autoconf.h \ 15 -include include/autoconf.h \
16 -D_GNU_SOURCE -DNDEBUG \ 16 -D_GNU_SOURCE -DNDEBUG \
17 $(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \ 17 $(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \
18 -D"BB_VER=KBUILD_STR($(BB_VER))" 18 -D"BB_VER=KBUILD_STR($(BB_VER))" -D"MINGW_VER=KBUILD_STR($(MINGW_VER))"
19 19
20CFLAGS += $(call cc-option,-Wall,) 20CFLAGS += $(call cc-option,-Wall,)
21CFLAGS += $(call cc-option,-Wshadow,) 21CFLAGS += $(call cc-option,-Wshadow,)
@@ -123,6 +123,12 @@ CFLAGS += --sysroot=$(CONFIG_SYSROOT)
123export SYSROOT=$(CONFIG_SYSROOT) 123export SYSROOT=$(CONFIG_SYSROOT)
124endif 124endif
125 125
126ifeq ($(CONFIG_PLATFORM_MINGW32),y)
127CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-ident
128EXEEXT = .exe
129LDLIBS += userenv ws2_32
130endif
131
126# Android has no separate crypt library 132# Android has no separate crypt library
127# gcc-4.2.1 fails if we try to feed C source on stdin: 133# gcc-4.2.1 fails if we try to feed C source on stdin:
128# echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc - 134# echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc -
diff --git a/README b/README
index ada5935b9..9936e6cc3 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..06720791f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
1### Status
2
3Things 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. If you don't have a GitHub account you can email me: rmy@pobox.com.
4
5### Building
6
7You need a MinGW compiler and a POSIX environment (so that `make menuconfig` works). I cross-compile on Linux. On Fedora or RHEL/CentOS+EPEL installing mingw32-gcc (32-bit build) or mingw64-gcc (64-bit build) will pull in everything needed.
8
9To start, run `make mingw32_defconfig` or `make mingw64_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 - Wildcard expansion is disabled by default, though it can be turned on at compile time. This only affects command line arguments to the binary: the BusyBox shell has full support for wildcards.
20 - Handling of users, groups and permissions is totally bogus. The system only admits to knowing about the current user and always returns the same hardcoded uid, gid and permission values.
21 - Some crufty old Windows code (Windows XP, cmd.exe) doesn't like forward slashes in environment variables. The -X shell option (which must be the first argument) prevents busybox-w32 from changing backslashes to forward slashes. If Windows programs don't run from the shell it's worth trying it.
22 - If you want to install 32-bit BusyBox in a system directory on a 64-bit version of Windows you should put it in `C:\Windows\SysWOW64`, not `C:\Windows\System32` as you might expect. On 64-bit systems the latter is for 64-bit binaries.
23 - ANSI escape sequences are emulated by converting to the equivalent in the Windows console API. Setting the environment variable `BB_SKIP_ANSI_EMULATION` will cause ANSI escapes to be passed to the console without emulation. This may be useful for Windows consoles that support ANSI escapes (e.g. ConEmu).
diff --git a/applets/applet_tables.c b/applets/applet_tables.c
index ef911a43b..9a2aa5329 100644
--- a/applets/applet_tables.c
+++ b/applets/applet_tables.c
@@ -179,7 +179,7 @@ int main(int argc, char **argv)
179 printf("};\n\n"); 179 printf("};\n\n");
180#endif 180#endif
181 181
182#if ENABLE_FEATURE_INSTALLER 182#if ENABLE_FEATURE_INSTALLER && !ENABLE_PLATFORM_MINGW32
183 printf("const uint8_t applet_install_loc[] ALIGN1 = {\n"); 183 printf("const uint8_t applet_install_loc[] ALIGN1 = {\n");
184 i = 0; 184 i = 0;
185 while (i < NUM_APPLETS) { 185 while (i < NUM_APPLETS) {
diff --git a/archival/ar.c b/archival/ar.c
index 2886d155b..ea36bda88 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -163,6 +163,7 @@ static int write_ar_archive(archive_handle_t *handle)
163{ 163{
164 struct stat st; 164 struct stat st;
165 archive_handle_t *out_handle; 165 archive_handle_t *out_handle;
166 char *temp_fn = NULL;
166 167
167 xfstat(handle->src_fd, &st, handle->ar__name); 168 xfstat(handle->src_fd, &st, handle->ar__name);
168 169
@@ -171,8 +172,14 @@ static int write_ar_archive(archive_handle_t *handle)
171 */ 172 */
172 if (st.st_size != 0) { 173 if (st.st_size != 0) {
173 out_handle = init_handle(); 174 out_handle = init_handle();
175#if !ENABLE_PLATFORM_MINGW32
174 xunlink(handle->ar__name); 176 xunlink(handle->ar__name);
175 out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC); 177 out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC);
178#else
179 /* can't unlink open file, create temporary output file */
180 temp_fn = xasprintf("%sXXXXXX", handle->ar__name);
181 out_handle->src_fd = xmkstemp(temp_fn);
182#endif
176 out_handle->accept = handle->accept; 183 out_handle->accept = handle->accept;
177 } else { 184 } else {
178 out_handle = handle; 185 out_handle = handle;
@@ -194,12 +201,19 @@ static int write_ar_archive(archive_handle_t *handle)
194 continue; 201 continue;
195 202
196 /* optional, since we exit right after we return */ 203 /* optional, since we exit right after we return */
197 if (ENABLE_FEATURE_CLEAN_UP) { 204 if (ENABLE_FEATURE_CLEAN_UP || ENABLE_PLATFORM_MINGW32) {
198 close(handle->src_fd); 205 close(handle->src_fd);
199 if (out_handle->src_fd != handle->src_fd) 206 if (out_handle->src_fd != handle->src_fd)
200 close(out_handle->src_fd); 207 close(out_handle->src_fd);
201 } 208 }
202 209
210#if ENABLE_PLATFORM_MINGW32
211 if ( temp_fn != NULL ) {
212 xrename(temp_fn, handle->ar__name);
213 free(temp_fn);
214 }
215#endif
216
203 return EXIT_SUCCESS; 217 return EXIT_SUCCESS;
204} 218}
205#endif /* FEATURE_AR_CREATE */ 219#endif /* FEATURE_AR_CREATE */
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index d2b162d5e..f91dd25eb 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -191,6 +191,8 @@ int FAST_FUNC bbunpack(char **argv,
191 if (option_mask32 & OPT_KEEP) /* ... unless -k */ 191 if (option_mask32 & OPT_KEEP) /* ... unless -k */
192 del = NULL; 192 del = NULL;
193 } 193 }
194 if (ENABLE_PLATFORM_MINGW32)
195 xclose(STDIN_FILENO);
194 if (del) 196 if (del)
195 xunlink(del); 197 xunlink(del);
196 free_name: 198 free_name:
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index c7fa5b526..74d364379 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -1118,6 +1118,9 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY)
1118 return res; 1118 return res;
1119} 1119}
1120 1120
1121#if ENABLE_PLATFORM_MINGW32 && __GNUC__
1122#pragma pack(2)
1123#endif
1121static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) 1124static int check_header_gzip(STATE_PARAM transformer_state_t *xstate)
1122{ 1125{
1123 union { 1126 union {
@@ -1189,6 +1192,9 @@ static int check_header_gzip(STATE_PARAM transformer_state_t *xstate)
1189 } 1192 }
1190 return 1; 1193 return 1;
1191} 1194}
1195#if ENABLE_PLATFORM_MINGW32 && __GNUC__
1196#pragma pack()
1197#endif
1192 1198
1193IF_DESKTOP(long long) int FAST_FUNC 1199IF_DESKTOP(long long) int FAST_FUNC
1194unpack_gz_stream(transformer_state_t *xstate) 1200unpack_gz_stream(transformer_state_t *xstate)
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index ac7e5db95..641256787 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -65,6 +65,7 @@ ssize_t FAST_FUNC xtransformer_write(transformer_state_t *xstate, const void *bu
65 return nwrote; 65 return nwrote;
66} 66}
67 67
68#if !ENABLE_PLATFORM_MINGW32
68void check_errors_in_children(int signo) 69void check_errors_in_children(int signo)
69{ 70{
70 int status; 71 int status;
@@ -151,6 +152,31 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
151 close(fd_pipe.wr); /* don't want to write to the child */ 152 close(fd_pipe.wr); /* don't want to write to the child */
152 xmove_fd(fd_pipe.rd, fd); 153 xmove_fd(fd_pipe.rd, fd);
153} 154}
155#else /* ENABLE_PLATFORM_MINGW */
156void check_errors_in_children(int signo UNUSED_PARAM)
157{
158 bb_got_signal = 0;
159}
160
161void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
162{
163 char *cmd;
164 int fd1;
165
166 if (find_applet_by_name(transform_prog) >= 0) {
167 cmd = xasprintf("%s --busybox %s -cf -", bb_busybox_exec_path,
168 transform_prog);
169 }
170 else {
171 cmd = xasprintf("%s -cf -", transform_prog);
172 }
173 if ( (fd1=mingw_popen_fd(cmd, "r", fd, NULL)) == -1 ) {
174 bb_perror_msg_and_die("can't execute '%s'", transform_prog);
175 }
176 free(cmd);
177 xmove_fd(fd1, fd);
178}
179#endif
154 180
155 181
156#if SEAMLESS_COMPRESSION 182#if SEAMLESS_COMPRESSION
diff --git a/archival/tar.c b/archival/tar.c
index 280ded4e1..d90a5dc4f 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -542,6 +542,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
542 } 542 }
543 } 543 }
544 544
545#if !ENABLE_PLATFORM_MINGW32
545 /* It is a bad idea to store the archive we are in the process of creating, 546 /* It is a bad idea to store the archive we are in the process of creating,
546 * so check the device and inode to be sure that this particular file isn't 547 * so check the device and inode to be sure that this particular file isn't
547 * the new tarball */ 548 * the new tarball */
@@ -551,6 +552,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
551 bb_error_msg("%s: file is the archive; skipping", fileName); 552 bb_error_msg("%s: file is the archive; skipping", fileName);
552 return TRUE; 553 return TRUE;
553 } 554 }
555#endif
554 556
555 if (exclude_file(tbInfo->excludeList, header_name)) 557 if (exclude_file(tbInfo->excludeList, header_name))
556 return SKIP; 558 return SKIP;
@@ -608,6 +610,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
608} 610}
609 611
610#if SEAMLESS_COMPRESSION 612#if SEAMLESS_COMPRESSION
613#if !ENABLE_PLATFORM_MINGW32
611/* Don't inline: vfork scares gcc and pessimizes code */ 614/* Don't inline: vfork scares gcc and pessimizes code */
612static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) 615static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
613{ 616{
@@ -667,6 +670,27 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
667 bb_perror_msg_and_die("can't execute '%s'", gzip); 670 bb_perror_msg_and_die("can't execute '%s'", gzip);
668 } 671 }
669} 672}
673#else
674static pid_t vfork_compressor(int tar_fd, const char *gzip)
675{
676 char *cmd;
677 int fd1;
678 pid_t pid;
679
680 if (find_applet_by_name(gzip) >= 0) {
681 cmd = xasprintf("%s --busybox %s -cf -", bb_busybox_exec_path, gzip);
682 }
683 else {
684 cmd = xasprintf("%s -cf -", gzip);
685 }
686 if ( (fd1=mingw_popen_fd(cmd, "w", tar_fd, &pid)) == -1 ) {
687 bb_perror_msg_and_die("can't execute '%s'", gzip);
688 }
689 free(cmd);
690 xmove_fd(fd1, tar_fd);
691 return pid;
692}
693#endif /* ENABLE_PLATFORM_MINGW32 */
670#endif /* SEAMLESS_COMPRESSION */ 694#endif /* SEAMLESS_COMPRESSION */
671 695
672 696
@@ -682,6 +706,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
682{ 706{
683 int errorFlag = FALSE; 707 int errorFlag = FALSE;
684 struct TarBallInfo tbInfo; 708 struct TarBallInfo tbInfo;
709 IF_PLATFORM_MINGW32(pid_t pid = 0;)
685 710
686 tbInfo.hlInfoHead = NULL; 711 tbInfo.hlInfoHead = NULL;
687 tbInfo.tarFd = tar_fd; 712 tbInfo.tarFd = tar_fd;
@@ -693,7 +718,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
693 718
694#if SEAMLESS_COMPRESSION 719#if SEAMLESS_COMPRESSION
695 if (gzip) 720 if (gzip)
696 vfork_compressor(tbInfo.tarFd, gzip); 721 IF_PLATFORM_MINGW32(pid = )vfork_compressor(tbInfo.tarFd, gzip);
697#endif 722#endif
698 723
699 tbInfo.excludeList = exclude; 724 tbInfo.excludeList = exclude;
@@ -729,7 +754,11 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
729#if SEAMLESS_COMPRESSION 754#if SEAMLESS_COMPRESSION
730 if (gzip) { 755 if (gzip) {
731 int status; 756 int status;
757#if !ENABLE_PLATFORM_MINGW32
732 if (safe_waitpid(-1, &status, 0) == -1) 758 if (safe_waitpid(-1, &status, 0) == -1)
759#else
760 if (safe_waitpid(pid, &status, 0) == -1)
761#endif
733 bb_perror_msg("waitpid"); 762 bb_perror_msg("waitpid");
734 else if (!WIFEXITED(status) || WEXITSTATUS(status)) 763 else if (!WIFEXITED(status) || WEXITSTATUS(status))
735 /* gzip was killed or has exited with nonzero! */ 764 /* gzip was killed or has exited with nonzero! */
diff --git a/archival/unzip.c b/archival/unzip.c
index 8ed9ae7d5..f37ea3519 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -70,6 +70,9 @@
70 70
71#include "libbb.h" 71#include "libbb.h"
72#include "bb_archive.h" 72#include "bb_archive.h"
73#if ENABLE_PLATFORM_MINGW32 && __GNUC__
74#pragma pack(2)
75#endif
73 76
74#if 0 77#if 0
75# define dbg(...) bb_error_msg(__VA_ARGS__) 78# define dbg(...) bb_error_msg(__VA_ARGS__)
@@ -586,7 +589,7 @@ int unzip_main(int argc, char **argv)
586 } 589 }
587 } 590 }
588 591
589#ifndef __GLIBC__ 592#if !defined(__GLIBC__) && !ENABLE_PLATFORM_MINGW32
590 /* 593 /*
591 * This code is needed for non-GNU getopt 594 * This code is needed for non-GNU getopt
592 * which doesn't understand "-" in option string. 595 * which doesn't understand "-" in option string.
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
new file mode 100644
index 000000000..c5bc6eb9a
--- /dev/null
+++ b/configs/mingw32_defconfig
@@ -0,0 +1,1131 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.28.0.git
4# Mon Jul 24 11:51:22 2017
5#
6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set
8CONFIG_PLATFORM_MINGW32=y
9
10#
11# Busybox Settings
12#
13CONFIG_DESKTOP=y
14# CONFIG_EXTRA_COMPAT is not set
15# CONFIG_INCLUDE_SUSv2 is not set
16CONFIG_LONG_OPTS=y
17CONFIG_SHOW_USAGE=y
18CONFIG_FEATURE_VERBOSE_USAGE=y
19CONFIG_FEATURE_COMPRESS_USAGE=y
20CONFIG_LFS=y
21# CONFIG_GLOBBING is not set
22# CONFIG_SAFE_ENV is not set
23# CONFIG_PAM is not set
24# CONFIG_FEATURE_DEVPTS is not set
25# CONFIG_FEATURE_UTMP is not set
26# CONFIG_FEATURE_WTMP is not set
27# CONFIG_FEATURE_PIDFILE is not set
28CONFIG_PID_FILE_PATH=""
29CONFIG_BUSYBOX=y
30CONFIG_FEATURE_INSTALLER=y
31# CONFIG_INSTALL_NO_USR is not set
32# CONFIG_FEATURE_SUID is not set
33# CONFIG_FEATURE_SUID_CONFIG is not set
34# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
35CONFIG_FEATURE_PREFER_APPLETS=y
36CONFIG_BUSYBOX_EXEC_PATH=""
37# CONFIG_SELINUX is not set
38# CONFIG_FEATURE_CLEAN_UP is not set
39# CONFIG_FEATURE_SYSLOG is not set
40# CONFIG_FEATURE_HAVE_RPC is not set
41# CONFIG_PLATFORM_LINUX is not set
42
43#
44# Build Options
45#
46# CONFIG_STATIC is not set
47# CONFIG_PIE is not set
48# CONFIG_NOMMU is not set
49# CONFIG_BUILD_LIBBUSYBOX is not set
50# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
51# CONFIG_FEATURE_INDIVIDUAL is not set
52# CONFIG_FEATURE_SHARED_BUSYBOX is not set
53CONFIG_CROSS_COMPILER_PREFIX="i686-w64-mingw32-"
54CONFIG_SYSROOT=""
55CONFIG_EXTRA_CFLAGS=""
56CONFIG_EXTRA_LDFLAGS=""
57CONFIG_EXTRA_LDLIBS=""
58CONFIG_USE_PORTABLE_CODE=y
59
60#
61# Installation Options ("make install" behavior)
62#
63CONFIG_INSTALL_APPLET_SYMLINKS=y
64# CONFIG_INSTALL_APPLET_HARDLINKS is not set
65# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
66# CONFIG_INSTALL_APPLET_DONT is not set
67# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
68# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
69# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
70CONFIG_PREFIX=""
71
72#
73# Debugging Options
74#
75CONFIG_DEBUG=y
76# CONFIG_DEBUG_PESSIMIZE is not set
77# CONFIG_DEBUG_SANITIZE is not set
78# CONFIG_UNIT_TEST is not set
79# CONFIG_WERROR is not set
80CONFIG_NO_DEBUG_LIB=y
81# CONFIG_DMALLOC is not set
82# CONFIG_EFENCE is not set
83
84#
85# Library Tuning
86#
87# CONFIG_FEATURE_USE_BSS_TAIL is not set
88CONFIG_FEATURE_RTMINMAX=y
89CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
90# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
91# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
92CONFIG_PASSWORD_MINLEN=6
93CONFIG_MD5_SMALL=1
94CONFIG_SHA3_SMALL=1
95# CONFIG_FEATURE_FAST_TOP is not set
96# CONFIG_FEATURE_ETC_NETWORKS is not set
97CONFIG_FEATURE_EDITING=y
98CONFIG_FEATURE_EDITING_MAX_LEN=1024
99CONFIG_FEATURE_EDITING_VI=y
100CONFIG_FEATURE_EDITING_HISTORY=255
101CONFIG_FEATURE_EDITING_SAVEHISTORY=y
102# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
103CONFIG_FEATURE_REVERSE_SEARCH=y
104CONFIG_FEATURE_TAB_COMPLETION=y
105CONFIG_FEATURE_USERNAME_COMPLETION=y
106CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
107# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
108# CONFIG_LOCALE_SUPPORT is not set
109# CONFIG_UNICODE_SUPPORT is not set
110# CONFIG_UNICODE_USING_LOCALE is not set
111# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
112CONFIG_SUBST_WCHAR=0
113CONFIG_LAST_SUPPORTED_WCHAR=0
114# CONFIG_UNICODE_COMBINING_WCHARS is not set
115# CONFIG_UNICODE_WIDE_WCHARS is not set
116# CONFIG_UNICODE_BIDI_SUPPORT is not set
117# CONFIG_UNICODE_NEUTRAL_TABLE is not set
118# CONFIG_UNICODE_PRESERVE_BROKEN is not set
119CONFIG_FEATURE_NON_POSIX_CP=y
120# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
121# CONFIG_FEATURE_USE_SENDFILE is not set
122CONFIG_FEATURE_COPYBUF_KB=4
123CONFIG_FEATURE_SKIP_ROOTFS=y
124# CONFIG_MONOTONIC_SYSCALL is not set
125CONFIG_IOCTL_HEX2STR_ERROR=y
126# CONFIG_FEATURE_HWIB is not set
127
128#
129# Applets
130#
131
132#
133# Archival Utilities
134#
135CONFIG_FEATURE_SEAMLESS_XZ=y
136CONFIG_FEATURE_SEAMLESS_LZMA=y
137CONFIG_FEATURE_SEAMLESS_BZ2=y
138CONFIG_FEATURE_SEAMLESS_GZ=y
139CONFIG_FEATURE_SEAMLESS_Z=y
140CONFIG_AR=y
141CONFIG_FEATURE_AR_LONG_FILENAMES=y
142CONFIG_FEATURE_AR_CREATE=y
143CONFIG_UNCOMPRESS=y
144CONFIG_GUNZIP=y
145CONFIG_ZCAT=y
146CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
147CONFIG_BUNZIP2=y
148CONFIG_BZCAT=y
149CONFIG_UNLZMA=y
150CONFIG_LZCAT=y
151CONFIG_LZMA=y
152CONFIG_UNXZ=y
153CONFIG_XZCAT=y
154CONFIG_XZ=y
155CONFIG_BZIP2=y
156CONFIG_FEATURE_BZIP2_DECOMPRESS=y
157CONFIG_CPIO=y
158CONFIG_FEATURE_CPIO_O=y
159CONFIG_FEATURE_CPIO_P=y
160# CONFIG_DPKG is not set
161CONFIG_DPKG_DEB=y
162CONFIG_GZIP=y
163CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
164CONFIG_GZIP_FAST=2
165CONFIG_FEATURE_GZIP_LEVELS=y
166CONFIG_FEATURE_GZIP_DECOMPRESS=y
167CONFIG_LZOP=y
168CONFIG_UNLZOP=y
169CONFIG_LZOPCAT=y
170# CONFIG_LZOP_COMPR_HIGH is not set
171CONFIG_RPM2CPIO=y
172# CONFIG_RPM is not set
173CONFIG_TAR=y
174CONFIG_FEATURE_TAR_LONG_OPTIONS=y
175CONFIG_FEATURE_TAR_CREATE=y
176CONFIG_FEATURE_TAR_AUTODETECT=y
177CONFIG_FEATURE_TAR_FROM=y
178CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
179# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
180CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
181# CONFIG_FEATURE_TAR_TO_COMMAND is not set
182# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
183CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
184# CONFIG_FEATURE_TAR_SELINUX is not set
185CONFIG_UNZIP=y
186CONFIG_FEATURE_UNZIP_CDF=y
187CONFIG_FEATURE_UNZIP_BZIP2=y
188CONFIG_FEATURE_UNZIP_LZMA=y
189CONFIG_FEATURE_UNZIP_XZ=y
190CONFIG_FEATURE_LZMA_FAST=y
191
192#
193# Coreutils
194#
195CONFIG_BASENAME=y
196CONFIG_CAT=y
197CONFIG_FEATURE_CATN=y
198CONFIG_FEATURE_CATV=y
199# CONFIG_CHGRP is not set
200CONFIG_CHMOD=y
201# CONFIG_CHOWN is not set
202# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
203# CONFIG_CHROOT is not set
204CONFIG_CKSUM=y
205CONFIG_COMM=y
206CONFIG_CP=y
207CONFIG_FEATURE_CP_LONG_OPTIONS=y
208CONFIG_CUT=y
209CONFIG_DATE=y
210CONFIG_FEATURE_DATE_ISOFMT=y
211# CONFIG_FEATURE_DATE_NANO is not set
212CONFIG_FEATURE_DATE_COMPAT=y
213CONFIG_DD=y
214# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
215# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
216CONFIG_FEATURE_DD_IBS_OBS=y
217CONFIG_FEATURE_DD_STATUS=y
218CONFIG_DF=y
219# CONFIG_FEATURE_DF_FANCY is not set
220CONFIG_DIRNAME=y
221CONFIG_DOS2UNIX=y
222CONFIG_UNIX2DOS=y
223CONFIG_DU=y
224CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
225CONFIG_ECHO=y
226CONFIG_FEATURE_FANCY_ECHO=y
227CONFIG_ENV=y
228CONFIG_FEATURE_ENV_LONG_OPTIONS=y
229CONFIG_EXPAND=y
230CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
231CONFIG_UNEXPAND=y
232CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
233CONFIG_EXPR=y
234CONFIG_EXPR_MATH_SUPPORT_64=y
235CONFIG_FACTOR=y
236CONFIG_FALSE=y
237CONFIG_FOLD=y
238# CONFIG_FSYNC is not set
239CONFIG_HEAD=y
240CONFIG_FEATURE_FANCY_HEAD=y
241# CONFIG_HOSTID is not set
242CONFIG_ID=y
243CONFIG_GROUPS=y
244# CONFIG_INSTALL is not set
245# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
246CONFIG_LINK=y
247CONFIG_LN=y
248CONFIG_LOGNAME=y
249CONFIG_LS=y
250CONFIG_FEATURE_LS_FILETYPES=y
251CONFIG_FEATURE_LS_FOLLOWLINKS=y
252CONFIG_FEATURE_LS_RECURSIVE=y
253CONFIG_FEATURE_LS_WIDTH=y
254CONFIG_FEATURE_LS_SORTFILES=y
255CONFIG_FEATURE_LS_TIMESTAMPS=y
256CONFIG_FEATURE_LS_USERNAME=y
257CONFIG_FEATURE_LS_COLOR=y
258CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
259CONFIG_MD5SUM=y
260CONFIG_SHA1SUM=y
261CONFIG_SHA256SUM=y
262CONFIG_SHA512SUM=y
263CONFIG_SHA3SUM=y
264
265#
266# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
267#
268CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
269CONFIG_MKDIR=y
270CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
271# CONFIG_MKFIFO is not set
272# CONFIG_MKNOD is not set
273CONFIG_MKTEMP=y
274CONFIG_MV=y
275CONFIG_FEATURE_MV_LONG_OPTIONS=y
276# CONFIG_NICE is not set
277CONFIG_NL=y
278# CONFIG_NOHUP is not set
279# CONFIG_NPROC is not set
280CONFIG_OD=y
281CONFIG_PASTE=y
282CONFIG_PRINTENV=y
283CONFIG_PRINTF=y
284CONFIG_PWD=y
285# CONFIG_READLINK is not set
286# CONFIG_FEATURE_READLINK_FOLLOW is not set
287# CONFIG_REALPATH is not set
288CONFIG_RM=y
289CONFIG_RMDIR=y
290CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
291CONFIG_SEQ=y
292# CONFIG_SHRED is not set
293CONFIG_SHUF=y
294CONFIG_SLEEP=y
295CONFIG_FEATURE_FANCY_SLEEP=y
296CONFIG_FEATURE_FLOAT_SLEEP=y
297CONFIG_SORT=y
298CONFIG_FEATURE_SORT_BIG=y
299CONFIG_SPLIT=y
300CONFIG_FEATURE_SPLIT_FANCY=y
301CONFIG_STAT=y
302CONFIG_FEATURE_STAT_FORMAT=y
303CONFIG_FEATURE_STAT_FILESYSTEM=y
304# CONFIG_STTY is not set
305CONFIG_SUM=y
306# CONFIG_SYNC is not set
307# CONFIG_FEATURE_SYNC_FANCY is not set
308CONFIG_TAC=y
309CONFIG_TAIL=y
310CONFIG_FEATURE_FANCY_TAIL=y
311CONFIG_TEE=y
312CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
313CONFIG_TEST=y
314CONFIG_TEST1=y
315CONFIG_TEST2=y
316CONFIG_FEATURE_TEST_64=y
317# CONFIG_TIMEOUT is not set
318CONFIG_TOUCH=y
319# CONFIG_FEATURE_TOUCH_NODEREF is not set
320CONFIG_FEATURE_TOUCH_SUSV3=y
321CONFIG_TR=y
322CONFIG_FEATURE_TR_CLASSES=y
323CONFIG_FEATURE_TR_EQUIV=y
324CONFIG_TRUE=y
325CONFIG_TRUNCATE=y
326# CONFIG_TTY is not set
327CONFIG_UNAME=y
328CONFIG_UNAME_OSNAME="MS/Windows"
329CONFIG_BB_ARCH=y
330CONFIG_UNIQ=y
331CONFIG_UNLINK=y
332CONFIG_USLEEP=y
333CONFIG_UUDECODE=y
334CONFIG_BASE64=y
335CONFIG_UUENCODE=y
336CONFIG_WC=y
337CONFIG_FEATURE_WC_LARGE=y
338CONFIG_WHOAMI=y
339# CONFIG_WHO is not set
340# CONFIG_W is not set
341# CONFIG_USERS is not set
342CONFIG_YES=y
343
344#
345# Common options
346#
347CONFIG_FEATURE_VERBOSE=y
348
349#
350# Common options for cp and mv
351#
352# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
353
354#
355# Common options for df, du, ls
356#
357CONFIG_FEATURE_HUMAN_READABLE=y
358
359#
360# Console Utilities
361#
362# CONFIG_CHVT is not set
363CONFIG_CLEAR=y
364# CONFIG_DEALLOCVT is not set
365# CONFIG_DUMPKMAP is not set
366# CONFIG_FGCONSOLE is not set
367# CONFIG_KBD_MODE is not set
368# CONFIG_LOADFONT is not set
369# CONFIG_SETFONT is not set
370# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
371CONFIG_DEFAULT_SETFONT_DIR=""
372# CONFIG_FEATURE_LOADFONT_PSF2 is not set
373# CONFIG_FEATURE_LOADFONT_RAW is not set
374# CONFIG_LOADKMAP is not set
375# CONFIG_OPENVT is not set
376# CONFIG_RESET is not set
377# CONFIG_RESIZE is not set
378# CONFIG_FEATURE_RESIZE_PRINT is not set
379# CONFIG_SETCONSOLE is not set
380# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
381# CONFIG_SETKEYCODES is not set
382# CONFIG_SETLOGCONS is not set
383# CONFIG_SHOWKEY is not set
384
385#
386# Debian Utilities
387#
388# CONFIG_PIPE_PROGRESS is not set
389# CONFIG_RUN_PARTS is not set
390# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
391# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
392# CONFIG_START_STOP_DAEMON is not set
393# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
394# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
395CONFIG_WHICH=y
396
397#
398# Editors
399#
400CONFIG_AWK=y
401CONFIG_FEATURE_AWK_LIBM=y
402CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
403CONFIG_CMP=y
404CONFIG_DIFF=y
405CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
406CONFIG_FEATURE_DIFF_DIR=y
407CONFIG_ED=y
408CONFIG_PATCH=y
409CONFIG_SED=y
410CONFIG_VI=y
411CONFIG_FEATURE_VI_MAX_LEN=4096
412CONFIG_FEATURE_VI_8BIT=y
413CONFIG_FEATURE_VI_COLON=y
414CONFIG_FEATURE_VI_YANKMARK=y
415CONFIG_FEATURE_VI_SEARCH=y
416# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
417# CONFIG_FEATURE_VI_USE_SIGNALS is not set
418CONFIG_FEATURE_VI_DOT_CMD=y
419CONFIG_FEATURE_VI_READONLY=y
420CONFIG_FEATURE_VI_SETOPTS=y
421CONFIG_FEATURE_VI_SET=y
422CONFIG_FEATURE_VI_WIN_RESIZE=y
423CONFIG_FEATURE_VI_ASK_TERMINAL=y
424CONFIG_FEATURE_VI_UNDO=y
425CONFIG_FEATURE_VI_UNDO_QUEUE=y
426CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
427CONFIG_FEATURE_ALLOW_EXEC=y
428
429#
430# Finding Utilities
431#
432CONFIG_FIND=y
433CONFIG_FEATURE_FIND_PRINT0=y
434CONFIG_FEATURE_FIND_MTIME=y
435CONFIG_FEATURE_FIND_MMIN=y
436CONFIG_FEATURE_FIND_PERM=y
437CONFIG_FEATURE_FIND_TYPE=y
438# CONFIG_FEATURE_FIND_XDEV is not set
439CONFIG_FEATURE_FIND_MAXDEPTH=y
440CONFIG_FEATURE_FIND_NEWER=y
441# CONFIG_FEATURE_FIND_INUM is not set
442# CONFIG_FEATURE_FIND_EXEC is not set
443# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
444# CONFIG_FEATURE_FIND_USER is not set
445# CONFIG_FEATURE_FIND_GROUP is not set
446CONFIG_FEATURE_FIND_NOT=y
447CONFIG_FEATURE_FIND_DEPTH=y
448CONFIG_FEATURE_FIND_PAREN=y
449CONFIG_FEATURE_FIND_SIZE=y
450CONFIG_FEATURE_FIND_PRUNE=y
451CONFIG_FEATURE_FIND_DELETE=y
452CONFIG_FEATURE_FIND_PATH=y
453CONFIG_FEATURE_FIND_REGEX=y
454# CONFIG_FEATURE_FIND_CONTEXT is not set
455# CONFIG_FEATURE_FIND_LINKS is not set
456CONFIG_GREP=y
457CONFIG_EGREP=y
458CONFIG_FGREP=y
459CONFIG_FEATURE_GREP_CONTEXT=y
460CONFIG_XARGS=y
461CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
462CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
463CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
464CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
465CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
466
467#
468# Init Utilities
469#
470# CONFIG_BOOTCHARTD is not set
471# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
472# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
473# CONFIG_HALT is not set
474# CONFIG_POWEROFF is not set
475# CONFIG_REBOOT is not set
476# CONFIG_FEATURE_CALL_TELINIT is not set
477CONFIG_TELINIT_PATH=""
478# CONFIG_INIT is not set
479# CONFIG_LINUXRC is not set
480# CONFIG_FEATURE_USE_INITTAB is not set
481# CONFIG_FEATURE_KILL_REMOVED is not set
482CONFIG_FEATURE_KILL_DELAY=0
483# CONFIG_FEATURE_INIT_SCTTY is not set
484# CONFIG_FEATURE_INIT_SYSLOG is not set
485# CONFIG_FEATURE_INIT_QUIET is not set
486# CONFIG_FEATURE_INIT_COREDUMPS is not set
487CONFIG_INIT_TERMINAL_TYPE=""
488# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
489
490#
491# Login/Password Management Utilities
492#
493# CONFIG_FEATURE_SHADOWPASSWDS is not set
494# CONFIG_USE_BB_PWD_GRP is not set
495# CONFIG_USE_BB_SHADOW is not set
496# CONFIG_USE_BB_CRYPT is not set
497# CONFIG_USE_BB_CRYPT_SHA is not set
498# CONFIG_ADDGROUP is not set
499# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
500# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
501# CONFIG_ADD_SHELL is not set
502# CONFIG_REMOVE_SHELL is not set
503# CONFIG_ADDUSER is not set
504# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
505# CONFIG_FEATURE_CHECK_NAMES is not set
506CONFIG_LAST_ID=0
507CONFIG_FIRST_SYSTEM_ID=0
508CONFIG_LAST_SYSTEM_ID=0
509# CONFIG_CHPASSWD is not set
510CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
511# CONFIG_CRYPTPW is not set
512# CONFIG_MKPASSWD is not set
513# CONFIG_DELUSER is not set
514# CONFIG_DELGROUP is not set
515# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
516# CONFIG_GETTY is not set
517# CONFIG_LOGIN is not set
518# CONFIG_LOGIN_SESSION_AS_CHILD is not set
519# CONFIG_LOGIN_SCRIPTS is not set
520# CONFIG_FEATURE_NOLOGIN is not set
521# CONFIG_FEATURE_SECURETTY is not set
522# CONFIG_PASSWD is not set
523# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
524# CONFIG_SU is not set
525# CONFIG_FEATURE_SU_SYSLOG is not set
526# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
527# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
528# CONFIG_SULOGIN is not set
529# CONFIG_VLOCK is not set
530
531#
532# Linux Ext2 FS Progs
533#
534# CONFIG_CHATTR is not set
535# CONFIG_FSCK is not set
536# CONFIG_LSATTR is not set
537# CONFIG_TUNE2FS is not set
538
539#
540# Linux Module Utilities
541#
542# CONFIG_MODPROBE_SMALL is not set
543# CONFIG_DEPMOD is not set
544# CONFIG_INSMOD is not set
545# CONFIG_LSMOD is not set
546# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
547# CONFIG_MODINFO is not set
548# CONFIG_MODPROBE is not set
549# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
550# CONFIG_RMMOD is not set
551
552#
553# Options common to multiple modutils
554#
555# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
556# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
557# CONFIG_FEATURE_2_4_MODULES is not set
558# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
559# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
560# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
561# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
562# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
563# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
564# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
565# CONFIG_FEATURE_MODUTILS_ALIAS is not set
566# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
567CONFIG_DEFAULT_MODULES_DIR=""
568CONFIG_DEFAULT_DEPMOD_FILE=""
569
570#
571# Linux System Utilities
572#
573# CONFIG_ACPID is not set
574# CONFIG_FEATURE_ACPID_COMPAT is not set
575# CONFIG_BLKDISCARD is not set
576# CONFIG_BLKID is not set
577# CONFIG_FEATURE_BLKID_TYPE is not set
578# CONFIG_BLOCKDEV is not set
579CONFIG_CAL=y
580# CONFIG_CHRT is not set
581# CONFIG_DMESG is not set
582# CONFIG_FEATURE_DMESG_PRETTY is not set
583# CONFIG_EJECT is not set
584# CONFIG_FEATURE_EJECT_SCSI is not set
585# CONFIG_FALLOCATE is not set
586# CONFIG_FATATTR is not set
587# CONFIG_FBSET is not set
588# CONFIG_FEATURE_FBSET_FANCY is not set
589# CONFIG_FEATURE_FBSET_READMODE is not set
590# CONFIG_FDFORMAT is not set
591# CONFIG_FDISK is not set
592# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
593# CONFIG_FEATURE_FDISK_WRITABLE is not set
594# CONFIG_FEATURE_AIX_LABEL is not set
595# CONFIG_FEATURE_SGI_LABEL is not set
596# CONFIG_FEATURE_SUN_LABEL is not set
597# CONFIG_FEATURE_OSF_LABEL is not set
598# CONFIG_FEATURE_GPT_LABEL is not set
599# CONFIG_FEATURE_FDISK_ADVANCED is not set
600# CONFIG_FINDFS is not set
601# CONFIG_FLOCK is not set
602# CONFIG_FDFLUSH is not set
603# CONFIG_FREERAMDISK is not set
604# CONFIG_FSCK_MINIX is not set
605# CONFIG_FSFREEZE is not set
606# CONFIG_FSTRIM is not set
607CONFIG_GETOPT=y
608CONFIG_FEATURE_GETOPT_LONG=y
609CONFIG_HEXDUMP=y
610CONFIG_FEATURE_HEXDUMP_REVERSE=y
611CONFIG_HD=y
612CONFIG_XXD=y
613# CONFIG_HWCLOCK is not set
614# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
615# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
616# CONFIG_IONICE is not set
617# CONFIG_IPCRM is not set
618# CONFIG_IPCS is not set
619# CONFIG_LAST is not set
620# CONFIG_FEATURE_LAST_FANCY is not set
621# CONFIG_LOSETUP is not set
622# CONFIG_LSPCI is not set
623# CONFIG_LSUSB is not set
624# CONFIG_MDEV is not set
625# CONFIG_FEATURE_MDEV_CONF is not set
626# CONFIG_FEATURE_MDEV_RENAME is not set
627# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
628# CONFIG_FEATURE_MDEV_EXEC is not set
629# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
630# CONFIG_MESG is not set
631# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
632# CONFIG_MKE2FS is not set
633# CONFIG_MKFS_EXT2 is not set
634# CONFIG_MKFS_MINIX is not set
635# CONFIG_FEATURE_MINIX2 is not set
636# CONFIG_MKFS_REISER is not set
637# CONFIG_MKDOSFS is not set
638# CONFIG_MKFS_VFAT is not set
639# CONFIG_MKSWAP is not set
640# CONFIG_FEATURE_MKSWAP_UUID is not set
641# CONFIG_MORE is not set
642# CONFIG_MOUNT is not set
643# CONFIG_FEATURE_MOUNT_FAKE is not set
644# CONFIG_FEATURE_MOUNT_VERBOSE is not set
645# CONFIG_FEATURE_MOUNT_HELPERS is not set
646# CONFIG_FEATURE_MOUNT_LABEL is not set
647# CONFIG_FEATURE_MOUNT_NFS is not set
648# CONFIG_FEATURE_MOUNT_CIFS is not set
649# CONFIG_FEATURE_MOUNT_FLAGS is not set
650# CONFIG_FEATURE_MOUNT_FSTAB is not set
651# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
652# CONFIG_MOUNTPOINT is not set
653# CONFIG_NSENTER is not set
654# CONFIG_FEATURE_NSENTER_LONG_OPTS is not set
655# CONFIG_PIVOT_ROOT is not set
656# CONFIG_RDATE is not set
657# CONFIG_RDEV is not set
658# CONFIG_READPROFILE is not set
659# CONFIG_RENICE is not set
660CONFIG_REV=y
661# CONFIG_RTCWAKE is not set
662# CONFIG_SCRIPT is not set
663# CONFIG_SCRIPTREPLAY is not set
664# CONFIG_SETARCH is not set
665# CONFIG_LINUX32 is not set
666# CONFIG_LINUX64 is not set
667# CONFIG_SETPRIV is not set
668# CONFIG_FEATURE_SETPRIV_DUMP is not set
669# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
670# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
671# CONFIG_SETSID is not set
672# CONFIG_SWAPON is not set
673# CONFIG_FEATURE_SWAPON_DISCARD is not set
674# CONFIG_FEATURE_SWAPON_PRI is not set
675# CONFIG_SWAPOFF is not set
676# CONFIG_SWITCH_ROOT is not set
677# CONFIG_TASKSET is not set
678# CONFIG_FEATURE_TASKSET_FANCY is not set
679# CONFIG_UEVENT is not set
680# CONFIG_UMOUNT is not set
681# CONFIG_FEATURE_UMOUNT_ALL is not set
682# CONFIG_UNSHARE is not set
683# CONFIG_WALL is not set
684# CONFIG_FEATURE_MOUNT_LOOP is not set
685# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
686# CONFIG_FEATURE_MTAB_SUPPORT is not set
687# CONFIG_VOLUMEID is not set
688# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
689# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
690# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
691# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
692# CONFIG_FEATURE_VOLUMEID_EXT is not set
693# CONFIG_FEATURE_VOLUMEID_F2FS is not set
694# CONFIG_FEATURE_VOLUMEID_FAT is not set
695# CONFIG_FEATURE_VOLUMEID_HFS is not set
696# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
697# CONFIG_FEATURE_VOLUMEID_JFS is not set
698# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
699# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
700# CONFIG_FEATURE_VOLUMEID_LUKS is not set
701# CONFIG_FEATURE_VOLUMEID_NILFS is not set
702# CONFIG_FEATURE_VOLUMEID_NTFS is not set
703# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
704# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
705# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
706# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
707# CONFIG_FEATURE_VOLUMEID_SYSV is not set
708# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
709# CONFIG_FEATURE_VOLUMEID_UDF is not set
710# CONFIG_FEATURE_VOLUMEID_XFS is not set
711
712#
713# Miscellaneous Utilities
714#
715# CONFIG_ADJTIMEX is not set
716# CONFIG_BBCONFIG is not set
717# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
718# CONFIG_BEEP is not set
719CONFIG_FEATURE_BEEP_FREQ=0
720CONFIG_FEATURE_BEEP_LENGTH_MS=0
721# CONFIG_CHAT is not set
722# CONFIG_FEATURE_CHAT_NOFAIL is not set
723# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
724# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
725# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
726# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
727# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
728# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
729# CONFIG_CONSPY is not set
730# CONFIG_CROND is not set
731# CONFIG_FEATURE_CROND_D is not set
732# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
733# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
734CONFIG_FEATURE_CROND_DIR=""
735# CONFIG_CRONTAB is not set
736CONFIG_DC=y
737CONFIG_FEATURE_DC_LIBM=y
738# CONFIG_DEVFSD is not set
739# CONFIG_DEVFSD_MODLOAD is not set
740# CONFIG_DEVFSD_FG_NP is not set
741# CONFIG_DEVFSD_VERBOSE is not set
742# CONFIG_FEATURE_DEVFS is not set
743# CONFIG_DEVMEM is not set
744# CONFIG_FBSPLASH is not set
745# CONFIG_FLASHCP is not set
746# CONFIG_FLASH_ERASEALL is not set
747# CONFIG_FLASH_LOCK is not set
748# CONFIG_FLASH_UNLOCK is not set
749# CONFIG_HDPARM is not set
750# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
751# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
752# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
753# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
754# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
755# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
756# CONFIG_I2CGET is not set
757# CONFIG_I2CSET is not set
758# CONFIG_I2CDUMP is not set
759# CONFIG_I2CDETECT is not set
760# CONFIG_INOTIFYD is not set
761CONFIG_LESS=y
762CONFIG_FEATURE_LESS_MAXLINES=9999999
763CONFIG_FEATURE_LESS_BRACKETS=y
764CONFIG_FEATURE_LESS_FLAGS=y
765CONFIG_FEATURE_LESS_TRUNCATE=y
766CONFIG_FEATURE_LESS_MARKS=y
767CONFIG_FEATURE_LESS_REGEXP=y
768# CONFIG_FEATURE_LESS_WINCH is not set
769# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
770CONFIG_FEATURE_LESS_DASHCMD=y
771CONFIG_FEATURE_LESS_LINENUMS=y
772# CONFIG_LSSCSI is not set
773# CONFIG_MAKEDEVS is not set
774# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
775# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
776CONFIG_MAN=y
777# CONFIG_MICROCOM is not set
778# CONFIG_MT is not set
779# CONFIG_NANDWRITE is not set
780# CONFIG_NANDDUMP is not set
781# CONFIG_PARTPROBE is not set
782# CONFIG_RAIDAUTORUN is not set
783# CONFIG_READAHEAD is not set
784# CONFIG_RFKILL is not set
785# CONFIG_RUNLEVEL is not set
786# CONFIG_RX is not set
787# CONFIG_SETSERIAL is not set
788CONFIG_STRINGS=y
789# CONFIG_TIME is not set
790# CONFIG_TTYSIZE is not set
791# CONFIG_UBIRENAME is not set
792# CONFIG_UBIATTACH is not set
793# CONFIG_UBIDETACH is not set
794# CONFIG_UBIMKVOL is not set
795# CONFIG_UBIRMVOL is not set
796# CONFIG_UBIRSVOL is not set
797# CONFIG_UBIUPDATEVOL is not set
798# CONFIG_VOLNAME is not set
799# CONFIG_WATCHDOG is not set
800
801#
802# Networking Utilities
803#
804CONFIG_FEATURE_IPV6=y
805# CONFIG_FEATURE_UNIX_LOCAL is not set
806CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
807# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
808# CONFIG_ARP is not set
809# CONFIG_ARPING is not set
810# CONFIG_BRCTL is not set
811# CONFIG_FEATURE_BRCTL_FANCY is not set
812# CONFIG_FEATURE_BRCTL_SHOW is not set
813# CONFIG_DNSD is not set
814# CONFIG_ETHER_WAKE is not set
815# CONFIG_FTPD is not set
816# CONFIG_FEATURE_FTPD_WRITE is not set
817# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
818# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
819CONFIG_FTPGET=y
820CONFIG_FTPPUT=y
821CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
822# CONFIG_HOSTNAME is not set
823# CONFIG_DNSDOMAINNAME is not set
824# CONFIG_HTTPD is not set
825# CONFIG_FEATURE_HTTPD_RANGES is not set
826# CONFIG_FEATURE_HTTPD_SETUID is not set
827# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
828# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
829# CONFIG_FEATURE_HTTPD_CGI is not set
830# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
831# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
832# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
833# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
834# CONFIG_FEATURE_HTTPD_PROXY is not set
835# CONFIG_FEATURE_HTTPD_GZIP is not set
836# CONFIG_IFCONFIG is not set
837# CONFIG_FEATURE_IFCONFIG_STATUS is not set
838# CONFIG_FEATURE_IFCONFIG_SLIP is not set
839# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
840# CONFIG_FEATURE_IFCONFIG_HW is not set
841# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
842# CONFIG_IFENSLAVE is not set
843# CONFIG_IFPLUGD is not set
844# CONFIG_IFUP is not set
845# CONFIG_IFDOWN is not set
846CONFIG_IFUPDOWN_IFSTATE_PATH=""
847# CONFIG_FEATURE_IFUPDOWN_IP is not set
848# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
849# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
850# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
851# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
852# CONFIG_INETD is not set
853# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
854# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
855# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
856# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
857# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
858# CONFIG_FEATURE_INETD_RPC is not set
859# CONFIG_IP is not set
860# CONFIG_IPADDR is not set
861# CONFIG_IPLINK is not set
862# CONFIG_IPROUTE is not set
863# CONFIG_IPTUNNEL is not set
864# CONFIG_IPRULE is not set
865# CONFIG_IPNEIGH is not set
866# CONFIG_FEATURE_IP_ADDRESS is not set
867# CONFIG_FEATURE_IP_LINK is not set
868# CONFIG_FEATURE_IP_ROUTE is not set
869CONFIG_FEATURE_IP_ROUTE_DIR=""
870# CONFIG_FEATURE_IP_TUNNEL is not set
871# CONFIG_FEATURE_IP_RULE is not set
872# CONFIG_FEATURE_IP_NEIGH is not set
873# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
874CONFIG_IPCALC=y
875CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
876CONFIG_FEATURE_IPCALC_FANCY=y
877# CONFIG_FAKEIDENTD is not set
878# CONFIG_NAMEIF is not set
879# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
880# CONFIG_NBDCLIENT is not set
881CONFIG_NC=y
882CONFIG_NC_SERVER=y
883# CONFIG_NC_EXTRA is not set
884# CONFIG_NC_110_COMPAT is not set
885# CONFIG_NETSTAT is not set
886# CONFIG_FEATURE_NETSTAT_WIDE is not set
887# CONFIG_FEATURE_NETSTAT_PRG is not set
888# CONFIG_NSLOOKUP is not set
889# CONFIG_NTPD is not set
890# CONFIG_FEATURE_NTPD_SERVER is not set
891# CONFIG_FEATURE_NTPD_CONF is not set
892# CONFIG_PING is not set
893# CONFIG_PING6 is not set
894# CONFIG_FEATURE_FANCY_PING is not set
895# CONFIG_PSCAN is not set
896# CONFIG_ROUTE is not set
897# CONFIG_SLATTACH is not set
898# CONFIG_SSL_CLIENT is not set
899# CONFIG_TCPSVD is not set
900# CONFIG_UDPSVD is not set
901# CONFIG_TELNET is not set
902# CONFIG_FEATURE_TELNET_TTYPE is not set
903# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
904# CONFIG_FEATURE_TELNET_WIDTH is not set
905# CONFIG_TELNETD is not set
906# CONFIG_FEATURE_TELNETD_STANDALONE is not set
907# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
908# CONFIG_TFTP is not set
909# CONFIG_TFTPD is not set
910# CONFIG_FEATURE_TFTP_GET is not set
911# CONFIG_FEATURE_TFTP_PUT is not set
912# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
913# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
914# CONFIG_TFTP_DEBUG is not set
915# CONFIG_TLS is not set
916# CONFIG_TRACEROUTE is not set
917# CONFIG_TRACEROUTE6 is not set
918# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
919# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
920# CONFIG_TUNCTL is not set
921# CONFIG_FEATURE_TUNCTL_UG is not set
922# CONFIG_VCONFIG is not set
923CONFIG_WGET=y
924CONFIG_FEATURE_WGET_LONG_OPTIONS=y
925# CONFIG_FEATURE_WGET_STATUSBAR is not set
926# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
927# CONFIG_FEATURE_WGET_TIMEOUT is not set
928# CONFIG_FEATURE_WGET_HTTPS is not set
929# CONFIG_FEATURE_WGET_OPENSSL is not set
930CONFIG_WHOIS=y
931# CONFIG_ZCIP is not set
932# CONFIG_UDHCPC6 is not set
933# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
934# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
935# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
936# CONFIG_UDHCPD is not set
937# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
938# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
939CONFIG_DHCPD_LEASES_FILE=""
940# CONFIG_DUMPLEASES is not set
941# CONFIG_DHCPRELAY is not set
942# CONFIG_UDHCPC is not set
943# CONFIG_FEATURE_UDHCPC_ARPING is not set
944# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
945CONFIG_UDHCPC_DEFAULT_SCRIPT=""
946# CONFIG_FEATURE_UDHCP_PORT is not set
947CONFIG_UDHCP_DEBUG=0
948# CONFIG_FEATURE_UDHCP_RFC3397 is not set
949# CONFIG_FEATURE_UDHCP_8021Q is not set
950CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
951CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
952
953#
954# Print Utilities
955#
956# CONFIG_LPD is not set
957# CONFIG_LPR is not set
958# CONFIG_LPQ is not set
959
960#
961# Mail Utilities
962#
963# CONFIG_MAKEMIME is not set
964# CONFIG_POPMAILDIR is not set
965# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
966# CONFIG_REFORMIME is not set
967# CONFIG_FEATURE_REFORMIME_COMPAT is not set
968# CONFIG_SENDMAIL is not set
969CONFIG_FEATURE_MIME_CHARSET=""
970
971#
972# Process Utilities
973#
974# CONFIG_FREE is not set
975# CONFIG_FUSER is not set
976# CONFIG_IOSTAT is not set
977CONFIG_KILL=y
978CONFIG_KILLALL=y
979# CONFIG_KILLALL5 is not set
980# CONFIG_LSOF is not set
981# CONFIG_MPSTAT is not set
982# CONFIG_NMETER is not set
983CONFIG_PGREP=y
984# CONFIG_PKILL is not set
985CONFIG_PIDOF=y
986CONFIG_FEATURE_PIDOF_SINGLE=y
987CONFIG_FEATURE_PIDOF_OMIT=y
988# CONFIG_PMAP is not set
989# CONFIG_POWERTOP is not set
990# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
991CONFIG_PS=y
992# CONFIG_FEATURE_PS_WIDE is not set
993# CONFIG_FEATURE_PS_LONG is not set
994# CONFIG_FEATURE_PS_TIME is not set
995# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
996# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
997# CONFIG_PSTREE is not set
998# CONFIG_PWDX is not set
999# CONFIG_SMEMCAP is not set
1000# CONFIG_BB_SYSCTL is not set
1001# CONFIG_TOP is not set
1002# CONFIG_FEATURE_TOP_INTERACTIVE is not set
1003# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
1004# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
1005# CONFIG_FEATURE_TOP_SMP_CPU is not set
1006# CONFIG_FEATURE_TOP_DECIMALS is not set
1007# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
1008# CONFIG_FEATURE_TOPMEM is not set
1009# CONFIG_UPTIME is not set
1010# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1011CONFIG_WATCH=y
1012# CONFIG_FEATURE_SHOW_THREADS is not set
1013
1014#
1015# Runit Utilities
1016#
1017# CONFIG_CHPST is not set
1018# CONFIG_SETUIDGID is not set
1019# CONFIG_ENVUIDGID is not set
1020# CONFIG_ENVDIR is not set
1021# CONFIG_SOFTLIMIT is not set
1022# CONFIG_RUNSV is not set
1023# CONFIG_RUNSVDIR is not set
1024# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1025# CONFIG_SV is not set
1026CONFIG_SV_DEFAULT_SERVICE_DIR=""
1027# CONFIG_SVC is not set
1028# CONFIG_SVLOGD is not set
1029# CONFIG_CHCON is not set
1030# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
1031# CONFIG_GETENFORCE is not set
1032# CONFIG_GETSEBOOL is not set
1033# CONFIG_LOAD_POLICY is not set
1034# CONFIG_MATCHPATHCON is not set
1035# CONFIG_RUNCON is not set
1036# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
1037# CONFIG_SELINUXENABLED is not set
1038# CONFIG_SESTATUS is not set
1039# CONFIG_SETENFORCE is not set
1040# CONFIG_SETFILES is not set
1041# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1042# CONFIG_RESTORECON is not set
1043# CONFIG_SETSEBOOL is not set
1044
1045#
1046# Shells
1047#
1048CONFIG_SH_IS_ASH=y
1049# CONFIG_SH_IS_HUSH is not set
1050# CONFIG_SH_IS_NONE is not set
1051CONFIG_BASH_IS_ASH=y
1052# CONFIG_BASH_IS_HUSH is not set
1053# CONFIG_BASH_IS_NONE is not set
1054CONFIG_ASH=y
1055CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1056CONFIG_ASH_INTERNAL_GLOB=y
1057CONFIG_ASH_BASH_COMPAT=y
1058# CONFIG_ASH_JOB_CONTROL is not set
1059CONFIG_ASH_ALIAS=y
1060CONFIG_ASH_RANDOM_SUPPORT=y
1061CONFIG_ASH_EXPAND_PRMT=y
1062# CONFIG_ASH_IDLE_TIMEOUT is not set
1063# CONFIG_ASH_MAIL is not set
1064CONFIG_ASH_ECHO=y
1065CONFIG_ASH_PRINTF=y
1066CONFIG_ASH_TEST=y
1067CONFIG_ASH_HELP=y
1068CONFIG_ASH_GETOPTS=y
1069CONFIG_ASH_CMDCMD=y
1070CONFIG_ASH_NOCONSOLE=y
1071# CONFIG_CTTYHACK is not set
1072# CONFIG_HUSH is not set
1073# CONFIG_HUSH_BASH_COMPAT is not set
1074# CONFIG_HUSH_BRACE_EXPANSION is not set
1075# CONFIG_HUSH_INTERACTIVE is not set
1076# CONFIG_HUSH_SAVEHISTORY is not set
1077# CONFIG_HUSH_JOB is not set
1078# CONFIG_HUSH_TICK is not set
1079# CONFIG_HUSH_IF is not set
1080# CONFIG_HUSH_LOOPS is not set
1081# CONFIG_HUSH_CASE is not set
1082# CONFIG_HUSH_FUNCTIONS is not set
1083# CONFIG_HUSH_LOCAL is not set
1084# CONFIG_HUSH_RANDOM_SUPPORT is not set
1085# CONFIG_HUSH_MODE_X is not set
1086# CONFIG_HUSH_ECHO is not set
1087# CONFIG_HUSH_PRINTF is not set
1088# CONFIG_HUSH_TEST is not set
1089# CONFIG_HUSH_HELP is not set
1090# CONFIG_HUSH_EXPORT is not set
1091# CONFIG_HUSH_EXPORT_N is not set
1092# CONFIG_HUSH_READONLY is not set
1093# CONFIG_HUSH_KILL is not set
1094# CONFIG_HUSH_WAIT is not set
1095# CONFIG_HUSH_TRAP is not set
1096# CONFIG_HUSH_TYPE is not set
1097# CONFIG_HUSH_READ is not set
1098# CONFIG_HUSH_SET is not set
1099# CONFIG_HUSH_UNSET is not set
1100# CONFIG_HUSH_ULIMIT is not set
1101# CONFIG_HUSH_UMASK is not set
1102# CONFIG_HUSH_MEMLEAK is not set
1103
1104#
1105# Options common to all shells
1106#
1107CONFIG_FEATURE_SH_MATH=y
1108CONFIG_FEATURE_SH_MATH_64=y
1109CONFIG_FEATURE_SH_EXTRA_QUIET=y
1110CONFIG_FEATURE_SH_STANDALONE=y
1111CONFIG_FEATURE_SH_NOFORK=y
1112# CONFIG_FEATURE_SH_READ_FRAC is not set
1113CONFIG_FEATURE_SH_HISTFILESIZE=y
1114
1115#
1116# System Logging Utilities
1117#
1118# CONFIG_KLOGD is not set
1119# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1120# CONFIG_LOGGER is not set
1121# CONFIG_LOGREAD is not set
1122# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1123# CONFIG_SYSLOGD is not set
1124# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1125# CONFIG_FEATURE_REMOTE_LOG is not set
1126# CONFIG_FEATURE_SYSLOGD_DUP is not set
1127# CONFIG_FEATURE_SYSLOGD_CFG is not set
1128CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1129# CONFIG_FEATURE_IPC_SYSLOG is not set
1130CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1131# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
new file mode 100644
index 000000000..decb93015
--- /dev/null
+++ b/configs/mingw64_defconfig
@@ -0,0 +1,1131 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.28.0.git
4# Mon Jul 24 11:51:22 2017
5#
6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set
8CONFIG_PLATFORM_MINGW32=y
9
10#
11# Busybox Settings
12#
13CONFIG_DESKTOP=y
14# CONFIG_EXTRA_COMPAT is not set
15# CONFIG_INCLUDE_SUSv2 is not set
16CONFIG_LONG_OPTS=y
17CONFIG_SHOW_USAGE=y
18CONFIG_FEATURE_VERBOSE_USAGE=y
19CONFIG_FEATURE_COMPRESS_USAGE=y
20CONFIG_LFS=y
21# CONFIG_GLOBBING is not set
22CONFIG_SAFE_ENV=y
23# CONFIG_PAM is not set
24# CONFIG_FEATURE_DEVPTS is not set
25# CONFIG_FEATURE_UTMP is not set
26# CONFIG_FEATURE_WTMP is not set
27# CONFIG_FEATURE_PIDFILE is not set
28CONFIG_PID_FILE_PATH=""
29CONFIG_BUSYBOX=y
30CONFIG_FEATURE_INSTALLER=y
31# CONFIG_INSTALL_NO_USR is not set
32# CONFIG_FEATURE_SUID is not set
33# CONFIG_FEATURE_SUID_CONFIG is not set
34# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
35CONFIG_FEATURE_PREFER_APPLETS=y
36CONFIG_BUSYBOX_EXEC_PATH=""
37# CONFIG_SELINUX is not set
38# CONFIG_FEATURE_CLEAN_UP is not set
39# CONFIG_FEATURE_SYSLOG is not set
40# CONFIG_FEATURE_HAVE_RPC is not set
41# CONFIG_PLATFORM_LINUX is not set
42
43#
44# Build Options
45#
46# CONFIG_STATIC is not set
47# CONFIG_PIE is not set
48# CONFIG_NOMMU is not set
49# CONFIG_BUILD_LIBBUSYBOX is not set
50# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
51# CONFIG_FEATURE_INDIVIDUAL is not set
52# CONFIG_FEATURE_SHARED_BUSYBOX is not set
53CONFIG_CROSS_COMPILER_PREFIX="x86_64-w64-mingw32-"
54CONFIG_SYSROOT=""
55CONFIG_EXTRA_CFLAGS="-funwind-tables -fasynchronous-unwind-tables"
56CONFIG_EXTRA_LDFLAGS=""
57CONFIG_EXTRA_LDLIBS=""
58CONFIG_USE_PORTABLE_CODE=y
59
60#
61# Installation Options ("make install" behavior)
62#
63CONFIG_INSTALL_APPLET_SYMLINKS=y
64# CONFIG_INSTALL_APPLET_HARDLINKS is not set
65# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
66# CONFIG_INSTALL_APPLET_DONT is not set
67# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
68# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
69# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
70CONFIG_PREFIX=""
71
72#
73# Debugging Options
74#
75CONFIG_DEBUG=y
76# CONFIG_DEBUG_PESSIMIZE is not set
77# CONFIG_DEBUG_SANITIZE is not set
78# CONFIG_UNIT_TEST is not set
79# CONFIG_WERROR is not set
80CONFIG_NO_DEBUG_LIB=y
81# CONFIG_DMALLOC is not set
82# CONFIG_EFENCE is not set
83
84#
85# Library Tuning
86#
87# CONFIG_FEATURE_USE_BSS_TAIL is not set
88CONFIG_FEATURE_RTMINMAX=y
89CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
90# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
91# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
92CONFIG_PASSWORD_MINLEN=6
93CONFIG_MD5_SMALL=1
94CONFIG_SHA3_SMALL=1
95# CONFIG_FEATURE_FAST_TOP is not set
96# CONFIG_FEATURE_ETC_NETWORKS is not set
97CONFIG_FEATURE_EDITING=y
98CONFIG_FEATURE_EDITING_MAX_LEN=1024
99CONFIG_FEATURE_EDITING_VI=y
100CONFIG_FEATURE_EDITING_HISTORY=255
101CONFIG_FEATURE_EDITING_SAVEHISTORY=y
102# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
103CONFIG_FEATURE_REVERSE_SEARCH=y
104CONFIG_FEATURE_TAB_COMPLETION=y
105CONFIG_FEATURE_USERNAME_COMPLETION=y
106CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
107# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
108# CONFIG_LOCALE_SUPPORT is not set
109# CONFIG_UNICODE_SUPPORT is not set
110# CONFIG_UNICODE_USING_LOCALE is not set
111# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
112CONFIG_SUBST_WCHAR=0
113CONFIG_LAST_SUPPORTED_WCHAR=0
114# CONFIG_UNICODE_COMBINING_WCHARS is not set
115# CONFIG_UNICODE_WIDE_WCHARS is not set
116# CONFIG_UNICODE_BIDI_SUPPORT is not set
117# CONFIG_UNICODE_NEUTRAL_TABLE is not set
118# CONFIG_UNICODE_PRESERVE_BROKEN is not set
119CONFIG_FEATURE_NON_POSIX_CP=y
120# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
121# CONFIG_FEATURE_USE_SENDFILE is not set
122CONFIG_FEATURE_COPYBUF_KB=4
123CONFIG_FEATURE_SKIP_ROOTFS=y
124# CONFIG_MONOTONIC_SYSCALL is not set
125CONFIG_IOCTL_HEX2STR_ERROR=y
126# CONFIG_FEATURE_HWIB is not set
127
128#
129# Applets
130#
131
132#
133# Archival Utilities
134#
135CONFIG_FEATURE_SEAMLESS_XZ=y
136CONFIG_FEATURE_SEAMLESS_LZMA=y
137CONFIG_FEATURE_SEAMLESS_BZ2=y
138CONFIG_FEATURE_SEAMLESS_GZ=y
139CONFIG_FEATURE_SEAMLESS_Z=y
140CONFIG_AR=y
141CONFIG_FEATURE_AR_LONG_FILENAMES=y
142CONFIG_FEATURE_AR_CREATE=y
143CONFIG_UNCOMPRESS=y
144CONFIG_GUNZIP=y
145CONFIG_ZCAT=y
146CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
147CONFIG_BUNZIP2=y
148CONFIG_BZCAT=y
149CONFIG_UNLZMA=y
150CONFIG_LZCAT=y
151CONFIG_LZMA=y
152CONFIG_UNXZ=y
153CONFIG_XZCAT=y
154CONFIG_XZ=y
155CONFIG_BZIP2=y
156CONFIG_FEATURE_BZIP2_DECOMPRESS=y
157CONFIG_CPIO=y
158CONFIG_FEATURE_CPIO_O=y
159CONFIG_FEATURE_CPIO_P=y
160# CONFIG_DPKG is not set
161CONFIG_DPKG_DEB=y
162CONFIG_GZIP=y
163CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
164CONFIG_GZIP_FAST=2
165CONFIG_FEATURE_GZIP_LEVELS=y
166CONFIG_FEATURE_GZIP_DECOMPRESS=y
167CONFIG_LZOP=y
168CONFIG_UNLZOP=y
169CONFIG_LZOPCAT=y
170# CONFIG_LZOP_COMPR_HIGH is not set
171CONFIG_RPM2CPIO=y
172# CONFIG_RPM is not set
173CONFIG_TAR=y
174CONFIG_FEATURE_TAR_LONG_OPTIONS=y
175CONFIG_FEATURE_TAR_CREATE=y
176CONFIG_FEATURE_TAR_AUTODETECT=y
177CONFIG_FEATURE_TAR_FROM=y
178CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
179# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
180CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
181# CONFIG_FEATURE_TAR_TO_COMMAND is not set
182# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
183CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
184# CONFIG_FEATURE_TAR_SELINUX is not set
185CONFIG_UNZIP=y
186CONFIG_FEATURE_UNZIP_CDF=y
187CONFIG_FEATURE_UNZIP_BZIP2=y
188CONFIG_FEATURE_UNZIP_LZMA=y
189CONFIG_FEATURE_UNZIP_XZ=y
190CONFIG_FEATURE_LZMA_FAST=y
191
192#
193# Coreutils
194#
195CONFIG_BASENAME=y
196CONFIG_CAT=y
197CONFIG_FEATURE_CATN=y
198CONFIG_FEATURE_CATV=y
199# CONFIG_CHGRP is not set
200CONFIG_CHMOD=y
201# CONFIG_CHOWN is not set
202# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
203# CONFIG_CHROOT is not set
204CONFIG_CKSUM=y
205CONFIG_COMM=y
206CONFIG_CP=y
207CONFIG_FEATURE_CP_LONG_OPTIONS=y
208CONFIG_CUT=y
209CONFIG_DATE=y
210CONFIG_FEATURE_DATE_ISOFMT=y
211# CONFIG_FEATURE_DATE_NANO is not set
212CONFIG_FEATURE_DATE_COMPAT=y
213CONFIG_DD=y
214# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
215# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
216CONFIG_FEATURE_DD_IBS_OBS=y
217CONFIG_FEATURE_DD_STATUS=y
218CONFIG_DF=y
219# CONFIG_FEATURE_DF_FANCY is not set
220CONFIG_DIRNAME=y
221CONFIG_DOS2UNIX=y
222CONFIG_UNIX2DOS=y
223CONFIG_DU=y
224CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
225CONFIG_ECHO=y
226CONFIG_FEATURE_FANCY_ECHO=y
227CONFIG_ENV=y
228CONFIG_FEATURE_ENV_LONG_OPTIONS=y
229CONFIG_EXPAND=y
230CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
231CONFIG_UNEXPAND=y
232CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
233CONFIG_EXPR=y
234CONFIG_EXPR_MATH_SUPPORT_64=y
235CONFIG_FACTOR=y
236CONFIG_FALSE=y
237CONFIG_FOLD=y
238# CONFIG_FSYNC is not set
239CONFIG_HEAD=y
240CONFIG_FEATURE_FANCY_HEAD=y
241# CONFIG_HOSTID is not set
242CONFIG_ID=y
243CONFIG_GROUPS=y
244# CONFIG_INSTALL is not set
245# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
246CONFIG_LINK=y
247CONFIG_LN=y
248CONFIG_LOGNAME=y
249CONFIG_LS=y
250CONFIG_FEATURE_LS_FILETYPES=y
251CONFIG_FEATURE_LS_FOLLOWLINKS=y
252CONFIG_FEATURE_LS_RECURSIVE=y
253CONFIG_FEATURE_LS_WIDTH=y
254CONFIG_FEATURE_LS_SORTFILES=y
255CONFIG_FEATURE_LS_TIMESTAMPS=y
256CONFIG_FEATURE_LS_USERNAME=y
257CONFIG_FEATURE_LS_COLOR=y
258CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
259CONFIG_MD5SUM=y
260CONFIG_SHA1SUM=y
261CONFIG_SHA256SUM=y
262CONFIG_SHA512SUM=y
263CONFIG_SHA3SUM=y
264
265#
266# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
267#
268CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
269CONFIG_MKDIR=y
270CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
271# CONFIG_MKFIFO is not set
272# CONFIG_MKNOD is not set
273CONFIG_MKTEMP=y
274CONFIG_MV=y
275CONFIG_FEATURE_MV_LONG_OPTIONS=y
276# CONFIG_NICE is not set
277CONFIG_NL=y
278# CONFIG_NOHUP is not set
279# CONFIG_NPROC is not set
280CONFIG_OD=y
281CONFIG_PASTE=y
282CONFIG_PRINTENV=y
283CONFIG_PRINTF=y
284CONFIG_PWD=y
285# CONFIG_READLINK is not set
286# CONFIG_FEATURE_READLINK_FOLLOW is not set
287# CONFIG_REALPATH is not set
288CONFIG_RM=y
289CONFIG_RMDIR=y
290CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
291CONFIG_SEQ=y
292# CONFIG_SHRED is not set
293CONFIG_SHUF=y
294CONFIG_SLEEP=y
295CONFIG_FEATURE_FANCY_SLEEP=y
296CONFIG_FEATURE_FLOAT_SLEEP=y
297CONFIG_SORT=y
298CONFIG_FEATURE_SORT_BIG=y
299CONFIG_SPLIT=y
300CONFIG_FEATURE_SPLIT_FANCY=y
301CONFIG_STAT=y
302CONFIG_FEATURE_STAT_FORMAT=y
303CONFIG_FEATURE_STAT_FILESYSTEM=y
304# CONFIG_STTY is not set
305CONFIG_SUM=y
306# CONFIG_SYNC is not set
307# CONFIG_FEATURE_SYNC_FANCY is not set
308CONFIG_TAC=y
309CONFIG_TAIL=y
310CONFIG_FEATURE_FANCY_TAIL=y
311CONFIG_TEE=y
312CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
313CONFIG_TEST=y
314CONFIG_TEST1=y
315CONFIG_TEST2=y
316CONFIG_FEATURE_TEST_64=y
317# CONFIG_TIMEOUT is not set
318CONFIG_TOUCH=y
319# CONFIG_FEATURE_TOUCH_NODEREF is not set
320CONFIG_FEATURE_TOUCH_SUSV3=y
321CONFIG_TR=y
322CONFIG_FEATURE_TR_CLASSES=y
323CONFIG_FEATURE_TR_EQUIV=y
324CONFIG_TRUE=y
325CONFIG_TRUNCATE=y
326# CONFIG_TTY is not set
327CONFIG_UNAME=y
328CONFIG_UNAME_OSNAME="MS/Windows"
329CONFIG_BB_ARCH=y
330CONFIG_UNIQ=y
331CONFIG_UNLINK=y
332CONFIG_USLEEP=y
333CONFIG_UUDECODE=y
334CONFIG_BASE64=y
335CONFIG_UUENCODE=y
336CONFIG_WC=y
337CONFIG_FEATURE_WC_LARGE=y
338CONFIG_WHOAMI=y
339# CONFIG_WHO is not set
340# CONFIG_W is not set
341# CONFIG_USERS is not set
342CONFIG_YES=y
343
344#
345# Common options
346#
347CONFIG_FEATURE_VERBOSE=y
348
349#
350# Common options for cp and mv
351#
352# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
353
354#
355# Common options for df, du, ls
356#
357CONFIG_FEATURE_HUMAN_READABLE=y
358
359#
360# Console Utilities
361#
362# CONFIG_CHVT is not set
363CONFIG_CLEAR=y
364# CONFIG_DEALLOCVT is not set
365# CONFIG_DUMPKMAP is not set
366# CONFIG_FGCONSOLE is not set
367# CONFIG_KBD_MODE is not set
368# CONFIG_LOADFONT is not set
369# CONFIG_SETFONT is not set
370# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
371CONFIG_DEFAULT_SETFONT_DIR=""
372# CONFIG_FEATURE_LOADFONT_PSF2 is not set
373# CONFIG_FEATURE_LOADFONT_RAW is not set
374# CONFIG_LOADKMAP is not set
375# CONFIG_OPENVT is not set
376# CONFIG_RESET is not set
377# CONFIG_RESIZE is not set
378# CONFIG_FEATURE_RESIZE_PRINT is not set
379# CONFIG_SETCONSOLE is not set
380# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
381# CONFIG_SETKEYCODES is not set
382# CONFIG_SETLOGCONS is not set
383# CONFIG_SHOWKEY is not set
384
385#
386# Debian Utilities
387#
388# CONFIG_PIPE_PROGRESS is not set
389# CONFIG_RUN_PARTS is not set
390# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
391# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
392# CONFIG_START_STOP_DAEMON is not set
393# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
394# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
395CONFIG_WHICH=y
396
397#
398# Editors
399#
400CONFIG_AWK=y
401CONFIG_FEATURE_AWK_LIBM=y
402CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
403CONFIG_CMP=y
404CONFIG_DIFF=y
405CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
406CONFIG_FEATURE_DIFF_DIR=y
407CONFIG_ED=y
408CONFIG_PATCH=y
409CONFIG_SED=y
410CONFIG_VI=y
411CONFIG_FEATURE_VI_MAX_LEN=4096
412CONFIG_FEATURE_VI_8BIT=y
413CONFIG_FEATURE_VI_COLON=y
414CONFIG_FEATURE_VI_YANKMARK=y
415CONFIG_FEATURE_VI_SEARCH=y
416# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
417# CONFIG_FEATURE_VI_USE_SIGNALS is not set
418CONFIG_FEATURE_VI_DOT_CMD=y
419CONFIG_FEATURE_VI_READONLY=y
420CONFIG_FEATURE_VI_SETOPTS=y
421CONFIG_FEATURE_VI_SET=y
422CONFIG_FEATURE_VI_WIN_RESIZE=y
423CONFIG_FEATURE_VI_ASK_TERMINAL=y
424CONFIG_FEATURE_VI_UNDO=y
425CONFIG_FEATURE_VI_UNDO_QUEUE=y
426CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
427CONFIG_FEATURE_ALLOW_EXEC=y
428
429#
430# Finding Utilities
431#
432CONFIG_FIND=y
433CONFIG_FEATURE_FIND_PRINT0=y
434CONFIG_FEATURE_FIND_MTIME=y
435CONFIG_FEATURE_FIND_MMIN=y
436CONFIG_FEATURE_FIND_PERM=y
437CONFIG_FEATURE_FIND_TYPE=y
438# CONFIG_FEATURE_FIND_XDEV is not set
439CONFIG_FEATURE_FIND_MAXDEPTH=y
440CONFIG_FEATURE_FIND_NEWER=y
441# CONFIG_FEATURE_FIND_INUM is not set
442# CONFIG_FEATURE_FIND_EXEC is not set
443# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
444# CONFIG_FEATURE_FIND_USER is not set
445# CONFIG_FEATURE_FIND_GROUP is not set
446CONFIG_FEATURE_FIND_NOT=y
447CONFIG_FEATURE_FIND_DEPTH=y
448CONFIG_FEATURE_FIND_PAREN=y
449CONFIG_FEATURE_FIND_SIZE=y
450CONFIG_FEATURE_FIND_PRUNE=y
451CONFIG_FEATURE_FIND_DELETE=y
452CONFIG_FEATURE_FIND_PATH=y
453CONFIG_FEATURE_FIND_REGEX=y
454# CONFIG_FEATURE_FIND_CONTEXT is not set
455# CONFIG_FEATURE_FIND_LINKS is not set
456CONFIG_GREP=y
457CONFIG_EGREP=y
458CONFIG_FGREP=y
459CONFIG_FEATURE_GREP_CONTEXT=y
460CONFIG_XARGS=y
461CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
462CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
463CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
464CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
465CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
466
467#
468# Init Utilities
469#
470# CONFIG_BOOTCHARTD is not set
471# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
472# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
473# CONFIG_HALT is not set
474# CONFIG_POWEROFF is not set
475# CONFIG_REBOOT is not set
476# CONFIG_FEATURE_CALL_TELINIT is not set
477CONFIG_TELINIT_PATH=""
478# CONFIG_INIT is not set
479# CONFIG_LINUXRC is not set
480# CONFIG_FEATURE_USE_INITTAB is not set
481# CONFIG_FEATURE_KILL_REMOVED is not set
482CONFIG_FEATURE_KILL_DELAY=0
483# CONFIG_FEATURE_INIT_SCTTY is not set
484# CONFIG_FEATURE_INIT_SYSLOG is not set
485# CONFIG_FEATURE_INIT_QUIET is not set
486# CONFIG_FEATURE_INIT_COREDUMPS is not set
487CONFIG_INIT_TERMINAL_TYPE=""
488# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
489
490#
491# Login/Password Management Utilities
492#
493# CONFIG_FEATURE_SHADOWPASSWDS is not set
494# CONFIG_USE_BB_PWD_GRP is not set
495# CONFIG_USE_BB_SHADOW is not set
496# CONFIG_USE_BB_CRYPT is not set
497# CONFIG_USE_BB_CRYPT_SHA is not set
498# CONFIG_ADDGROUP is not set
499# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
500# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
501# CONFIG_ADD_SHELL is not set
502# CONFIG_REMOVE_SHELL is not set
503# CONFIG_ADDUSER is not set
504# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
505# CONFIG_FEATURE_CHECK_NAMES is not set
506CONFIG_LAST_ID=0
507CONFIG_FIRST_SYSTEM_ID=0
508CONFIG_LAST_SYSTEM_ID=0
509# CONFIG_CHPASSWD is not set
510CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
511# CONFIG_CRYPTPW is not set
512# CONFIG_MKPASSWD is not set
513# CONFIG_DELUSER is not set
514# CONFIG_DELGROUP is not set
515# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
516# CONFIG_GETTY is not set
517# CONFIG_LOGIN is not set
518# CONFIG_LOGIN_SESSION_AS_CHILD is not set
519# CONFIG_LOGIN_SCRIPTS is not set
520# CONFIG_FEATURE_NOLOGIN is not set
521# CONFIG_FEATURE_SECURETTY is not set
522# CONFIG_PASSWD is not set
523# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
524# CONFIG_SU is not set
525# CONFIG_FEATURE_SU_SYSLOG is not set
526# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
527# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
528# CONFIG_SULOGIN is not set
529# CONFIG_VLOCK is not set
530
531#
532# Linux Ext2 FS Progs
533#
534# CONFIG_CHATTR is not set
535# CONFIG_FSCK is not set
536# CONFIG_LSATTR is not set
537# CONFIG_TUNE2FS is not set
538
539#
540# Linux Module Utilities
541#
542# CONFIG_MODPROBE_SMALL is not set
543# CONFIG_DEPMOD is not set
544# CONFIG_INSMOD is not set
545# CONFIG_LSMOD is not set
546# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
547# CONFIG_MODINFO is not set
548# CONFIG_MODPROBE is not set
549# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
550# CONFIG_RMMOD is not set
551
552#
553# Options common to multiple modutils
554#
555# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
556# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
557# CONFIG_FEATURE_2_4_MODULES is not set
558# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
559# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
560# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
561# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
562# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
563# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
564# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
565# CONFIG_FEATURE_MODUTILS_ALIAS is not set
566# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
567CONFIG_DEFAULT_MODULES_DIR=""
568CONFIG_DEFAULT_DEPMOD_FILE=""
569
570#
571# Linux System Utilities
572#
573# CONFIG_ACPID is not set
574# CONFIG_FEATURE_ACPID_COMPAT is not set
575# CONFIG_BLKDISCARD is not set
576# CONFIG_BLKID is not set
577# CONFIG_FEATURE_BLKID_TYPE is not set
578# CONFIG_BLOCKDEV is not set
579CONFIG_CAL=y
580# CONFIG_CHRT is not set
581# CONFIG_DMESG is not set
582# CONFIG_FEATURE_DMESG_PRETTY is not set
583# CONFIG_EJECT is not set
584# CONFIG_FEATURE_EJECT_SCSI is not set
585# CONFIG_FALLOCATE is not set
586# CONFIG_FATATTR is not set
587# CONFIG_FBSET is not set
588# CONFIG_FEATURE_FBSET_FANCY is not set
589# CONFIG_FEATURE_FBSET_READMODE is not set
590# CONFIG_FDFORMAT is not set
591# CONFIG_FDISK is not set
592# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
593# CONFIG_FEATURE_FDISK_WRITABLE is not set
594# CONFIG_FEATURE_AIX_LABEL is not set
595# CONFIG_FEATURE_SGI_LABEL is not set
596# CONFIG_FEATURE_SUN_LABEL is not set
597# CONFIG_FEATURE_OSF_LABEL is not set
598# CONFIG_FEATURE_GPT_LABEL is not set
599# CONFIG_FEATURE_FDISK_ADVANCED is not set
600# CONFIG_FINDFS is not set
601# CONFIG_FLOCK is not set
602# CONFIG_FDFLUSH is not set
603# CONFIG_FREERAMDISK is not set
604# CONFIG_FSCK_MINIX is not set
605# CONFIG_FSFREEZE is not set
606# CONFIG_FSTRIM is not set
607CONFIG_GETOPT=y
608CONFIG_FEATURE_GETOPT_LONG=y
609CONFIG_HEXDUMP=y
610CONFIG_FEATURE_HEXDUMP_REVERSE=y
611CONFIG_HD=y
612CONFIG_XXD=y
613# CONFIG_HWCLOCK is not set
614# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
615# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
616# CONFIG_IONICE is not set
617# CONFIG_IPCRM is not set
618# CONFIG_IPCS is not set
619# CONFIG_LAST is not set
620# CONFIG_FEATURE_LAST_FANCY is not set
621# CONFIG_LOSETUP is not set
622# CONFIG_LSPCI is not set
623# CONFIG_LSUSB is not set
624# CONFIG_MDEV is not set
625# CONFIG_FEATURE_MDEV_CONF is not set
626# CONFIG_FEATURE_MDEV_RENAME is not set
627# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
628# CONFIG_FEATURE_MDEV_EXEC is not set
629# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
630# CONFIG_MESG is not set
631# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
632# CONFIG_MKE2FS is not set
633# CONFIG_MKFS_EXT2 is not set
634# CONFIG_MKFS_MINIX is not set
635# CONFIG_FEATURE_MINIX2 is not set
636# CONFIG_MKFS_REISER is not set
637# CONFIG_MKDOSFS is not set
638# CONFIG_MKFS_VFAT is not set
639# CONFIG_MKSWAP is not set
640# CONFIG_FEATURE_MKSWAP_UUID is not set
641# CONFIG_MORE is not set
642# CONFIG_MOUNT is not set
643# CONFIG_FEATURE_MOUNT_FAKE is not set
644# CONFIG_FEATURE_MOUNT_VERBOSE is not set
645# CONFIG_FEATURE_MOUNT_HELPERS is not set
646# CONFIG_FEATURE_MOUNT_LABEL is not set
647# CONFIG_FEATURE_MOUNT_NFS is not set
648# CONFIG_FEATURE_MOUNT_CIFS is not set
649# CONFIG_FEATURE_MOUNT_FLAGS is not set
650# CONFIG_FEATURE_MOUNT_FSTAB is not set
651# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
652# CONFIG_MOUNTPOINT is not set
653# CONFIG_NSENTER is not set
654# CONFIG_FEATURE_NSENTER_LONG_OPTS is not set
655# CONFIG_PIVOT_ROOT is not set
656# CONFIG_RDATE is not set
657# CONFIG_RDEV is not set
658# CONFIG_READPROFILE is not set
659# CONFIG_RENICE is not set
660CONFIG_REV=y
661# CONFIG_RTCWAKE is not set
662# CONFIG_SCRIPT is not set
663# CONFIG_SCRIPTREPLAY is not set
664# CONFIG_SETARCH is not set
665# CONFIG_LINUX32 is not set
666# CONFIG_LINUX64 is not set
667# CONFIG_SETPRIV is not set
668# CONFIG_FEATURE_SETPRIV_DUMP is not set
669# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
670# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
671# CONFIG_SETSID is not set
672# CONFIG_SWAPON is not set
673# CONFIG_FEATURE_SWAPON_DISCARD is not set
674# CONFIG_FEATURE_SWAPON_PRI is not set
675# CONFIG_SWAPOFF is not set
676# CONFIG_SWITCH_ROOT is not set
677# CONFIG_TASKSET is not set
678# CONFIG_FEATURE_TASKSET_FANCY is not set
679# CONFIG_UEVENT is not set
680# CONFIG_UMOUNT is not set
681# CONFIG_FEATURE_UMOUNT_ALL is not set
682# CONFIG_UNSHARE is not set
683# CONFIG_WALL is not set
684# CONFIG_FEATURE_MOUNT_LOOP is not set
685# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
686# CONFIG_FEATURE_MTAB_SUPPORT is not set
687# CONFIG_VOLUMEID is not set
688# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
689# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
690# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
691# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
692# CONFIG_FEATURE_VOLUMEID_EXT is not set
693# CONFIG_FEATURE_VOLUMEID_F2FS is not set
694# CONFIG_FEATURE_VOLUMEID_FAT is not set
695# CONFIG_FEATURE_VOLUMEID_HFS is not set
696# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
697# CONFIG_FEATURE_VOLUMEID_JFS is not set
698# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
699# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
700# CONFIG_FEATURE_VOLUMEID_LUKS is not set
701# CONFIG_FEATURE_VOLUMEID_NILFS is not set
702# CONFIG_FEATURE_VOLUMEID_NTFS is not set
703# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
704# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
705# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
706# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
707# CONFIG_FEATURE_VOLUMEID_SYSV is not set
708# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
709# CONFIG_FEATURE_VOLUMEID_UDF is not set
710# CONFIG_FEATURE_VOLUMEID_XFS is not set
711
712#
713# Miscellaneous Utilities
714#
715# CONFIG_ADJTIMEX is not set
716# CONFIG_BBCONFIG is not set
717# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
718# CONFIG_BEEP is not set
719CONFIG_FEATURE_BEEP_FREQ=0
720CONFIG_FEATURE_BEEP_LENGTH_MS=0
721# CONFIG_CHAT is not set
722# CONFIG_FEATURE_CHAT_NOFAIL is not set
723# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
724# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
725# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
726# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
727# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
728# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
729# CONFIG_CONSPY is not set
730# CONFIG_CROND is not set
731# CONFIG_FEATURE_CROND_D is not set
732# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
733# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
734CONFIG_FEATURE_CROND_DIR=""
735# CONFIG_CRONTAB is not set
736CONFIG_DC=y
737CONFIG_FEATURE_DC_LIBM=y
738# CONFIG_DEVFSD is not set
739# CONFIG_DEVFSD_MODLOAD is not set
740# CONFIG_DEVFSD_FG_NP is not set
741# CONFIG_DEVFSD_VERBOSE is not set
742# CONFIG_FEATURE_DEVFS is not set
743# CONFIG_DEVMEM is not set
744# CONFIG_FBSPLASH is not set
745# CONFIG_FLASHCP is not set
746# CONFIG_FLASH_ERASEALL is not set
747# CONFIG_FLASH_LOCK is not set
748# CONFIG_FLASH_UNLOCK is not set
749# CONFIG_HDPARM is not set
750# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
751# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
752# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
753# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
754# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
755# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
756# CONFIG_I2CGET is not set
757# CONFIG_I2CSET is not set
758# CONFIG_I2CDUMP is not set
759# CONFIG_I2CDETECT is not set
760# CONFIG_INOTIFYD is not set
761CONFIG_LESS=y
762CONFIG_FEATURE_LESS_MAXLINES=9999999
763CONFIG_FEATURE_LESS_BRACKETS=y
764CONFIG_FEATURE_LESS_FLAGS=y
765CONFIG_FEATURE_LESS_TRUNCATE=y
766CONFIG_FEATURE_LESS_MARKS=y
767CONFIG_FEATURE_LESS_REGEXP=y
768# CONFIG_FEATURE_LESS_WINCH is not set
769# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
770CONFIG_FEATURE_LESS_DASHCMD=y
771CONFIG_FEATURE_LESS_LINENUMS=y
772# CONFIG_LSSCSI is not set
773# CONFIG_MAKEDEVS is not set
774# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
775# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
776CONFIG_MAN=y
777# CONFIG_MICROCOM is not set
778# CONFIG_MT is not set
779# CONFIG_NANDWRITE is not set
780# CONFIG_NANDDUMP is not set
781# CONFIG_PARTPROBE is not set
782# CONFIG_RAIDAUTORUN is not set
783# CONFIG_READAHEAD is not set
784# CONFIG_RFKILL is not set
785# CONFIG_RUNLEVEL is not set
786# CONFIG_RX is not set
787# CONFIG_SETSERIAL is not set
788CONFIG_STRINGS=y
789# CONFIG_TIME is not set
790# CONFIG_TTYSIZE is not set
791# CONFIG_UBIRENAME is not set
792# CONFIG_UBIATTACH is not set
793# CONFIG_UBIDETACH is not set
794# CONFIG_UBIMKVOL is not set
795# CONFIG_UBIRMVOL is not set
796# CONFIG_UBIRSVOL is not set
797# CONFIG_UBIUPDATEVOL is not set
798# CONFIG_VOLNAME is not set
799# CONFIG_WATCHDOG is not set
800
801#
802# Networking Utilities
803#
804CONFIG_FEATURE_IPV6=y
805# CONFIG_FEATURE_UNIX_LOCAL is not set
806CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
807# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
808# CONFIG_ARP is not set
809# CONFIG_ARPING is not set
810# CONFIG_BRCTL is not set
811# CONFIG_FEATURE_BRCTL_FANCY is not set
812# CONFIG_FEATURE_BRCTL_SHOW is not set
813# CONFIG_DNSD is not set
814# CONFIG_ETHER_WAKE is not set
815# CONFIG_FTPD is not set
816# CONFIG_FEATURE_FTPD_WRITE is not set
817# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
818# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
819CONFIG_FTPGET=y
820CONFIG_FTPPUT=y
821CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
822# CONFIG_HOSTNAME is not set
823# CONFIG_DNSDOMAINNAME is not set
824# CONFIG_HTTPD is not set
825# CONFIG_FEATURE_HTTPD_RANGES is not set
826# CONFIG_FEATURE_HTTPD_SETUID is not set
827# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
828# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
829# CONFIG_FEATURE_HTTPD_CGI is not set
830# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
831# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
832# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
833# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
834# CONFIG_FEATURE_HTTPD_PROXY is not set
835# CONFIG_FEATURE_HTTPD_GZIP is not set
836# CONFIG_IFCONFIG is not set
837# CONFIG_FEATURE_IFCONFIG_STATUS is not set
838# CONFIG_FEATURE_IFCONFIG_SLIP is not set
839# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
840# CONFIG_FEATURE_IFCONFIG_HW is not set
841# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
842# CONFIG_IFENSLAVE is not set
843# CONFIG_IFPLUGD is not set
844# CONFIG_IFUP is not set
845# CONFIG_IFDOWN is not set
846CONFIG_IFUPDOWN_IFSTATE_PATH=""
847# CONFIG_FEATURE_IFUPDOWN_IP is not set
848# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
849# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
850# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
851# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
852# CONFIG_INETD is not set
853# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
854# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
855# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
856# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
857# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
858# CONFIG_FEATURE_INETD_RPC is not set
859# CONFIG_IP is not set
860# CONFIG_IPADDR is not set
861# CONFIG_IPLINK is not set
862# CONFIG_IPROUTE is not set
863# CONFIG_IPTUNNEL is not set
864# CONFIG_IPRULE is not set
865# CONFIG_IPNEIGH is not set
866# CONFIG_FEATURE_IP_ADDRESS is not set
867# CONFIG_FEATURE_IP_LINK is not set
868# CONFIG_FEATURE_IP_ROUTE is not set
869CONFIG_FEATURE_IP_ROUTE_DIR=""
870# CONFIG_FEATURE_IP_TUNNEL is not set
871# CONFIG_FEATURE_IP_RULE is not set
872# CONFIG_FEATURE_IP_NEIGH is not set
873# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
874CONFIG_IPCALC=y
875CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
876CONFIG_FEATURE_IPCALC_FANCY=y
877# CONFIG_FAKEIDENTD is not set
878# CONFIG_NAMEIF is not set
879# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
880# CONFIG_NBDCLIENT is not set
881CONFIG_NC=y
882CONFIG_NC_SERVER=y
883# CONFIG_NC_EXTRA is not set
884# CONFIG_NC_110_COMPAT is not set
885# CONFIG_NETSTAT is not set
886# CONFIG_FEATURE_NETSTAT_WIDE is not set
887# CONFIG_FEATURE_NETSTAT_PRG is not set
888# CONFIG_NSLOOKUP is not set
889# CONFIG_NTPD is not set
890# CONFIG_FEATURE_NTPD_SERVER is not set
891# CONFIG_FEATURE_NTPD_CONF is not set
892# CONFIG_PING is not set
893# CONFIG_PING6 is not set
894# CONFIG_FEATURE_FANCY_PING is not set
895# CONFIG_PSCAN is not set
896# CONFIG_ROUTE is not set
897# CONFIG_SLATTACH is not set
898# CONFIG_SSL_CLIENT is not set
899# CONFIG_TCPSVD is not set
900# CONFIG_UDPSVD is not set
901# CONFIG_TELNET is not set
902# CONFIG_FEATURE_TELNET_TTYPE is not set
903# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
904# CONFIG_FEATURE_TELNET_WIDTH is not set
905# CONFIG_TELNETD is not set
906# CONFIG_FEATURE_TELNETD_STANDALONE is not set
907# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
908# CONFIG_TFTP is not set
909# CONFIG_TFTPD is not set
910# CONFIG_FEATURE_TFTP_GET is not set
911# CONFIG_FEATURE_TFTP_PUT is not set
912# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
913# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
914# CONFIG_TFTP_DEBUG is not set
915# CONFIG_TLS is not set
916# CONFIG_TRACEROUTE is not set
917# CONFIG_TRACEROUTE6 is not set
918# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
919# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
920# CONFIG_TUNCTL is not set
921# CONFIG_FEATURE_TUNCTL_UG is not set
922# CONFIG_VCONFIG is not set
923CONFIG_WGET=y
924CONFIG_FEATURE_WGET_LONG_OPTIONS=y
925# CONFIG_FEATURE_WGET_STATUSBAR is not set
926# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
927# CONFIG_FEATURE_WGET_TIMEOUT is not set
928# CONFIG_FEATURE_WGET_HTTPS is not set
929# CONFIG_FEATURE_WGET_OPENSSL is not set
930CONFIG_WHOIS=y
931# CONFIG_ZCIP is not set
932# CONFIG_UDHCPC6 is not set
933# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
934# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
935# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
936# CONFIG_UDHCPD is not set
937# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
938# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
939CONFIG_DHCPD_LEASES_FILE=""
940# CONFIG_DUMPLEASES is not set
941# CONFIG_DHCPRELAY is not set
942# CONFIG_UDHCPC is not set
943# CONFIG_FEATURE_UDHCPC_ARPING is not set
944# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
945CONFIG_UDHCPC_DEFAULT_SCRIPT=""
946# CONFIG_FEATURE_UDHCP_PORT is not set
947CONFIG_UDHCP_DEBUG=0
948# CONFIG_FEATURE_UDHCP_RFC3397 is not set
949# CONFIG_FEATURE_UDHCP_8021Q is not set
950CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
951CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
952
953#
954# Print Utilities
955#
956# CONFIG_LPD is not set
957# CONFIG_LPR is not set
958# CONFIG_LPQ is not set
959
960#
961# Mail Utilities
962#
963# CONFIG_MAKEMIME is not set
964# CONFIG_POPMAILDIR is not set
965# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
966# CONFIG_REFORMIME is not set
967# CONFIG_FEATURE_REFORMIME_COMPAT is not set
968# CONFIG_SENDMAIL is not set
969CONFIG_FEATURE_MIME_CHARSET=""
970
971#
972# Process Utilities
973#
974# CONFIG_FREE is not set
975# CONFIG_FUSER is not set
976# CONFIG_IOSTAT is not set
977CONFIG_KILL=y
978CONFIG_KILLALL=y
979# CONFIG_KILLALL5 is not set
980# CONFIG_LSOF is not set
981# CONFIG_MPSTAT is not set
982# CONFIG_NMETER is not set
983CONFIG_PGREP=y
984# CONFIG_PKILL is not set
985CONFIG_PIDOF=y
986CONFIG_FEATURE_PIDOF_SINGLE=y
987CONFIG_FEATURE_PIDOF_OMIT=y
988# CONFIG_PMAP is not set
989# CONFIG_POWERTOP is not set
990# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
991CONFIG_PS=y
992# CONFIG_FEATURE_PS_WIDE is not set
993# CONFIG_FEATURE_PS_LONG is not set
994# CONFIG_FEATURE_PS_TIME is not set
995# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
996# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
997# CONFIG_PSTREE is not set
998# CONFIG_PWDX is not set
999# CONFIG_SMEMCAP is not set
1000# CONFIG_BB_SYSCTL is not set
1001# CONFIG_TOP is not set
1002# CONFIG_FEATURE_TOP_INTERACTIVE is not set
1003# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
1004# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
1005# CONFIG_FEATURE_TOP_SMP_CPU is not set
1006# CONFIG_FEATURE_TOP_DECIMALS is not set
1007# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
1008# CONFIG_FEATURE_TOPMEM is not set
1009# CONFIG_UPTIME is not set
1010# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1011CONFIG_WATCH=y
1012# CONFIG_FEATURE_SHOW_THREADS is not set
1013
1014#
1015# Runit Utilities
1016#
1017# CONFIG_CHPST is not set
1018# CONFIG_SETUIDGID is not set
1019# CONFIG_ENVUIDGID is not set
1020# CONFIG_ENVDIR is not set
1021# CONFIG_SOFTLIMIT is not set
1022# CONFIG_RUNSV is not set
1023# CONFIG_RUNSVDIR is not set
1024# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1025# CONFIG_SV is not set
1026CONFIG_SV_DEFAULT_SERVICE_DIR=""
1027# CONFIG_SVC is not set
1028# CONFIG_SVLOGD is not set
1029# CONFIG_CHCON is not set
1030# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
1031# CONFIG_GETENFORCE is not set
1032# CONFIG_GETSEBOOL is not set
1033# CONFIG_LOAD_POLICY is not set
1034# CONFIG_MATCHPATHCON is not set
1035# CONFIG_RUNCON is not set
1036# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
1037# CONFIG_SELINUXENABLED is not set
1038# CONFIG_SESTATUS is not set
1039# CONFIG_SETENFORCE is not set
1040# CONFIG_SETFILES is not set
1041# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1042# CONFIG_RESTORECON is not set
1043# CONFIG_SETSEBOOL is not set
1044
1045#
1046# Shells
1047#
1048CONFIG_SH_IS_ASH=y
1049# CONFIG_SH_IS_HUSH is not set
1050# CONFIG_SH_IS_NONE is not set
1051CONFIG_BASH_IS_ASH=y
1052# CONFIG_BASH_IS_HUSH is not set
1053# CONFIG_BASH_IS_NONE is not set
1054CONFIG_ASH=y
1055CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1056CONFIG_ASH_INTERNAL_GLOB=y
1057CONFIG_ASH_BASH_COMPAT=y
1058# CONFIG_ASH_JOB_CONTROL is not set
1059CONFIG_ASH_ALIAS=y
1060CONFIG_ASH_RANDOM_SUPPORT=y
1061CONFIG_ASH_EXPAND_PRMT=y
1062# CONFIG_ASH_IDLE_TIMEOUT is not set
1063# CONFIG_ASH_MAIL is not set
1064CONFIG_ASH_ECHO=y
1065CONFIG_ASH_PRINTF=y
1066CONFIG_ASH_TEST=y
1067CONFIG_ASH_HELP=y
1068CONFIG_ASH_GETOPTS=y
1069CONFIG_ASH_CMDCMD=y
1070# CONFIG_ASH_NOCONSOLE is not set
1071# CONFIG_CTTYHACK is not set
1072# CONFIG_HUSH is not set
1073# CONFIG_HUSH_BASH_COMPAT is not set
1074# CONFIG_HUSH_BRACE_EXPANSION is not set
1075# CONFIG_HUSH_INTERACTIVE is not set
1076# CONFIG_HUSH_SAVEHISTORY is not set
1077# CONFIG_HUSH_JOB is not set
1078# CONFIG_HUSH_TICK is not set
1079# CONFIG_HUSH_IF is not set
1080# CONFIG_HUSH_LOOPS is not set
1081# CONFIG_HUSH_CASE is not set
1082# CONFIG_HUSH_FUNCTIONS is not set
1083# CONFIG_HUSH_LOCAL is not set
1084# CONFIG_HUSH_RANDOM_SUPPORT is not set
1085# CONFIG_HUSH_MODE_X is not set
1086# CONFIG_HUSH_ECHO is not set
1087# CONFIG_HUSH_PRINTF is not set
1088# CONFIG_HUSH_TEST is not set
1089# CONFIG_HUSH_HELP is not set
1090# CONFIG_HUSH_EXPORT is not set
1091# CONFIG_HUSH_EXPORT_N is not set
1092# CONFIG_HUSH_READONLY is not set
1093# CONFIG_HUSH_KILL is not set
1094# CONFIG_HUSH_WAIT is not set
1095# CONFIG_HUSH_TRAP is not set
1096# CONFIG_HUSH_TYPE is not set
1097# CONFIG_HUSH_READ is not set
1098# CONFIG_HUSH_SET is not set
1099# CONFIG_HUSH_UNSET is not set
1100# CONFIG_HUSH_ULIMIT is not set
1101# CONFIG_HUSH_UMASK is not set
1102# CONFIG_HUSH_MEMLEAK is not set
1103
1104#
1105# Options common to all shells
1106#
1107CONFIG_FEATURE_SH_MATH=y
1108CONFIG_FEATURE_SH_MATH_64=y
1109CONFIG_FEATURE_SH_EXTRA_QUIET=y
1110CONFIG_FEATURE_SH_STANDALONE=y
1111CONFIG_FEATURE_SH_NOFORK=y
1112# CONFIG_FEATURE_SH_READ_FRAC is not set
1113CONFIG_FEATURE_SH_HISTFILESIZE=y
1114
1115#
1116# System Logging Utilities
1117#
1118# CONFIG_KLOGD is not set
1119# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1120# CONFIG_LOGGER is not set
1121# CONFIG_LOGREAD is not set
1122# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1123# CONFIG_SYSLOGD is not set
1124# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1125# CONFIG_FEATURE_REMOTE_LOG is not set
1126# CONFIG_FEATURE_SYSLOGD_DUP is not set
1127# CONFIG_FEATURE_SYSLOGD_CFG is not set
1128CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1129# CONFIG_FEATURE_IPC_SYSLOG is not set
1130CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1131# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 43545c010..f7f1c9564 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -293,6 +293,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
293#endif 293#endif
294 }; 294 };
295 smallint exitcode = EXIT_FAILURE; 295 smallint exitcode = EXIT_FAILURE;
296 int devzero = 0;
296 int i; 297 int i;
297 size_t ibs = 512; 298 size_t ibs = 512;
298 char *ibuf; 299 char *ibuf;
@@ -419,7 +420,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
419#endif 420#endif
420 421
421 if (infile) { 422 if (infile) {
422 xmove_fd(xopen(infile, O_RDONLY), ifd); 423 if (ENABLE_PLATFORM_MINGW32 && !strcmp(infile, "/dev/zero")) {
424 G.flags |= FLAG_NOERROR;
425 devzero = 1;
426 } else {
427 xmove_fd(xopen(infile, O_RDONLY), ifd);
428 }
423 } else { 429 } else {
424 infile = bb_msg_standard_input; 430 infile = bb_msg_standard_input;
425 } 431 }
@@ -446,7 +452,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
446 } else { 452 } else {
447 outfile = bb_msg_standard_output; 453 outfile = bb_msg_standard_output;
448 } 454 }
449 if (skip) { 455 if (skip && !devzero) {
450 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; 456 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs;
451 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { 457 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) {
452 do { 458 do {
@@ -466,7 +472,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
466 while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { 472 while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
467 ssize_t n; 473 ssize_t n;
468 474
469 n = safe_read(ifd, ibuf, ibs); 475 if (devzero) {
476 memset(ibuf, 0, ibs);
477 n = ibs;
478 }
479 else
480 n = safe_read(ifd, ibuf, ibs);
470 if (n == 0) 481 if (n == 0)
471 break; 482 break;
472 if (n < 0) { 483 if (n < 0) {
@@ -542,7 +553,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
542 if (write_and_stats(obuf, oc, obs, outfile)) 553 if (write_and_stats(obuf, oc, obs, outfile))
543 goto out_status; 554 goto out_status;
544 } 555 }
545 if (close(ifd) < 0) { 556
557 if (!devzero && close(ifd) < 0) {
546 die_infile: 558 die_infile:
547 bb_simple_perror_msg_and_die(infile); 559 bb_simple_perror_msg_and_die(infile);
548 } 560 }
diff --git a/coreutils/expr.c b/coreutils/expr.c
index a2bbfdd69..0cf2b9bd9 100644
--- a/coreutils/expr.c
+++ b/coreutils/expr.c
@@ -84,7 +84,7 @@
84#if ENABLE_EXPR_MATH_SUPPORT_64 84#if ENABLE_EXPR_MATH_SUPPORT_64
85typedef int64_t arith_t; 85typedef int64_t arith_t;
86 86
87#define PF_REZ "ll" 87#define PF_REZ LL_FMT
88#define PF_REZ_TYPE (long long) 88#define PF_REZ_TYPE (long long)
89#define STRTOL(s, e, b) strtoll(s, e, b) 89#define STRTOL(s, e, b) strtoll(s, e, b)
90#else 90#else
diff --git a/coreutils/factor.c b/coreutils/factor.c
index 467e23a4d..ee3943a4a 100644
--- a/coreutils/factor.c
+++ b/coreutils/factor.c
@@ -161,7 +161,7 @@ static NOINLINE void factorize(wide_t N)
161 } 161 }
162 end: 162 end:
163 if (N > 1) 163 if (N > 1)
164 printf(" %llu", N); 164 printf(" %"LL_FMT"u", N);
165 bb_putchar('\n'); 165 bb_putchar('\n');
166} 166}
167 167
@@ -175,7 +175,7 @@ static void factorize_numstr(const char *numstr)
175 N = bb_strtoull(numstr, NULL, 10); 175 N = bb_strtoull(numstr, NULL, 10);
176 if (errno) 176 if (errno)
177 bb_show_usage(); 177 bb_show_usage();
178 printf("%llu:", N); 178 printf("%"LL_FMT"u:", N);
179 factorize(N); 179 factorize(N);
180} 180}
181 181
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 0fe0345b3..4c0944bb0 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -496,7 +496,7 @@ static NOINLINE unsigned display_single(const struct dnode *dn)
496 lpath = xmalloc_readlink_or_warn(dn->fullname); 496 lpath = xmalloc_readlink_or_warn(dn->fullname);
497 497
498 if (opt & OPT_i) /* show inode# */ 498 if (opt & OPT_i) /* show inode# */
499 column += printf("%7llu ", (long long) dn->dn_ino); 499 column += printf("%7"LL_FMT"u ", (long long) dn->dn_ino);
500//TODO: -h should affect -s too: 500//TODO: -h should affect -s too:
501 if (opt & OPT_s) /* show allocated blocks */ 501 if (opt & OPT_s) /* show allocated blocks */
502 column += printf("%6"OFF_FMT"u ", (off_t) (dn->dn_blocks >> 1)); 502 column += printf("%6"OFF_FMT"u ", (off_t) (dn->dn_blocks >> 1));
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index fa0196ca4..513c8ef37 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -101,6 +101,13 @@ typedef long long llong;
101# define LDBL_DIG DBL_DIG 101# define LDBL_DIG DBL_DIG
102#endif 102#endif
103 103
104#if ENABLE_PLATFORM_MINGW32
105/* symbol conflict */
106#define CHAR SIZE_CHAR
107#define SHORT SIZE_SHORT
108#define LONG SIZE_LONG
109#define INT SIZE_INT
110#endif
104enum size_spec { 111enum size_spec {
105 NO_SIZE, 112 NO_SIZE,
106 CHAR, 113 CHAR,
diff --git a/coreutils/stat.c b/coreutils/stat.c
index 3b85808b5..96efa1d5d 100644
--- a/coreutils/stat.c
+++ b/coreutils/stat.c
@@ -31,7 +31,6 @@
31//config: bool "Enable display of filesystem status (-f)" 31//config: bool "Enable display of filesystem status (-f)"
32//config: default y 32//config: default y
33//config: depends on STAT 33//config: depends on STAT
34//config: select PLATFORM_LINUX # statfs()
35//config: help 34//config: help
36//config: Without this, stat will not support the '-f' option to display 35//config: Without this, stat will not support the '-f' option to display
37//config: information about filesystem status. 36//config: information about filesystem status.
diff --git a/coreutils/sum.c b/coreutils/sum.c
index 487e93f4a..ee758877f 100644
--- a/coreutils/sum.c
+++ b/coreutils/sum.c
@@ -82,9 +82,9 @@ static unsigned sum_file(const char *file, unsigned type)
82 if (type >= SUM_SYSV) { 82 if (type >= SUM_SYSV) {
83 r = (s & 0xffff) + ((s & 0xffffffff) >> 16); 83 r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
84 s = (r & 0xffff) + (r >> 16); 84 s = (r & 0xffff) + (r >> 16);
85 printf("%u %llu %s\n", s, (total_bytes + 511) / 512, file); 85 printf("%u %"LL_FMT"u %s\n", s, (total_bytes + 511) / 512, file);
86 } else 86 } else
87 printf("%05u %5llu %s\n", s, (total_bytes + 1023) / 1024, file); 87 printf("%05u %5"OFF_FMT"u %s\n", s, (total_bytes + 1023) / 1024, file);
88 return 1; 88 return 1;
89#undef buf 89#undef buf
90} 90}
diff --git a/coreutils/test.c b/coreutils/test.c
index a8286525a..ed708c6d3 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -637,6 +637,21 @@ static int filstat(char *nm, enum token mode)
637 return 0; 637 return 0;
638 } 638 }
639 639
640#if ENABLE_PLATFORM_MINGW32
641 if (mode == FILEX) {
642 char *p;
643
644 if (file_is_executable(nm)) {
645 return 1;
646 }
647 else if ((p=file_is_win32_executable(nm))) {
648 free(p);
649 return 1;
650 }
651 return 0;
652 }
653#endif
654
640 if (stat(nm, &s) != 0) 655 if (stat(nm, &s) != 0)
641 return 0; 656 return 0;
642 if (mode == FILEXIST) 657 if (mode == FILEXIST)
diff --git a/coreutils/yes.c b/coreutils/yes.c
index 493b7b1c3..a5a444249 100644
--- a/coreutils/yes.c
+++ b/coreutils/yes.c
@@ -40,6 +40,10 @@ int yes_main(int argc UNUSED_PARAM, char **argv)
40 ++argv; 40 ++argv;
41 41
42 do { 42 do {
43#if ENABLE_PLATFORM_MINGW32
44 if (ferror(stdout) != 0)
45 break;
46#endif
43 pp = argv; 47 pp = argv;
44 while (1) { 48 while (1) {
45 fputs(*pp, stdout); 49 fputs(*pp, stdout);
diff --git a/debianutils/which.c b/debianutils/which.c
index 3197ddac1..23a481438 100644
--- a/debianutils/which.c
+++ b/debianutils/which.c
@@ -43,17 +43,34 @@ int which_main(int argc UNUSED_PARAM, char **argv)
43 43
44 do { 44 do {
45 int missing = 1; 45 int missing = 1;
46 char *p;
47
48#if ENABLE_FEATURE_SH_STANDALONE
49 if (find_applet_by_name(*argv) >= 0 ||
50 is_prefixed_with(*argv, "busybox")) {
51 missing = 0;
52 puts(*argv);
53 if (!option_mask32) /* -a not set */
54 break;
55 }
56#endif
46 57
47 /* If file contains a slash don't use PATH */ 58 /* If file contains a slash don't use PATH */
48 if (strchr(*argv, '/')) { 59 if (strchr(*argv, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(*argv, '\\'))) {
49 if (file_is_executable(*argv)) { 60 if (file_is_executable(*argv)) {
50 missing = 0; 61 missing = 0;
51 puts(*argv); 62 puts(*argv);
52 } 63 }
64#if ENABLE_PLATFORM_MINGW32
65 else if ((p=file_is_win32_executable(*argv)) != NULL) {
66 missing = 0;
67 puts(p);
68 free(p);
69 }
70#endif
53 } else { 71 } else {
54 char *path; 72 char *path;
55 char *tmp; 73 char *tmp;
56 char *p;
57 74
58 path = tmp = xstrdup(env_path); 75 path = tmp = xstrdup(env_path);
59 while ((p = find_executable(*argv, &tmp)) != NULL) { 76 while ((p = find_executable(*argv, &tmp)) != NULL) {
diff --git a/editors/awk.c b/editors/awk.c
index cc17ad438..56688d72c 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -727,7 +727,11 @@ static char *skip_spaces(char *p)
727 if (*p == '\\' && p[1] == '\n') { 727 if (*p == '\\' && p[1] == '\n') {
728 p++; 728 p++;
729 t_lineno++; 729 t_lineno++;
730#if !ENABLE_PLATFORM_MINGW32
730 } else if (*p != ' ' && *p != '\t') { 731 } else if (*p != ' ' && *p != '\t') {
732#else
733 } else if (*p != ' ' && *p != '\t' && *p != '\r') {
734#endif
731 break; 735 break;
732 } 736 }
733 p++; 737 p++;
@@ -2073,7 +2077,7 @@ static int fmt_num(char *b, int size, const char *format, double n, int int_as_i
2073 const char *s = format; 2077 const char *s = format;
2074 2078
2075 if (int_as_int && n == (long long)n) { 2079 if (int_as_int && n == (long long)n) {
2076 r = snprintf(b, size, "%lld", (long long)n); 2080 r = snprintf(b, size, "%"LL_FMT"d", (long long)n);
2077 } else { 2081 } else {
2078 do { c = *s; } while (c && *++s); 2082 do { c = *s; } while (c && *++s);
2079 if (strchr("diouxX", c)) { 2083 if (strchr("diouxX", c)) {
diff --git a/editors/diff.c b/editors/diff.c
index 03c13908e..62f558944 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -711,6 +711,10 @@ static int diffreg(char *file[2])
711 FILE *fp[2]; 711 FILE *fp[2];
712 bool binary = false, differ = false; 712 bool binary = false, differ = false;
713 int status = STATUS_SAME, i; 713 int status = STATUS_SAME, i;
714#if ENABLE_PLATFORM_MINGW32
715 char *tmpfile[2] = { NULL, NULL };
716 char *tmpdir;
717#endif
714 718
715 fp[0] = stdin; 719 fp[0] = stdin;
716 fp[1] = stdin; 720 fp[1] = stdin;
@@ -732,10 +736,19 @@ static int diffreg(char *file[2])
732 * When we meet non-seekable file, we must make a temp copy. 736 * When we meet non-seekable file, we must make a temp copy.
733 */ 737 */
734 if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) { 738 if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) {
739#if !ENABLE_PLATFORM_MINGW32
735 char name[] = "/tmp/difXXXXXX"; 740 char name[] = "/tmp/difXXXXXX";
736 int fd_tmp = xmkstemp(name); 741 int fd_tmp = xmkstemp(name);
737 742
738 unlink(name); 743 unlink(name);
744#else
745 int fd_tmp;
746
747 if (!(tmpdir=getenv("TMPDIR")))
748 goto out;
749 tmpfile[i] = xasprintf("%s/difXXXXXX", tmpdir);
750 fd_tmp = xmkstemp(tmpfile[i]);
751#endif
739 if (bb_copyfd_eof(fd, fd_tmp) < 0) 752 if (bb_copyfd_eof(fd, fd_tmp) < 0)
740 xfunc_die(); 753 xfunc_die();
741 if (fd != STDIN_FILENO) 754 if (fd != STDIN_FILENO)
@@ -778,6 +791,14 @@ static int diffreg(char *file[2])
778out: 791out:
779 fclose_if_not_stdin(fp[0]); 792 fclose_if_not_stdin(fp[0]);
780 fclose_if_not_stdin(fp[1]); 793 fclose_if_not_stdin(fp[1]);
794#if ENABLE_PLATFORM_MINGW32
795 for (i = 0; i < 2; i++) {
796 if (tmpfile[i]) {
797 unlink(tmpfile[i]);
798 free(tmpfile[i]);
799 }
800 }
801#endif
781 802
782 return status; 803 return status;
783} 804}
diff --git a/editors/sed.c b/editors/sed.c
index bec20040a..e10078b7c 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -1016,6 +1016,11 @@ static char *get_next_line(char *gets_char, char *last_puts_char)
1016 char c = temp[len-1]; 1016 char c = temp[len-1];
1017 if (c == '\n' || c == '\0') { 1017 if (c == '\n' || c == '\0') {
1018 temp[len-1] = '\0'; 1018 temp[len-1] = '\0';
1019#if ENABLE_PLATFORM_MINGW32
1020 if (c == '\n' && len > 1 && temp[len-2] == '\r') {
1021 temp[len-2] = '\0';
1022 }
1023#endif
1019 gc = c; 1024 gc = c;
1020 if (c == '\0') { 1025 if (c == '\0') {
1021 int ch = fgetc(fp); 1026 int ch = fgetc(fp);
diff --git a/editors/vi.c b/editors/vi.c
index 116022c93..91e954a87 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -2800,6 +2800,14 @@ static void catch_sig(int sig)
2800 2800
2801static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready 2801static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
2802{ 2802{
2803#if ENABLE_PLATFORM_MINGW32
2804 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
2805 DWORD ret;
2806
2807 fflush(stdout);
2808 ret = WaitForSingleObject(h, hund*10);
2809 return ret != WAIT_TIMEOUT;
2810#else
2803 struct pollfd pfd[1]; 2811 struct pollfd pfd[1];
2804 2812
2805 if (hund != 0) 2813 if (hund != 0)
@@ -2808,6 +2816,7 @@ static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
2808 pfd[0].fd = STDIN_FILENO; 2816 pfd[0].fd = STDIN_FILENO;
2809 pfd[0].events = POLLIN; 2817 pfd[0].events = POLLIN;
2810 return safe_poll(pfd, 1, hund*10) > 0; 2818 return safe_poll(pfd, 1, hund*10) > 0;
2819#endif
2811} 2820}
2812 2821
2813//----- IO Routines -------------------------------------------- 2822//----- IO Routines --------------------------------------------
@@ -2936,6 +2945,9 @@ static int file_insert(const char *fn, char *p, int initial)
2936 status_line_bold("'%s' is not a regular file", fn); 2945 status_line_bold("'%s' is not a regular file", fn);
2937 goto fi; 2946 goto fi;
2938 } 2947 }
2948#if ENABLE_PLATFORM_MINGW32
2949 _setmode(fd, _O_TEXT);
2950#endif
2939 size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX); 2951 size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX);
2940 p += text_hole_make(p, size); 2952 p += text_hole_make(p, size);
2941 cnt = full_read(fd, p, size); 2953 cnt = full_read(fd, p, size);
@@ -2944,8 +2956,25 @@ static int file_insert(const char *fn, char *p, int initial)
2944 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert 2956 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert
2945 } else if (cnt < size) { 2957 } else if (cnt < size) {
2946 // There was a partial read, shrink unused space 2958 // There was a partial read, shrink unused space
2959#if ENABLE_PLATFORM_MINGW32
2960 int i, newline;
2961
2962 newline = 0;
2963 for ( i=0; i<cnt; ++i ) {
2964 if ( p[i] == '\n' ) {
2965 ++newline;
2966 }
2967 }
2968#endif
2947 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO); 2969 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO);
2970#if ENABLE_PLATFORM_MINGW32
2971 // on WIN32 a partial read might just mean CRs have been removed
2972 if ( cnt+newline != size ) {
2973 status_line_bold("can't read '%s'", fn);
2974 }
2975#else
2948 status_line_bold("can't read '%s'", fn); 2976 status_line_bold("can't read '%s'", fn);
2977#endif
2949 } 2978 }
2950 fi: 2979 fi:
2951 close(fd); 2980 close(fd);
@@ -2967,6 +2996,9 @@ static int file_insert(const char *fn, char *p, int initial)
2967static int file_write(char *fn, char *first, char *last) 2996static int file_write(char *fn, char *first, char *last)
2968{ 2997{
2969 int fd, cnt, charcnt; 2998 int fd, cnt, charcnt;
2999#if ENABLE_PLATFORM_MINGW32
3000 int i, newline;
3001#endif
2970 3002
2971 if (fn == 0) { 3003 if (fn == 0) {
2972 status_line_bold("No current filename"); 3004 status_line_bold("No current filename");
@@ -2980,8 +3012,23 @@ static int file_write(char *fn, char *first, char *last)
2980 if (fd < 0) 3012 if (fd < 0)
2981 return -1; 3013 return -1;
2982 cnt = last - first + 1; 3014 cnt = last - first + 1;
3015#if ENABLE_PLATFORM_MINGW32
3016 /* write file in text mode; this makes it bigger so adjust
3017 * the truncation to match
3018 */
3019 _setmode(fd, _O_TEXT);
3020 newline = 0;
3021 for ( i=0; i<cnt; ++i ) {
3022 if ( first[i] == '\n' ) {
3023 ++newline;
3024 }
3025 }
3026 charcnt = full_write(fd, first, cnt);
3027 ftruncate(fd, charcnt+newline);
3028#else
2983 charcnt = full_write(fd, first, cnt); 3029 charcnt = full_write(fd, first, cnt);
2984 ftruncate(fd, charcnt); 3030 ftruncate(fd, charcnt);
3031#endif
2985 if (charcnt == cnt) { 3032 if (charcnt == cnt) {
2986 // good write 3033 // good write
2987 //modified_count = FALSE; 3034 //modified_count = FALSE;
@@ -3032,7 +3079,12 @@ static void go_bottom_and_clear_to_eol(void)
3032//----- Erase from cursor to end of screen ----------------------- 3079//----- Erase from cursor to end of screen -----------------------
3033static void clear_to_eos(void) 3080static void clear_to_eos(void)
3034{ 3081{
3082#if !ENABLE_PLATFORM_MINGW32
3035 write1(ESC_CLEAR2EOS); 3083 write1(ESC_CLEAR2EOS);
3084#else
3085 /* in practice clear_to_eos() always clears the entire screen */
3086 reset_screen();
3087#endif
3036} 3088}
3037 3089
3038//----- Start standout mode ------------------------------------ 3090//----- Start standout mode ------------------------------------
@@ -3578,12 +3630,7 @@ static void do_cmd(int c)
3578 break; 3630 break;
3579 case 12: // ctrl-L force redraw whole screen 3631 case 12: // ctrl-L force redraw whole screen
3580 case 18: // ctrl-R force redraw 3632 case 18: // ctrl-R force redraw
3581 place_cursor(0, 0); 3633 redraw(TRUE); // this will redraw the entire display
3582 clear_to_eos();
3583 //mysleep(10); // why???
3584 screen_erase(); // erase the internal screen buffer
3585 last_status_cksum = 0; // force status update
3586 refresh(TRUE); // this will redraw the entire display
3587 break; 3634 break;
3588 case 13: // Carriage Return ^M 3635 case 13: // Carriage Return ^M
3589 case '+': // +- goto next line 3636 case '+': // +- goto next line
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 2d0d1c8b9..e5384d14c 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#include "common_bufsiz.h" 72#include "common_bufsiz.h"
70 73
@@ -405,13 +408,23 @@ static int xargs_ask_confirmation(void)
405 FILE *tty_stream; 408 FILE *tty_stream;
406 int c, savec; 409 int c, savec;
407 410
411#if !ENABLE_PLATFORM_MINGW32
408 tty_stream = xfopen_for_read(CURRENT_TTY); 412 tty_stream = xfopen_for_read(CURRENT_TTY);
413#endif
409 fputs(" ?...", stderr); 414 fputs(" ?...", stderr);
410 fflush_all(); 415 fflush_all();
416#if !ENABLE_PLATFORM_MINGW32
411 c = savec = getc(tty_stream); 417 c = savec = getc(tty_stream);
412 while (c != EOF && c != '\n') 418 while (c != EOF && c != '\n')
413 c = getc(tty_stream); 419 c = getc(tty_stream);
414 fclose(tty_stream); 420 fclose(tty_stream);
421#else
422 c = savec = getche();
423 while (c != EOF && c != '\r')
424 c = getche();
425 fputs("\n", stderr);
426 fflush_all();
427#endif
415 return (savec == 'y' || savec == 'Y'); 428 return (savec == 'y' || savec == 'Y');
416} 429}
417#else 430#else
diff --git a/include/bb_archive.h b/include/bb_archive.h
index d3762415f..c118fa7ec 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -2,6 +2,16 @@
2#ifndef UNARCHIVE_H 2#ifndef UNARCHIVE_H
3#define UNARCHIVE_H 1 3#define UNARCHIVE_H 1
4 4
5#if !defined(BB_ARCHIVE_PUBLIC) && ENABLE_PLATFORM_MINGW32
6/* treat mingw as a non-MMU platform */
7#undef BB_MMU
8#undef USE_FOR_NOMMU
9#undef USE_FOR_MMU
10#define BB_MMU 0
11#define USE_FOR_NOMMU(...) __VA_ARGS__
12#define USE_FOR_MMU(...)
13#endif
14
5PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 15PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
6 16
7enum { 17enum {
diff --git a/include/libbb.h b/include/libbb.h
index 9aba71949..61ceb6085 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -138,6 +138,12 @@
138# include <arpa/inet.h> 138# include <arpa/inet.h>
139#elif defined __APPLE__ 139#elif defined __APPLE__
140# include <netinet/in.h> 140# include <netinet/in.h>
141#elif ENABLE_PLATFORM_MINGW32
142# ifndef WINVER
143# define WINVER 0x0501
144# endif
145# include <winsock2.h>
146# include <ws2tcpip.h>
141#else 147#else
142# include <arpa/inet.h> 148# include <arpa/inet.h>
143//This breaks on bionic: 149//This breaks on bionic:
@@ -166,7 +172,9 @@
166 172
167/* Some libc's forget to declare these, do it ourself */ 173/* Some libc's forget to declare these, do it ourself */
168 174
175#if !ENABLE_PLATFORM_MINGW32
169extern char **environ; 176extern char **environ;
177#endif
170/* klogctl is in libc's klog.h, but we cheat and not #include that */ 178/* klogctl is in libc's klog.h, but we cheat and not #include that */
171int klogctl(int type, char *b, int len); 179int klogctl(int type, char *b, int len);
172#ifndef PATH_MAX 180#ifndef PATH_MAX
@@ -176,6 +184,9 @@ int klogctl(int type, char *b, int len);
176# define BUFSIZ 4096 184# define BUFSIZ 4096
177#endif 185#endif
178 186
187#if ENABLE_PLATFORM_MINGW32
188# include "mingw.h"
189#endif
179 190
180/* Busybox does not use threads, we can speed up stdio. */ 191/* Busybox does not use threads, we can speed up stdio. */
181#ifdef HAVE_UNLOCKED_STDIO 192#ifdef HAVE_UNLOCKED_STDIO
@@ -238,6 +249,13 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
238 : ((T)1 << (sizeof(T)*8-1)) \ 249 : ((T)1 << (sizeof(T)*8-1)) \
239 ) 250 )
240 251
252#if ENABLE_PLATFORM_MINGW32 && \
253 (!defined(__USE_MINGW_ANSI_STDIO) || !__USE_MINGW_ANSI_STDIO)
254#define LL_FMT "I64"
255#else
256#define LL_FMT "ll"
257#endif
258
241/* Large file support */ 259/* Large file support */
242/* Note that CONFIG_LFS=y forces bbox to be built with all common ops 260/* Note that CONFIG_LFS=y forces bbox to be built with all common ops
243 * (stat, lseek etc) mapped to "largefile" variants by libc. 261 * (stat, lseek etc) mapped to "largefile" variants by libc.
@@ -263,7 +281,7 @@ typedef unsigned long long uoff_t;
263# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX) 281# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX)
264# define BB_STRTOOFF bb_strtoull 282# define BB_STRTOOFF bb_strtoull
265# define STRTOOFF strtoull 283# define STRTOOFF strtoull
266# define OFF_FMT "ll" 284# define OFF_FMT LL_FMT
267# endif 285# endif
268#else 286#else
269/* CONFIG_LFS is off */ 287/* CONFIG_LFS is off */
@@ -510,6 +528,7 @@ enum {
510 + (1LL << SIGUSR2) 528 + (1LL << SIGUSR2)
511 + 0), 529 + 0),
512}; 530};
531#if !ENABLE_PLATFORM_MINGW32
513void bb_signals(int sigs, void (*f)(int)) FAST_FUNC; 532void bb_signals(int sigs, void (*f)(int)) FAST_FUNC;
514/* Unlike signal() and bb_signals, sets handler with sigaction() 533/* Unlike signal() and bb_signals, sets handler with sigaction()
515 * and in a way that while signal handler is run, no other signals 534 * and in a way that while signal handler is run, no other signals
@@ -527,6 +546,10 @@ void sig_unblock(int sig) FAST_FUNC;
527int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC; 546int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC;
528/* SIG_BLOCK/SIG_UNBLOCK all signals: */ 547/* SIG_BLOCK/SIG_UNBLOCK all signals: */
529int sigprocmask_allsigs(int how) FAST_FUNC; 548int sigprocmask_allsigs(int how) FAST_FUNC;
549#else
550#define bb_signals(s, f)
551#define kill_myself_with_sig(s)
552#endif
530/* Standard handler which just records signo */ 553/* Standard handler which just records signo */
531extern smallint bb_got_signal; 554extern smallint bb_got_signal;
532void record_signo(int signo); /* not FAST_FUNC! */ 555void record_signo(int signo); /* not FAST_FUNC! */
@@ -606,7 +629,7 @@ char *strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC;
606int xsocket(int domain, int type, int protocol) FAST_FUNC; 629int xsocket(int domain, int type, int protocol) FAST_FUNC;
607void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; 630void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC;
608void xlisten(int s, int backlog) FAST_FUNC; 631void xlisten(int s, int backlog) FAST_FUNC;
609void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) FAST_FUNC; 632void xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen) FAST_FUNC;
610ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, 633ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
611 socklen_t tolen) FAST_FUNC; 634 socklen_t tolen) FAST_FUNC;
612 635
@@ -941,6 +964,9 @@ char *safe_gethostname(void) FAST_FUNC;
941char* str_tolower(char *str) FAST_FUNC; 964char* str_tolower(char *str) FAST_FUNC;
942 965
943char *utoa(unsigned n) FAST_FUNC; 966char *utoa(unsigned n) FAST_FUNC;
967#if ENABLE_PLATFORM_MINGW32
968# define itoa bb_itoa
969#endif
944char *itoa(int n) FAST_FUNC; 970char *itoa(int n) FAST_FUNC;
945/* Returns a pointer past the formatted number, does NOT null-terminate */ 971/* Returns a pointer past the formatted number, does NOT null-terminate */
946char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; 972char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC;
@@ -1116,6 +1142,9 @@ int run_nofork_applet(int applet_no, char **argv) FAST_FUNC;
1116extern int find_applet_by_name(const char *name) FAST_FUNC; 1142extern int find_applet_by_name(const char *name) FAST_FUNC;
1117extern void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; 1143extern void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC;
1118#endif 1144#endif
1145#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_NOFORK
1146extern int long_running_applet(int applet_no) FAST_FUNC;
1147#endif
1119 1148
1120/* Helpers for daemonization. 1149/* Helpers for daemonization.
1121 * 1150 *
@@ -1199,7 +1228,7 @@ extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC;
1199 * By ~2008, OpenBSD 3.4 was changed to survive glibc-like optind = 0 1228 * By ~2008, OpenBSD 3.4 was changed to survive glibc-like optind = 0
1200 * (to interpret it as if optreset was set). 1229 * (to interpret it as if optreset was set).
1201 */ 1230 */
1202#ifdef __GLIBC__ 1231#if defined(__GLIBC__) || ENABLE_PLATFORM_MINGW32
1203#define GETOPT_RESET() (optind = 0) 1232#define GETOPT_RESET() (optind = 0)
1204#else /* BSD style */ 1233#else /* BSD style */
1205#define GETOPT_RESET() (optind = 1) 1234#define GETOPT_RESET() (optind = 1)
@@ -1776,6 +1805,9 @@ typedef struct procps_status_t {
1776#if ENABLE_FEATURE_TOP_SMP_PROCESS 1805#if ENABLE_FEATURE_TOP_SMP_PROCESS
1777 int last_seen_on_cpu; 1806 int last_seen_on_cpu;
1778#endif 1807#endif
1808#if ENABLE_PLATFORM_MINGW32
1809 HANDLE snapshot;
1810#endif
1779} procps_status_t; 1811} procps_status_t;
1780/* flag bits for procps_scan(xx, flags) calls */ 1812/* flag bits for procps_scan(xx, flags) calls */
1781enum { 1813enum {
@@ -1814,7 +1846,11 @@ void free_procps_scan(procps_status_t* sp) FAST_FUNC;
1814procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; 1846procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC;
1815/* Format cmdline (up to col chars) into char buf[size] */ 1847/* Format cmdline (up to col chars) into char buf[size] */
1816/* Puts [comm] if cmdline is empty (-> process is a kernel thread) */ 1848/* Puts [comm] if cmdline is empty (-> process is a kernel thread) */
1849#if !ENABLE_PLATFORM_MINGW32
1817void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; 1850void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC;
1851#else
1852#define read_cmdline(buf, size, pid, comm) snprintf(buf, size, "[%s]", comm)
1853#endif
1818pid_t *find_pid_by_name(const char* procName) FAST_FUNC; 1854pid_t *find_pid_by_name(const char* procName) FAST_FUNC;
1819pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; 1855pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC;
1820int starts_with_cpu(const char *str) FAST_FUNC; 1856int starts_with_cpu(const char *str) FAST_FUNC;
@@ -1958,7 +1994,11 @@ extern const char bb_path_wtmp_file[] ALIGN1;
1958#define bb_path_motd_file "/etc/motd" 1994#define bb_path_motd_file "/etc/motd"
1959 1995
1960#define bb_dev_null "/dev/null" 1996#define bb_dev_null "/dev/null"
1997#if ENABLE_PLATFORM_MINGW32
1998#define bb_busybox_exec_path get_busybox_exec_path()
1999#else
1961extern const char bb_busybox_exec_path[] ALIGN1; 2000extern const char bb_busybox_exec_path[] ALIGN1;
2001#endif
1962/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 2002/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
1963 * but I want to save a few bytes here */ 2003 * but I want to save a few bytes here */
1964extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ 2004extern 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..5f1074160
--- /dev/null
+++ b/include/mingw.h
@@ -0,0 +1,484 @@
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#define DEFAULT_UID 1000
17#define DEFAULT_GID 1000
18
19/*
20 * arpa/inet.h
21 */
22static inline unsigned int git_ntohl(unsigned int x) { return (unsigned int)ntohl(x); }
23#define ntohl git_ntohl
24int inet_aton(const char *cp, struct in_addr *inp);
25int inet_pton(int af, const char *src, void *dst);
26
27/*
28 * fcntl.h
29 */
30#define F_DUPFD 0
31#define F_GETFD 1
32#define F_SETFD 2
33#define F_GETFL 3
34#define F_SETFL 3
35#define FD_CLOEXEC 0x1
36#define O_NONBLOCK 0
37#define O_NOFOLLOW 0
38
39/*
40 * grp.h
41 */
42
43struct group {
44 char *gr_name;
45 char *gr_passwd;
46 gid_t gr_gid;
47 char **gr_mem;
48};
49IMPL(getgrnam,struct group *,NULL,const char *name UNUSED_PARAM);
50struct group *getgrgid(gid_t gid);
51NOIMPL(initgroups,const char *group UNUSED_PARAM,gid_t gid UNUSED_PARAM);
52static inline void endgrent(void) {}
53int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups);
54
55/*
56 * limits.h
57 */
58#define NAME_MAX 255
59#define MAXSYMLINKS 20
60
61/*
62 * netdb.h
63 */
64
65typedef int sa_family_t;
66
67/*
68 * linux/un.h
69 */
70struct sockaddr_un {
71 sa_family_t sun_family;
72 char sun_path[1]; /* to make compiler happy, don't bother */
73};
74
75/*
76 * pwd.h
77 */
78struct passwd {
79 char *pw_name;
80 char *pw_passwd;
81 char *pw_gecos;
82 char *pw_dir;
83 char *pw_shell;
84 uid_t pw_uid;
85 gid_t pw_gid;
86};
87
88struct passwd *getpwnam(const char *name);
89struct passwd *getpwuid(uid_t uid);
90static inline void setpwent(void) {}
91static inline void endpwent(void) {}
92IMPL(getpwent_r,int,ENOENT,struct passwd *pwbuf UNUSED_PARAM,char *buf UNUSED_PARAM,size_t buflen UNUSED_PARAM,struct passwd **pwbufp UNUSED_PARAM);
93IMPL(getpwent,struct passwd *,NULL,void)
94
95/*
96 * signal.h
97 */
98#define SIGHUP 1
99#define SIGQUIT 3
100#define SIGKILL 9
101#define SIGUSR1 10
102#define SIGUSR2 12
103#define SIGPIPE 13
104#define SIGALRM 14
105#define SIGCHLD 17
106#define SIGCONT 18
107#define SIGSTOP 19
108#define SIGTSTP 20
109#define SIGTTIN 21
110#define SIGTTOU 22
111#define SIGXCPU 24
112#define SIGXFSZ 25
113#define SIGVTALRM 26
114#define SIGWINCH 28
115
116#define SIG_UNBLOCK 1
117
118typedef void (__cdecl *sighandler_t)(int);
119struct sigaction {
120 sighandler_t sa_handler;
121 unsigned sa_flags;
122 int sa_mask;
123};
124#define sigemptyset(x) (void)0
125#define SA_RESTART 0
126
127NOIMPL(sigaction,int sig UNUSED_PARAM, struct sigaction *in UNUSED_PARAM, struct sigaction *out UNUSED_PARAM);
128NOIMPL(sigfillset,int *mask UNUSED_PARAM);
129NOIMPL(FAST_FUNC sigprocmask_allsigs, int how UNUSED_PARAM);
130NOIMPL(FAST_FUNC sigaction_set,int signo UNUSED_PARAM, const struct sigaction *sa UNUSED_PARAM);
131
132/*
133 * stdio.h
134 */
135#undef fseeko
136#define fseeko(f,o,w) fseek(f,o,w)
137
138int fdprintf(int fd, const char *format, ...);
139FILE* mingw_fopen(const char *filename, const char *mode);
140int mingw_rename(const char*, const char*);
141#define fopen mingw_fopen
142#define rename mingw_rename
143
144FILE *mingw_popen(const char *cmd, const char *mode);
145int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid);
146int mingw_pclose(FILE *fd);
147#undef popen
148#undef pclose
149#define popen mingw_popen
150#define pclose mingw_pclose
151
152#define setlinebuf(fd) setvbuf(fd, (char *) NULL, _IOLBF, 0)
153
154/*
155 * ANSI emulation wrappers
156 */
157
158void move_cursor_row(int n);
159void reset_screen(void);
160int winansi_putchar(int c);
161int winansi_puts(const char *s);
162size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
163int winansi_fputs(const char *str, FILE *stream);
164int winansi_vfprintf(FILE *stream, const char *format, va_list list);
165int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
166int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
167int winansi_write(int fd, const void *buf, size_t count);
168int winansi_read(int fd, void *buf, size_t count);
169int winansi_getc(FILE *stream);
170#define putchar winansi_putchar
171#define puts winansi_puts
172#define fwrite winansi_fwrite
173#define fputs winansi_fputs
174#define vfprintf(stream, ...) winansi_vfprintf(stream, __VA_ARGS__)
175#define vprintf(...) winansi_vfprintf(stdout, __VA_ARGS__)
176#define printf(...) winansi_printf(__VA_ARGS__)
177#define fprintf(...) winansi_fprintf(__VA_ARGS__)
178#define write winansi_write
179#define read winansi_read
180#define getc winansi_getc
181
182int winansi_get_terminal_width_height(struct winsize *win);
183
184/*
185 * stdlib.h
186 */
187#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */
188#define WEXITSTATUS(x) ((x) & 0xff)
189#define WIFSIGNALED(x) ((unsigned)(x) > 259)
190#define WTERMSIG(x) ((x) & 0x7f)
191#define WCOREDUMP(x) 0
192
193int mingw_system(const char *cmd);
194#define system mingw_system
195
196int clearenv(void);
197char *mingw_getenv(const char *name);
198int mingw_putenv(const char *env);
199char *mingw_mktemp(char *template);
200int mkstemp(char *template);
201char *realpath(const char *path, char *resolved_path);
202int setenv(const char *name, const char *value, int replace);
203#if ENABLE_SAFE_ENV
204int unsetenv(const char *env);
205#else
206void unsetenv(const char *env);
207#endif
208
209#define getenv mingw_getenv
210#if ENABLE_SAFE_ENV
211#define putenv mingw_putenv
212#endif
213#define mktemp mingw_mktemp
214
215/*
216 * string.h
217 */
218void *mempcpy(void *dest, const void *src, size_t n);
219
220/*
221 * strings.h
222 */
223int ffs(int i);
224
225/*
226 * sys/ioctl.h
227 */
228
229#define TIOCGWINSZ 0x5413
230
231int ioctl(int fd, int code, ...);
232
233/*
234 * sys/socket.h
235 */
236#define hstrerror strerror
237
238#define SHUT_WR SD_SEND
239
240int mingw_socket(int domain, int type, int protocol);
241int mingw_connect(int sockfd, const struct sockaddr *sa, size_t sz);
242int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
243int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
244int mingw_shutdown(int sockfd, int how);
245int mingw_listen(int sockfd, int backlog);
246int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz);
247int mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
248 struct timeval *timeout);
249
250NOIMPL(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);
251
252#define socket mingw_socket
253#define connect mingw_connect
254#define sendto mingw_sendto
255#define listen mingw_listen
256#define bind mingw_bind
257#define setsockopt mingw_setsockopt
258#define shutdown mingw_shutdown
259#define accept mingw_accept
260#define select mingw_select
261
262/*
263 * sys/stat.h
264 */
265#define S_ISUID 04000
266#define S_ISGID 02000
267#define S_ISVTX 01000
268#ifndef S_IRWXU
269#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
270#endif
271#define S_IRWXG (S_IRWXU >> 3)
272#define S_IRWXO (S_IRWXG >> 3)
273
274#define S_IFSOCK 0140000
275#define S_IFLNK 0120000 /* Symbolic link */
276#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
277#define S_ISSOCK(x) 0
278
279#define S_IRGRP (S_IRUSR >> 3)
280#define S_IWGRP (S_IWUSR >> 3)
281#define S_IXGRP (S_IXUSR >> 3)
282#define S_IROTH (S_IRGRP >> 3)
283#define S_IWOTH (S_IWGRP >> 3)
284#define S_IXOTH (S_IXGRP >> 3)
285
286IMPL(fchmod,int,0,int fildes UNUSED_PARAM, mode_t mode UNUSED_PARAM);
287NOIMPL(fchown,int fd UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
288int mingw_mkdir(const char *path, int mode);
289int mingw_chmod(const char *path, int mode);
290
291#define mkdir mingw_mkdir
292#define chmod mingw_chmod
293
294#if ENABLE_LFS && !defined(__MINGW64_VERSION_MAJOR)
295# define off_t off64_t
296#endif
297
298typedef int nlink_t;
299typedef int blksize_t;
300typedef off_t blkcnt_t;
301
302struct mingw_stat {
303 dev_t st_dev;
304 ino_t st_ino;
305 mode_t st_mode;
306 nlink_t st_nlink;
307 uid_t st_uid;
308 gid_t st_gid;
309 dev_t st_rdev;
310 off_t st_size;
311 time_t st_atime;
312 time_t st_mtime;
313 time_t st_ctime;
314 blksize_t st_blksize;
315 blkcnt_t st_blocks;
316};
317
318int mingw_lstat(const char *file_name, struct mingw_stat *buf);
319int mingw_stat(const char *file_name, struct mingw_stat *buf);
320int mingw_fstat(int fd, struct mingw_stat *buf);
321#undef lstat
322#undef stat
323#undef fstat
324#define lstat mingw_lstat
325#define stat mingw_stat
326#define fstat mingw_fstat
327
328/*
329 * sys/sysmacros.h
330 */
331#define makedev(a,b) 0*(a)*(b) /* avoid unused warning */
332#define minor(x) 0
333#define major(x) 0
334
335/*
336 * sys/time.h
337 */
338#ifndef _TIMESPEC_DEFINED
339#define _TIMESPEC_DEFINED
340struct timespec {
341 time_t tv_sec;
342 long int tv_nsec;
343};
344#endif
345
346int nanosleep(const struct timespec *req, struct timespec *rem);
347
348/*
349 * sys/wait.h
350 */
351#define WNOHANG 1
352#define WUNTRACED 2
353int waitpid(pid_t pid, int *status, int options);
354
355/*
356 * time.h
357 */
358struct tm *gmtime_r(const time_t *timep, struct tm *result);
359struct tm *localtime_r(const time_t *timep, struct tm *result);
360char *strptime(const char *s, const char *format, struct tm *tm);
361size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm);
362int stime(time_t *t);
363
364#define strftime mingw_strftime
365
366/*
367 * times.h
368 */
369#define clock_t long
370
371struct tms {
372 clock_t tms_utime; /* user CPU time */
373 clock_t tms_stime; /* system CPU time */
374 clock_t tms_cutime; /* user CPU time of children */
375 clock_t tms_cstime; /* system CPU time of children */
376};
377
378clock_t times(struct tms *buf);
379
380/*
381 * unistd.h
382 */
383#define PIPE_BUF 8192
384
385#define _SC_CLK_TCK 2
386
387IMPL(alarm,unsigned int,0,unsigned int seconds UNUSED_PARAM);
388IMPL(chown,int,0,const char *path UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
389NOIMPL(chroot,const char *root UNUSED_PARAM);
390NOIMPL(fchdir,int fd UNUSED_PARAM);
391int mingw_dup2 (int fd, int fdto);
392char *mingw_getcwd(char *pointer, int len);
393off_t mingw_lseek(int fd, off_t offset, int whence);
394
395
396IMPL(getgid,int,DEFAULT_GID,void);
397int getgroups(int n, gid_t *groups);
398IMPL(getppid,int,1,void);
399IMPL(getegid,int,DEFAULT_GID,void);
400IMPL(geteuid,int,DEFAULT_UID,void);
401NOIMPL(getsid,pid_t pid UNUSED_PARAM);
402IMPL(getuid,int,DEFAULT_UID,void);
403int getlogin_r(char *buf, size_t len);
404int fcntl(int fd, int cmd, ...);
405#define fork() -1
406IMPL(fsync,int,0,int fd UNUSED_PARAM);
407int kill(pid_t pid, int sig);
408int link(const char *oldpath, const char *newpath);
409NOIMPL(mknod,const char *name UNUSED_PARAM, mode_t mode UNUSED_PARAM, dev_t device UNUSED_PARAM);
410int mingw_open (const char *filename, int oflags, ...);
411int pipe(int filedes[2]);
412NOIMPL(readlink,const char *path UNUSED_PARAM, char *buf UNUSED_PARAM, size_t bufsiz UNUSED_PARAM);
413NOIMPL(setgid,gid_t gid UNUSED_PARAM);
414NOIMPL(setegid,gid_t gid UNUSED_PARAM);
415NOIMPL(setsid,void);
416NOIMPL(setuid,uid_t gid UNUSED_PARAM);
417NOIMPL(seteuid,uid_t gid UNUSED_PARAM);
418unsigned int sleep(unsigned int seconds);
419NOIMPL(symlink,const char *oldpath UNUSED_PARAM, const char *newpath UNUSED_PARAM);
420static inline void sync(void) {}
421long sysconf(int name);
422NOIMPL(ttyname_r,int fd UNUSED_PARAM, char *buf UNUSED_PARAM, int sz UNUSED_PARAM);
423int mingw_unlink(const char *pathname);
424NOIMPL(vfork,void);
425int mingw_access(const char *name, int mode);
426int mingw_rmdir(const char *name);
427
428#define dup2 mingw_dup2
429#define getcwd mingw_getcwd
430#define lchown chown
431#define open mingw_open
432#define unlink mingw_unlink
433#define rmdir mingw_rmdir
434#undef lseek
435#define lseek mingw_lseek
436
437#undef access
438#define access mingw_access
439
440/*
441 * utime.h
442 */
443int utimes(const char *file_name, const struct timeval times[2]);
444
445/*
446 * dirent.h
447 */
448DIR *mingw_opendir(const char *path);
449#define opendir mingw_opendir
450
451/*
452 * MinGW specific
453 */
454#define is_dir_sep(c) ((c) == '/' || (c) == '\\')
455#define PRIuMAX "I64u"
456
457pid_t FAST_FUNC mingw_spawn(char **argv);
458intptr_t FAST_FUNC mingw_spawn_proc(char **argv);
459int mingw_execv(const char *cmd, const char *const *argv);
460int mingw_execvp(const char *cmd, const char *const *argv);
461int mingw_execve(const char *cmd, const char *const *argv, const char *const *envp);
462#define spawn mingw_spawn
463#define execvp mingw_execvp
464#define execve mingw_execve
465#define execv mingw_execv
466
467const char * next_path_sep(const char *path);
468#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
469#define is_absolute_path(path) ((path)[0] == '/' || (path)[0] == '\\' || has_dos_drive_prefix(path))
470
471/*
472 * helpers
473 */
474
475char **copy_environ(const char *const *env);
476void free_environ(char **env);
477char **env_setenv(char **env, const char *name);
478
479const char *get_busybox_exec_path(void);
480void init_winsock(void);
481
482char *file_is_win32_executable(const char *p);
483
484int err_win_to_posix(DWORD winerr);
diff --git a/include/platform.h b/include/platform.h
index b81c59d4e..749169b0c 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
@@ -131,7 +140,7 @@
131 140
132/* Make all declarations hidden (-fvisibility flag only affects definitions) */ 141/* Make all declarations hidden (-fvisibility flag only affects definitions) */
133/* (don't include system headers after this until corresponding pop!) */ 142/* (don't include system headers after this until corresponding pop!) */
134#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) 143#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) && !ENABLE_PLATFORM_MINGW32
135# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)") 144# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)")
136# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop") 145# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop")
137#else 146#else
@@ -160,6 +169,14 @@
160# define bswap_64 __bswap64 169# define bswap_64 __bswap64
161# define bswap_32 __bswap32 170# define bswap_32 __bswap32
162# define bswap_16 __bswap16 171# define bswap_16 __bswap16
172# define __BIG_ENDIAN__ (_BYTE_ORDER == _BIG_ENDIAN)
173#elif ENABLE_PLATFORM_MINGW32
174# define __BIG_ENDIAN 0
175# define __LITTLE_ENDIAN 1
176# define __BYTE_ORDER __LITTLE_ENDIAN
177# define bswap_16(x) ((((x) & 0xFF00) >> 8) | (((x) & 0xFF) << 8))
178# define bswap_32(x) ((bswap_16(((x) & 0xFFFF0000L) >> 16)) | (bswap_16((x) & 0xFFFFL) << 16))
179# define bswap_64(x) ((bswap_32(((x) & 0xFFFFFFFF00000000LL) >> 32)) | (bswap_32((x) & 0xFFFFFFFFLL) << 32))
163#else 180#else
164# include <byteswap.h> 181# include <byteswap.h>
165# include <endian.h> 182# include <endian.h>
@@ -419,6 +436,26 @@ typedef unsigned smalluint;
419# endif 436# endif
420#endif 437#endif
421 438
439#if ENABLE_PLATFORM_MINGW32
440# undef HAVE_DPRINTF
441# undef HAVE_GETLINE
442# undef HAVE_MEMRCHR
443# undef HAVE_MKDTEMP
444# undef HAVE_SETBIT
445# undef HAVE_STPCPY
446# undef HAVE_STRCASESTR
447# undef HAVE_STRCHRNUL
448# undef HAVE_STRSEP
449# undef HAVE_STRSIGNAL
450# undef HAVE_STRVERSCMP
451#if !defined(__MINGW64_VERSION_MAJOR)
452# undef HAVE_VASPRINTF
453#endif
454# undef HAVE_UNLOCKED_STDIO
455# undef HAVE_UNLOCKED_LINE_OPS
456# undef HAVE_PRINTF_PERCENTM
457#endif
458
422#if defined(__WATCOMC__) 459#if defined(__WATCOMC__)
423# undef HAVE_DPRINTF 460# undef HAVE_DPRINTF
424# undef HAVE_GETLINE 461# undef HAVE_GETLINE
@@ -533,6 +570,7 @@ extern int dprintf(int fd, const char *format, ...);
533#endif 570#endif
534 571
535#ifndef HAVE_MEMRCHR 572#ifndef HAVE_MEMRCHR
573#include <stddef.h>
536extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC; 574extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC;
537#endif 575#endif
538 576
@@ -592,6 +630,7 @@ extern int usleep(unsigned) FAST_FUNC;
592#endif 630#endif
593 631
594#ifndef HAVE_VASPRINTF 632#ifndef HAVE_VASPRINTF
633# include <stdarg.h>
595extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC; 634extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC;
596#endif 635#endif
597 636
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index 458973f17..6749cceda 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -37,24 +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 46lib-y += inet_common.o
49lib-y += inode_hash.o 47lib-y += inode_hash.o
50lib-y += isdirectory.o 48lib-y += isdirectory.o
51lib-y += kernel_version.o
52lib-y += last_char_is.o 49lib-y += last_char_is.o
53lib-y += lineedit.o lineedit_ptr_hack.o 50lib-y += lineedit.o lineedit_ptr_hack.o
54lib-y += llist.o 51lib-y += llist.o
55lib-y += login.o
56lib-y += make_directory.o 52lib-y += make_directory.o
57lib-y += makedev.o
58lib-y += hash_md5_sha.o 53lib-y += hash_md5_sha.o
59# Alternative (disabled) MD5 implementation 54# Alternative (disabled) MD5 implementation
60#lib-y += hash_md5prime.o 55#lib-y += hash_md5prime.o
@@ -75,7 +70,6 @@ lib-y += progress.o
75lib-y += ptr_to_globals.o 70lib-y += ptr_to_globals.o
76lib-y += read.o 71lib-y += read.o
77lib-y += read_printf.o 72lib-y += read_printf.o
78lib-y += read_key.o
79lib-y += recursive_action.o 73lib-y += recursive_action.o
80lib-y += remove_file.o 74lib-y += remove_file.o
81lib-y += run_shell.o 75lib-y += run_shell.o
@@ -85,7 +79,6 @@ lib-y += safe_strncpy.o
85lib-y += safe_write.o 79lib-y += safe_write.o
86lib-y += securetty.o 80lib-y += securetty.o
87lib-y += setup_environment.o 81lib-y += setup_environment.o
88lib-y += signals.o
89lib-y += simplify_path.o 82lib-y += simplify_path.o
90lib-y += single_argv.o 83lib-y += single_argv.o
91lib-y += skip_whitespace.o 84lib-y += skip_whitespace.o
@@ -109,10 +102,20 @@ lib-y += xfuncs.o
109lib-y += xfuncs_printf.o 102lib-y += xfuncs_printf.o
110lib-y += xfunc_die.o 103lib-y += xfunc_die.o
111lib-y += xgetcwd.o 104lib-y += xgetcwd.o
112lib-y += xgethostbyname.o
113lib-y += xreadlink.o 105lib-y += xreadlink.o
114lib-y += xrealloc_vector.o 106lib-y += xrealloc_vector.o
115 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
116lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o 119lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o
117 120
118lib-$(CONFIG_FEATURE_UTMP) += utmp.o 121lib-$(CONFIG_FEATURE_UTMP) += utmp.o
@@ -124,7 +127,7 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
124lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o 127lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o
125lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o 128lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
126 129
127lib-$(CONFIG_NC) += udp_io.o 130lib-$(CONFIG_NC_110_COMPAT) += udp_io.o
128lib-$(CONFIG_DNSD) += udp_io.o 131lib-$(CONFIG_DNSD) += udp_io.o
129lib-$(CONFIG_NTPD) += udp_io.o 132lib-$(CONFIG_NTPD) += udp_io.o
130lib-$(CONFIG_TFTP) += udp_io.o 133lib-$(CONFIG_TFTP) += udp_io.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index fa28d433b..401475f18 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -105,6 +105,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
105#if ENABLE_FEATURE_COMPRESS_USAGE 105#if ENABLE_FEATURE_COMPRESS_USAGE
106 106
107static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; 107static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
108#define BB_ARCHIVE_PUBLIC
108# include "bb_archive.h" 109# include "bb_archive.h"
109static const char *unpack_usage_messages(void) 110static const char *unpack_usage_messages(void)
110{ 111{
@@ -165,7 +166,7 @@ void FAST_FUNC bb_show_usage(void)
165 ap--; 166 ap--;
166 } 167 }
167 full_write2_str(bb_banner); 168 full_write2_str(bb_banner);
168 full_write2_str(" multi-call binary.\n"); 169 full_write2_str(" multi-call binary\n");
169 if (*p == '\b') 170 if (*p == '\b')
170 full_write2_str("\nNo help available.\n\n"); 171 full_write2_str("\nNo help available.\n\n");
171 else { 172 else {
@@ -309,6 +310,22 @@ int FAST_FUNC find_applet_by_name(const char *name)
309#endif 310#endif
310} 311}
311 312
313# if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_NOFORK
314int FAST_FUNC long_running_applet(int applet_no)
315{
316 int ret = 0;
317
318#if defined(APPLET_NO_seq)
319 ret |= (applet_no == APPLET_NO_seq);
320#endif
321#if defined(APPLET_NO_yes)
322 ret |= (applet_no == APPLET_NO_yes);
323#endif
324
325 return ret;
326}
327#endif
328
312 329
313void lbb_prepare(const char *applet 330void lbb_prepare(const char *applet
314 IF_FEATURE_INDIVIDUAL(, char **argv)) 331 IF_FEATURE_INDIVIDUAL(, char **argv))
@@ -325,6 +342,10 @@ void lbb_prepare(const char *applet
325 if (ENABLE_LOCALE_SUPPORT) 342 if (ENABLE_LOCALE_SUPPORT)
326 setlocale(LC_ALL, ""); 343 setlocale(LC_ALL, "");
327 344
345#if ENABLE_PLATFORM_MINGW32
346 init_winsock();
347#endif
348
328#if ENABLE_FEATURE_INDIVIDUAL 349#if ENABLE_FEATURE_INDIVIDUAL
329 /* Redundant for busybox (run_applet_and_exit covers that case) 350 /* Redundant for busybox (run_applet_and_exit covers that case)
330 * but needed for "individual applet" mode */ 351 * but needed for "individual applet" mode */
@@ -715,6 +736,7 @@ static void check_suid(int applet_no)
715 736
716 737
717# if ENABLE_FEATURE_INSTALLER 738# if ENABLE_FEATURE_INSTALLER
739# if !ENABLE_PLATFORM_MINGW32
718static const char usr_bin [] ALIGN1 = "/usr/bin/"; 740static const char usr_bin [] ALIGN1 = "/usr/bin/";
719static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; 741static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
720static const char *const install_dir[] = { 742static const char *const install_dir[] = {
@@ -759,6 +781,29 @@ static void install_links(const char *busybox, int use_symbolic_links,
759 continue; 781 continue;
760 } 782 }
761} 783}
784# else /* ENABLE_PLATFORM_MINGW32 */
785static void install_links(const char *busybox,
786 int use_symbolic_links UNUSED_PARAM, char *custom_install_dir)
787{
788 char *fpc;
789 const char *appname = applet_names;
790 int rc;
791
792 if (!is_directory(custom_install_dir, FALSE))
793 bb_error_msg_and_die("'%s' is not a directory", custom_install_dir);
794
795 while (*appname) {
796 fpc = xasprintf("%s/%s.exe", custom_install_dir, appname);
797 rc = link(busybox, fpc);
798 if (rc != 0 && errno != EEXIST) {
799 bb_simple_perror_msg(fpc);
800 }
801 free(fpc);
802 while (*appname++ != '\0')
803 continue;
804 }
805}
806# endif
762# elif ENABLE_BUSYBOX 807# elif ENABLE_BUSYBOX
763static void install_links(const char *busybox UNUSED_PARAM, 808static void install_links(const char *busybox UNUSED_PARAM,
764 int use_symbolic_links UNUSED_PARAM, 809 int use_symbolic_links UNUSED_PARAM,
@@ -798,16 +843,26 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
798 843
799 dup2(1, 2); 844 dup2(1, 2);
800 full_write2_str(bb_banner); /* reuse const string */ 845 full_write2_str(bb_banner); /* reuse const string */
801 full_write2_str(" multi-call binary.\n"); /* reuse */ 846 full_write2_str(" multi-call binary\n"); /* reuse */
847#if defined(MINGW_VER)
848 if (strlen(MINGW_VER)) {
849 full_write2_str(MINGW_VER "\n\n");
850 }
851#endif
802 full_write2_str( 852 full_write2_str(
803 "BusyBox is copyrighted by many authors between 1998-2015.\n" 853 "BusyBox is copyrighted by many authors between 1998-2015.\n"
804 "Licensed under GPLv2. See source distribution for detailed\n" 854 "Licensed under GPLv2. See source distribution for detailed\n"
805 "copyright notices.\n" 855 "copyright notices.\n"
806 "\n" 856 "\n"
807 "Usage: busybox [function [arguments]...]\n" 857 "Usage: busybox [function [arguments]...]\n"
858 IF_NOT_PLATFORM_MINGW32(
808 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" 859 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
860 )
861 IF_PLATFORM_MINGW32(
862 " or: busybox --list\n"
863 )
809 IF_FEATURE_INSTALLER( 864 IF_FEATURE_INSTALLER(
810 " or: busybox --install [-s] [DIR]\n" 865 " or: busybox --install "IF_NOT_PLATFORM_MINGW32("[-s] ")"[DIR]\n"
811 ) 866 )
812 " or: function [arguments]...\n" 867 " or: function [arguments]...\n"
813 "\n" 868 "\n"
@@ -825,6 +880,11 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
825 "\tTo run external program, use full path (/sbin/ip instead of ip).\n" 880 "\tTo run external program, use full path (/sbin/ip instead of ip).\n"
826 ) 881 )
827 "\n" 882 "\n"
883#if ENABLE_GLOBBING
884 "\tSupport for native Windows wildcards is enabled. In some\n"
885 "\tcases this may result in wildcards being processed twice.\n"
886 "\n"
887#endif
828 "Currently defined functions:\n" 888 "Currently defined functions:\n"
829 ); 889 );
830 col = 0; 890 col = 0;
@@ -856,7 +916,7 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
856 const char *a = applet_names; 916 const char *a = applet_names;
857 dup2(1, 2); 917 dup2(1, 2);
858 while (*a) { 918 while (*a) {
859# if ENABLE_FEATURE_INSTALLER 919# if ENABLE_FEATURE_INSTALLER && !ENABLE_PLATFORM_MINGW32
860 if (argv[1][6]) /* --list-full? */ 920 if (argv[1][6]) /* --list-full? */
861 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); 921 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
862# endif 922# endif
@@ -870,6 +930,7 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
870 } 930 }
871 931
872 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { 932 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
933#if !ENABLE_PLATFORM_MINGW32
873 int use_symbolic_links; 934 int use_symbolic_links;
874 const char *busybox; 935 const char *busybox;
875 936
@@ -890,6 +951,14 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
890 */ 951 */
891 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv); 952 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv);
892 install_links(busybox, use_symbolic_links, argv[2]); 953 install_links(busybox, use_symbolic_links, argv[2]);
954#else
955 /* busybox --install [DIR]
956 * where DIR is the directory to install to. If DIR is not
957 * provided put the links in the same directory as busybox.
958 */
959 install_links(bb_busybox_exec_path, FALSE, argv[2] ? argv[2] :
960 dirname(xstrdup(bb_busybox_exec_path)));
961#endif
893 return 0; 962 return 0;
894 } 963 }
895 964
@@ -1031,6 +1100,18 @@ int main(int argc UNUSED_PARAM, char **argv)
1031 } 1100 }
1032#endif 1101#endif
1033 1102
1103#if defined(__MINGW64_VERSION_MAJOR)
1104 if ( stdin ) {
1105 _setmode(fileno(stdin), _O_BINARY);
1106 }
1107 if ( stdout ) {
1108 _setmode(fileno(stdout), _O_BINARY);
1109 }
1110 if ( stderr ) {
1111 _setmode(fileno(stderr), _O_BINARY);
1112 }
1113#endif
1114
1034#if defined(SINGLE_APPLET_MAIN) 1115#if defined(SINGLE_APPLET_MAIN)
1035 1116
1036 /* Only one applet is selected in .config */ 1117 /* Only one applet is selected in .config */
@@ -1062,6 +1143,24 @@ int main(int argc UNUSED_PARAM, char **argv)
1062 applet_name = argv[0]; 1143 applet_name = argv[0];
1063 if (applet_name[0] == '-') 1144 if (applet_name[0] == '-')
1064 applet_name++; 1145 applet_name++;
1146 if (ENABLE_PLATFORM_MINGW32) {
1147 if ( argv[1] && argv[2] && strcmp(argv[1], "--busybox") == 0 ) {
1148 argv += 2;
1149 applet_name = argv[0];
1150 }
1151 else {
1152 char *s = argv[0];
1153 int i, len = strlen(s);
1154
1155 for ( i=0; i < len; ++i ) {
1156 s[i] = tolower(s[i]);
1157 }
1158 if (len > 4 && !strcmp(s+len-4, ".exe")) {
1159 len -= 4;
1160 s[len] = '\0';
1161 }
1162 }
1163 }
1065 applet_name = bb_basename(applet_name); 1164 applet_name = bb_basename(applet_name);
1066 1165
1067# if defined(__linux__) 1166# if defined(__linux__)
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index 23c0f8320..cb6d12359 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -105,12 +105,15 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
105 return -1; 105 return -1;
106 } 106 }
107 } else { 107 } else {
108#if !ENABLE_PLATFORM_MINGW32
109 /* MinGW does not have inode, and does not use device */
108 if (source_stat.st_dev == dest_stat.st_dev 110 if (source_stat.st_dev == dest_stat.st_dev
109 && source_stat.st_ino == dest_stat.st_ino 111 && source_stat.st_ino == dest_stat.st_ino
110 ) { 112 ) {
111 bb_error_msg("'%s' and '%s' are the same file", source, dest); 113 bb_error_msg("'%s' and '%s' are the same file", source, dest);
112 return -1; 114 return -1;
113 } 115 }
116#endif
114 dest_exists = 1; 117 dest_exists = 1;
115 } 118 }
116 119
diff --git a/libbb/executable.c b/libbb/executable.c
index 3a1d4ff44..5f0ff8c6e 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..de314a3c7 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 static 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..15eb85ca8 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
@@ -26,8 +31,18 @@ char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path)
26{ 31{
27 char *slash = strrchr(path, '/'); 32 char *slash = strrchr(path, '/');
28 33
34#if ENABLE_PLATFORM_MINGW32
35 const char *start = has_dos_drive_prefix(path) ? path+2 : path;
36
37 if (!slash)
38 slash = strrchr(path, '\\');
39
40 if (!slash || (slash == start && !slash[1]))
41 return (char*)path;
42#else
29 if (!slash || (slash == path && !slash[1])) 43 if (!slash || (slash == path && !slash[1]))
30 return (char*)path; 44 return (char*)path;
45#endif
31 46
32 return slash + 1; 47 return slash + 1;
33} 48}
@@ -42,9 +57,20 @@ char* FAST_FUNC bb_get_last_path_component_strip(char *path)
42{ 57{
43 char *slash = last_char_is(path, '/'); 58 char *slash = last_char_is(path, '/');
44 59
60#if ENABLE_PLATFORM_MINGW32
61 const char *start = has_dos_drive_prefix(path) ? path+2 : path;
62
63 if (!slash)
64 slash = last_char_is(path, '\\');
65
66 if (slash)
67 while ((*slash == '/' || *slash == '\\') && slash != start)
68 *slash-- = '\0';
69#else
45 if (slash) 70 if (slash)
46 while (*slash == '/' && slash != path) 71 while (*slash == '/' && slash != path)
47 *slash-- = '\0'; 72 *slash-- = '\0';
73#endif
48 74
49 return bb_get_last_path_component_nostrip(path); 75 return bb_get_last_path_component_nostrip(path);
50} 76}
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/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 e5721b063..051a39b2e 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -354,7 +354,7 @@ int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
354/* Put 'command_ps[cursor]', cursor++. 354/* Put 'command_ps[cursor]', cursor++.
355 * Advance cursor on screen. If we reached right margin, scroll text up 355 * Advance cursor on screen. If we reached right margin, scroll text up
356 * and remove terminal margin effect by printing 'next_char' */ 356 * and remove terminal margin effect by printing 'next_char' */
357#define HACK_FOR_WRONG_WIDTH 1 357#define HACK_FOR_WRONG_WIDTH 1 && !ENABLE_PLATFORM_MINGW32
358static void put_cur_glyph_and_inc_cursor(void) 358static void put_cur_glyph_and_inc_cursor(void)
359{ 359{
360 CHAR_T c = command_ps[cursor]; 360 CHAR_T c = command_ps[cursor];
@@ -417,6 +417,42 @@ static void put_cur_glyph_and_inc_cursor(void)
417 } 417 }
418} 418}
419 419
420#if ENABLE_PLATFORM_MINGW32
421static void inc_cursor(void)
422{
423 CHAR_T c = command_ps[cursor];
424 unsigned width = 0;
425 int ofs_to_right;
426
427 /* advance cursor */
428 cursor++;
429 if (unicode_status == UNICODE_ON) {
430 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
431 c = adjust_width_and_validate_wc(&cmdedit_x, c);
432 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
433 } else {
434 cmdedit_x++;
435 }
436
437 ofs_to_right = cmdedit_x - cmdedit_termw;
438 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
439 /* cursor remains on this line */
440 printf(ESC"[1C");
441 }
442
443 if (ofs_to_right >= 0) {
444 /* we go to the next line */
445 printf(ESC"[1B");
446 bb_putchar('\r');
447 cmdedit_y++;
448 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
449 width = 0;
450 }
451 cmdedit_x = width;
452 }
453}
454#endif
455
420/* Move to end of line (by printing all chars till the end) */ 456/* Move to end of line (by printing all chars till the end) */
421static void put_till_end_and_adv_cursor(void) 457static void put_till_end_and_adv_cursor(void)
422{ 458{
@@ -469,6 +505,7 @@ static void input_backward(unsigned num)
469 505
470 if (cmdedit_x >= num) { 506 if (cmdedit_x >= num) {
471 cmdedit_x -= num; 507 cmdedit_x -= num;
508#if !ENABLE_PLATFORM_MINGW32
472 if (num <= 4) { 509 if (num <= 4) {
473 /* This is longer by 5 bytes on x86. 510 /* This is longer by 5 bytes on x86.
474 * Also gets miscompiled for ARM users 511 * Also gets miscompiled for ARM users
@@ -481,6 +518,7 @@ static void input_backward(unsigned num)
481 } while (--num); 518 } while (--num);
482 return; 519 return;
483 } 520 }
521#endif
484 printf(ESC"[%uD", num); 522 printf(ESC"[%uD", num);
485 return; 523 return;
486 } 524 }
@@ -610,7 +648,11 @@ static void input_backspace(void)
610static void input_forward(void) 648static void input_forward(void)
611{ 649{
612 if (cursor < command_len) 650 if (cursor < command_len)
651#if !ENABLE_PLATFORM_MINGW32
613 put_cur_glyph_and_inc_cursor(); 652 put_cur_glyph_and_inc_cursor();
653#else
654 inc_cursor();
655#endif
614} 656}
615 657
616#if ENABLE_FEATURE_TAB_COMPLETION 658#if ENABLE_FEATURE_TAB_COMPLETION
@@ -718,7 +760,11 @@ static int path_parse(char ***p)
718 tmp = (char*)pth; 760 tmp = (char*)pth;
719 npth = 1; /* path component count */ 761 npth = 1; /* path component count */
720 while (1) { 762 while (1) {
763#if ENABLE_PLATFORM_MINGW32
764 tmp = (char *)next_path_sep(tmp);
765#else
721 tmp = strchr(tmp, ':'); 766 tmp = strchr(tmp, ':');
767#endif
722 if (!tmp) 768 if (!tmp)
723 break; 769 break;
724 tmp++; 770 tmp++;
@@ -731,7 +777,11 @@ static int path_parse(char ***p)
731 res[0] = tmp = xstrdup(pth); 777 res[0] = tmp = xstrdup(pth);
732 npth = 1; 778 npth = 1;
733 while (1) { 779 while (1) {
780#if ENABLE_PLATFORM_MINGW32
781 tmp = (char *)next_path_sep(tmp);
782#else
734 tmp = strchr(tmp, ':'); 783 tmp = strchr(tmp, ':');
784#endif
735 if (!tmp) 785 if (!tmp)
736 break; 786 break;
737 *tmp++ = '\0'; /* ':' -> '\0' */ 787 *tmp++ = '\0'; /* ':' -> '\0' */
@@ -817,6 +867,9 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
817 if (stat(found, &st) && lstat(found, &st)) 867 if (stat(found, &st) && lstat(found, &st))
818 goto cont; /* hmm, remove in progress? */ 868 goto cont; /* hmm, remove in progress? */
819 869
870 if (type == FIND_EXE_ONLY && !file_is_executable(found))
871 goto cont;
872
820 /* Save only name */ 873 /* Save only name */
821 len = strlen(name_found); 874 len = strlen(name_found);
822 found = xrealloc(found, len + 2); /* +2: for slash and NUL */ 875 found = xrealloc(found, len + 2); /* +2: for slash and NUL */
@@ -1898,7 +1951,16 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1898 char *after_home_user; 1951 char *after_home_user;
1899 1952
1900 /* /home/user[/something] -> ~[/something] */ 1953 /* /home/user[/something] -> ~[/something] */
1954#if !ENABLE_PLATFORM_MINGW32
1901 after_home_user = is_prefixed_with(cwd_buf, home_pwd_buf); 1955 after_home_user = is_prefixed_with(cwd_buf, home_pwd_buf);
1956#else
1957 after_home_user = NULL;
1958 l = strlen(home_pwd_buf);
1959 if (l != 0
1960 && strncasecmp(home_pwd_buf, cwd_buf, l) == 0) {
1961 after_home_user = cwd_buf + l;
1962 }
1963#endif
1902 if (after_home_user 1964 if (after_home_user
1903 && (*after_home_user == '/' || *after_home_user == '\0') 1965 && (*after_home_user == '/' || *after_home_user == '\0')
1904 ) { 1966 ) {
@@ -2272,9 +2334,16 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2272 2334
2273 INIT_S(); 2335 INIT_S();
2274 2336
2337#if ENABLE_PLATFORM_MINGW32
2338 memset(initial_settings.c_cc, 0, sizeof(initial_settings.c_cc));
2339 initial_settings.c_cc[VINTR] = CTRL('C');
2340 initial_settings.c_cc[VEOF] = CTRL('D');
2341 if (!isatty(0) || !isatty(1)) {
2342#else
2275 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0 2343 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
2276 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON 2344 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON
2277 ) { 2345 ) {
2346#endif
2278 /* Happens when e.g. stty -echo was run before. 2347 /* Happens when e.g. stty -echo was run before.
2279 * But if ICANON is not set, we don't come here. 2348 * But if ICANON is not set, we don't come here.
2280 * (example: interactive python ^Z-backgrounded, 2349 * (example: interactive python ^Z-backgrounded,
@@ -2383,6 +2452,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2383 } 2452 }
2384 2453
2385 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); 2454 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
2455#if ENABLE_PLATFORM_MINGW32
2456 /* scroll to cursor position on any keypress */
2457 if (isatty(fileno(stdin)) && isatty(fileno(stdout)))
2458 move_cursor_row(0);
2459#endif
2386 2460
2387#if ENABLE_FEATURE_REVERSE_SEARCH 2461#if ENABLE_FEATURE_REVERSE_SEARCH
2388 again: 2462 again:
diff --git a/libbb/make_directory.c b/libbb/make_directory.c
index a6b7c28df..3e171ff02 100644
--- a/libbb/make_directory.c
+++ b/libbb/make_directory.c
@@ -51,11 +51,44 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
51 } 51 }
52 52
53 org_mask = cur_mask = (mode_t)-1L; 53 org_mask = cur_mask = (mode_t)-1L;
54#if ENABLE_PLATFORM_MINGW32
55 /* normalise path separators, path is already assumed writable */
56 for (s=path; *s; ++s) {
57 if (*s == '\\') {
58 *s = '/';
59 }
60 }
61#endif
54 s = path; 62 s = path;
55 while (1) { 63 while (1) {
56 c = '\0'; 64 c = '\0';
57 65
58 if (flags & FILEUTILS_RECUR) { /* Get the parent */ 66 if (flags & FILEUTILS_RECUR) { /* Get the parent */
67#if ENABLE_PLATFORM_MINGW32
68 if (s == path && *s && s[1] == ':') {
69 /* skip drive letter */
70 s += 2;
71 }
72 else if (s == path && s[0] == '/' && s[1] == '/' ) {
73 /* skip UNC server and share */
74 int count = 0;
75 s += 2;
76 while (*s) {
77 if (*s == '/') {
78 do {
79 ++s;
80 } while (*s == '/');
81 if (++count == 2) {
82 --s;
83 break;
84 }
85 }
86 else {
87 ++s;
88 }
89 }
90 }
91#endif
59 /* Bypass leading non-'/'s and then subsequent '/'s */ 92 /* Bypass leading non-'/'s and then subsequent '/'s */
60 while (*s) { 93 while (*s) {
61 if (*s == '/') { 94 if (*s == '/') {
diff --git a/libbb/messages.c b/libbb/messages.c
index 27fd14ecc..3c0b921cf 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -33,7 +33,9 @@ const char bb_msg_standard_output[] ALIGN1 = "standard output";
33 33
34const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; 34const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
35 35
36#if !ENABLE_PLATFORM_MINGW32
36const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; 37const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
38#endif
37const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; 39const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
38/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 40/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
39 * but I want to save a few bytes here. Check libbb.h before changing! */ 41 * 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 077d58d32..e638a178e 100644
--- a/libbb/printable_string.c
+++ b/libbb/printable_string.c
@@ -42,7 +42,7 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
42 unsigned char c = *d; 42 unsigned char c = *d;
43 if (c == '\0') 43 if (c == '\0')
44 break; 44 break;
45 if (c < ' ' || c >= 0x7f) 45 if (c < ' ' || (c >= 0x7f && !ENABLE_PLATFORM_MINGW32))
46 *d = '?'; 46 *d = '?';
47 d++; 47 d++;
48 } 48 }
diff --git a/libbb/procps.c b/libbb/procps.c
index b52c0f51b..6f971a116 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
@@ -622,6 +623,8 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
622 } 623 }
623} 624}
624 625
626#endif /* ENABLE_PLATFORM_MINGW32 */
627
625/* from kernel: 628/* from kernel:
626 // pid comm S ppid pgid sid tty_nr tty_pgrp flg 629 // pid comm S ppid pgid sid tty_nr tty_pgrp flg
627 sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ 630 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 b6a17cc36..e47ac7afe 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 576534ee5..4b3ed5a3b 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -18,6 +18,7 @@
18#include "busybox.h" /* uses applet tables */ 18#include "busybox.h" /* uses applet tables */
19#include "NUM_APPLETS.h" 19#include "NUM_APPLETS.h"
20 20
21#if !ENABLE_PLATFORM_MINGW32
21/* This does a fork/exec in one call, using vfork(). Returns PID of new child, 22/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
22 * -1 for failure. Runs argv[0], searching path if that has no / in it. */ 23 * -1 for failure. Runs argv[0], searching path if that has no / in it. */
23pid_t FAST_FUNC spawn(char **argv) 24pid_t FAST_FUNC spawn(char **argv)
@@ -59,6 +60,7 @@ pid_t FAST_FUNC spawn(char **argv)
59 } 60 }
60 return pid; 61 return pid;
61} 62}
63#endif
62 64
63/* Die with an error message if we can't spawn a child process. */ 65/* Die with an error message if we can't spawn a child process. */
64pid_t FAST_FUNC xspawn(char **argv) 66pid_t FAST_FUNC xspawn(char **argv)
@@ -164,6 +166,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
164 if (APPLET_IS_NOFORK(a)) 166 if (APPLET_IS_NOFORK(a))
165 return run_nofork_applet(a, argv); 167 return run_nofork_applet(a, argv);
166# if BB_MMU /* NOEXEC needs fork(), thus this is done only on MMU machines: */ 168# if BB_MMU /* NOEXEC needs fork(), thus this is done only on MMU machines: */
169# if !ENABLE_PLATFORM_MINGW32 /* and then only if not on Microsoft Windows */
167 if (APPLET_IS_NOEXEC(a)) { 170 if (APPLET_IS_NOEXEC(a)) {
168 fflush_all(); 171 fflush_all();
169 rc = fork(); 172 rc = fork();
@@ -182,6 +185,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
182 /* xfunc_error_retval and applet_name are init by: */ 185 /* xfunc_error_retval and applet_name are init by: */
183 run_applet_no_and_exit(a, argv[0], argv); 186 run_applet_no_and_exit(a, argv[0], argv);
184 } 187 }
188# endif
185# endif 189# endif
186 } 190 }
187#endif /* FEATURE_PREFER_APPLETS */ 191#endif /* FEATURE_PREFER_APPLETS */
diff --git a/libbb/xatonum_template.c b/libbb/xatonum_template.c
index e0471983c..0d5d35b47 100644
--- a/libbb/xatonum_template.c
+++ b/libbb/xatonum_template.c
@@ -67,7 +67,7 @@ unsigned type FAST_FUNC xstrtou(_range_sfx)(const char *numstr, int base,
67 if (r >= lower && r <= upper) 67 if (r >= lower && r <= upper)
68 return r; 68 return r;
69 range: 69 range:
70 bb_error_msg_and_die("number %s is not in %llu..%llu range", 70 bb_error_msg_and_die("number %s is not in %"LL_FMT"u..%"LL_FMT"u range",
71 numstr, (unsigned long long)lower, 71 numstr, (unsigned long long)lower,
72 (unsigned long long)upper); 72 (unsigned long long)upper);
73 inval: 73 inval:
@@ -144,7 +144,8 @@ type FAST_FUNC xstrto(_range_sfx)(const char *numstr, int base,
144 } 144 }
145 145
146 if (r < lower || r > upper) { 146 if (r < lower || r > upper) {
147 bb_error_msg_and_die("number %s is not in %lld..%lld range", 147 bb_error_msg_and_die("number %s is not in "
148 "%"LL_FMT"d..%"LL_FMT"d range",
148 numstr, (long long)lower, (long long)upper); 149 numstr, (long long)lower, (long long)upper);
149 } 150 }
150 151
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 3a0dc2653..ee54898e3 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -98,15 +98,15 @@ len_and_sockaddr* FAST_FUNC get_peer_lsa(int fd)
98 return get_lsa(fd, getpeername); 98 return get_lsa(fd, getpeername);
99} 99}
100 100
101void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) 101void FAST_FUNC xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen)
102{ 102{
103 if (connect(s, s_addr, addrlen) < 0) { 103 if (connect(s, saddr, addrlen) < 0) {
104 if (ENABLE_FEATURE_CLEAN_UP) 104 if (ENABLE_FEATURE_CLEAN_UP)
105 close(s); 105 close(s);
106 if (s_addr->sa_family == AF_INET) 106 if (saddr->sa_family == AF_INET)
107 bb_perror_msg_and_die("%s (%s)", 107 bb_perror_msg_and_die("%s (%s)",
108 "can't connect to remote host", 108 "can't connect to remote host",
109 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr)); 109 inet_ntoa(((struct sockaddr_in *)saddr)->sin_addr));
110 bb_perror_msg_and_die("can't connect to remote host"); 110 bb_perror_msg_and_die("can't connect to remote host");
111 } 111 }
112} 112}
@@ -353,6 +353,10 @@ int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, int family, int sock_type)
353#if ENABLE_FEATURE_IPV6 353#if ENABLE_FEATURE_IPV6
354 fd = socket(AF_INET6, sock_type, 0); 354 fd = socket(AF_INET6, sock_type, 0);
355 if (fd >= 0) { 355 if (fd >= 0) {
356#if ENABLE_PLATFORM_MINGW32
357 DWORD buffer = 0;
358 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &buffer, sizeof(DWORD));
359#endif
356 family = AF_INET6; 360 family = AF_INET6;
357 goto done; 361 goto done;
358 } 362 }
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/bbconfig.c b/miscutils/bbconfig.c
index 045aca211..bcc9caa7c 100644
--- a/miscutils/bbconfig.c
+++ b/miscutils/bbconfig.c
@@ -34,6 +34,7 @@
34#include "libbb.h" 34#include "libbb.h"
35#include "bbconfigopts.h" 35#include "bbconfigopts.h"
36#if ENABLE_FEATURE_COMPRESS_BBCONFIG 36#if ENABLE_FEATURE_COMPRESS_BBCONFIG
37#define BB_ARCHIVE_PUBLIC
37# include "bb_archive.h" 38# include "bb_archive.h"
38# include "bbconfigopts_bz2.h" 39# include "bbconfigopts_bz2.h"
39#endif 40#endif
diff --git a/miscutils/dc.c b/miscutils/dc.c
index b922a7184..f752a1377 100644
--- a/miscutils/dc.c
+++ b/miscutils/dc.c
@@ -56,7 +56,7 @@ typedef unsigned long data_t;
56#define DATA_FMT "l" 56#define DATA_FMT "l"
57#else 57#else
58typedef unsigned long long data_t; 58typedef unsigned long long data_t;
59#define DATA_FMT "ll" 59#define DATA_FMT LL_FMT
60#endif 60#endif
61 61
62 62
diff --git a/miscutils/less.c b/miscutils/less.c
index c1d5e1b39..75ded97cf 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -127,6 +127,10 @@
127 127
128#include <sched.h> /* sched_yield() */ 128#include <sched.h> /* sched_yield() */
129 129
130#if ENABLE_PLATFORM_MINGW32
131#include <conio.h>
132#endif
133
130#include "libbb.h" 134#include "libbb.h"
131#include "common_bufsiz.h" 135#include "common_bufsiz.h"
132#if ENABLE_FEATURE_LESS_REGEXP 136#if ENABLE_FEATURE_LESS_REGEXP
@@ -533,6 +537,11 @@ static void read_lines(void)
533 last_line_pos = 0; 537 last_line_pos = 0;
534 break; 538 break;
535 } 539 }
540#if ENABLE_PLATFORM_MINGW32
541 if (c == '\r') {
542 continue;
543 }
544#endif
536 /* NUL is substituted by '\n'! */ 545 /* NUL is substituted by '\n'! */
537 if (c == '\0') c = '\n'; 546 if (c == '\0') c = '\n';
538 *p++ = c; 547 *p++ = c;
@@ -629,7 +638,12 @@ static void update_num_lines(void)
629 /* only do this for regular files */ 638 /* only do this for regular files */
630 if (num_lines == REOPEN_AND_COUNT || num_lines == REOPEN_STDIN) { 639 if (num_lines == REOPEN_AND_COUNT || num_lines == REOPEN_STDIN) {
631 count = 0; 640 count = 0;
641#if !ENABLE_PLATFORM_MINGW32
632 fd = open("/proc/self/fd/0", O_RDONLY); 642 fd = open("/proc/self/fd/0", O_RDONLY);
643#else
644 /* don't even try to access /proc on WIN32 */
645 fd = -1;
646#endif
633 if (fd < 0 && num_lines == REOPEN_AND_COUNT) { 647 if (fd < 0 && num_lines == REOPEN_AND_COUNT) {
634 /* "filename" is valid only if REOPEN_AND_COUNT */ 648 /* "filename" is valid only if REOPEN_AND_COUNT */
635 fd = open(filename, O_RDONLY); 649 fd = open(filename, O_RDONLY);
@@ -812,7 +826,12 @@ static void print_found(const char *line)
812 match_status = 1; 826 match_status = 1;
813 } 827 }
814 828
829#if !ENABLE_PLATFORM_MINGW32
815 printf("%s%s\n", growline ? growline : "", str); 830 printf("%s%s\n", growline ? growline : "", str);
831#else
832 /* skip newline, we use explicit positioning on WIN32 */
833 printf("%s%s", growline ? growline : "", str);
834#endif
816 free(growline); 835 free(growline);
817} 836}
818#else 837#else
@@ -848,7 +867,12 @@ static void print_ascii(const char *str)
848 *p = '\0'; 867 *p = '\0';
849 print_hilite(buf); 868 print_hilite(buf);
850 } 869 }
870#if !ENABLE_PLATFORM_MINGW32
851 puts(str); 871 puts(str);
872#else
873 /* skip newline, we use explicit positioning on WIN32 */
874 printf("%s", str);
875#endif
852} 876}
853 877
854/* Print the buffer */ 878/* Print the buffer */
@@ -858,6 +882,10 @@ static void buffer_print(void)
858 882
859 move_cursor(0, 0); 883 move_cursor(0, 0);
860 for (i = 0; i <= max_displayed_line; i++) { 884 for (i = 0; i <= max_displayed_line; i++) {
885#if ENABLE_PLATFORM_MINGW32
886 /* make sure we're on the right line */
887 move_cursor(i+1, 0);
888#endif
861 printf(CLEAR_2_EOL); 889 printf(CLEAR_2_EOL);
862 if (option_mask32 & FLAG_N) 890 if (option_mask32 & FLAG_N)
863 print_lineno(buffer[i]); 891 print_lineno(buffer[i]);
@@ -1044,9 +1072,13 @@ static void reinitialize(void)
1044 if (G.winsize_err) 1072 if (G.winsize_err)
1045 printf("\033[999;999H" "\033[6n"); 1073 printf("\033[999;999H" "\033[6n");
1046#endif 1074#endif
1075#if ENABLE_PLATFORM_MINGW32
1076 reset_screen();
1077#endif
1047 buffer_fill_and_print(); 1078 buffer_fill_and_print();
1048} 1079}
1049 1080
1081#if !ENABLE_PLATFORM_MINGW32
1050static int64_t getch_nowait(void) 1082static int64_t getch_nowait(void)
1051{ 1083{
1052 int rd; 1084 int rd;
@@ -1108,6 +1140,46 @@ static int64_t getch_nowait(void)
1108 set_tty_cooked(); 1140 set_tty_cooked();
1109 return key64; 1141 return key64;
1110} 1142}
1143#else
1144static int64_t getch_nowait(void)
1145{
1146 int64_t c;
1147
1148retry:
1149 c = _getch();
1150 if (c == 0 || c == 0xe0) {
1151 switch (_getch()) {
1152 case 0x48:
1153 c = KEYCODE_UP;
1154 break;
1155 case 0x50:
1156 c = KEYCODE_DOWN;
1157 break;
1158 case 0x49:
1159 c = KEYCODE_PAGEUP;
1160 break;
1161 case 0x51:
1162 c = KEYCODE_PAGEDOWN;
1163 break;
1164 case 0x47:
1165 c = KEYCODE_HOME;
1166 break;
1167 case 0x4f:
1168 c = KEYCODE_END;
1169 break;
1170 default:
1171 goto retry;
1172 }
1173 }
1174
1175 /* Position cursor if line input is done */
1176 if (less_gets_pos >= 0)
1177 move_cursor(max_displayed_line + 2, less_gets_pos + 1);
1178 fflush_all();
1179
1180 return c;
1181}
1182#endif
1111 1183
1112/* Grab a character from input without requiring the return key. 1184/* Grab a character from input without requiring the return key.
1113 * May return KEYCODE_xxx values. 1185 * May return KEYCODE_xxx values.
@@ -1763,8 +1835,10 @@ static void sigwinch_handler(int sig UNUSED_PARAM)
1763int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1835int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1764int less_main(int argc, char **argv) 1836int less_main(int argc, char **argv)
1765{ 1837{
1838#if !ENABLE_PLATFORM_MINGW32
1766 char *tty_name; 1839 char *tty_name;
1767 int tty_fd; 1840 int tty_fd;
1841#endif
1768 1842
1769 INIT_G(); 1843 INIT_G();
1770 1844
@@ -1798,6 +1872,7 @@ int less_main(int argc, char **argv)
1798 if (option_mask32 & FLAG_TILDE) 1872 if (option_mask32 & FLAG_TILDE)
1799 empty_line_marker = ""; 1873 empty_line_marker = "";
1800 1874
1875#if !ENABLE_PLATFORM_MINGW32
1801 /* Some versions of less can survive w/o controlling tty, 1876 /* Some versions of less can survive w/o controlling tty,
1802 * try to do the same. This also allows to specify an alternative 1877 * try to do the same. This also allows to specify an alternative
1803 * tty via "less 1<>TTY". 1878 * tty via "less 1<>TTY".
@@ -1823,6 +1898,9 @@ int less_main(int argc, char **argv)
1823 } 1898 }
1824 G.kbd_fd_orig_flags = ndelay_on(tty_fd); 1899 G.kbd_fd_orig_flags = ndelay_on(tty_fd);
1825 kbd_fd = tty_fd; /* save in a global */ 1900 kbd_fd = tty_fd; /* save in a global */
1901#else
1902 kbd_fd = 0;
1903#endif
1826 1904
1827 tcgetattr(kbd_fd, &term_orig); 1905 tcgetattr(kbd_fd, &term_orig);
1828 term_less = term_orig; 1906 term_less = term_orig;
diff --git a/miscutils/man.c b/miscutils/man.c
index a16202f25..f68784767 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -200,7 +200,11 @@ static char **add_MANPATH(char **man_path_list, int *count_mp, char *path)
200 char *next_path; 200 char *next_path;
201 char **path_element; 201 char **path_element;
202 202
203#if ENABLE_PLATFORM_MINGW32
204 next_path = next_path_sep(path);
205#else
203 next_path = strchr(path, ':'); 206 next_path = strchr(path, ':');
207#endif
204 if (next_path) { 208 if (next_path) {
205 if (next_path == path) /* "::"? */ 209 if (next_path == path) /* "::"? */
206 goto next; 210 goto next;
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index d70f4ca77..cb0a96b59 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -123,6 +123,9 @@ static int ftpcmd(const char *s1, const char *s2)
123 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3), 123 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3),
124 s1, s2); 124 s1, s2);
125 fflush(control_stream); 125 fflush(control_stream);
126#if ENABLE_PLATFORM_MINGW32
127 fseek(control_stream, 0L, SEEK_CUR);
128#endif
126 } 129 }
127 130
128 do { 131 do {
@@ -131,6 +134,9 @@ static int ftpcmd(const char *s1, const char *s2)
131 ftp_die(NULL); 134 ftp_die(NULL);
132 } 135 }
133 } while (!isdigit(buf[0]) || buf[3] != ' '); 136 } while (!isdigit(buf[0]) || buf[3] != ' ');
137#if ENABLE_PLATFORM_MINGW32
138 fseek(control_stream, 0L, SEEK_CUR);
139#endif
134 140
135 buf[3] = '\0'; 141 buf[3] = '\0';
136 n = xatou(buf); 142 n = xatou(buf);
diff --git a/networking/nc.c b/networking/nc.c
index a13d77a00..df073d7df 100644
--- a/networking/nc.c
+++ b/networking/nc.c
@@ -117,7 +117,7 @@ int nc_main(int argc, char **argv)
117 IF_NOT_NC_EXTRA (const) unsigned delay = 0; 117 IF_NOT_NC_EXTRA (const) unsigned delay = 0;
118 IF_NOT_NC_EXTRA (const int execparam = 0;) 118 IF_NOT_NC_EXTRA (const int execparam = 0;)
119 IF_NC_EXTRA (char **execparam = NULL;) 119 IF_NC_EXTRA (char **execparam = NULL;)
120 struct pollfd pfds[2]; 120 fd_set readfds, testfds;
121 int opt; /* must be signed (getopt returns -1) */ 121 int opt; /* must be signed (getopt returns -1) */
122 122
123 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { 123 if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) {
@@ -235,28 +235,29 @@ int nc_main(int argc, char **argv)
235 IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);) 235 IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);)
236 } 236 }
237 237
238 /* loop copying stdin to cfd, and cfd to stdout */ 238 /* Select loop copying stdin to cfd, and cfd to stdout */
239 239
240 pfds[0].fd = STDIN_FILENO; 240 FD_ZERO(&readfds);
241 pfds[0].events = POLLIN; 241 FD_SET(cfd, &readfds);
242 pfds[1].fd = cfd; 242 FD_SET(STDIN_FILENO, &readfds);
243 pfds[1].events = POLLIN;
244 243
245#define iobuf bb_common_bufsiz1 244#define iobuf bb_common_bufsiz1
246 setup_common_bufsiz(); 245 setup_common_bufsiz();
247 for (;;) { 246 for (;;) {
248 int fdidx; 247 int fd;
249 int ofd; 248 int ofd;
250 int nread; 249 int nread;
251 250
252 if (safe_poll(pfds, 2, -1) < 0) 251 testfds = readfds;
253 bb_perror_msg_and_die("poll");
254 252
255 fdidx = 0; 253 if (select(cfd + 1, &testfds, NULL, NULL, NULL) < 0)
254 bb_perror_msg_and_die("select");
255
256 fd = STDIN_FILENO;
256 while (1) { 257 while (1) {
257 if (pfds[fdidx].revents) { 258 if (FD_ISSET(fd, &testfds)) {
258 nread = safe_read(pfds[fdidx].fd, iobuf, COMMON_BUFSIZE); 259 nread = safe_read(fd, iobuf, COMMON_BUFSIZE);
259 if (fdidx != 0) { 260 if (fd == cfd) {
260 if (nread < 1) 261 if (nread < 1)
261 exit(EXIT_SUCCESS); 262 exit(EXIT_SUCCESS);
262 ofd = STDOUT_FILENO; 263 ofd = STDOUT_FILENO;
@@ -265,7 +266,7 @@ int nc_main(int argc, char **argv)
265 /* Close outgoing half-connection so they get EOF, 266 /* Close outgoing half-connection so they get EOF,
266 * but leave incoming alone so we can see response */ 267 * but leave incoming alone so we can see response */
267 shutdown(cfd, SHUT_WR); 268 shutdown(cfd, SHUT_WR);
268 pfds[0].fd = -1; 269 FD_CLR(STDIN_FILENO, &readfds);
269 } 270 }
270 ofd = cfd; 271 ofd = cfd;
271 } 272 }
@@ -273,9 +274,9 @@ int nc_main(int argc, char **argv)
273 if (delay > 0) 274 if (delay > 0)
274 sleep(delay); 275 sleep(delay);
275 } 276 }
276 if (fdidx == 1) 277 if (fd == cfd)
277 break; 278 break;
278 fdidx++; 279 fd = cfd;
279 } 280 }
280 } 281 }
281} 282}
diff --git a/networking/wget.c b/networking/wget.c
index e47c9a51b..ab9bc1836 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -457,11 +457,17 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp)
457 fprintf(stderr, "--> %s%s\n\n", s1, s2); 457 fprintf(stderr, "--> %s%s\n\n", s1, s2);
458 fflush(fp); 458 fflush(fp);
459 log_io("> %s%s", s1, s2); 459 log_io("> %s%s", s1, s2);
460#if ENABLE_PLATFORM_MINGW32
461 fseek(fp, 0L, SEEK_CUR);
462#endif
460 } 463 }
461 464
462 do { 465 do {
463 fgets_and_trim(fp, "%s\n"); 466 fgets_and_trim(fp, "%s\n");
464 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); 467 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
468#if ENABLE_PLATFORM_MINGW32
469 fseek(fp, 0L, SEEK_CUR);
470#endif
465 471
466 G.wget_buf[3] = '\0'; 472 G.wget_buf[3] = '\0';
467 result = xatoi_positive(G.wget_buf); 473 result = xatoi_positive(G.wget_buf);
diff --git a/procps/iostat.c b/procps/iostat.c
index 608d41364..6a39c324f 100644
--- a/procps/iostat.c
+++ b/procps/iostat.c
@@ -29,7 +29,7 @@
29#if 1 29#if 1
30typedef unsigned long long cputime_t; 30typedef unsigned long long cputime_t;
31typedef long long icputime_t; 31typedef long long icputime_t;
32# define FMT_DATA "ll" 32# define FMT_DATA LL_FMT
33# define CPUTIME_MAX (~0ULL) 33# define CPUTIME_MAX (~0ULL)
34#else 34#else
35typedef unsigned long cputime_t; 35typedef unsigned long cputime_t;
diff --git a/procps/mpstat.c b/procps/mpstat.c
index 1eabd8e38..05a3f3ff3 100644
--- a/procps/mpstat.c
+++ b/procps/mpstat.c
@@ -49,7 +49,7 @@
49#if 1 49#if 1
50typedef unsigned long long data_t; 50typedef unsigned long long data_t;
51typedef long long idata_t; 51typedef long long idata_t;
52#define FMT_DATA "ll" 52#define FMT_DATA LL_FMT
53#define DATA_MAX ULLONG_MAX 53#define DATA_MAX ULLONG_MAX
54#else 54#else
55typedef unsigned long data_t; 55typedef unsigned long data_t;
diff --git a/procps/ps.c b/procps/ps.c
index eb1946d27..3e83a3e03 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -286,6 +286,7 @@ static unsigned get_kernel_HZ(void)
286 286
287/* Print value to buf, max size+1 chars (including trailing '\0') */ 287/* Print value to buf, max size+1 chars (including trailing '\0') */
288 288
289#if !ENABLE_PLATFORM_MINGW32
289static void func_user(char *buf, int size, const procps_status_t *ps) 290static void func_user(char *buf, int size, const procps_status_t *ps)
290{ 291{
291#if 1 292#if 1
@@ -309,12 +310,14 @@ static void func_group(char *buf, int size, const procps_status_t *ps)
309{ 310{
310 safe_strncpy(buf, get_cached_groupname(ps->gid), size+1); 311 safe_strncpy(buf, get_cached_groupname(ps->gid), size+1);
311} 312}
313#endif
312 314
313static void func_comm(char *buf, int size, const procps_status_t *ps) 315static void func_comm(char *buf, int size, const procps_status_t *ps)
314{ 316{
315 safe_strncpy(buf, ps->comm, size+1); 317 safe_strncpy(buf, ps->comm, size+1);
316} 318}
317 319
320#if !ENABLE_PLATFORM_MINGW32
318static void func_state(char *buf, int size, const procps_status_t *ps) 321static void func_state(char *buf, int size, const procps_status_t *ps)
319{ 322{
320 safe_strncpy(buf, ps->state, size+1); 323 safe_strncpy(buf, ps->state, size+1);
@@ -324,12 +327,14 @@ static void func_args(char *buf, int size, const procps_status_t *ps)
324{ 327{
325 read_cmdline(buf, size+1, ps->pid, ps->comm); 328 read_cmdline(buf, size+1, ps->pid, ps->comm);
326} 329}
330#endif
327 331
328static void func_pid(char *buf, int size, const procps_status_t *ps) 332static void func_pid(char *buf, int size, const procps_status_t *ps)
329{ 333{
330 sprintf(buf, "%*u", size, ps->pid); 334 sprintf(buf, "%*u", size, ps->pid);
331} 335}
332 336
337#if !ENABLE_PLATFORM_MINGW32
333static void func_ppid(char *buf, int size, const procps_status_t *ps) 338static void func_ppid(char *buf, int size, const procps_status_t *ps)
334{ 339{
335 sprintf(buf, "%*u", size, ps->ppid); 340 sprintf(buf, "%*u", size, ps->ppid);
@@ -371,6 +376,7 @@ static void func_tty(char *buf, int size, const procps_status_t *ps)
371 if (ps->tty_major) /* tty field of "0" means "no tty" */ 376 if (ps->tty_major) /* tty field of "0" means "no tty" */
372 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor); 377 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
373} 378}
379#endif
374 380
375#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 381#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
376 382
@@ -436,13 +442,19 @@ static void func_pcpu(char *buf, int size, const procps_status_t *ps)
436 442
437static const ps_out_t out_spec[] = { 443static const ps_out_t out_spec[] = {
438/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */ 444/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */
445#if !ENABLE_PLATFORM_MINGW32
439 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, 446 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID },
440 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, 447 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID },
448#endif
441 { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, 449 { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM },
450#if !ENABLE_PLATFORM_MINGW32
442 { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM }, 451 { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM },
452#endif
443 { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID }, 453 { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID },
454#if !ENABLE_PLATFORM_MINGW32
444 { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID }, 455 { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID },
445 { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID }, 456 { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID },
457#endif
446#if ENABLE_FEATURE_PS_TIME 458#if ENABLE_FEATURE_PS_TIME
447 { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME }, 459 { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME },
448#endif 460#endif
@@ -455,12 +467,14 @@ static const ps_out_t out_spec[] = {
455#if ENABLE_FEATURE_PS_TIME 467#if ENABLE_FEATURE_PS_TIME
456 { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, 468 { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME },
457#endif 469#endif
470#if !ENABLE_PLATFORM_MINGW32
458 { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, 471 { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY },
459 { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, 472 { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ },
460/* Not mandated, but useful: */ 473/* Not mandated, but useful: */
461 { 5 , "sid" ,"SID" ,func_sid ,PSSCAN_SID }, 474 { 5 , "sid" ,"SID" ,func_sid ,PSSCAN_SID },
462 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE }, 475 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE },
463 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, 476 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS },
477#endif
464#if ENABLE_SELINUX 478#if ENABLE_SELINUX
465 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, 479 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT },
466#endif 480#endif
@@ -599,6 +613,8 @@ static void format_process(const procps_status_t *ps)
599#if ENABLE_SELINUX 613#if ENABLE_SELINUX
600# define SELINUX_O_PREFIX "label," 614# define SELINUX_O_PREFIX "label,"
601# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") 615# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args")
616#elif ENABLE_PLATFORM_MINGW32
617# define DEFAULT_O_STR ("pid,comm")
602#else 618#else
603# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") 619# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args")
604#endif 620#endif
diff --git a/procps/smemcap.c b/procps/smemcap.c
index c15fef1c3..17aeccd53 100644
--- a/procps/smemcap.c
+++ b/procps/smemcap.c
@@ -20,6 +20,7 @@
20//config: a memory usage statistic tool. 20//config: a memory usage statistic tool.
21 21
22#include "libbb.h" 22#include "libbb.h"
23#define BB_ARCHIVE_PUBLIC
23#include "bb_archive.h" 24#include "bb_archive.h"
24 25
25struct fileblock { 26struct fileblock {
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
index 720098a23..bfc1a9844 100644
--- a/scripts/basic/docproc.c
+++ b/scripts/basic/docproc.c
@@ -38,7 +38,9 @@
38#include <unistd.h> 38#include <unistd.h>
39#include <limits.h> 39#include <limits.h>
40#include <sys/types.h> 40#include <sys/types.h>
41#ifndef __MINGW32__
41#include <sys/wait.h> 42#include <sys/wait.h>
43#endif
42//bbox disabled: #include <alloca.h> 44//bbox disabled: #include <alloca.h>
43 45
44/* exitstatus is used to keep track of any failing calls to kernel-doc, 46/* exitstatus is used to keep track of any failing calls to kernel-doc,
@@ -78,12 +80,24 @@ void usage (void)
78 */ 80 */
79void exec_kernel_doc(char **svec) 81void exec_kernel_doc(char **svec)
80{ 82{
83#ifndef __MINGW32__
81 pid_t pid; 84 pid_t pid;
82 int ret; 85 int ret;
86#endif
83 char *real_filename; 87 char *real_filename;
84 int rflen; 88 int rflen;
85 89
86 /* Make sure output generated so far are flushed */ 90 /* Make sure output generated so far are flushed */
91#ifdef __MINGW32__
92 fflush(stdout);
93 rflen = strlen(getenv("SRCTREE"));
94 rflen += strlen(KERNELDOCPATH KERNELDOC);
95 real_filename = alloca(rflen + 1);
96 strcpy(real_filename, getenv("SRCTREE"));
97 strcat(real_filename, KERNELDOCPATH KERNELDOC);
98 fprintf(stderr, "NOTIMPL: exec %s\n", real_filename);
99 exit(1);
100#else
87 fflush(stdout); 101 fflush(stdout);
88 switch(pid=fork()) { 102 switch(pid=fork()) {
89 case -1: 103 case -1:
@@ -106,6 +120,7 @@ void exec_kernel_doc(char **svec)
106 exitstatus |= WEXITSTATUS(ret); 120 exitstatus |= WEXITSTATUS(ret);
107 else 121 else
108 exitstatus = 0xff; 122 exitstatus = 0xff;
123#endif
109} 124}
110 125
111/* Types used to create list of all exported symbols in a number of files */ 126/* Types used to create list of all exported symbols in a number of files */
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 19f82df09..9f461a65b 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,57 @@
122#define INT_FIG_ ntohl(0x4649475f) 126#define INT_FIG_ ntohl(0x4649475f)
123*/ 127*/
124 128
129#ifndef O_BINARY
130#define O_BINARY 0
131#endif
132
133#ifdef __MINGW32__
134#define UNUSED __attribute__ ((__unused__))
135
136/* Workaround specifically for fixdep */
137#define PROT_READ 0
138#define MAP_PRIVATE 0
139void *mmap(void *start UNUSED, size_t size, int prot UNUSED,
140 int flags UNUSED, int fd, off_t offset UNUSED)
141{
142 void *p;
143 void *curP;
144 ssize_t readB;
145
146 p = malloc(size);
147 if (!p)
148 return (void*)((long)-1);
149
150 curP = p;
151
152 while (size > 0)
153 {
154 readB = read(fd, curP, size);
155
156 if (readB == 0)
157 {
158 /* EOF reached */
159 break;
160 }
161 else if (readB < 0)
162 {
163 perror("fixdep: read config");
164 free(p);
165 return (void*)((long)-1);
166 }
167
168 size -= readB;
169 curP += readB;
170 }
171
172 return p;
173}
174void munmap(void *p, size_t size UNUSED)
175{
176 free(p);
177}
178#endif
179
125char *target; 180char *target;
126char *depfile; 181char *depfile;
127char *cmdline; 182char *cmdline;
@@ -286,7 +341,7 @@ void do_config_file(char *filename)
286 int fd; 341 int fd;
287 void *map; 342 void *map;
288 343
289 fd = open(filename, O_RDONLY); 344 fd = open(filename, O_RDONLY | O_BINARY);
290 if (fd < 0) { 345 if (fd < 0) {
291 fprintf(stderr, "fixdep: "); 346 fprintf(stderr, "fixdep: ");
292 perror(filename); 347 perror(filename);
@@ -298,7 +353,7 @@ void do_config_file(char *filename)
298 return; 353 return;
299 } 354 }
300 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 355 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
301 if ((long) map == -1) { 356 if ((intptr_t) map == -1) {
302 perror("fixdep: mmap"); 357 perror("fixdep: mmap");
303 close(fd); 358 close(fd);
304 return; 359 return;
@@ -334,10 +389,12 @@ void parse_dep_file(void *map, size_t len)
334 m++; 389 m++;
335 p = m; 390 p = m;
336 while (p < end && *p != ' ') p++; 391 while (p < end && *p != ' ') p++;
392 if (p == m) break;
337 if (p == end) { 393 if (p == end) {
338 do p--; while (!isalnum(*p)); 394 do p--; while (p != m && !isalnum(*p));
339 p++; 395 p++;
340 } 396 }
397 if (p == m) break;
341 memcpy(s, m, p-m); s[p-m] = 0; 398 memcpy(s, m, p-m); s[p-m] = 0;
342 if (strrcmp(s, "include/autoconf.h") && 399 if (strrcmp(s, "include/autoconf.h") &&
343 strrcmp(s, "arch/um/include/uml-config.h") && 400 strrcmp(s, "arch/um/include/uml-config.h") &&
@@ -345,6 +402,7 @@ void parse_dep_file(void *map, size_t len)
345 printf(" %s \\\n", s); 402 printf(" %s \\\n", s);
346 do_config_file(s); 403 do_config_file(s);
347 } 404 }
405 if (p == end) break;
348 m = p + 1; 406 m = p + 1;
349 } 407 }
350 printf("\n%s: $(deps_%s)\n\n", target, target); 408 printf("\n%s: $(deps_%s)\n\n", target, target);
@@ -357,7 +415,7 @@ void print_deps(void)
357 int fd; 415 int fd;
358 void *map; 416 void *map;
359 417
360 fd = open(depfile, O_RDONLY); 418 fd = open(depfile, O_RDONLY | O_BINARY);
361 if (fd < 0) { 419 if (fd < 0) {
362 fprintf(stderr, "fixdep: "); 420 fprintf(stderr, "fixdep: ");
363 perror(depfile); 421 perror(depfile);
@@ -370,7 +428,7 @@ void print_deps(void)
370 return; 428 return;
371 } 429 }
372 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 430 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
373 if ((long) map == -1) { 431 if ((intptr_t) map == -1) {
374 perror("fixdep: mmap"); 432 perror("fixdep: mmap");
375 close(fd); 433 close(fd);
376 return; 434 return;
diff --git a/scripts/basic/split-include.c b/scripts/basic/split-include.c
index e328788e2..8127fe261 100644
--- a/scripts/basic/split-include.c
+++ b/scripts/basic/split-include.c
@@ -39,8 +39,6 @@
39 exit(1); \ 39 exit(1); \
40 } 40 }
41 41
42
43
44int main(int argc, const char * argv []) 42int main(int argc, const char * argv [])
45{ 43{
46 const char * str_my_name; 44 const char * str_my_name;
@@ -89,7 +87,11 @@ int main(int argc, const char * argv [])
89 /* Make output directory if needed. */ 87 /* Make output directory if needed. */
90 if (stat(str_dir_config, &stat_buf) != 0) 88 if (stat(str_dir_config, &stat_buf) != 0)
91 { 89 {
90#ifdef __MINGW32__
91 if (mkdir(str_dir_config) != 0)
92#else
92 if (mkdir(str_dir_config, 0755) != 0) 93 if (mkdir(str_dir_config, 0755) != 0)
94#endif
93 ERROR_EXIT(str_dir_config); 95 ERROR_EXIT(str_dir_config);
94 } 96 }
95 97
@@ -148,7 +150,12 @@ int main(int argc, const char * argv [])
148 { 150 {
149 ptarget[islash] = '\0'; 151 ptarget[islash] = '\0';
150 if (stat(ptarget, &stat_buf) != 0 152 if (stat(ptarget, &stat_buf) != 0
151 && mkdir(ptarget, 0755) != 0) 153#ifdef __MINGW32__
154 && mkdir(ptarget) != 0
155#else
156 && mkdir(ptarget, 0755) != 0
157#endif
158 )
152 ERROR_EXIT( ptarget ); 159 ERROR_EXIT( ptarget );
153 ptarget[islash] = '/'; 160 ptarget[islash] = '/';
154 } 161 }
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index ea2446a89..41ac23936 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -153,9 +153,14 @@ static void conf_askvalue(struct symbol *sym, const char *def)
153 break; 153 break;
154 } 154 }
155 case set_random: 155 case set_random:
156#ifdef __MINGW32__
157 fprintf(stderr, "set_random not supported\n");
158 exit(1);
159#else
156 do { 160 do {
157 val = (tristate)(random() % 3); 161 val = (tristate)(random() % 3);
158 } while (!sym_tristate_within_range(sym, val)); 162 } while (!sym_tristate_within_range(sym, val));
163#endif
159 switch (val) { 164 switch (val) {
160 case no: line[0] = 'n'; break; 165 case no: line[0] = 'n'; break;
161 case mod: line[0] = 'm'; break; 166 case mod: line[0] = 'm'; break;
@@ -366,7 +371,12 @@ static int conf_choice(struct menu *menu)
366 continue; 371 continue;
367 break; 372 break;
368 case set_random: 373 case set_random:
374#ifdef __MINGW32__
375 fprintf(stderr, "set_random not supported\n");
376 exit(1);
377#else
369 def = (random() % cnt) + 1; 378 def = (random() % cnt) + 1;
379#endif
370 case set_default: 380 case set_default:
371 case set_yes: 381 case set_yes:
372 case set_mod: 382 case set_mod:
@@ -522,8 +532,13 @@ int main(int ac, char **av)
522 input_mode = set_yes; 532 input_mode = set_yes;
523 break; 533 break;
524 case 'r': 534 case 'r':
535#ifdef __MINGW32__
536 fprintf(stderr, "set_random not supported\n");
537 exit(1);
538#else
525 input_mode = set_random; 539 input_mode = set_random;
526 srandom(time(NULL)); 540 srandom(time(NULL));
541#endif
527 break; 542 break;
528 case 'h': 543 case 'h':
529 case '?': 544 case '?':
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 8f4ecbd33..1d77aefb7 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -571,15 +571,24 @@ int conf_write(const char *name)
571 fclose(out); 571 fclose(out);
572 if (out_h) { 572 if (out_h) {
573 fclose(out_h); 573 fclose(out_h);
574#ifdef __MINGW32__
575 unlink("include/autoconf.h");
576#endif
574 rename(".tmpconfig.h", "include/autoconf.h"); 577 rename(".tmpconfig.h", "include/autoconf.h");
575 } 578 }
576 if (!name || basename != conf_def_filename) { 579 if (!name || basename != conf_def_filename) {
577 if (!name) 580 if (!name)
578 name = conf_def_filename; 581 name = conf_def_filename;
579 sprintf(tmpname, "%s.old", name); 582 sprintf(tmpname, "%s.old", name);
583#ifdef __MINGW32__
584 unlink(tmpname);
585#endif
580 rename(name, tmpname); 586 rename(name, tmpname);
581 } 587 }
582 sprintf(tmpname, "%s%s", dirname, basename); 588 sprintf(tmpname, "%s%s", dirname, basename);
589#ifdef __MINGW32__
590 unlink(tmpname);
591#endif
583 if (rename(newname, tmpname)) 592 if (rename(newname, tmpname))
584 return 1; 593 return 1;
585 594
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 527f60c99..b88b89d2d 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -11,9 +11,9 @@
11#ifndef KBUILD_NO_NLS 11#ifndef KBUILD_NO_NLS
12# include <libintl.h> 12# include <libintl.h>
13#else 13#else
14# define gettext(Msgid) ((const char *) (Msgid)) 14static inline const char *gettext(const char *txt) { return txt; }
15# define textdomain(Domainname) ((const char *) (Domainname)) 15static inline void textdomain(const char *domainname) {}
16# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) 16static inline void bindtextdomain(const char *name, const char *dir) {}
17#endif 17#endif
18 18
19#ifdef __cplusplus 19#ifdef __cplusplus
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 006d03708..d3ad12d90 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -12,8 +12,10 @@
12/* On Darwin, this may be needed to get SIGWINCH: */ 12/* On Darwin, this may be needed to get SIGWINCH: */
13#define _DARWIN_C_SOURCE 1 13#define _DARWIN_C_SOURCE 1
14 14
15#ifndef __MINGW32__
15#include <sys/ioctl.h> 16#include <sys/ioctl.h>
16#include <sys/wait.h> 17#include <sys/wait.h>
18#endif
17#include <ctype.h> 19#include <ctype.h>
18#include <errno.h> 20#include <errno.h>
19#include <fcntl.h> 21#include <fcntl.h>
@@ -23,7 +25,9 @@
23#include <stdlib.h> 25#include <stdlib.h>
24#include <string.h> 26#include <string.h>
25#include <strings.h> /* for strcasecmp */ 27#include <strings.h> /* for strcasecmp */
28#ifndef __MINGW32__
26#include <termios.h> 29#include <termios.h>
30#endif
27#include <unistd.h> 31#include <unistd.h>
28#include <locale.h> 32#include <locale.h>
29 33
@@ -266,11 +270,15 @@ static char input_buf[4096];
266static const char filename[] = ".config"; 270static const char filename[] = ".config";
267static char *args[1024], **argptr = args; 271static char *args[1024], **argptr = args;
268static int indent; 272static int indent;
273#ifndef __MINGW32__
269static struct termios ios_org; 274static struct termios ios_org;
275#endif
270static int rows = 0, cols = 0; 276static int rows = 0, cols = 0;
271static struct menu *current_menu; 277static struct menu *current_menu;
272static int child_count; 278static int child_count;
279#ifndef __MINGW32__
273static int do_resize; 280static int do_resize;
281#endif
274static int single_menu_mode; 282static int single_menu_mode;
275 283
276static void conf(struct menu *menu); 284static void conf(struct menu *menu);
@@ -290,6 +298,9 @@ static int cprint(const char *fmt, ...);
290 298
291static void init_wsize(void) 299static void init_wsize(void)
292{ 300{
301#ifdef __MINGW32__
302 fprintf(stderr, "Skipping attempt to change window size\n");
303#else
293 struct winsize ws; 304 struct winsize ws;
294 char *env; 305 char *env;
295 306
@@ -321,6 +332,7 @@ static void init_wsize(void)
321 332
322 rows -= 4; 333 rows -= 4;
323 cols -= 5; 334 cols -= 5;
335#endif
324} 336}
325 337
326static void cprint_init(void) 338static void cprint_init(void)
@@ -457,6 +469,10 @@ static void winch_handler(int sig)
457 469
458static int exec_conf(void) 470static int exec_conf(void)
459{ 471{
472#ifdef __MINGW32__
473 fprintf(stderr, "exec_conf not implemented\n");
474 exit(1);
475#else
460 int pipefd[2], stat, size; 476 int pipefd[2], stat, size;
461 sigset_t sset, osset; 477 sigset_t sset, osset;
462 478
@@ -530,6 +546,7 @@ static int exec_conf(void)
530 sigprocmask(SIG_SETMASK, &osset, NULL); 546 sigprocmask(SIG_SETMASK, &osset, NULL);
531 547
532 return WEXITSTATUS(stat); 548 return WEXITSTATUS(stat);
549#endif
533} 550}
534 551
535static void search_conf(void) 552static void search_conf(void)
@@ -783,7 +800,7 @@ static void conf(struct menu *menu)
783 switch (type) { 800 switch (type) {
784 case 'm': 801 case 'm':
785 if (single_menu_mode) 802 if (single_menu_mode)
786 submenu->data = (void *) (long) !submenu->data; 803 submenu->data = (void *) (intptr_t) !submenu->data;
787 else 804 else
788 conf(submenu); 805 conf(submenu);
789 break; 806 break;
@@ -1044,7 +1061,9 @@ static void conf_save(void)
1044 1061
1045static void conf_cleanup(void) 1062static void conf_cleanup(void)
1046{ 1063{
1064#ifndef __MINGW32__
1047 tcsetattr(1, TCSAFLUSH, &ios_org); 1065 tcsetattr(1, TCSAFLUSH, &ios_org);
1066#endif
1048 unlink(".help.tmp"); 1067 unlink(".help.tmp");
1049 unlink("lxdialog.scrltmp"); 1068 unlink("lxdialog.scrltmp");
1050} 1069}
@@ -1073,7 +1092,9 @@ int main(int ac, char **av)
1073 single_menu_mode = 1; 1092 single_menu_mode = 1;
1074 } 1093 }
1075 1094
1095#ifndef __MINGW32__
1076 tcgetattr(1, &ios_org); 1096 tcgetattr(1, &ios_org);
1097#endif
1077 atexit(conf_cleanup); 1098 atexit(conf_cleanup);
1078 init_wsize(); 1099 init_wsize();
1079 conf(&rootmenu); 1100 conf(&rootmenu);
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 3d7877afc..63199cd93 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -6,8 +6,10 @@
6#include <ctype.h> 6#include <ctype.h>
7#include <stdlib.h> 7#include <stdlib.h>
8#include <string.h> 8#include <string.h>
9#ifndef __MINGW32__
9#include <regex.h> 10#include <regex.h>
10#include <sys/utsname.h> 11#include <sys/utsname.h>
12#endif
11 13
12#define LKC_DIRECT_LINK 14#define LKC_DIRECT_LINK
13#include "lkc.h" 15#include "lkc.h"
@@ -44,7 +46,9 @@ void sym_add_default(struct symbol *sym, const char *def)
44void sym_init(void) 46void sym_init(void)
45{ 47{
46 struct symbol *sym; 48 struct symbol *sym;
49#ifndef __MINGW32__
47 struct utsname uts; 50 struct utsname uts;
51#endif
48 char *p; 52 char *p;
49 static bool inited = false; 53 static bool inited = false;
50 54
@@ -52,7 +56,9 @@ void sym_init(void)
52 return; 56 return;
53 inited = true; 57 inited = true;
54 58
59#ifndef __MINGW32__
55 uname(&uts); 60 uname(&uts);
61#endif
56 62
57 sym = sym_lookup("ARCH", 0); 63 sym = sym_lookup("ARCH", 0);
58 sym->type = S_STRING; 64 sym->type = S_STRING;
@@ -71,7 +77,11 @@ void sym_init(void)
71 sym = sym_lookup("UNAME_RELEASE", 0); 77 sym = sym_lookup("UNAME_RELEASE", 0);
72 sym->type = S_STRING; 78 sym->type = S_STRING;
73 sym->flags |= SYMBOL_AUTO; 79 sym->flags |= SYMBOL_AUTO;
80#ifdef __MINGW32__
81 sym_add_default(sym, "UNKNOWN");
82#else
74 sym_add_default(sym, uts.release); 83 sym_add_default(sym, uts.release);
84#endif
75} 85}
76 86
77enum symbol_type sym_get_type(struct symbol *sym) 87enum symbol_type sym_get_type(struct symbol *sym)
@@ -720,6 +730,10 @@ struct symbol *sym_find(const char *name)
720 730
721struct symbol **sym_re_search(const char *pattern) 731struct symbol **sym_re_search(const char *pattern)
722{ 732{
733#ifdef __MINGW32__
734 fprintf(stderr, "NOTIMPL: sym_re_search\n");
735 exit(1);
736#else
723 struct symbol *sym, **sym_arr = NULL; 737 struct symbol *sym, **sym_arr = NULL;
724 int i, cnt, size; 738 int i, cnt, size;
725 regex_t re; 739 regex_t re;
@@ -752,6 +766,7 @@ struct symbol **sym_re_search(const char *pattern)
752 regfree(&re); 766 regfree(&re);
753 767
754 return sym_arr; 768 return sym_arr;
769#endif
755} 770}
756 771
757 772
diff --git a/scripts/kconfig/zconf.hash.c_shipped b/scripts/kconfig/zconf.hash.c_shipped
index 29d9cf6cc..6996aba7f 100644
--- a/scripts/kconfig/zconf.hash.c_shipped
+++ b/scripts/kconfig/zconf.hash.c_shipped
@@ -161,43 +161,43 @@ kconf_id_lookup (register const char *str, register unsigned int len)
161 static struct kconf_id wordlist[] = 161 static struct kconf_id wordlist[] =
162 { 162 {
163 {-1}, {-1}, 163 {-1}, {-1},
164 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM}, 164 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM},
165 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT}, 165 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT},
166 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4, T_HELP, TF_COMMAND}, 166 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4, T_HELP, TF_COMMAND},
167 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, 167 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND},
168 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_SELECT, TF_COMMAND}, 168 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_SELECT, TF_COMMAND},
169 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND}, 169 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND},
170 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE}, 170 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE},
171 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND}, 171 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND},
172 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND}, 172 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_RANGE, TF_COMMAND},
173 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_TYPE, TF_COMMAND, S_STRING}, 173 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11, T_TYPE, TF_COMMAND, S_STRING},
174 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, 174 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN},
175 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, 175 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
176 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_MENU, TF_COMMAND}, 176 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_MENU, TF_COMMAND},
177 {-1}, 177 {-1},
178 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, 178 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_DEFAULT, TF_COMMAND, S_BOOLEAN},
179 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE}, 179 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE},
180 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_MAINMENU, TF_COMMAND}, 180 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_MAINMENU, TF_COMMAND},
181 {-1}, 181 {-1},
182 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20, T_MENUCONFIG, TF_COMMAND}, 182 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20, T_MENUCONFIG, TF_COMMAND},
183 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_CONFIG, TF_COMMAND}, 183 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_CONFIG, TF_COMMAND},
184 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ON, TF_PARAM}, 184 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ON, TF_PARAM},
185 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_HEX}, 185 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_HEX},
186 {-1}, {-1}, 186 {-1}, {-1},
187 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SOURCE, TF_COMMAND}, 187 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SOURCE, TF_COMMAND},
188 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_DEPENDS, TF_COMMAND}, 188 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_DEPENDS, TF_COMMAND},
189 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPTIONAL, TF_COMMAND}, 189 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPTIONAL, TF_COMMAND},
190 {-1}, {-1}, 190 {-1}, {-1},
191 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND}, 191 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND},
192 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, 192 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND},
193 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_REQUIRES, TF_COMMAND}, 193 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_REQUIRES, TF_COMMAND},
194 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34, T_TYPE, TF_COMMAND, S_BOOLEAN}, 194 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str34, T_TYPE, TF_COMMAND, S_BOOLEAN},
195 {-1}, {-1}, 195 {-1}, {-1},
196 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_TYPE, TF_COMMAND, S_BOOLEAN}, 196 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_TYPE, TF_COMMAND, S_BOOLEAN},
197 {-1}, {-1}, {-1}, 197 {-1}, {-1}, {-1},
198 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_CHOICE, TF_COMMAND}, 198 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_CHOICE, TF_COMMAND},
199 {-1}, {-1}, {-1}, {-1}, 199 {-1}, {-1}, {-1}, {-1},
200 {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_PROMPT, TF_COMMAND} 200 {(int)(intptr_t)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_PROMPT, TF_COMMAND}
201 }; 201 };
202 202
203 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) 203 if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index a27d256d6..863f375be 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -143,6 +143,7 @@
143#include <stdarg.h> 143#include <stdarg.h>
144#include <stdio.h> 144#include <stdio.h>
145#include <stdlib.h> 145#include <stdlib.h>
146#include <stdint.h>
146#include <string.h> 147#include <string.h>
147#include <stdbool.h> 148#include <stdbool.h>
148 149
diff --git a/shell/ash.c b/shell/ash.c
index 1deae7c2f..18e53a0da 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -15,6 +15,21 @@
15 * 15 *
16 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 16 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
17 */ 17 */
18
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
18//config:config ASH 33//config:config ASH
19//config: bool "ash (77 kb)" 34//config: bool "ash (77 kb)"
20//config: default y 35//config: default y
@@ -132,6 +147,18 @@
132//config: you to run the specified command or builtin, 147//config: you to run the specified command or builtin,
133//config: even when there is a function with the same name. 148//config: even when there is a function with the same name.
134//config: 149//config:
150//config:
151//config:config ASH_NOCONSOLE
152//config: bool "'noconsole' option"
153//config: default y
154//config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32
155//config: help
156//config: Enable support for the 'noconsole' option, which attempts to
157//config: hide the console normally associated with a command line
158//config: application. This may be useful when running a shell script
159//config: from a GUI application. Disable this if your platform doesn't
160//config: support the required APIs.
161//config:
135//config:endif # ash options 162//config:endif # ash options
136 163
137//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) 164//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
@@ -240,10 +267,58 @@ typedef long arith_t;
240# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 267# define PIPE_BUF 4096 /* amount of buffering in a pipe */
241#endif 268#endif
242 269
270#if !ENABLE_PLATFORM_MINGW32
271# define is_absolute_path(path) ((path)[0] == '/')
272#endif
273
243#if !BB_MMU 274#if !BB_MMU
244# error "Do not even bother, ash will not run on NOMMU machine" 275# error "Do not even bother, ash will not run on NOMMU machine"
245#endif 276#endif
246 277
278#if ENABLE_PLATFORM_MINGW32
279union node;
280struct strlist;
281struct job;
282
283struct forkshell {
284 /* filled by forkshell_copy() */
285 struct globals_var *gvp;
286 struct globals_misc *gmp;
287 struct tblentry **cmdtable;
288 /* struct alias **atab; */
289 /* struct parsefile *g_parsefile; */
290 HANDLE hMapFile;
291 void *old_base;
292 int nodeptr_offset;
293 int size;
294
295 /* type of forkshell */
296 int fpid;
297
298 /* optional data, used by forkshell_child */
299 int flags;
300 int fd[10];
301 union node *n;
302 char **argv;
303 char *string;
304 struct strlist *strlist;
305};
306
307enum {
308 FS_OPENHERE,
309 FS_EVALBACKCMD,
310 FS_EVALSUBSHELL,
311 FS_EVALPIPE,
312 FS_SHELLEXEC
313};
314
315static struct forkshell* forkshell_prepare(struct forkshell *fs);
316static void forkshell_init(const char *idstr);
317static void forkshell_child(struct forkshell *fs);
318static void sticky_free(void *p);
319#define free(p) sticky_free(p)
320static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
321#endif
247 322
248/* ============ Hash table sizes. Configurable. */ 323/* ============ Hash table sizes. Configurable. */
249 324
@@ -276,6 +351,12 @@ static const char *const optletters_optnames[] = {
276 ,"\0" "nolog" 351 ,"\0" "nolog"
277 ,"\0" "debug" 352 ,"\0" "debug"
278#endif 353#endif
354#if ENABLE_PLATFORM_MINGW32
355 ,"X" "winxp"
356#endif
357#if ENABLE_ASH_NOCONSOLE
358 ,"\0" "noconsole"
359#endif
279}; 360};
280 361
281#define optletters(n) optletters_optnames[n][0] 362#define optletters(n) optletters_optnames[n][0]
@@ -354,6 +435,12 @@ struct globals_misc {
354# define nolog optlist[14 + BASH_PIPEFAIL] 435# define nolog optlist[14 + BASH_PIPEFAIL]
355# define debug optlist[15 + BASH_PIPEFAIL] 436# define debug optlist[15 + BASH_PIPEFAIL]
356#endif 437#endif
438#if ENABLE_PLATFORM_MINGW32
439# define winxp optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
440#endif
441#if ENABLE_ASH_NOCONSOLE
442# define noconsole optlist[15 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
443#endif
357 444
358 /* trap handler commands */ 445 /* trap handler commands */
359 /* 446 /*
@@ -2434,10 +2521,22 @@ path_advance(const char **path, const char *name)
2434 if (*path == NULL) 2521 if (*path == NULL)
2435 return NULL; 2522 return NULL;
2436 start = *path; 2523 start = *path;
2524#if ENABLE_PLATFORM_MINGW32
2525 p = next_path_sep(start);
2526 q = strchr(start, '%');
2527 if ((p && q && q < p) || (!p && q))
2528 p = q;
2529 if (!p)
2530 for (p = start; *p; p++)
2531 continue;
2532#else
2437 for (p = start; *p && *p != ':' && *p != '%'; p++) 2533 for (p = start; *p && *p != ':' && *p != '%'; p++)
2438 continue; 2534 continue;
2535#endif
2439 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2536 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2440 while (stackblocksize() < len) 2537
2538 /* preserve space for .exe too */
2539 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2441 growstackblock(); 2540 growstackblock();
2442 q = stackblock(); 2541 q = stackblock();
2443 if (p != start) { 2542 if (p != start) {
@@ -2448,10 +2547,19 @@ path_advance(const char **path, const char *name)
2448 pathopt = NULL; 2547 pathopt = NULL;
2449 if (*p == '%') { 2548 if (*p == '%') {
2450 pathopt = ++p; 2549 pathopt = ++p;
2550#if ENABLE_PLATFORM_MINGW32
2551 p = next_path_sep(start);
2552
2553 /* *p != ':' and '*' would suffice */
2554 if (!p)
2555 p = pathopt - 1;
2556#else
2451 while (*p && *p != ':') 2557 while (*p && *p != ':')
2452 p++; 2558 p++;
2559#endif
2453 } 2560 }
2454 if (*p == ':') 2561 if (*p == ':' ||
2562 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2455 *path = p + 1; 2563 *path = p + 1;
2456 else 2564 else
2457 *path = NULL; 2565 *path = NULL;
@@ -2560,6 +2668,106 @@ cdopt(void)
2560static const char * 2668static const char *
2561updatepwd(const char *dir) 2669updatepwd(const char *dir)
2562{ 2670{
2671#if ENABLE_PLATFORM_MINGW32
2672#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2673#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1]))
2674 /*
2675 * Due to Windows drive notion, getting pwd is a completely
2676 * different thing. Handle it in a separate routine
2677 */
2678
2679 char *new;
2680 char *p;
2681 char *cdcomppath;
2682 const char *lim;
2683 /*
2684 * There are five cases that make some kind of sense
2685 * absdrive + abspath: c:/path
2686 * absdrive + !abspath: c:path
2687 * !absdrive + abspath: /path
2688 * !absdrive + uncpath: //host/share
2689 * !absdrive + !abspath: path
2690 *
2691 * Damn DOS!
2692 * c:path behaviour is "undefined"
2693 * To properly handle this case, I have to keep track of cwd
2694 * of every drive, which is too painful to do.
2695 * So when c:path is given, I assume it's c:${curdir}path
2696 * with ${curdir} comes from the current drive
2697 */
2698 int absdrive = *dir && dir[1] == ':';
2699 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2700
2701 cdcomppath = sstrdup(dir);
2702 STARTSTACKSTR(new);
2703 if (!absdrive && curdir == nullstr)
2704 return 0;
2705 if (!abspath) {
2706 if (curdir == nullstr)
2707 return 0;
2708 new = stack_putstr(curdir, new);
2709 }
2710 new = makestrspace(strlen(dir) + 2, new);
2711
2712 if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) {
2713 lim = (char *)stackblock() + 1;
2714 }
2715 else {
2716 char *drive = stackblock();
2717 if (absdrive) {
2718 *drive = *dir;
2719 cdcomppath += 2;
2720 dir += 2;
2721 } else {
2722 *drive = *curdir;
2723 }
2724 drive[1] = ':'; /* in case of absolute drive+path */
2725
2726 if (abspath)
2727 new = drive + 2;
2728 lim = drive + 3;
2729 }
2730
2731 if (!abspath) {
2732 if (!is_path_sep(new[-1]))
2733 USTPUTC('/', new);
2734 if (new > lim && is_path_sep(*lim))
2735 lim++;
2736 } else {
2737 USTPUTC('/', new);
2738 cdcomppath ++;
2739 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2740 USTPUTC('/', new);
2741 cdcomppath++;
2742 lim++;
2743 }
2744 }
2745 p = strtok(cdcomppath, "/\\");
2746 while (p) {
2747 switch (*p) {
2748 case '.':
2749 if (p[1] == '.' && p[2] == '\0') {
2750 while (new > lim) {
2751 STUNPUTC(new);
2752 if (is_path_sep(new[-1]))
2753 break;
2754 }
2755 break;
2756 }
2757 if (p[1] == '\0')
2758 break;
2759 /* fall through */
2760 default:
2761 new = stack_putstr(p, new);
2762 USTPUTC('/', new);
2763 }
2764 p = strtok(0, "/\\");
2765 }
2766 if (new > lim)
2767 STUNPUTC(new);
2768 *new = 0;
2769 return stackblock();
2770#else
2563 char *new; 2771 char *new;
2564 char *p; 2772 char *p;
2565 char *cdcomppath; 2773 char *cdcomppath;
@@ -2613,6 +2821,7 @@ updatepwd(const char *dir)
2613 STUNPUTC(new); 2821 STUNPUTC(new);
2614 *new = 0; 2822 *new = 0;
2615 return stackblock(); 2823 return stackblock();
2824#endif
2616} 2825}
2617 2826
2618/* 2827/*
@@ -2707,7 +2916,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2707 } 2916 }
2708 if (!dest) 2917 if (!dest)
2709 dest = nullstr; 2918 dest = nullstr;
2710 if (*dest == '/') 2919 if (is_absolute_path(dest))
2711 goto step6; 2920 goto step6;
2712 if (*dest == '.') { 2921 if (*dest == '.') {
2713 c = dest[1]; 2922 c = dest[1];
@@ -3409,6 +3618,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3409 */ 3618 */
3410struct procstat { 3619struct procstat {
3411 pid_t ps_pid; /* process id */ 3620 pid_t ps_pid; /* process id */
3621#if ENABLE_PLATFORM_MINGW32
3622 HANDLE ps_proc;
3623#endif
3412 int ps_status; /* last process status from wait() */ 3624 int ps_status; /* last process status from wait() */
3413 char *ps_cmd; /* text of command being run */ 3625 char *ps_cmd; /* text of command being run */
3414}; 3626};
@@ -3437,7 +3649,9 @@ struct job {
3437}; 3649};
3438 3650
3439static struct job *makejob(/*union node *,*/ int); 3651static struct job *makejob(/*union node *,*/ int);
3652#if !ENABLE_PLATFORM_MINGW32
3440static int forkshell(struct job *, union node *, int); 3653static int forkshell(struct job *, union node *, int);
3654#endif
3441static int waitforjob(struct job *); 3655static int waitforjob(struct job *);
3442 3656
3443#if !JOBS 3657#if !JOBS
@@ -3462,6 +3676,7 @@ ignoresig(int signo)
3462 sigmode[signo - 1] = S_HARD_IGN; 3676 sigmode[signo - 1] = S_HARD_IGN;
3463} 3677}
3464 3678
3679#if !ENABLE_PLATFORM_MINGW32
3465/* 3680/*
3466 * Only one usage site - in setsignal() 3681 * Only one usage site - in setsignal()
3467 */ 3682 */
@@ -3586,6 +3801,9 @@ setsignal(int signo)
3586 3801
3587 *t = new_act; 3802 *t = new_act;
3588} 3803}
3804#else
3805#define setsignal(s)
3806#endif
3589 3807
3590/* mode flags for set_curjob */ 3808/* mode flags for set_curjob */
3591#define CUR_DELETE 2 3809#define CUR_DELETE 2
@@ -4083,6 +4301,98 @@ sprint_status48(char *s, int status, int sigonly)
4083 return col; 4301 return col;
4084} 4302}
4085 4303
4304#if ENABLE_PLATFORM_MINGW32
4305
4306HANDLE hSIGINT; /* Ctrl-C is pressed */
4307
4308static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4309{
4310 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4311 SetEvent(hSIGINT);
4312 pending_int = 1;
4313 return TRUE;
4314 }
4315 return FALSE;
4316}
4317
4318/*
4319 * Windows does not know about parent-child relationship
4320 * They don't support waitpid(-1)
4321 */
4322static pid_t
4323waitpid_child(int *status, int wait_flags)
4324{
4325 pid_t *pidlist;
4326 HANDLE *proclist;
4327 int pid_nr = 0;
4328 pid_t pid;
4329 DWORD win_status, idx;
4330 struct job *jb;
4331
4332 for (jb = curjob; jb; jb = jb->prev_job) {
4333 if (jb->state != JOBDONE)
4334 pid_nr += jb->nprocs;
4335 }
4336 if ( pid_nr++ == 0 )
4337 return -1;
4338
4339 pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4340 proclist = ckmalloc(sizeof(*proclist)*pid_nr);
4341
4342 pidlist[0] = -1;
4343 proclist[0] = hSIGINT;
4344 pid_nr = 1;
4345 for (jb = curjob; jb; jb = jb->prev_job) {
4346 struct procstat *ps, *psend;
4347 if (jb->state == JOBDONE)
4348 continue;
4349 ps = jb->ps;
4350 psend = ps + jb->nprocs;
4351 while (ps < psend) {
4352 if (ps->ps_pid != -1 && ps->ps_proc != NULL) {
4353 pidlist[pid_nr] = ps->ps_pid;
4354 proclist[pid_nr++] = ps->ps_proc;
4355 }
4356 ps++;
4357 }
4358 }
4359
4360 if (pid_nr == 1) {
4361 free(pidlist);
4362 free(proclist);
4363 return -1;
4364 }
4365
4366 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE,
4367 wait_flags|WNOHANG ? 1 : INFINITE);
4368 if (idx >= pid_nr) {
4369 free(pidlist);
4370 free(proclist);
4371 return -1;
4372 }
4373 if (!idx) { /* hSIGINT */
4374 int i;
4375 ResetEvent(hSIGINT);
4376 for (i = 1; i < pid_nr; i++)
4377 TerminateProcess(proclist[i], 1);
4378 pid = pidlist[1];
4379 free(pidlist);
4380 free(proclist);
4381 *status = 260; /* terminated by a signal */
4382 return pid;
4383 }
4384 GetExitCodeProcess(proclist[idx], &win_status);
4385 pid = pidlist[idx];
4386 free(pidlist);
4387 free(proclist);
4388 *status = (int)win_status;
4389 return pid;
4390}
4391#define waitpid(p, s, f) waitpid_child(s, f)
4392#define wait_block_or_sig(s) waitpid_child(s, 0)
4393
4394#else
4395
4086static int 4396static int
4087wait_block_or_sig(int *status) 4397wait_block_or_sig(int *status)
4088{ 4398{
@@ -4115,6 +4425,7 @@ wait_block_or_sig(int *status)
4115 4425
4116 return pid; 4426 return pid;
4117} 4427}
4428#endif
4118 4429
4119#define DOWAIT_NONBLOCK 0 4430#define DOWAIT_NONBLOCK 0
4120#define DOWAIT_BLOCK 1 4431#define DOWAIT_BLOCK 1
@@ -4183,6 +4494,11 @@ dowait(int block, struct job *job)
4183 jobno(jp), pid, ps->ps_status, status)); 4494 jobno(jp), pid, ps->ps_status, status));
4184 ps->ps_status = status; 4495 ps->ps_status = status;
4185 thisjob = jp; 4496 thisjob = jp;
4497#if ENABLE_PLATFORM_MINGW32
4498 ps->ps_pid = -1;
4499 CloseHandle(ps->ps_proc);
4500 ps->ps_proc = NULL;
4501#endif
4186 } 4502 }
4187 if (ps->ps_status == -1) 4503 if (ps->ps_status == -1)
4188 jobstate = JOBRUNNING; 4504 jobstate = JOBRUNNING;
@@ -4865,6 +5181,7 @@ commandtext(union node *n)
4865 * 5181 *
4866 * Called with interrupts off. 5182 * Called with interrupts off.
4867 */ 5183 */
5184#if !ENABLE_PLATFORM_MINGW32
4868/* 5185/*
4869 * Clear traps on a fork. 5186 * Clear traps on a fork.
4870 */ 5187 */
@@ -5014,16 +5331,24 @@ forkchild(struct job *jp, union node *n, int mode)
5014 freejob(jp); 5331 freejob(jp);
5015 jobless = 0; 5332 jobless = 0;
5016} 5333}
5334#endif
5017 5335
5018/* Called after fork(), in parent */ 5336/* Called after fork(), in parent */
5019#if !JOBS 5337#if !JOBS
5020#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) 5338#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
5021#endif 5339#endif
5022static void 5340static void
5341#if !ENABLE_PLATFORM_MINGW32
5023forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5342forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5343#else
5344forkparent(struct job *jp, union node *n, int mode, HANDLE proc)
5345#endif
5024{ 5346{
5347#if ENABLE_PLATFORM_MINGW32
5348 pid_t pid = GetProcessId(proc);
5349#endif
5025 TRACE(("In parent shell: child = %d\n", pid)); 5350 TRACE(("In parent shell: child = %d\n", pid));
5026 if (!jp) { 5351 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
5027 /* jp is NULL when called by openhere() for heredoc support */ 5352 /* jp is NULL when called by openhere() for heredoc support */
5028 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5353 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
5029 continue; 5354 continue;
@@ -5049,6 +5374,9 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5049 if (jp) { 5374 if (jp) {
5050 struct procstat *ps = &jp->ps[jp->nprocs++]; 5375 struct procstat *ps = &jp->ps[jp->nprocs++];
5051 ps->ps_pid = pid; 5376 ps->ps_pid = pid;
5377#if ENABLE_PLATFORM_MINGW32
5378 ps->ps_proc = proc;
5379#endif
5052 ps->ps_status = -1; 5380 ps->ps_status = -1;
5053 ps->ps_cmd = nullstr; 5381 ps->ps_cmd = nullstr;
5054#if JOBS 5382#if JOBS
@@ -5058,6 +5386,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5058 } 5386 }
5059} 5387}
5060 5388
5389#if !ENABLE_PLATFORM_MINGW32
5061/* jp and n are NULL when called by openhere() for heredoc support */ 5390/* jp and n are NULL when called by openhere() for heredoc support */
5062static int 5391static int
5063forkshell(struct job *jp, union node *n, int mode) 5392forkshell(struct job *jp, union node *n, int mode)
@@ -5080,6 +5409,7 @@ forkshell(struct job *jp, union node *n, int mode)
5080 } 5409 }
5081 return pid; 5410 return pid;
5082} 5411}
5412#endif
5083 5413
5084/* 5414/*
5085 * Wait for job to finish. 5415 * Wait for job to finish.
@@ -5211,6 +5541,7 @@ openhere(union node *redir)
5211{ 5541{
5212 int pip[2]; 5542 int pip[2];
5213 size_t len = 0; 5543 size_t len = 0;
5544 IF_PLATFORM_MINGW32(struct forkshell fs);
5214 5545
5215 if (pipe(pip) < 0) 5546 if (pipe(pip) < 0)
5216 ash_msg_and_raise_error("pipe call failed"); 5547 ash_msg_and_raise_error("pipe call failed");
@@ -5221,6 +5552,15 @@ openhere(union node *redir)
5221 goto out; 5552 goto out;
5222 } 5553 }
5223 } 5554 }
5555#if ENABLE_PLATFORM_MINGW32
5556 memset(&fs, 0, sizeof(fs));
5557 fs.fpid = FS_OPENHERE;
5558 fs.n = redir;
5559 fs.fd[0] = pip[0];
5560 fs.fd[1] = pip[1];
5561 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5562 ash_msg_and_raise_error("unable to spawn shell");
5563#else
5224 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5564 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5225 /* child */ 5565 /* child */
5226 close(pip[0]); 5566 close(pip[0]);
@@ -5235,6 +5575,7 @@ openhere(union node *redir)
5235 expandhere(redir->nhere.doc, pip[1]); 5575 expandhere(redir->nhere.doc, pip[1]);
5236 _exit(EXIT_SUCCESS); 5576 _exit(EXIT_SUCCESS);
5237 } 5577 }
5578#endif
5238 out: 5579 out:
5239 close(pip[1]); 5580 close(pip[1]);
5240 return pip[0]; 5581 return pip[0];
@@ -5261,6 +5602,31 @@ openredirect(union node *redir)
5261 * allocated space. Do it only when we know it is safe. 5602 * allocated space. Do it only when we know it is safe.
5262 */ 5603 */
5263 fname = redir->nfile.expfname; 5604 fname = redir->nfile.expfname;
5605#if ENABLE_PLATFORM_MINGW32
5606 /* Support for /dev/null */
5607 switch (redir->nfile.type) {
5608 case NFROM:
5609 if (!strcmp(fname, "/dev/null"))
5610 return open("nul",O_RDWR);
5611 if (!strncmp(fname, "/dev/", 5)) {
5612 ash_msg("Unhandled device %s\n", fname);
5613 return -1;
5614 }
5615 break;
5616
5617 case NFROMTO:
5618 case NTO:
5619 case NCLOBBER:
5620 case NAPPEND:
5621 if (!strcmp(fname, "/dev/null"))
5622 return open("nul",O_RDWR);
5623 if (!strncmp(fname, "/dev/", 5)) {
5624 ash_msg("Unhandled device %s\n", fname);
5625 return -1;
5626 }
5627 break;
5628 }
5629#endif
5264 5630
5265 switch (redir->nfile.type) { 5631 switch (redir->nfile.type) {
5266 default: 5632 default:
@@ -5312,6 +5678,9 @@ openredirect(union node *redir)
5312 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5678 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5313 if (f < 0) 5679 if (f < 0)
5314 goto ecreate; 5680 goto ecreate;
5681#if ENABLE_PLATFORM_MINGW32
5682 lseek(f, 0, SEEK_END);
5683#endif
5315 break; 5684 break;
5316 } 5685 }
5317 5686
@@ -6240,6 +6609,7 @@ struct backcmd { /* result of evalbackcmd */
6240 int fd; /* file descriptor to read from */ 6609 int fd; /* file descriptor to read from */
6241 int nleft; /* number of chars in buffer */ 6610 int nleft; /* number of chars in buffer */
6242 char *buf; /* buffer */ 6611 char *buf; /* buffer */
6612 IF_PLATFORM_MINGW32(struct forkshell fs);
6243 struct job *jp; /* job structure for command */ 6613 struct job *jp; /* job structure for command */
6244}; 6614};
6245 6615
@@ -6271,6 +6641,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6271 result->fd = -1; 6641 result->fd = -1;
6272 result->buf = NULL; 6642 result->buf = NULL;
6273 result->nleft = 0; 6643 result->nleft = 0;
6644 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
6274 result->jp = NULL; 6645 result->jp = NULL;
6275 if (n == NULL) { 6646 if (n == NULL) {
6276 goto out; 6647 goto out;
@@ -6279,6 +6650,14 @@ evalbackcmd(union node *n, struct backcmd *result)
6279 if (pipe(pip) < 0) 6650 if (pipe(pip) < 0)
6280 ash_msg_and_raise_error("pipe call failed"); 6651 ash_msg_and_raise_error("pipe call failed");
6281 jp = makejob(/*n,*/ 1); 6652 jp = makejob(/*n,*/ 1);
6653#if ENABLE_PLATFORM_MINGW32
6654 result->fs.fpid = FS_EVALBACKCMD;
6655 result->fs.n = n;
6656 result->fs.fd[0] = pip[0];
6657 result->fs.fd[1] = pip[1];
6658 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6659 ash_msg_and_raise_error("unable to spawn shell");
6660#else
6282 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6661 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6283 /* child */ 6662 /* child */
6284 FORCE_INT_ON; 6663 FORCE_INT_ON;
@@ -6301,6 +6680,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6301 evaltreenr(n, EV_EXIT); 6680 evaltreenr(n, EV_EXIT);
6302 /* NOTREACHED */ 6681 /* NOTREACHED */
6303 } 6682 }
6683#endif
6304 /* parent */ 6684 /* parent */
6305 close(pip[1]); 6685 close(pip[1]);
6306 result->fd = pip[0]; 6686 result->fd = pip[0];
@@ -6357,7 +6737,8 @@ expbackq(union node *cmd, int flag)
6357 6737
6358 /* Eat all trailing newlines */ 6738 /* Eat all trailing newlines */
6359 dest = expdest; 6739 dest = expdest;
6360 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6740 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6741 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
6361 STUNPUTC(dest); 6742 STUNPUTC(dest);
6362 expdest = dest; 6743 expdest = dest;
6363 6744
@@ -7856,7 +8237,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
7856 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ 8237 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7857 8238
7858 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 8239 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7859 if (strchr(prog, '/') != NULL 8240 if ((strchr(prog, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(prog, '\\')))
7860#if ENABLE_FEATURE_SH_STANDALONE 8241#if ENABLE_FEATURE_SH_STANDALONE
7861 || (applet_no = find_applet_by_name(prog)) >= 0 8242 || (applet_no = find_applet_by_name(prog)) >= 0
7862#endif 8243#endif
@@ -8440,10 +8821,14 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8440#endif 8821#endif
8441 8822
8442 8823
8443/*static int funcblocksize; // size of structures in function */ 8824static int funcblocksize; /* size of structures in function */
8444/*static int funcstringsize; // size of strings in node */ 8825static int funcstringsize; /* size of strings in node */
8445static void *funcblock; /* block to allocate function from */ 8826static void *funcblock; /* block to allocate function from */
8446static char *funcstring_end; /* end of block to allocate strings from */ 8827static char *funcstring; /* block to allocate strings from */
8828#if ENABLE_PLATFORM_MINGW32
8829static int nodeptrsize;
8830static char **nodeptr;
8831#endif
8447 8832
8448static const uint8_t nodesize[N_NUMBER] ALIGN1 = { 8833static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8449 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)), 8834 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
@@ -8477,72 +8862,81 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8477 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), 8862 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8478}; 8863};
8479 8864
8480static int calcsize(int funcblocksize, union node *n); 8865static void calcsize(union node *n);
8481 8866
8482static int 8867static void
8483sizenodelist(int funcblocksize, struct nodelist *lp) 8868sizenodelist(struct nodelist *lp)
8484{ 8869{
8485 while (lp) { 8870 while (lp) {
8486 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8871 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8487 funcblocksize = calcsize(funcblocksize, lp->n); 8872 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8873 calcsize(lp->n);
8488 lp = lp->next; 8874 lp = lp->next;
8489 } 8875 }
8490 return funcblocksize;
8491} 8876}
8492 8877
8493static int 8878static void
8494calcsize(int funcblocksize, union node *n) 8879calcsize(union node *n)
8495{ 8880{
8496 if (n == NULL) 8881 if (n == NULL)
8497 return funcblocksize; 8882 return;
8498 funcblocksize += nodesize[n->type]; 8883 funcblocksize += nodesize[n->type];
8499 switch (n->type) { 8884 switch (n->type) {
8500 case NCMD: 8885 case NCMD:
8501 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect); 8886 calcsize(n->ncmd.redirect);
8502 funcblocksize = calcsize(funcblocksize, n->ncmd.args); 8887 calcsize(n->ncmd.args);
8503 funcblocksize = calcsize(funcblocksize, n->ncmd.assign); 8888 calcsize(n->ncmd.assign);
8889 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8504 break; 8890 break;
8505 case NPIPE: 8891 case NPIPE:
8506 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist); 8892 sizenodelist(n->npipe.cmdlist);
8893 IF_PLATFORM_MINGW32(nodeptrsize++);
8507 break; 8894 break;
8508 case NREDIR: 8895 case NREDIR:
8509 case NBACKGND: 8896 case NBACKGND:
8510 case NSUBSHELL: 8897 case NSUBSHELL:
8511 funcblocksize = calcsize(funcblocksize, n->nredir.redirect); 8898 calcsize(n->nredir.redirect);
8512 funcblocksize = calcsize(funcblocksize, n->nredir.n); 8899 calcsize(n->nredir.n);
8900 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8513 break; 8901 break;
8514 case NAND: 8902 case NAND:
8515 case NOR: 8903 case NOR:
8516 case NSEMI: 8904 case NSEMI:
8517 case NWHILE: 8905 case NWHILE:
8518 case NUNTIL: 8906 case NUNTIL:
8519 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2); 8907 calcsize(n->nbinary.ch2);
8520 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1); 8908 calcsize(n->nbinary.ch1);
8909 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8521 break; 8910 break;
8522 case NIF: 8911 case NIF:
8523 funcblocksize = calcsize(funcblocksize, n->nif.elsepart); 8912 calcsize(n->nif.elsepart);
8524 funcblocksize = calcsize(funcblocksize, n->nif.ifpart); 8913 calcsize(n->nif.ifpart);
8525 funcblocksize = calcsize(funcblocksize, n->nif.test); 8914 calcsize(n->nif.test);
8915 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8526 break; 8916 break;
8527 case NFOR: 8917 case NFOR:
8528 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */ 8918 funcstringsize += strlen(n->nfor.var) + 1;
8529 funcblocksize = calcsize(funcblocksize, n->nfor.body); 8919 calcsize(n->nfor.body);
8530 funcblocksize = calcsize(funcblocksize, n->nfor.args); 8920 calcsize(n->nfor.args);
8921 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8531 break; 8922 break;
8532 case NCASE: 8923 case NCASE:
8533 funcblocksize = calcsize(funcblocksize, n->ncase.cases); 8924 calcsize(n->ncase.cases);
8534 funcblocksize = calcsize(funcblocksize, n->ncase.expr); 8925 calcsize(n->ncase.expr);
8926 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8535 break; 8927 break;
8536 case NCLIST: 8928 case NCLIST:
8537 funcblocksize = calcsize(funcblocksize, n->nclist.body); 8929 calcsize(n->nclist.body);
8538 funcblocksize = calcsize(funcblocksize, n->nclist.pattern); 8930 calcsize(n->nclist.pattern);
8539 funcblocksize = calcsize(funcblocksize, n->nclist.next); 8931 calcsize(n->nclist.next);
8932 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8540 break; 8933 break;
8541 case NDEFUN: 8934 case NDEFUN:
8542 case NARG: 8935 case NARG:
8543 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); 8936 sizenodelist(n->narg.backquote);
8544 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ 8937 funcstringsize += strlen(n->narg.text) + 1;
8545 funcblocksize = calcsize(funcblocksize, n->narg.next); 8938 calcsize(n->narg.next);
8939 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8546 break; 8940 break;
8547 case NTO: 8941 case NTO:
8548#if BASH_REDIR_OUTPUT 8942#if BASH_REDIR_OUTPUT
@@ -8552,35 +8946,55 @@ calcsize(int funcblocksize, union node *n)
8552 case NFROM: 8946 case NFROM:
8553 case NFROMTO: 8947 case NFROMTO:
8554 case NAPPEND: 8948 case NAPPEND:
8555 funcblocksize = calcsize(funcblocksize, n->nfile.fname); 8949 calcsize(n->nfile.fname);
8556 funcblocksize = calcsize(funcblocksize, n->nfile.next); 8950 calcsize(n->nfile.next);
8951 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8557 break; 8952 break;
8558 case NTOFD: 8953 case NTOFD:
8559 case NFROMFD: 8954 case NFROMFD:
8560 funcblocksize = calcsize(funcblocksize, n->ndup.vname); 8955 calcsize(n->ndup.vname);
8561 funcblocksize = calcsize(funcblocksize, n->ndup.next); 8956 calcsize(n->ndup.next);
8957 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8562 break; 8958 break;
8563 case NHERE: 8959 case NHERE:
8564 case NXHERE: 8960 case NXHERE:
8565 funcblocksize = calcsize(funcblocksize, n->nhere.doc); 8961 calcsize(n->nhere.doc);
8566 funcblocksize = calcsize(funcblocksize, n->nhere.next); 8962 calcsize(n->nhere.next);
8963 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8567 break; 8964 break;
8568 case NNOT: 8965 case NNOT:
8569 funcblocksize = calcsize(funcblocksize, n->nnot.com); 8966 calcsize(n->nnot.com);
8967 IF_PLATFORM_MINGW32(nodeptrsize++);
8570 break; 8968 break;
8571 }; 8969 };
8572 return funcblocksize;
8573} 8970}
8574 8971
8575static char * 8972static char *
8576nodeckstrdup(char *s) 8973nodeckstrdup(const char *s)
8577{ 8974{
8578 funcstring_end -= SHELL_ALIGN(strlen(s) + 1); 8975 char *rtn = funcstring;
8579 return strcpy(funcstring_end, s); 8976
8977 if (!s)
8978 return NULL;
8979 strcpy(funcstring, s);
8980 funcstring += strlen(s) + 1;
8981 return rtn;
8580} 8982}
8581 8983
8582static union node *copynode(union node *); 8984static union node *copynode(union node *);
8583 8985
8986#if ENABLE_PLATFORM_MINGW32
8987# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char *)&(dst);}
8988# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);}}
8989# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);}}
8990# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);*nodeptr++ = (char *)&(dst4);}}
8991#else
8992# define SAVE_PTR(dst)
8993# define SAVE_PTR2(dst,dst2)
8994# define SAVE_PTR3(dst,dst2,dst3)
8995# define SAVE_PTR4(dst,dst2,dst3,dst4)
8996#endif
8997
8584static struct nodelist * 8998static struct nodelist *
8585copynodelist(struct nodelist *lp) 8999copynodelist(struct nodelist *lp)
8586{ 9000{
@@ -8592,6 +9006,7 @@ copynodelist(struct nodelist *lp)
8592 *lpp = funcblock; 9006 *lpp = funcblock;
8593 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 9007 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8594 (*lpp)->n = copynode(lp->n); 9008 (*lpp)->n = copynode(lp->n);
9009 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8595 lp = lp->next; 9010 lp = lp->next;
8596 lpp = &(*lpp)->next; 9011 lpp = &(*lpp)->next;
8597 } 9012 }
@@ -8614,16 +9029,19 @@ copynode(union node *n)
8614 new->ncmd.redirect = copynode(n->ncmd.redirect); 9029 new->ncmd.redirect = copynode(n->ncmd.redirect);
8615 new->ncmd.args = copynode(n->ncmd.args); 9030 new->ncmd.args = copynode(n->ncmd.args);
8616 new->ncmd.assign = copynode(n->ncmd.assign); 9031 new->ncmd.assign = copynode(n->ncmd.assign);
9032 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8617 break; 9033 break;
8618 case NPIPE: 9034 case NPIPE:
8619 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 9035 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8620 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 9036 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
9037 SAVE_PTR(new->npipe.cmdlist);
8621 break; 9038 break;
8622 case NREDIR: 9039 case NREDIR:
8623 case NBACKGND: 9040 case NBACKGND:
8624 case NSUBSHELL: 9041 case NSUBSHELL:
8625 new->nredir.redirect = copynode(n->nredir.redirect); 9042 new->nredir.redirect = copynode(n->nredir.redirect);
8626 new->nredir.n = copynode(n->nredir.n); 9043 new->nredir.n = copynode(n->nredir.n);
9044 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8627 break; 9045 break;
8628 case NAND: 9046 case NAND:
8629 case NOR: 9047 case NOR:
@@ -8632,31 +9050,37 @@ copynode(union node *n)
8632 case NUNTIL: 9050 case NUNTIL:
8633 new->nbinary.ch2 = copynode(n->nbinary.ch2); 9051 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8634 new->nbinary.ch1 = copynode(n->nbinary.ch1); 9052 new->nbinary.ch1 = copynode(n->nbinary.ch1);
9053 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8635 break; 9054 break;
8636 case NIF: 9055 case NIF:
8637 new->nif.elsepart = copynode(n->nif.elsepart); 9056 new->nif.elsepart = copynode(n->nif.elsepart);
8638 new->nif.ifpart = copynode(n->nif.ifpart); 9057 new->nif.ifpart = copynode(n->nif.ifpart);
8639 new->nif.test = copynode(n->nif.test); 9058 new->nif.test = copynode(n->nif.test);
9059 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8640 break; 9060 break;
8641 case NFOR: 9061 case NFOR:
8642 new->nfor.var = nodeckstrdup(n->nfor.var); 9062 new->nfor.var = nodeckstrdup(n->nfor.var);
8643 new->nfor.body = copynode(n->nfor.body); 9063 new->nfor.body = copynode(n->nfor.body);
8644 new->nfor.args = copynode(n->nfor.args); 9064 new->nfor.args = copynode(n->nfor.args);
9065 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8645 break; 9066 break;
8646 case NCASE: 9067 case NCASE:
8647 new->ncase.cases = copynode(n->ncase.cases); 9068 new->ncase.cases = copynode(n->ncase.cases);
8648 new->ncase.expr = copynode(n->ncase.expr); 9069 new->ncase.expr = copynode(n->ncase.expr);
9070 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8649 break; 9071 break;
8650 case NCLIST: 9072 case NCLIST:
8651 new->nclist.body = copynode(n->nclist.body); 9073 new->nclist.body = copynode(n->nclist.body);
8652 new->nclist.pattern = copynode(n->nclist.pattern); 9074 new->nclist.pattern = copynode(n->nclist.pattern);
8653 new->nclist.next = copynode(n->nclist.next); 9075 new->nclist.next = copynode(n->nclist.next);
9076 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8654 break; 9077 break;
8655 case NDEFUN: 9078 case NDEFUN:
8656 case NARG: 9079 case NARG:
8657 new->narg.backquote = copynodelist(n->narg.backquote); 9080 new->narg.backquote = copynodelist(n->narg.backquote);
8658 new->narg.text = nodeckstrdup(n->narg.text); 9081 new->narg.text = nodeckstrdup(n->narg.text);
8659 new->narg.next = copynode(n->narg.next); 9082 new->narg.next = copynode(n->narg.next);
9083 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8660 break; 9084 break;
8661 case NTO: 9085 case NTO:
8662#if BASH_REDIR_OUTPUT 9086#if BASH_REDIR_OUTPUT
@@ -8669,6 +9093,7 @@ copynode(union node *n)
8669 new->nfile.fname = copynode(n->nfile.fname); 9093 new->nfile.fname = copynode(n->nfile.fname);
8670 new->nfile.fd = n->nfile.fd; 9094 new->nfile.fd = n->nfile.fd;
8671 new->nfile.next = copynode(n->nfile.next); 9095 new->nfile.next = copynode(n->nfile.next);
9096 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8672 break; 9097 break;
8673 case NTOFD: 9098 case NTOFD:
8674 case NFROMFD: 9099 case NFROMFD:
@@ -8676,15 +9101,18 @@ copynode(union node *n)
8676 new->ndup.dupfd = n->ndup.dupfd; 9101 new->ndup.dupfd = n->ndup.dupfd;
8677 new->ndup.fd = n->ndup.fd; 9102 new->ndup.fd = n->ndup.fd;
8678 new->ndup.next = copynode(n->ndup.next); 9103 new->ndup.next = copynode(n->ndup.next);
9104 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8679 break; 9105 break;
8680 case NHERE: 9106 case NHERE:
8681 case NXHERE: 9107 case NXHERE:
8682 new->nhere.doc = copynode(n->nhere.doc); 9108 new->nhere.doc = copynode(n->nhere.doc);
8683 new->nhere.fd = n->nhere.fd; 9109 new->nhere.fd = n->nhere.fd;
8684 new->nhere.next = copynode(n->nhere.next); 9110 new->nhere.next = copynode(n->nhere.next);
9111 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8685 break; 9112 break;
8686 case NNOT: 9113 case NNOT:
8687 new->nnot.com = copynode(n->nnot.com); 9114 new->nnot.com = copynode(n->nnot.com);
9115 SAVE_PTR(new->nnot.com);
8688 break; 9116 break;
8689 }; 9117 };
8690 new->type = n->type; 9118 new->type = n->type;
@@ -8700,13 +9128,16 @@ copyfunc(union node *n)
8700 struct funcnode *f; 9128 struct funcnode *f;
8701 size_t blocksize; 9129 size_t blocksize;
8702 9130
8703 /*funcstringsize = 0;*/ 9131 funcblocksize = offsetof(struct funcnode, n);
8704 blocksize = offsetof(struct funcnode, n) + calcsize(0, n); 9132 funcstringsize = 0;
8705 f = ckzalloc(blocksize /* + funcstringsize */); 9133 calcsize(n);
9134 blocksize = funcblocksize;
9135 f = ckmalloc(blocksize + funcstringsize);
8706 funcblock = (char *) f + offsetof(struct funcnode, n); 9136 funcblock = (char *) f + offsetof(struct funcnode, n);
8707 funcstring_end = (char *) f + blocksize; 9137 funcstring = (char *) f + blocksize;
9138 IF_PLATFORM_MINGW32(nodeptr = NULL);
8708 copynode(n); 9139 copynode(n);
8709 /* f->count = 0; - ckzalloc did it */ 9140 f->count = 0;
8710 return f; 9141 return f;
8711} 9142}
8712 9143
@@ -9042,6 +9473,7 @@ evalcase(union node *n, int flags)
9042static int 9473static int
9043evalsubshell(union node *n, int flags) 9474evalsubshell(union node *n, int flags)
9044{ 9475{
9476 IF_PLATFORM_MINGW32(struct forkshell fs;)
9045 struct job *jp; 9477 struct job *jp;
9046 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ 9478 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
9047 int status; 9479 int status;
@@ -9053,12 +9485,22 @@ evalsubshell(union node *n, int flags)
9053 if (backgnd == FORK_FG) 9485 if (backgnd == FORK_FG)
9054 get_tty_state(); 9486 get_tty_state();
9055 jp = makejob(/*n,*/ 1); 9487 jp = makejob(/*n,*/ 1);
9488#if ENABLE_PLATFORM_MINGW32
9489 memset(&fs, 0, sizeof(fs));
9490 fs.fpid = FS_EVALSUBSHELL;
9491 fs.n = n;
9492 fs.flags = flags;
9493 if (spawn_forkshell(jp, &fs, backgnd) < 0)
9494 ash_msg_and_raise_error("unable to spawn shell");
9495 if ( 0 ) {
9496#else
9056 if (forkshell(jp, n, backgnd) == 0) { 9497 if (forkshell(jp, n, backgnd) == 0) {
9057 /* child */ 9498 /* child */
9058 INT_ON; 9499 INT_ON;
9059 flags |= EV_EXIT; 9500 flags |= EV_EXIT;
9060 if (backgnd) 9501 if (backgnd)
9061 flags &= ~EV_TESTED; 9502 flags &= ~EV_TESTED;
9503#endif
9062 nofork: 9504 nofork:
9063 redirect(n->nredir.redirect, 0); 9505 redirect(n->nredir.redirect, 0);
9064 evaltreenr(n->nredir.n, flags); 9506 evaltreenr(n->nredir.n, flags);
@@ -9145,6 +9587,7 @@ expredir(union node *n)
9145static int 9587static int
9146evalpipe(union node *n, int flags) 9588evalpipe(union node *n, int flags)
9147{ 9589{
9590 IF_PLATFORM_MINGW32(struct forkshell fs;)
9148 struct job *jp; 9591 struct job *jp;
9149 struct nodelist *lp; 9592 struct nodelist *lp;
9150 int pipelen; 9593 int pipelen;
@@ -9171,6 +9614,17 @@ evalpipe(union node *n, int flags)
9171 ash_msg_and_raise_error("pipe call failed"); 9614 ash_msg_and_raise_error("pipe call failed");
9172 } 9615 }
9173 } 9616 }
9617#if ENABLE_PLATFORM_MINGW32
9618 memset(&fs, 0, sizeof(fs));
9619 fs.fpid = FS_EVALPIPE;
9620 fs.flags = flags;
9621 fs.n = lp->n;
9622 fs.fd[0] = pip[0];
9623 fs.fd[1] = pip[1];
9624 fs.fd[2] = prevfd;
9625 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9626 ash_msg_and_raise_error("unable to spawn shell");
9627#else
9174 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9628 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9175 /* child */ 9629 /* child */
9176 INT_ON; 9630 INT_ON;
@@ -9188,6 +9642,7 @@ evalpipe(union node *n, int flags)
9188 evaltreenr(lp->n, flags); 9642 evaltreenr(lp->n, flags);
9189 /* never returns */ 9643 /* never returns */
9190 } 9644 }
9645#endif
9191 /* parent */ 9646 /* parent */
9192 if (prevfd >= 0) 9647 if (prevfd >= 0)
9193 close(prevfd); 9648 close(prevfd);
@@ -9717,6 +10172,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9717 * as POSIX mandates */ 10172 * as POSIX mandates */
9718 return back_exitstatus; 10173 return back_exitstatus;
9719} 10174}
10175
9720static int 10176static int
9721evalcommand(union node *cmd, int flags) 10177evalcommand(union node *cmd, int flags)
9722{ 10178{
@@ -9915,7 +10371,15 @@ evalcommand(union node *cmd, int flags)
9915 */ 10371 */
9916 /* find_command() encodes applet_no as (-2 - applet_no) */ 10372 /* find_command() encodes applet_no as (-2 - applet_no) */
9917 int applet_no = (- cmdentry.u.index - 2); 10373 int applet_no = (- cmdentry.u.index - 2);
9918 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) { 10374 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)
10375#if ENABLE_PLATFORM_MINGW32
10376 /*
10377 * Fork long-running nofork applets (e.g. yes) in interactive
10378 * sessions. Otherwise ctrl-c won't let the user kill them.
10379 */
10380 && !(iflag && long_running_applet(applet_no))
10381#endif
10382 ) {
9919 listsetvar(varlist.list, VEXPORT|VSTACK); 10383 listsetvar(varlist.list, VEXPORT|VSTACK);
9920 /* run <applet>_main() */ 10384 /* run <applet>_main() */
9921 status = run_nofork_applet(applet_no, argv); 10385 status = run_nofork_applet(applet_no, argv);
@@ -9926,6 +10390,28 @@ evalcommand(union node *cmd, int flags)
9926 * in a script or a subshell does not need forking, 10390 * in a script or a subshell does not need forking,
9927 * we can just exec it. 10391 * we can just exec it.
9928 */ 10392 */
10393#if ENABLE_PLATFORM_MINGW32
10394 if (!(flags & EV_EXIT) || trap[0]) {
10395 /* No, forking off a child is necessary */
10396 struct forkshell fs;
10397
10398 INT_OFF;
10399 memset(&fs, 0, sizeof(fs));
10400 fs.fpid = FS_SHELLEXEC;
10401 fs.argv = argv;
10402 fs.string = (char*)path;
10403 fs.fd[0] = cmdentry.u.index;
10404 fs.strlist = varlist.list;
10405 jp = makejob(/*cmd,*/ 1);
10406 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
10407 ash_msg_and_raise_error("unable to spawn shell");
10408 status = waitforjob(jp);
10409 INT_ON;
10410 TRACE(("forked child exited with %d\n", exitstatus));
10411 break;
10412 }
10413 /* goes through to shellexec() */
10414#else
9929 if (!(flags & EV_EXIT) || may_have_traps) { 10415 if (!(flags & EV_EXIT) || may_have_traps) {
9930 /* No, forking off a child is necessary */ 10416 /* No, forking off a child is necessary */
9931 INT_OFF; 10417 INT_OFF;
@@ -9942,6 +10428,7 @@ evalcommand(union node *cmd, int flags)
9942 FORCE_INT_ON; 10428 FORCE_INT_ON;
9943 /* fall through to exec'ing external program */ 10429 /* fall through to exec'ing external program */
9944 } 10430 }
10431#endif
9945 listsetvar(varlist.list, VEXPORT|VSTACK); 10432 listsetvar(varlist.list, VEXPORT|VSTACK);
9946 shellexec(argv[0], argv, path, cmdentry.u.index); 10433 shellexec(argv[0], argv, path, cmdentry.u.index);
9947 /* NOTREACHED */ 10434 /* NOTREACHED */
@@ -10325,7 +10812,7 @@ preadbuffer(void)
10325 more--; 10812 more--;
10326 10813
10327 c = *q; 10814 c = *q;
10328 if (c == '\0') { 10815 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
10329 memmove(q, q + 1, more); 10816 memmove(q, q + 1, more);
10330 } else { 10817 } else {
10331 q++; 10818 q++;
@@ -10487,6 +10974,7 @@ popallfiles(void)
10487 popfile(); 10974 popfile();
10488} 10975}
10489 10976
10977#if !ENABLE_PLATFORM_MINGW32
10490/* 10978/*
10491 * Close the file(s) that the shell is reading commands from. Called 10979 * Close the file(s) that the shell is reading commands from. Called
10492 * after a fork is done. 10980 * after a fork is done.
@@ -10500,6 +10988,7 @@ closescript(void)
10500 g_parsefile->pf_fd = 0; 10988 g_parsefile->pf_fd = 0;
10501 } 10989 }
10502} 10990}
10991#endif
10503 10992
10504/* 10993/*
10505 * Like setinputfile, but takes an open file descriptor. Call this with 10994 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -12786,7 +13275,7 @@ find_dot_file(char *name)
12786 struct stat statb; 13275 struct stat statb;
12787 13276
12788 /* don't try this for absolute or relative paths */ 13277 /* don't try this for absolute or relative paths */
12789 if (strchr(name, '/')) 13278 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12790 return name; 13279 return name;
12791 13280
12792 while ((fullname = path_advance(&path, name)) != NULL) { 13281 while ((fullname = path_advance(&path, name)) != NULL) {
@@ -12897,17 +13386,22 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12897 struct tblentry *cmdp; 13386 struct tblentry *cmdp;
12898 int idx; 13387 int idx;
12899 int prev; 13388 int prev;
12900 char *fullname; 13389 char *fullname IF_PLATFORM_MINGW32(= NULL);
12901 struct stat statb; 13390 struct stat statb;
12902 int e; 13391 int e;
12903 int updatetbl; 13392 int updatetbl;
13393 IF_PLATFORM_MINGW32(int len;)
12904 struct builtincmd *bcmd; 13394 struct builtincmd *bcmd;
12905 13395
12906 /* If name contains a slash, don't use PATH or hash table */ 13396 /* If name contains a slash, don't use PATH or hash table */
12907 if (strchr(name, '/') != NULL) { 13397 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12908 entry->u.index = -1; 13398 entry->u.index = -1;
12909 if (act & DO_ABS) { 13399 if (act & DO_ABS) {
12910 while (stat(name, &statb) < 0) { 13400 while (stat(name, &statb) < 0
13401#if ENABLE_PLATFORM_MINGW32
13402 && (fullname=file_is_win32_executable(name)) == NULL
13403#endif
13404 ) {
12911#ifdef SYSV 13405#ifdef SYSV
12912 if (errno == EINTR) 13406 if (errno == EINTR)
12913 continue; 13407 continue;
@@ -12915,6 +13409,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12915 entry->cmdtype = CMDUNKNOWN; 13409 entry->cmdtype = CMDUNKNOWN;
12916 return; 13410 return;
12917 } 13411 }
13412#if ENABLE_PLATFORM_MINGW32
13413 free(fullname);
13414#endif
12918 } 13415 }
12919 entry->cmdtype = CMDNORMAL; 13416 entry->cmdtype = CMDNORMAL;
12920 return; 13417 return;
@@ -13011,12 +13508,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13011 } 13508 }
13012 } 13509 }
13013 /* if rehash, don't redo absolute path names */ 13510 /* if rehash, don't redo absolute path names */
13014 if (fullname[0] == '/' && idx <= prev) { 13511 if (is_absolute_path(fullname) && idx <= prev) {
13015 if (idx < prev) 13512 if (idx < prev)
13016 continue; 13513 continue;
13017 TRACE(("searchexec \"%s\": no change\n", name)); 13514 TRACE(("searchexec \"%s\": no change\n", name));
13018 goto success; 13515 goto success;
13019 } 13516 }
13517#if ENABLE_PLATFORM_MINGW32
13518 len = strlen(fullname);
13519 if (len > 4 &&
13520 (!strcasecmp(fullname+len-4, ".exe") ||
13521 !strcasecmp(fullname+len-4, ".com"))) {
13522 if (stat(fullname, &statb) < 0) {
13523 if (errno != ENOENT && errno != ENOTDIR)
13524 e = errno;
13525 goto loop;
13526 }
13527 }
13528 else {
13529 /* path_advance() has reserved space for .exe */
13530 memcpy(fullname+len, ".exe", 5);
13531 if (stat(fullname, &statb) < 0) {
13532 if (errno != ENOENT && errno != ENOTDIR)
13533 e = errno;
13534 memcpy(fullname+len, ".com", 5);
13535 if (stat(fullname, &statb) < 0) {
13536 if (errno != ENOENT && errno != ENOTDIR)
13537 e = errno;
13538 fullname[len] = '\0';
13539 if (stat(fullname, &statb) < 0) {
13540 if (errno != ENOENT && errno != ENOTDIR)
13541 e = errno;
13542 goto loop;
13543 }
13544 if (!file_is_executable(fullname)) {
13545 e = ENOEXEC;
13546 goto loop;
13547 }
13548 }
13549 }
13550 fullname[len] = '\0';
13551 }
13552#else
13020 while (stat(fullname, &statb) < 0) { 13553 while (stat(fullname, &statb) < 0) {
13021#ifdef SYSV 13554#ifdef SYSV
13022 if (errno == EINTR) 13555 if (errno == EINTR)
@@ -13026,6 +13559,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13026 e = errno; 13559 e = errno;
13027 goto loop; 13560 goto loop;
13028 } 13561 }
13562#endif
13029 e = EACCES; /* if we fail, this will be the error */ 13563 e = EACCES; /* if we fail, this will be the error */
13030 if (!S_ISREG(statb.st_mode)) 13564 if (!S_ISREG(statb.st_mode))
13031 continue; 13565 continue;
@@ -13542,7 +14076,11 @@ exitshell(void)
13542} 14076}
13543 14077
13544static void 14078static void
14079#if ENABLE_PLATFORM_MINGW32
14080init(int xp)
14081#else
13545init(void) 14082init(void)
14083#endif
13546{ 14084{
13547 /* we will never free this */ 14085 /* we will never free this */
13548 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 14086 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
@@ -13561,6 +14099,86 @@ init(void)
13561 struct stat st1, st2; 14099 struct stat st1, st2;
13562 14100
13563 initvar(); 14101 initvar();
14102
14103#if ENABLE_PLATFORM_MINGW32
14104 /*
14105 * case insensitive env names from Windows world
14106 *
14107 * Some standard env names such as PATH is named Path and so on
14108 * ash itself is case sensitive, so "Path" will confuse it, as
14109 * MSVC getenv() is case insensitive.
14110 *
14111 * We may end up having both Path and PATH. Then Path will be chosen
14112 * because it appears first.
14113 */
14114 for (envp = environ; envp && *envp; envp++) {
14115 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
14116 strncmp(*envp, "PATH=", 5) != 0) {
14117 break;
14118 }
14119 }
14120
14121 if (envp && *envp) {
14122 /*
14123 * If we get here it's because the environment contains a path
14124 * variable called something other than PATH. This suggests we
14125 * haven't been invoked from an earlier instance of BusyBox.
14126 */
14127 char *start, *end, *s;
14128 struct passwd *pw;
14129
14130 for (envp = environ; envp && *envp; envp++) {
14131 if (!(end=strchr(*envp, '=')))
14132 continue;
14133
14134 /* make all variable names uppercase */
14135 for (start = *envp;start < end;start++)
14136 *start = toupper(*start);
14137
14138 /* skip conversion of variables known to cause problems */
14139 if ( strncmp(*envp, "SYSTEMROOT=", 11) == 0 ||
14140 strncmp(*envp, "COMSPEC=", 8) == 0 ) {
14141 continue;
14142 }
14143
14144 /* convert backslashes to forward slashes in value */
14145 if (!xp) {
14146 for ( s=end+1; *s; ++s ) {
14147 if ( *s == '\\' ) {
14148 *s = '/';
14149 }
14150 }
14151 }
14152
14153 /* check for invalid characters in name */
14154 for (start = *envp;start < end;start++) {
14155 if (!isdigit(*start) && !isalpha(*start) && *start != '_') {
14156 break;
14157 }
14158 }
14159
14160 if (start != end) {
14161 /*
14162 * Make a copy of the variable, replacing invalid
14163 * characters in the name with underscores.
14164 */
14165 char *var = xstrdup(*envp);
14166
14167 for (start = var;*start != '=';start++) {
14168 if (!isdigit(*start) && !isalpha(*start)) {
14169 *start = '_';
14170 }
14171 }
14172 setvareq(var, VEXPORT|VNOSAVE);
14173 }
14174 }
14175
14176 /* some initialisation normally performed at login */
14177 pw = xgetpwuid(getuid());
14178 setup_environment(pw->pw_shell,
14179 SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw);
14180 }
14181#endif
13564 for (envp = environ; envp && *envp; envp++) { 14182 for (envp = environ; envp && *envp; envp++) {
13565 p = endofname(*envp); 14183 p = endofname(*envp);
13566 if (p != *envp && *p == '=') { 14184 if (p != *envp && *p == '=') {
@@ -13772,17 +14390,44 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13772 exception_handler = &jmploc; 14390 exception_handler = &jmploc;
13773 rootpid = getpid(); 14391 rootpid = getpid();
13774 14392
13775 init(); 14393 init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0));
13776 setstackmark(&smark); 14394 setstackmark(&smark);
14395
14396#if ENABLE_PLATFORM_MINGW32
14397 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
14398 SetConsoleCtrlHandler(ctrl_handler, TRUE);
14399
14400 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
14401 forkshell_init(argv[2]);
14402
14403 /* NOTREACHED */
14404 bb_error_msg_and_die("subshell ended unexpectedly");
14405 }
14406#endif
13777 login_sh = procargs(argv); 14407 login_sh = procargs(argv);
13778#if DEBUG 14408#if DEBUG
13779 TRACE(("Shell args: ")); 14409 TRACE(("Shell args: "));
13780 trace_puts_args(argv); 14410 trace_puts_args(argv);
13781#endif 14411#endif
13782 14412
14413#if ENABLE_ASH_NOCONSOLE
14414 if ( noconsole ) {
14415 DWORD dummy;
14416
14417 if ( GetConsoleProcessList(&dummy, 1) == 1 ) {
14418 ShowWindow(GetConsoleWindow(), SW_HIDE);
14419 }
14420 }
14421#endif
14422
13783 if (login_sh) { 14423 if (login_sh) {
13784 const char *hp; 14424 const char *hp;
13785 14425
14426#if ENABLE_PLATFORM_MINGW32
14427 chdir(xgetpwuid(getuid())->pw_dir);
14428 setpwd(NULL, 0);
14429#endif
14430
13786 state = 1; 14431 state = 1;
13787 read_profile("/etc/profile"); 14432 read_profile("/etc/profile");
13788 state1: 14433 state1:
@@ -13857,6 +14502,642 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13857 /* NOTREACHED */ 14502 /* NOTREACHED */
13858} 14503}
13859 14504
14505#if ENABLE_PLATFORM_MINGW32
14506static void
14507forkshell_openhere(struct forkshell *fs)
14508{
14509 union node *redir = fs->n;
14510 int pip[2];
14511
14512 pip[0] = fs->fd[0];
14513 pip[1] = fs->fd[1];
14514
14515 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14516
14517 close(pip[0]);
14518 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
14519 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
14520 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
14521 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
14522 signal(SIGPIPE, SIG_DFL);
14523 if (redir->type == NHERE) {
14524 size_t len = strlen(redir->nhere.doc->narg.text);
14525 full_write(pip[1], redir->nhere.doc->narg.text, len);
14526 } else /* NXHERE */
14527 expandhere(redir->nhere.doc, pip[1]);
14528 _exit(EXIT_SUCCESS);
14529}
14530
14531static void
14532forkshell_evalbackcmd(struct forkshell *fs)
14533{
14534 union node *n = fs->n;
14535 int pip[2] = {fs->fd[0], fs->fd[1]};
14536
14537 FORCE_INT_ON;
14538 close(pip[0]);
14539 if (pip[1] != 1) {
14540 /*close(1);*/
14541 dup2_or_raise(pip[1], 1);
14542 close(pip[1]);
14543 }
14544 eflag = 0;
14545 evaltree(n, EV_EXIT); /* actually evaltreenr... */
14546 /* NOTREACHED */
14547}
14548
14549static void
14550forkshell_evalsubshell(struct forkshell *fs)
14551{
14552 union node *n = fs->n;
14553 int flags = fs->flags;
14554
14555 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14556 INT_ON;
14557 flags |= EV_EXIT;
14558 expredir(n->nredir.redirect);
14559 redirect(n->nredir.redirect, 0);
14560 evaltreenr(n->nredir.n, flags);
14561 /* never returns */
14562}
14563
14564static void
14565forkshell_evalpipe(struct forkshell *fs)
14566{
14567 union node *n = fs->n;
14568 int flags = fs->flags;
14569 int prevfd = fs->fd[2];
14570 int pip[2] = {fs->fd[0], fs->fd[1]};
14571
14572 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14573 INT_ON;
14574 if (pip[1] >= 0) {
14575 close(pip[0]);
14576 }
14577 if (prevfd > 0) {
14578 dup2(prevfd, 0);
14579 close(prevfd);
14580 }
14581 if (pip[1] > 1) {
14582 dup2(pip[1], 1);
14583 close(pip[1]);
14584 }
14585 evaltreenr(n, flags);
14586}
14587
14588static void
14589forkshell_shellexec(struct forkshell *fs)
14590{
14591 int idx = fs->fd[0];
14592 struct strlist *varlist = fs->strlist;
14593 char **argv = fs->argv;
14594 char *path = fs->string;
14595
14596 FORCE_INT_ON;
14597 listsetvar(varlist, VEXPORT|VSTACK);
14598 shellexec(argv[0], argv, path, idx);
14599}
14600
14601static void
14602forkshell_child(struct forkshell *fs)
14603{
14604 switch ( fs->fpid ) {
14605 case FS_OPENHERE:
14606 forkshell_openhere(fs);
14607 break;
14608 case FS_EVALBACKCMD:
14609 forkshell_evalbackcmd(fs);
14610 break;
14611 case FS_EVALSUBSHELL:
14612 forkshell_evalsubshell(fs);
14613 break;
14614 case FS_EVALPIPE:
14615 forkshell_evalpipe(fs);
14616 break;
14617 case FS_SHELLEXEC:
14618 forkshell_shellexec(fs);
14619 break;
14620 }
14621}
14622
14623/*
14624 * Reset the pointers to the builtin environment variables in the hash
14625 * table to point to varinit rather than the bogus copy created during
14626 * forkshell_prepare.
14627 */
14628static void
14629reinitvar(void)
14630{
14631 struct var *vp;
14632 struct var *end;
14633 struct var **vpp;
14634 struct var **old;
14635
14636 vp = varinit;
14637 end = vp + ARRAY_SIZE(varinit);
14638 do {
14639 vpp = hashvar(vp->var_text);
14640 if ( (old=findvar(vpp, vp->var_text)) != NULL ) {
14641 vp->next = (*old)->next;
14642 *old = vp;
14643 }
14644 } while (++vp < end);
14645}
14646
14647/* FIXME: should consider running forkparent() and forkchild() */
14648static int
14649spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
14650{
14651 struct forkshell *new;
14652 char buf[16];
14653 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
14654 intptr_t ret;
14655
14656 new = forkshell_prepare(fs);
14657 sprintf(buf, "%x", (unsigned int)new->hMapFile);
14658 argv[2] = buf;
14659 ret = mingw_spawn_proc(argv);
14660 CloseHandle(new->hMapFile);
14661 UnmapViewOfFile(new);
14662 if (ret == -1) {
14663 free(jp);
14664 return -1;
14665 }
14666 forkparent(jp, fs->node, mode, (HANDLE)ret);
14667 return ret == -1 ? -1 : 0;
14668}
14669
14670/*
14671 * forkshell_prepare() and friends
14672 *
14673 * The sequence is as follows:
14674 * - funcblocksize, funcstringsize, nodeptrsize are initialized
14675 * - forkshell_size(fs) is called to calculate the exact memory needed
14676 * - a new struct is allocated
14677 * - funcblock, funcstring, nodeptr are initialized from the new block
14678 * - forkshell_copy(fs) is called to copy recursively everything over
14679 * it will record all pointers along the way, to nodeptr
14680 *
14681 * When this memory is mapped elsewhere, pointer fixup will be needed
14682 */
14683#define SLIST_SIZE_BEGIN(name,type) \
14684static void \
14685name(type *p) \
14686{ \
14687 while (p) { \
14688 funcblocksize += sizeof(type);
14689 /* do something here with p */
14690#define SLIST_SIZE_END() \
14691 nodeptrsize++; \
14692 p = p->next; \
14693 } \
14694}
14695
14696#define SLIST_COPY_BEGIN(name,type) \
14697static type * \
14698name(type *vp) \
14699{ \
14700 type *start; \
14701 type **vpp; \
14702 vpp = &start; \
14703 while (vp) { \
14704 *vpp = funcblock; \
14705 funcblock = (char *) funcblock + sizeof(type);
14706 /* do something here with vpp and vp */
14707#define SLIST_COPY_END() \
14708 SAVE_PTR((*vpp)->next); \
14709 vp = vp->next; \
14710 vpp = &(*vpp)->next; \
14711 } \
14712 *vpp = NULL; \
14713 return start; \
14714}
14715
14716/*
14717 * struct var
14718 */
14719SLIST_SIZE_BEGIN(var_size,struct var)
14720funcstringsize += strlen(p->var_text) + 1;
14721nodeptrsize++; /* p->text */
14722SLIST_SIZE_END()
14723
14724SLIST_COPY_BEGIN(var_copy,struct var)
14725(*vpp)->var_text = nodeckstrdup(vp->var_text);
14726(*vpp)->flags = vp->flags;
14727/*
14728 * The only place that can set struct var#func is varinit[],
14729 * which will be fixed by forkshell_init()
14730 */
14731(*vpp)->var_func = NULL;
14732SAVE_PTR((*vpp)->var_text);
14733SLIST_COPY_END()
14734
14735/*
14736 * struct strlist
14737 */
14738SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14739funcstringsize += strlen(p->text) + 1;
14740nodeptrsize++; /* p->text */
14741SLIST_SIZE_END()
14742
14743SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14744(*vpp)->text = nodeckstrdup(vp->text);
14745SAVE_PTR((*vpp)->text);
14746SLIST_COPY_END()
14747
14748/*
14749 * struct tblentry
14750 */
14751static void
14752tblentry_size(struct tblentry *tep)
14753{
14754 while (tep) {
14755 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14756 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14757 if (tep->cmdtype == CMDFUNCTION) {
14758 funcblocksize += offsetof(struct funcnode, n);
14759 calcsize(&tep->param.func->n);
14760 nodeptrsize++; /* tep->param.func */
14761 }
14762 nodeptrsize++; /* tep->next */
14763 tep = tep->next;
14764 }
14765}
14766
14767static struct tblentry *
14768tblentry_copy(struct tblentry *tep)
14769{
14770 struct tblentry *start;
14771 struct tblentry **newp;
14772 int size;
14773
14774 newp = &start;
14775 while (tep) {
14776 *newp = funcblock;
14777 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14778
14779 funcblock = (char *) funcblock + size;
14780 memcpy(*newp, tep, size);
14781 switch (tep->cmdtype) {
14782 case CMDBUILTIN:
14783 /* No pointer saving, this field must be fixed by forkshell_init() */
14784 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14785 break;
14786 case CMDFUNCTION:
14787 (*newp)->param.func = funcblock;
14788 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14789 copynode(&tep->param.func->n);
14790 SAVE_PTR((*newp)->param.func);
14791 break;
14792 default:
14793 break;
14794 }
14795 SAVE_PTR((*newp)->next);
14796 tep = tep->next;
14797 newp = &(*newp)->next;
14798 }
14799 *newp = NULL;
14800 return start;
14801}
14802
14803static void
14804cmdtable_size(struct tblentry **cmdtablep)
14805{
14806 int i;
14807 nodeptrsize += CMDTABLESIZE;
14808 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14809 for (i = 0; i < CMDTABLESIZE; i++)
14810 tblentry_size(cmdtablep[i]);
14811}
14812
14813static struct tblentry **
14814cmdtable_copy(struct tblentry **cmdtablep)
14815{
14816 struct tblentry **new = funcblock;
14817 int i;
14818
14819 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14820 for (i = 0; i < CMDTABLESIZE; i++) {
14821 new[i] = tblentry_copy(cmdtablep[i]);
14822 SAVE_PTR(new[i]);
14823 }
14824 return new;
14825}
14826
14827/*
14828 * char **
14829 */
14830static void
14831argv_size(char **p)
14832{
14833 while (p && *p) {
14834 funcblocksize += sizeof(char *);
14835 funcstringsize += strlen(*p)+1;
14836 nodeptrsize++;
14837 p++;
14838 }
14839 funcblocksize += sizeof(char *);
14840}
14841
14842static char **
14843argv_copy(char **p)
14844{
14845 char **new, **start = funcblock;
14846
14847 while (p && *p) {
14848 new = funcblock;
14849 funcblock = (char *) funcblock + sizeof(char *);
14850 *new = nodeckstrdup(*p);
14851 SAVE_PTR(*new);
14852 p++;
14853 new++;
14854 }
14855 new = funcblock;
14856 funcblock = (char *) funcblock + sizeof(char *);
14857 *new = NULL;
14858 return start;
14859}
14860
14861/*
14862 * struct redirtab
14863 */
14864static void
14865redirtab_size(struct redirtab *rdtp)
14866{
14867 while (rdtp) {
14868 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14869 rdtp = rdtp->next;
14870 nodeptrsize++; /* rdtp->next */
14871 }
14872}
14873
14874static struct redirtab *
14875redirtab_copy(struct redirtab *rdtp)
14876{
14877 struct redirtab *start;
14878 struct redirtab **vpp;
14879
14880 vpp = &start;
14881 while (rdtp) {
14882 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14883 *vpp = funcblock;
14884 funcblock = (char *) funcblock + size;
14885 memcpy(*vpp, rdtp, size);
14886 SAVE_PTR((*vpp)->next);
14887 rdtp = rdtp->next;
14888 vpp = &(*vpp)->next;
14889 }
14890 *vpp = NULL;
14891 return start;
14892}
14893
14894#undef shellparam
14895#undef redirlist
14896#undef varinit
14897#undef vartab
14898static void
14899globals_var_size(struct globals_var *gvp)
14900{
14901 int i;
14902
14903 funcblocksize += sizeof(struct globals_var);
14904 argv_size(gvp->shellparam.p);
14905 redirtab_size(gvp->redirlist);
14906 for (i = 0; i < VTABSIZE; i++)
14907 var_size(gvp->vartab[i]);
14908 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14909 var_size(gvp->varinit+i);
14910 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14911}
14912
14913#undef preverrout_fd
14914static struct globals_var *
14915globals_var_copy(struct globals_var *gvp)
14916{
14917 int i;
14918 struct globals_var *new;
14919
14920 new = funcblock;
14921 funcblock = (char *) funcblock + sizeof(struct globals_var);
14922
14923 /* shparam */
14924 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14925 new->shellparam.malloced = 0;
14926 new->shellparam.p = argv_copy(gvp->shellparam.p);
14927 SAVE_PTR(new->shellparam.p);
14928
14929 new->redirlist = redirtab_copy(gvp->redirlist);
14930 SAVE_PTR(new->redirlist);
14931
14932 new->preverrout_fd = gvp->preverrout_fd;
14933 for (i = 0; i < VTABSIZE; i++) {
14934 new->vartab[i] = var_copy(gvp->vartab[i]);
14935 SAVE_PTR(new->vartab[i]);
14936 }
14937
14938 /* Can't use var_copy because varinit is already allocated */
14939 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14940 new->varinit[i].next = NULL;
14941 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14942 SAVE_PTR(new->varinit[i].var_text);
14943 new->varinit[i].flags = gvp->varinit[i].flags;
14944 new->varinit[i].var_func = gvp->varinit[i].var_func;
14945 }
14946 return new;
14947}
14948
14949#undef minusc
14950#undef curdir
14951#undef physdir
14952#undef arg0
14953#undef nullstr
14954static void
14955globals_misc_size(struct globals_misc *p)
14956{
14957 funcblocksize += sizeof(struct globals_misc);
14958 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14959 if (p->curdir != p->nullstr)
14960 funcstringsize += strlen(p->curdir) + 1;
14961 if (p->physdir != p->nullstr)
14962 funcstringsize += strlen(p->physdir) + 1;
14963 funcstringsize += strlen(p->arg0) + 1;
14964 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14965}
14966
14967static struct globals_misc *
14968globals_misc_copy(struct globals_misc *p)
14969{
14970 struct globals_misc *new = funcblock;
14971
14972 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14973 memcpy(new, p, sizeof(struct globals_misc));
14974
14975 new->minusc = nodeckstrdup(p->minusc);
14976 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14977 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14978 new->arg0 = nodeckstrdup(p->arg0);
14979 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14980 return new;
14981}
14982
14983static void
14984forkshell_size(struct forkshell *fs)
14985{
14986 funcblocksize += sizeof(struct forkshell);
14987 globals_var_size(fs->gvp);
14988 globals_misc_size(fs->gmp);
14989 cmdtable_size(fs->cmdtable);
14990 /* optlist_transfer(sending, fd); */
14991 /* misc_transfer(sending, fd); */
14992
14993 calcsize(fs->n);
14994 argv_size(fs->argv);
14995 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14996 strlist_size(fs->strlist);
14997
14998 nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */
14999}
15000
15001static struct forkshell *
15002forkshell_copy(struct forkshell *fs)
15003{
15004 struct forkshell *new;
15005
15006 new = funcblock;
15007 funcblock = (char *) funcblock + sizeof(struct forkshell);
15008
15009 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
15010 new->gvp = globals_var_copy(fs->gvp);
15011 new->gmp = globals_misc_copy(fs->gmp);
15012 new->cmdtable = cmdtable_copy(fs->cmdtable);
15013 SAVE_PTR3(new->gvp, new->gmp, new->cmdtable);
15014
15015 new->n = copynode(fs->n);
15016 new->argv = argv_copy(fs->argv);
15017 new->string = nodeckstrdup(fs->string);
15018 new->strlist = strlist_copy(fs->strlist);
15019 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
15020 return new;
15021}
15022
15023static struct forkshell *
15024forkshell_prepare(struct forkshell *fs)
15025{
15026 struct forkshell *new;
15027 int size, nodeptr_offset;
15028 HANDLE h;
15029 SECURITY_ATTRIBUTES sa;
15030
15031 /* Calculate size of "new" */
15032 fs->gvp = ash_ptr_to_globals_var;
15033 fs->gmp = ash_ptr_to_globals_misc;
15034 fs->cmdtable = cmdtable;
15035
15036 nodeptrsize = 1; /* NULL terminated */
15037 funcblocksize = 0;
15038 funcstringsize = 0;
15039 forkshell_size(fs);
15040 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(char *);
15041
15042 /* Allocate, initialize pointers */
15043 memset(&sa, 0, sizeof(sa));
15044 sa.nLength = sizeof(sa);
15045 sa.lpSecurityDescriptor = NULL;
15046 sa.bInheritHandle = TRUE;
15047 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
15048 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
15049 /* new = ckmalloc(size); */
15050 funcblock = new;
15051 funcstring = (char *) funcblock + funcblocksize;
15052 nodeptr = (char **)((char *)funcstring + funcstringsize);
15053 nodeptr_offset = (char *)nodeptr - (char *)new;
15054
15055 /* Now pack them all */
15056 forkshell_copy(fs);
15057
15058 /* Finish it up */
15059 *nodeptr = NULL;
15060 new->size = size;
15061 new->nodeptr_offset = nodeptr_offset;
15062 new->old_base = new;
15063 new->hMapFile = h;
15064 return new;
15065}
15066
15067#undef exception_handler
15068#undef trap
15069#undef trap_ptr
15070static void *sticky_mem_start, *sticky_mem_end;
15071static void
15072forkshell_init(const char *idstr)
15073{
15074 struct forkshell *fs;
15075 int map_handle;
15076 HANDLE h;
15077 struct globals_var **gvpp;
15078 struct globals_misc **gmpp;
15079 int i;
15080 char **ptr;
15081
15082 if (sscanf(idstr, "%x", &map_handle) != 1)
15083 bb_error_msg_and_die("invalid forkshell ID");
15084
15085 h = (HANDLE)map_handle;
15086 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
15087 if (!fs)
15088 bb_error_msg_and_die("Invalid forkshell memory");
15089
15090 /* this memory can't be freed */
15091 sticky_mem_start = fs;
15092 sticky_mem_end = (char *) fs + fs->size;
15093
15094 /* pointer fixup */
15095 nodeptr = (char **)((char *)fs + fs->nodeptr_offset);
15096 for ( i=0; nodeptr[i]; ++i ) {
15097 ptr = (char **)((char *)fs + (nodeptr[i] - (char *)fs->old_base));
15098 if (*ptr)
15099 *ptr = (char *)fs + (*ptr - (char *)fs->old_base);
15100 }
15101
15102 /* Now fix up stuff that can't be transferred */
15103 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
15104 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
15105 for (i = 0; i < CMDTABLESIZE; i++) {
15106 struct tblentry *e = fs->cmdtable[i];
15107 while (e) {
15108 if (e->cmdtype == CMDBUILTIN)
15109 e->param.cmd = builtintab + (int)e->param.cmd;
15110 e = e->next;
15111 }
15112 }
15113 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
15114 for (i = 0; i < NSIG; i++)
15115 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
15116 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
15117
15118 /* Switch global variables */
15119 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
15120 *gvpp = fs->gvp;
15121 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
15122 *gmpp = fs->gmp;
15123 cmdtable = fs->cmdtable;
15124
15125 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
15126
15127 reinitvar();
15128
15129 forkshell_child(fs);
15130}
15131
15132#undef free
15133static void
15134sticky_free(void *base)
15135{
15136 if (base >= sticky_mem_start && base < sticky_mem_end)
15137 return;
15138 free(base);
15139}
15140#endif
13860 15141
13861/*- 15142/*-
13862 * Copyright (c) 1989, 1991, 1993, 1994 15143 * Copyright (c) 1989, 1991, 1993, 1994
diff --git a/shell/math.h b/shell/math.h
index 32e1ffe35..90eb49144 100644
--- a/shell/math.h
+++ b/shell/math.h
@@ -65,7 +65,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
65 65
66#if ENABLE_FEATURE_SH_MATH_64 66#if ENABLE_FEATURE_SH_MATH_64
67typedef long long arith_t; 67typedef long long arith_t;
68#define ARITH_FMT "%lld" 68#define ARITH_FMT "%"LL_FMT"d"
69#define strto_arith_t strtoull 69#define strto_arith_t strtoull
70#else 70#else
71typedef long arith_t; 71typedef long arith_t;
diff --git a/shell/shell_common.c b/shell/shell_common.c
index a9f8d8413..750adc5d8 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
24const char defoptindvar[] ALIGN1 = "OPTIND=1"; 28const char defoptindvar[] ALIGN1 = "OPTIND=1";
25 29
26 30
@@ -209,6 +213,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
209 * regardless of SA_RESTART-ness of that signal! 213 * regardless of SA_RESTART-ness of that signal!
210 */ 214 */
211 errno = 0; 215 errno = 0;
216#if !ENABLE_PLATFORM_MINGW32
212 pfd[0].events = POLLIN; 217 pfd[0].events = POLLIN;
213 if (poll(pfd, 1, timeout) <= 0) { 218 if (poll(pfd, 1, timeout) <= 0) {
214 /* timed out, or EINTR */ 219 /* timed out, or EINTR */
@@ -216,6 +221,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
216 retval = (const char *)(uintptr_t)1; 221 retval = (const char *)(uintptr_t)1;
217 goto ret; 222 goto ret;
218 } 223 }
224#endif
219 if (read(fd, &buffer[bufpos], 1) != 1) { 225 if (read(fd, &buffer[bufpos], 1) != 1) {
220 err = errno; 226 err = errno;
221 retval = (const char *)(uintptr_t)1; 227 retval = (const char *)(uintptr_t)1;
@@ -223,7 +229,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
223 } 229 }
224 230
225 c = buffer[bufpos]; 231 c = buffer[bufpos];
226 if (c == '\0') 232 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r'))
227 continue; 233 continue;
228 if (!(read_flags & BUILTIN_READ_RAW)) { 234 if (!(read_flags & BUILTIN_READ_RAW)) {
229 if (backslash) { 235 if (backslash) {
@@ -298,6 +304,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
298 304
299/* ulimit builtin */ 305/* ulimit builtin */
300 306
307#if !ENABLE_PLATFORM_MINGW32
301struct limits { 308struct limits {
302 uint8_t cmd; /* RLIMIT_xxx fit into it */ 309 uint8_t cmd; /* RLIMIT_xxx fit into it */
303 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 310 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
@@ -514,3 +521,9 @@ shell_builtin_ulimit(char **argv)
514 521
515 return 0; 522 return 0;
516} 523}
524#else
525int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM)
526{
527 return 1;
528}
529#endif
diff --git a/util-linux/more.c b/util-linux/more.c
index 926cf5f26..fafc80403 100644
--- a/util-linux/more.c
+++ b/util-linux/more.c
@@ -35,6 +35,9 @@
35//usage:#define more_example_usage 35//usage:#define more_example_usage
36//usage: "$ dmesg | more\n" 36//usage: "$ dmesg | more\n"
37 37
38#if ENABLE_PLATFORM_MINGW32
39#include <conio.h>
40#endif
38#include "libbb.h" 41#include "libbb.h"
39#include "common_bufsiz.h" 42#include "common_bufsiz.h"
40 43
@@ -95,9 +98,13 @@ int more_main(int argc UNUSED_PARAM, char **argv)
95 * is not a tty and turns into cat. This makes sense. */ 98 * is not a tty and turns into cat. This makes sense. */
96 if (!isatty(STDOUT_FILENO)) 99 if (!isatty(STDOUT_FILENO))
97 return bb_cat(argv); 100 return bb_cat(argv);
101#if !ENABLE_PLATFORM_MINGW32
98 tty = fopen_for_read(CURRENT_TTY); 102 tty = fopen_for_read(CURRENT_TTY);
99 if (!tty) 103 if (!tty)
100 return bb_cat(argv); 104 return bb_cat(argv);
105#else
106 tty = stdin;
107#endif
101 108
102 G.tty_fileno = fileno(tty); 109 G.tty_fileno = fileno(tty);
103 110
@@ -151,8 +158,12 @@ int more_main(int argc UNUSED_PARAM, char **argv)
151 * to get input from the user. 158 * to get input from the user.
152 */ 159 */
153 for (;;) { 160 for (;;) {
161#if !ENABLE_PLATFORM_MINGW32
154 fflush_all(); 162 fflush_all();
155 input = getc(tty); 163 input = getc(tty);
164#else
165 input = _getch();
166#endif
156 input = tolower(input); 167 input = tolower(input);
157 /* Erase the last message */ 168 /* Erase the last message */
158 printf("\r%*s\r", len, ""); 169 printf("\r%*s\r", len, "");
@@ -166,6 +177,10 @@ int more_main(int argc UNUSED_PARAM, char **argv)
166 * commands, else we show help msg. */ 177 * commands, else we show help msg. */
167 if (input == ' ' || input == '\n' || input == 'r') 178 if (input == ' ' || input == '\n' || input == 'r')
168 break; 179 break;
180#if ENABLE_PLATFORM_MINGW32
181 if (input == '\r')
182 break;
183#endif
169 len = printf("(Enter:next line Space:next page Q:quit R:show the rest)"); 184 len = printf("(Enter:next line Space:next page Q:quit R:show the rest)");
170 } 185 }
171 len = 0; 186 len = 0;
@@ -200,6 +215,10 @@ int more_main(int argc UNUSED_PARAM, char **argv)
200 * will move us to a new line. */ 215 * will move us to a new line. */
201 if (++lines >= G.terminal_height || input == '\n') 216 if (++lines >= G.terminal_height || input == '\n')
202 please_display_more_prompt = 1; 217 please_display_more_prompt = 1;
218#if ENABLE_PLATFORM_MINGW32
219 if (input == '\r')
220 please_display_more_prompt = 1;
221#endif
203 len = 0; 222 len = 0;
204 } 223 }
205 if (c != '\n' && wrap) { 224 if (c != '\n' && wrap) {
diff --git a/util-linux/rev.c b/util-linux/rev.c
index 2bef9b9be..b0a0c01aa 100644
--- a/util-linux/rev.c
+++ b/util-linux/rev.c
@@ -31,7 +31,7 @@
31#endif 31#endif
32 32
33/* In-place invert */ 33/* In-place invert */
34static void strrev(CHAR_T *s, int len) 34static void bb_strrev(CHAR_T *s, int len)
35{ 35{
36 int i; 36 int i;
37 37
@@ -39,6 +39,10 @@ static void strrev(CHAR_T *s, int len)
39 len--; 39 len--;
40 if (len != 0 && s[len] == '\n') 40 if (len != 0 && s[len] == '\n')
41 len--; 41 len--;
42#if ENABLE_PLATFORM_MINGW32
43 if (len != 0 && s[len] == '\r')
44 len--;
45#endif
42 } 46 }
43 47
44 for (i = 0; i < len; i++, len--) { 48 for (i = 0; i < len; i++, len--) {
@@ -99,14 +103,14 @@ int rev_main(int argc UNUSED_PARAM, char **argv)
99 /* Convert to wchar_t (might error out!) */ 103 /* Convert to wchar_t (might error out!) */
100 int len = mbstowcs(tmp, buf, bufsize); 104 int len = mbstowcs(tmp, buf, bufsize);
101 if (len >= 0) { 105 if (len >= 0) {
102 strrev(tmp, len); 106 bb_strrev(tmp, len);
103 /* Convert back to char */ 107 /* Convert back to char */
104 wcstombs(buf, tmp, bufsize); 108 wcstombs(buf, tmp, bufsize);
105 } 109 }
106 free(tmp); 110 free(tmp);
107 } 111 }
108#else 112#else
109 strrev(buf, strlen(buf)); 113 bb_strrev(buf, strlen(buf));
110#endif 114#endif
111 fputs(buf, stdout); 115 fputs(buf, stdout);
112 } 116 }
diff --git a/win32/Kbuild b/win32/Kbuild
new file mode 100644
index 000000000..ba361f1ca
--- /dev/null
+++ b/win32/Kbuild
@@ -0,0 +1,25 @@
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) += inet_pton.o
15lib-$(CONFIG_PLATFORM_MINGW32) += poll.o
16lib-$(CONFIG_PLATFORM_MINGW32) += select.o
17lib-$(CONFIG_PLATFORM_MINGW32) += popen.o
18lib-$(CONFIG_PLATFORM_MINGW32) += statfs.o
19lib-$(CONFIG_PLATFORM_MINGW32) += mempcpy.o
20lib-$(CONFIG_PLATFORM_MINGW32) += mntent.o
21lib-$(CONFIG_PLATFORM_MINGW32) += strptime.o
22lib-$(CONFIG_PLATFORM_MINGW32) += system.o
23lib-$(CONFIG_PLATFORM_MINGW32) += termios.o
24lib-$(CONFIG_PLATFORM_MINGW32) += uname.o
25lib-$(CONFIG_PLATFORM_MINGW32) += winansi.o
diff --git a/win32/arpa/inet.h b/win32/arpa/inet.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/arpa/inet.h
diff --git a/win32/env.c b/win32/env.c
new file mode 100644
index 000000000..48b86c555
--- /dev/null
+++ b/win32/env.c
@@ -0,0 +1,189 @@
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#if !ENABLE_SAFE_ENV
108 SetEnvironmentVariable(name, NULL);
109#endif
110 }
111 }
112 return env;
113}
114
115#if ENABLE_SAFE_ENV
116/*
117 * Removing an environment variable with WIN32 putenv requires an argument
118 * like "NAME="; glibc omits the '='. The implementations of unsetenv and
119 * clearenv allow for this.
120 *
121 * It isn't possible to create an environment variable with an empty value
122 * using WIN32 putenv.
123 */
124#undef putenv
125int unsetenv(const char *env)
126{
127 char *name;
128 int ret;
129
130 name = xmalloc(strlen(env)+2);
131 strcat(strcpy(name, env), "=");
132 ret = putenv(name);
133 free(name);
134
135 return ret;
136}
137
138int clearenv(void)
139{
140 char *name, *s;
141
142 while ( environ && *environ ) {
143 if ( (s=strchr(*environ, '=')) != NULL ) {
144 name = xstrndup(*environ, s-*environ+1);
145 putenv(name);
146 free(name);
147 }
148 else {
149 return -1;
150 }
151 }
152 return 0;
153}
154
155int mingw_putenv(const char *env)
156{
157 char *s;
158
159 if ( (s=strchr(env, '=')) == NULL ) {
160 return unsetenv(env);
161 }
162
163 if ( s[1] != '\0' ) {
164 return putenv(env);
165 }
166
167 /* can't set empty value */
168 return 0;
169}
170#else
171void unsetenv(const char *env)
172{
173 env_setenv(environ, env);
174}
175
176int clearenv(void)
177{
178 char **env = environ;
179 if (!env)
180 return 0;
181 while (*env) {
182 free(*env);
183 env++;
184 }
185 free(env);
186 environ = NULL;
187 return 0;
188}
189#endif
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/inet_pton.c b/win32/inet_pton.c
new file mode 100644
index 000000000..ec87abec5
--- /dev/null
+++ b/win32/inet_pton.c
@@ -0,0 +1,255 @@
1/* inet_pton.c -- convert IPv4 and IPv6 addresses from text to binary form
2
3 Copyright (C) 2006, 2008-2015 Free Software Foundation, Inc.
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 3 of the License, or
8 (at your option) 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
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18/*
19 * Copyright (c) 1996,1999 by Internet Software Consortium.
20 *
21 * Permission to use, copy, modify, and distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
28 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
29 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
30 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
31 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
32 * SOFTWARE.
33 */
34
35#include "libbb.h"
36
37/* Specification. */
38#include <arpa/inet.h>
39
40# include <ctype.h>
41# include <string.h>
42# include <errno.h>
43
44# define NS_INADDRSZ 4
45# define NS_IN6ADDRSZ 16
46# define NS_INT16SZ 2
47# define HAVE_IPV6 1
48
49/*
50 * WARNING: Don't even consider trying to compile this on a system where
51 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
52 */
53
54static int inet_pton4 (const char *src, unsigned char *dst);
55# if HAVE_IPV6
56static int inet_pton6 (const char *src, unsigned char *dst);
57# endif
58
59/* int
60 * inet_pton(af, src, dst)
61 * convert from presentation format (which usually means ASCII printable)
62 * to network format (which is usually some kind of binary format).
63 * return:
64 * 1 if the address was valid for the specified address family
65 * 0 if the address wasn't valid ('dst' is untouched in this case)
66 * -1 if some other error occurred ('dst' is untouched in this case, too)
67 * author:
68 * Paul Vixie, 1996.
69 */
70int
71inet_pton (int af, const char *restrict src, void *restrict dst)
72{
73 switch (af)
74 {
75 case AF_INET:
76 return (inet_pton4 (src, dst));
77
78# if HAVE_IPV6
79 case AF_INET6:
80 return (inet_pton6 (src, dst));
81# endif
82
83 default:
84 errno = EAFNOSUPPORT;
85 return (-1);
86 }
87 /* NOTREACHED */
88}
89
90/* int
91 * inet_pton4(src, dst)
92 * like inet_aton() but without all the hexadecimal, octal (with the
93 * exception of 0) and shorthand.
94 * return:
95 * 1 if 'src' is a valid dotted quad, else 0.
96 * notice:
97 * does not touch 'dst' unless it's returning 1.
98 * author:
99 * Paul Vixie, 1996.
100 */
101static int
102inet_pton4 (const char *restrict src, unsigned char *restrict dst)
103{
104 int saw_digit, octets, ch;
105 unsigned char tmp[NS_INADDRSZ], *tp;
106
107 saw_digit = 0;
108 octets = 0;
109 *(tp = tmp) = 0;
110 while ((ch = *src++) != '\0')
111 {
112
113 if (ch >= '0' && ch <= '9')
114 {
115 unsigned new = *tp * 10 + (ch - '0');
116
117 if (saw_digit && *tp == 0)
118 return (0);
119 if (new > 255)
120 return (0);
121 *tp = new;
122 if (!saw_digit)
123 {
124 if (++octets > 4)
125 return (0);
126 saw_digit = 1;
127 }
128 }
129 else if (ch == '.' && saw_digit)
130 {
131 if (octets == 4)
132 return (0);
133 *++tp = 0;
134 saw_digit = 0;
135 }
136 else
137 return (0);
138 }
139 if (octets < 4)
140 return (0);
141 memcpy (dst, tmp, NS_INADDRSZ);
142 return (1);
143}
144
145# if HAVE_IPV6
146
147/* int
148 * inet_pton6(src, dst)
149 * convert presentation level address to network order binary form.
150 * return:
151 * 1 if 'src' is a valid [RFC1884 2.2] address, else 0.
152 * notice:
153 * (1) does not touch 'dst' unless it's returning 1.
154 * (2) :: in a full address is silently ignored.
155 * credit:
156 * inspired by Mark Andrews.
157 * author:
158 * Paul Vixie, 1996.
159 */
160static int
161inet_pton6 (const char *restrict src, unsigned char *restrict dst)
162{
163 static const char xdigits[] = "0123456789abcdef";
164 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
165 const char *curtok;
166 int ch, saw_xdigit;
167 unsigned val;
168
169 tp = memset (tmp, '\0', NS_IN6ADDRSZ);
170 endp = tp + NS_IN6ADDRSZ;
171 colonp = NULL;
172 /* Leading :: requires some special handling. */
173 if (*src == ':')
174 if (*++src != ':')
175 return (0);
176 curtok = src;
177 saw_xdigit = 0;
178 val = 0;
179 while ((ch = tolower (*src++)) != '\0')
180 {
181 const char *pch;
182
183 pch = strchr (xdigits, ch);
184 if (pch != NULL)
185 {
186 val <<= 4;
187 val |= (pch - xdigits);
188 if (val > 0xffff)
189 return (0);
190 saw_xdigit = 1;
191 continue;
192 }
193 if (ch == ':')
194 {
195 curtok = src;
196 if (!saw_xdigit)
197 {
198 if (colonp)
199 return (0);
200 colonp = tp;
201 continue;
202 }
203 else if (*src == '\0')
204 {
205 return (0);
206 }
207 if (tp + NS_INT16SZ > endp)
208 return (0);
209 *tp++ = (u_char) (val >> 8) & 0xff;
210 *tp++ = (u_char) val & 0xff;
211 saw_xdigit = 0;
212 val = 0;
213 continue;
214 }
215 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
216 inet_pton4 (curtok, tp) > 0)
217 {
218 tp += NS_INADDRSZ;
219 saw_xdigit = 0;
220 break; /* '\0' was seen by inet_pton4(). */
221 }
222 return (0);
223 }
224 if (saw_xdigit)
225 {
226 if (tp + NS_INT16SZ > endp)
227 return (0);
228 *tp++ = (u_char) (val >> 8) & 0xff;
229 *tp++ = (u_char) val & 0xff;
230 }
231 if (colonp != NULL)
232 {
233 /*
234 * Since some memmove()'s erroneously fail to handle
235 * overlapping regions, we'll do the shift by hand.
236 */
237 const int n = tp - colonp;
238 int i;
239
240 if (tp == endp)
241 return (0);
242 for (i = 1; i <= n; i++)
243 {
244 endp[-i] = colonp[n - i];
245 colonp[n - i] = 0;
246 }
247 tp = endp;
248 }
249 if (tp != endp)
250 return (0);
251 memcpy (dst, tmp, NS_IN6ADDRSZ);
252 return (1);
253}
254
255# endif
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..1170cd9d5
--- /dev/null
+++ b/win32/mingw.c
@@ -0,0 +1,1064 @@
1#include "libbb.h"
2#include <userenv.h>
3
4#if defined(__MINGW64_VERSION_MAJOR)
5#if ENABLE_GLOBBING
6int _dowildcard = -1;
7#else
8int _dowildcard = 0;
9#endif
10
11#undef _fmode
12int _fmode = _O_BINARY;
13#endif
14
15#if !defined(__MINGW64_VERSION_MAJOR)
16#if ENABLE_GLOBBING
17int _CRT_glob = 1;
18#else
19int _CRT_glob = 0;
20#endif
21
22unsigned int _CRT_fmode = _O_BINARY;
23#endif
24
25smallint bb_got_signal;
26
27int err_win_to_posix(DWORD winerr)
28{
29 int error = ENOSYS;
30 switch(winerr) {
31 case ERROR_ACCESS_DENIED: error = EACCES; break;
32 case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
33 case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
34 case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
35 case ERROR_ALREADY_EXISTS: error = EEXIST; break;
36 case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
37 case ERROR_BAD_COMMAND: error = EIO; break;
38 case ERROR_BAD_DEVICE: error = ENODEV; break;
39 case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
40 case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
41 case ERROR_BAD_FORMAT: error = ENOEXEC; break;
42 case ERROR_BAD_LENGTH: error = EINVAL; break;
43 case ERROR_BAD_PATHNAME: error = ENOENT; break;
44 case ERROR_BAD_PIPE: error = EPIPE; break;
45 case ERROR_BAD_UNIT: error = ENODEV; break;
46 case ERROR_BAD_USERNAME: error = EINVAL; break;
47 case ERROR_BROKEN_PIPE: error = EPIPE; break;
48 case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
49 case ERROR_BUSY: error = EBUSY; break;
50 case ERROR_BUSY_DRIVE: error = EBUSY; break;
51 case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
52 case ERROR_CANNOT_MAKE: error = EACCES; break;
53 case ERROR_CANTOPEN: error = EIO; break;
54 case ERROR_CANTREAD: error = EIO; break;
55 case ERROR_CANTWRITE: error = EIO; break;
56 case ERROR_CRC: error = EIO; break;
57 case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
58 case ERROR_DEVICE_IN_USE: error = EBUSY; break;
59 case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
60 case ERROR_DIRECTORY: error = EINVAL; break;
61 case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
62 case ERROR_DISK_CHANGE: error = EIO; break;
63 case ERROR_DISK_FULL: error = ENOSPC; break;
64 case ERROR_DRIVE_LOCKED: error = EBUSY; break;
65 case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
66 case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
67 case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
68 case ERROR_FILE_EXISTS: error = EEXIST; break;
69 case ERROR_FILE_INVALID: error = ENODEV; break;
70 case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
71 case ERROR_GEN_FAILURE: error = EIO; break;
72 case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
73 case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
74 case ERROR_INVALID_ACCESS: error = EACCES; break;
75 case ERROR_INVALID_ADDRESS: error = EFAULT; break;
76 case ERROR_INVALID_BLOCK: error = EFAULT; break;
77 case ERROR_INVALID_DATA: error = EINVAL; break;
78 case ERROR_INVALID_DRIVE: error = ENODEV; break;
79 case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
80 case ERROR_INVALID_FLAGS: error = EINVAL; break;
81 case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
82 case ERROR_INVALID_HANDLE: error = EBADF; break;
83 case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
84 case ERROR_INVALID_NAME: error = EINVAL; break;
85 case ERROR_INVALID_OWNER: error = EINVAL; break;
86 case ERROR_INVALID_PARAMETER: error = EINVAL; break;
87 case ERROR_INVALID_PASSWORD: error = EPERM; break;
88 case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
89 case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
90 case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
91 case ERROR_INVALID_WORKSTATION: error = EACCES; break;
92 case ERROR_IO_DEVICE: error = EIO; break;
93 case ERROR_IO_INCOMPLETE: error = EINTR; break;
94 case ERROR_LOCKED: error = EBUSY; break;
95 case ERROR_LOCK_VIOLATION: error = EACCES; break;
96 case ERROR_LOGON_FAILURE: error = EACCES; break;
97 case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
98 case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
99 case ERROR_MORE_DATA: error = EPIPE; break;
100 case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
101 case ERROR_NOACCESS: error = EFAULT; break;
102 case ERROR_NONE_MAPPED: error = EINVAL; break;
103 case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
104 case ERROR_NOT_READY: error = EAGAIN; break;
105 case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
106 case ERROR_NO_DATA: error = EPIPE; break;
107 case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
108 case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
109 case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
110 case ERROR_OPEN_FAILED: error = EIO; break;
111 case ERROR_OPEN_FILES: error = EBUSY; break;
112 case ERROR_OPERATION_ABORTED: error = EINTR; break;
113 case ERROR_OUTOFMEMORY: error = ENOMEM; break;
114 case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
115 case ERROR_PATH_BUSY: error = EBUSY; break;
116 case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
117 case ERROR_PIPE_BUSY: error = EBUSY; break;
118 case ERROR_PIPE_CONNECTED: error = EPIPE; break;
119 case ERROR_PIPE_LISTENING: error = EPIPE; break;
120 case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
121 case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
122 case ERROR_READ_FAULT: error = EIO; break;
123 case ERROR_SEEK: error = EIO; break;
124 case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
125 case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
126 case ERROR_SHARING_VIOLATION: error = EACCES; break;
127 case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
128 case ERROR_SWAPERROR: error = ENOENT; break;
129 case ERROR_TOO_MANY_LINKS: error = EMLINK; break;
130 case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
131 case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
132 case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
133 case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
134 case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
135 case ERROR_WRITE_FAULT: error = EIO; break;
136 case ERROR_WRITE_PROTECT: error = EROFS; break;
137 }
138 return error;
139}
140
141#undef open
142int mingw_open (const char *filename, int oflags, ...)
143{
144 va_list args;
145 unsigned mode;
146 int fd;
147
148 va_start(args, oflags);
149 mode = va_arg(args, int);
150 va_end(args);
151
152 if (oflags & O_NONBLOCK) {
153 oflags &= ~O_NONBLOCK;
154 }
155 if (filename && !strcmp(filename, "/dev/null"))
156 filename = "nul";
157 fd = open(filename, oflags, mode);
158 if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
159 DWORD attrs = GetFileAttributes(filename);
160 if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
161 errno = EISDIR;
162 }
163 return fd;
164}
165
166#undef fopen
167FILE *mingw_fopen (const char *filename, const char *otype)
168{
169 if (filename && !strcmp(filename, "/dev/null"))
170 filename = "nul";
171 return fopen(filename, otype);
172}
173
174#undef dup2
175int mingw_dup2 (int fd, int fdto)
176{
177 int ret = dup2(fd, fdto);
178 return ret != -1 ? fdto : -1;
179}
180
181/*
182 * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
183 * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
184 */
185static inline long long filetime_to_hnsec(const FILETIME *ft)
186{
187 long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
188 /* Windows to Unix Epoch conversion */
189 return winTime - 116444736000000000LL;
190}
191
192static inline time_t filetime_to_time_t(const FILETIME *ft)
193{
194 return (time_t)(filetime_to_hnsec(ft) / 10000000);
195}
196
197static inline int file_attr_to_st_mode (DWORD attr)
198{
199 int fMode = S_IREAD;
200 if (attr & FILE_ATTRIBUTE_DIRECTORY)
201 fMode |= S_IFDIR|S_IWRITE|S_IEXEC;
202 else
203 fMode |= S_IFREG;
204 if (!(attr & FILE_ATTRIBUTE_READONLY))
205 fMode |= S_IWRITE;
206 return fMode;
207}
208
209static inline int get_file_attr(const char *fname, WIN32_FILE_ATTRIBUTE_DATA *fdata)
210{
211 if (GetFileAttributesExA(fname, GetFileExInfoStandard, fdata))
212 return 0;
213
214 switch (GetLastError()) {
215 case ERROR_ACCESS_DENIED:
216 case ERROR_SHARING_VIOLATION:
217 case ERROR_LOCK_VIOLATION:
218 case ERROR_SHARING_BUFFER_EXCEEDED:
219 return EACCES;
220 case ERROR_BUFFER_OVERFLOW:
221 return ENAMETOOLONG;
222 case ERROR_NOT_ENOUGH_MEMORY:
223 return ENOMEM;
224 default:
225 return ENOENT;
226 }
227}
228
229/* We keep the do_lstat code in a separate function to avoid recursion.
230 * When a path ends with a slash, the stat will fail with ENOENT. In
231 * this case, we strip the trailing slashes and stat again.
232 *
233 * If follow is true then act like stat() and report on the link
234 * target. Otherwise report on the link itself.
235 */
236static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf)
237{
238 int err;
239 WIN32_FILE_ATTRIBUTE_DATA fdata;
240 mode_t usermode;
241
242 if (!(err = get_file_attr(file_name, &fdata))) {
243 int len = strlen(file_name);
244
245 buf->st_ino = 0;
246 buf->st_uid = DEFAULT_UID;
247 buf->st_gid = DEFAULT_GID;
248 buf->st_nlink = 1;
249 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
250 if (len > 4 && (!strcasecmp(file_name+len-4, ".exe") ||
251 !strcasecmp(file_name+len-4, ".com")))
252 buf->st_mode |= S_IEXEC;
253 buf->st_size = fdata.nFileSizeLow |
254 (((off64_t)fdata.nFileSizeHigh)<<32);
255 buf->st_dev = buf->st_rdev = 0; /* not used by Git */
256 buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
257 buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
258 buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
259 if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
260 WIN32_FIND_DATAA findbuf;
261 HANDLE handle = FindFirstFileA(file_name, &findbuf);
262 if (handle != INVALID_HANDLE_VALUE) {
263 if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
264 (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
265 if (follow) {
266 char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
267 buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
268 } else {
269 buf->st_mode = S_IFLNK;
270 }
271 buf->st_mode |= S_IREAD;
272 if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
273 buf->st_mode |= S_IWRITE;
274 }
275 FindClose(handle);
276 }
277 }
278 usermode = buf->st_mode & S_IRWXU;
279 buf->st_mode |= (usermode >> 3) | ((usermode >> 6) & ~S_IWOTH);
280
281 /*
282 * Assume a block is 4096 bytes and calculate number of 512 byte
283 * sectors.
284 */
285 buf->st_blksize = 4096;
286 buf->st_blocks = ((buf->st_size+4095)>>12)<<3;
287 return 0;
288 }
289 errno = err;
290 return -1;
291}
292
293/* We provide our own lstat/fstat functions, since the provided
294 * lstat/fstat functions are so slow. These stat functions are
295 * tailored for Git's usage (read: fast), and are not meant to be
296 * complete. Note that Git stat()s are redirected to mingw_lstat()
297 * too, since Windows doesn't really handle symlinks that well.
298 */
299static int do_stat_internal(int follow, const char *file_name, struct mingw_stat *buf)
300{
301 int namelen;
302 char alt_name[PATH_MAX];
303
304 if (!do_lstat(follow, file_name, buf))
305 return 0;
306
307 /* if file_name ended in a '/', Windows returned ENOENT;
308 * try again without trailing slashes
309 */
310 if (errno != ENOENT)
311 return -1;
312
313 namelen = strlen(file_name);
314 if (namelen && file_name[namelen-1] != '/')
315 return -1;
316 while (namelen && file_name[namelen-1] == '/')
317 --namelen;
318 if (!namelen || namelen >= PATH_MAX)
319 return -1;
320
321 memcpy(alt_name, file_name, namelen);
322 alt_name[namelen] = 0;
323 return do_lstat(follow, alt_name, buf);
324}
325
326int mingw_lstat(const char *file_name, struct mingw_stat *buf)
327{
328 return do_stat_internal(0, file_name, buf);
329}
330int mingw_stat(const char *file_name, struct mingw_stat *buf)
331{
332 return do_stat_internal(1, file_name, buf);
333}
334
335int mingw_fstat(int fd, struct mingw_stat *buf)
336{
337 HANDLE fh = (HANDLE)_get_osfhandle(fd);
338 BY_HANDLE_FILE_INFORMATION fdata;
339
340 if (fh == INVALID_HANDLE_VALUE) {
341 errno = EBADF;
342 return -1;
343 }
344 /* direct non-file handles to MS's fstat() */
345 if (GetFileType(fh) != FILE_TYPE_DISK) {
346 struct _stati64 buf64;
347
348 if ( _fstati64(fd, &buf64) != 0 ) {
349 return -1;
350 }
351 buf->st_dev = 0;
352 buf->st_ino = 0;
353 buf->st_mode = S_IREAD|S_IWRITE;
354 buf->st_nlink = 1;
355 buf->st_uid = DEFAULT_UID;
356 buf->st_gid = DEFAULT_GID;
357 buf->st_rdev = 0;
358 buf->st_size = buf64.st_size;
359 buf->st_atime = buf64.st_atime;
360 buf->st_mtime = buf64.st_mtime;
361 buf->st_ctime = buf64.st_ctime;
362 buf->st_blksize = 4096;
363 buf->st_blocks = ((buf64.st_size+4095)>>12)<<3;
364 }
365
366 if (GetFileInformationByHandle(fh, &fdata)) {
367 buf->st_ino = 0;
368 buf->st_uid = DEFAULT_UID;
369 buf->st_gid = DEFAULT_GID;
370 /* could use fdata.nNumberOfLinks but it's inconsistent with stat */
371 buf->st_nlink = 1;
372 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
373 buf->st_size = fdata.nFileSizeLow |
374 (((off64_t)fdata.nFileSizeHigh)<<32);
375 buf->st_dev = buf->st_rdev = 0; /* not used by Git */
376 buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
377 buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
378 buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
379 buf->st_blksize = 4096;
380 buf->st_blocks = ((buf->st_size+4095)>>12)<<3;
381 return 0;
382 }
383 errno = EBADF;
384 return -1;
385}
386
387static inline void timeval_to_filetime(const struct timeval tv, FILETIME *ft)
388{
389 long long winTime = ((tv.tv_sec * 1000000LL) + tv.tv_usec) * 10LL + 116444736000000000LL;
390 ft->dwLowDateTime = winTime;
391 ft->dwHighDateTime = winTime >> 32;
392}
393
394int utimes(const char *file_name, const struct timeval tims[2])
395{
396 FILETIME mft, aft;
397 HANDLE fh;
398 DWORD flags, attrs;
399 int rc;
400
401 flags = FILE_ATTRIBUTE_NORMAL;
402
403 /* must have write permission */
404 attrs = GetFileAttributes(file_name);
405 if ( attrs != INVALID_FILE_ATTRIBUTES ) {
406 if ( attrs & FILE_ATTRIBUTE_READONLY ) {
407 /* ignore errors here; open() will report them */
408 SetFileAttributes(file_name, attrs & ~FILE_ATTRIBUTE_READONLY);
409 }
410
411 if ( attrs & FILE_ATTRIBUTE_DIRECTORY ) {
412 flags = FILE_FLAG_BACKUP_SEMANTICS;
413 }
414 }
415
416 fh = CreateFile(file_name, GENERIC_READ|GENERIC_WRITE,
417 FILE_SHARE_READ|FILE_SHARE_WRITE,
418 NULL, OPEN_EXISTING, flags, NULL);
419 if ( fh == INVALID_HANDLE_VALUE ) {
420 errno = err_win_to_posix(GetLastError());
421 rc = -1;
422 goto revert_attrs;
423 }
424
425 if (tims) {
426 timeval_to_filetime(tims[0], &aft);
427 timeval_to_filetime(tims[1], &mft);
428 }
429 else {
430 GetSystemTimeAsFileTime(&mft);
431 aft = mft;
432 }
433 if (!SetFileTime(fh, NULL, &aft, &mft)) {
434 errno = EINVAL;
435 rc = -1;
436 } else
437 rc = 0;
438 CloseHandle(fh);
439
440revert_attrs:
441 if (attrs != INVALID_FILE_ATTRIBUTES &&
442 (attrs & FILE_ATTRIBUTE_READONLY)) {
443 /* ignore errors again */
444 SetFileAttributes(file_name, attrs);
445 }
446 return rc;
447}
448
449unsigned int sleep (unsigned int seconds)
450{
451 Sleep(seconds*1000);
452 return 0;
453}
454
455int nanosleep(const struct timespec *req, struct timespec *rem)
456{
457 if (req->tv_nsec < 0 || 1000000000 <= req->tv_nsec) {
458 errno = EINVAL;
459 return -1;
460 }
461
462 Sleep(req->tv_sec*1000 + req->tv_nsec/1000000);
463
464 /* Sleep is not interruptible. So there is no remaining delay. */
465 if (rem != NULL) {
466 rem->tv_sec = 0;
467 rem->tv_nsec = 0;
468 }
469
470 return 0;
471}
472
473/*
474 * Windows' mktemp returns NULL on error whereas POSIX always returns the
475 * template and signals an error by making it an empty string.
476 */
477#undef mktemp
478char *mingw_mktemp(char *template)
479{
480 if ( mktemp(template) == NULL ) {
481 template[0] = '\0';
482 }
483
484 return template;
485}
486
487int mkstemp(char *template)
488{
489 char *filename = mktemp(template);
490 if (filename == NULL)
491 return -1;
492 return open(filename, O_RDWR | O_CREAT, 0600);
493}
494
495int gettimeofday(struct timeval *tv, void *tz UNUSED_PARAM)
496{
497 FILETIME ft;
498 long long hnsec;
499
500 GetSystemTimeAsFileTime(&ft);
501 hnsec = filetime_to_hnsec(&ft);
502 tv->tv_sec = hnsec / 10000000;
503 tv->tv_usec = (hnsec % 10000000) / 10;
504 return 0;
505}
506
507int pipe(int filedes[2])
508{
509 if (_pipe(filedes, PIPE_BUF, 0) < 0)
510 return -1;
511 return 0;
512}
513
514struct tm *gmtime_r(const time_t *timep, struct tm *result)
515{
516 /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
517 memcpy(result, gmtime(timep), sizeof(struct tm));
518 return result;
519}
520
521struct tm *localtime_r(const time_t *timep, struct tm *result)
522{
523 /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */
524 memcpy(result, localtime(timep), sizeof(struct tm));
525 return result;
526}
527
528#undef getcwd
529char *mingw_getcwd(char *pointer, int len)
530{
531 int i;
532 char *ret = getcwd(pointer, len);
533 if (!ret)
534 return ret;
535 for (i = 0; ret[i]; i++)
536 if (ret[i] == '\\')
537 ret[i] = '/';
538 return ret;
539}
540
541#undef rename
542int mingw_rename(const char *pold, const char *pnew)
543{
544 DWORD attrs;
545
546 /*
547 * Try native rename() first to get errno right.
548 * It is based on MoveFile(), which cannot overwrite existing files.
549 */
550 if (!rename(pold, pnew))
551 return 0;
552 if (errno != EEXIST)
553 return -1;
554 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
555 return 0;
556 /* TODO: translate more errors */
557 if (GetLastError() == ERROR_ACCESS_DENIED &&
558 (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
559 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
560 errno = EISDIR;
561 return -1;
562 }
563 if ((attrs & FILE_ATTRIBUTE_READONLY) &&
564 SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
565 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
566 return 0;
567 /* revert file attributes on failure */
568 SetFileAttributes(pnew, attrs);
569 }
570 }
571 errno = EACCES;
572 return -1;
573}
574
575static char *gethomedir(void)
576{
577 static char buf[PATH_MAX];
578 DWORD len = sizeof(buf);
579 HANDLE h;
580 char *s;
581
582 buf[0] = '\0';
583 if ( !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h) )
584 return buf;
585
586 if ( !GetUserProfileDirectory(h, buf, &len) ) {
587 CloseHandle(h);
588 return buf;
589 }
590
591 CloseHandle(h);
592
593 for ( s=buf; *s; ++s ) {
594 if ( *s == '\\' ) {
595 *s = '/';
596 }
597 }
598
599 return buf;
600}
601
602static char *get_user_name(void)
603{
604 static char user_name[100] = "";
605 char *s;
606 DWORD len = sizeof(user_name);
607
608 if ( user_name[0] != '\0' ) {
609 return user_name;
610 }
611
612 if ( !GetUserName(user_name, &len) ) {
613 return NULL;
614 }
615
616 for ( s=user_name; *s; ++s ) {
617 if ( *s == ' ' ) {
618 *s = '_';
619 }
620 }
621
622 return user_name;
623}
624
625struct passwd *getpwnam(const char *name)
626{
627 const char *myname;
628
629 if ( (myname=get_user_name()) != NULL &&
630 strcmp(myname, name) == 0 ) {
631 return getpwuid(DEFAULT_UID);
632 }
633
634 return NULL;
635}
636
637struct passwd *getpwuid(uid_t uid UNUSED_PARAM)
638{
639 static struct passwd p;
640
641 if ( (p.pw_name=get_user_name()) == NULL ) {
642 return NULL;
643 }
644 p.pw_passwd = (char *)"secret";
645 p.pw_gecos = (char *)"unknown";
646 p.pw_dir = gethomedir();
647 p.pw_shell = NULL;
648 p.pw_uid = DEFAULT_UID;
649 p.pw_gid = DEFAULT_GID;
650
651 return &p;
652}
653
654struct group *getgrgid(gid_t gid UNUSED_PARAM)
655{
656 static char *members[2] = { NULL, NULL };
657 static struct group g;
658
659 if ( (g.gr_name=get_user_name()) == NULL ) {
660 return NULL;
661 }
662 g.gr_passwd = (char *)"secret";
663 g.gr_gid = DEFAULT_GID;
664 members[0] = g.gr_name;
665 g.gr_mem = members;
666
667 return &g;
668}
669
670int getgrouplist(const char *user UNUSED_PARAM, gid_t group UNUSED_PARAM,
671 gid_t *groups, int *ngroups)
672{
673 if ( *ngroups == 0 ) {
674 *ngroups = 1;
675 return -1;
676 }
677
678 *ngroups = 1;
679 groups[0] = DEFAULT_GID;
680 return 1;
681}
682
683int getgroups(int n, gid_t *groups)
684{
685 if ( n == 0 ) {
686 return 1;
687 }
688
689 groups[0] = DEFAULT_GID;
690 return 1;
691}
692
693int getlogin_r(char *buf, size_t len)
694{
695 char *name;
696
697 if ( (name=get_user_name()) == NULL ) {
698 return -1;
699 }
700
701 if ( strlen(name) >= len ) {
702 errno = ERANGE;
703 return -1;
704 }
705
706 strcpy(buf, name);
707 return 0;
708}
709
710long sysconf(int name)
711{
712 if ( name == _SC_CLK_TCK ) {
713 return 100;
714 }
715 errno = EINVAL;
716 return -1;
717}
718
719clock_t times(struct tms *buf)
720{
721 buf->tms_utime = 0;
722 buf->tms_stime = 0;
723 buf->tms_cutime = 0;
724 buf->tms_cstime = 0;
725
726 return 0;
727}
728
729int link(const char *oldpath, const char *newpath)
730{
731 typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
732 static T create_hard_link = NULL;
733 if (!create_hard_link) {
734 create_hard_link = (T) GetProcAddress(
735 GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
736 if (!create_hard_link)
737 create_hard_link = (T)-1;
738 }
739 if (create_hard_link == (T)-1) {
740 errno = ENOSYS;
741 return -1;
742 }
743 if (!create_hard_link(newpath, oldpath, NULL)) {
744 errno = err_win_to_posix(GetLastError());
745 return -1;
746 }
747 return 0;
748}
749
750char *realpath(const char *path, char *resolved_path)
751{
752 /* FIXME: need normalization */
753 return strcpy(resolved_path, path);
754}
755
756const char *get_busybox_exec_path(void)
757{
758 static char path[PATH_MAX] = "";
759
760 if (!*path)
761 GetModuleFileName(NULL, path, PATH_MAX);
762 return path;
763}
764
765#undef mkdir
766int mingw_mkdir(const char *path, int mode UNUSED_PARAM)
767{
768 int ret;
769 struct stat st;
770 int lerrno = 0;
771
772 if ( (ret=mkdir(path)) < 0 ) {
773 lerrno = errno;
774 if ( lerrno == EACCES && stat(path, &st) == 0 ) {
775 ret = 0;
776 lerrno = 0;
777 }
778 }
779
780 errno = lerrno;
781 return ret;
782}
783
784#undef chmod
785int mingw_chmod(const char *path, int mode)
786{
787 WIN32_FILE_ATTRIBUTE_DATA fdata;
788
789 if ( get_file_attr(path, &fdata) == 0 &&
790 fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
791 mode |= 0222;
792 }
793
794 return chmod(path, mode);
795}
796
797int fcntl(int fd, int cmd, ...)
798{
799 va_list arg;
800 int result = -1;
801 char *fds;
802 int target, i, newfd;
803
804 va_start(arg, cmd);
805
806 switch (cmd) {
807 case F_GETFD:
808 case F_SETFD:
809 case F_GETFL:
810 /*
811 * Our fake F_GETFL won't matter if the return value is used as
812 * fcntl(fd, F_SETFL, ret|something);
813 * because F_SETFL isn't supported either.
814 */
815 result = 0;
816 break;
817 case F_DUPFD:
818 target = va_arg(arg, int);
819 fds = xzalloc(target);
820 while ((newfd = dup(fd)) < target && newfd >= 0) {
821 fds[newfd] = 1;
822 }
823 for (i = 0; i < target; ++i) {
824 if (fds[i]) {
825 close(i);
826 }
827 }
828 free(fds);
829 result = newfd;
830 break;
831 default:
832 errno = ENOSYS;
833 break;
834 }
835
836 va_end(arg);
837 return result;
838}
839
840#undef unlink
841int mingw_unlink(const char *pathname)
842{
843 /* read-only files cannot be removed */
844 chmod(pathname, 0666);
845 return unlink(pathname);
846}
847
848#undef strftime
849size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm)
850{
851 size_t ret;
852 char day[3];
853 char *t;
854 char *fmt, *newfmt;
855 struct tm tm2;
856 int m;
857
858 /*
859 * Emulate the '%e' and '%s' formats that Windows' strftime lacks.
860 * Happily, the string that replaces '%e' is two characters long.
861 * '%s' is a bit more complicated.
862 */
863 fmt = xstrdup(format);
864 for ( t=fmt; *t; ++t ) {
865 if ( *t == '%' ) {
866 if ( t[1] == 'e' ) {
867 if ( tm->tm_mday >= 0 && tm->tm_mday <= 99 ) {
868 sprintf(day, "%2d", tm->tm_mday);
869 }
870 else {
871 strcpy(day, " ");
872 }
873 memcpy(t++, day, 2);
874 }
875 else if ( t[1] == 's' ) {
876 *t = '\0';
877 m = t - fmt;
878 tm2 = *tm;
879 newfmt = xasprintf("%s%d%s", fmt, (int)mktime(&tm2), t+2);
880 free(fmt);
881 t = newfmt + m + 1;
882 fmt = newfmt;
883 }
884 else if ( t[1] == 'z' ) {
885 char buffer[16] = "";
886
887 *t = '\0';
888 m = t - fmt;
889 _tzset();
890 if ( tm->tm_isdst >= 0 ) {
891 int offset = (int)_timezone - (tm->tm_isdst > 0 ? 3600 : 0);
892 int hr, min;
893
894 if ( offset > 0 ) {
895 buffer[0] = '-';
896 }
897 else {
898 buffer[0] = '+';
899 offset = -offset;
900 }
901
902 hr = offset / 3600;
903 min = (offset % 3600) / 60;
904 sprintf(buffer+1, "%02d%02d", hr, min);
905 }
906 newfmt = xasprintf("%s%s%s", fmt, buffer, t+2);
907 free(fmt);
908 t = newfmt + m + 1;
909 fmt = newfmt;
910 }
911 else if ( t[1] != '\0' ) {
912 ++t;
913 }
914 }
915 }
916
917 ret = strftime(buf, max, fmt, tm);
918 free(fmt);
919
920 return ret;
921}
922
923int stime(time_t *t UNUSED_PARAM)
924{
925 errno = EPERM;
926 return -1;
927}
928
929#undef access
930int mingw_access(const char *name, int mode)
931{
932 int ret;
933 struct stat s;
934 int fd, n, sig;
935 unsigned int offset;
936 unsigned char buf[1024];
937
938 /* Windows can only handle test for existence, read or write */
939 if (mode == F_OK || (mode & ~X_OK)) {
940 ret = _access(name, mode & ~X_OK);
941 if (ret < 0 || !(mode & X_OK)) {
942 return ret;
943 }
944 }
945
946 if (!mingw_stat(name, &s) && S_ISREG(s.st_mode)) {
947
948 /* stat marks .exe and .com files as executable */
949 if ((s.st_mode&S_IEXEC)) {
950 return 0;
951 }
952
953 fd = open(name, O_RDONLY);
954 if (fd < 0)
955 return -1;
956 n = read(fd, buf, sizeof(buf)-1);
957 close(fd);
958 if (n < 4) /* at least '#!/x' and not error */
959 return -1;
960
961 /* shell script */
962 if (buf[0] == '#' && buf[1] == '!') {
963 return 0;
964 }
965
966 /*
967 * Poke about in file to see if it's a PE binary. I've just copied
968 * the magic from the file command.
969 */
970 if (buf[0] == 'M' && buf[1] == 'Z') {
971 offset = (buf[0x19] << 8) + buf[0x18];
972 if (offset > 0x3f) {
973 offset = (buf[0x3f] << 24) + (buf[0x3e] << 16) +
974 (buf[0x3d] << 8) + buf[0x3c];
975 if (offset < sizeof(buf)-100) {
976 if (memcmp(buf+offset, "PE\0\0", 4) == 0) {
977 sig = (buf[offset+25] << 8) + buf[offset+24];
978 if (sig == 0x10b || sig == 0x20b) {
979 sig = (buf[offset+23] << 8) + buf[offset+22];
980 if ((sig & 0x2000) != 0) {
981 /* DLL */
982 return -1;
983 }
984 sig = buf[offset+92];
985 return !(sig == 1 || sig == 2 ||
986 sig == 3 || sig == 7);
987 }
988 }
989 }
990 }
991 }
992 }
993
994 return -1;
995}
996
997#undef rmdir
998int mingw_rmdir(const char *path)
999{
1000 /* read-only directories cannot be removed */
1001 chmod(path, 0666);
1002 return rmdir(path);
1003}
1004
1005/* check if path can be made into an executable by adding a suffix;
1006 * return an allocated string containing the path if it can;
1007 * return NULL if not.
1008 *
1009 * if path already has a suffix don't even bother trying
1010 */
1011char *file_is_win32_executable(const char *p)
1012{
1013 char *path;
1014 int len = strlen(p);
1015
1016 if (len > 4 && (!strcasecmp(p+len-4, ".exe") ||
1017 !strcasecmp(p+len-4, ".com"))) {
1018 return NULL;
1019 }
1020
1021 if ( (path=malloc(len+5)) != NULL ) {
1022 memcpy(path, p, len);
1023 memcpy(path+len, ".exe", 5);
1024 if (file_is_executable(path)) {
1025 return path;
1026 }
1027 memcpy(path+len, ".com", 5);
1028 if (file_is_executable(path)) {
1029 return path;
1030 }
1031 free(path);
1032 }
1033
1034 return NULL;
1035}
1036
1037#undef opendir
1038DIR *mingw_opendir(const char *path)
1039{
1040 char name[4];
1041
1042 if (isalpha(path[0]) && path[1] == ':' && path[2] == '\0') {
1043 strcpy(name, path);
1044 name[2] = '/';
1045 name[3] = '\0';
1046 path = name;
1047 }
1048
1049 return opendir(path);
1050}
1051
1052off_t mingw_lseek(int fd, off_t offset, int whence)
1053{
1054 HANDLE h = (HANDLE)_get_osfhandle(fd);
1055 if (h == INVALID_HANDLE_VALUE) {
1056 errno = EBADF;
1057 return -1;
1058 }
1059 if (GetFileType(h) != FILE_TYPE_DISK) {
1060 errno = ESPIPE;
1061 return -1;
1062 }
1063 return _lseeki64(fd, offset, whence);
1064}
diff --git a/win32/mntent.c b/win32/mntent.c
new file mode 100644
index 000000000..9b04a9c5e
--- /dev/null
+++ b/win32/mntent.c
@@ -0,0 +1,69 @@
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 char mnt_type[100];
32 static char mnt_opts[4];
33 static struct mntent my_mount_entry =
34 { mnt_fsname, mnt_dir, mnt_type, mnt_opts, 0, 0 };
35 struct mntent *entry;
36
37 entry = NULL;
38 while ( ++data->index < 26 ) {
39 if ( (data->flags & 1<<data->index) != 0 ) {
40 mnt_fsname[0] = 'A' + data->index;
41 mnt_fsname[1] = ':';
42 mnt_fsname[2] = '\0';
43 mnt_dir[0] = 'A' + data->index;
44 mnt_dir[1] = ':';
45 mnt_dir[2] = '\\';
46 mnt_dir[3] = '\0';
47 mnt_type[0] = '\0';
48 mnt_opts[0] = '\0';
49
50 if ( GetDriveType(mnt_dir) == DRIVE_FIXED ) {
51 if ( !GetVolumeInformation(mnt_dir, NULL, 0, NULL, NULL,
52 NULL, mnt_type, 100) ) {
53 mnt_type[0] = '\0';
54 }
55
56 entry = &my_mount_entry;
57 break;
58 }
59 }
60 }
61
62 return entry;
63}
64
65int endmntent(FILE *stream)
66{
67 free(stream);
68 return 0;
69}
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..2341119b0
--- /dev/null
+++ b/win32/net.c
@@ -0,0 +1,101 @@
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((intptr_t)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, const struct sockaddr *sa, size_t sz)
51{
52 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
53 return connect(s, sa, sz);
54}
55
56#undef bind
57int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
58{
59 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
60 return bind(s, sa, sz);
61}
62
63#undef setsockopt
64int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
65{
66 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
67 return setsockopt(s, lvl, optname, (const char*)optval, optlen);
68}
69
70#undef shutdown
71int mingw_shutdown(int sockfd, int how)
72{
73 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
74 return shutdown(s, how);
75}
76
77#undef listen
78int mingw_listen(int sockfd, int backlog)
79{
80 SOCKET s = (SOCKET)_get_osfhandle(sockfd);
81 return listen(s, backlog);
82}
83
84#undef accept
85int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
86{
87 int sockfd2;
88
89 SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
90 SOCKET s2 = accept(s1, sa, sz);
91
92 /* convert into a file descriptor */
93 if ((sockfd2 = _open_osfhandle((intptr_t)s2, O_RDWR|O_BINARY)) < 0) {
94 int err = errno;
95 closesocket(s2);
96 bb_error_msg("unable to make a socket file descriptor: %s",
97 strerror(err));
98 return -1;
99 }
100 return sockfd2;
101}
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..6b8e52ca9
--- /dev/null
+++ b/win32/popen.c
@@ -0,0 +1,318 @@
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
29static pipe_data *find_pipe(void)
30{
31 int i;
32 pipe_data *p = NULL;
33
34 /* find an unused pipe structure */
35 for ( i=0; i<num_pipes; ++i ) {
36 if ( pipes[i].mode == '\0' ) {
37 p = pipes+i;
38 break;
39 }
40 }
41
42 if ( p == NULL ) {
43 /* need to extend array */
44 if ( (p=realloc(pipes, sizeof(pipe_data)*(num_pipes+10))) == NULL ) {
45 return NULL;
46 }
47
48 pipes = p;
49 for ( i=0; i<10; ++i ) {
50 memset(pipes+num_pipes+i, 0, sizeof(pipe_data));
51 }
52 p = pipes + num_pipes;
53 num_pipes += 10;
54 }
55
56 p->pipe[0] = INVALID_HANDLE_VALUE;
57 p->pipe[1] = INVALID_HANDLE_VALUE;
58
59 return p;
60}
61
62FILE *mingw_popen(const char *cmd, const char *mode)
63{
64 pipe_data *p;
65 FILE *fptr = NULL;
66 STARTUPINFO siStartInfo;
67 int success;
68 int fd;
69 int len, count;
70 int ip, ic;
71 char *cmd_buff = NULL;
72 const char *s;
73 char *t;
74
75 if ( cmd == NULL || *cmd == '\0' || mode == NULL ||
76 (*mode != 'r' && *mode != 'w') ) {
77 return NULL;
78 }
79
80 /* find an unused pipe structure */
81 if ( (p=find_pipe()) == NULL ) {
82 return NULL;
83 }
84
85 /* count double quotes */
86 count = 0;
87 for ( s=cmd; *s; ++s ) {
88 if ( *s == '"' ) {
89 ++count;
90 }
91 }
92
93 len = strlen(cmd) + 10 + count;
94 if ( (cmd_buff=malloc(len)) == NULL ) {
95 return NULL;
96 }
97
98 /* escape double quotes */
99 strcpy(cmd_buff, "sh -c \"");
100 for ( s=cmd,t=cmd_buff+strlen(cmd_buff); *s; ++s ) {
101 if ( *s == '"' ) {
102 *t++ = '\\';
103 }
104 *t++ = *s;
105 }
106 *t++ = '"';
107 *t = '\0';
108
109 /* Create the pipe */
110 if ( mingw_pipe(p->pipe) == -1 ) {
111 goto finito;
112 }
113
114 /* index of parent end of pipe */
115 ip = !(*mode == 'r');
116 /* index of child end of pipe */
117 ic = (*mode == 'r');
118
119 /* Make the parent end of the pipe non-inheritable */
120 SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0);
121
122 /* Now create the child process */
123 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
124 siStartInfo.cb = sizeof(STARTUPINFO);
125 if ( *mode == 'r' ) {
126 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
127 siStartInfo.hStdOutput = p->pipe[ic];
128 }
129 else {
130 siStartInfo.hStdInput = p->pipe[ic];
131 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
132 }
133 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
134 siStartInfo.wShowWindow = SW_HIDE;
135 siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
136
137 success = CreateProcess(NULL,
138 (LPTSTR)cmd_buff, /* command line */
139 NULL, /* process security attributes */
140 NULL, /* primary thread security attributes */
141 TRUE, /* handles are inherited */
142 0, /* creation flags */
143 NULL, /* use parent's environment */
144 NULL, /* use parent's current directory */
145 &siStartInfo, /* STARTUPINFO pointer */
146 &p->piProcInfo); /* receives PROCESS_INFORMATION */
147
148 if ( !success ) {
149 goto finito;
150 }
151
152 /* close child end of pipe */
153 CloseHandle(p->pipe[ic]);
154 p->pipe[ic] = INVALID_HANDLE_VALUE;
155
156 if ( *mode == 'r' ) {
157 fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_RDONLY|_O_BINARY);
158 fptr = _fdopen(fd, "rb");
159 }
160 else {
161 fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_WRONLY|_O_BINARY);
162 fptr = _fdopen(fd, "wb");
163 }
164
165finito:
166 if ( !fptr ) {
167 if ( p->pipe[0] != INVALID_HANDLE_VALUE ) {
168 CloseHandle(p->pipe[0]);
169 }
170 if ( p->pipe[1] != INVALID_HANDLE_VALUE ) {
171 CloseHandle(p->pipe[1]);
172 }
173 }
174 else {
175 p->mode = *mode;
176 p->fd = fd;
177 }
178 free(cmd_buff);
179
180 return fptr;
181}
182
183/*
184 * Open a pipe to a command where the file descriptor fd0 is used
185 * as input to the command (read mode) or as the destination of the
186 * output from the command (write mode). The pid of the command is
187 * returned in the variable pid, which can be NULL.
188 */
189int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid)
190{
191 pipe_data *p;
192 STARTUPINFO siStartInfo;
193 int success;
194 int fd = -1;
195 int ip, ic;
196
197 if ( cmd == NULL || *cmd == '\0' || mode == NULL ||
198 (*mode != 'r' && *mode != 'w') ) {
199 return -1;
200 }
201
202 /* find an unused pipe structure */
203 if ( (p=find_pipe()) == NULL ) {
204 return -1;
205 }
206
207 /* Create the pipe */
208 if ( mingw_pipe(p->pipe) == -1 ) {
209 goto finito;
210 }
211
212 /* index of parent end of pipe */
213 ip = !(*mode == 'r');
214 /* index of child end of pipe */
215 ic = (*mode == 'r');
216
217 /* Make the parent end of the pipe non-inheritable */
218 SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0);
219
220 /* Now create the child process */
221 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
222 siStartInfo.cb = sizeof(STARTUPINFO);
223 if ( *mode == 'r' ) {
224 siStartInfo.hStdInput = (HANDLE)_get_osfhandle(fd0);
225 siStartInfo.hStdOutput = p->pipe[ic];
226 }
227 else {
228 siStartInfo.hStdInput = p->pipe[ic];
229 siStartInfo.hStdOutput = (HANDLE)_get_osfhandle(fd0);
230 }
231 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
232 siStartInfo.wShowWindow = SW_HIDE;
233 siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
234
235 success = CreateProcess(NULL,
236 (LPTSTR)cmd, /* command line */
237 NULL, /* process security attributes */
238 NULL, /* primary thread security attributes */
239 TRUE, /* handles are inherited */
240 0, /* creation flags */
241 NULL, /* use parent's environment */
242 NULL, /* use parent's current directory */
243 &siStartInfo, /* STARTUPINFO pointer */
244 &p->piProcInfo); /* receives PROCESS_INFORMATION */
245
246 if ( !success ) {
247 goto finito;
248 }
249
250 /* close child end of pipe */
251 CloseHandle(p->pipe[ic]);
252 p->pipe[ic] = INVALID_HANDLE_VALUE;
253
254 if ( *mode == 'r' ) {
255 fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_RDONLY|_O_BINARY);
256 }
257 else {
258 fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_WRONLY|_O_BINARY);
259 }
260
261finito:
262 if ( fd == -1 ) {
263 if ( p->pipe[0] != INVALID_HANDLE_VALUE ) {
264 CloseHandle(p->pipe[0]);
265 }
266 if ( p->pipe[1] != INVALID_HANDLE_VALUE ) {
267 CloseHandle(p->pipe[1]);
268 }
269 }
270 else {
271 p->mode = *mode;
272 p->fd = fd;
273 if ( pid ) {
274 *pid = (pid_t)p->piProcInfo.dwProcessId;
275 }
276 }
277
278 return fd;
279}
280
281int mingw_pclose(FILE *fp)
282{
283 int i, ip, fd;
284 pipe_data *p = NULL;
285 DWORD ret;
286
287 if ( fp == NULL ) {
288 return -1;
289 }
290
291 /* find struct containing fd */
292 fd = fileno(fp);
293 for ( i=0; i<num_pipes; ++i ) {
294 if ( pipes[i].mode && pipes[i].fd == fd ) {
295 p = pipes+i;
296 break;
297 }
298 }
299
300 if ( p == NULL ) {
301 /* no pipe data, maybe fd isn't a pipe? */
302 return -1;
303 }
304
305 fclose(fp);
306
307 ip = !(p->mode == 'r');
308 CloseHandle(p->pipe[ip]);
309
310 ret = WaitForSingleObject(p->piProcInfo.hProcess, INFINITE);
311
312 CloseHandle(p->piProcInfo.hProcess);
313 CloseHandle(p->piProcInfo.hThread);
314
315 p->mode = '\0';
316
317 return (ret == WAIT_OBJECT_0) ? 0 : -1;
318}
diff --git a/win32/process.c b/win32/process.c
new file mode 100644
index 000000000..968ea9afd
--- /dev/null
+++ b/win32/process.c
@@ -0,0 +1,425 @@
1#include "libbb.h"
2#include <tlhelp32.h>
3
4int waitpid(pid_t pid, int *status, int options)
5{
6 HANDLE proc;
7 intptr_t ret;
8
9 /* Windows does not understand parent-child */
10 if (pid > 0 && options == 0) {
11 if ( (proc=OpenProcess(SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
12 FALSE, pid)) != NULL ) {
13 ret = _cwait(status, (intptr_t)proc, 0);
14 CloseHandle(proc);
15 return ret == -1 ? -1 : pid;
16 }
17 }
18 errno = EINVAL;
19 return -1;
20}
21
22const char *
23next_path_sep(const char *path)
24{
25 static const char *from = NULL, *to;
26 static int has_semicolon;
27 int len = strlen(path);
28
29 if (!from || !(path >= from && path+len <= to)) {
30 from = path;
31 to = from+len;
32 has_semicolon = strchr(path, ';') != NULL;
33 }
34
35 /* Semicolons take precedence, it's Windows PATH */
36 if (has_semicolon)
37 return strchr(path, ';');
38 /* PATH=C:, not really a separator */
39 return strchr(has_dos_drive_prefix(path) ? path+2 : path, ':');
40}
41
42#define MAX_OPT 10
43
44static const char *
45parse_interpreter(const char *cmd, char ***opts, int *nopts)
46{
47 static char buf[100], *opt[MAX_OPT];
48 char *p, *s, *t;
49 int n, fd;
50
51 *nopts = 0;
52 *opts = opt;
53
54 /* don't even try a .exe */
55 n = strlen(cmd);
56 if (n >= 4 &&
57 (!strcasecmp(cmd+n-4, ".exe") ||
58 !strcasecmp(cmd+n-4, ".com")))
59 return NULL;
60
61 fd = open(cmd, O_RDONLY);
62 if (fd < 0)
63 return NULL;
64 n = read(fd, buf, sizeof(buf)-1);
65 close(fd);
66 if (n < 4) /* at least '#!/x' and not error */
67 return NULL;
68
69 /*
70 * See http://www.in-ulm.de/~mascheck/various/shebang/ for trivia
71 * relating to '#!'.
72 */
73 if (buf[0] != '#' || buf[1] != '!')
74 return NULL;
75 buf[n] = '\0';
76 p = strchr(buf, '\n');
77 if (!p)
78 return NULL;
79 *p = '\0';
80
81 /* remove trailing whitespace */
82 while ( isspace(*--p) ) {
83 *p = '\0';
84 }
85
86 /* skip whitespace after '#!' */
87 for ( s=buf+2; *s && isspace(*s); ++s ) {
88 }
89
90 /* move to end of interpreter path (which may not contain spaces) */
91 for ( ; *s && !isspace(*s); ++s ) {
92 }
93
94 n = 0;
95 if ( *s != '\0' ) {
96 /* there are options */
97 *s++ = '\0';
98
99 while ( (t=strtok(s, " \t")) && n < MAX_OPT ) {
100 s = NULL;
101 opt[n++] = t;
102 }
103 }
104
105 /* find interpreter name */
106 if (!(p = strrchr(buf+2, '/')))
107 return NULL;
108
109 *nopts = n;
110 *opts = opt;
111
112 return p+1;
113}
114
115/*
116 * See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
117 * (Parsing C++ Command-Line Arguments)
118 */
119static char *
120quote_arg(const char *arg)
121{
122 int len = 0, n = 0;
123 int force_quotes = 0;
124 char *q, *d;
125 const char *p = arg;
126
127 /* empty arguments must be quoted */
128 if (!*p) {
129 force_quotes = 1;
130 }
131
132 while (*p) {
133 if (isspace(*p)) {
134 /* arguments containing whitespace must be quoted */
135 force_quotes = 1;
136 }
137 else if (*p == '"') {
138 /* double quotes in arguments need to be escaped */
139 n++;
140 }
141 else if (*p == '\\') {
142 /* count contiguous backslashes */
143 int count = 0;
144 while (*p == '\\') {
145 count++;
146 p++;
147 len++;
148 }
149
150 /*
151 * Only escape backslashes before explicit double quotes or
152 * or where the backslashes are at the end of an argument
153 * that is scheduled to be quoted.
154 */
155 if (*p == '"' || (force_quotes && *p == '\0')) {
156 n += count*2 + 1;
157 }
158
159 if (*p == '\0') {
160 break;
161 }
162 continue;
163 }
164 len++;
165 p++;
166 }
167
168 if (!force_quotes && n == 0) {
169 return (char*)arg;
170 }
171
172 /* insert double quotes and backslashes where necessary */
173 d = q = xmalloc(len+n+3);
174 if (force_quotes) {
175 *d++ = '"';
176 }
177
178 while (*arg) {
179 if (*arg == '"') {
180 *d++ = '\\';
181 }
182 else if (*arg == '\\') {
183 int count = 0;
184 while (*arg == '\\') {
185 count++;
186 *d++ = *arg++;
187 }
188
189 if (*arg == '"' || (force_quotes && *arg == '\0')) {
190 while (count-- > 0) {
191 *d++ = '\\';
192 }
193 if (*arg == '"') {
194 *d++ = '\\';
195 }
196 }
197 }
198 if (*arg != '\0') {
199 *d++ = *arg++;
200 }
201 }
202 if (force_quotes) {
203 *d++ = '"';
204 }
205 *d = '\0';
206
207 return q;
208}
209
210static intptr_t
211spawnveq(int mode, const char *path, const char *const *argv, const char *const *env)
212{
213 char **new_argv;
214 int i, argc = 0;
215 intptr_t ret;
216
217 if (!argv) {
218 const char *empty_argv[] = { path, NULL };
219 return spawnve(mode, path, empty_argv, env);
220 }
221
222
223 while (argv[argc])
224 argc++;
225
226 new_argv = malloc(sizeof(*argv)*(argc+1));
227 for (i = 0;i < argc;i++)
228 new_argv[i] = quote_arg(argv[i]);
229 new_argv[argc] = NULL;
230 ret = spawnve(mode, path, (const char *const *)new_argv, env);
231 for (i = 0;i < argc;i++)
232 if (new_argv[i] != argv[i])
233 free(new_argv[i]);
234 free(new_argv);
235 return ret;
236}
237
238#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE
239static intptr_t
240mingw_spawn_applet(int mode,
241 const char *const *argv,
242 const char *const *envp)
243{
244 return spawnveq(mode, bb_busybox_exec_path, argv, envp);
245}
246#endif
247
248static intptr_t
249mingw_spawn_interpreter(int mode, const char *prog, const char *const *argv, const char *const *envp)
250{
251 intptr_t ret;
252 char **opts;
253 int nopts;
254 const char *interpr = parse_interpreter(prog, &opts, &nopts);
255 const char **new_argv;
256 int argc = 0;
257
258 if (!interpr)
259 return spawnveq(mode, prog, argv, envp);
260
261
262 while (argv[argc])
263 argc++;
264 new_argv = malloc(sizeof(*argv)*(argc+nopts+2));
265 memcpy(new_argv+1, opts, sizeof(*opts)*nopts);
266 memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc);
267 new_argv[nopts+1] = prog; /* pass absolute path */
268
269#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE
270 if (find_applet_by_name(interpr) >= 0) {
271 new_argv[0] = interpr;
272 ret = mingw_spawn_applet(mode, new_argv, envp);
273 } else
274#endif
275 {
276 char *path = xstrdup(getenv("PATH"));
277 char *tmp = path;
278 char *iprog = find_executable(interpr, &tmp);
279 free(path);
280 if (!iprog) {
281 free(new_argv);
282 errno = ENOENT;
283 return -1;
284 }
285 new_argv[0] = iprog;
286 ret = spawnveq(mode, iprog, new_argv, envp);
287 free(iprog);
288 }
289
290 free(new_argv);
291 return ret;
292}
293
294static intptr_t
295mingw_spawn_1(int mode, const char *cmd, const char *const *argv, const char *const *envp)
296{
297 intptr_t ret;
298
299#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE
300 if (find_applet_by_name(cmd) >= 0)
301 return mingw_spawn_applet(mode, argv, envp);
302 else
303#endif
304 if (strchr(cmd, '/') || strchr(cmd, '\\'))
305 return mingw_spawn_interpreter(mode, cmd, argv, envp);
306 else {
307 char *tmp, *path = getenv("PATH");
308 char *prog;
309
310 if (!path) {
311 errno = ENOENT;
312 return -1;
313 }
314
315 /* executable_exists() does not return new file name */
316 tmp = path = xstrdup(path);
317 prog = find_executable(cmd, &tmp);
318 free(path);
319 if (!prog) {
320 errno = ENOENT;
321 return -1;
322 }
323 ret = mingw_spawn_interpreter(mode, prog, argv, envp);
324 free(prog);
325 }
326 return ret;
327}
328
329pid_t FAST_FUNC
330mingw_spawn(char **argv)
331{
332 intptr_t ret;
333
334 ret = mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)argv,
335 (const char *const *)environ);
336
337 return ret == -1 ? -1 : GetProcessId((HANDLE)ret);
338}
339
340intptr_t FAST_FUNC
341mingw_spawn_proc(char **argv)
342{
343 return mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)argv,
344 (const char *const *)environ);
345}
346
347int
348mingw_execvp(const char *cmd, const char *const *argv)
349{
350 int ret = (int)mingw_spawn_1(P_WAIT, cmd, argv, (const char *const *)environ);
351 if (ret != -1)
352 exit(ret);
353 return ret;
354}
355
356int
357mingw_execve(const char *cmd, const char *const *argv, const char *const *envp)
358{
359 int ret;
360 int mode = P_WAIT;
361
362 ret = (int)mingw_spawn_interpreter(mode, cmd, argv, envp);
363 if (ret != -1)
364 exit(ret);
365 return ret;
366}
367
368int
369mingw_execv(const char *cmd, const char *const *argv)
370{
371 return mingw_execve(cmd, argv, (const char *const *)environ);
372}
373
374/* POSIX version in libbb/procps.c */
375procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags UNUSED_PARAM)
376{
377 PROCESSENTRY32 pe;
378
379 pe.dwSize = sizeof(pe);
380 if (!sp) {
381 sp = xzalloc(sizeof(struct procps_status_t));
382 sp->snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
383 if (sp->snapshot == INVALID_HANDLE_VALUE) {
384 free(sp);
385 return NULL;
386 }
387 if (!Process32First(sp->snapshot, &pe)) {
388 CloseHandle(sp->snapshot);
389 free(sp);
390 return NULL;
391 }
392 }
393 else {
394 if (!Process32Next(sp->snapshot, &pe)) {
395 CloseHandle(sp->snapshot);
396 free(sp);
397 return NULL;
398 }
399 }
400
401 sp->pid = pe.th32ProcessID;
402 safe_strncpy(sp->comm, pe.szExeFile, COMM_LEN);
403 return sp;
404}
405
406int kill(pid_t pid, int sig)
407{
408 HANDLE h;
409
410 if (pid > 0 && sig == SIGTERM) {
411 if ((h=OpenProcess(PROCESS_TERMINATE, FALSE, pid)) != NULL &&
412 TerminateProcess(h, 0)) {
413 CloseHandle(h);
414 return 0;
415 }
416
417 errno = err_win_to_posix(GetLastError());
418 if (h != NULL)
419 CloseHandle(h);
420 return -1;
421 }
422
423 errno = EINVAL;
424 return -1;
425}
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/regcomp.c b/win32/regcomp.c
new file mode 100644
index 000000000..dca7e6ef3
--- /dev/null
+++ b/win32/regcomp.c
@@ -0,0 +1,3886 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2007,2009,2010 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA. */
20
21#define UNUSED_PARAM __attribute__ ((__unused__))
22
23static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
24 size_t length, reg_syntax_t syntax);
25static void re_compile_fastmap_iter (regex_t *bufp,
26 const re_dfastate_t *init_state,
27 char *fastmap);
28static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len);
29#ifdef RE_ENABLE_I18N
30static void free_charset (re_charset_t *cset);
31#endif /* RE_ENABLE_I18N */
32static void free_workarea_compile (regex_t *preg);
33static reg_errcode_t create_initial_state (re_dfa_t *dfa);
34#ifdef RE_ENABLE_I18N
35static void optimize_utf8 (re_dfa_t *dfa);
36#endif
37static reg_errcode_t analyze (regex_t *preg);
38static reg_errcode_t preorder (bin_tree_t *root,
39 reg_errcode_t (fn (void *, bin_tree_t *)),
40 void *extra);
41static reg_errcode_t postorder (bin_tree_t *root,
42 reg_errcode_t (fn (void *, bin_tree_t *)),
43 void *extra);
44static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node);
45static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node);
46static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg,
47 bin_tree_t *node);
48static reg_errcode_t calc_first (void *extra, bin_tree_t *node);
49static reg_errcode_t calc_next (void *extra, bin_tree_t *node);
50static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node);
51static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint);
52static int search_duplicated_node (const re_dfa_t *dfa, int org_node,
53 unsigned int constraint);
54static reg_errcode_t calc_eclosure (re_dfa_t *dfa);
55static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa,
56 int node, int root);
57static reg_errcode_t calc_inveclosure (re_dfa_t *dfa);
58static int fetch_number (re_string_t *input, re_token_t *token,
59 reg_syntax_t syntax);
60static int peek_token (re_token_t *token, re_string_t *input,
61 reg_syntax_t syntax) internal_function;
62static bin_tree_t *parse (re_string_t *regexp, regex_t *preg,
63 reg_syntax_t syntax, reg_errcode_t *err);
64static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg,
65 re_token_t *token, reg_syntax_t syntax,
66 int nest, reg_errcode_t *err);
67static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg,
68 re_token_t *token, reg_syntax_t syntax,
69 int nest, reg_errcode_t *err);
70static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg,
71 re_token_t *token, reg_syntax_t syntax,
72 int nest, reg_errcode_t *err);
73static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg,
74 re_token_t *token, reg_syntax_t syntax,
75 int nest, reg_errcode_t *err);
76static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp,
77 re_dfa_t *dfa, re_token_t *token,
78 reg_syntax_t syntax, reg_errcode_t *err);
79static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa,
80 re_token_t *token, reg_syntax_t syntax,
81 reg_errcode_t *err);
82static reg_errcode_t parse_bracket_element (bracket_elem_t *elem,
83 re_string_t *regexp,
84 re_token_t *token, int token_len,
85 re_dfa_t *dfa,
86 reg_syntax_t syntax,
87 int accept_hyphen);
88static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem,
89 re_string_t *regexp,
90 re_token_t *token);
91#ifdef RE_ENABLE_I18N
92static reg_errcode_t build_equiv_class (bitset_t sbcset,
93 re_charset_t *mbcset,
94 int *equiv_class_alloc,
95 const unsigned char *name);
96static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
97 bitset_t sbcset,
98 re_charset_t *mbcset,
99 int *char_class_alloc,
100 const char *class_name,
101 reg_syntax_t syntax);
102#else /* not RE_ENABLE_I18N */
103static reg_errcode_t build_equiv_class (bitset_t sbcset,
104 const unsigned char *name);
105static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
106 bitset_t sbcset,
107 const char *class_name,
108 reg_syntax_t syntax);
109#endif /* not RE_ENABLE_I18N */
110static bin_tree_t *build_charclass_op (re_dfa_t *dfa,
111 RE_TRANSLATE_TYPE trans,
112 const char *class_name,
113 const char *extra,
114 int non_match, reg_errcode_t *err);
115static bin_tree_t *create_tree (re_dfa_t *dfa,
116 bin_tree_t *left, bin_tree_t *right,
117 re_token_type_t type);
118static bin_tree_t *create_token_tree (re_dfa_t *dfa,
119 bin_tree_t *left, bin_tree_t *right,
120 const re_token_t *token);
121static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa);
122static void free_token (re_token_t *node);
123static reg_errcode_t free_tree (void *extra, bin_tree_t *node);
124static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node);
125
126/* This table gives an error message for each of the error codes listed
127 in regex.h. Obviously the order here has to be same as there.
128 POSIX doesn't require that we do anything for REG_NOERROR,
129 but why not be nice? */
130
131const char __re_error_msgid[] attribute_hidden =
132 {
133#define REG_NOERROR_IDX 0
134 gettext_noop ("Success") /* REG_NOERROR */
135 "\0"
136#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
137 gettext_noop ("No match") /* REG_NOMATCH */
138 "\0"
139#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
140 gettext_noop ("Invalid regular expression") /* REG_BADPAT */
141 "\0"
142#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
143 gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
144 "\0"
145#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
146 gettext_noop ("Invalid character class name") /* REG_ECTYPE */
147 "\0"
148#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name")
149 gettext_noop ("Trailing backslash") /* REG_EESCAPE */
150 "\0"
151#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash")
152 gettext_noop ("Invalid back reference") /* REG_ESUBREG */
153 "\0"
154#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
155 gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
156 "\0"
157#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
158 gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
159 "\0"
160#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
161 gettext_noop ("Unmatched \\{") /* REG_EBRACE */
162 "\0"
163#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{")
164 gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
165 "\0"
166#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
167 gettext_noop ("Invalid range end") /* REG_ERANGE */
168 "\0"
169#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
170 gettext_noop ("Memory exhausted") /* REG_ESPACE */
171 "\0"
172#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
173 gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
174 "\0"
175#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
176 gettext_noop ("Premature end of regular expression") /* REG_EEND */
177 "\0"
178#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression")
179 gettext_noop ("Regular expression too big") /* REG_ESIZE */
180 "\0"
181#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big")
182 gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
183 };
184
185const size_t __re_error_msgid_idx[] attribute_hidden =
186 {
187 REG_NOERROR_IDX,
188 REG_NOMATCH_IDX,
189 REG_BADPAT_IDX,
190 REG_ECOLLATE_IDX,
191 REG_ECTYPE_IDX,
192 REG_EESCAPE_IDX,
193 REG_ESUBREG_IDX,
194 REG_EBRACK_IDX,
195 REG_EPAREN_IDX,
196 REG_EBRACE_IDX,
197 REG_BADBR_IDX,
198 REG_ERANGE_IDX,
199 REG_ESPACE_IDX,
200 REG_BADRPT_IDX,
201 REG_EEND_IDX,
202 REG_ESIZE_IDX,
203 REG_ERPAREN_IDX
204 };
205
206/* Entry points for GNU code. */
207
208
209#ifdef ZOS_USS
210
211/* For ZOS USS we must define btowc */
212
213wchar_t
214btowc (int c)
215{
216 wchar_t wtmp[2];
217 char tmp[2];
218
219 tmp[0] = c;
220 tmp[1] = 0;
221
222 mbtowc (wtmp, tmp, 1);
223 return wtmp[0];
224}
225#endif
226
227/* re_compile_pattern is the GNU regular expression compiler: it
228 compiles PATTERN (of length LENGTH) and puts the result in BUFP.
229 Returns 0 if the pattern was valid, otherwise an error string.
230
231 Assumes the `allocated' (and perhaps `buffer') and `translate' fields
232 are set in BUFP on entry. */
233
234const char *
235re_compile_pattern (const char *pattern,
236 size_t length,
237 struct re_pattern_buffer *bufp)
238{
239 reg_errcode_t ret;
240
241 /* And GNU code determines whether or not to get register information
242 by passing null for the REGS argument to re_match, etc., not by
243 setting no_sub, unless RE_NO_SUB is set. */
244 bufp->no_sub = !!(re_syntax_options & RE_NO_SUB);
245
246 /* Match anchors at newline. */
247 bufp->newline_anchor = 1;
248
249 ret = re_compile_internal (bufp, pattern, length, re_syntax_options);
250
251 if (!ret)
252 return NULL;
253 return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
254}
255#ifdef _LIBC
256weak_alias (__re_compile_pattern, re_compile_pattern)
257#endif
258
259/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
260 also be assigned to arbitrarily: each pattern buffer stores its own
261 syntax, so it can be changed between regex compilations. */
262/* This has no initializer because initialized variables in Emacs
263 become read-only after dumping. */
264reg_syntax_t re_syntax_options;
265
266
267/* Specify the precise syntax of regexps for compilation. This provides
268 for compatibility for various utilities which historically have
269 different, incompatible syntaxes.
270
271 The argument SYNTAX is a bit mask comprised of the various bits
272 defined in regex.h. We return the old syntax. */
273
274reg_syntax_t
275re_set_syntax (reg_syntax_t syntax)
276{
277 reg_syntax_t ret = re_syntax_options;
278
279 re_syntax_options = syntax;
280 return ret;
281}
282#ifdef _LIBC
283weak_alias (__re_set_syntax, re_set_syntax)
284#endif
285
286int
287re_compile_fastmap (struct re_pattern_buffer *bufp)
288{
289 re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
290 char *fastmap = bufp->fastmap;
291
292 memset (fastmap, '\0', sizeof (char) * SBC_MAX);
293 re_compile_fastmap_iter (bufp, dfa->init_state, fastmap);
294 if (dfa->init_state != dfa->init_state_word)
295 re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap);
296 if (dfa->init_state != dfa->init_state_nl)
297 re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap);
298 if (dfa->init_state != dfa->init_state_begbuf)
299 re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap);
300 bufp->fastmap_accurate = 1;
301 return 0;
302}
303#ifdef _LIBC
304weak_alias (__re_compile_fastmap, re_compile_fastmap)
305#endif
306
307static inline void
308__attribute ((always_inline))
309re_set_fastmap (char *fastmap, int icase, int ch)
310{
311 fastmap[ch] = 1;
312 if (icase)
313 fastmap[tolower (ch)] = 1;
314}
315
316/* Helper function for re_compile_fastmap.
317 Compile fastmap for the initial_state INIT_STATE. */
318
319static void
320re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
321 char *fastmap)
322{
323 volatile re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
324 int node_cnt;
325 int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE));
326 for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
327 {
328 int node = init_state->nodes.elems[node_cnt];
329 re_token_type_t type = dfa->nodes[node].type;
330
331 if (type == CHARACTER)
332 {
333 re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
334#ifdef RE_ENABLE_I18N
335 if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
336 {
337 unsigned char *buf = re_malloc (unsigned char, dfa->mb_cur_max), *p;
338 wchar_t wc;
339 mbstate_t state;
340
341 p = buf;
342 *p++ = dfa->nodes[node].opr.c;
343 while (++node < dfa->nodes_len
344 && dfa->nodes[node].type == CHARACTER
345 && dfa->nodes[node].mb_partial)
346 *p++ = dfa->nodes[node].opr.c;
347 memset (&state, '\0', sizeof (state));
348 if (__mbrtowc (&wc, (const char *) buf, p - buf,
349 &state) == p - buf
350 && (__wcrtomb ((char *) buf, towlower (wc), &state)
351 != (size_t) -1))
352 re_set_fastmap (fastmap, 0, buf[0]);
353 re_free (buf);
354 }
355#endif
356 }
357 else if (type == SIMPLE_BRACKET)
358 {
359 int i, ch;
360 for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
361 {
362 int j;
363 bitset_word_t w = dfa->nodes[node].opr.sbcset[i];
364 for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
365 if (w & ((bitset_word_t) 1 << j))
366 re_set_fastmap (fastmap, icase, ch);
367 }
368 }
369#ifdef RE_ENABLE_I18N
370 else if (type == COMPLEX_BRACKET)
371 {
372 re_charset_t *cset = dfa->nodes[node].opr.mbcset;
373 int i;
374
375# ifdef _LIBC
376 /* See if we have to try all bytes which start multiple collation
377 elements.
378 e.g. In da_DK, we want to catch 'a' since "aa" is a valid
379 collation element, and don't catch 'b' since 'b' is
380 the only collation element which starts from 'b' (and
381 it is caught by SIMPLE_BRACKET). */
382 if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0
383 && (cset->ncoll_syms || cset->nranges))
384 {
385 const int32_t *table = (const int32_t *)
386 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
387 for (i = 0; i < SBC_MAX; ++i)
388 if (table[i] < 0)
389 re_set_fastmap (fastmap, icase, i);
390 }
391# endif /* _LIBC */
392
393 /* See if we have to start the match at all multibyte characters,
394 i.e. where we would not find an invalid sequence. This only
395 applies to multibyte character sets; for single byte character
396 sets, the SIMPLE_BRACKET again suffices. */
397 if (dfa->mb_cur_max > 1
398 && (cset->nchar_classes || cset->non_match || cset->nranges
399# ifdef _LIBC
400 || cset->nequiv_classes
401# endif /* _LIBC */
402 ))
403 {
404 unsigned char c = 0;
405 do
406 {
407 mbstate_t mbs;
408 memset (&mbs, 0, sizeof (mbs));
409 if (__mbrtowc (NULL, (char *) &c, 1, &mbs) == (size_t) -2)
410 re_set_fastmap (fastmap, false, (int) c);
411 }
412 while (++c != 0);
413 }
414
415 else
416 {
417 /* ... Else catch all bytes which can start the mbchars. */
418 for (i = 0; i < cset->nmbchars; ++i)
419 {
420 char buf[256];
421 mbstate_t state;
422 memset (&state, '\0', sizeof (state));
423 if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
424 re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
425 if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
426 {
427 if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
428 != (size_t) -1)
429 re_set_fastmap (fastmap, false, *(unsigned char *) buf);
430 }
431 }
432 }
433 }
434#endif /* RE_ENABLE_I18N */
435 else if (type == OP_PERIOD
436#ifdef RE_ENABLE_I18N
437 || type == OP_UTF8_PERIOD
438#endif /* RE_ENABLE_I18N */
439 || type == END_OF_RE)
440 {
441 memset (fastmap, '\1', sizeof (char) * SBC_MAX);
442 if (type == END_OF_RE)
443 bufp->can_be_null = 1;
444 return;
445 }
446 }
447}
448
449/* Entry point for POSIX code. */
450/* regcomp takes a regular expression as a string and compiles it.
451
452 PREG is a regex_t *. We do not expect any fields to be initialized,
453 since POSIX says we shouldn't. Thus, we set
454
455 `buffer' to the compiled pattern;
456 `used' to the length of the compiled pattern;
457 `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
458 REG_EXTENDED bit in CFLAGS is set; otherwise, to
459 RE_SYNTAX_POSIX_BASIC;
460 `newline_anchor' to REG_NEWLINE being set in CFLAGS;
461 `fastmap' to an allocated space for the fastmap;
462 `fastmap_accurate' to zero;
463 `re_nsub' to the number of subexpressions in PATTERN.
464
465 PATTERN is the address of the pattern string.
466
467 CFLAGS is a series of bits which affect compilation.
468
469 If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
470 use POSIX basic syntax.
471
472 If REG_NEWLINE is set, then . and [^...] don't match newline.
473 Also, regexec will try a match beginning after every newline.
474
475 If REG_ICASE is set, then we considers upper- and lowercase
476 versions of letters to be equivalent when matching.
477
478 If REG_NOSUB is set, then when PREG is passed to regexec, that
479 routine will report only success or failure, and nothing about the
480 registers.
481
482 It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
483 the return codes and their meanings.) */
484
485int
486regcomp (regex_t *__restrict preg,
487 const char *__restrict pattern,
488 int cflags)
489{
490 reg_errcode_t ret;
491 reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED
492 : RE_SYNTAX_POSIX_BASIC);
493
494 preg->buffer = NULL;
495 preg->allocated = 0;
496 preg->used = 0;
497
498 /* Try to allocate space for the fastmap. */
499 preg->fastmap = re_malloc (char, SBC_MAX);
500 if (BE (preg->fastmap == NULL, 0))
501 return REG_ESPACE;
502
503 syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0;
504
505 /* If REG_NEWLINE is set, newlines are treated differently. */
506 if (cflags & REG_NEWLINE)
507 { /* REG_NEWLINE implies neither . nor [^...] match newline. */
508 syntax &= ~RE_DOT_NEWLINE;
509 syntax |= RE_HAT_LISTS_NOT_NEWLINE;
510 /* It also changes the matching behavior. */
511 preg->newline_anchor = 1;
512 }
513 else
514 preg->newline_anchor = 0;
515 preg->no_sub = !!(cflags & REG_NOSUB);
516 preg->translate = NULL;
517
518 ret = re_compile_internal (preg, pattern, strlen (pattern), syntax);
519
520 /* POSIX doesn't distinguish between an unmatched open-group and an
521 unmatched close-group: both are REG_EPAREN. */
522 if (ret == REG_ERPAREN)
523 ret = REG_EPAREN;
524
525 /* We have already checked preg->fastmap != NULL. */
526 if (BE (ret == REG_NOERROR, 1))
527 /* Compute the fastmap now, since regexec cannot modify the pattern
528 buffer. This function never fails in this implementation. */
529 (void) re_compile_fastmap (preg);
530 else
531 {
532 /* Some error occurred while compiling the expression. */
533 re_free (preg->fastmap);
534 preg->fastmap = NULL;
535 }
536
537 return (int) ret;
538}
539#ifdef _LIBC
540weak_alias (__regcomp, regcomp)
541#endif
542
543/* Returns a message corresponding to an error code, ERRCODE, returned
544 from either regcomp or regexec. We don't use PREG here. */
545
546size_t
547regerror(int errcode, UNUSED_PARAM const regex_t *__restrict preg,
548 char *__restrict errbuf, size_t errbuf_size)
549{
550 const char *msg;
551 size_t msg_size;
552
553 if (BE (errcode < 0
554 || errcode >= (int) (sizeof (__re_error_msgid_idx)
555 / sizeof (__re_error_msgid_idx[0])), 0))
556 /* Only error codes returned by the rest of the code should be passed
557 to this routine. If we are given anything else, or if other regex
558 code generates an invalid error code, then the program has a bug.
559 Dump core so we can fix it. */
560 abort ();
561
562 msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
563
564 msg_size = strlen (msg) + 1; /* Includes the null. */
565
566 if (BE (errbuf_size != 0, 1))
567 {
568 if (BE (msg_size > errbuf_size, 0))
569 {
570 memcpy (errbuf, msg, errbuf_size - 1);
571 errbuf[errbuf_size - 1] = 0;
572 }
573 else
574 memcpy (errbuf, msg, msg_size);
575 }
576
577 return msg_size;
578}
579#ifdef _LIBC
580weak_alias (__regerror, regerror)
581#endif
582
583
584#ifdef RE_ENABLE_I18N
585/* This static array is used for the map to single-byte characters when
586 UTF-8 is used. Otherwise we would allocate memory just to initialize
587 it the same all the time. UTF-8 is the preferred encoding so this is
588 a worthwhile optimization. */
589#if __GNUC__ >= 3
590static const bitset_t utf8_sb_map = {
591 /* Set the first 128 bits. */
592 [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX
593};
594#else /* ! (__GNUC__ >= 3) */
595static bitset_t utf8_sb_map;
596#endif /* __GNUC__ >= 3 */
597#endif /* RE_ENABLE_I18N */
598
599
600static void
601free_dfa_content (re_dfa_t *dfa)
602{
603 int i, j;
604
605 if (dfa->nodes)
606 for (i = 0; i < dfa->nodes_len; ++i)
607 free_token (dfa->nodes + i);
608 re_free (dfa->nexts);
609 for (i = 0; i < dfa->nodes_len; ++i)
610 {
611 if (dfa->eclosures != NULL)
612 re_node_set_free (dfa->eclosures + i);
613 if (dfa->inveclosures != NULL)
614 re_node_set_free (dfa->inveclosures + i);
615 if (dfa->edests != NULL)
616 re_node_set_free (dfa->edests + i);
617 }
618 re_free (dfa->edests);
619 re_free (dfa->eclosures);
620 re_free (dfa->inveclosures);
621 re_free (dfa->nodes);
622
623 if (dfa->state_table)
624 for (i = 0; i <= dfa->state_hash_mask; ++i)
625 {
626 struct re_state_table_entry *entry = dfa->state_table + i;
627 for (j = 0; j < entry->num; ++j)
628 {
629 re_dfastate_t *state = entry->array[j];
630 free_state (state);
631 }
632 re_free (entry->array);
633 }
634 re_free (dfa->state_table);
635#ifdef RE_ENABLE_I18N
636 if (dfa->sb_char != utf8_sb_map)
637 re_free (dfa->sb_char);
638#endif
639 re_free (dfa->subexp_map);
640#ifdef DEBUG
641 re_free (dfa->re_str);
642#endif
643
644 re_free (dfa);
645}
646
647
648/* Free dynamically allocated space used by PREG. */
649
650void
651regfree (regex_t *preg)
652{
653 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
654 if (BE (dfa != NULL, 1))
655 free_dfa_content (dfa);
656 preg->buffer = NULL;
657 preg->allocated = 0;
658
659 re_free (preg->fastmap);
660 preg->fastmap = NULL;
661
662 re_free (preg->translate);
663 preg->translate = NULL;
664}
665#ifdef _LIBC
666weak_alias (__regfree, regfree)
667#endif
668
669/* Entry points compatible with 4.2 BSD regex library. We don't define
670 them unless specifically requested. */
671
672#if defined _REGEX_RE_COMP || defined _LIBC
673
674/* BSD has one and only one pattern buffer. */
675static struct re_pattern_buffer re_comp_buf;
676
677char *
678# ifdef _LIBC
679/* Make these definitions weak in libc, so POSIX programs can redefine
680 these names if they don't use our functions, and still use
681 regcomp/regexec above without link errors. */
682weak_function
683# endif
684re_comp (s)
685 const char *s;
686{
687 reg_errcode_t ret;
688 char *fastmap;
689
690 if (!s)
691 {
692 if (!re_comp_buf.buffer)
693 return gettext ("No previous regular expression");
694 return 0;
695 }
696
697 if (re_comp_buf.buffer)
698 {
699 fastmap = re_comp_buf.fastmap;
700 re_comp_buf.fastmap = NULL;
701 __regfree (&re_comp_buf);
702 memset (&re_comp_buf, '\0', sizeof (re_comp_buf));
703 re_comp_buf.fastmap = fastmap;
704 }
705
706 if (re_comp_buf.fastmap == NULL)
707 {
708 re_comp_buf.fastmap = (char *) malloc (SBC_MAX);
709 if (re_comp_buf.fastmap == NULL)
710 return (char *) gettext (__re_error_msgid
711 + __re_error_msgid_idx[(int) REG_ESPACE]);
712 }
713
714 /* Since `re_exec' always passes NULL for the `regs' argument, we
715 don't need to initialize the pattern buffer fields which affect it. */
716
717 /* Match anchors at newlines. */
718 re_comp_buf.newline_anchor = 1;
719
720 ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options);
721
722 if (!ret)
723 return NULL;
724
725 /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
726 return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
727}
728
729#ifdef _LIBC
730libc_freeres_fn (free_mem)
731{
732 __regfree (&re_comp_buf);
733}
734#endif
735
736#endif /* _REGEX_RE_COMP */
737
738/* Internal entry point.
739 Compile the regular expression PATTERN, whose length is LENGTH.
740 SYNTAX indicate regular expression's syntax. */
741
742static reg_errcode_t
743re_compile_internal (regex_t *preg, const char * pattern, size_t length,
744 reg_syntax_t syntax)
745{
746 reg_errcode_t err = REG_NOERROR;
747 re_dfa_t *dfa;
748 re_string_t regexp;
749
750 /* Initialize the pattern buffer. */
751 preg->fastmap_accurate = 0;
752 preg->syntax = syntax;
753 preg->not_bol = preg->not_eol = 0;
754 preg->used = 0;
755 preg->re_nsub = 0;
756 preg->can_be_null = 0;
757 preg->regs_allocated = REGS_UNALLOCATED;
758
759 /* Initialize the dfa. */
760 dfa = (re_dfa_t *) preg->buffer;
761 if (BE (preg->allocated < sizeof (re_dfa_t), 0))
762 {
763 /* If zero allocated, but buffer is non-null, try to realloc
764 enough space. This loses if buffer's address is bogus, but
765 that is the user's responsibility. If ->buffer is NULL this
766 is a simple allocation. */
767 dfa = re_realloc (preg->buffer, re_dfa_t, 1);
768 if (dfa == NULL)
769 return REG_ESPACE;
770 preg->allocated = sizeof (re_dfa_t);
771 preg->buffer = (unsigned char *) dfa;
772 }
773 preg->used = sizeof (re_dfa_t);
774
775 err = init_dfa (dfa, length);
776 if (BE (err != REG_NOERROR, 0))
777 {
778 free_dfa_content (dfa);
779 preg->buffer = NULL;
780 preg->allocated = 0;
781 return err;
782 }
783#ifdef DEBUG
784 /* Note: length+1 will not overflow since it is checked in init_dfa. */
785 dfa->re_str = re_malloc (char, length + 1);
786 strncpy (dfa->re_str, pattern, length + 1);
787#endif
788
789 __libc_lock_init (dfa->lock);
790
791 err = re_string_construct (&regexp, pattern, length, preg->translate,
792 syntax & RE_ICASE, dfa);
793 if (BE (err != REG_NOERROR, 0))
794 {
795 re_compile_internal_free_return:
796 free_workarea_compile (preg);
797 re_string_destruct (&regexp);
798 free_dfa_content (dfa);
799 preg->buffer = NULL;
800 preg->allocated = 0;
801 return err;
802 }
803
804 /* Parse the regular expression, and build a structure tree. */
805 preg->re_nsub = 0;
806 dfa->str_tree = parse (&regexp, preg, syntax, &err);
807 if (BE (dfa->str_tree == NULL, 0))
808 goto re_compile_internal_free_return;
809
810 /* Analyze the tree and create the nfa. */
811 err = analyze (preg);
812 if (BE (err != REG_NOERROR, 0))
813 goto re_compile_internal_free_return;
814
815#ifdef RE_ENABLE_I18N
816 /* If possible, do searching in single byte encoding to speed things up. */
817 if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL)
818 optimize_utf8 (dfa);
819#endif
820
821 /* Then create the initial state of the dfa. */
822 err = create_initial_state (dfa);
823
824 /* Release work areas. */
825 free_workarea_compile (preg);
826 re_string_destruct (&regexp);
827
828 if (BE (err != REG_NOERROR, 0))
829 {
830 free_dfa_content (dfa);
831 preg->buffer = NULL;
832 preg->allocated = 0;
833 }
834
835 return err;
836}
837
838/* Initialize DFA. We use the length of the regular expression PAT_LEN
839 as the initial length of some arrays. */
840
841static reg_errcode_t
842init_dfa (re_dfa_t *dfa, size_t pat_len)
843{
844 unsigned int table_size;
845#ifndef _LIBC
846 const char *codeset_name;
847#endif
848
849 memset (dfa, '\0', sizeof (re_dfa_t));
850
851 /* Force allocation of str_tree_storage the first time. */
852 dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
853
854 /* Avoid overflows. */
855 if (pat_len == SIZE_MAX)
856 return REG_ESPACE;
857
858 dfa->nodes_alloc = pat_len + 1;
859 dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc);
860
861 /* table_size = 2 ^ ceil(log pat_len) */
862 for (table_size = 1; ; table_size <<= 1)
863 if (table_size > pat_len)
864 break;
865
866 dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size);
867 dfa->state_hash_mask = table_size - 1;
868
869 dfa->mb_cur_max = MB_CUR_MAX;
870#ifdef _LIBC
871 if (dfa->mb_cur_max == 6
872 && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
873 dfa->is_utf8 = 1;
874 dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
875 != 0);
876#else
877# ifdef HAVE_LANGINFO_CODESET
878 codeset_name = nl_langinfo (CODESET);
879# else
880 codeset_name = getenv ("LC_ALL");
881 if (codeset_name == NULL || codeset_name[0] == '\0')
882 codeset_name = getenv ("LC_CTYPE");
883 if (codeset_name == NULL || codeset_name[0] == '\0')
884 codeset_name = getenv ("LANG");
885 if (codeset_name == NULL)
886 codeset_name = "";
887 else if (strchr (codeset_name, '.') != NULL)
888 codeset_name = strchr (codeset_name, '.') + 1;
889# endif
890
891 /* strcasecmp isn't a standard interface. brute force check */
892#if 0
893 if (strcasecmp (codeset_name, "UTF-8") == 0
894 || strcasecmp (codeset_name, "UTF8") == 0)
895 dfa->is_utf8 = 1;
896#else
897 if ( (codeset_name[0] == 'U' || codeset_name[0] == 'u')
898 && (codeset_name[1] == 'T' || codeset_name[1] == 't')
899 && (codeset_name[2] == 'F' || codeset_name[2] == 'f')
900 && (codeset_name[3] == '-'
901 ? codeset_name[4] == '8' && codeset_name[5] == '\0'
902 : codeset_name[3] == '8' && codeset_name[4] == '\0'))
903 dfa->is_utf8 = 1;
904#endif
905
906 /* We check exhaustively in the loop below if this charset is a
907 superset of ASCII. */
908 dfa->map_notascii = 0;
909#endif
910
911#ifdef RE_ENABLE_I18N
912 if (dfa->mb_cur_max > 1)
913 {
914 if (dfa->is_utf8)
915 {
916#if !defined(__GNUC__) || __GNUC__ < 3
917 static short utf8_sb_map_inited = 0;
918
919 if (! utf8_sb_map_inited)
920 {
921 int i;
922
923 utf8_sb_map_inited = 0;
924 for (i = 0; i <= 0x80 / BITSET_WORD_BITS - 1; i++)
925 utf8_sb_map[i] = BITSET_WORD_MAX;
926 }
927#endif
928 dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
929 }
930 else
931 {
932 int i, j, ch;
933
934 dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
935 if (BE (dfa->sb_char == NULL, 0))
936 return REG_ESPACE;
937
938 /* Set the bits corresponding to single byte chars. */
939 for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
940 for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
941 {
942 wint_t wch = __btowc (ch);
943 if (wch != WEOF)
944 dfa->sb_char[i] |= (bitset_word_t) 1 << j;
945# ifndef _LIBC
946 if (isascii (ch) && wch != ch)
947 dfa->map_notascii = 1;
948# endif
949 }
950 }
951 }
952#endif
953
954 if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0))
955 return REG_ESPACE;
956 return REG_NOERROR;
957}
958
959/* Initialize WORD_CHAR table, which indicate which character is
960 "word". In this case "word" means that it is the word construction
961 character used by some operators like "\<", "\>", etc. */
962
963static void
964internal_function
965init_word_char (re_dfa_t *dfa)
966{
967 int i, j, ch;
968 dfa->word_ops_used = 1;
969 for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
970 for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
971 if (isalnum (ch) || ch == '_')
972 dfa->word_char[i] |= (bitset_word_t) 1 << j;
973}
974
975/* Free the work area which are only used while compiling. */
976
977static void
978free_workarea_compile (regex_t *preg)
979{
980 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
981 bin_tree_storage_t *storage, *next;
982 for (storage = dfa->str_tree_storage; storage; storage = next)
983 {
984 next = storage->next;
985 re_free (storage);
986 }
987 dfa->str_tree_storage = NULL;
988 dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
989 dfa->str_tree = NULL;
990 re_free (dfa->org_indices);
991 dfa->org_indices = NULL;
992}
993
994/* Create initial states for all contexts. */
995
996static reg_errcode_t
997create_initial_state (re_dfa_t *dfa)
998{
999 int first, i;
1000 reg_errcode_t err;
1001 re_node_set init_nodes;
1002
1003 /* Initial states have the epsilon closure of the node which is
1004 the first node of the regular expression. */
1005 first = dfa->str_tree->first->node_idx;
1006 dfa->init_node = first;
1007 err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first);
1008 if (BE (err != REG_NOERROR, 0))
1009 return err;
1010
1011 /* The back-references which are in initial states can epsilon transit,
1012 since in this case all of the subexpressions can be null.
1013 Then we add epsilon closures of the nodes which are the next nodes of
1014 the back-references. */
1015 if (dfa->nbackref > 0)
1016 for (i = 0; i < init_nodes.nelem; ++i)
1017 {
1018 int node_idx = init_nodes.elems[i];
1019 re_token_type_t type = dfa->nodes[node_idx].type;
1020
1021 int clexp_idx;
1022 if (type != OP_BACK_REF)
1023 continue;
1024 for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx)
1025 {
1026 re_token_t *clexp_node;
1027 clexp_node = dfa->nodes + init_nodes.elems[clexp_idx];
1028 if (clexp_node->type == OP_CLOSE_SUBEXP
1029 && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx)
1030 break;
1031 }
1032 if (clexp_idx == init_nodes.nelem)
1033 continue;
1034
1035 if (type == OP_BACK_REF)
1036 {
1037 int dest_idx = dfa->edests[node_idx].elems[0];
1038 if (!re_node_set_contains (&init_nodes, dest_idx))
1039 {
1040 err = re_node_set_merge (&init_nodes,
1041 dfa->eclosures + dest_idx);
1042 if (err != REG_NOERROR)
1043 return err;
1044 i = 0;
1045 }
1046 }
1047 }
1048
1049 /* It must be the first time to invoke acquire_state. */
1050 dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
1051 /* We don't check ERR here, since the initial state must not be NULL. */
1052 if (BE (dfa->init_state == NULL, 0))
1053 return err;
1054 if (dfa->init_state->has_constraint)
1055 {
1056 dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
1057 CONTEXT_WORD);
1058 dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes,
1059 CONTEXT_NEWLINE);
1060 dfa->init_state_begbuf = re_acquire_state_context (&err, dfa,
1061 &init_nodes,
1062 CONTEXT_NEWLINE
1063 | CONTEXT_BEGBUF);
1064 if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL
1065 || dfa->init_state_begbuf == NULL, 0))
1066 return err;
1067 }
1068 else
1069 dfa->init_state_word = dfa->init_state_nl
1070 = dfa->init_state_begbuf = dfa->init_state;
1071
1072 re_node_set_free (&init_nodes);
1073 return REG_NOERROR;
1074}
1075
1076#ifdef RE_ENABLE_I18N
1077/* If it is possible to do searching in single byte encoding instead of UTF-8
1078 to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change
1079 DFA nodes where needed. */
1080
1081static void
1082optimize_utf8 (re_dfa_t *dfa)
1083{
1084 int node, i, mb_chars = 0, has_period = 0;
1085
1086 for (node = 0; node < dfa->nodes_len; ++node)
1087 switch (dfa->nodes[node].type)
1088 {
1089 case CHARACTER:
1090 if (dfa->nodes[node].opr.c >= 0x80)
1091 mb_chars = 1;
1092 break;
1093 case ANCHOR:
1094 switch (dfa->nodes[node].opr.ctx_type)
1095 {
1096 case LINE_FIRST:
1097 case LINE_LAST:
1098 case BUF_FIRST:
1099 case BUF_LAST:
1100 break;
1101 default:
1102 /* Word anchors etc. cannot be handled. It's okay to test
1103 opr.ctx_type since constraints (for all DFA nodes) are
1104 created by ORing one or more opr.ctx_type values. */
1105 return;
1106 }
1107 break;
1108 case OP_PERIOD:
1109 has_period = 1;
1110 break;
1111 case OP_BACK_REF:
1112 case OP_ALT:
1113 case END_OF_RE:
1114 case OP_DUP_ASTERISK:
1115 case OP_OPEN_SUBEXP:
1116 case OP_CLOSE_SUBEXP:
1117 break;
1118 case COMPLEX_BRACKET:
1119 return;
1120 case SIMPLE_BRACKET:
1121 /* Just double check. The non-ASCII range starts at 0x80. */
1122 assert (0x80 % BITSET_WORD_BITS == 0);
1123 for (i = 0x80 / BITSET_WORD_BITS; i < BITSET_WORDS; ++i)
1124 if (dfa->nodes[node].opr.sbcset[i])
1125 return;
1126 break;
1127 default:
1128 abort ();
1129 }
1130
1131 if (mb_chars || has_period)
1132 for (node = 0; node < dfa->nodes_len; ++node)
1133 {
1134 if (dfa->nodes[node].type == CHARACTER
1135 && dfa->nodes[node].opr.c >= 0x80)
1136 dfa->nodes[node].mb_partial = 0;
1137 else if (dfa->nodes[node].type == OP_PERIOD)
1138 dfa->nodes[node].type = OP_UTF8_PERIOD;
1139 }
1140
1141 /* The search can be in single byte locale. */
1142 dfa->mb_cur_max = 1;
1143 dfa->is_utf8 = 0;
1144 dfa->has_mb_node = dfa->nbackref > 0 || has_period;
1145}
1146#endif
1147
1148/* Analyze the structure tree, and calculate "first", "next", "edest",
1149 "eclosure", and "inveclosure". */
1150
1151static reg_errcode_t
1152analyze (regex_t *preg)
1153{
1154 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
1155 reg_errcode_t ret;
1156
1157 /* Allocate arrays. */
1158 dfa->nexts = re_malloc (int, dfa->nodes_alloc);
1159 dfa->org_indices = re_malloc (int, dfa->nodes_alloc);
1160 dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc);
1161 dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc);
1162 if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL
1163 || dfa->eclosures == NULL, 0))
1164 return REG_ESPACE;
1165
1166 dfa->subexp_map = re_malloc (int, preg->re_nsub);
1167 if (dfa->subexp_map != NULL)
1168 {
1169 int i;
1170 for (i = 0; i < preg->re_nsub; i++)
1171 dfa->subexp_map[i] = i;
1172 preorder (dfa->str_tree, optimize_subexps, dfa);
1173 for (i = 0; i < preg->re_nsub; i++)
1174 if (dfa->subexp_map[i] != i)
1175 break;
1176 if (i == preg->re_nsub)
1177 {
1178 free (dfa->subexp_map);
1179 dfa->subexp_map = NULL;
1180 }
1181 }
1182
1183 ret = postorder (dfa->str_tree, lower_subexps, preg);
1184 if (BE (ret != REG_NOERROR, 0))
1185 return ret;
1186 ret = postorder (dfa->str_tree, calc_first, dfa);
1187 if (BE (ret != REG_NOERROR, 0))
1188 return ret;
1189 preorder (dfa->str_tree, calc_next, dfa);
1190 ret = preorder (dfa->str_tree, link_nfa_nodes, dfa);
1191 if (BE (ret != REG_NOERROR, 0))
1192 return ret;
1193 ret = calc_eclosure (dfa);
1194 if (BE (ret != REG_NOERROR, 0))
1195 return ret;
1196
1197 /* We only need this during the prune_impossible_nodes pass in regexec.c;
1198 skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */
1199 if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match)
1200 || dfa->nbackref)
1201 {
1202 dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len);
1203 if (BE (dfa->inveclosures == NULL, 0))
1204 return REG_ESPACE;
1205 ret = calc_inveclosure (dfa);
1206 }
1207
1208 return ret;
1209}
1210
1211/* Our parse trees are very unbalanced, so we cannot use a stack to
1212 implement parse tree visits. Instead, we use parent pointers and
1213 some hairy code in these two functions. */
1214static reg_errcode_t
1215postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
1216 void *extra)
1217{
1218 bin_tree_t *node, *prev;
1219
1220 for (node = root; ; )
1221 {
1222 /* Descend down the tree, preferably to the left (or to the right
1223 if that's the only child). */
1224 while (node->left || node->right)
1225 if (node->left)
1226 node = node->left;
1227 else
1228 node = node->right;
1229
1230 do
1231 {
1232 reg_errcode_t err = fn (extra, node);
1233 if (BE (err != REG_NOERROR, 0))
1234 return err;
1235 if (node->parent == NULL)
1236 return REG_NOERROR;
1237 prev = node;
1238 node = node->parent;
1239 }
1240 /* Go up while we have a node that is reached from the right. */
1241 while (node->right == prev || node->right == NULL);
1242 node = node->right;
1243 }
1244}
1245
1246static reg_errcode_t
1247preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
1248 void *extra)
1249{
1250 bin_tree_t *node;
1251
1252 for (node = root; ; )
1253 {
1254 reg_errcode_t err = fn (extra, node);
1255 if (BE (err != REG_NOERROR, 0))
1256 return err;
1257
1258 /* Go to the left node, or up and to the right. */
1259 if (node->left)
1260 node = node->left;
1261 else
1262 {
1263 bin_tree_t *prev = NULL;
1264 while (node->right == prev || node->right == NULL)
1265 {
1266 prev = node;
1267 node = node->parent;
1268 if (!node)
1269 return REG_NOERROR;
1270 }
1271 node = node->right;
1272 }
1273 }
1274}
1275
1276/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell
1277 re_search_internal to map the inner one's opr.idx to this one's. Adjust
1278 backreferences as well. Requires a preorder visit. */
1279static reg_errcode_t
1280optimize_subexps (void *extra, bin_tree_t *node)
1281{
1282 re_dfa_t *dfa = (re_dfa_t *) extra;
1283
1284 if (node->token.type == OP_BACK_REF && dfa->subexp_map)
1285 {
1286 int idx = node->token.opr.idx;
1287 node->token.opr.idx = dfa->subexp_map[idx];
1288 dfa->used_bkref_map |= 1 << node->token.opr.idx;
1289 }
1290
1291 else if (node->token.type == SUBEXP
1292 && node->left && node->left->token.type == SUBEXP)
1293 {
1294 int other_idx = node->left->token.opr.idx;
1295
1296 node->left = node->left->left;
1297 if (node->left)
1298 node->left->parent = node;
1299
1300 dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx];
1301 if (other_idx < BITSET_WORD_BITS)
1302 dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx);
1303 }
1304
1305 return REG_NOERROR;
1306}
1307
1308/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation
1309 of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */
1310static reg_errcode_t
1311lower_subexps (void *extra, bin_tree_t *node)
1312{
1313 regex_t *preg = (regex_t *) extra;
1314 reg_errcode_t err = REG_NOERROR;
1315
1316 if (node->left && node->left->token.type == SUBEXP)
1317 {
1318 node->left = lower_subexp (&err, preg, node->left);
1319 if (node->left)
1320 node->left->parent = node;
1321 }
1322 if (node->right && node->right->token.type == SUBEXP)
1323 {
1324 node->right = lower_subexp (&err, preg, node->right);
1325 if (node->right)
1326 node->right->parent = node;
1327 }
1328
1329 return err;
1330}
1331
1332static bin_tree_t *
1333lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node)
1334{
1335 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
1336 bin_tree_t *body = node->left;
1337 bin_tree_t *op, *cls, *tree1, *tree;
1338
1339 if (preg->no_sub
1340 /* We do not optimize empty subexpressions, because otherwise we may
1341 have bad CONCAT nodes with NULL children. This is obviously not
1342 very common, so we do not lose much. An example that triggers
1343 this case is the sed "script" /\(\)/x. */
1344 && node->left != NULL
1345 && (node->token.opr.idx >= BITSET_WORD_BITS
1346 || !(dfa->used_bkref_map
1347 & ((bitset_word_t) 1 << node->token.opr.idx))))
1348 return node->left;
1349
1350 /* Convert the SUBEXP node to the concatenation of an
1351 OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */
1352 op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP);
1353 cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP);
1354 tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls;
1355 tree = create_tree (dfa, op, tree1, CONCAT);
1356 if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0))
1357 {
1358 *err = REG_ESPACE;
1359 return NULL;
1360 }
1361
1362 op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx;
1363 op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp;
1364 return tree;
1365}
1366
1367/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton
1368 nodes. Requires a postorder visit. */
1369static reg_errcode_t
1370calc_first (void *extra, bin_tree_t *node)
1371{
1372 re_dfa_t *dfa = (re_dfa_t *) extra;
1373 if (node->token.type == CONCAT)
1374 {
1375 node->first = node->left->first;
1376 node->node_idx = node->left->node_idx;
1377 }
1378 else
1379 {
1380 node->first = node;
1381 node->node_idx = re_dfa_add_node (dfa, node->token);
1382 if (BE (node->node_idx == -1, 0))
1383 return REG_ESPACE;
1384 if (node->token.type == ANCHOR)
1385 dfa->nodes[node->node_idx].constraint = node->token.opr.ctx_type;
1386 }
1387 return REG_NOERROR;
1388}
1389
1390/* Pass 2: compute NEXT on the tree. Preorder visit. */
1391static reg_errcode_t
1392calc_next (UNUSED_PARAM void *extra, bin_tree_t *node)
1393{
1394 switch (node->token.type)
1395 {
1396 case OP_DUP_ASTERISK:
1397 node->left->next = node;
1398 break;
1399 case CONCAT:
1400 node->left->next = node->right->first;
1401 node->right->next = node->next;
1402 break;
1403 default:
1404 if (node->left)
1405 node->left->next = node->next;
1406 if (node->right)
1407 node->right->next = node->next;
1408 break;
1409 }
1410 return REG_NOERROR;
1411}
1412
1413/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */
1414static reg_errcode_t
1415link_nfa_nodes (void *extra, bin_tree_t *node)
1416{
1417 re_dfa_t *dfa = (re_dfa_t *) extra;
1418 int idx = node->node_idx;
1419 reg_errcode_t err = REG_NOERROR;
1420
1421 switch (node->token.type)
1422 {
1423 case CONCAT:
1424 break;
1425
1426 case END_OF_RE:
1427 assert (node->next == NULL);
1428 break;
1429
1430 case OP_DUP_ASTERISK:
1431 case OP_ALT:
1432 {
1433 int left, right;
1434 dfa->has_plural_match = 1;
1435 if (node->left != NULL)
1436 left = node->left->first->node_idx;
1437 else
1438 left = node->next->node_idx;
1439 if (node->right != NULL)
1440 right = node->right->first->node_idx;
1441 else
1442 right = node->next->node_idx;
1443 assert (left > -1);
1444 assert (right > -1);
1445 err = re_node_set_init_2 (dfa->edests + idx, left, right);
1446 }
1447 break;
1448
1449 case ANCHOR:
1450 case OP_OPEN_SUBEXP:
1451 case OP_CLOSE_SUBEXP:
1452 err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx);
1453 break;
1454
1455 case OP_BACK_REF:
1456 dfa->nexts[idx] = node->next->node_idx;
1457 if (node->token.type == OP_BACK_REF)
1458 err = re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]);
1459 break;
1460
1461 default:
1462 assert (!IS_EPSILON_NODE (node->token.type));
1463 dfa->nexts[idx] = node->next->node_idx;
1464 break;
1465 }
1466
1467 return err;
1468}
1469
1470/* Duplicate the epsilon closure of the node ROOT_NODE.
1471 Note that duplicated nodes have constraint INIT_CONSTRAINT in addition
1472 to their own constraint. */
1473
1474static reg_errcode_t
1475internal_function
1476duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node,
1477 int root_node, unsigned int init_constraint)
1478{
1479 int org_node, clone_node, ret;
1480 unsigned int constraint = init_constraint;
1481 for (org_node = top_org_node, clone_node = top_clone_node;;)
1482 {
1483 int org_dest, clone_dest;
1484 if (dfa->nodes[org_node].type == OP_BACK_REF)
1485 {
1486 /* If the back reference epsilon-transit, its destination must
1487 also have the constraint. Then duplicate the epsilon closure
1488 of the destination of the back reference, and store it in
1489 edests of the back reference. */
1490 org_dest = dfa->nexts[org_node];
1491 re_node_set_empty (dfa->edests + clone_node);
1492 clone_dest = duplicate_node (dfa, org_dest, constraint);
1493 if (BE (clone_dest == -1, 0))
1494 return REG_ESPACE;
1495 dfa->nexts[clone_node] = dfa->nexts[org_node];
1496 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1497 if (BE (ret < 0, 0))
1498 return REG_ESPACE;
1499 }
1500 else if (dfa->edests[org_node].nelem == 0)
1501 {
1502 /* In case of the node can't epsilon-transit, don't duplicate the
1503 destination and store the original destination as the
1504 destination of the node. */
1505 dfa->nexts[clone_node] = dfa->nexts[org_node];
1506 break;
1507 }
1508 else if (dfa->edests[org_node].nelem == 1)
1509 {
1510 /* In case of the node can epsilon-transit, and it has only one
1511 destination. */
1512 org_dest = dfa->edests[org_node].elems[0];
1513 re_node_set_empty (dfa->edests + clone_node);
1514 /* If the node is root_node itself, it means the epsilon clsoure
1515 has a loop. Then tie it to the destination of the root_node. */
1516 if (org_node == root_node && clone_node != org_node)
1517 {
1518 ret = re_node_set_insert (dfa->edests + clone_node, org_dest);
1519 if (BE (ret < 0, 0))
1520 return REG_ESPACE;
1521 break;
1522 }
1523 /* In case of the node has another constraint, add it. */
1524 constraint |= dfa->nodes[org_node].constraint;
1525 clone_dest = duplicate_node (dfa, org_dest, constraint);
1526 if (BE (clone_dest == -1, 0))
1527 return REG_ESPACE;
1528 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1529 if (BE (ret < 0, 0))
1530 return REG_ESPACE;
1531 }
1532 else /* dfa->edests[org_node].nelem == 2 */
1533 {
1534 /* In case of the node can epsilon-transit, and it has two
1535 destinations. In the bin_tree_t and DFA, that's '|' and '*'. */
1536 org_dest = dfa->edests[org_node].elems[0];
1537 re_node_set_empty (dfa->edests + clone_node);
1538 /* Search for a duplicated node which satisfies the constraint. */
1539 clone_dest = search_duplicated_node (dfa, org_dest, constraint);
1540 if (clone_dest == -1)
1541 {
1542 /* There is no such duplicated node, create a new one. */
1543 reg_errcode_t err;
1544 clone_dest = duplicate_node (dfa, org_dest, constraint);
1545 if (BE (clone_dest == -1, 0))
1546 return REG_ESPACE;
1547 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1548 if (BE (ret < 0, 0))
1549 return REG_ESPACE;
1550 err = duplicate_node_closure (dfa, org_dest, clone_dest,
1551 root_node, constraint);
1552 if (BE (err != REG_NOERROR, 0))
1553 return err;
1554 }
1555 else
1556 {
1557 /* There is a duplicated node which satisfies the constraint,
1558 use it to avoid infinite loop. */
1559 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1560 if (BE (ret < 0, 0))
1561 return REG_ESPACE;
1562 }
1563
1564 org_dest = dfa->edests[org_node].elems[1];
1565 clone_dest = duplicate_node (dfa, org_dest, constraint);
1566 if (BE (clone_dest == -1, 0))
1567 return REG_ESPACE;
1568 ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
1569 if (BE (ret < 0, 0))
1570 return REG_ESPACE;
1571 }
1572 org_node = org_dest;
1573 clone_node = clone_dest;
1574 }
1575 return REG_NOERROR;
1576}
1577
1578/* Search for a node which is duplicated from the node ORG_NODE, and
1579 satisfies the constraint CONSTRAINT. */
1580
1581static int
1582search_duplicated_node (const re_dfa_t *dfa, int org_node,
1583 unsigned int constraint)
1584{
1585 int idx;
1586 for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx)
1587 {
1588 if (org_node == dfa->org_indices[idx]
1589 && constraint == dfa->nodes[idx].constraint)
1590 return idx; /* Found. */
1591 }
1592 return -1; /* Not found. */
1593}
1594
1595/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT.
1596 Return the index of the new node, or -1 if insufficient storage is
1597 available. */
1598
1599static int
1600duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint)
1601{
1602 int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]);
1603 if (BE (dup_idx != -1, 1))
1604 {
1605 dfa->nodes[dup_idx].constraint = constraint;
1606 dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].constraint;
1607 dfa->nodes[dup_idx].duplicated = 1;
1608
1609 /* Store the index of the original node. */
1610 dfa->org_indices[dup_idx] = org_idx;
1611 }
1612 return dup_idx;
1613}
1614
1615static reg_errcode_t
1616calc_inveclosure (re_dfa_t *dfa)
1617{
1618 int src, idx, ret;
1619 for (idx = 0; idx < dfa->nodes_len; ++idx)
1620 re_node_set_init_empty (dfa->inveclosures + idx);
1621
1622 for (src = 0; src < dfa->nodes_len; ++src)
1623 {
1624 int *elems = dfa->eclosures[src].elems;
1625 for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx)
1626 {
1627 ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src);
1628 if (BE (ret == -1, 0))
1629 return REG_ESPACE;
1630 }
1631 }
1632
1633 return REG_NOERROR;
1634}
1635
1636/* Calculate "eclosure" for all the node in DFA. */
1637
1638static reg_errcode_t
1639calc_eclosure (re_dfa_t *dfa)
1640{
1641 int node_idx, incomplete;
1642#ifdef DEBUG
1643 assert (dfa->nodes_len > 0);
1644#endif
1645 incomplete = 0;
1646 /* For each nodes, calculate epsilon closure. */
1647 for (node_idx = 0; ; ++node_idx)
1648 {
1649 reg_errcode_t err;
1650 re_node_set eclosure_elem;
1651 if (node_idx == dfa->nodes_len)
1652 {
1653 if (!incomplete)
1654 break;
1655 incomplete = 0;
1656 node_idx = 0;
1657 }
1658
1659#ifdef DEBUG
1660 assert (dfa->eclosures[node_idx].nelem != -1);
1661#endif
1662
1663 /* If we have already calculated, skip it. */
1664 if (dfa->eclosures[node_idx].nelem != 0)
1665 continue;
1666 /* Calculate epsilon closure of `node_idx'. */
1667 err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1);
1668 if (BE (err != REG_NOERROR, 0))
1669 return err;
1670
1671 if (dfa->eclosures[node_idx].nelem == 0)
1672 {
1673 incomplete = 1;
1674 re_node_set_free (&eclosure_elem);
1675 }
1676 }
1677 return REG_NOERROR;
1678}
1679
1680/* Calculate epsilon closure of NODE. */
1681
1682static reg_errcode_t
1683calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root)
1684{
1685 reg_errcode_t err;
1686 int i;
1687 re_node_set eclosure;
1688 int ret;
1689 int incomplete = 0;
1690 err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1);
1691 if (BE (err != REG_NOERROR, 0))
1692 return err;
1693
1694 /* This indicates that we are calculating this node now.
1695 We reference this value to avoid infinite loop. */
1696 dfa->eclosures[node].nelem = -1;
1697
1698 /* If the current node has constraints, duplicate all nodes
1699 since they must inherit the constraints. */
1700 if (dfa->nodes[node].constraint
1701 && dfa->edests[node].nelem
1702 && !dfa->nodes[dfa->edests[node].elems[0]].duplicated)
1703 {
1704 err = duplicate_node_closure (dfa, node, node, node,
1705 dfa->nodes[node].constraint);
1706 if (BE (err != REG_NOERROR, 0))
1707 return err;
1708 }
1709
1710 /* Expand each epsilon destination nodes. */
1711 if (IS_EPSILON_NODE(dfa->nodes[node].type))
1712 for (i = 0; i < dfa->edests[node].nelem; ++i)
1713 {
1714 re_node_set eclosure_elem;
1715 int edest = dfa->edests[node].elems[i];
1716 /* If calculating the epsilon closure of `edest' is in progress,
1717 return intermediate result. */
1718 if (dfa->eclosures[edest].nelem == -1)
1719 {
1720 incomplete = 1;
1721 continue;
1722 }
1723 /* If we haven't calculated the epsilon closure of `edest' yet,
1724 calculate now. Otherwise use calculated epsilon closure. */
1725 if (dfa->eclosures[edest].nelem == 0)
1726 {
1727 err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0);
1728 if (BE (err != REG_NOERROR, 0))
1729 return err;
1730 }
1731 else
1732 eclosure_elem = dfa->eclosures[edest];
1733 /* Merge the epsilon closure of `edest'. */
1734 err = re_node_set_merge (&eclosure, &eclosure_elem);
1735 if (BE (err != REG_NOERROR, 0))
1736 return err;
1737 /* If the epsilon closure of `edest' is incomplete,
1738 the epsilon closure of this node is also incomplete. */
1739 if (dfa->eclosures[edest].nelem == 0)
1740 {
1741 incomplete = 1;
1742 re_node_set_free (&eclosure_elem);
1743 }
1744 }
1745
1746 /* An epsilon closure includes itself. */
1747 ret = re_node_set_insert (&eclosure, node);
1748 if (BE (ret < 0, 0))
1749 return REG_ESPACE;
1750 if (incomplete && !root)
1751 dfa->eclosures[node].nelem = 0;
1752 else
1753 dfa->eclosures[node] = eclosure;
1754 *new_set = eclosure;
1755 return REG_NOERROR;
1756}
1757
1758/* Functions for token which are used in the parser. */
1759
1760/* Fetch a token from INPUT.
1761 We must not use this function inside bracket expressions. */
1762
1763static void
1764internal_function
1765fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax)
1766{
1767 re_string_skip_bytes (input, peek_token (result, input, syntax));
1768}
1769
1770/* Peek a token from INPUT, and return the length of the token.
1771 We must not use this function inside bracket expressions. */
1772
1773static int
1774internal_function
1775peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
1776{
1777 unsigned char c;
1778
1779 if (re_string_eoi (input))
1780 {
1781 token->type = END_OF_RE;
1782 return 0;
1783 }
1784
1785 c = re_string_peek_byte (input, 0);
1786 token->opr.c = c;
1787
1788 token->word_char = 0;
1789#ifdef RE_ENABLE_I18N
1790 token->mb_partial = 0;
1791 if (input->mb_cur_max > 1 &&
1792 !re_string_first_byte (input, re_string_cur_idx (input)))
1793 {
1794 token->type = CHARACTER;
1795 token->mb_partial = 1;
1796 return 1;
1797 }
1798#endif
1799 if (c == '\\')
1800 {
1801 unsigned char c2;
1802 if (re_string_cur_idx (input) + 1 >= re_string_length (input))
1803 {
1804 token->type = BACK_SLASH;
1805 return 1;
1806 }
1807
1808 c2 = re_string_peek_byte_case (input, 1);
1809 token->opr.c = c2;
1810 token->type = CHARACTER;
1811#ifdef RE_ENABLE_I18N
1812 if (input->mb_cur_max > 1)
1813 {
1814 wint_t wc = re_string_wchar_at (input,
1815 re_string_cur_idx (input) + 1);
1816 token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
1817 }
1818 else
1819#endif
1820 token->word_char = IS_WORD_CHAR (c2) != 0;
1821
1822 switch (c2)
1823 {
1824 case '|':
1825 if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR))
1826 token->type = OP_ALT;
1827 break;
1828 case '1': case '2': case '3': case '4': case '5':
1829 case '6': case '7': case '8': case '9':
1830 if (!(syntax & RE_NO_BK_REFS))
1831 {
1832 token->type = OP_BACK_REF;
1833 token->opr.idx = c2 - '1';
1834 }
1835 break;
1836 case '<':
1837 if (!(syntax & RE_NO_GNU_OPS))
1838 {
1839 token->type = ANCHOR;
1840 token->opr.ctx_type = WORD_FIRST;
1841 }
1842 break;
1843 case '>':
1844 if (!(syntax & RE_NO_GNU_OPS))
1845 {
1846 token->type = ANCHOR;
1847 token->opr.ctx_type = WORD_LAST;
1848 }
1849 break;
1850 case 'b':
1851 if (!(syntax & RE_NO_GNU_OPS))
1852 {
1853 token->type = ANCHOR;
1854 token->opr.ctx_type = WORD_DELIM;
1855 }
1856 break;
1857 case 'B':
1858 if (!(syntax & RE_NO_GNU_OPS))
1859 {
1860 token->type = ANCHOR;
1861 token->opr.ctx_type = NOT_WORD_DELIM;
1862 }
1863 break;
1864 case 'w':
1865 if (!(syntax & RE_NO_GNU_OPS))
1866 token->type = OP_WORD;
1867 break;
1868 case 'W':
1869 if (!(syntax & RE_NO_GNU_OPS))
1870 token->type = OP_NOTWORD;
1871 break;
1872 case 's':
1873 if (!(syntax & RE_NO_GNU_OPS))
1874 token->type = OP_SPACE;
1875 break;
1876 case 'S':
1877 if (!(syntax & RE_NO_GNU_OPS))
1878 token->type = OP_NOTSPACE;
1879 break;
1880 case '`':
1881 if (!(syntax & RE_NO_GNU_OPS))
1882 {
1883 token->type = ANCHOR;
1884 token->opr.ctx_type = BUF_FIRST;
1885 }
1886 break;
1887 case '\'':
1888 if (!(syntax & RE_NO_GNU_OPS))
1889 {
1890 token->type = ANCHOR;
1891 token->opr.ctx_type = BUF_LAST;
1892 }
1893 break;
1894 case '(':
1895 if (!(syntax & RE_NO_BK_PARENS))
1896 token->type = OP_OPEN_SUBEXP;
1897 break;
1898 case ')':
1899 if (!(syntax & RE_NO_BK_PARENS))
1900 token->type = OP_CLOSE_SUBEXP;
1901 break;
1902 case '+':
1903 if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
1904 token->type = OP_DUP_PLUS;
1905 break;
1906 case '?':
1907 if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
1908 token->type = OP_DUP_QUESTION;
1909 break;
1910 case '{':
1911 if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
1912 token->type = OP_OPEN_DUP_NUM;
1913 break;
1914 case '}':
1915 if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
1916 token->type = OP_CLOSE_DUP_NUM;
1917 break;
1918 default:
1919 break;
1920 }
1921 return 2;
1922 }
1923
1924 token->type = CHARACTER;
1925#ifdef RE_ENABLE_I18N
1926 if (input->mb_cur_max > 1)
1927 {
1928 wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
1929 token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
1930 }
1931 else
1932#endif
1933 token->word_char = IS_WORD_CHAR (token->opr.c);
1934
1935 switch (c)
1936 {
1937 case '\n':
1938 if (syntax & RE_NEWLINE_ALT)
1939 token->type = OP_ALT;
1940 break;
1941 case '|':
1942 if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR))
1943 token->type = OP_ALT;
1944 break;
1945 case '*':
1946 token->type = OP_DUP_ASTERISK;
1947 break;
1948 case '+':
1949 if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
1950 token->type = OP_DUP_PLUS;
1951 break;
1952 case '?':
1953 if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
1954 token->type = OP_DUP_QUESTION;
1955 break;
1956 case '{':
1957 if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
1958 token->type = OP_OPEN_DUP_NUM;
1959 break;
1960 case '}':
1961 if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
1962 token->type = OP_CLOSE_DUP_NUM;
1963 break;
1964 case '(':
1965 if (syntax & RE_NO_BK_PARENS)
1966 token->type = OP_OPEN_SUBEXP;
1967 break;
1968 case ')':
1969 if (syntax & RE_NO_BK_PARENS)
1970 token->type = OP_CLOSE_SUBEXP;
1971 break;
1972 case '[':
1973 token->type = OP_OPEN_BRACKET;
1974 break;
1975 case '.':
1976 token->type = OP_PERIOD;
1977 break;
1978 case '^':
1979 if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) &&
1980 re_string_cur_idx (input) != 0)
1981 {
1982 char prev = re_string_peek_byte (input, -1);
1983 if (!(syntax & RE_NEWLINE_ALT) || prev != '\n')
1984 break;
1985 }
1986 token->type = ANCHOR;
1987 token->opr.ctx_type = LINE_FIRST;
1988 break;
1989 case '$':
1990 if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) &&
1991 re_string_cur_idx (input) + 1 != re_string_length (input))
1992 {
1993 re_token_t next;
1994 re_string_skip_bytes (input, 1);
1995 peek_token (&next, input, syntax);
1996 re_string_skip_bytes (input, -1);
1997 if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP)
1998 break;
1999 }
2000 token->type = ANCHOR;
2001 token->opr.ctx_type = LINE_LAST;
2002 break;
2003 default:
2004 break;
2005 }
2006 return 1;
2007}
2008
2009/* Peek a token from INPUT, and return the length of the token.
2010 We must not use this function out of bracket expressions. */
2011
2012static int
2013internal_function
2014peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
2015{
2016 unsigned char c;
2017 if (re_string_eoi (input))
2018 {
2019 token->type = END_OF_RE;
2020 return 0;
2021 }
2022 c = re_string_peek_byte (input, 0);
2023 token->opr.c = c;
2024
2025#ifdef RE_ENABLE_I18N
2026 if (input->mb_cur_max > 1 &&
2027 !re_string_first_byte (input, re_string_cur_idx (input)))
2028 {
2029 token->type = CHARACTER;
2030 return 1;
2031 }
2032#endif /* RE_ENABLE_I18N */
2033
2034 if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS)
2035 && re_string_cur_idx (input) + 1 < re_string_length (input))
2036 {
2037 /* In this case, '\' escape a character. */
2038 unsigned char c2;
2039 re_string_skip_bytes (input, 1);
2040 c2 = re_string_peek_byte (input, 0);
2041 token->opr.c = c2;
2042 token->type = CHARACTER;
2043 return 1;
2044 }
2045 if (c == '[') /* '[' is a special char in a bracket exps. */
2046 {
2047 unsigned char c2;
2048 int token_len;
2049 if (re_string_cur_idx (input) + 1 < re_string_length (input))
2050 c2 = re_string_peek_byte (input, 1);
2051 else
2052 c2 = 0;
2053 token->opr.c = c2;
2054 token_len = 2;
2055 switch (c2)
2056 {
2057 case '.':
2058 token->type = OP_OPEN_COLL_ELEM;
2059 break;
2060 case '=':
2061 token->type = OP_OPEN_EQUIV_CLASS;
2062 break;
2063 case ':':
2064 if (syntax & RE_CHAR_CLASSES)
2065 {
2066 token->type = OP_OPEN_CHAR_CLASS;
2067 break;
2068 }
2069 /* else fall through. */
2070 default:
2071 token->type = CHARACTER;
2072 token->opr.c = c;
2073 token_len = 1;
2074 break;
2075 }
2076 return token_len;
2077 }
2078 switch (c)
2079 {
2080 case '-':
2081 token->type = OP_CHARSET_RANGE;
2082 break;
2083 case ']':
2084 token->type = OP_CLOSE_BRACKET;
2085 break;
2086 case '^':
2087 token->type = OP_NON_MATCH_LIST;
2088 break;
2089 default:
2090 token->type = CHARACTER;
2091 }
2092 return 1;
2093}
2094
2095/* Functions for parser. */
2096
2097/* Entry point of the parser.
2098 Parse the regular expression REGEXP and return the structure tree.
2099 If an error has occurred, ERR is set by error code, and return NULL.
2100 This function build the following tree, from regular expression <reg_exp>:
2101 CAT
2102 / \
2103 / \
2104 <reg_exp> EOR
2105
2106 CAT means concatenation.
2107 EOR means end of regular expression. */
2108
2109static bin_tree_t *
2110parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax,
2111 reg_errcode_t *err)
2112{
2113 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2114 bin_tree_t *tree, *eor, *root;
2115 re_token_t current_token;
2116 dfa->syntax = syntax;
2117 fetch_token (&current_token, regexp, syntax | RE_CARET_ANCHORS_HERE);
2118 tree = parse_reg_exp (regexp, preg, &current_token, syntax, 0, err);
2119 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2120 return NULL;
2121 eor = create_tree (dfa, NULL, NULL, END_OF_RE);
2122 if (tree != NULL)
2123 root = create_tree (dfa, tree, eor, CONCAT);
2124 else
2125 root = eor;
2126 if (BE (eor == NULL || root == NULL, 0))
2127 {
2128 *err = REG_ESPACE;
2129 return NULL;
2130 }
2131 return root;
2132}
2133
2134/* This function build the following tree, from regular expression
2135 <branch1>|<branch2>:
2136 ALT
2137 / \
2138 / \
2139 <branch1> <branch2>
2140
2141 ALT means alternative, which represents the operator `|'. */
2142
2143static bin_tree_t *
2144parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
2145 reg_syntax_t syntax, int nest, reg_errcode_t *err)
2146{
2147 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2148 bin_tree_t *tree, *branch = NULL;
2149 tree = parse_branch (regexp, preg, token, syntax, nest, err);
2150 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2151 return NULL;
2152
2153 while (token->type == OP_ALT)
2154 {
2155 fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
2156 if (token->type != OP_ALT && token->type != END_OF_RE
2157 && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
2158 {
2159 branch = parse_branch (regexp, preg, token, syntax, nest, err);
2160 if (BE (*err != REG_NOERROR && branch == NULL, 0))
2161 return NULL;
2162 }
2163 else
2164 branch = NULL;
2165 tree = create_tree (dfa, tree, branch, OP_ALT);
2166 if (BE (tree == NULL, 0))
2167 {
2168 *err = REG_ESPACE;
2169 return NULL;
2170 }
2171 }
2172 return tree;
2173}
2174
2175/* This function build the following tree, from regular expression
2176 <exp1><exp2>:
2177 CAT
2178 / \
2179 / \
2180 <exp1> <exp2>
2181
2182 CAT means concatenation. */
2183
2184static bin_tree_t *
2185parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token,
2186 reg_syntax_t syntax, int nest, reg_errcode_t *err)
2187{
2188 bin_tree_t *tree, *exp;
2189 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2190 tree = parse_expression (regexp, preg, token, syntax, nest, err);
2191 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2192 return NULL;
2193
2194 while (token->type != OP_ALT && token->type != END_OF_RE
2195 && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
2196 {
2197 exp = parse_expression (regexp, preg, token, syntax, nest, err);
2198 if (BE (*err != REG_NOERROR && exp == NULL, 0))
2199 {
2200 return NULL;
2201 }
2202 if (tree != NULL && exp != NULL)
2203 {
2204 tree = create_tree (dfa, tree, exp, CONCAT);
2205 if (tree == NULL)
2206 {
2207 *err = REG_ESPACE;
2208 return NULL;
2209 }
2210 }
2211 else if (tree == NULL)
2212 tree = exp;
2213 /* Otherwise exp == NULL, we don't need to create new tree. */
2214 }
2215 return tree;
2216}
2217
2218/* This function build the following tree, from regular expression a*:
2219 *
2220 |
2221 a
2222*/
2223
2224static bin_tree_t *
2225parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token,
2226 reg_syntax_t syntax, int nest, reg_errcode_t *err)
2227{
2228 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2229 bin_tree_t *tree;
2230 switch (token->type)
2231 {
2232 case CHARACTER:
2233 tree = create_token_tree (dfa, NULL, NULL, token);
2234 if (BE (tree == NULL, 0))
2235 {
2236 *err = REG_ESPACE;
2237 return NULL;
2238 }
2239#ifdef RE_ENABLE_I18N
2240 if (dfa->mb_cur_max > 1)
2241 {
2242 while (!re_string_eoi (regexp)
2243 && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
2244 {
2245 bin_tree_t *mbc_remain;
2246 fetch_token (token, regexp, syntax);
2247 mbc_remain = create_token_tree (dfa, NULL, NULL, token);
2248 tree = create_tree (dfa, tree, mbc_remain, CONCAT);
2249 if (BE (mbc_remain == NULL || tree == NULL, 0))
2250 {
2251 *err = REG_ESPACE;
2252 return NULL;
2253 }
2254 }
2255 }
2256#endif
2257 break;
2258 case OP_OPEN_SUBEXP:
2259 tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err);
2260 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2261 return NULL;
2262 break;
2263 case OP_OPEN_BRACKET:
2264 tree = parse_bracket_exp (regexp, dfa, token, syntax, err);
2265 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2266 return NULL;
2267 break;
2268 case OP_BACK_REF:
2269 if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1))
2270 {
2271 *err = REG_ESUBREG;
2272 return NULL;
2273 }
2274 dfa->used_bkref_map |= 1 << token->opr.idx;
2275 tree = create_token_tree (dfa, NULL, NULL, token);
2276 if (BE (tree == NULL, 0))
2277 {
2278 *err = REG_ESPACE;
2279 return NULL;
2280 }
2281 ++dfa->nbackref;
2282 dfa->has_mb_node = 1;
2283 break;
2284 case OP_OPEN_DUP_NUM:
2285 if (syntax & RE_CONTEXT_INVALID_DUP)
2286 {
2287 *err = REG_BADRPT;
2288 return NULL;
2289 }
2290 /* FALLTHROUGH */
2291 case OP_DUP_ASTERISK:
2292 case OP_DUP_PLUS:
2293 case OP_DUP_QUESTION:
2294 if (syntax & RE_CONTEXT_INVALID_OPS)
2295 {
2296 *err = REG_BADRPT;
2297 return NULL;
2298 }
2299 else if (syntax & RE_CONTEXT_INDEP_OPS)
2300 {
2301 fetch_token (token, regexp, syntax);
2302 return parse_expression (regexp, preg, token, syntax, nest, err);
2303 }
2304 /* else fall through */
2305 case OP_CLOSE_SUBEXP:
2306 if ((token->type == OP_CLOSE_SUBEXP) &&
2307 !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD))
2308 {
2309 *err = REG_ERPAREN;
2310 return NULL;
2311 }
2312 /* else fall through */
2313 case OP_CLOSE_DUP_NUM:
2314 /* We treat it as a normal character. */
2315
2316 /* Then we can these characters as normal characters. */
2317 token->type = CHARACTER;
2318 /* mb_partial and word_char bits should be initialized already
2319 by peek_token. */
2320 tree = create_token_tree (dfa, NULL, NULL, token);
2321 if (BE (tree == NULL, 0))
2322 {
2323 *err = REG_ESPACE;
2324 return NULL;
2325 }
2326 break;
2327 case ANCHOR:
2328 if ((token->opr.ctx_type
2329 & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST))
2330 && dfa->word_ops_used == 0)
2331 init_word_char (dfa);
2332 if (token->opr.ctx_type == WORD_DELIM
2333 || token->opr.ctx_type == NOT_WORD_DELIM)
2334 {
2335 bin_tree_t *tree_first, *tree_last;
2336 if (token->opr.ctx_type == WORD_DELIM)
2337 {
2338 token->opr.ctx_type = WORD_FIRST;
2339 tree_first = create_token_tree (dfa, NULL, NULL, token);
2340 token->opr.ctx_type = WORD_LAST;
2341 }
2342 else
2343 {
2344 token->opr.ctx_type = INSIDE_WORD;
2345 tree_first = create_token_tree (dfa, NULL, NULL, token);
2346 token->opr.ctx_type = INSIDE_NOTWORD;
2347 }
2348 tree_last = create_token_tree (dfa, NULL, NULL, token);
2349 tree = create_tree (dfa, tree_first, tree_last, OP_ALT);
2350 if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0))
2351 {
2352 *err = REG_ESPACE;
2353 return NULL;
2354 }
2355 }
2356 else
2357 {
2358 tree = create_token_tree (dfa, NULL, NULL, token);
2359 if (BE (tree == NULL, 0))
2360 {
2361 *err = REG_ESPACE;
2362 return NULL;
2363 }
2364 }
2365 /* We must return here, since ANCHORs can't be followed
2366 by repetition operators.
2367 eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>",
2368 it must not be "<ANCHOR(^)><REPEAT(*)>". */
2369 fetch_token (token, regexp, syntax);
2370 return tree;
2371 case OP_PERIOD:
2372 tree = create_token_tree (dfa, NULL, NULL, token);
2373 if (BE (tree == NULL, 0))
2374 {
2375 *err = REG_ESPACE;
2376 return NULL;
2377 }
2378 if (dfa->mb_cur_max > 1)
2379 dfa->has_mb_node = 1;
2380 break;
2381 case OP_WORD:
2382 case OP_NOTWORD:
2383 tree = build_charclass_op (dfa, regexp->trans,
2384 "alnum",
2385 "_",
2386 token->type == OP_NOTWORD, err);
2387 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2388 return NULL;
2389 break;
2390 case OP_SPACE:
2391 case OP_NOTSPACE:
2392 tree = build_charclass_op (dfa, regexp->trans,
2393 "space",
2394 "",
2395 token->type == OP_NOTSPACE, err);
2396 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2397 return NULL;
2398 break;
2399 case OP_ALT:
2400 case END_OF_RE:
2401 return NULL;
2402 case BACK_SLASH:
2403 *err = REG_EESCAPE;
2404 return NULL;
2405 default:
2406 /* Must not happen? */
2407#ifdef DEBUG
2408 assert (0);
2409#endif
2410 return NULL;
2411 }
2412 fetch_token (token, regexp, syntax);
2413
2414 while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS
2415 || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM)
2416 {
2417 tree = parse_dup_op (tree, regexp, dfa, token, syntax, err);
2418 if (BE (*err != REG_NOERROR && tree == NULL, 0))
2419 return NULL;
2420 /* In BRE consecutive duplications are not allowed. */
2421 if ((syntax & RE_CONTEXT_INVALID_DUP)
2422 && (token->type == OP_DUP_ASTERISK
2423 || token->type == OP_OPEN_DUP_NUM))
2424 {
2425 *err = REG_BADRPT;
2426 return NULL;
2427 }
2428 }
2429
2430 return tree;
2431}
2432
2433/* This function build the following tree, from regular expression
2434 (<reg_exp>):
2435 SUBEXP
2436 |
2437 <reg_exp>
2438*/
2439
2440static bin_tree_t *
2441parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
2442 reg_syntax_t syntax, int nest, reg_errcode_t *err)
2443{
2444 re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
2445 bin_tree_t *tree;
2446 size_t cur_nsub;
2447 cur_nsub = preg->re_nsub++;
2448
2449 fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
2450
2451 /* The subexpression may be a null string. */
2452 if (token->type == OP_CLOSE_SUBEXP)
2453 tree = NULL;
2454 else
2455 {
2456 tree = parse_reg_exp (regexp, preg, token, syntax, nest, err);
2457 if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0))
2458 *err = REG_EPAREN;
2459 if (BE (*err != REG_NOERROR, 0))
2460 return NULL;
2461 }
2462
2463 if (cur_nsub <= '9' - '1')
2464 dfa->completed_bkref_map |= 1 << cur_nsub;
2465
2466 tree = create_tree (dfa, tree, NULL, SUBEXP);
2467 if (BE (tree == NULL, 0))
2468 {
2469 *err = REG_ESPACE;
2470 return NULL;
2471 }
2472 tree->token.opr.idx = cur_nsub;
2473 return tree;
2474}
2475
2476/* This function parse repetition operators like "*", "+", "{1,3}" etc. */
2477
2478static bin_tree_t *
2479parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
2480 re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err)
2481{
2482 bin_tree_t *tree = NULL, *old_tree = NULL;
2483 int i, start, end, start_idx = re_string_cur_idx (regexp);
2484#ifndef RE_TOKEN_INIT_BUG
2485 re_token_t start_token = *token;
2486#else
2487 re_token_t start_token;
2488
2489 memcpy ((void *) &start_token, (void *) token, sizeof start_token);
2490#endif
2491
2492 if (token->type == OP_OPEN_DUP_NUM)
2493 {
2494 end = 0;
2495 start = fetch_number (regexp, token, syntax);
2496 if (start == -1)
2497 {
2498 if (token->type == CHARACTER && token->opr.c == ',')
2499 start = 0; /* We treat "{,m}" as "{0,m}". */
2500 else
2501 {
2502 *err = REG_BADBR; /* <re>{} is invalid. */
2503 return NULL;
2504 }
2505 }
2506 if (BE (start != -2, 1))
2507 {
2508 /* We treat "{n}" as "{n,n}". */
2509 end = ((token->type == OP_CLOSE_DUP_NUM) ? start
2510 : ((token->type == CHARACTER && token->opr.c == ',')
2511 ? fetch_number (regexp, token, syntax) : -2));
2512 }
2513 if (BE (start == -2 || end == -2, 0))
2514 {
2515 /* Invalid sequence. */
2516 if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0))
2517 {
2518 if (token->type == END_OF_RE)
2519 *err = REG_EBRACE;
2520 else
2521 *err = REG_BADBR;
2522
2523 return NULL;
2524 }
2525
2526 /* If the syntax bit is set, rollback. */
2527 re_string_set_index (regexp, start_idx);
2528 *token = start_token;
2529 token->type = CHARACTER;
2530 /* mb_partial and word_char bits should be already initialized by
2531 peek_token. */
2532 return elem;
2533 }
2534
2535 if (BE ((end != -1 && start > end) || token->type != OP_CLOSE_DUP_NUM, 0))
2536 {
2537 /* First number greater than second. */
2538 *err = REG_BADBR;
2539 return NULL;
2540 }
2541 }
2542 else
2543 {
2544 start = (token->type == OP_DUP_PLUS) ? 1 : 0;
2545 end = (token->type == OP_DUP_QUESTION) ? 1 : -1;
2546 }
2547
2548 fetch_token (token, regexp, syntax);
2549
2550 if (BE (elem == NULL, 0))
2551 return NULL;
2552 if (BE (start == 0 && end == 0, 0))
2553 {
2554 postorder (elem, free_tree, NULL);
2555 return NULL;
2556 }
2557
2558 /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */
2559 if (BE (start > 0, 0))
2560 {
2561 tree = elem;
2562 for (i = 2; i <= start; ++i)
2563 {
2564 elem = duplicate_tree (elem, dfa);
2565 tree = create_tree (dfa, tree, elem, CONCAT);
2566 if (BE (elem == NULL || tree == NULL, 0))
2567 goto parse_dup_op_espace;
2568 }
2569
2570 if (start == end)
2571 return tree;
2572
2573 /* Duplicate ELEM before it is marked optional. */
2574 elem = duplicate_tree (elem, dfa);
2575 old_tree = tree;
2576 }
2577 else
2578 old_tree = NULL;
2579
2580 if (elem->token.type == SUBEXP)
2581 postorder (elem, mark_opt_subexp, (void *) (intptr_t) elem->token.opr.idx);
2582
2583 tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT));
2584 if (BE (tree == NULL, 0))
2585 goto parse_dup_op_espace;
2586
2587 /* This loop is actually executed only when end != -1,
2588 to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have
2589 already created the start+1-th copy. */
2590 for (i = start + 2; i <= end; ++i)
2591 {
2592 elem = duplicate_tree (elem, dfa);
2593 tree = create_tree (dfa, tree, elem, CONCAT);
2594 if (BE (elem == NULL || tree == NULL, 0))
2595 goto parse_dup_op_espace;
2596
2597 tree = create_tree (dfa, tree, NULL, OP_ALT);
2598 if (BE (tree == NULL, 0))
2599 goto parse_dup_op_espace;
2600 }
2601
2602 if (old_tree)
2603 tree = create_tree (dfa, old_tree, tree, CONCAT);
2604
2605 return tree;
2606
2607 parse_dup_op_espace:
2608 *err = REG_ESPACE;
2609 return NULL;
2610}
2611
2612/* Size of the names for collating symbol/equivalence_class/character_class.
2613 I'm not sure, but maybe enough. */
2614#define BRACKET_NAME_BUF_SIZE 32
2615
2616#ifndef _LIBC
2617 /* Local function for parse_bracket_exp only used in case of NOT _LIBC.
2618 Build the range expression which starts from START_ELEM, and ends
2619 at END_ELEM. The result are written to MBCSET and SBCSET.
2620 RANGE_ALLOC is the allocated size of mbcset->range_starts, and
2621 mbcset->range_ends, is a pointer argument since we may
2622 update it. */
2623
2624static reg_errcode_t
2625internal_function
2626# ifdef RE_ENABLE_I18N
2627build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc,
2628 bracket_elem_t *start_elem, bracket_elem_t *end_elem)
2629# else /* not RE_ENABLE_I18N */
2630build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem,
2631 bracket_elem_t *end_elem)
2632# endif /* not RE_ENABLE_I18N */
2633{
2634 unsigned int start_ch, end_ch;
2635 /* Equivalence Classes and Character Classes can't be a range start/end. */
2636 if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
2637 || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
2638 0))
2639 return REG_ERANGE;
2640
2641 /* We can handle no multi character collating elements without libc
2642 support. */
2643 if (BE ((start_elem->type == COLL_SYM
2644 && strlen ((char *) start_elem->opr.name) > 1)
2645 || (end_elem->type == COLL_SYM
2646 && strlen ((char *) end_elem->opr.name) > 1), 0))
2647 return REG_ECOLLATE;
2648
2649# ifdef RE_ENABLE_I18N
2650 {
2651 wchar_t wc;
2652 wint_t start_wc;
2653 wint_t end_wc;
2654 wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
2655
2656 start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch
2657 : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
2658 : 0));
2659 end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch
2660 : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
2661 : 0));
2662#ifdef GAWK
2663 /*
2664 * Fedora Core 2, maybe others, have broken `btowc' that returns -1
2665 * for any value > 127. Sigh. Note that `start_ch' and `end_ch' are
2666 * unsigned, so we don't have sign extension problems.
2667 */
2668 start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
2669 ? start_ch : start_elem->opr.wch);
2670 end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
2671 ? end_ch : end_elem->opr.wch);
2672#else
2673 start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
2674 ? __btowc (start_ch) : start_elem->opr.wch);
2675 end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
2676 ? __btowc (end_ch) : end_elem->opr.wch);
2677#endif
2678 if (start_wc == WEOF || end_wc == WEOF)
2679 return REG_ECOLLATE;
2680 cmp_buf[0] = start_wc;
2681 cmp_buf[4] = end_wc;
2682 if (wcscoll (cmp_buf, cmp_buf + 4) > 0)
2683 return REG_ERANGE;
2684
2685 /* Got valid collation sequence values, add them as a new entry.
2686 However, for !_LIBC we have no collation elements: if the
2687 character set is single byte, the single byte character set
2688 that we build below suffices. parse_bracket_exp passes
2689 no MBCSET if dfa->mb_cur_max == 1. */
2690 if (mbcset)
2691 {
2692 /* Check the space of the arrays. */
2693 if (BE (*range_alloc == mbcset->nranges, 0))
2694 {
2695 /* There is not enough space, need realloc. */
2696 wchar_t *new_array_start, *new_array_end;
2697 int new_nranges;
2698
2699 /* +1 in case of mbcset->nranges is 0. */
2700 new_nranges = 2 * mbcset->nranges + 1;
2701 /* Use realloc since mbcset->range_starts and mbcset->range_ends
2702 are NULL if *range_alloc == 0. */
2703 new_array_start = re_realloc (mbcset->range_starts, wchar_t,
2704 new_nranges);
2705 new_array_end = re_realloc (mbcset->range_ends, wchar_t,
2706 new_nranges);
2707
2708 if (BE (new_array_start == NULL || new_array_end == NULL, 0))
2709 return REG_ESPACE;
2710
2711 mbcset->range_starts = new_array_start;
2712 mbcset->range_ends = new_array_end;
2713 *range_alloc = new_nranges;
2714 }
2715
2716 mbcset->range_starts[mbcset->nranges] = start_wc;
2717 mbcset->range_ends[mbcset->nranges++] = end_wc;
2718 }
2719
2720 /* Build the table for single byte characters. */
2721 for (wc = 0; wc < SBC_MAX; ++wc)
2722 {
2723 cmp_buf[2] = wc;
2724 if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
2725 && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
2726 bitset_set (sbcset, wc);
2727 }
2728 }
2729# else /* not RE_ENABLE_I18N */
2730 {
2731 unsigned int ch;
2732 start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch
2733 : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
2734 : 0));
2735 end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch
2736 : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
2737 : 0));
2738 if (start_ch > end_ch)
2739 return REG_ERANGE;
2740 /* Build the table for single byte characters. */
2741 for (ch = 0; ch < SBC_MAX; ++ch)
2742 if (start_ch <= ch && ch <= end_ch)
2743 bitset_set (sbcset, ch);
2744 }
2745# endif /* not RE_ENABLE_I18N */
2746 return REG_NOERROR;
2747}
2748#endif /* not _LIBC */
2749
2750#ifndef _LIBC
2751/* Helper function for parse_bracket_exp only used in case of NOT _LIBC..
2752 Build the collating element which is represented by NAME.
2753 The result are written to MBCSET and SBCSET.
2754 COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
2755 pointer argument since we may update it. */
2756
2757static reg_errcode_t
2758internal_function
2759# ifdef RE_ENABLE_I18N
2760build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset,
2761 int *coll_sym_alloc, const unsigned char *name)
2762# else /* not RE_ENABLE_I18N */
2763build_collating_symbol (bitset_t sbcset, const unsigned char *name)
2764# endif /* not RE_ENABLE_I18N */
2765{
2766 size_t name_len = strlen ((const char *) name);
2767 if (BE (name_len != 1, 0))
2768 return REG_ECOLLATE;
2769 else
2770 {
2771 bitset_set (sbcset, name[0]);
2772 return REG_NOERROR;
2773 }
2774}
2775#endif /* not _LIBC */
2776
2777/* This function parse bracket expression like "[abc]", "[a-c]",
2778 "[[.a-a.]]" etc. */
2779
2780static bin_tree_t *
2781parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
2782 reg_syntax_t syntax, reg_errcode_t *err)
2783{
2784#ifdef _LIBC
2785 const unsigned char *collseqmb;
2786 const char *collseqwc;
2787 uint32_t nrules;
2788 int32_t table_size;
2789 const int32_t *symb_table;
2790 const unsigned char *extra;
2791
2792 /* Local function for parse_bracket_exp used in _LIBC environment.
2793 Seek the collating symbol entry correspondings to NAME.
2794 Return the index of the symbol in the SYMB_TABLE. */
2795
2796 auto inline int32_t
2797 __attribute ((always_inline))
2798 seek_collating_symbol_entry (name, name_len)
2799 const unsigned char *name;
2800 size_t name_len;
2801 {
2802 int32_t hash = elem_hash ((const char *) name, name_len);
2803 int32_t elem = hash % table_size;
2804 if (symb_table[2 * elem] != 0)
2805 {
2806 int32_t second = hash % (table_size - 2) + 1;
2807
2808 do
2809 {
2810 /* First compare the hashing value. */
2811 if (symb_table[2 * elem] == hash
2812 /* Compare the length of the name. */
2813 && name_len == extra[symb_table[2 * elem + 1]]
2814 /* Compare the name. */
2815 && memcmp (name, &extra[symb_table[2 * elem + 1] + 1],
2816 name_len) == 0)
2817 {
2818 /* Yep, this is the entry. */
2819 break;
2820 }
2821
2822 /* Next entry. */
2823 elem += second;
2824 }
2825 while (symb_table[2 * elem] != 0);
2826 }
2827 return elem;
2828 }
2829
2830 /* Local function for parse_bracket_exp used in _LIBC environment.
2831 Look up the collation sequence value of BR_ELEM.
2832 Return the value if succeeded, UINT_MAX otherwise. */
2833
2834 auto inline unsigned int
2835 __attribute ((always_inline))
2836 lookup_collation_sequence_value (br_elem)
2837 bracket_elem_t *br_elem;
2838 {
2839 if (br_elem->type == SB_CHAR)
2840 {
2841 /*
2842 if (MB_CUR_MAX == 1)
2843 */
2844 if (nrules == 0)
2845 return collseqmb[br_elem->opr.ch];
2846 else
2847 {
2848 wint_t wc = __btowc (br_elem->opr.ch);
2849 return __collseq_table_lookup (collseqwc, wc);
2850 }
2851 }
2852 else if (br_elem->type == MB_CHAR)
2853 {
2854 if (nrules != 0)
2855 return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
2856 }
2857 else if (br_elem->type == COLL_SYM)
2858 {
2859 size_t sym_name_len = strlen ((char *) br_elem->opr.name);
2860 if (nrules != 0)
2861 {
2862 int32_t elem, idx;
2863 elem = seek_collating_symbol_entry (br_elem->opr.name,
2864 sym_name_len);
2865 if (symb_table[2 * elem] != 0)
2866 {
2867 /* We found the entry. */
2868 idx = symb_table[2 * elem + 1];
2869 /* Skip the name of collating element name. */
2870 idx += 1 + extra[idx];
2871 /* Skip the byte sequence of the collating element. */
2872 idx += 1 + extra[idx];
2873 /* Adjust for the alignment. */
2874 idx = (idx + 3) & ~3;
2875 /* Skip the multibyte collation sequence value. */
2876 idx += sizeof (unsigned int);
2877 /* Skip the wide char sequence of the collating element. */
2878 idx += sizeof (unsigned int) *
2879 (1 + *(unsigned int *) (extra + idx));
2880 /* Return the collation sequence value. */
2881 return *(unsigned int *) (extra + idx);
2882 }
2883 else if (symb_table[2 * elem] == 0 && sym_name_len == 1)
2884 {
2885 /* No valid character. Match it as a single byte
2886 character. */
2887 return collseqmb[br_elem->opr.name[0]];
2888 }
2889 }
2890 else if (sym_name_len == 1)
2891 return collseqmb[br_elem->opr.name[0]];
2892 }
2893 return UINT_MAX;
2894 }
2895
2896 /* Local function for parse_bracket_exp used in _LIBC environment.
2897 Build the range expression which starts from START_ELEM, and ends
2898 at END_ELEM. The result are written to MBCSET and SBCSET.
2899 RANGE_ALLOC is the allocated size of mbcset->range_starts, and
2900 mbcset->range_ends, is a pointer argument since we may
2901 update it. */
2902
2903 auto inline reg_errcode_t
2904 __attribute ((always_inline))
2905 build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem)
2906 re_charset_t *mbcset;
2907 int *range_alloc;
2908 bitset_t sbcset;
2909 bracket_elem_t *start_elem, *end_elem;
2910 {
2911 unsigned int ch;
2912 uint32_t start_collseq;
2913 uint32_t end_collseq;
2914
2915 /* Equivalence Classes and Character Classes can't be a range
2916 start/end. */
2917 if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
2918 || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
2919 0))
2920 return REG_ERANGE;
2921
2922 start_collseq = lookup_collation_sequence_value (start_elem);
2923 end_collseq = lookup_collation_sequence_value (end_elem);
2924 /* Check start/end collation sequence values. */
2925 if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0))
2926 return REG_ECOLLATE;
2927 if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0))
2928 return REG_ERANGE;
2929
2930 /* Got valid collation sequence values, add them as a new entry.
2931 However, if we have no collation elements, and the character set
2932 is single byte, the single byte character set that we
2933 build below suffices. */
2934 if (nrules > 0 || dfa->mb_cur_max > 1)
2935 {
2936 /* Check the space of the arrays. */
2937 if (BE (*range_alloc == mbcset->nranges, 0))
2938 {
2939 /* There is not enough space, need realloc. */
2940 uint32_t *new_array_start;
2941 uint32_t *new_array_end;
2942 int new_nranges;
2943
2944 /* +1 in case of mbcset->nranges is 0. */
2945 new_nranges = 2 * mbcset->nranges + 1;
2946 new_array_start = re_realloc (mbcset->range_starts, uint32_t,
2947 new_nranges);
2948 new_array_end = re_realloc (mbcset->range_ends, uint32_t,
2949 new_nranges);
2950
2951 if (BE (new_array_start == NULL || new_array_end == NULL, 0))
2952 return REG_ESPACE;
2953
2954 mbcset->range_starts = new_array_start;
2955 mbcset->range_ends = new_array_end;
2956 *range_alloc = new_nranges;
2957 }
2958
2959 mbcset->range_starts[mbcset->nranges] = start_collseq;
2960 mbcset->range_ends[mbcset->nranges++] = end_collseq;
2961 }
2962
2963 /* Build the table for single byte characters. */
2964 for (ch = 0; ch < SBC_MAX; ch++)
2965 {
2966 uint32_t ch_collseq;
2967 /*
2968 if (MB_CUR_MAX == 1)
2969 */
2970 if (nrules == 0)
2971 ch_collseq = collseqmb[ch];
2972 else
2973 ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
2974 if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
2975 bitset_set (sbcset, ch);
2976 }
2977 return REG_NOERROR;
2978 }
2979
2980 /* Local function for parse_bracket_exp used in _LIBC environment.
2981 Build the collating element which is represented by NAME.
2982 The result are written to MBCSET and SBCSET.
2983 COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
2984 pointer argument since we may update it. */
2985
2986 auto inline reg_errcode_t
2987 __attribute ((always_inline))
2988 build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name)
2989 re_charset_t *mbcset;
2990 int *coll_sym_alloc;
2991 bitset_t sbcset;
2992 const unsigned char *name;
2993 {
2994 int32_t elem, idx;
2995 size_t name_len = strlen ((const char *) name);
2996 if (nrules != 0)
2997 {
2998 elem = seek_collating_symbol_entry (name, name_len);
2999 if (symb_table[2 * elem] != 0)
3000 {
3001 /* We found the entry. */
3002 idx = symb_table[2 * elem + 1];
3003 /* Skip the name of collating element name. */
3004 idx += 1 + extra[idx];
3005 }
3006 else if (symb_table[2 * elem] == 0 && name_len == 1)
3007 {
3008 /* No valid character, treat it as a normal
3009 character. */
3010 bitset_set (sbcset, name[0]);
3011 return REG_NOERROR;
3012 }
3013 else
3014 return REG_ECOLLATE;
3015
3016 /* Got valid collation sequence, add it as a new entry. */
3017 /* Check the space of the arrays. */
3018 if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0))
3019 {
3020 /* Not enough, realloc it. */
3021 /* +1 in case of mbcset->ncoll_syms is 0. */
3022 int new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1;
3023 /* Use realloc since mbcset->coll_syms is NULL
3024 if *alloc == 0. */
3025 int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t,
3026 new_coll_sym_alloc);
3027 if (BE (new_coll_syms == NULL, 0))
3028 return REG_ESPACE;
3029 mbcset->coll_syms = new_coll_syms;
3030 *coll_sym_alloc = new_coll_sym_alloc;
3031 }
3032 mbcset->coll_syms[mbcset->ncoll_syms++] = idx;
3033 return REG_NOERROR;
3034 }
3035 else
3036 {
3037 if (BE (name_len != 1, 0))
3038 return REG_ECOLLATE;
3039 else
3040 {
3041 bitset_set (sbcset, name[0]);
3042 return REG_NOERROR;
3043 }
3044 }
3045 }
3046#endif
3047
3048 re_token_t br_token;
3049 re_bitset_ptr_t sbcset;
3050#ifdef RE_ENABLE_I18N
3051 re_charset_t *mbcset;
3052 int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
3053 int equiv_class_alloc = 0, char_class_alloc = 0;
3054#endif /* not RE_ENABLE_I18N */
3055 int non_match = 0;
3056 bin_tree_t *work_tree;
3057 int token_len;
3058 int first_round = 1;
3059#ifdef _LIBC
3060 collseqmb = (const unsigned char *)
3061 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
3062 nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
3063 if (nrules)
3064 {
3065 /*
3066 if (MB_CUR_MAX > 1)
3067 */
3068 collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
3069 table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB);
3070 symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE,
3071 _NL_COLLATE_SYMB_TABLEMB);
3072 extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
3073 _NL_COLLATE_SYMB_EXTRAMB);
3074 }
3075#endif
3076 sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
3077#ifdef RE_ENABLE_I18N
3078 mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
3079#endif /* RE_ENABLE_I18N */
3080#ifdef RE_ENABLE_I18N
3081 if (BE (sbcset == NULL || mbcset == NULL, 0))
3082#else
3083 if (BE (sbcset == NULL, 0))
3084#endif /* RE_ENABLE_I18N */
3085 {
3086 *err = REG_ESPACE;
3087 return NULL;
3088 }
3089
3090 token_len = peek_token_bracket (token, regexp, syntax);
3091 if (BE (token->type == END_OF_RE, 0))
3092 {
3093 *err = REG_BADPAT;
3094 goto parse_bracket_exp_free_return;
3095 }
3096 if (token->type == OP_NON_MATCH_LIST)
3097 {
3098#ifdef RE_ENABLE_I18N
3099 mbcset->non_match = 1;
3100#endif /* not RE_ENABLE_I18N */
3101 non_match = 1;
3102 if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
3103 bitset_set (sbcset, '\n');
3104 re_string_skip_bytes (regexp, token_len); /* Skip a token. */
3105 token_len = peek_token_bracket (token, regexp, syntax);
3106 if (BE (token->type == END_OF_RE, 0))
3107 {
3108 *err = REG_BADPAT;
3109 goto parse_bracket_exp_free_return;
3110 }
3111 }
3112
3113 /* We treat the first ']' as a normal character. */
3114 if (token->type == OP_CLOSE_BRACKET)
3115 token->type = CHARACTER;
3116
3117 while (1)
3118 {
3119 bracket_elem_t start_elem, end_elem;
3120 unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE];
3121 unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE];
3122 reg_errcode_t ret;
3123 int token_len2 = 0, is_range_exp = 0;
3124 re_token_t token2;
3125
3126 start_elem.opr.name = start_name_buf;
3127 ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa,
3128 syntax, first_round);
3129 if (BE (ret != REG_NOERROR, 0))
3130 {
3131 *err = ret;
3132 goto parse_bracket_exp_free_return;
3133 }
3134 first_round = 0;
3135
3136 /* Get information about the next token. We need it in any case. */
3137 token_len = peek_token_bracket (token, regexp, syntax);
3138
3139 /* Do not check for ranges if we know they are not allowed. */
3140 if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS)
3141 {
3142 if (BE (token->type == END_OF_RE, 0))
3143 {
3144 *err = REG_EBRACK;
3145 goto parse_bracket_exp_free_return;
3146 }
3147 if (token->type == OP_CHARSET_RANGE)
3148 {
3149 re_string_skip_bytes (regexp, token_len); /* Skip '-'. */
3150 token_len2 = peek_token_bracket (&token2, regexp, syntax);
3151 if (BE (token2.type == END_OF_RE, 0))
3152 {
3153 *err = REG_EBRACK;
3154 goto parse_bracket_exp_free_return;
3155 }
3156 if (token2.type == OP_CLOSE_BRACKET)
3157 {
3158 /* We treat the last '-' as a normal character. */
3159 re_string_skip_bytes (regexp, -token_len);
3160 token->type = CHARACTER;
3161 }
3162 else
3163 is_range_exp = 1;
3164 }
3165 }
3166
3167 if (is_range_exp == 1)
3168 {
3169 end_elem.opr.name = end_name_buf;
3170 ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2,
3171 dfa, syntax, 1);
3172 if (BE (ret != REG_NOERROR, 0))
3173 {
3174 *err = ret;
3175 goto parse_bracket_exp_free_return;
3176 }
3177
3178 token_len = peek_token_bracket (token, regexp, syntax);
3179
3180#ifdef _LIBC
3181 *err = build_range_exp (sbcset, mbcset, &range_alloc,
3182 &start_elem, &end_elem);
3183#else
3184# ifdef RE_ENABLE_I18N
3185 *err = build_range_exp (sbcset,
3186 dfa->mb_cur_max > 1 ? mbcset : NULL,
3187 &range_alloc, &start_elem, &end_elem);
3188# else
3189 *err = build_range_exp (sbcset, &start_elem, &end_elem);
3190# endif
3191#endif /* RE_ENABLE_I18N */
3192 if (BE (*err != REG_NOERROR, 0))
3193 goto parse_bracket_exp_free_return;
3194 }
3195 else
3196 {
3197 switch (start_elem.type)
3198 {
3199 case SB_CHAR:
3200 bitset_set (sbcset, start_elem.opr.ch);
3201 break;
3202#ifdef RE_ENABLE_I18N
3203 case MB_CHAR:
3204 /* Check whether the array has enough space. */
3205 if (BE (mbchar_alloc == mbcset->nmbchars, 0))
3206 {
3207 wchar_t *new_mbchars;
3208 /* Not enough, realloc it. */
3209 /* +1 in case of mbcset->nmbchars is 0. */
3210 mbchar_alloc = 2 * mbcset->nmbchars + 1;
3211 /* Use realloc since array is NULL if *alloc == 0. */
3212 new_mbchars = re_realloc (mbcset->mbchars, wchar_t,
3213 mbchar_alloc);
3214 if (BE (new_mbchars == NULL, 0))
3215 goto parse_bracket_exp_espace;
3216 mbcset->mbchars = new_mbchars;
3217 }
3218 mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
3219 break;
3220#endif /* RE_ENABLE_I18N */
3221 case EQUIV_CLASS:
3222 *err = build_equiv_class (sbcset,
3223#ifdef RE_ENABLE_I18N
3224 mbcset, &equiv_class_alloc,
3225#endif /* RE_ENABLE_I18N */
3226 start_elem.opr.name);
3227 if (BE (*err != REG_NOERROR, 0))
3228 goto parse_bracket_exp_free_return;
3229 break;
3230 case COLL_SYM:
3231 *err = build_collating_symbol (sbcset,
3232#ifdef RE_ENABLE_I18N
3233 mbcset, &coll_sym_alloc,
3234#endif /* RE_ENABLE_I18N */
3235 start_elem.opr.name);
3236 if (BE (*err != REG_NOERROR, 0))
3237 goto parse_bracket_exp_free_return;
3238 break;
3239 case CHAR_CLASS:
3240 *err = build_charclass (regexp->trans, sbcset,
3241#ifdef RE_ENABLE_I18N
3242 mbcset, &char_class_alloc,
3243#endif /* RE_ENABLE_I18N */
3244 (const char *) start_elem.opr.name, syntax);
3245 if (BE (*err != REG_NOERROR, 0))
3246 goto parse_bracket_exp_free_return;
3247 break;
3248 default:
3249 assert (0);
3250 break;
3251 }
3252 }
3253 if (BE (token->type == END_OF_RE, 0))
3254 {
3255 *err = REG_EBRACK;
3256 goto parse_bracket_exp_free_return;
3257 }
3258 if (token->type == OP_CLOSE_BRACKET)
3259 break;
3260 }
3261
3262 re_string_skip_bytes (regexp, token_len); /* Skip a token. */
3263
3264 /* If it is non-matching list. */
3265 if (non_match)
3266 bitset_not (sbcset);
3267
3268#ifdef RE_ENABLE_I18N
3269 /* Ensure only single byte characters are set. */
3270 if (dfa->mb_cur_max > 1)
3271 bitset_mask (sbcset, dfa->sb_char);
3272
3273 if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
3274 || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
3275 || mbcset->non_match)))
3276 {
3277 bin_tree_t *mbc_tree;
3278 int sbc_idx;
3279 /* Build a tree for complex bracket. */
3280 dfa->has_mb_node = 1;
3281 br_token.type = COMPLEX_BRACKET;
3282 br_token.opr.mbcset = mbcset;
3283 mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
3284 if (BE (mbc_tree == NULL, 0))
3285 goto parse_bracket_exp_espace;
3286 for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx)
3287 if (sbcset[sbc_idx])
3288 break;
3289 /* If there are no bits set in sbcset, there is no point
3290 of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */
3291 if (sbc_idx < BITSET_WORDS)
3292 {
3293 /* Build a tree for simple bracket. */
3294 br_token.type = SIMPLE_BRACKET;
3295 br_token.opr.sbcset = sbcset;
3296 work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
3297 if (BE (work_tree == NULL, 0))
3298 goto parse_bracket_exp_espace;
3299
3300 /* Then join them by ALT node. */
3301 work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT);
3302 if (BE (work_tree == NULL, 0))
3303 goto parse_bracket_exp_espace;
3304 }
3305 else
3306 {
3307 re_free (sbcset);
3308 work_tree = mbc_tree;
3309 }
3310 }
3311 else
3312#endif /* not RE_ENABLE_I18N */
3313 {
3314#ifdef RE_ENABLE_I18N
3315 free_charset (mbcset);
3316#endif
3317 /* Build a tree for simple bracket. */
3318 br_token.type = SIMPLE_BRACKET;
3319 br_token.opr.sbcset = sbcset;
3320 work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
3321 if (BE (work_tree == NULL, 0))
3322 goto parse_bracket_exp_espace;
3323 }
3324 return work_tree;
3325
3326 parse_bracket_exp_espace:
3327 *err = REG_ESPACE;
3328 parse_bracket_exp_free_return:
3329 re_free (sbcset);
3330#ifdef RE_ENABLE_I18N
3331 free_charset (mbcset);
3332#endif /* RE_ENABLE_I18N */
3333 return NULL;
3334}
3335
3336/* Parse an element in the bracket expression. */
3337
3338static reg_errcode_t
3339parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp,
3340 re_token_t *token, int token_len,
3341 UNUSED_PARAM re_dfa_t *dfa, reg_syntax_t syntax,
3342 int accept_hyphen)
3343{
3344#ifdef RE_ENABLE_I18N
3345 int cur_char_size;
3346 cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
3347 if (cur_char_size > 1)
3348 {
3349 elem->type = MB_CHAR;
3350 elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp));
3351 re_string_skip_bytes (regexp, cur_char_size);
3352 return REG_NOERROR;
3353 }
3354#endif /* RE_ENABLE_I18N */
3355 re_string_skip_bytes (regexp, token_len); /* Skip a token. */
3356 if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
3357 || token->type == OP_OPEN_EQUIV_CLASS)
3358 return parse_bracket_symbol (elem, regexp, token);
3359 if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen)
3360 {
3361 /* A '-' must only appear as anything but a range indicator before
3362 the closing bracket. Everything else is an error. */
3363 re_token_t token2;
3364 (void) peek_token_bracket (&token2, regexp, syntax);
3365 if (token2.type != OP_CLOSE_BRACKET)
3366 /* The actual error value is not standardized since this whole
3367 case is undefined. But ERANGE makes good sense. */
3368 return REG_ERANGE;
3369 }
3370 elem->type = SB_CHAR;
3371 elem->opr.ch = token->opr.c;
3372 return REG_NOERROR;
3373}
3374
3375/* Parse a bracket symbol in the bracket expression. Bracket symbols are
3376 such as [:<character_class>:], [.<collating_element>.], and
3377 [=<equivalent_class>=]. */
3378
3379static reg_errcode_t
3380parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp,
3381 re_token_t *token)
3382{
3383 unsigned char ch, delim = token->opr.c;
3384 int i = 0;
3385 if (re_string_eoi(regexp))
3386 return REG_EBRACK;
3387 for (;; ++i)
3388 {
3389 if (i >= BRACKET_NAME_BUF_SIZE)
3390 return REG_EBRACK;
3391 if (token->type == OP_OPEN_CHAR_CLASS)
3392 ch = re_string_fetch_byte_case (regexp);
3393 else
3394 ch = re_string_fetch_byte (regexp);
3395 if (re_string_eoi(regexp))
3396 return REG_EBRACK;
3397 if (ch == delim && re_string_peek_byte (regexp, 0) == ']')
3398 break;
3399 elem->opr.name[i] = ch;
3400 }
3401 re_string_skip_bytes (regexp, 1);
3402 elem->opr.name[i] = '\0';
3403 switch (token->type)
3404 {
3405 case OP_OPEN_COLL_ELEM:
3406 elem->type = COLL_SYM;
3407 break;
3408 case OP_OPEN_EQUIV_CLASS:
3409 elem->type = EQUIV_CLASS;
3410 break;
3411 case OP_OPEN_CHAR_CLASS:
3412 elem->type = CHAR_CLASS;
3413 break;
3414 default:
3415 break;
3416 }
3417 return REG_NOERROR;
3418}
3419
3420 /* Helper function for parse_bracket_exp.
3421 Build the equivalence class which is represented by NAME.
3422 The result are written to MBCSET and SBCSET.
3423 EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes,
3424 is a pointer argument since we may update it. */
3425
3426static reg_errcode_t
3427#ifdef RE_ENABLE_I18N
3428build_equiv_class (bitset_t sbcset, re_charset_t *mbcset,
3429 int *equiv_class_alloc, const unsigned char *name)
3430#else /* not RE_ENABLE_I18N */
3431build_equiv_class (bitset_t sbcset, const unsigned char *name)
3432#endif /* not RE_ENABLE_I18N */
3433{
3434#ifdef _LIBC
3435 uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
3436 if (nrules != 0)
3437 {
3438 const int32_t *table, *indirect;
3439 const unsigned char *weights, *extra, *cp;
3440 unsigned char char_buf[2];
3441 int32_t idx1, idx2;
3442 unsigned int ch;
3443 size_t len;
3444 /* This #include defines a local function! */
3445# include <locale/weight.h>
3446 /* Calculate the index for equivalence class. */
3447 cp = name;
3448 table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
3449 weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
3450 _NL_COLLATE_WEIGHTMB);
3451 extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
3452 _NL_COLLATE_EXTRAMB);
3453 indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
3454 _NL_COLLATE_INDIRECTMB);
3455 idx1 = findidx (&cp);
3456 if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0))
3457 /* This isn't a valid character. */
3458 return REG_ECOLLATE;
3459
3460 /* Build single byte matcing table for this equivalence class. */
3461 char_buf[1] = (unsigned char) '\0';
3462 len = weights[idx1 & 0xffffff];
3463 for (ch = 0; ch < SBC_MAX; ++ch)
3464 {
3465 char_buf[0] = ch;
3466 cp = char_buf;
3467 idx2 = findidx (&cp);
3468/*
3469 idx2 = table[ch];
3470*/
3471 if (idx2 == 0)
3472 /* This isn't a valid character. */
3473 continue;
3474 /* Compare only if the length matches and the collation rule
3475 index is the same. */
3476 if (len == weights[idx2 & 0xffffff] && (idx1 >> 24) == (idx2 >> 24))
3477 {
3478 int cnt = 0;
3479
3480 while (cnt <= len &&
3481 weights[(idx1 & 0xffffff) + 1 + cnt]
3482 == weights[(idx2 & 0xffffff) + 1 + cnt])
3483 ++cnt;
3484
3485 if (cnt > len)
3486 bitset_set (sbcset, ch);
3487 }
3488 }
3489 /* Check whether the array has enough space. */
3490 if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0))
3491 {
3492 /* Not enough, realloc it. */
3493 /* +1 in case of mbcset->nequiv_classes is 0. */
3494 int new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1;
3495 /* Use realloc since the array is NULL if *alloc == 0. */
3496 int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes,
3497 int32_t,
3498 new_equiv_class_alloc);
3499 if (BE (new_equiv_classes == NULL, 0))
3500 return REG_ESPACE;
3501 mbcset->equiv_classes = new_equiv_classes;
3502 *equiv_class_alloc = new_equiv_class_alloc;
3503 }
3504 mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
3505 }
3506 else
3507#endif /* _LIBC */
3508 {
3509 if (BE (strlen ((const char *) name) != 1, 0))
3510 return REG_ECOLLATE;
3511 bitset_set (sbcset, *name);
3512 }
3513 return REG_NOERROR;
3514}
3515
3516 /* Helper function for parse_bracket_exp.
3517 Build the character class which is represented by NAME.
3518 The result are written to MBCSET and SBCSET.
3519 CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
3520 is a pointer argument since we may update it. */
3521
3522static reg_errcode_t
3523#ifdef RE_ENABLE_I18N
3524build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
3525 re_charset_t *mbcset, int *char_class_alloc,
3526 const char *class_name, reg_syntax_t syntax)
3527#else /* not RE_ENABLE_I18N */
3528build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
3529 const char *class_name, reg_syntax_t syntax)
3530#endif /* not RE_ENABLE_I18N */
3531{
3532 int i;
3533
3534 /* In case of REG_ICASE "upper" and "lower" match the both of
3535 upper and lower cases. */
3536 if ((syntax & RE_ICASE)
3537 && (strcmp (class_name, "upper") == 0 || strcmp (class_name, "lower") == 0))
3538 class_name = "alpha";
3539
3540#ifdef RE_ENABLE_I18N
3541 /* Check the space of the arrays. */
3542 if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
3543 {
3544 /* Not enough, realloc it. */
3545 /* +1 in case of mbcset->nchar_classes is 0. */
3546 int new_char_class_alloc = 2 * mbcset->nchar_classes + 1;
3547 /* Use realloc since array is NULL if *alloc == 0. */
3548 wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t,
3549 new_char_class_alloc);
3550 if (BE (new_char_classes == NULL, 0))
3551 return REG_ESPACE;
3552 mbcset->char_classes = new_char_classes;
3553 *char_class_alloc = new_char_class_alloc;
3554 }
3555 mbcset->char_classes[mbcset->nchar_classes++] = __wctype (class_name);
3556#endif /* RE_ENABLE_I18N */
3557
3558#define BUILD_CHARCLASS_LOOP(ctype_func) \
3559 do { \
3560 if (BE (trans != NULL, 0)) \
3561 { \
3562 for (i = 0; i < SBC_MAX; ++i) \
3563 if (ctype_func (i)) \
3564 bitset_set (sbcset, trans[i]); \
3565 } \
3566 else \
3567 { \
3568 for (i = 0; i < SBC_MAX; ++i) \
3569 if (ctype_func (i)) \
3570 bitset_set (sbcset, i); \
3571 } \
3572 } while (0)
3573
3574 if (strcmp (class_name, "alnum") == 0)
3575 BUILD_CHARCLASS_LOOP (isalnum);
3576 else if (strcmp (class_name, "cntrl") == 0)
3577 BUILD_CHARCLASS_LOOP (iscntrl);
3578 else if (strcmp (class_name, "lower") == 0)
3579 BUILD_CHARCLASS_LOOP (islower);
3580 else if (strcmp (class_name, "space") == 0)
3581 BUILD_CHARCLASS_LOOP (isspace);
3582 else if (strcmp (class_name, "alpha") == 0)
3583 BUILD_CHARCLASS_LOOP (isalpha);
3584 else if (strcmp (class_name, "digit") == 0)
3585 BUILD_CHARCLASS_LOOP (isdigit);
3586 else if (strcmp (class_name, "print") == 0)
3587 BUILD_CHARCLASS_LOOP (isprint);
3588 else if (strcmp (class_name, "upper") == 0)
3589 BUILD_CHARCLASS_LOOP (isupper);
3590 else if (strcmp (class_name, "blank") == 0)
3591#ifndef GAWK
3592 BUILD_CHARCLASS_LOOP (isblank);
3593#else
3594 /* see comments above */
3595 BUILD_CHARCLASS_LOOP (is_blank);
3596#endif
3597 else if (strcmp (class_name, "graph") == 0)
3598 BUILD_CHARCLASS_LOOP (isgraph);
3599 else if (strcmp (class_name, "punct") == 0)
3600 BUILD_CHARCLASS_LOOP (ispunct);
3601 else if (strcmp (class_name, "xdigit") == 0)
3602 BUILD_CHARCLASS_LOOP (isxdigit);
3603 else
3604 return REG_ECTYPE;
3605
3606 return REG_NOERROR;
3607}
3608
3609static bin_tree_t *
3610build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans,
3611 const char *class_name,
3612 const char *extra, int non_match,
3613 reg_errcode_t *err)
3614{
3615 re_bitset_ptr_t sbcset;
3616#ifdef RE_ENABLE_I18N
3617 re_charset_t *mbcset;
3618 int alloc = 0;
3619#endif /* not RE_ENABLE_I18N */
3620 reg_errcode_t ret;
3621 re_token_t br_token;
3622 bin_tree_t *tree;
3623
3624 sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
3625#ifdef RE_ENABLE_I18N
3626 mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
3627#endif /* RE_ENABLE_I18N */
3628
3629#ifdef RE_ENABLE_I18N
3630 if (BE (sbcset == NULL || mbcset == NULL, 0))
3631#else /* not RE_ENABLE_I18N */
3632 if (BE (sbcset == NULL, 0))
3633#endif /* not RE_ENABLE_I18N */
3634 {
3635 *err = REG_ESPACE;
3636 return NULL;
3637 }
3638
3639 if (non_match)
3640 {
3641#ifdef RE_ENABLE_I18N
3642 mbcset->non_match = 1;
3643#endif /* not RE_ENABLE_I18N */
3644 }
3645
3646 /* We don't care the syntax in this case. */
3647 ret = build_charclass (trans, sbcset,
3648#ifdef RE_ENABLE_I18N
3649 mbcset, &alloc,
3650#endif /* RE_ENABLE_I18N */
3651 class_name, 0);
3652
3653 if (BE (ret != REG_NOERROR, 0))
3654 {
3655 re_free (sbcset);
3656#ifdef RE_ENABLE_I18N
3657 free_charset (mbcset);
3658#endif /* RE_ENABLE_I18N */
3659 *err = ret;
3660 return NULL;
3661 }
3662 /* \w match '_' also. */
3663 for (; *extra; extra++)
3664 bitset_set (sbcset, *extra);
3665
3666 /* If it is non-matching list. */
3667 if (non_match)
3668 bitset_not (sbcset);
3669
3670#ifdef RE_ENABLE_I18N
3671 /* Ensure only single byte characters are set. */
3672 if (dfa->mb_cur_max > 1)
3673 bitset_mask (sbcset, dfa->sb_char);
3674#endif
3675
3676 /* Build a tree for simple bracket. */
3677 br_token.type = SIMPLE_BRACKET;
3678 br_token.opr.sbcset = sbcset;
3679 tree = create_token_tree (dfa, NULL, NULL, &br_token);
3680 if (BE (tree == NULL, 0))
3681 goto build_word_op_espace;
3682
3683#ifdef RE_ENABLE_I18N
3684 if (dfa->mb_cur_max > 1)
3685 {
3686 bin_tree_t *mbc_tree;
3687 /* Build a tree for complex bracket. */
3688 br_token.type = COMPLEX_BRACKET;
3689 br_token.opr.mbcset = mbcset;
3690 dfa->has_mb_node = 1;
3691 mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
3692 if (BE (mbc_tree == NULL, 0))
3693 goto build_word_op_espace;
3694 /* Then join them by ALT node. */
3695 tree = create_tree (dfa, tree, mbc_tree, OP_ALT);
3696 if (BE (mbc_tree != NULL, 1))
3697 return tree;
3698 }
3699 else
3700 {
3701 free_charset (mbcset);
3702 return tree;
3703 }
3704#else /* not RE_ENABLE_I18N */
3705 return tree;
3706#endif /* not RE_ENABLE_I18N */
3707
3708 build_word_op_espace:
3709 re_free (sbcset);
3710#ifdef RE_ENABLE_I18N
3711 free_charset (mbcset);
3712#endif /* RE_ENABLE_I18N */
3713 *err = REG_ESPACE;
3714 return NULL;
3715}
3716
3717/* This is intended for the expressions like "a{1,3}".
3718 Fetch a number from `input', and return the number.
3719 Return -1, if the number field is empty like "{,1}".
3720 Return -2, if an error has occurred. */
3721
3722static int
3723fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
3724{
3725 int num = -1;
3726 unsigned char c;
3727 while (1)
3728 {
3729 fetch_token (token, input, syntax);
3730 c = token->opr.c;
3731 if (BE (token->type == END_OF_RE, 0))
3732 return -2;
3733 if (token->type == OP_CLOSE_DUP_NUM || c == ',')
3734 break;
3735 num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2)
3736 ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0'));
3737 num = (num > RE_DUP_MAX) ? -2 : num;
3738 }
3739 return num;
3740}
3741
3742#ifdef RE_ENABLE_I18N
3743static void
3744free_charset (re_charset_t *cset)
3745{
3746 re_free (cset->mbchars);
3747# ifdef _LIBC
3748 re_free (cset->coll_syms);
3749 re_free (cset->equiv_classes);
3750 re_free (cset->range_starts);
3751 re_free (cset->range_ends);
3752# endif
3753 re_free (cset->char_classes);
3754 re_free (cset);
3755}
3756#endif /* RE_ENABLE_I18N */
3757
3758/* Functions for binary tree operation. */
3759
3760/* Create a tree node. */
3761
3762static bin_tree_t *
3763create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
3764 re_token_type_t type)
3765{
3766 re_token_t t;
3767 t.type = type;
3768 return create_token_tree (dfa, left, right, &t);
3769}
3770
3771static bin_tree_t *
3772create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
3773 const re_token_t *token)
3774{
3775 bin_tree_t *tree;
3776 if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0))
3777 {
3778 bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1);
3779
3780 if (storage == NULL)
3781 return NULL;
3782 storage->next = dfa->str_tree_storage;
3783 dfa->str_tree_storage = storage;
3784 dfa->str_tree_storage_idx = 0;
3785 }
3786 tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++];
3787
3788 tree->parent = NULL;
3789 tree->left = left;
3790 tree->right = right;
3791 tree->token = *token;
3792 tree->token.duplicated = 0;
3793 tree->token.opt_subexp = 0;
3794 tree->first = NULL;
3795 tree->next = NULL;
3796 tree->node_idx = -1;
3797
3798 if (left != NULL)
3799 left->parent = tree;
3800 if (right != NULL)
3801 right->parent = tree;
3802 return tree;
3803}
3804
3805/* Mark the tree SRC as an optional subexpression.
3806 To be called from preorder or postorder. */
3807
3808static reg_errcode_t
3809mark_opt_subexp (void *extra, bin_tree_t *node)
3810{
3811 int idx = (int) (intptr_t) extra;
3812 if (node->token.type == SUBEXP && node->token.opr.idx == idx)
3813 node->token.opt_subexp = 1;
3814
3815 return REG_NOERROR;
3816}
3817
3818/* Free the allocated memory inside NODE. */
3819
3820static void
3821free_token (re_token_t *node)
3822{
3823#ifdef RE_ENABLE_I18N
3824 if (node->type == COMPLEX_BRACKET && node->duplicated == 0)
3825 free_charset (node->opr.mbcset);
3826 else
3827#endif /* RE_ENABLE_I18N */
3828 if (node->type == SIMPLE_BRACKET && node->duplicated == 0)
3829 re_free (node->opr.sbcset);
3830}
3831
3832/* Worker function for tree walking. Free the allocated memory inside NODE
3833 and its children. */
3834
3835static reg_errcode_t
3836free_tree (UNUSED_PARAM void *extra, bin_tree_t *node)
3837{
3838 free_token (&node->token);
3839 return REG_NOERROR;
3840}
3841
3842
3843/* Duplicate the node SRC, and return new node. This is a preorder
3844 visit similar to the one implemented by the generic visitor, but
3845 we need more infrastructure to maintain two parallel trees --- so,
3846 it's easier to duplicate. */
3847
3848static bin_tree_t *
3849duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa)
3850{
3851 const bin_tree_t *node;
3852 bin_tree_t *dup_root;
3853 bin_tree_t **p_new = &dup_root, *dup_node = root->parent;
3854
3855 for (node = root; ; )
3856 {
3857 /* Create a new tree and link it back to the current parent. */
3858 *p_new = create_token_tree (dfa, NULL, NULL, &node->token);
3859 if (*p_new == NULL)
3860 return NULL;
3861 (*p_new)->parent = dup_node;
3862 (*p_new)->token.duplicated = 1;
3863 dup_node = *p_new;
3864
3865 /* Go to the left node, or up and to the right. */
3866 if (node->left)
3867 {
3868 node = node->left;
3869 p_new = &dup_node->left;
3870 }
3871 else
3872 {
3873 const bin_tree_t *prev = NULL;
3874 while (node->right == prev || node->right == NULL)
3875 {
3876 prev = node;
3877 node = node->parent;
3878 dup_node = dup_node->parent;
3879 if (!node)
3880 return dup_root;
3881 }
3882 node = node->right;
3883 p_new = &dup_node->right;
3884 }
3885 }
3886}
diff --git a/win32/regex.c b/win32/regex.c
new file mode 100644
index 000000000..e40a2ea01
--- /dev/null
+++ b/win32/regex.c
@@ -0,0 +1,90 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA. */
20
21#define HAVE_LIBINTL_H 0
22#define ENABLE_NLS 0
23#define HAVE_ALLOCA 0
24#define NO_MBSUPPORT 1
25#define GAWK 1
26
27/* Make sure no one compiles this code with a C++ compiler. */
28#ifdef __cplusplus
29# error "This is C code, use a C compiler"
30#endif
31
32#ifdef _LIBC
33/* We have to keep the namespace clean. */
34# define regfree(preg) __regfree (preg)
35# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
36# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
37# define regerror(errcode, preg, errbuf, errbuf_size) \
38 __regerror(errcode, preg, errbuf, errbuf_size)
39# define re_set_registers(bu, re, nu, st, en) \
40 __re_set_registers (bu, re, nu, st, en)
41# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
42 __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
43# define re_match(bufp, string, size, pos, regs) \
44 __re_match (bufp, string, size, pos, regs)
45# define re_search(bufp, string, size, startpos, range, regs) \
46 __re_search (bufp, string, size, startpos, range, regs)
47# define re_compile_pattern(pattern, length, bufp) \
48 __re_compile_pattern (pattern, length, bufp)
49# define re_set_syntax(syntax) __re_set_syntax (syntax)
50# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
51 __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
52# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
53
54# include "../locale/localeinfo.h"
55#endif
56
57#if defined (_MSC_VER)
58#include <stdio.h> /* for size_t */
59#endif
60
61/* On some systems, limits.h sets RE_DUP_MAX to a lower value than
62 GNU regex allows. Include it before <regex.h>, which correctly
63 #undefs RE_DUP_MAX and sets it to the right value. */
64#include <limits.h>
65#include <stdint.h>
66
67#ifdef GAWK
68#undef alloca
69#define alloca alloca_is_bad_you_should_never_use_it
70#endif
71#include <regex.h>
72#include "regex_internal.h"
73
74#include "regex_internal.c"
75#ifdef GAWK
76#define bool int
77#define true (1)
78#define false (0)
79#endif
80#include "regcomp.c"
81#include "regexec.c"
82
83/* Binary backward compatibility. */
84#ifdef _LIBC
85# include <shlib-compat.h>
86# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
87link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
88int re_max_failures = 2000;
89# endif
90#endif
diff --git a/win32/regex.h b/win32/regex.h
new file mode 100644
index 000000000..61c968387
--- /dev/null
+++ b/win32/regex.h
@@ -0,0 +1,582 @@
1#include <stdio.h>
2#include <stddef.h>
3
4/* Definitions for data structures and routines for the regular
5 expression library.
6 Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006,2008
7 Free Software Foundation, Inc.
8 This file is part of the GNU C Library.
9
10 The GNU C Library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14
15 The GNU C Library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with the GNU C Library; if not, write to the Free
22 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 02110-1301 USA. */
24
25#ifndef _REGEX_H
26#define _REGEX_H 1
27
28#ifdef HAVE_STDDEF_H
29#include <stddef.h>
30#endif
31
32#ifdef HAVE_SYS_TYPES_H
33#include <sys/types.h>
34#endif
35
36#ifndef _LIBC
37#define __USE_GNU 1
38#endif
39
40/* Allow the use in C++ code. */
41#ifdef __cplusplus
42extern "C" {
43#endif
44
45/* The following two types have to be signed and unsigned integer type
46 wide enough to hold a value of a pointer. For most ANSI compilers
47 ptrdiff_t and size_t should be likely OK. Still size of these two
48 types is 2 for Microsoft C. Ugh... */
49typedef long int s_reg_t;
50typedef unsigned long int active_reg_t;
51
52/* The following bits are used to determine the regexp syntax we
53 recognize. The set/not-set meanings are chosen so that Emacs syntax
54 remains the value 0. The bits are given in alphabetical order, and
55 the definitions shifted by one from the previous bit; thus, when we
56 add or remove a bit, only one other definition need change. */
57typedef unsigned long int reg_syntax_t;
58
59#ifdef __USE_GNU
60/* If this bit is not set, then \ inside a bracket expression is literal.
61 If set, then such a \ quotes the following character. */
62# define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
63
64/* If this bit is not set, then + and ? are operators, and \+ and \? are
65 literals.
66 If set, then \+ and \? are operators and + and ? are literals. */
67# define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
68
69/* If this bit is set, then character classes are supported. They are:
70 [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
71 [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
72 If not set, then character classes are not supported. */
73# define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
74
75/* If this bit is set, then ^ and $ are always anchors (outside bracket
76 expressions, of course).
77 If this bit is not set, then it depends:
78 ^ is an anchor if it is at the beginning of a regular
79 expression or after an open-group or an alternation operator;
80 $ is an anchor if it is at the end of a regular expression, or
81 before a close-group or an alternation operator.
82
83 This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
84 POSIX draft 11.2 says that * etc. in leading positions is undefined.
85 We already implemented a previous draft which made those constructs
86 invalid, though, so we haven't changed the code back. */
87# define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
88
89/* If this bit is set, then special characters are always special
90 regardless of where they are in the pattern.
91 If this bit is not set, then special characters are special only in
92 some contexts; otherwise they are ordinary. Specifically,
93 * + ? and intervals are only special when not after the beginning,
94 open-group, or alternation operator. */
95# define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
96
97/* If this bit is set, then *, +, ?, and { cannot be first in an re or
98 immediately after an alternation or begin-group operator. */
99# define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
100
101/* If this bit is set, then . matches newline.
102 If not set, then it doesn't. */
103# define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
104
105/* If this bit is set, then . doesn't match NUL.
106 If not set, then it does. */
107# define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
108
109/* If this bit is set, nonmatching lists [^...] do not match newline.
110 If not set, they do. */
111# define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
112
113/* If this bit is set, either \{...\} or {...} defines an
114 interval, depending on RE_NO_BK_BRACES.
115 If not set, \{, \}, {, and } are literals. */
116# define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
117
118/* If this bit is set, +, ? and | aren't recognized as operators.
119 If not set, they are. */
120# define RE_LIMITED_OPS (RE_INTERVALS << 1)
121
122/* If this bit is set, newline is an alternation operator.
123 If not set, newline is literal. */
124# define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
125
126/* If this bit is set, then `{...}' defines an interval, and \{ and \}
127 are literals.
128 If not set, then `\{...\}' defines an interval. */
129# define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
130
131/* If this bit is set, (...) defines a group, and \( and \) are literals.
132 If not set, \(...\) defines a group, and ( and ) are literals. */
133# define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
134
135/* If this bit is set, then \<digit> matches <digit>.
136 If not set, then \<digit> is a back-reference. */
137# define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
138
139/* If this bit is set, then | is an alternation operator, and \| is literal.
140 If not set, then \| is an alternation operator, and | is literal. */
141# define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
142
143/* If this bit is set, then an ending range point collating higher
144 than the starting range point, as in [z-a], is invalid.
145 If not set, then when ending range point collates higher than the
146 starting range point, the range is ignored. */
147# define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
148
149/* If this bit is set, then an unmatched ) is ordinary.
150 If not set, then an unmatched ) is invalid. */
151# define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
152
153/* If this bit is set, succeed as soon as we match the whole pattern,
154 without further backtracking. */
155# define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
156
157/* If this bit is set, do not process the GNU regex operators.
158 If not set, then the GNU regex operators are recognized. */
159# define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
160
161/* If this bit is set, a syntactically invalid interval is treated as
162 a string of ordinary characters. For example, the ERE 'a{1' is
163 treated as 'a\{1'. */
164# define RE_INVALID_INTERVAL_ORD (RE_NO_GNU_OPS << 1)
165
166/* If this bit is set, then ignore case when matching.
167 If not set, then case is significant. */
168# define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
169
170/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only
171 for ^, because it is difficult to scan the regex backwards to find
172 whether ^ should be special. */
173# define RE_CARET_ANCHORS_HERE (RE_ICASE << 1)
174
175/* If this bit is set, then \{ cannot be first in an bre or
176 immediately after an alternation or begin-group operator. */
177# define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1)
178
179/* If this bit is set, then no_sub will be set to 1 during
180 re_compile_pattern. */
181#define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
182#endif
183
184/* This global variable defines the particular regexp syntax to use (for
185 some interfaces). When a regexp is compiled, the syntax used is
186 stored in the pattern buffer, so changing this does not affect
187 already-compiled regexps. */
188extern reg_syntax_t re_syntax_options;
189
190#ifdef __USE_GNU
191/* Define combinations of the above bits for the standard possibilities.
192 (The [[[ comments delimit what gets put into the Texinfo file, so
193 don't delete them!) */
194/* [[[begin syntaxes]]] */
195#define RE_SYNTAX_EMACS 0
196
197#define RE_SYNTAX_AWK \
198 (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
199 | RE_NO_BK_PARENS | RE_NO_BK_REFS \
200 | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
201 | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
202 | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
203
204#define RE_SYNTAX_GNU_AWK \
205 ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
206 | RE_INVALID_INTERVAL_ORD) \
207 & ~(RE_DOT_NOT_NULL | RE_CONTEXT_INDEP_OPS \
208 | RE_CONTEXT_INVALID_OPS ))
209
210#define RE_SYNTAX_POSIX_AWK \
211 (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
212 | RE_INTERVALS | RE_NO_GNU_OPS \
213 | RE_INVALID_INTERVAL_ORD)
214
215#define RE_SYNTAX_GREP \
216 (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
217 | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
218 | RE_NEWLINE_ALT)
219
220#define RE_SYNTAX_EGREP \
221 (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
222 | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
223 | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
224 | RE_NO_BK_VBAR)
225
226#define RE_SYNTAX_POSIX_EGREP \
227 (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \
228 | RE_INVALID_INTERVAL_ORD)
229
230/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
231#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
232
233#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
234
235/* Syntax bits common to both basic and extended POSIX regex syntax. */
236#define _RE_SYNTAX_POSIX_COMMON \
237 (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
238 | RE_INTERVALS | RE_NO_EMPTY_RANGES)
239
240#define RE_SYNTAX_POSIX_BASIC \
241 (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP)
242
243/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
244 RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
245 isn't minimal, since other operators, such as \`, aren't disabled. */
246#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
247 (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
248
249#define RE_SYNTAX_POSIX_EXTENDED \
250 (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
251 | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
252 | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
253 | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD)
254
255/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is
256 removed and RE_NO_BK_REFS is added. */
257#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
258 (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
259 | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
260 | RE_NO_BK_PARENS | RE_NO_BK_REFS \
261 | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
262/* [[[end syntaxes]]] */
263
264/* Maximum number of duplicates an interval can allow. Some systems
265 (erroneously) define this in other header files, but we want our
266 value, so remove any previous define. */
267# ifdef RE_DUP_MAX
268# undef RE_DUP_MAX
269# endif
270/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
271# define RE_DUP_MAX (0x7fff)
272#endif
273
274
275/* POSIX `cflags' bits (i.e., information for `regcomp'). */
276
277/* If this bit is set, then use extended regular expression syntax.
278 If not set, then use basic regular expression syntax. */
279#define REG_EXTENDED 1
280
281/* If this bit is set, then ignore case when matching.
282 If not set, then case is significant. */
283#define REG_ICASE (REG_EXTENDED << 1)
284
285/* If this bit is set, then anchors do not match at newline
286 characters in the string.
287 If not set, then anchors do match at newlines. */
288#define REG_NEWLINE (REG_ICASE << 1)
289
290/* If this bit is set, then report only success or fail in regexec.
291 If not set, then returns differ between not matching and errors. */
292#define REG_NOSUB (REG_NEWLINE << 1)
293
294
295/* POSIX `eflags' bits (i.e., information for regexec). */
296
297/* If this bit is set, then the beginning-of-line operator doesn't match
298 the beginning of the string (presumably because it's not the
299 beginning of a line).
300 If not set, then the beginning-of-line operator does match the
301 beginning of the string. */
302#define REG_NOTBOL 1
303
304/* Like REG_NOTBOL, except for the end-of-line. */
305#define REG_NOTEOL (1 << 1)
306
307/* Use PMATCH[0] to delimit the start and end of the search in the
308 buffer. */
309#define REG_STARTEND (1 << 2)
310
311
312/* If any error codes are removed, changed, or added, update the
313 `re_error_msg' table in regex.c. */
314typedef enum
315{
316#if defined _XOPEN_SOURCE || defined __USE_XOPEN2K
317 REG_ENOSYS = -1, /* This will never happen for this implementation. */
318#endif
319
320 REG_NOERROR = 0, /* Success. */
321 REG_NOMATCH, /* Didn't find a match (for regexec). */
322
323 /* POSIX regcomp return error codes. (In the order listed in the
324 standard.) */
325 REG_BADPAT, /* Invalid pattern. */
326 REG_ECOLLATE, /* Inalid collating element. */
327 REG_ECTYPE, /* Invalid character class name. */
328 REG_EESCAPE, /* Trailing backslash. */
329 REG_ESUBREG, /* Invalid back reference. */
330 REG_EBRACK, /* Unmatched left bracket. */
331 REG_EPAREN, /* Parenthesis imbalance. */
332 REG_EBRACE, /* Unmatched \{. */
333 REG_BADBR, /* Invalid contents of \{\}. */
334 REG_ERANGE, /* Invalid range end. */
335 REG_ESPACE, /* Ran out of memory. */
336 REG_BADRPT, /* No preceding re for repetition op. */
337
338 /* Error codes we've added. */
339 REG_EEND, /* Premature end. */
340 REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
341 REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
342} reg_errcode_t;
343
344/* This data structure represents a compiled pattern. Before calling
345 the pattern compiler, the fields `buffer', `allocated', `fastmap',
346 `translate', and `no_sub' can be set. After the pattern has been
347 compiled, the `re_nsub' field is available. All other fields are
348 private to the regex routines. */
349
350#ifndef RE_TRANSLATE_TYPE
351# define __RE_TRANSLATE_TYPE unsigned char *
352# ifdef __USE_GNU
353# define RE_TRANSLATE_TYPE __RE_TRANSLATE_TYPE
354# endif
355#endif
356
357#ifdef __USE_GNU
358# define __REPB_PREFIX(name) name
359#else
360# define __REPB_PREFIX(name) __##name
361#endif
362
363struct re_pattern_buffer
364{
365 /* Space that holds the compiled pattern. It is declared as
366 `unsigned char *' because its elements are sometimes used as
367 array indexes. */
368 unsigned char *__REPB_PREFIX(buffer);
369
370 /* Number of bytes to which `buffer' points. */
371 unsigned long int __REPB_PREFIX(allocated);
372
373 /* Number of bytes actually used in `buffer'. */
374 unsigned long int __REPB_PREFIX(used);
375
376 /* Syntax setting with which the pattern was compiled. */
377 reg_syntax_t __REPB_PREFIX(syntax);
378
379 /* Pointer to a fastmap, if any, otherwise zero. re_search uses the
380 fastmap, if there is one, to skip over impossible starting points
381 for matches. */
382 char *__REPB_PREFIX(fastmap);
383
384 /* Either a translate table to apply to all characters before
385 comparing them, or zero for no translation. The translation is
386 applied to a pattern when it is compiled and to a string when it
387 is matched. */
388 __RE_TRANSLATE_TYPE __REPB_PREFIX(translate);
389
390 /* Number of subexpressions found by the compiler. */
391 size_t re_nsub;
392
393 /* Zero if this pattern cannot match the empty string, one else.
394 Well, in truth it's used only in `re_search_2', to see whether or
395 not we should use the fastmap, so we don't set this absolutely
396 perfectly; see `re_compile_fastmap' (the `duplicate' case). */
397 unsigned __REPB_PREFIX(can_be_null) : 1;
398
399 /* If REGS_UNALLOCATED, allocate space in the `regs' structure
400 for `max (RE_NREGS, re_nsub + 1)' groups.
401 If REGS_REALLOCATE, reallocate space if necessary.
402 If REGS_FIXED, use what's there. */
403#ifdef __USE_GNU
404# define REGS_UNALLOCATED 0
405# define REGS_REALLOCATE 1
406# define REGS_FIXED 2
407#endif
408 unsigned __REPB_PREFIX(regs_allocated) : 2;
409
410 /* Set to zero when `regex_compile' compiles a pattern; set to one
411 by `re_compile_fastmap' if it updates the fastmap. */
412 unsigned __REPB_PREFIX(fastmap_accurate) : 1;
413
414 /* If set, `re_match_2' does not return information about
415 subexpressions. */
416 unsigned __REPB_PREFIX(no_sub) : 1;
417
418 /* If set, a beginning-of-line anchor doesn't match at the beginning
419 of the string. */
420 unsigned __REPB_PREFIX(not_bol) : 1;
421
422 /* Similarly for an end-of-line anchor. */
423 unsigned __REPB_PREFIX(not_eol) : 1;
424
425 /* If true, an anchor at a newline matches. */
426 unsigned __REPB_PREFIX(newline_anchor) : 1;
427};
428
429typedef struct re_pattern_buffer regex_t;
430
431/* Type for byte offsets within the string. POSIX mandates this. */
432typedef int regoff_t;
433
434
435#ifdef __USE_GNU
436/* This is the structure we store register match data in. See
437 regex.texinfo for a full description of what registers match. */
438struct re_registers
439{
440 unsigned num_regs;
441 regoff_t *start;
442 regoff_t *end;
443};
444
445
446/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
447 `re_match_2' returns information about at least this many registers
448 the first time a `regs' structure is passed. */
449# ifndef RE_NREGS
450# define RE_NREGS 30
451# endif
452#endif
453
454
455/* POSIX specification for registers. Aside from the different names than
456 `re_registers', POSIX uses an array of structures, instead of a
457 structure of arrays. */
458typedef struct
459{
460 regoff_t rm_so; /* Byte offset from string's start to substring's start. */
461 regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
462} regmatch_t;
463
464/* Declarations for routines. */
465
466#ifdef __USE_GNU
467/* Sets the current default syntax to SYNTAX, and return the old syntax.
468 You can also simply assign to the `re_syntax_options' variable. */
469extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
470
471/* Compile the regular expression PATTERN, with length LENGTH
472 and syntax given by the global `re_syntax_options', into the buffer
473 BUFFER. Return NULL if successful, and an error string if not. */
474extern const char *re_compile_pattern (const char *__pattern, size_t __length,
475 struct re_pattern_buffer *__buffer);
476
477
478/* Compile a fastmap for the compiled pattern in BUFFER; used to
479 accelerate searches. Return 0 if successful and -2 if was an
480 internal error. */
481extern int re_compile_fastmap (struct re_pattern_buffer *__buffer);
482
483
484/* Search in the string STRING (with length LENGTH) for the pattern
485 compiled into BUFFER. Start searching at position START, for RANGE
486 characters. Return the starting position of the match, -1 for no
487 match, or -2 for an internal error. Also return register
488 information in REGS (if REGS and BUFFER->no_sub are nonzero). */
489extern int re_search (struct re_pattern_buffer *__buffer, const char *__cstring,
490 int __length, int __start, int __range,
491 struct re_registers *__regs);
492
493
494/* Like `re_search', but search in the concatenation of STRING1 and
495 STRING2. Also, stop searching at index START + STOP. */
496extern int re_search_2 (struct re_pattern_buffer *__buffer,
497 const char *__string1, int __length1,
498 const char *__string2, int __length2, int __start,
499 int __range, struct re_registers *__regs, int __stop);
500
501
502/* Like `re_search', but return how many characters in STRING the regexp
503 in BUFFER matched, starting at position START. */
504extern int re_match (struct re_pattern_buffer *__buffer, const char *__cstring,
505 int __length, int __start, struct re_registers *__regs);
506
507
508/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
509extern int re_match_2 (struct re_pattern_buffer *__buffer,
510 const char *__string1, int __length1,
511 const char *__string2, int __length2, int __start,
512 struct re_registers *__regs, int __stop);
513
514
515/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
516 ENDS. Subsequent matches using BUFFER and REGS will use this memory
517 for recording register information. STARTS and ENDS must be
518 allocated with malloc, and must each be at least `NUM_REGS * sizeof
519 (regoff_t)' bytes long.
520
521 If NUM_REGS == 0, then subsequent matches should allocate their own
522 register data.
523
524 Unless this function is called, the first search or match using
525 PATTERN_BUFFER will allocate its own register data, without
526 freeing the old data. */
527extern void re_set_registers (struct re_pattern_buffer *__buffer,
528 struct re_registers *__regs,
529 unsigned int __num_regs,
530 regoff_t *__starts, regoff_t *__ends);
531#endif /* Use GNU */
532
533#if defined _REGEX_RE_COMP || (defined _LIBC && defined __USE_BSD)
534# ifndef _CRAY
535/* 4.2 bsd compatibility. */
536extern char *re_comp (const char *);
537extern int re_exec (const char *);
538# endif
539#endif
540
541/* GCC 2.95 and later have "__restrict"; C99 compilers have
542 "restrict", and "configure" may have defined "restrict". */
543#ifndef __restrict
544# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__))
545# if defined restrict || 199901L <= __STDC_VERSION__
546# define __restrict restrict
547# else
548# define __restrict
549# endif
550# endif
551#endif
552/* gcc 3.1 and up support the [restrict] syntax. */
553#ifndef __restrict_arr
554# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \
555 && !defined __GNUG__
556# define __restrict_arr __restrict
557# else
558# define __restrict_arr
559# endif
560#endif
561
562/* POSIX compatibility. */
563extern int regcomp (regex_t *__restrict __preg,
564 const char *__restrict __pattern,
565 int __cflags);
566
567extern int regexec (const regex_t *__restrict __preg,
568 const char *__restrict __cstring, size_t __nmatch,
569 regmatch_t __pmatch[__restrict_arr],
570 int __eflags);
571
572extern size_t regerror (int __errcode, const regex_t *__restrict __preg,
573 char *__restrict __errbuf, size_t __errbuf_size);
574
575extern void regfree (regex_t *__preg);
576
577
578#ifdef __cplusplus
579}
580#endif /* C++ */
581
582#endif /* regex.h */
diff --git a/win32/regex_internal.c b/win32/regex_internal.c
new file mode 100644
index 000000000..c33561743
--- /dev/null
+++ b/win32/regex_internal.c
@@ -0,0 +1,1744 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2006, 2010 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA. */
20
21static void re_string_construct_common (const char *str, int len,
22 re_string_t *pstr,
23 RE_TRANSLATE_TYPE trans, int icase,
24 const re_dfa_t *dfa) internal_function;
25static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa,
26 const re_node_set *nodes,
27 unsigned int hash) internal_function;
28static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa,
29 const re_node_set *nodes,
30 unsigned int context,
31 unsigned int hash) internal_function;
32
33#ifdef GAWK
34#undef MAX /* safety */
35static int
36MAX(size_t a, size_t b)
37{
38 return (a > b ? a : b);
39}
40#endif
41
42/* Functions for string operation. */
43
44/* This function allocate the buffers. It is necessary to call
45 re_string_reconstruct before using the object. */
46
47static reg_errcode_t
48internal_function
49re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len,
50 RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
51{
52 reg_errcode_t ret;
53 int init_buf_len;
54
55 /* Ensure at least one character fits into the buffers. */
56 if (init_len < dfa->mb_cur_max)
57 init_len = dfa->mb_cur_max;
58 init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
59 re_string_construct_common (str, len, pstr, trans, icase, dfa);
60
61 ret = re_string_realloc_buffers (pstr, init_buf_len);
62 if (BE (ret != REG_NOERROR, 0))
63 return ret;
64
65 pstr->word_char = dfa->word_char;
66 pstr->word_ops_used = dfa->word_ops_used;
67 pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
68 pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
69 pstr->valid_raw_len = pstr->valid_len;
70 return REG_NOERROR;
71}
72
73/* This function allocate the buffers, and initialize them. */
74
75static reg_errcode_t
76internal_function
77re_string_construct (re_string_t *pstr, const char *str, int len,
78 RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
79{
80 reg_errcode_t ret;
81 memset (pstr, '\0', sizeof (re_string_t));
82 re_string_construct_common (str, len, pstr, trans, icase, dfa);
83
84 if (len > 0)
85 {
86 ret = re_string_realloc_buffers (pstr, len + 1);
87 if (BE (ret != REG_NOERROR, 0))
88 return ret;
89 }
90 pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
91
92 if (icase)
93 {
94#ifdef RE_ENABLE_I18N
95 if (dfa->mb_cur_max > 1)
96 {
97 while (1)
98 {
99 ret = build_wcs_upper_buffer (pstr);
100 if (BE (ret != REG_NOERROR, 0))
101 return ret;
102 if (pstr->valid_raw_len >= len)
103 break;
104 if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
105 break;
106 ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
107 if (BE (ret != REG_NOERROR, 0))
108 return ret;
109 }
110 }
111 else
112#endif /* RE_ENABLE_I18N */
113 build_upper_buffer (pstr);
114 }
115 else
116 {
117#ifdef RE_ENABLE_I18N
118 if (dfa->mb_cur_max > 1)
119 build_wcs_buffer (pstr);
120 else
121#endif /* RE_ENABLE_I18N */
122 {
123 if (trans != NULL)
124 re_string_translate_buffer (pstr);
125 else
126 {
127 pstr->valid_len = pstr->bufs_len;
128 pstr->valid_raw_len = pstr->bufs_len;
129 }
130 }
131 }
132
133 return REG_NOERROR;
134}
135
136/* Helper functions for re_string_allocate, and re_string_construct. */
137
138static reg_errcode_t
139internal_function
140re_string_realloc_buffers (re_string_t *pstr, int new_buf_len)
141{
142#ifdef RE_ENABLE_I18N
143 if (pstr->mb_cur_max > 1)
144 {
145 wint_t *new_wcs;
146
147 /* Avoid overflow in realloc. */
148 const size_t max_object_size = MAX (sizeof (wint_t), sizeof (int));
149 if (BE (SIZE_MAX / max_object_size < new_buf_len, 0))
150 return REG_ESPACE;
151
152 new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len);
153 if (BE (new_wcs == NULL, 0))
154 return REG_ESPACE;
155 pstr->wcs = new_wcs;
156 if (pstr->offsets != NULL)
157 {
158 int *new_offsets = re_realloc (pstr->offsets, int, new_buf_len);
159 if (BE (new_offsets == NULL, 0))
160 return REG_ESPACE;
161 pstr->offsets = new_offsets;
162 }
163 }
164#endif /* RE_ENABLE_I18N */
165 if (pstr->mbs_allocated)
166 {
167 unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char,
168 new_buf_len);
169 if (BE (new_mbs == NULL, 0))
170 return REG_ESPACE;
171 pstr->mbs = new_mbs;
172 }
173 pstr->bufs_len = new_buf_len;
174 return REG_NOERROR;
175}
176
177
178static void
179internal_function
180re_string_construct_common (const char *str, int len, re_string_t *pstr,
181 RE_TRANSLATE_TYPE trans, int icase,
182 const re_dfa_t *dfa)
183{
184 pstr->raw_mbs = (const unsigned char *) str;
185 pstr->len = len;
186 pstr->raw_len = len;
187 pstr->trans = trans;
188 pstr->icase = icase ? 1 : 0;
189 pstr->mbs_allocated = (trans != NULL || icase);
190 pstr->mb_cur_max = dfa->mb_cur_max;
191 pstr->is_utf8 = dfa->is_utf8;
192 pstr->map_notascii = dfa->map_notascii;
193 pstr->stop = pstr->len;
194 pstr->raw_stop = pstr->stop;
195}
196
197#ifdef RE_ENABLE_I18N
198
199/* Build wide character buffer PSTR->WCS.
200 If the byte sequence of the string are:
201 <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3>
202 Then wide character buffer will be:
203 <wc1> , WEOF , <wc2> , WEOF , <wc3>
204 We use WEOF for padding, they indicate that the position isn't
205 a first byte of a multibyte character.
206
207 Note that this function assumes PSTR->VALID_LEN elements are already
208 built and starts from PSTR->VALID_LEN. */
209
210static void
211internal_function
212build_wcs_buffer (re_string_t *pstr)
213{
214#ifdef _LIBC
215 unsigned char buf[MB_LEN_MAX];
216 assert (MB_LEN_MAX >= pstr->mb_cur_max);
217#else
218 unsigned char buf[64];
219#endif
220 mbstate_t prev_st;
221 int byte_idx, end_idx, remain_len;
222 size_t mbclen;
223
224 /* Build the buffers from pstr->valid_len to either pstr->len or
225 pstr->bufs_len. */
226 end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
227 for (byte_idx = pstr->valid_len; byte_idx < end_idx;)
228 {
229 wchar_t wc;
230 const char *p;
231
232 remain_len = end_idx - byte_idx;
233 prev_st = pstr->cur_state;
234 /* Apply the translation if we need. */
235 if (BE (pstr->trans != NULL, 0))
236 {
237 int i, ch;
238
239 for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
240 {
241 ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
242 buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
243 }
244 p = (const char *) buf;
245 }
246 else
247 p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
248 mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
249 if (BE (mbclen == (size_t) -2, 0))
250 {
251 /* The buffer doesn't have enough space, finish to build. */
252 pstr->cur_state = prev_st;
253 break;
254 }
255 else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0))
256 {
257 /* We treat these cases as a singlebyte character. */
258 mbclen = 1;
259 wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
260 if (BE (pstr->trans != NULL, 0))
261 wc = pstr->trans[wc];
262 pstr->cur_state = prev_st;
263 }
264
265 /* Write wide character and padding. */
266 pstr->wcs[byte_idx++] = wc;
267 /* Write paddings. */
268 for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
269 pstr->wcs[byte_idx++] = WEOF;
270 }
271 pstr->valid_len = byte_idx;
272 pstr->valid_raw_len = byte_idx;
273}
274
275/* Build wide character buffer PSTR->WCS like build_wcs_buffer,
276 but for REG_ICASE. */
277
278static reg_errcode_t
279internal_function
280build_wcs_upper_buffer (re_string_t *pstr)
281{
282 mbstate_t prev_st;
283 int src_idx, byte_idx, end_idx, remain_len;
284 size_t mbclen;
285#ifdef _LIBC
286 char buf[MB_LEN_MAX];
287 assert (MB_LEN_MAX >= pstr->mb_cur_max);
288#else
289 char buf[64];
290#endif
291
292 byte_idx = pstr->valid_len;
293 end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
294
295 /* The following optimization assumes that ASCII characters can be
296 mapped to wide characters with a simple cast. */
297 if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
298 {
299 while (byte_idx < end_idx)
300 {
301 wchar_t wc;
302
303 if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
304 && mbsinit (&pstr->cur_state))
305 {
306 /* In case of a singlebyte character. */
307 pstr->mbs[byte_idx]
308 = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
309 /* The next step uses the assumption that wchar_t is encoded
310 ASCII-safe: all ASCII values can be converted like this. */
311 pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx];
312 ++byte_idx;
313 continue;
314 }
315
316 remain_len = end_idx - byte_idx;
317 prev_st = pstr->cur_state;
318 mbclen = __mbrtowc (&wc,
319 ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
320 + byte_idx), remain_len, &pstr->cur_state);
321 if (BE (mbclen + 2 > 2, 1))
322 {
323 wchar_t wcu = wc;
324 if (iswlower (wc))
325 {
326 size_t mbcdlen;
327
328 wcu = towupper (wc);
329 mbcdlen = wcrtomb (buf, wcu, &prev_st);
330 if (BE (mbclen == mbcdlen, 1))
331 memcpy (pstr->mbs + byte_idx, buf, mbclen);
332 else
333 {
334 src_idx = byte_idx;
335 goto offsets_needed;
336 }
337 }
338 else
339 memcpy (pstr->mbs + byte_idx,
340 pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen);
341 pstr->wcs[byte_idx++] = wcu;
342 /* Write paddings. */
343 for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
344 pstr->wcs[byte_idx++] = WEOF;
345 }
346 else if (mbclen == (size_t) -1 || mbclen == 0)
347 {
348 /* It is an invalid character or '\0'. Just use the byte. */
349 int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
350 pstr->mbs[byte_idx] = ch;
351 /* And also cast it to wide char. */
352 pstr->wcs[byte_idx++] = (wchar_t) ch;
353 if (BE (mbclen == (size_t) -1, 0))
354 pstr->cur_state = prev_st;
355 }
356 else
357 {
358 /* The buffer doesn't have enough space, finish to build. */
359 pstr->cur_state = prev_st;
360 break;
361 }
362 }
363 pstr->valid_len = byte_idx;
364 pstr->valid_raw_len = byte_idx;
365 return REG_NOERROR;
366 }
367 else
368 for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
369 {
370 wchar_t wc;
371 const char *p;
372 offsets_needed:
373 remain_len = end_idx - byte_idx;
374 prev_st = pstr->cur_state;
375 if (BE (pstr->trans != NULL, 0))
376 {
377 int i, ch;
378
379 for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
380 {
381 ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
382 buf[i] = pstr->trans[ch];
383 }
384 p = (const char *) buf;
385 }
386 else
387 p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
388 mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
389 if (BE (mbclen + 2 > 2, 1))
390 {
391 wchar_t wcu = wc;
392 if (iswlower (wc))
393 {
394 size_t mbcdlen;
395
396 wcu = towupper (wc);
397 mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st);
398 if (BE (mbclen == mbcdlen, 1))
399 memcpy (pstr->mbs + byte_idx, buf, mbclen);
400 else if (mbcdlen != (size_t) -1)
401 {
402 size_t i;
403
404 if (byte_idx + mbcdlen > pstr->bufs_len)
405 {
406 pstr->cur_state = prev_st;
407 break;
408 }
409
410 if (pstr->offsets == NULL)
411 {
412 pstr->offsets = re_malloc (int, pstr->bufs_len);
413
414 if (pstr->offsets == NULL)
415 return REG_ESPACE;
416 }
417 if (!pstr->offsets_needed)
418 {
419 for (i = 0; i < (size_t) byte_idx; ++i)
420 pstr->offsets[i] = i;
421 pstr->offsets_needed = 1;
422 }
423
424 memcpy (pstr->mbs + byte_idx, buf, mbcdlen);
425 pstr->wcs[byte_idx] = wcu;
426 pstr->offsets[byte_idx] = src_idx;
427 for (i = 1; i < mbcdlen; ++i)
428 {
429 pstr->offsets[byte_idx + i]
430 = src_idx + (i < mbclen ? i : mbclen - 1);
431 pstr->wcs[byte_idx + i] = WEOF;
432 }
433 pstr->len += mbcdlen - mbclen;
434 if (pstr->raw_stop > src_idx)
435 pstr->stop += mbcdlen - mbclen;
436 end_idx = (pstr->bufs_len > pstr->len)
437 ? pstr->len : pstr->bufs_len;
438 byte_idx += mbcdlen;
439 src_idx += mbclen;
440 continue;
441 }
442 else
443 memcpy (pstr->mbs + byte_idx, p, mbclen);
444 }
445 else
446 memcpy (pstr->mbs + byte_idx, p, mbclen);
447
448 if (BE (pstr->offsets_needed != 0, 0))
449 {
450 size_t i;
451 for (i = 0; i < mbclen; ++i)
452 pstr->offsets[byte_idx + i] = src_idx + i;
453 }
454 src_idx += mbclen;
455
456 pstr->wcs[byte_idx++] = wcu;
457 /* Write paddings. */
458 for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
459 pstr->wcs[byte_idx++] = WEOF;
460 }
461 else if (mbclen == (size_t) -1 || mbclen == 0)
462 {
463 /* It is an invalid character or '\0'. Just use the byte. */
464 int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
465
466 if (BE (pstr->trans != NULL, 0))
467 ch = pstr->trans [ch];
468 pstr->mbs[byte_idx] = ch;
469
470 if (BE (pstr->offsets_needed != 0, 0))
471 pstr->offsets[byte_idx] = src_idx;
472 ++src_idx;
473
474 /* And also cast it to wide char. */
475 pstr->wcs[byte_idx++] = (wchar_t) ch;
476 if (BE (mbclen == (size_t) -1, 0))
477 pstr->cur_state = prev_st;
478 }
479 else
480 {
481 /* The buffer doesn't have enough space, finish to build. */
482 pstr->cur_state = prev_st;
483 break;
484 }
485 }
486 pstr->valid_len = byte_idx;
487 pstr->valid_raw_len = src_idx;
488 return REG_NOERROR;
489}
490
491/* Skip characters until the index becomes greater than NEW_RAW_IDX.
492 Return the index. */
493
494static int
495internal_function
496re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc)
497{
498 mbstate_t prev_st;
499 int rawbuf_idx;
500 size_t mbclen;
501 wint_t wc = WEOF;
502
503 /* Skip the characters which are not necessary to check. */
504 for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
505 rawbuf_idx < new_raw_idx;)
506 {
507 wchar_t wc2;
508 int remain_len = pstr->len - rawbuf_idx;
509 prev_st = pstr->cur_state;
510 mbclen = __mbrtowc (&wc2, (const char *) pstr->raw_mbs + rawbuf_idx,
511 remain_len, &pstr->cur_state);
512 if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
513 {
514 /* We treat these cases as a single byte character. */
515 if (mbclen == 0 || remain_len == 0)
516 wc = L'\0';
517 else
518 wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx);
519 mbclen = 1;
520 pstr->cur_state = prev_st;
521 }
522 else
523 wc = (wint_t) wc2;
524 /* Then proceed the next character. */
525 rawbuf_idx += mbclen;
526 }
527 *last_wc = (wint_t) wc;
528 return rawbuf_idx;
529}
530#endif /* RE_ENABLE_I18N */
531
532/* Build the buffer PSTR->MBS, and apply the translation if we need.
533 This function is used in case of REG_ICASE. */
534
535static void
536internal_function
537build_upper_buffer (re_string_t *pstr)
538{
539 int char_idx, end_idx;
540 end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
541
542 for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx)
543 {
544 int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx];
545 if (BE (pstr->trans != NULL, 0))
546 ch = pstr->trans[ch];
547 if (islower (ch))
548 pstr->mbs[char_idx] = toupper (ch);
549 else
550 pstr->mbs[char_idx] = ch;
551 }
552 pstr->valid_len = char_idx;
553 pstr->valid_raw_len = char_idx;
554}
555
556/* Apply TRANS to the buffer in PSTR. */
557
558static void
559internal_function
560re_string_translate_buffer (re_string_t *pstr)
561{
562 int buf_idx, end_idx;
563 end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
564
565 for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx)
566 {
567 int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx];
568 pstr->mbs[buf_idx] = pstr->trans[ch];
569 }
570
571 pstr->valid_len = buf_idx;
572 pstr->valid_raw_len = buf_idx;
573}
574
575/* This function re-construct the buffers.
576 Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
577 convert to upper case in case of REG_ICASE, apply translation. */
578
579static reg_errcode_t
580internal_function
581re_string_reconstruct (re_string_t *pstr, int idx, int eflags)
582{
583 int offset = idx - pstr->raw_mbs_idx;
584 if (BE (offset < 0, 0))
585 {
586 /* Reset buffer. */
587#ifdef RE_ENABLE_I18N
588 if (pstr->mb_cur_max > 1)
589 memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
590#endif /* RE_ENABLE_I18N */
591 pstr->len = pstr->raw_len;
592 pstr->stop = pstr->raw_stop;
593 pstr->valid_len = 0;
594 pstr->raw_mbs_idx = 0;
595 pstr->valid_raw_len = 0;
596 pstr->offsets_needed = 0;
597 pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
598 : CONTEXT_NEWLINE | CONTEXT_BEGBUF);
599 if (!pstr->mbs_allocated)
600 pstr->mbs = (unsigned char *) pstr->raw_mbs;
601 offset = idx;
602 }
603
604 if (BE (offset != 0, 1))
605 {
606 /* Should the already checked characters be kept? */
607 if (BE (offset < pstr->valid_raw_len, 1))
608 {
609 /* Yes, move them to the front of the buffer. */
610#ifdef RE_ENABLE_I18N
611 if (BE (pstr->offsets_needed, 0))
612 {
613 int low = 0, high = pstr->valid_len, mid;
614 do
615 {
616 mid = (high + low) / 2;
617 if (pstr->offsets[mid] > offset)
618 high = mid;
619 else if (pstr->offsets[mid] < offset)
620 low = mid + 1;
621 else
622 break;
623 }
624 while (low < high);
625 if (pstr->offsets[mid] < offset)
626 ++mid;
627 pstr->tip_context = re_string_context_at (pstr, mid - 1,
628 eflags);
629 /* This can be quite complicated, so handle specially
630 only the common and easy case where the character with
631 different length representation of lower and upper
632 case is present at or after offset. */
633 if (pstr->valid_len > offset
634 && mid == offset && pstr->offsets[mid] == offset)
635 {
636 memmove (pstr->wcs, pstr->wcs + offset,
637 (pstr->valid_len - offset) * sizeof (wint_t));
638 memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset);
639 pstr->valid_len -= offset;
640 pstr->valid_raw_len -= offset;
641 for (low = 0; low < pstr->valid_len; low++)
642 pstr->offsets[low] = pstr->offsets[low + offset] - offset;
643 }
644 else
645 {
646 /* Otherwise, just find out how long the partial multibyte
647 character at offset is and fill it with WEOF/255. */
648 pstr->len = pstr->raw_len - idx + offset;
649 pstr->stop = pstr->raw_stop - idx + offset;
650 pstr->offsets_needed = 0;
651 while (mid > 0 && pstr->offsets[mid - 1] == offset)
652 --mid;
653 while (mid < pstr->valid_len)
654 if (pstr->wcs[mid] != WEOF)
655 break;
656 else
657 ++mid;
658 if (mid == pstr->valid_len)
659 pstr->valid_len = 0;
660 else
661 {
662 pstr->valid_len = pstr->offsets[mid] - offset;
663 if (pstr->valid_len)
664 {
665 for (low = 0; low < pstr->valid_len; ++low)
666 pstr->wcs[low] = WEOF;
667 memset (pstr->mbs, 255, pstr->valid_len);
668 }
669 }
670 pstr->valid_raw_len = pstr->valid_len;
671 }
672 }
673 else
674#endif
675 {
676 pstr->tip_context = re_string_context_at (pstr, offset - 1,
677 eflags);
678#ifdef RE_ENABLE_I18N
679 if (pstr->mb_cur_max > 1)
680 memmove (pstr->wcs, pstr->wcs + offset,
681 (pstr->valid_len - offset) * sizeof (wint_t));
682#endif /* RE_ENABLE_I18N */
683 if (BE (pstr->mbs_allocated, 0))
684 memmove (pstr->mbs, pstr->mbs + offset,
685 pstr->valid_len - offset);
686 pstr->valid_len -= offset;
687 pstr->valid_raw_len -= offset;
688#ifdef DEBUG
689 assert (pstr->valid_len > 0);
690#endif
691 }
692 }
693 else
694 {
695#ifdef RE_ENABLE_I18N
696 /* No, skip all characters until IDX. */
697 int prev_valid_len = pstr->valid_len;
698
699 if (BE (pstr->offsets_needed, 0))
700 {
701 pstr->len = pstr->raw_len - idx + offset;
702 pstr->stop = pstr->raw_stop - idx + offset;
703 pstr->offsets_needed = 0;
704 }
705#endif
706 pstr->valid_len = 0;
707#ifdef RE_ENABLE_I18N
708 if (pstr->mb_cur_max > 1)
709 {
710 int wcs_idx;
711 wint_t wc = WEOF;
712
713 if (pstr->is_utf8)
714 {
715 const unsigned char *raw, *p, *end;
716
717 /* Special case UTF-8. Multi-byte chars start with any
718 byte other than 0x80 - 0xbf. */
719 raw = pstr->raw_mbs + pstr->raw_mbs_idx;
720 end = raw + (offset - pstr->mb_cur_max);
721 if (end < pstr->raw_mbs)
722 end = pstr->raw_mbs;
723 p = raw + offset - 1;
724#ifdef _LIBC
725 /* We know the wchar_t encoding is UCS4, so for the simple
726 case, ASCII characters, skip the conversion step. */
727 if (isascii (*p) && BE (pstr->trans == NULL, 1))
728 {
729 memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
730 /* pstr->valid_len = 0; */
731 wc = (wchar_t) *p;
732 }
733 else
734#endif
735 for (; p >= end; --p)
736 if ((*p & 0xc0) != 0x80)
737 {
738 mbstate_t cur_state;
739 wchar_t wc2;
740 int mlen = raw + pstr->len - p;
741 unsigned char buf[6];
742 size_t mbclen;
743
744 if (BE (pstr->trans != NULL, 0))
745 {
746 int i = mlen < 6 ? mlen : 6;
747 while (--i >= 0)
748 buf[i] = pstr->trans[p[i]];
749 }
750 /* XXX Don't use mbrtowc, we know which conversion
751 to use (UTF-8 -> UCS4). */
752 memset (&cur_state, 0, sizeof (cur_state));
753 mbclen = __mbrtowc (&wc2, (const char *) p, mlen,
754 &cur_state);
755 if (raw + offset - p <= mbclen
756 && mbclen < (size_t) -2)
757 {
758 memset (&pstr->cur_state, '\0',
759 sizeof (mbstate_t));
760 pstr->valid_len = mbclen - (raw + offset - p);
761 wc = wc2;
762 }
763 break;
764 }
765 }
766
767 if (wc == WEOF)
768 pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
769 if (wc == WEOF)
770 pstr->tip_context
771 = re_string_context_at (pstr, prev_valid_len - 1, eflags);
772 else
773 pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
774 && IS_WIDE_WORD_CHAR (wc))
775 ? CONTEXT_WORD
776 : ((IS_WIDE_NEWLINE (wc)
777 && pstr->newline_anchor)
778 ? CONTEXT_NEWLINE : 0));
779 if (BE (pstr->valid_len, 0))
780 {
781 for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
782 pstr->wcs[wcs_idx] = WEOF;
783 if (pstr->mbs_allocated)
784 memset (pstr->mbs, 255, pstr->valid_len);
785 }
786 pstr->valid_raw_len = pstr->valid_len;
787 }
788 else
789#endif /* RE_ENABLE_I18N */
790 {
791 int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
792 pstr->valid_raw_len = 0;
793 if (pstr->trans)
794 c = pstr->trans[c];
795 pstr->tip_context = (bitset_contain (pstr->word_char, c)
796 ? CONTEXT_WORD
797 : ((IS_NEWLINE (c) && pstr->newline_anchor)
798 ? CONTEXT_NEWLINE : 0));
799 }
800 }
801 if (!BE (pstr->mbs_allocated, 0))
802 pstr->mbs += offset;
803 }
804 pstr->raw_mbs_idx = idx;
805 pstr->len -= offset;
806 pstr->stop -= offset;
807
808 /* Then build the buffers. */
809#ifdef RE_ENABLE_I18N
810 if (pstr->mb_cur_max > 1)
811 {
812 if (pstr->icase)
813 {
814 reg_errcode_t ret = build_wcs_upper_buffer (pstr);
815 if (BE (ret != REG_NOERROR, 0))
816 return ret;
817 }
818 else
819 build_wcs_buffer (pstr);
820 }
821 else
822#endif /* RE_ENABLE_I18N */
823 if (BE (pstr->mbs_allocated, 0))
824 {
825 if (pstr->icase)
826 build_upper_buffer (pstr);
827 else if (pstr->trans != NULL)
828 re_string_translate_buffer (pstr);
829 }
830 else
831 pstr->valid_len = pstr->len;
832
833 pstr->cur_idx = 0;
834 return REG_NOERROR;
835}
836
837static unsigned char
838internal_function __attribute ((pure))
839re_string_peek_byte_case (const re_string_t *pstr, int idx)
840{
841 int ch, off;
842
843 /* Handle the common (easiest) cases first. */
844 if (BE (!pstr->mbs_allocated, 1))
845 return re_string_peek_byte (pstr, idx);
846
847#ifdef RE_ENABLE_I18N
848 if (pstr->mb_cur_max > 1
849 && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
850 return re_string_peek_byte (pstr, idx);
851#endif
852
853 off = pstr->cur_idx + idx;
854#ifdef RE_ENABLE_I18N
855 if (pstr->offsets_needed)
856 off = pstr->offsets[off];
857#endif
858
859 ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
860
861#ifdef RE_ENABLE_I18N
862 /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I
863 this function returns CAPITAL LETTER I instead of first byte of
864 DOTLESS SMALL LETTER I. The latter would confuse the parser,
865 since peek_byte_case doesn't advance cur_idx in any way. */
866 if (pstr->offsets_needed && !isascii (ch))
867 return re_string_peek_byte (pstr, idx);
868#endif
869
870 return ch;
871}
872
873static unsigned char
874internal_function __attribute ((pure))
875re_string_fetch_byte_case (re_string_t *pstr)
876{
877 if (BE (!pstr->mbs_allocated, 1))
878 return re_string_fetch_byte (pstr);
879
880#ifdef RE_ENABLE_I18N
881 if (pstr->offsets_needed)
882 {
883 int off, ch;
884
885 /* For tr_TR.UTF-8 [[:islower:]] there is
886 [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip
887 in that case the whole multi-byte character and return
888 the original letter. On the other side, with
889 [[: DOTLESS SMALL LETTER I return [[:I, as doing
890 anything else would complicate things too much. */
891
892 if (!re_string_first_byte (pstr, pstr->cur_idx))
893 return re_string_fetch_byte (pstr);
894
895 off = pstr->offsets[pstr->cur_idx];
896 ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
897
898 if (! isascii (ch))
899 return re_string_fetch_byte (pstr);
900
901 re_string_skip_bytes (pstr,
902 re_string_char_size_at (pstr, pstr->cur_idx));
903 return ch;
904 }
905#endif
906
907 return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++];
908}
909
910static void
911internal_function
912re_string_destruct (re_string_t *pstr)
913{
914#ifdef RE_ENABLE_I18N
915 re_free (pstr->wcs);
916 re_free (pstr->offsets);
917#endif /* RE_ENABLE_I18N */
918 if (pstr->mbs_allocated)
919 re_free (pstr->mbs);
920}
921
922/* Return the context at IDX in INPUT. */
923
924static unsigned int
925internal_function
926re_string_context_at (const re_string_t *input, int idx, int eflags)
927{
928 int c;
929 if (BE (idx < 0, 0))
930 /* In this case, we use the value stored in input->tip_context,
931 since we can't know the character in input->mbs[-1] here. */
932 return input->tip_context;
933 if (BE (idx == input->len, 0))
934 return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
935 : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
936#ifdef RE_ENABLE_I18N
937 if (input->mb_cur_max > 1)
938 {
939 wint_t wc;
940 int wc_idx = idx;
941 while(input->wcs[wc_idx] == WEOF)
942 {
943#ifdef DEBUG
944 /* It must not happen. */
945 assert (wc_idx >= 0);
946#endif
947 --wc_idx;
948 if (wc_idx < 0)
949 return input->tip_context;
950 }
951 wc = input->wcs[wc_idx];
952 if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc))
953 return CONTEXT_WORD;
954 return (IS_WIDE_NEWLINE (wc) && input->newline_anchor
955 ? CONTEXT_NEWLINE : 0);
956 }
957 else
958#endif
959 {
960 c = re_string_byte_at (input, idx);
961 if (bitset_contain (input->word_char, c))
962 return CONTEXT_WORD;
963 return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0;
964 }
965}
966
967/* Functions for set operation. */
968
969static reg_errcode_t
970internal_function
971re_node_set_alloc (re_node_set *set, int size)
972{
973 /*
974 * ADR: valgrind says size can be 0, which then doesn't
975 * free the block of size 0. Harumph. This seems
976 * to work ok, though.
977 */
978 if (size == 0)
979 {
980 memset(set, 0, sizeof(*set));
981 return REG_NOERROR;
982 }
983 set->alloc = size;
984 set->nelem = 0;
985 set->elems = re_malloc (int, size);
986 if (BE (set->elems == NULL, 0))
987 return REG_ESPACE;
988 return REG_NOERROR;
989}
990
991static reg_errcode_t
992internal_function
993re_node_set_init_1 (re_node_set *set, int elem)
994{
995 set->alloc = 1;
996 set->nelem = 1;
997 set->elems = re_malloc (int, 1);
998 if (BE (set->elems == NULL, 0))
999 {
1000 set->alloc = set->nelem = 0;
1001 return REG_ESPACE;
1002 }
1003 set->elems[0] = elem;
1004 return REG_NOERROR;
1005}
1006
1007static reg_errcode_t
1008internal_function
1009re_node_set_init_2 (re_node_set *set, int elem1, int elem2)
1010{
1011 set->alloc = 2;
1012 set->elems = re_malloc (int, 2);
1013 if (BE (set->elems == NULL, 0))
1014 return REG_ESPACE;
1015 if (elem1 == elem2)
1016 {
1017 set->nelem = 1;
1018 set->elems[0] = elem1;
1019 }
1020 else
1021 {
1022 set->nelem = 2;
1023 if (elem1 < elem2)
1024 {
1025 set->elems[0] = elem1;
1026 set->elems[1] = elem2;
1027 }
1028 else
1029 {
1030 set->elems[0] = elem2;
1031 set->elems[1] = elem1;
1032 }
1033 }
1034 return REG_NOERROR;
1035}
1036
1037static reg_errcode_t
1038internal_function
1039re_node_set_init_copy (re_node_set *dest, const re_node_set *src)
1040{
1041 dest->nelem = src->nelem;
1042 if (src->nelem > 0)
1043 {
1044 dest->alloc = dest->nelem;
1045 dest->elems = re_malloc (int, dest->alloc);
1046 if (BE (dest->elems == NULL, 0))
1047 {
1048 dest->alloc = dest->nelem = 0;
1049 return REG_ESPACE;
1050 }
1051 memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
1052 }
1053 else
1054 re_node_set_init_empty (dest);
1055 return REG_NOERROR;
1056}
1057
1058/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to
1059 DEST. Return value indicate the error code or REG_NOERROR if succeeded.
1060 Note: We assume dest->elems is NULL, when dest->alloc is 0. */
1061
1062static reg_errcode_t
1063internal_function
1064re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1,
1065 const re_node_set *src2)
1066{
1067 int i1, i2, is, id, delta, sbase;
1068 if (src1->nelem == 0 || src2->nelem == 0)
1069 return REG_NOERROR;
1070
1071 /* We need dest->nelem + 2 * elems_in_intersection; this is a
1072 conservative estimate. */
1073 if (src1->nelem + src2->nelem + dest->nelem > dest->alloc)
1074 {
1075 int new_alloc = src1->nelem + src2->nelem + dest->alloc;
1076 int *new_elems = re_realloc (dest->elems, int, new_alloc);
1077 if (BE (new_elems == NULL, 0))
1078 return REG_ESPACE;
1079 dest->elems = new_elems;
1080 dest->alloc = new_alloc;
1081 }
1082
1083 /* Find the items in the intersection of SRC1 and SRC2, and copy
1084 into the top of DEST those that are not already in DEST itself. */
1085 sbase = dest->nelem + src1->nelem + src2->nelem;
1086 i1 = src1->nelem - 1;
1087 i2 = src2->nelem - 1;
1088 id = dest->nelem - 1;
1089 for (;;)
1090 {
1091 if (src1->elems[i1] == src2->elems[i2])
1092 {
1093 /* Try to find the item in DEST. Maybe we could binary search? */
1094 while (id >= 0 && dest->elems[id] > src1->elems[i1])
1095 --id;
1096
1097 if (id < 0 || dest->elems[id] != src1->elems[i1])
1098 dest->elems[--sbase] = src1->elems[i1];
1099
1100 if (--i1 < 0 || --i2 < 0)
1101 break;
1102 }
1103
1104 /* Lower the highest of the two items. */
1105 else if (src1->elems[i1] < src2->elems[i2])
1106 {
1107 if (--i2 < 0)
1108 break;
1109 }
1110 else
1111 {
1112 if (--i1 < 0)
1113 break;
1114 }
1115 }
1116
1117 id = dest->nelem - 1;
1118 is = dest->nelem + src1->nelem + src2->nelem - 1;
1119 delta = is - sbase + 1;
1120
1121 /* Now copy. When DELTA becomes zero, the remaining
1122 DEST elements are already in place; this is more or
1123 less the same loop that is in re_node_set_merge. */
1124 dest->nelem += delta;
1125 if (delta > 0 && id >= 0)
1126 for (;;)
1127 {
1128 if (dest->elems[is] > dest->elems[id])
1129 {
1130 /* Copy from the top. */
1131 dest->elems[id + delta--] = dest->elems[is--];
1132 if (delta == 0)
1133 break;
1134 }
1135 else
1136 {
1137 /* Slide from the bottom. */
1138 dest->elems[id + delta] = dest->elems[id];
1139 if (--id < 0)
1140 break;
1141 }
1142 }
1143
1144 /* Copy remaining SRC elements. */
1145 memcpy (dest->elems, dest->elems + sbase, delta * sizeof (int));
1146
1147 return REG_NOERROR;
1148}
1149
1150/* Calculate the union set of the sets SRC1 and SRC2. And store it to
1151 DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
1152
1153static reg_errcode_t
1154internal_function
1155re_node_set_init_union (re_node_set *dest, const re_node_set *src1,
1156 const re_node_set *src2)
1157{
1158 int i1, i2, id;
1159 if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0)
1160 {
1161 dest->alloc = src1->nelem + src2->nelem;
1162 dest->elems = re_malloc (int, dest->alloc);
1163 if (BE (dest->elems == NULL, 0))
1164 return REG_ESPACE;
1165 }
1166 else
1167 {
1168 if (src1 != NULL && src1->nelem > 0)
1169 return re_node_set_init_copy (dest, src1);
1170 else if (src2 != NULL && src2->nelem > 0)
1171 return re_node_set_init_copy (dest, src2);
1172 else
1173 re_node_set_init_empty (dest);
1174 return REG_NOERROR;
1175 }
1176 for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;)
1177 {
1178 if (src1->elems[i1] > src2->elems[i2])
1179 {
1180 dest->elems[id++] = src2->elems[i2++];
1181 continue;
1182 }
1183 if (src1->elems[i1] == src2->elems[i2])
1184 ++i2;
1185 dest->elems[id++] = src1->elems[i1++];
1186 }
1187 if (i1 < src1->nelem)
1188 {
1189 memcpy (dest->elems + id, src1->elems + i1,
1190 (src1->nelem - i1) * sizeof (int));
1191 id += src1->nelem - i1;
1192 }
1193 else if (i2 < src2->nelem)
1194 {
1195 memcpy (dest->elems + id, src2->elems + i2,
1196 (src2->nelem - i2) * sizeof (int));
1197 id += src2->nelem - i2;
1198 }
1199 dest->nelem = id;
1200 return REG_NOERROR;
1201}
1202
1203/* Calculate the union set of the sets DEST and SRC. And store it to
1204 DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
1205
1206static reg_errcode_t
1207internal_function
1208re_node_set_merge (re_node_set *dest, const re_node_set *src)
1209{
1210 int is, id, sbase, delta;
1211 if (src == NULL || src->nelem == 0)
1212 return REG_NOERROR;
1213 if (dest->alloc < 2 * src->nelem + dest->nelem)
1214 {
1215 int new_alloc = 2 * (src->nelem + dest->alloc);
1216 int *new_buffer = re_realloc (dest->elems, int, new_alloc);
1217 if (BE (new_buffer == NULL, 0))
1218 return REG_ESPACE;
1219 dest->elems = new_buffer;
1220 dest->alloc = new_alloc;
1221 }
1222
1223 if (BE (dest->nelem == 0, 0))
1224 {
1225 dest->nelem = src->nelem;
1226 memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
1227 return REG_NOERROR;
1228 }
1229
1230 /* Copy into the top of DEST the items of SRC that are not
1231 found in DEST. Maybe we could binary search in DEST? */
1232 for (sbase = dest->nelem + 2 * src->nelem,
1233 is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0; )
1234 {
1235 if (dest->elems[id] == src->elems[is])
1236 is--, id--;
1237 else if (dest->elems[id] < src->elems[is])
1238 dest->elems[--sbase] = src->elems[is--];
1239 else /* if (dest->elems[id] > src->elems[is]) */
1240 --id;
1241 }
1242
1243 if (is >= 0)
1244 {
1245 /* If DEST is exhausted, the remaining items of SRC must be unique. */
1246 sbase -= is + 1;
1247 memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (int));
1248 }
1249
1250 id = dest->nelem - 1;
1251 is = dest->nelem + 2 * src->nelem - 1;
1252 delta = is - sbase + 1;
1253 if (delta == 0)
1254 return REG_NOERROR;
1255
1256 /* Now copy. When DELTA becomes zero, the remaining
1257 DEST elements are already in place. */
1258 dest->nelem += delta;
1259 for (;;)
1260 {
1261 if (dest->elems[is] > dest->elems[id])
1262 {
1263 /* Copy from the top. */
1264 dest->elems[id + delta--] = dest->elems[is--];
1265 if (delta == 0)
1266 break;
1267 }
1268 else
1269 {
1270 /* Slide from the bottom. */
1271 dest->elems[id + delta] = dest->elems[id];
1272 if (--id < 0)
1273 {
1274 /* Copy remaining SRC elements. */
1275 memcpy (dest->elems, dest->elems + sbase,
1276 delta * sizeof (int));
1277 break;
1278 }
1279 }
1280 }
1281
1282 return REG_NOERROR;
1283}
1284
1285/* Insert the new element ELEM to the re_node_set* SET.
1286 SET should not already have ELEM.
1287 return -1 if an error has occurred, return 1 otherwise. */
1288
1289static int
1290internal_function
1291re_node_set_insert (re_node_set *set, int elem)
1292{
1293 int idx;
1294 /* In case the set is empty. */
1295 if (set->alloc == 0)
1296 {
1297 if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1))
1298 return 1;
1299 else
1300 return -1;
1301 }
1302
1303 if (BE (set->nelem, 0) == 0)
1304 {
1305 /* We already guaranteed above that set->alloc != 0. */
1306 set->elems[0] = elem;
1307 ++set->nelem;
1308 return 1;
1309 }
1310
1311 /* Realloc if we need. */
1312 if (set->alloc == set->nelem)
1313 {
1314 int *new_elems;
1315 set->alloc = set->alloc * 2;
1316 new_elems = re_realloc (set->elems, int, set->alloc);
1317 if (BE (new_elems == NULL, 0))
1318 return -1;
1319 set->elems = new_elems;
1320 }
1321
1322 /* Move the elements which follows the new element. Test the
1323 first element separately to skip a check in the inner loop. */
1324 if (elem < set->elems[0])
1325 {
1326 idx = 0;
1327 for (idx = set->nelem; idx > 0; idx--)
1328 set->elems[idx] = set->elems[idx - 1];
1329 }
1330 else
1331 {
1332 for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
1333 set->elems[idx] = set->elems[idx - 1];
1334 }
1335
1336 /* Insert the new element. */
1337 set->elems[idx] = elem;
1338 ++set->nelem;
1339 return 1;
1340}
1341
1342/* Insert the new element ELEM to the re_node_set* SET.
1343 SET should not already have any element greater than or equal to ELEM.
1344 Return -1 if an error has occurred, return 1 otherwise. */
1345
1346static int
1347internal_function
1348re_node_set_insert_last (re_node_set *set, int elem)
1349{
1350 /* Realloc if we need. */
1351 if (set->alloc == set->nelem)
1352 {
1353 int *new_elems;
1354 set->alloc = (set->alloc + 1) * 2;
1355 new_elems = re_realloc (set->elems, int, set->alloc);
1356 if (BE (new_elems == NULL, 0))
1357 return -1;
1358 set->elems = new_elems;
1359 }
1360
1361 /* Insert the new element. */
1362 set->elems[set->nelem++] = elem;
1363 return 1;
1364}
1365
1366/* Compare two node sets SET1 and SET2.
1367 return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */
1368
1369static int
1370internal_function __attribute ((pure))
1371re_node_set_compare (const re_node_set *set1, const re_node_set *set2)
1372{
1373 int i;
1374 if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem)
1375 return 0;
1376 for (i = set1->nelem ; --i >= 0 ; )
1377 if (set1->elems[i] != set2->elems[i])
1378 return 0;
1379 return 1;
1380}
1381
1382/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
1383
1384static int
1385internal_function __attribute ((pure))
1386re_node_set_contains (const re_node_set *set, int elem)
1387{
1388 unsigned int idx, right, mid;
1389 if (set->nelem <= 0)
1390 return 0;
1391
1392 /* Binary search the element. */
1393 idx = 0;
1394 right = set->nelem - 1;
1395 while (idx < right)
1396 {
1397 mid = (idx + right) / 2;
1398 if (set->elems[mid] < elem)
1399 idx = mid + 1;
1400 else
1401 right = mid;
1402 }
1403 return set->elems[idx] == elem ? idx + 1 : 0;
1404}
1405
1406static void
1407internal_function
1408re_node_set_remove_at (re_node_set *set, int idx)
1409{
1410 if (idx < 0 || idx >= set->nelem)
1411 return;
1412 --set->nelem;
1413 for (; idx < set->nelem; idx++)
1414 set->elems[idx] = set->elems[idx + 1];
1415}
1416
1417
1418/* Add the token TOKEN to dfa->nodes, and return the index of the token.
1419 Or return -1, if an error has occurred. */
1420
1421static int
1422internal_function
1423re_dfa_add_node (re_dfa_t *dfa, re_token_t token)
1424{
1425 if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0))
1426 {
1427 size_t new_nodes_alloc = dfa->nodes_alloc * 2;
1428 int *new_nexts, *new_indices;
1429 re_node_set *new_edests, *new_eclosures;
1430 re_token_t *new_nodes;
1431
1432 /* Avoid overflows in realloc. */
1433 const size_t max_object_size = MAX (sizeof (re_token_t),
1434 MAX (sizeof (re_node_set),
1435 sizeof (int)));
1436 if (BE (SIZE_MAX / max_object_size < new_nodes_alloc, 0))
1437 return -1;
1438
1439 new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc);
1440 if (BE (new_nodes == NULL, 0))
1441 return -1;
1442 dfa->nodes = new_nodes;
1443 new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc);
1444 new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc);
1445 new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc);
1446 new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc);
1447 if (BE (new_nexts == NULL || new_indices == NULL
1448 || new_edests == NULL || new_eclosures == NULL, 0))
1449 return -1;
1450 dfa->nexts = new_nexts;
1451 dfa->org_indices = new_indices;
1452 dfa->edests = new_edests;
1453 dfa->eclosures = new_eclosures;
1454 dfa->nodes_alloc = new_nodes_alloc;
1455 }
1456 dfa->nodes[dfa->nodes_len] = token;
1457 dfa->nodes[dfa->nodes_len].constraint = 0;
1458#ifdef RE_ENABLE_I18N
1459 dfa->nodes[dfa->nodes_len].accept_mb =
1460 (token.type == OP_PERIOD && dfa->mb_cur_max > 1) || token.type == COMPLEX_BRACKET;
1461#endif
1462 dfa->nexts[dfa->nodes_len] = -1;
1463 re_node_set_init_empty (dfa->edests + dfa->nodes_len);
1464 re_node_set_init_empty (dfa->eclosures + dfa->nodes_len);
1465 return dfa->nodes_len++;
1466}
1467
1468static inline unsigned int
1469internal_function
1470calc_state_hash (const re_node_set *nodes, unsigned int context)
1471{
1472 unsigned int hash = nodes->nelem + context;
1473 int i;
1474 for (i = 0 ; i < nodes->nelem ; i++)
1475 hash += nodes->elems[i];
1476 return hash;
1477}
1478
1479/* Search for the state whose node_set is equivalent to NODES.
1480 Return the pointer to the state, if we found it in the DFA.
1481 Otherwise create the new one and return it. In case of an error
1482 return NULL and set the error code in ERR.
1483 Note: - We assume NULL as the invalid state, then it is possible that
1484 return value is NULL and ERR is REG_NOERROR.
1485 - We never return non-NULL value in case of any errors, it is for
1486 optimization. */
1487
1488static re_dfastate_t *
1489internal_function
1490re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa,
1491 const re_node_set *nodes)
1492{
1493 unsigned int hash;
1494 re_dfastate_t *new_state;
1495 struct re_state_table_entry *spot;
1496 int i;
1497 if (BE (nodes->nelem == 0, 0))
1498 {
1499 *err = REG_NOERROR;
1500 return NULL;
1501 }
1502 hash = calc_state_hash (nodes, 0);
1503 spot = dfa->state_table + (hash & dfa->state_hash_mask);
1504
1505 for (i = 0 ; i < spot->num ; i++)
1506 {
1507 re_dfastate_t *state = spot->array[i];
1508 if (hash != state->hash)
1509 continue;
1510 if (re_node_set_compare (&state->nodes, nodes))
1511 return state;
1512 }
1513
1514 /* There are no appropriate state in the dfa, create the new one. */
1515 new_state = create_ci_newstate (dfa, nodes, hash);
1516 if (BE (new_state == NULL, 0))
1517 *err = REG_ESPACE;
1518
1519 return new_state;
1520}
1521
1522/* Search for the state whose node_set is equivalent to NODES and
1523 whose context is equivalent to CONTEXT.
1524 Return the pointer to the state, if we found it in the DFA.
1525 Otherwise create the new one and return it. In case of an error
1526 return NULL and set the error code in ERR.
1527 Note: - We assume NULL as the invalid state, then it is possible that
1528 return value is NULL and ERR is REG_NOERROR.
1529 - We never return non-NULL value in case of any errors, it is for
1530 optimization. */
1531
1532static re_dfastate_t *
1533internal_function
1534re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa,
1535 const re_node_set *nodes, unsigned int context)
1536{
1537 unsigned int hash;
1538 re_dfastate_t *new_state;
1539 struct re_state_table_entry *spot;
1540 int i;
1541 if (nodes->nelem == 0)
1542 {
1543 *err = REG_NOERROR;
1544 return NULL;
1545 }
1546 hash = calc_state_hash (nodes, context);
1547 spot = dfa->state_table + (hash & dfa->state_hash_mask);
1548
1549 for (i = 0 ; i < spot->num ; i++)
1550 {
1551 re_dfastate_t *state = spot->array[i];
1552 if (state->hash == hash
1553 && state->context == context
1554 && re_node_set_compare (state->entrance_nodes, nodes))
1555 return state;
1556 }
1557 /* There are no appropriate state in `dfa', create the new one. */
1558 new_state = create_cd_newstate (dfa, nodes, context, hash);
1559 if (BE (new_state == NULL, 0))
1560 *err = REG_ESPACE;
1561
1562 return new_state;
1563}
1564
1565/* Finish initialization of the new state NEWSTATE, and using its hash value
1566 HASH put in the appropriate bucket of DFA's state table. Return value
1567 indicates the error code if failed. */
1568
1569static reg_errcode_t
1570register_state (const re_dfa_t *dfa, re_dfastate_t *newstate,
1571 unsigned int hash)
1572{
1573 struct re_state_table_entry *spot;
1574 reg_errcode_t err;
1575 int i;
1576
1577 newstate->hash = hash;
1578 err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem);
1579 if (BE (err != REG_NOERROR, 0))
1580 return REG_ESPACE;
1581 for (i = 0; i < newstate->nodes.nelem; i++)
1582 {
1583 int elem = newstate->nodes.elems[i];
1584 if (!IS_EPSILON_NODE (dfa->nodes[elem].type))
1585 if (re_node_set_insert_last (&newstate->non_eps_nodes, elem) < 0)
1586 return REG_ESPACE;
1587 }
1588
1589 spot = dfa->state_table + (hash & dfa->state_hash_mask);
1590 if (BE (spot->alloc <= spot->num, 0))
1591 {
1592 int new_alloc = 2 * spot->num + 2;
1593 re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *,
1594 new_alloc);
1595 if (BE (new_array == NULL, 0))
1596 return REG_ESPACE;
1597 spot->array = new_array;
1598 spot->alloc = new_alloc;
1599 }
1600 spot->array[spot->num++] = newstate;
1601 return REG_NOERROR;
1602}
1603
1604static void
1605free_state (re_dfastate_t *state)
1606{
1607 re_node_set_free (&state->non_eps_nodes);
1608 re_node_set_free (&state->inveclosure);
1609 if (state->entrance_nodes != &state->nodes)
1610 {
1611 re_node_set_free (state->entrance_nodes);
1612 re_free (state->entrance_nodes);
1613 }
1614 re_node_set_free (&state->nodes);
1615 re_free (state->word_trtable);
1616 re_free (state->trtable);
1617 re_free (state);
1618}
1619
1620/* Create the new state which is independ of contexts.
1621 Return the new state if succeeded, otherwise return NULL. */
1622
1623static re_dfastate_t *
1624internal_function
1625create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
1626 unsigned int hash)
1627{
1628 int i;
1629 reg_errcode_t err;
1630 re_dfastate_t *newstate;
1631
1632 newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
1633 if (BE (newstate == NULL, 0))
1634 return NULL;
1635 err = re_node_set_init_copy (&newstate->nodes, nodes);
1636 if (BE (err != REG_NOERROR, 0))
1637 {
1638 re_free (newstate);
1639 return NULL;
1640 }
1641
1642 newstate->entrance_nodes = &newstate->nodes;
1643 for (i = 0 ; i < nodes->nelem ; i++)
1644 {
1645 re_token_t *node = dfa->nodes + nodes->elems[i];
1646 re_token_type_t type = node->type;
1647 if (type == CHARACTER && !node->constraint)
1648 continue;
1649#ifdef RE_ENABLE_I18N
1650 newstate->accept_mb |= node->accept_mb;
1651#endif /* RE_ENABLE_I18N */
1652
1653 /* If the state has the halt node, the state is a halt state. */
1654 if (type == END_OF_RE)
1655 newstate->halt = 1;
1656 else if (type == OP_BACK_REF)
1657 newstate->has_backref = 1;
1658 else if (type == ANCHOR || node->constraint)
1659 newstate->has_constraint = 1;
1660 }
1661 err = register_state (dfa, newstate, hash);
1662 if (BE (err != REG_NOERROR, 0))
1663 {
1664 free_state (newstate);
1665 newstate = NULL;
1666 }
1667 return newstate;
1668}
1669
1670/* Create the new state which is depend on the context CONTEXT.
1671 Return the new state if succeeded, otherwise return NULL. */
1672
1673static re_dfastate_t *
1674internal_function
1675create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
1676 unsigned int context, unsigned int hash)
1677{
1678 int i, nctx_nodes = 0;
1679 reg_errcode_t err;
1680 re_dfastate_t *newstate;
1681
1682 newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
1683 if (BE (newstate == NULL, 0))
1684 return NULL;
1685 err = re_node_set_init_copy (&newstate->nodes, nodes);
1686 if (BE (err != REG_NOERROR, 0))
1687 {
1688 re_free (newstate);
1689 return NULL;
1690 }
1691
1692 newstate->context = context;
1693 newstate->entrance_nodes = &newstate->nodes;
1694
1695 for (i = 0 ; i < nodes->nelem ; i++)
1696 {
1697 re_token_t *node = dfa->nodes + nodes->elems[i];
1698 re_token_type_t type = node->type;
1699 unsigned int constraint = node->constraint;
1700
1701 if (type == CHARACTER && !constraint)
1702 continue;
1703#ifdef RE_ENABLE_I18N
1704 newstate->accept_mb |= node->accept_mb;
1705#endif /* RE_ENABLE_I18N */
1706
1707 /* If the state has the halt node, the state is a halt state. */
1708 if (type == END_OF_RE)
1709 newstate->halt = 1;
1710 else if (type == OP_BACK_REF)
1711 newstate->has_backref = 1;
1712
1713 if (constraint)
1714 {
1715 if (newstate->entrance_nodes == &newstate->nodes)
1716 {
1717 newstate->entrance_nodes = re_malloc (re_node_set, 1);
1718 if (BE (newstate->entrance_nodes == NULL, 0))
1719 {
1720 free_state (newstate);
1721 return NULL;
1722 }
1723 if (re_node_set_init_copy (newstate->entrance_nodes, nodes)
1724 != REG_NOERROR)
1725 return NULL;
1726 nctx_nodes = 0;
1727 newstate->has_constraint = 1;
1728 }
1729
1730 if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context))
1731 {
1732 re_node_set_remove_at (&newstate->nodes, i - nctx_nodes);
1733 ++nctx_nodes;
1734 }
1735 }
1736 }
1737 err = register_state (dfa, newstate, hash);
1738 if (BE (err != REG_NOERROR, 0))
1739 {
1740 free_state (newstate);
1741 newstate = NULL;
1742 }
1743 return newstate;
1744}
diff --git a/win32/regex_internal.h b/win32/regex_internal.h
new file mode 100644
index 000000000..1495059ab
--- /dev/null
+++ b/win32/regex_internal.h
@@ -0,0 +1,810 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2005, 2007, 2008, 2010 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
20
21#ifndef _REGEX_INTERNAL_H
22#define _REGEX_INTERNAL_H 1
23
24#include <assert.h>
25#include <ctype.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
31# include <langinfo.h>
32#endif
33#if defined HAVE_LOCALE_H || defined _LIBC
34# include <locale.h>
35#endif
36#if defined HAVE_WCHAR_H || defined _LIBC
37# include <wchar.h>
38#endif /* HAVE_WCHAR_H || _LIBC */
39#if defined HAVE_WCTYPE_H || defined _LIBC
40# include <wctype.h>
41#endif /* HAVE_WCTYPE_H || _LIBC */
42#if defined HAVE_STDBOOL_H || defined _LIBC
43# include <stdbool.h>
44#endif /* HAVE_STDBOOL_H || _LIBC */
45#if !defined(ZOS_USS)
46#if defined HAVE_STDINT_H || defined _LIBC
47# include <stdint.h>
48#endif /* HAVE_STDINT_H || _LIBC */
49#endif /* !ZOS_USS */
50#if defined _LIBC
51# include <bits/libc-lock.h>
52#else
53# define __libc_lock_define(CLASS,NAME)
54# define __libc_lock_init(NAME) do { } while (0)
55# define __libc_lock_lock(NAME) do { } while (0)
56# define __libc_lock_unlock(NAME) do { } while (0)
57#endif
58
59#ifndef GAWK
60/* In case that the system doesn't have isblank(). */
61#if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank
62# define isblank(ch) ((ch) == ' ' || (ch) == '\t')
63#endif
64#else /* GAWK */
65/*
66 * This is a freaking mess. On glibc systems you have to define
67 * a magic constant to get isblank() out of <ctype.h>, since it's
68 * a C99 function. To heck with all that and borrow a page from
69 * dfa.c's book.
70 */
71
72static int
73is_blank (int c)
74{
75 return (c == ' ' || c == '\t');
76}
77#endif /* GAWK */
78
79#ifdef _LIBC
80# ifndef _RE_DEFINE_LOCALE_FUNCTIONS
81# define _RE_DEFINE_LOCALE_FUNCTIONS 1
82# include <locale/localeinfo.h>
83# include <locale/elem-hash.h>
84# include <locale/coll-lookup.h>
85# endif
86#endif
87
88/* This is for other GNU distributions with internationalized messages. */
89#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
90# include <libintl.h>
91# ifdef _LIBC
92# undef gettext
93# define gettext(msgid) \
94 INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES)
95# endif
96#else
97# define gettext(msgid) (msgid)
98#endif
99
100#ifndef gettext_noop
101/* This define is so xgettext can find the internationalizable
102 strings. */
103# define gettext_noop(String) String
104#endif
105
106/* For loser systems without the definition. */
107#ifndef SIZE_MAX
108# define SIZE_MAX ((size_t) -1)
109#endif
110
111#ifndef NO_MBSUPPORT
112#include "mbsupport.h" /* gawk */
113#endif
114#ifndef MB_CUR_MAX
115#define MB_CUR_MAX 1
116#endif
117
118#if (defined MBS_SUPPORT) || defined _LIBC
119# define RE_ENABLE_I18N
120#endif
121
122#if __GNUC__ >= 3
123# define BE(expr, val) __builtin_expect (expr, val)
124#else
125# define BE(expr, val) (expr)
126# ifdef inline
127# undef inline
128# endif
129# define inline
130#endif
131
132/* Number of single byte character. */
133#define SBC_MAX 256
134
135#define COLL_ELEM_LEN_MAX 8
136
137/* The character which represents newline. */
138#define NEWLINE_CHAR '\n'
139#define WIDE_NEWLINE_CHAR L'\n'
140
141/* Rename to standard API for using out of glibc. */
142#ifndef _LIBC
143# ifdef __wctype
144# undef __wctype
145# endif
146# define __wctype wctype
147# ifdef __iswctype
148# undef __iswctype
149# endif
150# define __iswctype iswctype
151# define __btowc btowc
152# define __mbrtowc mbrtowc
153#undef __mempcpy /* GAWK */
154# define __mempcpy mempcpy
155# define __wcrtomb wcrtomb
156# define __regfree regfree
157# define attribute_hidden
158#endif /* not _LIBC */
159
160#ifdef __GNUC__
161# define __attribute(arg) __attribute__ (arg)
162#else
163# define __attribute(arg)
164#endif
165
166extern const char __re_error_msgid[] attribute_hidden;
167extern const size_t __re_error_msgid_idx[] attribute_hidden;
168
169/* An integer used to represent a set of bits. It must be unsigned,
170 and must be at least as wide as unsigned int. */
171typedef unsigned long int bitset_word_t;
172/* All bits set in a bitset_word_t. */
173#define BITSET_WORD_MAX ULONG_MAX
174/* Number of bits in a bitset_word_t. */
175#define BITSET_WORD_BITS (sizeof (bitset_word_t) * CHAR_BIT)
176/* Number of bitset_word_t in a bit_set. */
177#define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS)
178typedef bitset_word_t bitset_t[BITSET_WORDS];
179typedef bitset_word_t *re_bitset_ptr_t;
180typedef const bitset_word_t *re_const_bitset_ptr_t;
181
182#define bitset_set(set,i) \
183 (set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS)
184#define bitset_clear(set,i) \
185 (set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS))
186#define bitset_contain(set,i) \
187 (set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS))
188#define bitset_empty(set) memset (set, '\0', sizeof (bitset_t))
189#define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t))
190#define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t))
191
192#define PREV_WORD_CONSTRAINT 0x0001
193#define PREV_NOTWORD_CONSTRAINT 0x0002
194#define NEXT_WORD_CONSTRAINT 0x0004
195#define NEXT_NOTWORD_CONSTRAINT 0x0008
196#define PREV_NEWLINE_CONSTRAINT 0x0010
197#define NEXT_NEWLINE_CONSTRAINT 0x0020
198#define PREV_BEGBUF_CONSTRAINT 0x0040
199#define NEXT_ENDBUF_CONSTRAINT 0x0080
200#define WORD_DELIM_CONSTRAINT 0x0100
201#define NOT_WORD_DELIM_CONSTRAINT 0x0200
202
203typedef enum
204{
205 INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
206 WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
207 WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
208 INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
209 LINE_FIRST = PREV_NEWLINE_CONSTRAINT,
210 LINE_LAST = NEXT_NEWLINE_CONSTRAINT,
211 BUF_FIRST = PREV_BEGBUF_CONSTRAINT,
212 BUF_LAST = NEXT_ENDBUF_CONSTRAINT,
213 WORD_DELIM = WORD_DELIM_CONSTRAINT,
214 NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT
215} re_context_type;
216
217typedef struct
218{
219 int alloc;
220 int nelem;
221 int *elems;
222} re_node_set;
223
224typedef enum
225{
226 NON_TYPE = 0,
227
228 /* Node type, These are used by token, node, tree. */
229 CHARACTER = 1,
230 END_OF_RE = 2,
231 SIMPLE_BRACKET = 3,
232 OP_BACK_REF = 4,
233 OP_PERIOD = 5,
234#ifdef RE_ENABLE_I18N
235 COMPLEX_BRACKET = 6,
236 OP_UTF8_PERIOD = 7,
237#endif /* RE_ENABLE_I18N */
238
239 /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used
240 when the debugger shows values of this enum type. */
241#define EPSILON_BIT 8
242 OP_OPEN_SUBEXP = EPSILON_BIT | 0,
243 OP_CLOSE_SUBEXP = EPSILON_BIT | 1,
244 OP_ALT = EPSILON_BIT | 2,
245 OP_DUP_ASTERISK = EPSILON_BIT | 3,
246 ANCHOR = EPSILON_BIT | 4,
247
248 /* Tree type, these are used only by tree. */
249 CONCAT = 16,
250 SUBEXP = 17,
251
252 /* Token type, these are used only by token. */
253 OP_DUP_PLUS = 18,
254 OP_DUP_QUESTION,
255 OP_OPEN_BRACKET,
256 OP_CLOSE_BRACKET,
257 OP_CHARSET_RANGE,
258 OP_OPEN_DUP_NUM,
259 OP_CLOSE_DUP_NUM,
260 OP_NON_MATCH_LIST,
261 OP_OPEN_COLL_ELEM,
262 OP_CLOSE_COLL_ELEM,
263 OP_OPEN_EQUIV_CLASS,
264 OP_CLOSE_EQUIV_CLASS,
265 OP_OPEN_CHAR_CLASS,
266 OP_CLOSE_CHAR_CLASS,
267 OP_WORD,
268 OP_NOTWORD,
269 OP_SPACE,
270 OP_NOTSPACE,
271 BACK_SLASH
272
273} re_token_type_t;
274
275#ifdef RE_ENABLE_I18N
276typedef struct
277{
278 /* Multibyte characters. */
279 wchar_t *mbchars;
280
281 /* Collating symbols. */
282# ifdef _LIBC
283 int32_t *coll_syms;
284# endif
285
286 /* Equivalence classes. */
287# ifdef _LIBC
288 int32_t *equiv_classes;
289# endif
290
291 /* Range expressions. */
292# ifdef _LIBC
293 uint32_t *range_starts;
294 uint32_t *range_ends;
295# else /* not _LIBC */
296 wchar_t *range_starts;
297 wchar_t *range_ends;
298# endif /* not _LIBC */
299
300 /* Character classes. */
301 wctype_t *char_classes;
302
303 /* If this character set is the non-matching list. */
304 unsigned int non_match : 1;
305
306 /* # of multibyte characters. */
307 int nmbchars;
308
309 /* # of collating symbols. */
310 int ncoll_syms;
311
312 /* # of equivalence classes. */
313 int nequiv_classes;
314
315 /* # of range expressions. */
316 int nranges;
317
318 /* # of character classes. */
319 int nchar_classes;
320} re_charset_t;
321#endif /* RE_ENABLE_I18N */
322
323typedef struct
324{
325 union
326 {
327 unsigned char c; /* for CHARACTER */
328 re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */
329#ifdef RE_ENABLE_I18N
330 re_charset_t *mbcset; /* for COMPLEX_BRACKET */
331#endif /* RE_ENABLE_I18N */
332 int idx; /* for BACK_REF */
333 re_context_type ctx_type; /* for ANCHOR */
334 } opr;
335#if __GNUC__ >= 2
336 re_token_type_t type : 8;
337#else
338 re_token_type_t type;
339#endif
340 unsigned int constraint : 10; /* context constraint */
341 unsigned int duplicated : 1;
342 unsigned int opt_subexp : 1;
343#ifdef RE_ENABLE_I18N
344 unsigned int accept_mb : 1;
345 /* These 2 bits can be moved into the union if needed (e.g. if running out
346 of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */
347 unsigned int mb_partial : 1;
348#endif
349 unsigned int word_char : 1;
350} re_token_t;
351
352#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT)
353
354struct re_string_t
355{
356 /* Indicate the raw buffer which is the original string passed as an
357 argument of regexec(), re_search(), etc.. */
358 const unsigned char *raw_mbs;
359 /* Store the multibyte string. In case of "case insensitive mode" like
360 REG_ICASE, upper cases of the string are stored, otherwise MBS points
361 the same address that RAW_MBS points. */
362 unsigned char *mbs;
363#ifdef RE_ENABLE_I18N
364 /* Store the wide character string which is corresponding to MBS. */
365 wint_t *wcs;
366 int *offsets;
367 mbstate_t cur_state;
368#endif
369 /* Index in RAW_MBS. Each character mbs[i] corresponds to
370 raw_mbs[raw_mbs_idx + i]. */
371 int raw_mbs_idx;
372 /* The length of the valid characters in the buffers. */
373 int valid_len;
374 /* The corresponding number of bytes in raw_mbs array. */
375 int valid_raw_len;
376 /* The length of the buffers MBS and WCS. */
377 int bufs_len;
378 /* The index in MBS, which is updated by re_string_fetch_byte. */
379 int cur_idx;
380 /* length of RAW_MBS array. */
381 int raw_len;
382 /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */
383 int len;
384 /* End of the buffer may be shorter than its length in the cases such
385 as re_match_2, re_search_2. Then, we use STOP for end of the buffer
386 instead of LEN. */
387 int raw_stop;
388 /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */
389 int stop;
390
391 /* The context of mbs[0]. We store the context independently, since
392 the context of mbs[0] may be different from raw_mbs[0], which is
393 the beginning of the input string. */
394 unsigned int tip_context;
395 /* The translation passed as a part of an argument of re_compile_pattern. */
396 RE_TRANSLATE_TYPE trans;
397 /* Copy of re_dfa_t's word_char. */
398 re_const_bitset_ptr_t word_char;
399 /* 1 if REG_ICASE. */
400 unsigned char icase;
401 unsigned char is_utf8;
402 unsigned char map_notascii;
403 unsigned char mbs_allocated;
404 unsigned char offsets_needed;
405 unsigned char newline_anchor;
406 unsigned char word_ops_used;
407 int mb_cur_max;
408};
409typedef struct re_string_t re_string_t;
410
411
412struct re_dfa_t;
413typedef struct re_dfa_t re_dfa_t;
414
415#ifndef _LIBC
416# ifdef __i386__
417# define internal_function __attribute ((regparm (3), stdcall))
418# else
419# define internal_function
420# endif
421#endif
422
423#ifndef NOT_IN_libc
424static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr,
425 int new_buf_len)
426 internal_function;
427# ifdef RE_ENABLE_I18N
428static void build_wcs_buffer (re_string_t *pstr) internal_function;
429static reg_errcode_t build_wcs_upper_buffer (re_string_t *pstr)
430 internal_function;
431# endif /* RE_ENABLE_I18N */
432static void build_upper_buffer (re_string_t *pstr) internal_function;
433static void re_string_translate_buffer (re_string_t *pstr) internal_function;
434static unsigned int re_string_context_at (const re_string_t *input, int idx,
435 int eflags)
436 internal_function __attribute ((pure));
437#endif
438#define re_string_peek_byte(pstr, offset) \
439 ((pstr)->mbs[(pstr)->cur_idx + offset])
440#define re_string_fetch_byte(pstr) \
441 ((pstr)->mbs[(pstr)->cur_idx++])
442#define re_string_first_byte(pstr, idx) \
443 ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF)
444#define re_string_is_single_byte_char(pstr, idx) \
445 ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \
446 || (pstr)->wcs[(idx) + 1] != WEOF))
447#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx)
448#define re_string_cur_idx(pstr) ((pstr)->cur_idx)
449#define re_string_get_buffer(pstr) ((pstr)->mbs)
450#define re_string_length(pstr) ((pstr)->len)
451#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx])
452#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
453#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
454
455#ifndef _LIBC
456# if HAVE_ALLOCA
457# ifdef (_MSC_VER)
458# include <malloc.h>
459# define __libc_use_alloca(n) 0
460# else
461# include <alloca.h>
462/* The OS usually guarantees only one guard page at the bottom of the stack,
463 and a page size can be as small as 4096 bytes. So we cannot safely
464 allocate anything larger than 4096 bytes. Also care for the possibility
465 of a few compiler-allocated temporary stack slots. */
466# define __libc_use_alloca(n) ((n) < 4032)
467# endif
468# else
469/* alloca is implemented with malloc, so just use malloc. */
470# define __libc_use_alloca(n) 0
471# endif
472#endif
473
474#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t)))
475/* SunOS 4.1.x realloc doesn't accept null pointers: pre-Standard C. Sigh. */
476#define re_realloc(p,t,n) ((p != NULL) ? (t *) realloc (p,(n)*sizeof(t)) : (t *) calloc(n,sizeof(t)))
477#define re_free(p) free (p)
478
479struct bin_tree_t
480{
481 struct bin_tree_t *parent;
482 struct bin_tree_t *left;
483 struct bin_tree_t *right;
484 struct bin_tree_t *first;
485 struct bin_tree_t *next;
486
487 re_token_t token;
488
489 /* `node_idx' is the index in dfa->nodes, if `type' == 0.
490 Otherwise `type' indicate the type of this node. */
491 int node_idx;
492};
493typedef struct bin_tree_t bin_tree_t;
494
495#define BIN_TREE_STORAGE_SIZE \
496 ((1024 - sizeof (void *)) / sizeof (bin_tree_t))
497
498struct bin_tree_storage_t
499{
500 struct bin_tree_storage_t *next;
501 bin_tree_t data[BIN_TREE_STORAGE_SIZE];
502};
503typedef struct bin_tree_storage_t bin_tree_storage_t;
504
505#define CONTEXT_WORD 1
506#define CONTEXT_NEWLINE (CONTEXT_WORD << 1)
507#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1)
508#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1)
509
510#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD)
511#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE)
512#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF)
513#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF)
514#define IS_ORDINARY_CONTEXT(c) ((c) == 0)
515
516#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_')
517#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR)
518#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_')
519#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR)
520
521#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \
522 ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
523 || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
524 || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\
525 || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context)))
526
527#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \
528 ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
529 || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
530 || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \
531 || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context)))
532
533struct re_dfastate_t
534{
535 unsigned int hash;
536 re_node_set nodes;
537 re_node_set non_eps_nodes;
538 re_node_set inveclosure;
539 re_node_set *entrance_nodes;
540 struct re_dfastate_t **trtable, **word_trtable;
541 unsigned int context : 4;
542 unsigned int halt : 1;
543 /* If this state can accept `multi byte'.
544 Note that we refer to multibyte characters, and multi character
545 collating elements as `multi byte'. */
546 unsigned int accept_mb : 1;
547 /* If this state has backreference node(s). */
548 unsigned int has_backref : 1;
549 unsigned int has_constraint : 1;
550};
551typedef struct re_dfastate_t re_dfastate_t;
552
553struct re_state_table_entry
554{
555 int num;
556 int alloc;
557 re_dfastate_t **array;
558};
559
560/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */
561
562typedef struct
563{
564 int next_idx;
565 int alloc;
566 re_dfastate_t **array;
567} state_array_t;
568
569/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */
570
571typedef struct
572{
573 int node;
574 int str_idx; /* The position NODE match at. */
575 state_array_t path;
576} re_sub_match_last_t;
577
578/* Store information about the node NODE whose type is OP_OPEN_SUBEXP.
579 And information about the node, whose type is OP_CLOSE_SUBEXP,
580 corresponding to NODE is stored in LASTS. */
581
582typedef struct
583{
584 int str_idx;
585 int node;
586 state_array_t *path;
587 int alasts; /* Allocation size of LASTS. */
588 int nlasts; /* The number of LASTS. */
589 re_sub_match_last_t **lasts;
590} re_sub_match_top_t;
591
592struct re_backref_cache_entry
593{
594 int node;
595 int str_idx;
596 int subexp_from;
597 int subexp_to;
598 char more;
599 char unused;
600 unsigned short int eps_reachable_subexps_map;
601};
602
603typedef struct
604{
605 /* The string object corresponding to the input string. */
606 re_string_t input;
607#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
608 const re_dfa_t *const dfa;
609#else
610 const re_dfa_t *dfa;
611#endif
612 /* EFLAGS of the argument of regexec. */
613 int eflags;
614 /* Where the matching ends. */
615 int match_last;
616 int last_node;
617 /* The state log used by the matcher. */
618 re_dfastate_t **state_log;
619 int state_log_top;
620 /* Back reference cache. */
621 int nbkref_ents;
622 int abkref_ents;
623 struct re_backref_cache_entry *bkref_ents;
624 int max_mb_elem_len;
625 int nsub_tops;
626 int asub_tops;
627 re_sub_match_top_t **sub_tops;
628} re_match_context_t;
629
630typedef struct
631{
632 re_dfastate_t **sifted_states;
633 re_dfastate_t **limited_states;
634 int last_node;
635 int last_str_idx;
636 re_node_set limits;
637} re_sift_context_t;
638
639struct re_fail_stack_ent_t
640{
641 int idx;
642 int node;
643 regmatch_t *regs;
644 re_node_set eps_via_nodes;
645};
646
647struct re_fail_stack_t
648{
649 int num;
650 int alloc;
651 struct re_fail_stack_ent_t *stack;
652};
653
654struct re_dfa_t
655{
656 re_token_t *nodes;
657 size_t nodes_alloc;
658 size_t nodes_len;
659 int *nexts;
660 int *org_indices;
661 re_node_set *edests;
662 re_node_set *eclosures;
663 re_node_set *inveclosures;
664 struct re_state_table_entry *state_table;
665 re_dfastate_t *init_state;
666 re_dfastate_t *init_state_word;
667 re_dfastate_t *init_state_nl;
668 re_dfastate_t *init_state_begbuf;
669 bin_tree_t *str_tree;
670 bin_tree_storage_t *str_tree_storage;
671 re_bitset_ptr_t sb_char;
672 int str_tree_storage_idx;
673
674 /* number of subexpressions `re_nsub' is in regex_t. */
675 unsigned int state_hash_mask;
676 int init_node;
677 int nbackref; /* The number of backreference in this dfa. */
678
679 /* Bitmap expressing which backreference is used. */
680 bitset_word_t used_bkref_map;
681 bitset_word_t completed_bkref_map;
682
683 unsigned int has_plural_match : 1;
684 /* If this dfa has "multibyte node", which is a backreference or
685 a node which can accept multibyte character or multi character
686 collating element. */
687 unsigned int has_mb_node : 1;
688 unsigned int is_utf8 : 1;
689 unsigned int map_notascii : 1;
690 unsigned int word_ops_used : 1;
691 int mb_cur_max;
692 bitset_t word_char;
693 reg_syntax_t syntax;
694 int *subexp_map;
695#ifdef DEBUG
696 char* re_str;
697#endif
698#if defined _LIBC
699 __libc_lock_define (, lock)
700#endif
701};
702
703#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
704#define re_node_set_remove(set,id) \
705 (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
706#define re_node_set_empty(p) ((p)->nelem = 0)
707#define re_node_set_free(set) re_free ((set)->elems)
708
709
710typedef enum
711{
712 SB_CHAR,
713 MB_CHAR,
714 EQUIV_CLASS,
715 COLL_SYM,
716 CHAR_CLASS
717} bracket_elem_type;
718
719typedef struct
720{
721 bracket_elem_type type;
722 union
723 {
724 unsigned char ch;
725 unsigned char *name;
726 wchar_t wch;
727 } opr;
728} bracket_elem_t;
729
730
731/* Inline functions for bitset operation. */
732static inline void
733bitset_not (bitset_t set)
734{
735 int bitset_i;
736 for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
737 set[bitset_i] = ~set[bitset_i];
738}
739
740static inline void
741bitset_merge (bitset_t dest, const bitset_t src)
742{
743 int bitset_i;
744 for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
745 dest[bitset_i] |= src[bitset_i];
746}
747
748static inline void
749bitset_mask (bitset_t dest, const bitset_t src)
750{
751 int bitset_i;
752 for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
753 dest[bitset_i] &= src[bitset_i];
754}
755
756#ifdef RE_ENABLE_I18N
757/* Inline functions for re_string. */
758static inline int
759internal_function __attribute ((pure))
760re_string_char_size_at (const re_string_t *pstr, int idx)
761{
762 int byte_idx;
763 if (pstr->mb_cur_max == 1)
764 return 1;
765 for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
766 if (pstr->wcs[idx + byte_idx] != WEOF)
767 break;
768 return byte_idx;
769}
770
771static inline wint_t
772internal_function __attribute ((pure))
773re_string_wchar_at (const re_string_t *pstr, int idx)
774{
775 if (pstr->mb_cur_max == 1)
776 return (wint_t) pstr->mbs[idx];
777 return (wint_t) pstr->wcs[idx];
778}
779
780# ifndef NOT_IN_libc
781static int
782internal_function __attribute ((pure))
783re_string_elem_size_at (const re_string_t *pstr, int idx)
784{
785# ifdef _LIBC
786 const unsigned char *p, *extra;
787 const int32_t *table, *indirect;
788 int32_t tmp;
789# include <locale/weight.h>
790 uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
791
792 if (nrules != 0)
793 {
794 table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
795 extra = (const unsigned char *)
796 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
797 indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
798 _NL_COLLATE_INDIRECTMB);
799 p = pstr->mbs + idx;
800 tmp = findidx (&p);
801 return p - pstr->mbs - idx;
802 }
803 else
804# endif /* _LIBC */
805 return 1;
806}
807# endif
808#endif /* RE_ENABLE_I18N */
809
810#endif /* _REGEX_INTERNAL_H */
diff --git a/win32/regexec.c b/win32/regexec.c
new file mode 100644
index 000000000..eb5e1d443
--- /dev/null
+++ b/win32/regexec.c
@@ -0,0 +1,4369 @@
1/* Extended regular expression matching and search library.
2 Copyright (C) 2002-2005, 2007, 2009, 2010 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library 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 GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA. */
20
21static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
22 int n) internal_function;
23static void match_ctx_clean (re_match_context_t *mctx) internal_function;
24static void match_ctx_free (re_match_context_t *cache) internal_function;
25static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node,
26 int str_idx, int from, int to)
27 internal_function;
28static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
29 internal_function;
30static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node,
31 int str_idx) internal_function;
32static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop,
33 int node, int str_idx)
34 internal_function;
35static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
36 re_dfastate_t **limited_sts, int last_node,
37 int last_str_idx)
38 internal_function;
39static reg_errcode_t re_search_internal (const regex_t *preg,
40 const char *string, int length,
41 int start, int range, int stop,
42 size_t nmatch, regmatch_t pmatch[],
43 int eflags);
44static int re_search_2_stub (struct re_pattern_buffer *bufp,
45 const char *string1, int length1,
46 const char *string2, int length2,
47 int start, int range, struct re_registers *regs,
48 int stop, int ret_len);
49static int re_search_stub (struct re_pattern_buffer *bufp,
50 const char *string, int length, int start,
51 int range, int stop, struct re_registers *regs,
52 int ret_len);
53static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
54 int nregs, int regs_allocated);
55static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx);
56static int check_matching (re_match_context_t *mctx, int fl_longest_match,
57 int *p_match_first) internal_function;
58static int check_halt_state_context (const re_match_context_t *mctx,
59 const re_dfastate_t *state, int idx)
60 internal_function;
61static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
62 regmatch_t *prev_idx_match, int cur_node,
63 int cur_idx, int nmatch) internal_function;
64static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
65 int str_idx, int dest_node, int nregs,
66 regmatch_t *regs,
67 re_node_set *eps_via_nodes)
68 internal_function;
69static reg_errcode_t set_regs (const regex_t *preg,
70 const re_match_context_t *mctx,
71 size_t nmatch, regmatch_t *pmatch,
72 int fl_backtrack) internal_function;
73static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs)
74 internal_function;
75
76#ifdef RE_ENABLE_I18N
77static int sift_states_iter_mb (const re_match_context_t *mctx,
78 re_sift_context_t *sctx,
79 int node_idx, int str_idx, int max_str_idx)
80 internal_function;
81#endif /* RE_ENABLE_I18N */
82static reg_errcode_t sift_states_backward (const re_match_context_t *mctx,
83 re_sift_context_t *sctx)
84 internal_function;
85static reg_errcode_t build_sifted_states (const re_match_context_t *mctx,
86 re_sift_context_t *sctx, int str_idx,
87 re_node_set *cur_dest)
88 internal_function;
89static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx,
90 re_sift_context_t *sctx,
91 int str_idx,
92 re_node_set *dest_nodes)
93 internal_function;
94static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa,
95 re_node_set *dest_nodes,
96 const re_node_set *candidates)
97 internal_function;
98static int check_dst_limits (const re_match_context_t *mctx,
99 re_node_set *limits,
100 int dst_node, int dst_idx, int src_node,
101 int src_idx) internal_function;
102static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx,
103 int boundaries, int subexp_idx,
104 int from_node, int bkref_idx)
105 internal_function;
106static int check_dst_limits_calc_pos (const re_match_context_t *mctx,
107 int limit, int subexp_idx,
108 int node, int str_idx,
109 int bkref_idx) internal_function;
110static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa,
111 re_node_set *dest_nodes,
112 const re_node_set *candidates,
113 re_node_set *limits,
114 struct re_backref_cache_entry *bkref_ents,
115 int str_idx) internal_function;
116static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx,
117 re_sift_context_t *sctx,
118 int str_idx, const re_node_set *candidates)
119 internal_function;
120static reg_errcode_t merge_state_array (const re_dfa_t *dfa,
121 re_dfastate_t **dst,
122 re_dfastate_t **src, int num)
123 internal_function;
124static re_dfastate_t *find_recover_state (reg_errcode_t *err,
125 re_match_context_t *mctx) internal_function;
126static re_dfastate_t *transit_state (reg_errcode_t *err,
127 re_match_context_t *mctx,
128 re_dfastate_t *state) internal_function;
129static re_dfastate_t *merge_state_with_log (reg_errcode_t *err,
130 re_match_context_t *mctx,
131 re_dfastate_t *next_state)
132 internal_function;
133static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx,
134 re_node_set *cur_nodes,
135 int str_idx) internal_function;
136#if 0
137static re_dfastate_t *transit_state_sb (reg_errcode_t *err,
138 re_match_context_t *mctx,
139 re_dfastate_t *pstate)
140 internal_function;
141#endif
142#ifdef RE_ENABLE_I18N
143static reg_errcode_t transit_state_mb (re_match_context_t *mctx,
144 re_dfastate_t *pstate)
145 internal_function;
146#endif /* RE_ENABLE_I18N */
147static reg_errcode_t transit_state_bkref (re_match_context_t *mctx,
148 const re_node_set *nodes)
149 internal_function;
150static reg_errcode_t get_subexp (re_match_context_t *mctx,
151 int bkref_node, int bkref_str_idx)
152 internal_function;
153static reg_errcode_t get_subexp_sub (re_match_context_t *mctx,
154 const re_sub_match_top_t *sub_top,
155 re_sub_match_last_t *sub_last,
156 int bkref_node, int bkref_str)
157 internal_function;
158static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
159 int subexp_idx, int type) internal_function;
160static reg_errcode_t check_arrival (re_match_context_t *mctx,
161 state_array_t *path, int top_node,
162 int top_str, int last_node, int last_str,
163 int type) internal_function;
164static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx,
165 int str_idx,
166 re_node_set *cur_nodes,
167 re_node_set *next_nodes)
168 internal_function;
169static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa,
170 re_node_set *cur_nodes,
171 int ex_subexp, int type)
172 internal_function;
173static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa,
174 re_node_set *dst_nodes,
175 int target, int ex_subexp,
176 int type) internal_function;
177static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx,
178 re_node_set *cur_nodes, int cur_str,
179 int subexp_num, int type)
180 internal_function;
181static int build_trtable (const re_dfa_t *dfa,
182 re_dfastate_t *state) internal_function;
183#ifdef RE_ENABLE_I18N
184static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
185 const re_string_t *input, int idx)
186 internal_function;
187# ifdef _LIBC
188static unsigned int find_collation_sequence_value (const unsigned char *mbs,
189 size_t name_len)
190 internal_function;
191# endif /* _LIBC */
192#endif /* RE_ENABLE_I18N */
193static int group_nodes_into_DFAstates (const re_dfa_t *dfa,
194 const re_dfastate_t *state,
195 re_node_set *states_node,
196 bitset_t *states_ch) internal_function;
197static int check_node_accept (const re_match_context_t *mctx,
198 const re_token_t *node, int idx)
199 internal_function;
200static reg_errcode_t extend_buffers (re_match_context_t *mctx)
201 internal_function;
202
203/* Entry point for POSIX code. */
204
205/* regexec searches for a given pattern, specified by PREG, in the
206 string STRING.
207
208 If NMATCH is zero or REG_NOSUB was set in the cflags argument to
209 `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
210 least NMATCH elements, and we set them to the offsets of the
211 corresponding matched substrings.
212
213 EFLAGS specifies `execution flags' which affect matching: if
214 REG_NOTBOL is set, then ^ does not match at the beginning of the
215 string; if REG_NOTEOL is set, then $ does not match at the end.
216
217 We return 0 if we find a match and REG_NOMATCH if not. */
218
219int
220regexec (
221 const regex_t *__restrict preg,
222 const char *__restrict string,
223 size_t nmatch,
224 regmatch_t pmatch[],
225 int eflags)
226{
227 reg_errcode_t err;
228 int start, length;
229
230 if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND))
231 return REG_BADPAT;
232
233 if (eflags & REG_STARTEND)
234 {
235 start = pmatch[0].rm_so;
236 length = pmatch[0].rm_eo;
237 }
238 else
239 {
240 start = 0;
241 length = strlen (string);
242 }
243
244 __libc_lock_lock (dfa->lock);
245 if (preg->no_sub)
246 err = re_search_internal (preg, string, length, start, length - start,
247 length, 0, NULL, eflags);
248 else
249 err = re_search_internal (preg, string, length, start, length - start,
250 length, nmatch, pmatch, eflags);
251 __libc_lock_unlock (dfa->lock);
252 return err != REG_NOERROR;
253}
254
255#ifdef _LIBC
256# include <shlib-compat.h>
257versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
258
259# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
260__typeof__ (__regexec) __compat_regexec;
261
262int
263attribute_compat_text_section
264__compat_regexec (const regex_t *__restrict preg,
265 const char *__restrict string, size_t nmatch,
266 regmatch_t pmatch[], int eflags)
267{
268 return regexec (preg, string, nmatch, pmatch,
269 eflags & (REG_NOTBOL | REG_NOTEOL));
270}
271compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
272# endif
273#endif
274
275/* Entry points for GNU code. */
276
277/* re_match, re_search, re_match_2, re_search_2
278
279 The former two functions operate on STRING with length LENGTH,
280 while the later two operate on concatenation of STRING1 and STRING2
281 with lengths LENGTH1 and LENGTH2, respectively.
282
283 re_match() matches the compiled pattern in BUFP against the string,
284 starting at index START.
285
286 re_search() first tries matching at index START, then it tries to match
287 starting from index START + 1, and so on. The last start position tried
288 is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same
289 way as re_match().)
290
291 The parameter STOP of re_{match,search}_2 specifies that no match exceeding
292 the first STOP characters of the concatenation of the strings should be
293 concerned.
294
295 If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match
296 and all groups is stroed in REGS. (For the "_2" variants, the offsets are
297 computed relative to the concatenation, not relative to the individual
298 strings.)
299
300 On success, re_match* functions return the length of the match, re_search*
301 return the position of the start of the match. Return value -1 means no
302 match was found and -2 indicates an internal error. */
303
304int
305re_match (struct re_pattern_buffer *bufp,
306 const char *string,
307 int length,
308 int start,
309 struct re_registers *regs)
310{
311 return re_search_stub (bufp, string, length, start, 0, length, regs, 1);
312}
313#ifdef _LIBC
314weak_alias (__re_match, re_match)
315#endif
316
317int
318re_search (struct re_pattern_buffer *bufp,
319 const char *string,
320 int length, int start, int range,
321 struct re_registers *regs)
322{
323 return re_search_stub (bufp, string, length, start, range, length, regs, 0);
324}
325#ifdef _LIBC
326weak_alias (__re_search, re_search)
327#endif
328
329int
330re_match_2 (struct re_pattern_buffer *bufp,
331 const char *string1, int length1,
332 const char *string2, int length2, int start,
333 struct re_registers *regs, int stop)
334{
335 return re_search_2_stub (bufp, string1, length1, string2, length2,
336 start, 0, regs, stop, 1);
337}
338#ifdef _LIBC
339weak_alias (__re_match_2, re_match_2)
340#endif
341
342int
343re_search_2 (struct re_pattern_buffer *bufp,
344 const char *string1, int length1,
345 const char *string2, int length2, int start,
346 int range, struct re_registers *regs, int stop)
347{
348 return re_search_2_stub (bufp, string1, length1, string2, length2,
349 start, range, regs, stop, 0);
350}
351#ifdef _LIBC
352weak_alias (__re_search_2, re_search_2)
353#endif
354
355static int
356re_search_2_stub (struct re_pattern_buffer *bufp,
357 const char *string1, int length1,
358 const char *string2, int length2, int start,
359 int range, struct re_registers *regs,
360 int stop, int ret_len)
361{
362 const char *str;
363 int rval;
364 int len = length1 + length2;
365 int free_str = 0;
366
367 if (BE (length1 < 0 || length2 < 0 || stop < 0, 0))
368 return -2;
369
370 /* Concatenate the strings. */
371 if (length2 > 0)
372 if (length1 > 0)
373 {
374 char *s = re_malloc (char, len);
375
376 if (BE (s == NULL, 0))
377 return -2;
378 memcpy (s, string1, length1);
379 memcpy (s + length1, string2, length2);
380 str = s;
381 free_str = 1;
382 }
383 else
384 str = string2;
385 else
386 str = string1;
387
388 rval = re_search_stub (bufp, str, len, start, range, stop, regs, ret_len);
389 if (free_str)
390 re_free ((char *) str);
391 return rval;
392}
393
394/* The parameters have the same meaning as those of re_search.
395 Additional parameters:
396 If RET_LEN is nonzero the length of the match is returned (re_match style);
397 otherwise the position of the match is returned. */
398
399static int
400re_search_stub (struct re_pattern_buffer *bufp,
401 const char *string, int length, int start,
402 int range, int stop,
403 struct re_registers *regs, int ret_len)
404{
405 reg_errcode_t result;
406 regmatch_t *pmatch;
407 int nregs, rval;
408 int eflags = 0;
409
410 /* Check for out-of-range. */
411 if (BE (start < 0 || start > length, 0))
412 return -1;
413 if (BE (start + range > length, 0))
414 range = length - start;
415 else if (BE (start + range < 0, 0))
416 range = -start;
417
418 __libc_lock_lock (dfa->lock);
419
420 eflags |= (bufp->not_bol) ? REG_NOTBOL : 0;
421 eflags |= (bufp->not_eol) ? REG_NOTEOL : 0;
422
423 /* Compile fastmap if we haven't yet. */
424 if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate)
425 re_compile_fastmap (bufp);
426
427 if (BE (bufp->no_sub, 0))
428 regs = NULL;
429
430 /* We need at least 1 register. */
431 if (regs == NULL)
432 nregs = 1;
433 else if (BE (bufp->regs_allocated == REGS_FIXED &&
434 regs->num_regs < bufp->re_nsub + 1, 0))
435 {
436 nregs = regs->num_regs;
437 if (BE (nregs < 1, 0))
438 {
439 /* Nothing can be copied to regs. */
440 regs = NULL;
441 nregs = 1;
442 }
443 }
444 else
445 nregs = bufp->re_nsub + 1;
446 pmatch = re_malloc (regmatch_t, nregs);
447 if (BE (pmatch == NULL, 0))
448 {
449 rval = -2;
450 goto out;
451 }
452
453 result = re_search_internal (bufp, string, length, start, range, stop,
454 nregs, pmatch, eflags);
455
456 rval = 0;
457
458 /* I hope we needn't fill their regs with -1's when no match was found. */
459 if (result != REG_NOERROR)
460 rval = -1;
461 else if (regs != NULL)
462 {
463 /* If caller wants register contents data back, copy them. */
464 bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs,
465 bufp->regs_allocated);
466 if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0))
467 rval = -2;
468 }
469
470 if (BE (rval == 0, 1))
471 {
472 if (ret_len)
473 {
474 assert (pmatch[0].rm_so == start);
475 rval = pmatch[0].rm_eo - start;
476 }
477 else
478 rval = pmatch[0].rm_so;
479 }
480 re_free (pmatch);
481 out:
482 __libc_lock_unlock (dfa->lock);
483 return rval;
484}
485
486static unsigned
487re_copy_regs (struct re_registers *regs,
488 regmatch_t *pmatch,
489 int nregs, int regs_allocated)
490{
491 int rval = REGS_REALLOCATE;
492 int i;
493 int need_regs = nregs + 1;
494 /* We need one extra element beyond `num_regs' for the `-1' marker GNU code
495 uses. */
496
497 /* Have the register data arrays been allocated? */
498 if (regs_allocated == REGS_UNALLOCATED)
499 { /* No. So allocate them with malloc. */
500 regs->start = re_malloc (regoff_t, need_regs);
501 if (BE (regs->start == NULL, 0))
502 return REGS_UNALLOCATED;
503 regs->end = re_malloc (regoff_t, need_regs);
504 if (BE (regs->end == NULL, 0))
505 {
506 re_free (regs->start);
507 return REGS_UNALLOCATED;
508 }
509 regs->num_regs = need_regs;
510 }
511 else if (regs_allocated == REGS_REALLOCATE)
512 { /* Yes. If we need more elements than were already
513 allocated, reallocate them. If we need fewer, just
514 leave it alone. */
515 if (BE (need_regs > regs->num_regs, 0))
516 {
517 regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs);
518 regoff_t *new_end;
519 if (BE (new_start == NULL, 0))
520 return REGS_UNALLOCATED;
521 new_end = re_realloc (regs->end, regoff_t, need_regs);
522 if (BE (new_end == NULL, 0))
523 {
524 re_free (new_start);
525 return REGS_UNALLOCATED;
526 }
527 regs->start = new_start;
528 regs->end = new_end;
529 regs->num_regs = need_regs;
530 }
531 }
532 else
533 {
534 assert (regs_allocated == REGS_FIXED);
535 /* This function may not be called with REGS_FIXED and nregs too big. */
536 assert (regs->num_regs >= nregs);
537 rval = REGS_FIXED;
538 }
539
540 /* Copy the regs. */
541 for (i = 0; i < nregs; ++i)
542 {
543 regs->start[i] = pmatch[i].rm_so;
544 regs->end[i] = pmatch[i].rm_eo;
545 }
546 for ( ; i < regs->num_regs; ++i)
547 regs->start[i] = regs->end[i] = -1;
548
549 return rval;
550}
551
552/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
553 ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
554 this memory for recording register information. STARTS and ENDS
555 must be allocated using the malloc library routine, and must each
556 be at least NUM_REGS * sizeof (regoff_t) bytes long.
557
558 If NUM_REGS == 0, then subsequent matches should allocate their own
559 register data.
560
561 Unless this function is called, the first search or match using
562 PATTERN_BUFFER will allocate its own register data, without
563 freeing the old data. */
564
565void
566re_set_registers (struct re_pattern_buffer *bufp,
567 struct re_registers *regs,
568 unsigned num_regs,
569 regoff_t *starts,
570 regoff_t *ends)
571{
572 if (num_regs)
573 {
574 bufp->regs_allocated = REGS_REALLOCATE;
575 regs->num_regs = num_regs;
576 regs->start = starts;
577 regs->end = ends;
578 }
579 else
580 {
581 bufp->regs_allocated = REGS_UNALLOCATED;
582 regs->num_regs = 0;
583 regs->start = regs->end = (regoff_t *) 0;
584 }
585}
586#ifdef _LIBC
587weak_alias (__re_set_registers, re_set_registers)
588#endif
589
590/* Entry points compatible with 4.2 BSD regex library. We don't define
591 them unless specifically requested. */
592
593#if defined _REGEX_RE_COMP || defined _LIBC
594int
595# ifdef _LIBC
596weak_function
597# endif
598re_exec (s)
599 const char *s;
600{
601 return 0 == regexec (&re_comp_buf, s, 0, NULL, 0);
602}
603#endif /* _REGEX_RE_COMP */
604
605/* Internal entry point. */
606
607/* Searches for a compiled pattern PREG in the string STRING, whose
608 length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same
609 mingings with regexec. START, and RANGE have the same meanings
610 with re_search.
611 Return REG_NOERROR if we find a match, and REG_NOMATCH if not,
612 otherwise return the error code.
613 Note: We assume front end functions already check ranges.
614 (START + RANGE >= 0 && START + RANGE <= LENGTH) */
615
616static reg_errcode_t
617re_search_internal (const regex_t *preg,
618 const char *string,
619 int length, int start, int range, int stop,
620 size_t nmatch, regmatch_t pmatch[],
621 int eflags)
622{
623 reg_errcode_t err;
624 const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
625 int left_lim, right_lim, incr;
626 int fl_longest_match, match_first, match_kind, match_last = -1;
627 int extra_nmatch;
628 int sb, ch;
629#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
630 re_match_context_t mctx = { .dfa = dfa };
631#else
632 re_match_context_t mctx;
633#endif
634 char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate
635 && range && !preg->can_be_null) ? preg->fastmap : NULL;
636 RE_TRANSLATE_TYPE t = preg->translate;
637
638#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
639 memset (&mctx, '\0', sizeof (re_match_context_t));
640 mctx.dfa = dfa;
641#endif
642
643 extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0;
644 nmatch -= extra_nmatch;
645
646 /* Check if the DFA haven't been compiled. */
647 if (BE (preg->used == 0 || dfa->init_state == NULL
648 || dfa->init_state_word == NULL || dfa->init_state_nl == NULL
649 || dfa->init_state_begbuf == NULL, 0))
650 return REG_NOMATCH;
651
652#ifdef DEBUG
653 /* We assume front-end functions already check them. */
654 assert (start + range >= 0 && start + range <= length);
655#endif
656
657 /* If initial states with non-begbuf contexts have no elements,
658 the regex must be anchored. If preg->newline_anchor is set,
659 we'll never use init_state_nl, so do not check it. */
660 if (dfa->init_state->nodes.nelem == 0
661 && dfa->init_state_word->nodes.nelem == 0
662 && (dfa->init_state_nl->nodes.nelem == 0
663 || !preg->newline_anchor))
664 {
665 if (start != 0 && start + range != 0)
666 return REG_NOMATCH;
667 start = range = 0;
668 }
669
670 /* We must check the longest matching, if nmatch > 0. */
671 fl_longest_match = (nmatch != 0 || dfa->nbackref);
672
673 err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1,
674 preg->translate, preg->syntax & RE_ICASE, dfa);
675 if (BE (err != REG_NOERROR, 0))
676 goto free_return;
677 mctx.input.stop = stop;
678 mctx.input.raw_stop = stop;
679 mctx.input.newline_anchor = preg->newline_anchor;
680
681 err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2);
682 if (BE (err != REG_NOERROR, 0))
683 goto free_return;
684
685 /* We will log all the DFA states through which the dfa pass,
686 if nmatch > 1, or this dfa has "multibyte node", which is a
687 back-reference or a node which can accept multibyte character or
688 multi character collating element. */
689 if (nmatch > 1 || dfa->has_mb_node)
690 {
691 /* Avoid overflow. */
692 if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= mctx.input.bufs_len, 0))
693 {
694 err = REG_ESPACE;
695 goto free_return;
696 }
697
698 mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1);
699 if (BE (mctx.state_log == NULL, 0))
700 {
701 err = REG_ESPACE;
702 goto free_return;
703 }
704 }
705 else
706 mctx.state_log = NULL;
707
708 match_first = start;
709 mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
710 : CONTEXT_NEWLINE | CONTEXT_BEGBUF;
711
712 /* Check incrementally whether of not the input string match. */
713 incr = (range < 0) ? -1 : 1;
714 left_lim = (range < 0) ? start + range : start;
715 right_lim = (range < 0) ? start : start + range;
716 sb = dfa->mb_cur_max == 1;
717 match_kind =
718 (fastmap
719 ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
720 | (range >= 0 ? 2 : 0)
721 | (t != NULL ? 1 : 0))
722 : 8);
723
724 for (;; match_first += incr)
725 {
726 err = REG_NOMATCH;
727 if (match_first < left_lim || right_lim < match_first)
728 goto free_return;
729
730 /* Advance as rapidly as possible through the string, until we
731 find a plausible place to start matching. This may be done
732 with varying efficiency, so there are various possibilities:
733 only the most common of them are specialized, in order to
734 save on code size. We use a switch statement for speed. */
735 switch (match_kind)
736 {
737 case 8:
738 /* No fastmap. */
739 break;
740
741 case 7:
742 /* Fastmap with single-byte translation, match forward. */
743 while (BE (match_first < right_lim, 1)
744 && !fastmap[t[(unsigned char) string[match_first]]])
745 ++match_first;
746 goto forward_match_found_start_or_reached_end;
747
748 case 6:
749 /* Fastmap without translation, match forward. */
750 while (BE (match_first < right_lim, 1)
751 && !fastmap[(unsigned char) string[match_first]])
752 ++match_first;
753
754 forward_match_found_start_or_reached_end:
755 if (BE (match_first == right_lim, 0))
756 {
757 ch = match_first >= length
758 ? 0 : (unsigned char) string[match_first];
759 if (!fastmap[t ? t[ch] : ch])
760 goto free_return;
761 }
762 break;
763
764 case 4:
765 case 5:
766 /* Fastmap without multi-byte translation, match backwards. */
767 while (match_first >= left_lim)
768 {
769 ch = match_first >= length
770 ? 0 : (unsigned char) string[match_first];
771 if (fastmap[t ? t[ch] : ch])
772 break;
773 --match_first;
774 }
775 if (match_first < left_lim)
776 goto free_return;
777 break;
778
779 default:
780 /* In this case, we can't determine easily the current byte,
781 since it might be a component byte of a multibyte
782 character. Then we use the constructed buffer instead. */
783 for (;;)
784 {
785 /* If MATCH_FIRST is out of the valid range, reconstruct the
786 buffers. */
787 unsigned int offset = match_first - mctx.input.raw_mbs_idx;
788 if (BE (offset >= (unsigned int) mctx.input.valid_raw_len, 0))
789 {
790 err = re_string_reconstruct (&mctx.input, match_first,
791 eflags);
792 if (BE (err != REG_NOERROR, 0))
793 goto free_return;
794
795 offset = match_first - mctx.input.raw_mbs_idx;
796 }
797 /* If MATCH_FIRST is out of the buffer, leave it as '\0'.
798 Note that MATCH_FIRST must not be smaller than 0. */
799 ch = (match_first >= length
800 ? 0 : re_string_byte_at (&mctx.input, offset));
801 if (fastmap[ch])
802 break;
803 match_first += incr;
804 if (match_first < left_lim || match_first > right_lim)
805 {
806 err = REG_NOMATCH;
807 goto free_return;
808 }
809 }
810 break;
811 }
812
813 /* Reconstruct the buffers so that the matcher can assume that
814 the matching starts from the beginning of the buffer. */
815 err = re_string_reconstruct (&mctx.input, match_first, eflags);
816 if (BE (err != REG_NOERROR, 0))
817 goto free_return;
818
819#ifdef RE_ENABLE_I18N
820 /* Don't consider this char as a possible match start if it part,
821 yet isn't the head, of a multibyte character. */
822 if (!sb && !re_string_first_byte (&mctx.input, 0))
823 continue;
824#endif
825
826 /* It seems to be appropriate one, then use the matcher. */
827 /* We assume that the matching starts from 0. */
828 mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0;
829 match_last = check_matching (&mctx, fl_longest_match,
830 range >= 0 ? &match_first : NULL);
831 if (match_last != -1)
832 {
833 if (BE (match_last == -2, 0))
834 {
835 err = REG_ESPACE;
836 goto free_return;
837 }
838 else
839 {
840 mctx.match_last = match_last;
841 if ((!preg->no_sub && nmatch > 1) || dfa->nbackref)
842 {
843 re_dfastate_t *pstate = mctx.state_log[match_last];
844 mctx.last_node = check_halt_state_context (&mctx, pstate,
845 match_last);
846 }
847 if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match)
848 || dfa->nbackref)
849 {
850 err = prune_impossible_nodes (&mctx);
851 if (err == REG_NOERROR)
852 break;
853 if (BE (err != REG_NOMATCH, 0))
854 goto free_return;
855 match_last = -1;
856 }
857 else
858 break; /* We found a match. */
859 }
860 }
861
862 match_ctx_clean (&mctx);
863 }
864
865#ifdef DEBUG
866 assert (match_last != -1);
867 assert (err == REG_NOERROR);
868#endif
869
870 /* Set pmatch[] if we need. */
871 if (nmatch > 0)
872 {
873 int reg_idx;
874
875 /* Initialize registers. */
876 for (reg_idx = 1; reg_idx < nmatch; ++reg_idx)
877 pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1;
878
879 /* Set the points where matching start/end. */
880 pmatch[0].rm_so = 0;
881 pmatch[0].rm_eo = mctx.match_last;
882
883 if (!preg->no_sub && nmatch > 1)
884 {
885 err = set_regs (preg, &mctx, nmatch, pmatch,
886 dfa->has_plural_match && dfa->nbackref > 0);
887 if (BE (err != REG_NOERROR, 0))
888 goto free_return;
889 }
890
891 /* At last, add the offset to the each registers, since we slided
892 the buffers so that we could assume that the matching starts
893 from 0. */
894 for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
895 if (pmatch[reg_idx].rm_so != -1)
896 {
897#ifdef RE_ENABLE_I18N
898 if (BE (mctx.input.offsets_needed != 0, 0))
899 {
900 pmatch[reg_idx].rm_so =
901 (pmatch[reg_idx].rm_so == mctx.input.valid_len
902 ? mctx.input.valid_raw_len
903 : mctx.input.offsets[pmatch[reg_idx].rm_so]);
904 pmatch[reg_idx].rm_eo =
905 (pmatch[reg_idx].rm_eo == mctx.input.valid_len
906 ? mctx.input.valid_raw_len
907 : mctx.input.offsets[pmatch[reg_idx].rm_eo]);
908 }
909#else
910 assert (mctx.input.offsets_needed == 0);
911#endif
912 pmatch[reg_idx].rm_so += match_first;
913 pmatch[reg_idx].rm_eo += match_first;
914 }
915 for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx)
916 {
917 pmatch[nmatch + reg_idx].rm_so = -1;
918 pmatch[nmatch + reg_idx].rm_eo = -1;
919 }
920
921 if (dfa->subexp_map)
922 for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++)
923 if (dfa->subexp_map[reg_idx] != reg_idx)
924 {
925 pmatch[reg_idx + 1].rm_so
926 = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so;
927 pmatch[reg_idx + 1].rm_eo
928 = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo;
929 }
930 }
931
932 free_return:
933 re_free (mctx.state_log);
934 if (dfa->nbackref)
935 match_ctx_free (&mctx);
936 re_string_destruct (&mctx.input);
937 return err;
938}
939
940static reg_errcode_t
941prune_impossible_nodes (re_match_context_t *mctx)
942{
943 const re_dfa_t *const dfa = mctx->dfa;
944 int halt_node, match_last;
945 reg_errcode_t ret;
946 re_dfastate_t **sifted_states;
947 re_dfastate_t **lim_states = NULL;
948 re_sift_context_t sctx;
949#ifdef DEBUG
950 assert (mctx->state_log != NULL);
951#endif
952 match_last = mctx->match_last;
953 halt_node = mctx->last_node;
954
955 /* Avoid overflow. */
956 if (BE (SIZE_MAX / sizeof (re_dfastate_t *) <= match_last, 0))
957 return REG_ESPACE;
958
959 sifted_states = re_malloc (re_dfastate_t *, match_last + 1);
960 if (BE (sifted_states == NULL, 0))
961 {
962 ret = REG_ESPACE;
963 goto free_return;
964 }
965 if (dfa->nbackref)
966 {
967 lim_states = re_malloc (re_dfastate_t *, match_last + 1);
968 if (BE (lim_states == NULL, 0))
969 {
970 ret = REG_ESPACE;
971 goto free_return;
972 }
973 while (1)
974 {
975 memset (lim_states, '\0',
976 sizeof (re_dfastate_t *) * (match_last + 1));
977 sift_ctx_init (&sctx, sifted_states, lim_states, halt_node,
978 match_last);
979 ret = sift_states_backward (mctx, &sctx);
980 re_node_set_free (&sctx.limits);
981 if (BE (ret != REG_NOERROR, 0))
982 goto free_return;
983 if (sifted_states[0] != NULL || lim_states[0] != NULL)
984 break;
985 do
986 {
987 --match_last;
988 if (match_last < 0)
989 {
990 ret = REG_NOMATCH;
991 goto free_return;
992 }
993 } while (mctx->state_log[match_last] == NULL
994 || !mctx->state_log[match_last]->halt);
995 halt_node = check_halt_state_context (mctx,
996 mctx->state_log[match_last],
997 match_last);
998 }
999 ret = merge_state_array (dfa, sifted_states, lim_states,
1000 match_last + 1);
1001 re_free (lim_states);
1002 lim_states = NULL;
1003 if (BE (ret != REG_NOERROR, 0))
1004 goto free_return;
1005 }
1006 else
1007 {
1008 sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last);
1009 ret = sift_states_backward (mctx, &sctx);
1010 re_node_set_free (&sctx.limits);
1011 if (BE (ret != REG_NOERROR, 0))
1012 goto free_return;
1013 if (sifted_states[0] == NULL)
1014 {
1015 ret = REG_NOMATCH;
1016 goto free_return;
1017 }
1018 }
1019 re_free (mctx->state_log);
1020 mctx->state_log = sifted_states;
1021 sifted_states = NULL;
1022 mctx->last_node = halt_node;
1023 mctx->match_last = match_last;
1024 ret = REG_NOERROR;
1025 free_return:
1026 re_free (sifted_states);
1027 re_free (lim_states);
1028 return ret;
1029}
1030
1031/* Acquire an initial state and return it.
1032 We must select appropriate initial state depending on the context,
1033 since initial states may have constraints like "\<", "^", etc.. */
1034
1035static inline re_dfastate_t *
1036__attribute ((always_inline)) internal_function
1037acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx,
1038 int idx)
1039{
1040 const re_dfa_t *const dfa = mctx->dfa;
1041 if (dfa->init_state->has_constraint)
1042 {
1043 unsigned int context;
1044 context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags);
1045 if (IS_WORD_CONTEXT (context))
1046 return dfa->init_state_word;
1047 else if (IS_ORDINARY_CONTEXT (context))
1048 return dfa->init_state;
1049 else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context))
1050 return dfa->init_state_begbuf;
1051 else if (IS_NEWLINE_CONTEXT (context))
1052 return dfa->init_state_nl;
1053 else if (IS_BEGBUF_CONTEXT (context))
1054 {
1055 /* It is relatively rare case, then calculate on demand. */
1056 return re_acquire_state_context (err, dfa,
1057 dfa->init_state->entrance_nodes,
1058 context);
1059 }
1060 else
1061 /* Must not happen? */
1062 return dfa->init_state;
1063 }
1064 else
1065 return dfa->init_state;
1066}
1067
1068/* Check whether the regular expression match input string INPUT or not,
1069 and return the index where the matching end, return -1 if not match,
1070 or return -2 in case of an error.
1071 FL_LONGEST_MATCH means we want the POSIX longest matching.
1072 If P_MATCH_FIRST is not NULL, and the match fails, it is set to the
1073 next place where we may want to try matching.
1074 Note that the matcher assume that the matching starts from the current
1075 index of the buffer. */
1076
1077static int
1078internal_function
1079check_matching (re_match_context_t *mctx, int fl_longest_match,
1080 int *p_match_first)
1081{
1082 const re_dfa_t *const dfa = mctx->dfa;
1083 reg_errcode_t err;
1084 int match = 0;
1085 int match_last = -1;
1086 int cur_str_idx = re_string_cur_idx (&mctx->input);
1087 re_dfastate_t *cur_state;
1088 int at_init_state = p_match_first != NULL;
1089 int next_start_idx = cur_str_idx;
1090
1091 err = REG_NOERROR;
1092 cur_state = acquire_init_state_context (&err, mctx, cur_str_idx);
1093 /* An initial state must not be NULL (invalid). */
1094 if (BE (cur_state == NULL, 0))
1095 {
1096 assert (err == REG_ESPACE);
1097 return -2;
1098 }
1099
1100 if (mctx->state_log != NULL)
1101 {
1102 mctx->state_log[cur_str_idx] = cur_state;
1103
1104 /* Check OP_OPEN_SUBEXP in the initial state in case that we use them
1105 later. E.g. Processing back references. */
1106 if (BE (dfa->nbackref, 0))
1107 {
1108 at_init_state = 0;
1109 err = check_subexp_matching_top (mctx, &cur_state->nodes, 0);
1110 if (BE (err != REG_NOERROR, 0))
1111 return err;
1112
1113 if (cur_state->has_backref)
1114 {
1115 err = transit_state_bkref (mctx, &cur_state->nodes);
1116 if (BE (err != REG_NOERROR, 0))
1117 return err;
1118 }
1119 }
1120 }
1121
1122 /* If the RE accepts NULL string. */
1123 if (BE (cur_state->halt, 0))
1124 {
1125 if (!cur_state->has_constraint
1126 || check_halt_state_context (mctx, cur_state, cur_str_idx))
1127 {
1128 if (!fl_longest_match)
1129 return cur_str_idx;
1130 else
1131 {
1132 match_last = cur_str_idx;
1133 match = 1;
1134 }
1135 }
1136 }
1137
1138 while (!re_string_eoi (&mctx->input))
1139 {
1140 re_dfastate_t *old_state = cur_state;
1141 int next_char_idx = re_string_cur_idx (&mctx->input) + 1;
1142
1143 if (BE (next_char_idx >= mctx->input.bufs_len, 0)
1144 || (BE (next_char_idx >= mctx->input.valid_len, 0)
1145 && mctx->input.valid_len < mctx->input.len))
1146 {
1147 err = extend_buffers (mctx);
1148 if (BE (err != REG_NOERROR, 0))
1149 {
1150 assert (err == REG_ESPACE);
1151 return -2;
1152 }
1153 }
1154
1155 cur_state = transit_state (&err, mctx, cur_state);
1156 if (mctx->state_log != NULL)
1157 cur_state = merge_state_with_log (&err, mctx, cur_state);
1158
1159 if (cur_state == NULL)
1160 {
1161 /* Reached the invalid state or an error. Try to recover a valid
1162 state using the state log, if available and if we have not
1163 already found a valid (even if not the longest) match. */
1164 if (BE (err != REG_NOERROR, 0))
1165 return -2;
1166
1167 if (mctx->state_log == NULL
1168 || (match && !fl_longest_match)
1169 || (cur_state = find_recover_state (&err, mctx)) == NULL)
1170 break;
1171 }
1172
1173 if (BE (at_init_state, 0))
1174 {
1175 if (old_state == cur_state)
1176 next_start_idx = next_char_idx;
1177 else
1178 at_init_state = 0;
1179 }
1180
1181 if (cur_state->halt)
1182 {
1183 /* Reached a halt state.
1184 Check the halt state can satisfy the current context. */
1185 if (!cur_state->has_constraint
1186 || check_halt_state_context (mctx, cur_state,
1187 re_string_cur_idx (&mctx->input)))
1188 {
1189 /* We found an appropriate halt state. */
1190 match_last = re_string_cur_idx (&mctx->input);
1191 match = 1;
1192
1193 /* We found a match, do not modify match_first below. */
1194 p_match_first = NULL;
1195 if (!fl_longest_match)
1196 break;
1197 }
1198 }
1199 }
1200
1201 if (p_match_first)
1202 *p_match_first += next_start_idx;
1203
1204 return match_last;
1205}
1206
1207/* Check NODE match the current context. */
1208
1209static int
1210internal_function
1211check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context)
1212{
1213 re_token_type_t type = dfa->nodes[node].type;
1214 unsigned int constraint = dfa->nodes[node].constraint;
1215 if (type != END_OF_RE)
1216 return 0;
1217 if (!constraint)
1218 return 1;
1219 if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context))
1220 return 0;
1221 return 1;
1222}
1223
1224/* Check the halt state STATE match the current context.
1225 Return 0 if not match, if the node, STATE has, is a halt node and
1226 match the context, return the node. */
1227
1228static int
1229internal_function
1230check_halt_state_context (const re_match_context_t *mctx,
1231 const re_dfastate_t *state, int idx)
1232{
1233 int i;
1234 unsigned int context;
1235#ifdef DEBUG
1236 assert (state->halt);
1237#endif
1238 context = re_string_context_at (&mctx->input, idx, mctx->eflags);
1239 for (i = 0; i < state->nodes.nelem; ++i)
1240 if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context))
1241 return state->nodes.elems[i];
1242 return 0;
1243}
1244
1245/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA
1246 corresponding to the DFA).
1247 Return the destination node, and update EPS_VIA_NODES, return -1 in case
1248 of errors. */
1249
1250static int
1251internal_function
1252proceed_next_node (const re_match_context_t *mctx, int nregs, regmatch_t *regs,
1253 int *pidx, int node, re_node_set *eps_via_nodes,
1254 struct re_fail_stack_t *fs)
1255{
1256 const re_dfa_t *const dfa = mctx->dfa;
1257 int i, err;
1258 if (IS_EPSILON_NODE (dfa->nodes[node].type))
1259 {
1260 re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes;
1261 re_node_set *edests = &dfa->edests[node];
1262 int dest_node;
1263 err = re_node_set_insert (eps_via_nodes, node);
1264 if (BE (err < 0, 0))
1265 return -2;
1266 /* Pick up a valid destination, or return -1 if none is found. */
1267 for (dest_node = -1, i = 0; i < edests->nelem; ++i)
1268 {
1269 int candidate = edests->elems[i];
1270 if (!re_node_set_contains (cur_nodes, candidate))
1271 continue;
1272 if (dest_node == -1)
1273 dest_node = candidate;
1274
1275 else
1276 {
1277 /* In order to avoid infinite loop like "(a*)*", return the second
1278 epsilon-transition if the first was already considered. */
1279 if (re_node_set_contains (eps_via_nodes, dest_node))
1280 return candidate;
1281
1282 /* Otherwise, push the second epsilon-transition on the fail stack. */
1283 else if (fs != NULL
1284 && push_fail_stack (fs, *pidx, candidate, nregs, regs,
1285 eps_via_nodes))
1286 return -2;
1287
1288 /* We know we are going to exit. */
1289 break;
1290 }
1291 }
1292 return dest_node;
1293 }
1294 else
1295 {
1296 int naccepted = 0;
1297 re_token_type_t type = dfa->nodes[node].type;
1298
1299#ifdef RE_ENABLE_I18N
1300 if (dfa->nodes[node].accept_mb)
1301 naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx);
1302 else
1303#endif /* RE_ENABLE_I18N */
1304 if (type == OP_BACK_REF)
1305 {
1306 int subexp_idx = dfa->nodes[node].opr.idx + 1;
1307 naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so;
1308 if (fs != NULL)
1309 {
1310 if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1)
1311 return -1;
1312 else if (naccepted)
1313 {
1314 char *buf = (char *) re_string_get_buffer (&mctx->input);
1315 if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
1316 naccepted) != 0)
1317 return -1;
1318 }
1319 }
1320
1321 if (naccepted == 0)
1322 {
1323 int dest_node;
1324 err = re_node_set_insert (eps_via_nodes, node);
1325 if (BE (err < 0, 0))
1326 return -2;
1327 dest_node = dfa->edests[node].elems[0];
1328 if (re_node_set_contains (&mctx->state_log[*pidx]->nodes,
1329 dest_node))
1330 return dest_node;
1331 }
1332 }
1333
1334 if (naccepted != 0
1335 || check_node_accept (mctx, dfa->nodes + node, *pidx))
1336 {
1337 int dest_node = dfa->nexts[node];
1338 *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted;
1339 if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL
1340 || !re_node_set_contains (&mctx->state_log[*pidx]->nodes,
1341 dest_node)))
1342 return -1;
1343 re_node_set_empty (eps_via_nodes);
1344 return dest_node;
1345 }
1346 }
1347 return -1;
1348}
1349
1350static reg_errcode_t
1351internal_function
1352push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node,
1353 int nregs, regmatch_t *regs, re_node_set *eps_via_nodes)
1354{
1355 reg_errcode_t err;
1356 int num = fs->num++;
1357 if (fs->num == fs->alloc)
1358 {
1359 struct re_fail_stack_ent_t *new_array;
1360 new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t)
1361 * fs->alloc * 2));
1362 if (new_array == NULL)
1363 return REG_ESPACE;
1364 fs->alloc *= 2;
1365 fs->stack = new_array;
1366 }
1367 fs->stack[num].idx = str_idx;
1368 fs->stack[num].node = dest_node;
1369 fs->stack[num].regs = re_malloc (regmatch_t, nregs);
1370 if (fs->stack[num].regs == NULL)
1371 return REG_ESPACE;
1372 memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs);
1373 err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes);
1374 return err;
1375}
1376
1377static int
1378internal_function
1379pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs,
1380 regmatch_t *regs, re_node_set *eps_via_nodes)
1381{
1382 int num = --fs->num;
1383 assert (num >= 0);
1384 *pidx = fs->stack[num].idx;
1385 memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs);
1386 re_node_set_free (eps_via_nodes);
1387 re_free (fs->stack[num].regs);
1388 *eps_via_nodes = fs->stack[num].eps_via_nodes;
1389 return fs->stack[num].node;
1390}
1391
1392/* Set the positions where the subexpressions are starts/ends to registers
1393 PMATCH.
1394 Note: We assume that pmatch[0] is already set, and
1395 pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */
1396
1397static reg_errcode_t
1398internal_function
1399set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
1400 regmatch_t *pmatch, int fl_backtrack)
1401{
1402 const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
1403 int idx, cur_node;
1404 re_node_set eps_via_nodes;
1405 struct re_fail_stack_t *fs;
1406 struct re_fail_stack_t fs_body = { 0, 2, NULL };
1407 regmatch_t *prev_idx_match;
1408 int prev_idx_match_malloced = 0;
1409
1410#ifdef DEBUG
1411 assert (nmatch > 1);
1412 assert (mctx->state_log != NULL);
1413#endif
1414 if (fl_backtrack)
1415 {
1416 fs = &fs_body;
1417 fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc);
1418 if (fs->stack == NULL)
1419 return REG_ESPACE;
1420 }
1421 else
1422 fs = NULL;
1423
1424 cur_node = dfa->init_node;
1425 re_node_set_init_empty (&eps_via_nodes);
1426
1427#ifdef HAVE_ALLOCA
1428 if (__libc_use_alloca (nmatch * sizeof (regmatch_t)))
1429 prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t));
1430 else
1431#endif
1432 {
1433 prev_idx_match = re_malloc (regmatch_t, nmatch);
1434 if (prev_idx_match == NULL)
1435 {
1436 free_fail_stack_return (fs);
1437 return REG_ESPACE;
1438 }
1439 prev_idx_match_malloced = 1;
1440 }
1441 memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
1442
1443 for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
1444 {
1445 update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
1446
1447 if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
1448 {
1449 int reg_idx;
1450 if (fs)
1451 {
1452 for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
1453 if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1)
1454 break;
1455 if (reg_idx == nmatch)
1456 {
1457 re_node_set_free (&eps_via_nodes);
1458 if (prev_idx_match_malloced)
1459 re_free (prev_idx_match);
1460 return free_fail_stack_return (fs);
1461 }
1462 cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
1463 &eps_via_nodes);
1464 }
1465 else
1466 {
1467 re_node_set_free (&eps_via_nodes);
1468 if (prev_idx_match_malloced)
1469 re_free (prev_idx_match);
1470 return REG_NOERROR;
1471 }
1472 }
1473
1474 /* Proceed to next node. */
1475 cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node,
1476 &eps_via_nodes, fs);
1477
1478 if (BE (cur_node < 0, 0))
1479 {
1480 if (BE (cur_node == -2, 0))
1481 {
1482 re_node_set_free (&eps_via_nodes);
1483 if (prev_idx_match_malloced)
1484 re_free (prev_idx_match);
1485 free_fail_stack_return (fs);
1486 return REG_ESPACE;
1487 }
1488 if (fs)
1489 cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
1490 &eps_via_nodes);
1491 else
1492 {
1493 re_node_set_free (&eps_via_nodes);
1494 if (prev_idx_match_malloced)
1495 re_free (prev_idx_match);
1496 return REG_NOMATCH;
1497 }
1498 }
1499 }
1500 re_node_set_free (&eps_via_nodes);
1501 if (prev_idx_match_malloced)
1502 re_free (prev_idx_match);
1503 return free_fail_stack_return (fs);
1504}
1505
1506static reg_errcode_t
1507internal_function
1508free_fail_stack_return (struct re_fail_stack_t *fs)
1509{
1510 if (fs)
1511 {
1512 int fs_idx;
1513 for (fs_idx = 0; fs_idx < fs->num; ++fs_idx)
1514 {
1515 re_node_set_free (&fs->stack[fs_idx].eps_via_nodes);
1516 re_free (fs->stack[fs_idx].regs);
1517 }
1518 re_free (fs->stack);
1519 }
1520 return REG_NOERROR;
1521}
1522
1523static void
1524internal_function
1525update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
1526 regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch)
1527{
1528 int type = dfa->nodes[cur_node].type;
1529 if (type == OP_OPEN_SUBEXP)
1530 {
1531 int reg_num = dfa->nodes[cur_node].opr.idx + 1;
1532
1533 /* We are at the first node of this sub expression. */
1534 if (reg_num < nmatch)
1535 {
1536 pmatch[reg_num].rm_so = cur_idx;
1537 pmatch[reg_num].rm_eo = -1;
1538 }
1539 }
1540 else if (type == OP_CLOSE_SUBEXP)
1541 {
1542 int reg_num = dfa->nodes[cur_node].opr.idx + 1;
1543 if (reg_num < nmatch)
1544 {
1545 /* We are at the last node of this sub expression. */
1546 if (pmatch[reg_num].rm_so < cur_idx)
1547 {
1548 pmatch[reg_num].rm_eo = cur_idx;
1549 /* This is a non-empty match or we are not inside an optional
1550 subexpression. Accept this right away. */
1551 memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
1552 }
1553 else
1554 {
1555 if (dfa->nodes[cur_node].opt_subexp
1556 && prev_idx_match[reg_num].rm_so != -1)
1557 /* We transited through an empty match for an optional
1558 subexpression, like (a?)*, and this is not the subexp's
1559 first match. Copy back the old content of the registers
1560 so that matches of an inner subexpression are undone as
1561 well, like in ((a?))*. */
1562 memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch);
1563 else
1564 /* We completed a subexpression, but it may be part of
1565 an optional one, so do not update PREV_IDX_MATCH. */
1566 pmatch[reg_num].rm_eo = cur_idx;
1567 }
1568 }
1569 }
1570}
1571
1572/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0
1573 and sift the nodes in each states according to the following rules.
1574 Updated state_log will be wrote to STATE_LOG.
1575
1576 Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if...
1577 1. When STR_IDX == MATCH_LAST(the last index in the state_log):
1578 If `a' isn't the LAST_NODE and `a' can't epsilon transit to
1579 the LAST_NODE, we throw away the node `a'.
1580 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts
1581 string `s' and transit to `b':
1582 i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw
1583 away the node `a'.
1584 ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is
1585 thrown away, we throw away the node `a'.
1586 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b':
1587 i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the
1588 node `a'.
1589 ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away,
1590 we throw away the node `a'. */
1591
1592#define STATE_NODE_CONTAINS(state,node) \
1593 ((state) != NULL && re_node_set_contains (&(state)->nodes, node))
1594
1595static reg_errcode_t
1596internal_function
1597sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx)
1598{
1599 reg_errcode_t err;
1600 int null_cnt = 0;
1601 int str_idx = sctx->last_str_idx;
1602 re_node_set cur_dest;
1603
1604#ifdef DEBUG
1605 assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL);
1606#endif
1607
1608 /* Build sifted state_log[str_idx]. It has the nodes which can epsilon
1609 transit to the last_node and the last_node itself. */
1610 err = re_node_set_init_1 (&cur_dest, sctx->last_node);
1611 if (BE (err != REG_NOERROR, 0))
1612 return err;
1613 err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
1614 if (BE (err != REG_NOERROR, 0))
1615 goto free_return;
1616
1617 /* Then check each states in the state_log. */
1618 while (str_idx > 0)
1619 {
1620 /* Update counters. */
1621 null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0;
1622 if (null_cnt > mctx->max_mb_elem_len)
1623 {
1624 memset (sctx->sifted_states, '\0',
1625 sizeof (re_dfastate_t *) * str_idx);
1626 re_node_set_free (&cur_dest);
1627 return REG_NOERROR;
1628 }
1629 re_node_set_empty (&cur_dest);
1630 --str_idx;
1631
1632 if (mctx->state_log[str_idx])
1633 {
1634 err = build_sifted_states (mctx, sctx, str_idx, &cur_dest);
1635 if (BE (err != REG_NOERROR, 0))
1636 goto free_return;
1637 }
1638
1639 /* Add all the nodes which satisfy the following conditions:
1640 - It can epsilon transit to a node in CUR_DEST.
1641 - It is in CUR_SRC.
1642 And update state_log. */
1643 err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
1644 if (BE (err != REG_NOERROR, 0))
1645 goto free_return;
1646 }
1647 err = REG_NOERROR;
1648 free_return:
1649 re_node_set_free (&cur_dest);
1650 return err;
1651}
1652
1653static reg_errcode_t
1654internal_function
1655build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx,
1656 int str_idx, re_node_set *cur_dest)
1657{
1658 const re_dfa_t *const dfa = mctx->dfa;
1659 const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes;
1660 int i;
1661
1662 /* Then build the next sifted state.
1663 We build the next sifted state on `cur_dest', and update
1664 `sifted_states[str_idx]' with `cur_dest'.
1665 Note:
1666 `cur_dest' is the sifted state from `state_log[str_idx + 1]'.
1667 `cur_src' points the node_set of the old `state_log[str_idx]'
1668 (with the epsilon nodes pre-filtered out). */
1669 for (i = 0; i < cur_src->nelem; i++)
1670 {
1671 int prev_node = cur_src->elems[i];
1672 int naccepted = 0;
1673 int ret;
1674
1675#ifdef DEBUG
1676 re_token_type_t type = dfa->nodes[prev_node].type;
1677 assert (!IS_EPSILON_NODE (type));
1678#endif
1679#ifdef RE_ENABLE_I18N
1680 /* If the node may accept `multi byte'. */
1681 if (dfa->nodes[prev_node].accept_mb)
1682 naccepted = sift_states_iter_mb (mctx, sctx, prev_node,
1683 str_idx, sctx->last_str_idx);
1684#endif /* RE_ENABLE_I18N */
1685
1686 /* We don't check backreferences here.
1687 See update_cur_sifted_state(). */
1688 if (!naccepted
1689 && check_node_accept (mctx, dfa->nodes + prev_node, str_idx)
1690 && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1],
1691 dfa->nexts[prev_node]))
1692 naccepted = 1;
1693
1694 if (naccepted == 0)
1695 continue;
1696
1697 if (sctx->limits.nelem)
1698 {
1699 int to_idx = str_idx + naccepted;
1700 if (check_dst_limits (mctx, &sctx->limits,
1701 dfa->nexts[prev_node], to_idx,
1702 prev_node, str_idx))
1703 continue;
1704 }
1705 ret = re_node_set_insert (cur_dest, prev_node);
1706 if (BE (ret == -1, 0))
1707 return REG_ESPACE;
1708 }
1709
1710 return REG_NOERROR;
1711}
1712
1713/* Helper functions. */
1714
1715static reg_errcode_t
1716internal_function
1717clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx)
1718{
1719 int top = mctx->state_log_top;
1720
1721 if (next_state_log_idx >= mctx->input.bufs_len
1722 || (next_state_log_idx >= mctx->input.valid_len
1723 && mctx->input.valid_len < mctx->input.len))
1724 {
1725 reg_errcode_t err;
1726 err = extend_buffers (mctx);
1727 if (BE (err != REG_NOERROR, 0))
1728 return err;
1729 }
1730
1731 if (top < next_state_log_idx)
1732 {
1733 memset (mctx->state_log + top + 1, '\0',
1734 sizeof (re_dfastate_t *) * (next_state_log_idx - top));
1735 mctx->state_log_top = next_state_log_idx;
1736 }
1737 return REG_NOERROR;
1738}
1739
1740static reg_errcode_t
1741internal_function
1742merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst,
1743 re_dfastate_t **src, int num)
1744{
1745 int st_idx;
1746 reg_errcode_t err;
1747 for (st_idx = 0; st_idx < num; ++st_idx)
1748 {
1749 if (dst[st_idx] == NULL)
1750 dst[st_idx] = src[st_idx];
1751 else if (src[st_idx] != NULL)
1752 {
1753 re_node_set merged_set;
1754 err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes,
1755 &src[st_idx]->nodes);
1756 if (BE (err != REG_NOERROR, 0))
1757 return err;
1758 dst[st_idx] = re_acquire_state (&err, dfa, &merged_set);
1759 re_node_set_free (&merged_set);
1760 if (BE (err != REG_NOERROR, 0))
1761 return err;
1762 }
1763 }
1764 return REG_NOERROR;
1765}
1766
1767static reg_errcode_t
1768internal_function
1769update_cur_sifted_state (const re_match_context_t *mctx,
1770 re_sift_context_t *sctx, int str_idx,
1771 re_node_set *dest_nodes)
1772{
1773 const re_dfa_t *const dfa = mctx->dfa;
1774 reg_errcode_t err = REG_NOERROR;
1775 const re_node_set *candidates;
1776 candidates = ((mctx->state_log[str_idx] == NULL) ? NULL
1777 : &mctx->state_log[str_idx]->nodes);
1778
1779 if (dest_nodes->nelem == 0)
1780 sctx->sifted_states[str_idx] = NULL;
1781 else
1782 {
1783 if (candidates)
1784 {
1785 /* At first, add the nodes which can epsilon transit to a node in
1786 DEST_NODE. */
1787 err = add_epsilon_src_nodes (dfa, dest_nodes, candidates);
1788 if (BE (err != REG_NOERROR, 0))
1789 return err;
1790
1791 /* Then, check the limitations in the current sift_context. */
1792 if (sctx->limits.nelem)
1793 {
1794 err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits,
1795 mctx->bkref_ents, str_idx);
1796 if (BE (err != REG_NOERROR, 0))
1797 return err;
1798 }
1799 }
1800
1801 sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes);
1802 if (BE (err != REG_NOERROR, 0))
1803 return err;
1804 }
1805
1806 if (candidates && mctx->state_log[str_idx]->has_backref)
1807 {
1808 err = sift_states_bkref (mctx, sctx, str_idx, candidates);
1809 if (BE (err != REG_NOERROR, 0))
1810 return err;
1811 }
1812 return REG_NOERROR;
1813}
1814
1815static reg_errcode_t
1816internal_function
1817add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes,
1818 const re_node_set *candidates)
1819{
1820 reg_errcode_t err = REG_NOERROR;
1821 int i;
1822
1823 re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes);
1824 if (BE (err != REG_NOERROR, 0))
1825 return err;
1826
1827 if (!state->inveclosure.alloc)
1828 {
1829 err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem);
1830 if (BE (err != REG_NOERROR, 0))
1831 return REG_ESPACE;
1832 for (i = 0; i < dest_nodes->nelem; i++)
1833 {
1834 err = re_node_set_merge (&state->inveclosure,
1835 dfa->inveclosures + dest_nodes->elems[i]);
1836 if (BE (err != REG_NOERROR, 0))
1837 return REG_ESPACE;
1838 }
1839 }
1840 return re_node_set_add_intersect (dest_nodes, candidates,
1841 &state->inveclosure);
1842}
1843
1844static reg_errcode_t
1845internal_function
1846sub_epsilon_src_nodes (const re_dfa_t *dfa, int node, re_node_set *dest_nodes,
1847 const re_node_set *candidates)
1848{
1849 int ecl_idx;
1850 reg_errcode_t err;
1851 re_node_set *inv_eclosure = dfa->inveclosures + node;
1852 re_node_set except_nodes;
1853 re_node_set_init_empty (&except_nodes);
1854 for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
1855 {
1856 int cur_node = inv_eclosure->elems[ecl_idx];
1857 if (cur_node == node)
1858 continue;
1859 if (IS_EPSILON_NODE (dfa->nodes[cur_node].type))
1860 {
1861 int edst1 = dfa->edests[cur_node].elems[0];
1862 int edst2 = ((dfa->edests[cur_node].nelem > 1)
1863 ? dfa->edests[cur_node].elems[1] : -1);
1864 if ((!re_node_set_contains (inv_eclosure, edst1)
1865 && re_node_set_contains (dest_nodes, edst1))
1866 || (edst2 > 0
1867 && !re_node_set_contains (inv_eclosure, edst2)
1868 && re_node_set_contains (dest_nodes, edst2)))
1869 {
1870 err = re_node_set_add_intersect (&except_nodes, candidates,
1871 dfa->inveclosures + cur_node);
1872 if (BE (err != REG_NOERROR, 0))
1873 {
1874 re_node_set_free (&except_nodes);
1875 return err;
1876 }
1877 }
1878 }
1879 }
1880 for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
1881 {
1882 int cur_node = inv_eclosure->elems[ecl_idx];
1883 if (!re_node_set_contains (&except_nodes, cur_node))
1884 {
1885 int idx = re_node_set_contains (dest_nodes, cur_node) - 1;
1886 re_node_set_remove_at (dest_nodes, idx);
1887 }
1888 }
1889 re_node_set_free (&except_nodes);
1890 return REG_NOERROR;
1891}
1892
1893static int
1894internal_function
1895check_dst_limits (const re_match_context_t *mctx, re_node_set *limits,
1896 int dst_node, int dst_idx, int src_node, int src_idx)
1897{
1898 const re_dfa_t *const dfa = mctx->dfa;
1899 int lim_idx, src_pos, dst_pos;
1900
1901 int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx);
1902 int src_bkref_idx = search_cur_bkref_entry (mctx, src_idx);
1903 for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
1904 {
1905 int subexp_idx;
1906 struct re_backref_cache_entry *ent;
1907 ent = mctx->bkref_ents + limits->elems[lim_idx];
1908 subexp_idx = dfa->nodes[ent->node].opr.idx;
1909
1910 dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
1911 subexp_idx, dst_node, dst_idx,
1912 dst_bkref_idx);
1913 src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
1914 subexp_idx, src_node, src_idx,
1915 src_bkref_idx);
1916
1917 /* In case of:
1918 <src> <dst> ( <subexp> )
1919 ( <subexp> ) <src> <dst>
1920 ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */
1921 if (src_pos == dst_pos)
1922 continue; /* This is unrelated limitation. */
1923 else
1924 return 1;
1925 }
1926 return 0;
1927}
1928
1929static int
1930internal_function
1931check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries,
1932 int subexp_idx, int from_node, int bkref_idx)
1933{
1934 const re_dfa_t *const dfa = mctx->dfa;
1935 const re_node_set *eclosures = dfa->eclosures + from_node;
1936 int node_idx;
1937
1938 /* Else, we are on the boundary: examine the nodes on the epsilon
1939 closure. */
1940 for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx)
1941 {
1942 int node = eclosures->elems[node_idx];
1943 switch (dfa->nodes[node].type)
1944 {
1945 case OP_BACK_REF:
1946 if (bkref_idx != -1)
1947 {
1948 struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx;
1949 do
1950 {
1951 int dst, cpos;
1952
1953 if (ent->node != node)
1954 continue;
1955
1956 if (subexp_idx < BITSET_WORD_BITS
1957 && !(ent->eps_reachable_subexps_map
1958 & ((bitset_word_t) 1 << subexp_idx)))
1959 continue;
1960
1961 /* Recurse trying to reach the OP_OPEN_SUBEXP and
1962 OP_CLOSE_SUBEXP cases below. But, if the
1963 destination node is the same node as the source
1964 node, don't recurse because it would cause an
1965 infinite loop: a regex that exhibits this behavior
1966 is ()\1*\1* */
1967 dst = dfa->edests[node].elems[0];
1968 if (dst == from_node)
1969 {
1970 if (boundaries & 1)
1971 return -1;
1972 else /* if (boundaries & 2) */
1973 return 0;
1974 }
1975
1976 cpos =
1977 check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
1978 dst, bkref_idx);
1979 if (cpos == -1 /* && (boundaries & 1) */)
1980 return -1;
1981 if (cpos == 0 && (boundaries & 2))
1982 return 0;
1983
1984 if (subexp_idx < BITSET_WORD_BITS)
1985 ent->eps_reachable_subexps_map
1986 &= ~((bitset_word_t) 1 << subexp_idx);
1987 }
1988 while (ent++->more);
1989 }
1990 break;
1991
1992 case OP_OPEN_SUBEXP:
1993 if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx)
1994 return -1;
1995 break;
1996
1997 case OP_CLOSE_SUBEXP:
1998 if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx)
1999 return 0;
2000 break;
2001
2002 default:
2003 break;
2004 }
2005 }
2006
2007 return (boundaries & 2) ? 1 : 0;
2008}
2009
2010static int
2011internal_function
2012check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit,
2013 int subexp_idx, int from_node, int str_idx,
2014 int bkref_idx)
2015{
2016 struct re_backref_cache_entry *lim = mctx->bkref_ents + limit;
2017 int boundaries;
2018
2019 /* If we are outside the range of the subexpression, return -1 or 1. */
2020 if (str_idx < lim->subexp_from)
2021 return -1;
2022
2023 if (lim->subexp_to < str_idx)
2024 return 1;
2025
2026 /* If we are within the subexpression, return 0. */
2027 boundaries = (str_idx == lim->subexp_from);
2028 boundaries |= (str_idx == lim->subexp_to) << 1;
2029 if (boundaries == 0)
2030 return 0;
2031
2032 /* Else, examine epsilon closure. */
2033 return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
2034 from_node, bkref_idx);
2035}
2036
2037/* Check the limitations of sub expressions LIMITS, and remove the nodes
2038 which are against limitations from DEST_NODES. */
2039
2040static reg_errcode_t
2041internal_function
2042check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes,
2043 const re_node_set *candidates, re_node_set *limits,
2044 struct re_backref_cache_entry *bkref_ents, int str_idx)
2045{
2046 reg_errcode_t err;
2047 int node_idx, lim_idx;
2048
2049 for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
2050 {
2051 int subexp_idx;
2052 struct re_backref_cache_entry *ent;
2053 ent = bkref_ents + limits->elems[lim_idx];
2054
2055 if (str_idx <= ent->subexp_from || ent->str_idx < str_idx)
2056 continue; /* This is unrelated limitation. */
2057
2058 subexp_idx = dfa->nodes[ent->node].opr.idx;
2059 if (ent->subexp_to == str_idx)
2060 {
2061 int ops_node = -1;
2062 int cls_node = -1;
2063 for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
2064 {
2065 int node = dest_nodes->elems[node_idx];
2066 re_token_type_t type = dfa->nodes[node].type;
2067 if (type == OP_OPEN_SUBEXP
2068 && subexp_idx == dfa->nodes[node].opr.idx)
2069 ops_node = node;
2070 else if (type == OP_CLOSE_SUBEXP
2071 && subexp_idx == dfa->nodes[node].opr.idx)
2072 cls_node = node;
2073 }
2074
2075 /* Check the limitation of the open subexpression. */
2076 /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */
2077 if (ops_node >= 0)
2078 {
2079 err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes,
2080 candidates);
2081 if (BE (err != REG_NOERROR, 0))
2082 return err;
2083 }
2084
2085 /* Check the limitation of the close subexpression. */
2086 if (cls_node >= 0)
2087 for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
2088 {
2089 int node = dest_nodes->elems[node_idx];
2090 if (!re_node_set_contains (dfa->inveclosures + node,
2091 cls_node)
2092 && !re_node_set_contains (dfa->eclosures + node,
2093 cls_node))
2094 {
2095 /* It is against this limitation.
2096 Remove it form the current sifted state. */
2097 err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
2098 candidates);
2099 if (BE (err != REG_NOERROR, 0))
2100 return err;
2101 --node_idx;
2102 }
2103 }
2104 }
2105 else /* (ent->subexp_to != str_idx) */
2106 {
2107 for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
2108 {
2109 int node = dest_nodes->elems[node_idx];
2110 re_token_type_t type = dfa->nodes[node].type;
2111 if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP)
2112 {
2113 if (subexp_idx != dfa->nodes[node].opr.idx)
2114 continue;
2115 /* It is against this limitation.
2116 Remove it form the current sifted state. */
2117 err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
2118 candidates);
2119 if (BE (err != REG_NOERROR, 0))
2120 return err;
2121 }
2122 }
2123 }
2124 }
2125 return REG_NOERROR;
2126}
2127
2128static reg_errcode_t
2129internal_function
2130sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx,
2131 int str_idx, const re_node_set *candidates)
2132{
2133 const re_dfa_t *const dfa = mctx->dfa;
2134 reg_errcode_t err;
2135 int node_idx, node;
2136 re_sift_context_t local_sctx;
2137 int first_idx = search_cur_bkref_entry (mctx, str_idx);
2138
2139 if (first_idx == -1)
2140 return REG_NOERROR;
2141
2142 local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */
2143
2144 for (node_idx = 0; node_idx < candidates->nelem; ++node_idx)
2145 {
2146 int enabled_idx;
2147 re_token_type_t type;
2148 struct re_backref_cache_entry *entry;
2149 node = candidates->elems[node_idx];
2150 type = dfa->nodes[node].type;
2151 /* Avoid infinite loop for the REs like "()\1+". */
2152 if (node == sctx->last_node && str_idx == sctx->last_str_idx)
2153 continue;
2154 if (type != OP_BACK_REF)
2155 continue;
2156
2157 entry = mctx->bkref_ents + first_idx;
2158 enabled_idx = first_idx;
2159 do
2160 {
2161 int subexp_len;
2162 int to_idx;
2163 int dst_node;
2164 int ret;
2165 re_dfastate_t *cur_state;
2166
2167 if (entry->node != node)
2168 continue;
2169 subexp_len = entry->subexp_to - entry->subexp_from;
2170 to_idx = str_idx + subexp_len;
2171 dst_node = (subexp_len ? dfa->nexts[node]
2172 : dfa->edests[node].elems[0]);
2173
2174 if (to_idx > sctx->last_str_idx
2175 || sctx->sifted_states[to_idx] == NULL
2176 || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node)
2177 || check_dst_limits (mctx, &sctx->limits, node,
2178 str_idx, dst_node, to_idx))
2179 continue;
2180
2181 if (local_sctx.sifted_states == NULL)
2182 {
2183 local_sctx = *sctx;
2184 err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits);
2185 if (BE (err != REG_NOERROR, 0))
2186 goto free_return;
2187 }
2188 local_sctx.last_node = node;
2189 local_sctx.last_str_idx = str_idx;
2190 ret = re_node_set_insert (&local_sctx.limits, enabled_idx);
2191 if (BE (ret < 0, 0))
2192 {
2193 err = REG_ESPACE;
2194 goto free_return;
2195 }
2196 cur_state = local_sctx.sifted_states[str_idx];
2197 err = sift_states_backward (mctx, &local_sctx);
2198 if (BE (err != REG_NOERROR, 0))
2199 goto free_return;
2200 if (sctx->limited_states != NULL)
2201 {
2202 err = merge_state_array (dfa, sctx->limited_states,
2203 local_sctx.sifted_states,
2204 str_idx + 1);
2205 if (BE (err != REG_NOERROR, 0))
2206 goto free_return;
2207 }
2208 local_sctx.sifted_states[str_idx] = cur_state;
2209 re_node_set_remove (&local_sctx.limits, enabled_idx);
2210
2211 /* mctx->bkref_ents may have changed, reload the pointer. */
2212 entry = mctx->bkref_ents + enabled_idx;
2213 }
2214 while (enabled_idx++, entry++->more);
2215 }
2216 err = REG_NOERROR;
2217 free_return:
2218 if (local_sctx.sifted_states != NULL)
2219 {
2220 re_node_set_free (&local_sctx.limits);
2221 }
2222
2223 return err;
2224}
2225
2226
2227#ifdef RE_ENABLE_I18N
2228static int
2229internal_function
2230sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx,
2231 int node_idx, int str_idx, int max_str_idx)
2232{
2233 const re_dfa_t *const dfa = mctx->dfa;
2234 int naccepted;
2235 /* Check the node can accept `multi byte'. */
2236 naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx);
2237 if (naccepted > 0 && str_idx + naccepted <= max_str_idx &&
2238 !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted],
2239 dfa->nexts[node_idx]))
2240 /* The node can't accept the `multi byte', or the
2241 destination was already thrown away, then the node
2242 couldn't accept the current input `multi byte'. */
2243 naccepted = 0;
2244 /* Otherwise, it is sure that the node could accept
2245 `naccepted' bytes input. */
2246 return naccepted;
2247}
2248#endif /* RE_ENABLE_I18N */
2249
2250
2251/* Functions for state transition. */
2252
2253/* Return the next state to which the current state STATE will transit by
2254 accepting the current input byte, and update STATE_LOG if necessary.
2255 If STATE can accept a multibyte char/collating element/back reference
2256 update the destination of STATE_LOG. */
2257
2258static re_dfastate_t *
2259internal_function
2260transit_state (reg_errcode_t *err, re_match_context_t *mctx,
2261 re_dfastate_t *state)
2262{
2263 re_dfastate_t **trtable;
2264 unsigned char ch;
2265
2266#ifdef RE_ENABLE_I18N
2267 /* If the current state can accept multibyte. */
2268 if (BE (state->accept_mb, 0))
2269 {
2270 *err = transit_state_mb (mctx, state);
2271 if (BE (*err != REG_NOERROR, 0))
2272 return NULL;
2273 }
2274#endif /* RE_ENABLE_I18N */
2275
2276 /* Then decide the next state with the single byte. */
2277#if 0
2278 if (0)
2279 /* don't use transition table */
2280 return transit_state_sb (err, mctx, state);
2281#endif
2282
2283 /* Use transition table */
2284 ch = re_string_fetch_byte (&mctx->input);
2285 for (;;)
2286 {
2287 trtable = state->trtable;
2288 if (BE (trtable != NULL, 1))
2289 return trtable[ch];
2290
2291 trtable = state->word_trtable;
2292 if (BE (trtable != NULL, 1))
2293 {
2294 unsigned int context;
2295 context
2296 = re_string_context_at (&mctx->input,
2297 re_string_cur_idx (&mctx->input) - 1,
2298 mctx->eflags);
2299 if (IS_WORD_CONTEXT (context))
2300 return trtable[ch + SBC_MAX];
2301 else
2302 return trtable[ch];
2303 }
2304
2305 if (!build_trtable (mctx->dfa, state))
2306 {
2307 *err = REG_ESPACE;
2308 return NULL;
2309 }
2310
2311 /* Retry, we now have a transition table. */
2312 }
2313}
2314
2315/* Update the state_log if we need */
2316static re_dfastate_t *
2317internal_function
2318merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
2319 re_dfastate_t *next_state)
2320{
2321 const re_dfa_t *const dfa = mctx->dfa;
2322 int cur_idx = re_string_cur_idx (&mctx->input);
2323
2324 if (cur_idx > mctx->state_log_top)
2325 {
2326 mctx->state_log[cur_idx] = next_state;
2327 mctx->state_log_top = cur_idx;
2328 }
2329 else if (mctx->state_log[cur_idx] == NULL)
2330 {
2331 mctx->state_log[cur_idx] = next_state;
2332 }
2333 else
2334 {
2335 re_dfastate_t *pstate;
2336 unsigned int context;
2337 re_node_set next_nodes, *log_nodes, *table_nodes = NULL;
2338 /* If (state_log[cur_idx] != 0), it implies that cur_idx is
2339 the destination of a multibyte char/collating element/
2340 back reference. Then the next state is the union set of
2341 these destinations and the results of the transition table. */
2342 pstate = mctx->state_log[cur_idx];
2343 log_nodes = pstate->entrance_nodes;
2344 if (next_state != NULL)
2345 {
2346 table_nodes = next_state->entrance_nodes;
2347 *err = re_node_set_init_union (&next_nodes, table_nodes,
2348 log_nodes);
2349 if (BE (*err != REG_NOERROR, 0))
2350 return NULL;
2351 }
2352 else
2353 next_nodes = *log_nodes;
2354 /* Note: We already add the nodes of the initial state,
2355 then we don't need to add them here. */
2356
2357 context = re_string_context_at (&mctx->input,
2358 re_string_cur_idx (&mctx->input) - 1,
2359 mctx->eflags);
2360 next_state = mctx->state_log[cur_idx]
2361 = re_acquire_state_context (err, dfa, &next_nodes, context);
2362 /* We don't need to check errors here, since the return value of
2363 this function is next_state and ERR is already set. */
2364
2365 if (table_nodes != NULL)
2366 re_node_set_free (&next_nodes);
2367 }
2368
2369 if (BE (dfa->nbackref, 0) && next_state != NULL)
2370 {
2371 /* Check OP_OPEN_SUBEXP in the current state in case that we use them
2372 later. We must check them here, since the back references in the
2373 next state might use them. */
2374 *err = check_subexp_matching_top (mctx, &next_state->nodes,
2375 cur_idx);
2376 if (BE (*err != REG_NOERROR, 0))
2377 return NULL;
2378
2379 /* If the next state has back references. */
2380 if (next_state->has_backref)
2381 {
2382 *err = transit_state_bkref (mctx, &next_state->nodes);
2383 if (BE (*err != REG_NOERROR, 0))
2384 return NULL;
2385 next_state = mctx->state_log[cur_idx];
2386 }
2387 }
2388
2389 return next_state;
2390}
2391
2392/* Skip bytes in the input that correspond to part of a
2393 multi-byte match, then look in the log for a state
2394 from which to restart matching. */
2395static re_dfastate_t *
2396internal_function
2397find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
2398{
2399 re_dfastate_t *cur_state;
2400 do
2401 {
2402 int max = mctx->state_log_top;
2403 int cur_str_idx = re_string_cur_idx (&mctx->input);
2404
2405 do
2406 {
2407 if (++cur_str_idx > max)
2408 return NULL;
2409 re_string_skip_bytes (&mctx->input, 1);
2410 }
2411 while (mctx->state_log[cur_str_idx] == NULL);
2412
2413 cur_state = merge_state_with_log (err, mctx, NULL);
2414 }
2415 while (*err == REG_NOERROR && cur_state == NULL);
2416 return cur_state;
2417}
2418
2419/* Helper functions for transit_state. */
2420
2421/* From the node set CUR_NODES, pick up the nodes whose types are
2422 OP_OPEN_SUBEXP and which have corresponding back references in the regular
2423 expression. And register them to use them later for evaluating the
2424 correspoding back references. */
2425
2426static reg_errcode_t
2427internal_function
2428check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes,
2429 int str_idx)
2430{
2431 const re_dfa_t *const dfa = mctx->dfa;
2432 int node_idx;
2433 reg_errcode_t err;
2434
2435 /* TODO: This isn't efficient.
2436 Because there might be more than one nodes whose types are
2437 OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
2438 nodes.
2439 E.g. RE: (a){2} */
2440 for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx)
2441 {
2442 int node = cur_nodes->elems[node_idx];
2443 if (dfa->nodes[node].type == OP_OPEN_SUBEXP
2444 && dfa->nodes[node].opr.idx < BITSET_WORD_BITS
2445 && (dfa->used_bkref_map
2446 & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx)))
2447 {
2448 err = match_ctx_add_subtop (mctx, node, str_idx);
2449 if (BE (err != REG_NOERROR, 0))
2450 return err;
2451 }
2452 }
2453 return REG_NOERROR;
2454}
2455
2456#if 0
2457/* Return the next state to which the current state STATE will transit by
2458 accepting the current input byte. */
2459
2460static re_dfastate_t *
2461transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx,
2462 re_dfastate_t *state)
2463{
2464 const re_dfa_t *const dfa = mctx->dfa;
2465 re_node_set next_nodes;
2466 re_dfastate_t *next_state;
2467 int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input);
2468 unsigned int context;
2469
2470 *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1);
2471 if (BE (*err != REG_NOERROR, 0))
2472 return NULL;
2473 for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt)
2474 {
2475 int cur_node = state->nodes.elems[node_cnt];
2476 if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx))
2477 {
2478 *err = re_node_set_merge (&next_nodes,
2479 dfa->eclosures + dfa->nexts[cur_node]);
2480 if (BE (*err != REG_NOERROR, 0))
2481 {
2482 re_node_set_free (&next_nodes);
2483 return NULL;
2484 }
2485 }
2486 }
2487 context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags);
2488 next_state = re_acquire_state_context (err, dfa, &next_nodes, context);
2489 /* We don't need to check errors here, since the return value of
2490 this function is next_state and ERR is already set. */
2491
2492 re_node_set_free (&next_nodes);
2493 re_string_skip_bytes (&mctx->input, 1);
2494 return next_state;
2495}
2496#endif
2497
2498#ifdef RE_ENABLE_I18N
2499static reg_errcode_t
2500internal_function
2501transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate)
2502{
2503 const re_dfa_t *const dfa = mctx->dfa;
2504 reg_errcode_t err;
2505 int i;
2506
2507 for (i = 0; i < pstate->nodes.nelem; ++i)
2508 {
2509 re_node_set dest_nodes, *new_nodes;
2510 int cur_node_idx = pstate->nodes.elems[i];
2511 int naccepted, dest_idx;
2512 unsigned int context;
2513 re_dfastate_t *dest_state;
2514
2515 if (!dfa->nodes[cur_node_idx].accept_mb)
2516 continue;
2517
2518 if (dfa->nodes[cur_node_idx].constraint)
2519 {
2520 context = re_string_context_at (&mctx->input,
2521 re_string_cur_idx (&mctx->input),
2522 mctx->eflags);
2523 if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint,
2524 context))
2525 continue;
2526 }
2527
2528 /* How many bytes the node can accept? */
2529 naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input,
2530 re_string_cur_idx (&mctx->input));
2531 if (naccepted == 0)
2532 continue;
2533
2534 /* The node can accepts `naccepted' bytes. */
2535 dest_idx = re_string_cur_idx (&mctx->input) + naccepted;
2536 mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted
2537 : mctx->max_mb_elem_len);
2538 err = clean_state_log_if_needed (mctx, dest_idx);
2539 if (BE (err != REG_NOERROR, 0))
2540 return err;
2541#ifdef DEBUG
2542 assert (dfa->nexts[cur_node_idx] != -1);
2543#endif
2544 new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx];
2545
2546 dest_state = mctx->state_log[dest_idx];
2547 if (dest_state == NULL)
2548 dest_nodes = *new_nodes;
2549 else
2550 {
2551 err = re_node_set_init_union (&dest_nodes,
2552 dest_state->entrance_nodes, new_nodes);
2553 if (BE (err != REG_NOERROR, 0))
2554 return err;
2555 }
2556 context = re_string_context_at (&mctx->input, dest_idx - 1,
2557 mctx->eflags);
2558 mctx->state_log[dest_idx]
2559 = re_acquire_state_context (&err, dfa, &dest_nodes, context);
2560 if (dest_state != NULL)
2561 re_node_set_free (&dest_nodes);
2562 if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0))
2563 return err;
2564 }
2565 return REG_NOERROR;
2566}
2567#endif /* RE_ENABLE_I18N */
2568
2569static reg_errcode_t
2570internal_function
2571transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes)
2572{
2573 const re_dfa_t *const dfa = mctx->dfa;
2574 reg_errcode_t err;
2575 int i;
2576 int cur_str_idx = re_string_cur_idx (&mctx->input);
2577
2578 for (i = 0; i < nodes->nelem; ++i)
2579 {
2580 int dest_str_idx, prev_nelem, bkc_idx;
2581 int node_idx = nodes->elems[i];
2582 unsigned int context;
2583 const re_token_t *node = dfa->nodes + node_idx;
2584 re_node_set *new_dest_nodes;
2585
2586 /* Check whether `node' is a backreference or not. */
2587 if (node->type != OP_BACK_REF)
2588 continue;
2589
2590 if (node->constraint)
2591 {
2592 context = re_string_context_at (&mctx->input, cur_str_idx,
2593 mctx->eflags);
2594 if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
2595 continue;
2596 }
2597
2598 /* `node' is a backreference.
2599 Check the substring which the substring matched. */
2600 bkc_idx = mctx->nbkref_ents;
2601 err = get_subexp (mctx, node_idx, cur_str_idx);
2602 if (BE (err != REG_NOERROR, 0))
2603 goto free_return;
2604
2605 /* And add the epsilon closures (which is `new_dest_nodes') of
2606 the backreference to appropriate state_log. */
2607#ifdef DEBUG
2608 assert (dfa->nexts[node_idx] != -1);
2609#endif
2610 for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx)
2611 {
2612 int subexp_len;
2613 re_dfastate_t *dest_state;
2614 struct re_backref_cache_entry *bkref_ent;
2615 bkref_ent = mctx->bkref_ents + bkc_idx;
2616 if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx)
2617 continue;
2618 subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from;
2619 new_dest_nodes = (subexp_len == 0
2620 ? dfa->eclosures + dfa->edests[node_idx].elems[0]
2621 : dfa->eclosures + dfa->nexts[node_idx]);
2622 dest_str_idx = (cur_str_idx + bkref_ent->subexp_to
2623 - bkref_ent->subexp_from);
2624 context = re_string_context_at (&mctx->input, dest_str_idx - 1,
2625 mctx->eflags);
2626 dest_state = mctx->state_log[dest_str_idx];
2627 prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0
2628 : mctx->state_log[cur_str_idx]->nodes.nelem);
2629 /* Add `new_dest_node' to state_log. */
2630 if (dest_state == NULL)
2631 {
2632 mctx->state_log[dest_str_idx]
2633 = re_acquire_state_context (&err, dfa, new_dest_nodes,
2634 context);
2635 if (BE (mctx->state_log[dest_str_idx] == NULL
2636 && err != REG_NOERROR, 0))
2637 goto free_return;
2638 }
2639 else
2640 {
2641 re_node_set dest_nodes;
2642 err = re_node_set_init_union (&dest_nodes,
2643 dest_state->entrance_nodes,
2644 new_dest_nodes);
2645 if (BE (err != REG_NOERROR, 0))
2646 {
2647 re_node_set_free (&dest_nodes);
2648 goto free_return;
2649 }
2650 mctx->state_log[dest_str_idx]
2651 = re_acquire_state_context (&err, dfa, &dest_nodes, context);
2652 re_node_set_free (&dest_nodes);
2653 if (BE (mctx->state_log[dest_str_idx] == NULL
2654 && err != REG_NOERROR, 0))
2655 goto free_return;
2656 }
2657 /* We need to check recursively if the backreference can epsilon
2658 transit. */
2659 if (subexp_len == 0
2660 && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem)
2661 {
2662 err = check_subexp_matching_top (mctx, new_dest_nodes,
2663 cur_str_idx);
2664 if (BE (err != REG_NOERROR, 0))
2665 goto free_return;
2666 err = transit_state_bkref (mctx, new_dest_nodes);
2667 if (BE (err != REG_NOERROR, 0))
2668 goto free_return;
2669 }
2670 }
2671 }
2672 err = REG_NOERROR;
2673 free_return:
2674 return err;
2675}
2676
2677/* Enumerate all the candidates which the backreference BKREF_NODE can match
2678 at BKREF_STR_IDX, and register them by match_ctx_add_entry().
2679 Note that we might collect inappropriate candidates here.
2680 However, the cost of checking them strictly here is too high, then we
2681 delay these checking for prune_impossible_nodes(). */
2682
2683static reg_errcode_t
2684internal_function
2685get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx)
2686{
2687 const re_dfa_t *const dfa = mctx->dfa;
2688 int subexp_num, sub_top_idx;
2689 const char *buf = (const char *) re_string_get_buffer (&mctx->input);
2690 /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */
2691 int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx);
2692 if (cache_idx != -1)
2693 {
2694 const struct re_backref_cache_entry *entry
2695 = mctx->bkref_ents + cache_idx;
2696 do
2697 if (entry->node == bkref_node)
2698 return REG_NOERROR; /* We already checked it. */
2699 while (entry++->more);
2700 }
2701
2702 subexp_num = dfa->nodes[bkref_node].opr.idx;
2703
2704 /* For each sub expression */
2705 for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx)
2706 {
2707 reg_errcode_t err;
2708 re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx];
2709 re_sub_match_last_t *sub_last;
2710 int sub_last_idx, sl_str, bkref_str_off;
2711
2712 if (dfa->nodes[sub_top->node].opr.idx != subexp_num)
2713 continue; /* It isn't related. */
2714
2715 sl_str = sub_top->str_idx;
2716 bkref_str_off = bkref_str_idx;
2717 /* At first, check the last node of sub expressions we already
2718 evaluated. */
2719 for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx)
2720 {
2721 int sl_str_diff;
2722 sub_last = sub_top->lasts[sub_last_idx];
2723 sl_str_diff = sub_last->str_idx - sl_str;
2724 /* The matched string by the sub expression match with the substring
2725 at the back reference? */
2726 if (sl_str_diff > 0)
2727 {
2728 if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0))
2729 {
2730 /* Not enough chars for a successful match. */
2731 if (bkref_str_off + sl_str_diff > mctx->input.len)
2732 break;
2733
2734 err = clean_state_log_if_needed (mctx,
2735 bkref_str_off
2736 + sl_str_diff);
2737 if (BE (err != REG_NOERROR, 0))
2738 return err;
2739 buf = (const char *) re_string_get_buffer (&mctx->input);
2740 }
2741 if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0)
2742 /* We don't need to search this sub expression any more. */
2743 break;
2744 }
2745 bkref_str_off += sl_str_diff;
2746 sl_str += sl_str_diff;
2747 err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
2748 bkref_str_idx);
2749
2750 /* Reload buf, since the preceding call might have reallocated
2751 the buffer. */
2752 buf = (const char *) re_string_get_buffer (&mctx->input);
2753
2754 if (err == REG_NOMATCH)
2755 continue;
2756 if (BE (err != REG_NOERROR, 0))
2757 return err;
2758 }
2759
2760 if (sub_last_idx < sub_top->nlasts)
2761 continue;
2762 if (sub_last_idx > 0)
2763 ++sl_str;
2764 /* Then, search for the other last nodes of the sub expression. */
2765 for (; sl_str <= bkref_str_idx; ++sl_str)
2766 {
2767 int cls_node, sl_str_off;
2768 const re_node_set *nodes;
2769 sl_str_off = sl_str - sub_top->str_idx;
2770 /* The matched string by the sub expression match with the substring
2771 at the back reference? */
2772 if (sl_str_off > 0)
2773 {
2774 if (BE (bkref_str_off >= mctx->input.valid_len, 0))
2775 {
2776 /* If we are at the end of the input, we cannot match. */
2777 if (bkref_str_off >= mctx->input.len)
2778 break;
2779
2780 err = extend_buffers (mctx);
2781 if (BE (err != REG_NOERROR, 0))
2782 return err;
2783
2784 buf = (const char *) re_string_get_buffer (&mctx->input);
2785 }
2786 if (buf [bkref_str_off++] != buf[sl_str - 1])
2787 break; /* We don't need to search this sub expression
2788 any more. */
2789 }
2790 if (mctx->state_log[sl_str] == NULL)
2791 continue;
2792 /* Does this state have a ')' of the sub expression? */
2793 nodes = &mctx->state_log[sl_str]->nodes;
2794 cls_node = find_subexp_node (dfa, nodes, subexp_num,
2795 OP_CLOSE_SUBEXP);
2796 if (cls_node == -1)
2797 continue; /* No. */
2798 if (sub_top->path == NULL)
2799 {
2800 sub_top->path = calloc (sizeof (state_array_t),
2801 sl_str - sub_top->str_idx + 1);
2802 if (sub_top->path == NULL)
2803 return REG_ESPACE;
2804 }
2805 /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node
2806 in the current context? */
2807 err = check_arrival (mctx, sub_top->path, sub_top->node,
2808 sub_top->str_idx, cls_node, sl_str,
2809 OP_CLOSE_SUBEXP);
2810 if (err == REG_NOMATCH)
2811 continue;
2812 if (BE (err != REG_NOERROR, 0))
2813 return err;
2814 sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str);
2815 if (BE (sub_last == NULL, 0))
2816 return REG_ESPACE;
2817 err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
2818 bkref_str_idx);
2819 if (err == REG_NOMATCH)
2820 continue;
2821 }
2822 }
2823 return REG_NOERROR;
2824}
2825
2826/* Helper functions for get_subexp(). */
2827
2828/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR.
2829 If it can arrive, register the sub expression expressed with SUB_TOP
2830 and SUB_LAST. */
2831
2832static reg_errcode_t
2833internal_function
2834get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top,
2835 re_sub_match_last_t *sub_last, int bkref_node, int bkref_str)
2836{
2837 reg_errcode_t err;
2838 int to_idx;
2839 /* Can the subexpression arrive the back reference? */
2840 err = check_arrival (mctx, &sub_last->path, sub_last->node,
2841 sub_last->str_idx, bkref_node, bkref_str,
2842 OP_OPEN_SUBEXP);
2843 if (err != REG_NOERROR)
2844 return err;
2845 err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx,
2846 sub_last->str_idx);
2847 if (BE (err != REG_NOERROR, 0))
2848 return err;
2849 to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx;
2850 return clean_state_log_if_needed (mctx, to_idx);
2851}
2852
2853/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX.
2854 Search '(' if FL_OPEN, or search ')' otherwise.
2855 TODO: This function isn't efficient...
2856 Because there might be more than one nodes whose types are
2857 OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
2858 nodes.
2859 E.g. RE: (a){2} */
2860
2861static int
2862internal_function
2863find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
2864 int subexp_idx, int type)
2865{
2866 int cls_idx;
2867 for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx)
2868 {
2869 int cls_node = nodes->elems[cls_idx];
2870 const re_token_t *node = dfa->nodes + cls_node;
2871 if (node->type == type
2872 && node->opr.idx == subexp_idx)
2873 return cls_node;
2874 }
2875 return -1;
2876}
2877
2878/* Check whether the node TOP_NODE at TOP_STR can arrive to the node
2879 LAST_NODE at LAST_STR. We record the path onto PATH since it will be
2880 heavily reused.
2881 Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */
2882
2883static reg_errcode_t
2884internal_function
2885check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node,
2886 int top_str, int last_node, int last_str, int type)
2887{
2888 const re_dfa_t *const dfa = mctx->dfa;
2889 reg_errcode_t err = REG_NOERROR;
2890 int subexp_num, backup_cur_idx, str_idx, null_cnt;
2891 re_dfastate_t *cur_state = NULL;
2892 re_node_set *cur_nodes, next_nodes;
2893 re_dfastate_t **backup_state_log;
2894 unsigned int context;
2895
2896 subexp_num = dfa->nodes[top_node].opr.idx;
2897 /* Extend the buffer if we need. */
2898 if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0))
2899 {
2900 re_dfastate_t **new_array;
2901 int old_alloc = path->alloc;
2902 path->alloc += last_str + mctx->max_mb_elem_len + 1;
2903 new_array = re_realloc (path->array, re_dfastate_t *, path->alloc);
2904 if (BE (new_array == NULL, 0))
2905 {
2906 path->alloc = old_alloc;
2907 return REG_ESPACE;
2908 }
2909 path->array = new_array;
2910 memset (new_array + old_alloc, '\0',
2911 sizeof (re_dfastate_t *) * (path->alloc - old_alloc));
2912 }
2913
2914 str_idx = path->next_idx ? path->next_idx : top_str;
2915
2916 /* Temporary modify MCTX. */
2917 backup_state_log = mctx->state_log;
2918 backup_cur_idx = mctx->input.cur_idx;
2919 mctx->state_log = path->array;
2920 mctx->input.cur_idx = str_idx;
2921
2922 /* Setup initial node set. */
2923 context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
2924 if (str_idx == top_str)
2925 {
2926 err = re_node_set_init_1 (&next_nodes, top_node);
2927 if (BE (err != REG_NOERROR, 0))
2928 return err;
2929 err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
2930 if (BE (err != REG_NOERROR, 0))
2931 {
2932 re_node_set_free (&next_nodes);
2933 return err;
2934 }
2935 }
2936 else
2937 {
2938 cur_state = mctx->state_log[str_idx];
2939 if (cur_state && cur_state->has_backref)
2940 {
2941 err = re_node_set_init_copy (&next_nodes, &cur_state->nodes);
2942 if (BE (err != REG_NOERROR, 0))
2943 return err;
2944 }
2945 else
2946 re_node_set_init_empty (&next_nodes);
2947 }
2948 if (str_idx == top_str || (cur_state && cur_state->has_backref))
2949 {
2950 if (next_nodes.nelem)
2951 {
2952 err = expand_bkref_cache (mctx, &next_nodes, str_idx,
2953 subexp_num, type);
2954 if (BE (err != REG_NOERROR, 0))
2955 {
2956 re_node_set_free (&next_nodes);
2957 return err;
2958 }
2959 }
2960 cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
2961 if (BE (cur_state == NULL && err != REG_NOERROR, 0))
2962 {
2963 re_node_set_free (&next_nodes);
2964 return err;
2965 }
2966 mctx->state_log[str_idx] = cur_state;
2967 }
2968
2969 for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
2970 {
2971 re_node_set_empty (&next_nodes);
2972 if (mctx->state_log[str_idx + 1])
2973 {
2974 err = re_node_set_merge (&next_nodes,
2975 &mctx->state_log[str_idx + 1]->nodes);
2976 if (BE (err != REG_NOERROR, 0))
2977 {
2978 re_node_set_free (&next_nodes);
2979 return err;
2980 }
2981 }
2982 if (cur_state)
2983 {
2984 err = check_arrival_add_next_nodes (mctx, str_idx,
2985 &cur_state->non_eps_nodes,
2986 &next_nodes);
2987 if (BE (err != REG_NOERROR, 0))
2988 {
2989 re_node_set_free (&next_nodes);
2990 return err;
2991 }
2992 }
2993 ++str_idx;
2994 if (next_nodes.nelem)
2995 {
2996 err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
2997 if (BE (err != REG_NOERROR, 0))
2998 {
2999 re_node_set_free (&next_nodes);
3000 return err;
3001 }
3002 err = expand_bkref_cache (mctx, &next_nodes, str_idx,
3003 subexp_num, type);
3004 if (BE (err != REG_NOERROR, 0))
3005 {
3006 re_node_set_free (&next_nodes);
3007 return err;
3008 }
3009 }
3010 context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
3011 cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
3012 if (BE (cur_state == NULL && err != REG_NOERROR, 0))
3013 {
3014 re_node_set_free (&next_nodes);
3015 return err;
3016 }
3017 mctx->state_log[str_idx] = cur_state;
3018 null_cnt = cur_state == NULL ? null_cnt + 1 : 0;
3019 }
3020 re_node_set_free (&next_nodes);
3021 cur_nodes = (mctx->state_log[last_str] == NULL ? NULL
3022 : &mctx->state_log[last_str]->nodes);
3023 path->next_idx = str_idx;
3024
3025 /* Fix MCTX. */
3026 mctx->state_log = backup_state_log;
3027 mctx->input.cur_idx = backup_cur_idx;
3028
3029 /* Then check the current node set has the node LAST_NODE. */
3030 if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node))
3031 return REG_NOERROR;
3032
3033 return REG_NOMATCH;
3034}
3035
3036/* Helper functions for check_arrival. */
3037
3038/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them
3039 to NEXT_NODES.
3040 TODO: This function is similar to the functions transit_state*(),
3041 however this function has many additional works.
3042 Can't we unify them? */
3043
3044static reg_errcode_t
3045internal_function
3046check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx,
3047 re_node_set *cur_nodes, re_node_set *next_nodes)
3048{
3049 const re_dfa_t *const dfa = mctx->dfa;
3050 int result;
3051 int cur_idx;
3052#ifdef RE_ENABLE_I18N
3053 reg_errcode_t err = REG_NOERROR;
3054#endif
3055 re_node_set union_set;
3056 re_node_set_init_empty (&union_set);
3057 for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx)
3058 {
3059 int naccepted = 0;
3060 int cur_node = cur_nodes->elems[cur_idx];
3061#ifdef DEBUG
3062 re_token_type_t type = dfa->nodes[cur_node].type;
3063 assert (!IS_EPSILON_NODE (type));
3064#endif
3065#ifdef RE_ENABLE_I18N
3066 /* If the node may accept `multi byte'. */
3067 if (dfa->nodes[cur_node].accept_mb)
3068 {
3069 naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input,
3070 str_idx);
3071 if (naccepted > 1)
3072 {
3073 re_dfastate_t *dest_state;
3074 int next_node = dfa->nexts[cur_node];
3075 int next_idx = str_idx + naccepted;
3076 dest_state = mctx->state_log[next_idx];
3077 re_node_set_empty (&union_set);
3078 if (dest_state)
3079 {
3080 err = re_node_set_merge (&union_set, &dest_state->nodes);
3081 if (BE (err != REG_NOERROR, 0))
3082 {
3083 re_node_set_free (&union_set);
3084 return err;
3085 }
3086 }
3087 result = re_node_set_insert (&union_set, next_node);
3088 if (BE (result < 0, 0))
3089 {
3090 re_node_set_free (&union_set);
3091 return REG_ESPACE;
3092 }
3093 mctx->state_log[next_idx] = re_acquire_state (&err, dfa,
3094 &union_set);
3095 if (BE (mctx->state_log[next_idx] == NULL
3096 && err != REG_NOERROR, 0))
3097 {
3098 re_node_set_free (&union_set);
3099 return err;
3100 }
3101 }
3102 }
3103#endif /* RE_ENABLE_I18N */
3104 if (naccepted
3105 || check_node_accept (mctx, dfa->nodes + cur_node, str_idx))
3106 {
3107 result = re_node_set_insert (next_nodes, dfa->nexts[cur_node]);
3108 if (BE (result < 0, 0))
3109 {
3110 re_node_set_free (&union_set);
3111 return REG_ESPACE;
3112 }
3113 }
3114 }
3115 re_node_set_free (&union_set);
3116 return REG_NOERROR;
3117}
3118
3119/* For all the nodes in CUR_NODES, add the epsilon closures of them to
3120 CUR_NODES, however exclude the nodes which are:
3121 - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN.
3122 - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN.
3123*/
3124
3125static reg_errcode_t
3126internal_function
3127check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes,
3128 int ex_subexp, int type)
3129{
3130 reg_errcode_t err;
3131 int idx, outside_node;
3132 re_node_set new_nodes;
3133#ifdef DEBUG
3134 assert (cur_nodes->nelem);
3135#endif
3136 err = re_node_set_alloc (&new_nodes, cur_nodes->nelem);
3137 if (BE (err != REG_NOERROR, 0))
3138 return err;
3139 /* Create a new node set NEW_NODES with the nodes which are epsilon
3140 closures of the node in CUR_NODES. */
3141
3142 for (idx = 0; idx < cur_nodes->nelem; ++idx)
3143 {
3144 int cur_node = cur_nodes->elems[idx];
3145 const re_node_set *eclosure = dfa->eclosures + cur_node;
3146 outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type);
3147 if (outside_node == -1)
3148 {
3149 /* There are no problematic nodes, just merge them. */
3150 err = re_node_set_merge (&new_nodes, eclosure);
3151 if (BE (err != REG_NOERROR, 0))
3152 {
3153 re_node_set_free (&new_nodes);
3154 return err;
3155 }
3156 }
3157 else
3158 {
3159 /* There are problematic nodes, re-calculate incrementally. */
3160 err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node,
3161 ex_subexp, type);
3162 if (BE (err != REG_NOERROR, 0))
3163 {
3164 re_node_set_free (&new_nodes);
3165 return err;
3166 }
3167 }
3168 }
3169 re_node_set_free (cur_nodes);
3170 *cur_nodes = new_nodes;
3171 return REG_NOERROR;
3172}
3173
3174/* Helper function for check_arrival_expand_ecl.
3175 Check incrementally the epsilon closure of TARGET, and if it isn't
3176 problematic append it to DST_NODES. */
3177
3178static reg_errcode_t
3179internal_function
3180check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes,
3181 int target, int ex_subexp, int type)
3182{
3183 int cur_node;
3184 for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);)
3185 {
3186 int err;
3187
3188 if (dfa->nodes[cur_node].type == type
3189 && dfa->nodes[cur_node].opr.idx == ex_subexp)
3190 {
3191 if (type == OP_CLOSE_SUBEXP)
3192 {
3193 err = re_node_set_insert (dst_nodes, cur_node);
3194 if (BE (err == -1, 0))
3195 return REG_ESPACE;
3196 }
3197 break;
3198 }
3199 err = re_node_set_insert (dst_nodes, cur_node);
3200 if (BE (err == -1, 0))
3201 return REG_ESPACE;
3202 if (dfa->edests[cur_node].nelem == 0)
3203 break;
3204 if (dfa->edests[cur_node].nelem == 2)
3205 {
3206 err = check_arrival_expand_ecl_sub (dfa, dst_nodes,
3207 dfa->edests[cur_node].elems[1],
3208 ex_subexp, type);
3209 if (BE (err != REG_NOERROR, 0))
3210 return err;
3211 }
3212 cur_node = dfa->edests[cur_node].elems[0];
3213 }
3214 return REG_NOERROR;
3215}
3216
3217
3218/* For all the back references in the current state, calculate the
3219 destination of the back references by the appropriate entry
3220 in MCTX->BKREF_ENTS. */
3221
3222static reg_errcode_t
3223internal_function
3224expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes,
3225 int cur_str, int subexp_num, int type)
3226{
3227 const re_dfa_t *const dfa = mctx->dfa;
3228 reg_errcode_t err;
3229 int cache_idx_start = search_cur_bkref_entry (mctx, cur_str);
3230 struct re_backref_cache_entry *ent;
3231
3232 if (cache_idx_start == -1)
3233 return REG_NOERROR;
3234
3235 restart:
3236 ent = mctx->bkref_ents + cache_idx_start;
3237 do
3238 {
3239 int to_idx, next_node;
3240
3241 /* Is this entry ENT is appropriate? */
3242 if (!re_node_set_contains (cur_nodes, ent->node))
3243 continue; /* No. */
3244
3245 to_idx = cur_str + ent->subexp_to - ent->subexp_from;
3246 /* Calculate the destination of the back reference, and append it
3247 to MCTX->STATE_LOG. */
3248 if (to_idx == cur_str)
3249 {
3250 /* The backreference did epsilon transit, we must re-check all the
3251 node in the current state. */
3252 re_node_set new_dests;
3253 reg_errcode_t err2, err3;
3254 next_node = dfa->edests[ent->node].elems[0];
3255 if (re_node_set_contains (cur_nodes, next_node))
3256 continue;
3257 err = re_node_set_init_1 (&new_dests, next_node);
3258 err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type);
3259 err3 = re_node_set_merge (cur_nodes, &new_dests);
3260 re_node_set_free (&new_dests);
3261 if (BE (err != REG_NOERROR || err2 != REG_NOERROR
3262 || err3 != REG_NOERROR, 0))
3263 {
3264 err = (err != REG_NOERROR ? err
3265 : (err2 != REG_NOERROR ? err2 : err3));
3266 return err;
3267 }
3268 /* TODO: It is still inefficient... */
3269 goto restart;
3270 }
3271 else
3272 {
3273 re_node_set union_set;
3274 next_node = dfa->nexts[ent->node];
3275 if (mctx->state_log[to_idx])
3276 {
3277 int ret;
3278 if (re_node_set_contains (&mctx->state_log[to_idx]->nodes,
3279 next_node))
3280 continue;
3281 err = re_node_set_init_copy (&union_set,
3282 &mctx->state_log[to_idx]->nodes);
3283 ret = re_node_set_insert (&union_set, next_node);
3284 if (BE (err != REG_NOERROR || ret < 0, 0))
3285 {
3286 re_node_set_free (&union_set);
3287 err = err != REG_NOERROR ? err : REG_ESPACE;
3288 return err;
3289 }
3290 }
3291 else
3292 {
3293 err = re_node_set_init_1 (&union_set, next_node);
3294 if (BE (err != REG_NOERROR, 0))
3295 return err;
3296 }
3297 mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set);
3298 re_node_set_free (&union_set);
3299 if (BE (mctx->state_log[to_idx] == NULL
3300 && err != REG_NOERROR, 0))
3301 return err;
3302 }
3303 }
3304 while (ent++->more);
3305 return REG_NOERROR;
3306}
3307
3308/* Build transition table for the state.
3309 Return 1 if succeeded, otherwise return NULL. */
3310
3311static int
3312internal_function
3313build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
3314{
3315 reg_errcode_t err;
3316 int i, j, ch, need_word_trtable = 0;
3317 bitset_word_t elem, mask;
3318 bool dests_node_malloced = false;
3319 bool dest_states_malloced = false;
3320 int ndests; /* Number of the destination states from `state'. */
3321 re_dfastate_t **trtable;
3322 re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl;
3323 re_node_set follows, *dests_node;
3324 bitset_t *dests_ch;
3325 bitset_t acceptable;
3326
3327 struct dests_alloc
3328 {
3329 re_node_set dests_node[SBC_MAX];
3330 bitset_t dests_ch[SBC_MAX];
3331 } *dests_alloc;
3332
3333 /* We build DFA states which corresponds to the destination nodes
3334 from `state'. `dests_node[i]' represents the nodes which i-th
3335 destination state contains, and `dests_ch[i]' represents the
3336 characters which i-th destination state accepts. */
3337#ifdef HAVE_ALLOCA
3338 if (__libc_use_alloca (sizeof (struct dests_alloc)))
3339 dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc));
3340 else
3341#endif
3342 {
3343 dests_alloc = re_malloc (struct dests_alloc, 1);
3344 if (BE (dests_alloc == NULL, 0))
3345 return 0;
3346 dests_node_malloced = true;
3347 }
3348 dests_node = dests_alloc->dests_node;
3349 dests_ch = dests_alloc->dests_ch;
3350
3351 /* Initialize transiton table. */
3352 state->word_trtable = state->trtable = NULL;
3353
3354 /* At first, group all nodes belonging to `state' into several
3355 destinations. */
3356 ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch);
3357 if (BE (ndests <= 0, 0))
3358 {
3359 if (dests_node_malloced)
3360 free (dests_alloc);
3361 /* Return 0 in case of an error, 1 otherwise. */
3362 if (ndests == 0)
3363 {
3364 state->trtable = (re_dfastate_t **)
3365 calloc (sizeof (re_dfastate_t *), SBC_MAX);
3366 return 1;
3367 }
3368 return 0;
3369 }
3370
3371 err = re_node_set_alloc (&follows, ndests + 1);
3372 if (BE (err != REG_NOERROR, 0))
3373 goto out_free;
3374
3375 /* Avoid arithmetic overflow in size calculation. */
3376 if (BE ((((SIZE_MAX - (sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX)
3377 / (3 * sizeof (re_dfastate_t *)))
3378 < ndests),
3379 0))
3380 goto out_free;
3381
3382#ifdef HAVE_ALLOCA
3383 if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX
3384 + ndests * 3 * sizeof (re_dfastate_t *)))
3385 dest_states = (re_dfastate_t **)
3386 alloca (ndests * 3 * sizeof (re_dfastate_t *));
3387 else
3388#endif
3389 {
3390 dest_states = (re_dfastate_t **)
3391 malloc (ndests * 3 * sizeof (re_dfastate_t *));
3392 if (BE (dest_states == NULL, 0))
3393 {
3394out_free:
3395 if (dest_states_malloced)
3396 free (dest_states);
3397 re_node_set_free (&follows);
3398 for (i = 0; i < ndests; ++i)
3399 re_node_set_free (dests_node + i);
3400 if (dests_node_malloced)
3401 free (dests_alloc);
3402 return 0;
3403 }
3404 dest_states_malloced = true;
3405 }
3406 dest_states_word = dest_states + ndests;
3407 dest_states_nl = dest_states_word + ndests;
3408 bitset_empty (acceptable);
3409
3410 /* Then build the states for all destinations. */
3411 for (i = 0; i < ndests; ++i)
3412 {
3413 int next_node;
3414 re_node_set_empty (&follows);
3415 /* Merge the follows of this destination states. */
3416 for (j = 0; j < dests_node[i].nelem; ++j)
3417 {
3418 next_node = dfa->nexts[dests_node[i].elems[j]];
3419 if (next_node != -1)
3420 {
3421 err = re_node_set_merge (&follows, dfa->eclosures + next_node);
3422 if (BE (err != REG_NOERROR, 0))
3423 goto out_free;
3424 }
3425 }
3426 dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0);
3427 if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0))
3428 goto out_free;
3429 /* If the new state has context constraint,
3430 build appropriate states for these contexts. */
3431 if (dest_states[i]->has_constraint)
3432 {
3433 dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows,
3434 CONTEXT_WORD);
3435 if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
3436 goto out_free;
3437
3438 if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
3439 need_word_trtable = 1;
3440
3441 dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
3442 CONTEXT_NEWLINE);
3443 if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0))
3444 goto out_free;
3445 }
3446 else
3447 {
3448 dest_states_word[i] = dest_states[i];
3449 dest_states_nl[i] = dest_states[i];
3450 }
3451 bitset_merge (acceptable, dests_ch[i]);
3452 }
3453
3454 if (!BE (need_word_trtable, 0))
3455 {
3456 /* We don't care about whether the following character is a word
3457 character, or we are in a single-byte character set so we can
3458 discern by looking at the character code: allocate a
3459 256-entry transition table. */
3460 trtable = state->trtable =
3461 (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX);
3462 if (BE (trtable == NULL, 0))
3463 goto out_free;
3464
3465 /* For all characters ch...: */
3466 for (i = 0; i < BITSET_WORDS; ++i)
3467 for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
3468 elem;
3469 mask <<= 1, elem >>= 1, ++ch)
3470 if (BE (elem & 1, 0))
3471 {
3472 /* There must be exactly one destination which accepts
3473 character ch. See group_nodes_into_DFAstates. */
3474 for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
3475 ;
3476
3477 /* j-th destination accepts the word character ch. */
3478 if (dfa->word_char[i] & mask)
3479 trtable[ch] = dest_states_word[j];
3480 else
3481 trtable[ch] = dest_states[j];
3482 }
3483 }
3484 else
3485 {
3486 /* We care about whether the following character is a word
3487 character, and we are in a multi-byte character set: discern
3488 by looking at the character code: build two 256-entry
3489 transition tables, one starting at trtable[0] and one
3490 starting at trtable[SBC_MAX]. */
3491 trtable = state->word_trtable =
3492 (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX);
3493 if (BE (trtable == NULL, 0))
3494 goto out_free;
3495
3496 /* For all characters ch...: */
3497 for (i = 0; i < BITSET_WORDS; ++i)
3498 for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
3499 elem;
3500 mask <<= 1, elem >>= 1, ++ch)
3501 if (BE (elem & 1, 0))
3502 {
3503 /* There must be exactly one destination which accepts
3504 character ch. See group_nodes_into_DFAstates. */
3505 for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
3506 ;
3507
3508 /* j-th destination accepts the word character ch. */
3509 trtable[ch] = dest_states[j];
3510 trtable[ch + SBC_MAX] = dest_states_word[j];
3511 }
3512 }
3513
3514 /* new line */
3515 if (bitset_contain (acceptable, NEWLINE_CHAR))
3516 {
3517 /* The current state accepts newline character. */
3518 for (j = 0; j < ndests; ++j)
3519 if (bitset_contain (dests_ch[j], NEWLINE_CHAR))
3520 {
3521 /* k-th destination accepts newline character. */
3522 trtable[NEWLINE_CHAR] = dest_states_nl[j];
3523 if (need_word_trtable)
3524 trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j];
3525 /* There must be only one destination which accepts
3526 newline. See group_nodes_into_DFAstates. */
3527 break;
3528 }
3529 }
3530
3531 if (dest_states_malloced)
3532 free (dest_states);
3533
3534 re_node_set_free (&follows);
3535 for (i = 0; i < ndests; ++i)
3536 re_node_set_free (dests_node + i);
3537
3538 if (dests_node_malloced)
3539 free (dests_alloc);
3540
3541 return 1;
3542}
3543
3544/* Group all nodes belonging to STATE into several destinations.
3545 Then for all destinations, set the nodes belonging to the destination
3546 to DESTS_NODE[i] and set the characters accepted by the destination
3547 to DEST_CH[i]. This function return the number of destinations. */
3548
3549static int
3550internal_function
3551group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state,
3552 re_node_set *dests_node, bitset_t *dests_ch)
3553{
3554 reg_errcode_t err;
3555 int result;
3556 int i, j, k;
3557 int ndests; /* Number of the destinations from `state'. */
3558 bitset_t accepts; /* Characters a node can accept. */
3559 const re_node_set *cur_nodes = &state->nodes;
3560 bitset_empty (accepts);
3561 ndests = 0;
3562
3563 /* For all the nodes belonging to `state', */
3564 for (i = 0; i < cur_nodes->nelem; ++i)
3565 {
3566 re_token_t *node = &dfa->nodes[cur_nodes->elems[i]];
3567 re_token_type_t type = node->type;
3568 unsigned int constraint = node->constraint;
3569
3570 /* Enumerate all single byte character this node can accept. */
3571 if (type == CHARACTER)
3572 bitset_set (accepts, node->opr.c);
3573 else if (type == SIMPLE_BRACKET)
3574 {
3575 bitset_merge (accepts, node->opr.sbcset);
3576 }
3577 else if (type == OP_PERIOD)
3578 {
3579#ifdef RE_ENABLE_I18N
3580 if (dfa->mb_cur_max > 1)
3581 bitset_merge (accepts, dfa->sb_char);
3582 else
3583#endif
3584 bitset_set_all (accepts);
3585 if (!(dfa->syntax & RE_DOT_NEWLINE))
3586 bitset_clear (accepts, '\n');
3587 if (dfa->syntax & RE_DOT_NOT_NULL)
3588 bitset_clear (accepts, '\0');
3589 }
3590#ifdef RE_ENABLE_I18N
3591 else if (type == OP_UTF8_PERIOD)
3592 {
3593 memset (accepts, '\xff', sizeof (bitset_t) / 2);
3594 if (!(dfa->syntax & RE_DOT_NEWLINE))
3595 bitset_clear (accepts, '\n');
3596 if (dfa->syntax & RE_DOT_NOT_NULL)
3597 bitset_clear (accepts, '\0');
3598 }
3599#endif
3600 else
3601 continue;
3602
3603 /* Check the `accepts' and sift the characters which are not
3604 match it the context. */
3605 if (constraint)
3606 {
3607 if (constraint & NEXT_NEWLINE_CONSTRAINT)
3608 {
3609 bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR);
3610 bitset_empty (accepts);
3611 if (accepts_newline)
3612 bitset_set (accepts, NEWLINE_CHAR);
3613 else
3614 continue;
3615 }
3616 if (constraint & NEXT_ENDBUF_CONSTRAINT)
3617 {
3618 bitset_empty (accepts);
3619 continue;
3620 }
3621
3622 if (constraint & NEXT_WORD_CONSTRAINT)
3623 {
3624 bitset_word_t any_set = 0;
3625 if (type == CHARACTER && !node->word_char)
3626 {
3627 bitset_empty (accepts);
3628 continue;
3629 }
3630#ifdef RE_ENABLE_I18N
3631 if (dfa->mb_cur_max > 1)
3632 for (j = 0; j < BITSET_WORDS; ++j)
3633 any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
3634 else
3635#endif
3636 for (j = 0; j < BITSET_WORDS; ++j)
3637 any_set |= (accepts[j] &= dfa->word_char[j]);
3638 if (!any_set)
3639 continue;
3640 }
3641 if (constraint & NEXT_NOTWORD_CONSTRAINT)
3642 {
3643 bitset_word_t any_set = 0;
3644 if (type == CHARACTER && node->word_char)
3645 {
3646 bitset_empty (accepts);
3647 continue;
3648 }
3649#ifdef RE_ENABLE_I18N
3650 if (dfa->mb_cur_max > 1)
3651 for (j = 0; j < BITSET_WORDS; ++j)
3652 any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
3653 else
3654#endif
3655 for (j = 0; j < BITSET_WORDS; ++j)
3656 any_set |= (accepts[j] &= ~dfa->word_char[j]);
3657 if (!any_set)
3658 continue;
3659 }
3660 }
3661
3662 /* Then divide `accepts' into DFA states, or create a new
3663 state. Above, we make sure that accepts is not empty. */
3664 for (j = 0; j < ndests; ++j)
3665 {
3666 bitset_t intersec; /* Intersection sets, see below. */
3667 bitset_t remains;
3668 /* Flags, see below. */
3669 bitset_word_t has_intersec, not_subset, not_consumed;
3670
3671 /* Optimization, skip if this state doesn't accept the character. */
3672 if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c))
3673 continue;
3674
3675 /* Enumerate the intersection set of this state and `accepts'. */
3676 has_intersec = 0;
3677 for (k = 0; k < BITSET_WORDS; ++k)
3678 has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k];
3679 /* And skip if the intersection set is empty. */
3680 if (!has_intersec)
3681 continue;
3682
3683 /* Then check if this state is a subset of `accepts'. */
3684 not_subset = not_consumed = 0;
3685 for (k = 0; k < BITSET_WORDS; ++k)
3686 {
3687 not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k];
3688 not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k];
3689 }
3690
3691 /* If this state isn't a subset of `accepts', create a
3692 new group state, which has the `remains'. */
3693 if (not_subset)
3694 {
3695 bitset_copy (dests_ch[ndests], remains);
3696 bitset_copy (dests_ch[j], intersec);
3697 err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]);
3698 if (BE (err != REG_NOERROR, 0))
3699 goto error_return;
3700 ++ndests;
3701 }
3702
3703 /* Put the position in the current group. */
3704 result = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]);
3705 if (BE (result < 0, 0))
3706 goto error_return;
3707
3708 /* If all characters are consumed, go to next node. */
3709 if (!not_consumed)
3710 break;
3711 }
3712 /* Some characters remain, create a new group. */
3713 if (j == ndests)
3714 {
3715 bitset_copy (dests_ch[ndests], accepts);
3716 err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]);
3717 if (BE (err != REG_NOERROR, 0))
3718 goto error_return;
3719 ++ndests;
3720 bitset_empty (accepts);
3721 }
3722 }
3723 return ndests;
3724 error_return:
3725 for (j = 0; j < ndests; ++j)
3726 re_node_set_free (dests_node + j);
3727 return -1;
3728}
3729
3730#ifdef RE_ENABLE_I18N
3731/* Check how many bytes the node `dfa->nodes[node_idx]' accepts.
3732 Return the number of the bytes the node accepts.
3733 STR_IDX is the current index of the input string.
3734
3735 This function handles the nodes which can accept one character, or
3736 one collating element like '.', '[a-z]', opposite to the other nodes
3737 can only accept one byte. */
3738
3739static int
3740internal_function
3741check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
3742 const re_string_t *input, int str_idx)
3743{
3744 const re_token_t *node = dfa->nodes + node_idx;
3745 int char_len, elem_len;
3746 int i;
3747 wint_t wc;
3748
3749 if (BE (node->type == OP_UTF8_PERIOD, 0))
3750 {
3751 unsigned char c = re_string_byte_at (input, str_idx), d;
3752 if (BE (c < 0xc2, 1))
3753 return 0;
3754
3755 if (str_idx + 2 > input->len)
3756 return 0;
3757
3758 d = re_string_byte_at (input, str_idx + 1);
3759 if (c < 0xe0)
3760 return (d < 0x80 || d > 0xbf) ? 0 : 2;
3761 else if (c < 0xf0)
3762 {
3763 char_len = 3;
3764 if (c == 0xe0 && d < 0xa0)
3765 return 0;
3766 }
3767 else if (c < 0xf8)
3768 {
3769 char_len = 4;
3770 if (c == 0xf0 && d < 0x90)
3771 return 0;
3772 }
3773 else if (c < 0xfc)
3774 {
3775 char_len = 5;
3776 if (c == 0xf8 && d < 0x88)
3777 return 0;
3778 }
3779 else if (c < 0xfe)
3780 {
3781 char_len = 6;
3782 if (c == 0xfc && d < 0x84)
3783 return 0;
3784 }
3785 else
3786 return 0;
3787
3788 if (str_idx + char_len > input->len)
3789 return 0;
3790
3791 for (i = 1; i < char_len; ++i)
3792 {
3793 d = re_string_byte_at (input, str_idx + i);
3794 if (d < 0x80 || d > 0xbf)
3795 return 0;
3796 }
3797 return char_len;
3798 }
3799
3800 char_len = re_string_char_size_at (input, str_idx);
3801 if (node->type == OP_PERIOD)
3802 {
3803 if (char_len <= 1)
3804 return 0;
3805 /* FIXME: I don't think this if is needed, as both '\n'
3806 and '\0' are char_len == 1. */
3807 /* '.' accepts any one character except the following two cases. */
3808 if ((!(dfa->syntax & RE_DOT_NEWLINE) &&
3809 re_string_byte_at (input, str_idx) == '\n') ||
3810 ((dfa->syntax & RE_DOT_NOT_NULL) &&
3811 re_string_byte_at (input, str_idx) == '\0'))
3812 return 0;
3813 return char_len;
3814 }
3815
3816 elem_len = re_string_elem_size_at (input, str_idx);
3817 wc = __btowc(*(input->mbs+str_idx));
3818 if (((elem_len <= 1 && char_len <= 1) || char_len == 0) && (wc != WEOF && wc < SBC_MAX))
3819 return 0;
3820
3821 if (node->type == COMPLEX_BRACKET)
3822 {
3823 const re_charset_t *cset = node->opr.mbcset;
3824# ifdef _LIBC
3825 const unsigned char *pin
3826 = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
3827 int j;
3828 uint32_t nrules;
3829# endif /* _LIBC */
3830 int match_len = 0;
3831 wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
3832 ? re_string_wchar_at (input, str_idx) : 0);
3833
3834 /* match with multibyte character? */
3835 for (i = 0; i < cset->nmbchars; ++i)
3836 if (wc == cset->mbchars[i])
3837 {
3838 match_len = char_len;
3839 goto check_node_accept_bytes_match;
3840 }
3841 /* match with character_class? */
3842 for (i = 0; i < cset->nchar_classes; ++i)
3843 {
3844 wctype_t wt = cset->char_classes[i];
3845 if (__iswctype (wc, wt))
3846 {
3847 match_len = char_len;
3848 goto check_node_accept_bytes_match;
3849 }
3850 }
3851
3852# ifdef _LIBC
3853 nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
3854 if (nrules != 0)
3855 {
3856 unsigned int in_collseq = 0;
3857 const int32_t *table, *indirect;
3858 const unsigned char *weights, *extra;
3859 const char *collseqwc;
3860 /* This #include defines a local function! */
3861# include <locale/weight.h>
3862
3863 /* match with collating_symbol? */
3864 if (cset->ncoll_syms)
3865 extra = (const unsigned char *)
3866 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
3867 for (i = 0; i < cset->ncoll_syms; ++i)
3868 {
3869 const unsigned char *coll_sym = extra + cset->coll_syms[i];
3870 /* Compare the length of input collating element and
3871 the length of current collating element. */
3872 if (*coll_sym != elem_len)
3873 continue;
3874 /* Compare each bytes. */
3875 for (j = 0; j < *coll_sym; j++)
3876 if (pin[j] != coll_sym[1 + j])
3877 break;
3878 if (j == *coll_sym)
3879 {
3880 /* Match if every bytes is equal. */
3881 match_len = j;
3882 goto check_node_accept_bytes_match;
3883 }
3884 }
3885
3886 if (cset->nranges)
3887 {
3888 if (elem_len <= char_len)
3889 {
3890 collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
3891 in_collseq = __collseq_table_lookup (collseqwc, wc);
3892 }
3893 else
3894 in_collseq = find_collation_sequence_value (pin, elem_len);
3895 }
3896 /* match with range expression? */
3897 for (i = 0; i < cset->nranges; ++i)
3898 if (cset->range_starts[i] <= in_collseq
3899 && in_collseq <= cset->range_ends[i])
3900 {
3901 match_len = elem_len;
3902 goto check_node_accept_bytes_match;
3903 }
3904
3905 /* match with equivalence_class? */
3906 if (cset->nequiv_classes)
3907 {
3908 const unsigned char *cp = pin;
3909 table = (const int32_t *)
3910 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
3911 weights = (const unsigned char *)
3912 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
3913 extra = (const unsigned char *)
3914 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
3915 indirect = (const int32_t *)
3916 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
3917 int32_t idx = findidx (&cp);
3918 if (idx > 0)
3919 for (i = 0; i < cset->nequiv_classes; ++i)
3920 {
3921 int32_t equiv_class_idx = cset->equiv_classes[i];
3922 size_t weight_len = weights[idx & 0xffffff];
3923 if (weight_len == weights[equiv_class_idx & 0xffffff]
3924 && (idx >> 24) == (equiv_class_idx >> 24))
3925 {
3926 int cnt = 0;
3927
3928 idx &= 0xffffff;
3929 equiv_class_idx &= 0xffffff;
3930
3931 while (cnt <= weight_len
3932 && (weights[equiv_class_idx + 1 + cnt]
3933 == weights[idx + 1 + cnt]))
3934 ++cnt;
3935 if (cnt > weight_len)
3936 {
3937 match_len = elem_len;
3938 goto check_node_accept_bytes_match;
3939 }
3940 }
3941 }
3942 }
3943 }
3944 else
3945# endif /* _LIBC */
3946 {
3947 /* match with range expression? */
3948#if __GNUC__ >= 2
3949 wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
3950#else
3951 wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
3952 cmp_buf[2] = wc;
3953#endif
3954 for (i = 0; i < cset->nranges; ++i)
3955 {
3956 cmp_buf[0] = cset->range_starts[i];
3957 cmp_buf[4] = cset->range_ends[i];
3958 if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
3959 && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
3960 {
3961 match_len = char_len;
3962 goto check_node_accept_bytes_match;
3963 }
3964 }
3965 }
3966 check_node_accept_bytes_match:
3967 if (!cset->non_match)
3968 return match_len;
3969 else
3970 {
3971 if (match_len > 0)
3972 return 0;
3973 else
3974 return (elem_len > char_len) ? elem_len : char_len;
3975 }
3976 }
3977 return 0;
3978}
3979
3980# ifdef _LIBC
3981static unsigned int
3982internal_function
3983find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
3984{
3985 uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
3986 if (nrules == 0)
3987 {
3988 if (mbs_len == 1)
3989 {
3990 /* No valid character. Match it as a single byte character. */
3991 const unsigned char *collseq = (const unsigned char *)
3992 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
3993 return collseq[mbs[0]];
3994 }
3995 return UINT_MAX;
3996 }
3997 else
3998 {
3999 int32_t idx;
4000 const unsigned char *extra = (const unsigned char *)
4001 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
4002 int32_t extrasize = (const unsigned char *)
4003 _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra;
4004
4005 for (idx = 0; idx < extrasize;)
4006 {
4007 int mbs_cnt, found = 0;
4008 int32_t elem_mbs_len;
4009 /* Skip the name of collating element name. */
4010 idx = idx + extra[idx] + 1;
4011 elem_mbs_len = extra[idx++];
4012 if (mbs_len == elem_mbs_len)
4013 {
4014 for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt)
4015 if (extra[idx + mbs_cnt] != mbs[mbs_cnt])
4016 break;
4017 if (mbs_cnt == elem_mbs_len)
4018 /* Found the entry. */
4019 found = 1;
4020 }
4021 /* Skip the byte sequence of the collating element. */
4022 idx += elem_mbs_len;
4023 /* Adjust for the alignment. */
4024 idx = (idx + 3) & ~3;
4025 /* Skip the collation sequence value. */
4026 idx += sizeof (uint32_t);
4027 /* Skip the wide char sequence of the collating element. */
4028 idx = idx + sizeof (uint32_t) * (extra[idx] + 1);
4029 /* If we found the entry, return the sequence value. */
4030 if (found)
4031 return *(uint32_t *) (extra + idx);
4032 /* Skip the collation sequence value. */
4033 idx += sizeof (uint32_t);
4034 }
4035 return UINT_MAX;
4036 }
4037}
4038# endif /* _LIBC */
4039#endif /* RE_ENABLE_I18N */
4040
4041/* Check whether the node accepts the byte which is IDX-th
4042 byte of the INPUT. */
4043
4044static int
4045internal_function
4046check_node_accept (const re_match_context_t *mctx, const re_token_t *node,
4047 int idx)
4048{
4049 unsigned char ch;
4050 ch = re_string_byte_at (&mctx->input, idx);
4051 switch (node->type)
4052 {
4053 case CHARACTER:
4054 if (node->opr.c != ch)
4055 return 0;
4056 break;
4057
4058 case SIMPLE_BRACKET:
4059 if (!bitset_contain (node->opr.sbcset, ch))
4060 return 0;
4061 break;
4062
4063#ifdef RE_ENABLE_I18N
4064 case OP_UTF8_PERIOD:
4065 if (ch >= 0x80)
4066 return 0;
4067 /* FALLTHROUGH */
4068#endif
4069 case OP_PERIOD:
4070 if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE))
4071 || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL)))
4072 return 0;
4073 break;
4074
4075 default:
4076 return 0;
4077 }
4078
4079 if (node->constraint)
4080 {
4081 /* The node has constraints. Check whether the current context
4082 satisfies the constraints. */
4083 unsigned int context = re_string_context_at (&mctx->input, idx,
4084 mctx->eflags);
4085 if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
4086 return 0;
4087 }
4088
4089 return 1;
4090}
4091
4092/* Extend the buffers, if the buffers have run out. */
4093
4094static reg_errcode_t
4095internal_function
4096extend_buffers (re_match_context_t *mctx)
4097{
4098 reg_errcode_t ret;
4099 re_string_t *pstr = &mctx->input;
4100
4101 /* Avoid overflow. */
4102 if (BE (INT_MAX / 2 / sizeof (re_dfastate_t *) <= pstr->bufs_len, 0))
4103 return REG_ESPACE;
4104
4105 /* Double the lengthes of the buffers. */
4106 ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
4107 if (BE (ret != REG_NOERROR, 0))
4108 return ret;
4109
4110 if (mctx->state_log != NULL)
4111 {
4112 /* And double the length of state_log. */
4113 /* XXX We have no indication of the size of this buffer. If this
4114 allocation fail we have no indication that the state_log array
4115 does not have the right size. */
4116 re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *,
4117 pstr->bufs_len + 1);
4118 if (BE (new_array == NULL, 0))
4119 return REG_ESPACE;
4120 mctx->state_log = new_array;
4121 }
4122
4123 /* Then reconstruct the buffers. */
4124 if (pstr->icase)
4125 {
4126#ifdef RE_ENABLE_I18N
4127 if (pstr->mb_cur_max > 1)
4128 {
4129 ret = build_wcs_upper_buffer (pstr);
4130 if (BE (ret != REG_NOERROR, 0))
4131 return ret;
4132 }
4133 else
4134#endif /* RE_ENABLE_I18N */
4135 build_upper_buffer (pstr);
4136 }
4137 else
4138 {
4139#ifdef RE_ENABLE_I18N
4140 if (pstr->mb_cur_max > 1)
4141 build_wcs_buffer (pstr);
4142 else
4143#endif /* RE_ENABLE_I18N */
4144 {
4145 if (pstr->trans != NULL)
4146 re_string_translate_buffer (pstr);
4147 }
4148 }
4149 return REG_NOERROR;
4150}
4151
4152
4153/* Functions for matching context. */
4154
4155/* Initialize MCTX. */
4156
4157static reg_errcode_t
4158internal_function
4159match_ctx_init (re_match_context_t *mctx, int eflags, int n)
4160{
4161 mctx->eflags = eflags;
4162 mctx->match_last = -1;
4163 if (n > 0)
4164 {
4165 mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n);
4166 mctx->sub_tops = re_malloc (re_sub_match_top_t *, n);
4167 if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0))
4168 return REG_ESPACE;
4169 }
4170 /* Already zero-ed by the caller.
4171 else
4172 mctx->bkref_ents = NULL;
4173 mctx->nbkref_ents = 0;
4174 mctx->nsub_tops = 0; */
4175 mctx->abkref_ents = n;
4176 mctx->max_mb_elem_len = 1;
4177 mctx->asub_tops = n;
4178 return REG_NOERROR;
4179}
4180
4181/* Clean the entries which depend on the current input in MCTX.
4182 This function must be invoked when the matcher changes the start index
4183 of the input, or changes the input string. */
4184
4185static void
4186internal_function
4187match_ctx_clean (re_match_context_t *mctx)
4188{
4189 int st_idx;
4190 for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx)
4191 {
4192 int sl_idx;
4193 re_sub_match_top_t *top = mctx->sub_tops[st_idx];
4194 for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx)
4195 {
4196 re_sub_match_last_t *last = top->lasts[sl_idx];
4197 re_free (last->path.array);
4198 re_free (last);
4199 }
4200 re_free (top->lasts);
4201 if (top->path)
4202 {
4203 re_free (top->path->array);
4204 re_free (top->path);
4205 }
4206 free (top);
4207 }
4208
4209 mctx->nsub_tops = 0;
4210 mctx->nbkref_ents = 0;
4211}
4212
4213/* Free all the memory associated with MCTX. */
4214
4215static void
4216internal_function
4217match_ctx_free (re_match_context_t *mctx)
4218{
4219 /* First, free all the memory associated with MCTX->SUB_TOPS. */
4220 match_ctx_clean (mctx);
4221 re_free (mctx->sub_tops);
4222 re_free (mctx->bkref_ents);
4223}
4224
4225/* Add a new backreference entry to MCTX.
4226 Note that we assume that caller never call this function with duplicate
4227 entry, and call with STR_IDX which isn't smaller than any existing entry.
4228*/
4229
4230static reg_errcode_t
4231internal_function
4232match_ctx_add_entry (re_match_context_t *mctx, int node, int str_idx, int from,
4233 int to)
4234{
4235 if (mctx->nbkref_ents >= mctx->abkref_ents)
4236 {
4237 struct re_backref_cache_entry* new_entry;
4238 new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry,
4239 mctx->abkref_ents * 2);
4240 if (BE (new_entry == NULL, 0))
4241 {
4242 re_free (mctx->bkref_ents);
4243 return REG_ESPACE;
4244 }
4245 mctx->bkref_ents = new_entry;
4246 memset (mctx->bkref_ents + mctx->nbkref_ents, '\0',
4247 sizeof (struct re_backref_cache_entry) * mctx->abkref_ents);
4248 mctx->abkref_ents *= 2;
4249 }
4250 if (mctx->nbkref_ents > 0
4251 && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx)
4252 mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1;
4253
4254 mctx->bkref_ents[mctx->nbkref_ents].node = node;
4255 mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx;
4256 mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from;
4257 mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to;
4258
4259 /* This is a cache that saves negative results of check_dst_limits_calc_pos.
4260 If bit N is clear, means that this entry won't epsilon-transition to
4261 an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If
4262 it is set, check_dst_limits_calc_pos_1 will recurse and try to find one
4263 such node.
4264
4265 A backreference does not epsilon-transition unless it is empty, so set
4266 to all zeros if FROM != TO. */
4267 mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map
4268 = (from == to ? ~0 : 0);
4269
4270 mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
4271 if (mctx->max_mb_elem_len < to - from)
4272 mctx->max_mb_elem_len = to - from;
4273 return REG_NOERROR;
4274}
4275
4276/* Search for the first entry which has the same str_idx, or -1 if none is
4277 found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */
4278
4279static int
4280internal_function
4281search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
4282{
4283 int left, right, mid, last;
4284 last = right = mctx->nbkref_ents;
4285 for (left = 0; left < right;)
4286 {
4287 mid = (left + right) / 2;
4288 if (mctx->bkref_ents[mid].str_idx < str_idx)
4289 left = mid + 1;
4290 else
4291 right = mid;
4292 }
4293 if (left < last && mctx->bkref_ents[left].str_idx == str_idx)
4294 return left;
4295 else
4296 return -1;
4297}
4298
4299/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches
4300 at STR_IDX. */
4301
4302static reg_errcode_t
4303internal_function
4304match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx)
4305{
4306#ifdef DEBUG
4307 assert (mctx->sub_tops != NULL);
4308 assert (mctx->asub_tops > 0);
4309#endif
4310 if (BE (mctx->nsub_tops == mctx->asub_tops, 0))
4311 {
4312 int new_asub_tops = mctx->asub_tops * 2;
4313 re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops,
4314 re_sub_match_top_t *,
4315 new_asub_tops);
4316 if (BE (new_array == NULL, 0))
4317 return REG_ESPACE;
4318 mctx->sub_tops = new_array;
4319 mctx->asub_tops = new_asub_tops;
4320 }
4321 mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t));
4322 if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0))
4323 return REG_ESPACE;
4324 mctx->sub_tops[mctx->nsub_tops]->node = node;
4325 mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx;
4326 return REG_NOERROR;
4327}
4328
4329/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches
4330 at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */
4331
4332static re_sub_match_last_t *
4333internal_function
4334match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx)
4335{
4336 re_sub_match_last_t *new_entry;
4337 if (BE (subtop->nlasts == subtop->alasts, 0))
4338 {
4339 int new_alasts = 2 * subtop->alasts + 1;
4340 re_sub_match_last_t **new_array = re_realloc (subtop->lasts,
4341 re_sub_match_last_t *,
4342 new_alasts);
4343 if (BE (new_array == NULL, 0))
4344 return NULL;
4345 subtop->lasts = new_array;
4346 subtop->alasts = new_alasts;
4347 }
4348 new_entry = calloc (1, sizeof (re_sub_match_last_t));
4349 if (BE (new_entry != NULL, 1))
4350 {
4351 subtop->lasts[subtop->nlasts] = new_entry;
4352 new_entry->node = node;
4353 new_entry->str_idx = str_idx;
4354 ++subtop->nlasts;
4355 }
4356 return new_entry;
4357}
4358
4359static void
4360internal_function
4361sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
4362 re_dfastate_t **limited_sts, int last_node, int last_str_idx)
4363{
4364 sctx->sifted_states = sifted_sts;
4365 sctx->limited_states = limited_sts;
4366 sctx->last_node = last_node;
4367 sctx->last_str_idx = last_str_idx;
4368 re_node_set_init_empty (&sctx->limits);
4369}
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/select.c b/win32/select.c
new file mode 100644
index 000000000..416174b3e
--- /dev/null
+++ b/win32/select.c
@@ -0,0 +1,573 @@
1/* Emulation for select(2)
2 Contributed by Paolo Bonzini.
3
4 Copyright 2008-2015 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, see <http://www.gnu.org/licenses/>. */
20
21#include <malloc.h>
22#include <assert.h>
23
24#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
25/* Native Windows. */
26
27#include <sys/types.h>
28#include <errno.h>
29#include <limits.h>
30
31#include <winsock2.h>
32#include <windows.h>
33#include <io.h>
34#include <stdio.h>
35#include <conio.h>
36#include <time.h>
37
38/* Get the overridden 'struct timeval'. */
39#include <sys/time.h>
40
41#undef select
42
43struct bitset {
44 unsigned char in[FD_SETSIZE / CHAR_BIT];
45 unsigned char out[FD_SETSIZE / CHAR_BIT];
46};
47
48/* Declare data structures for ntdll functions. */
49typedef struct _FILE_PIPE_LOCAL_INFORMATION {
50 ULONG NamedPipeType;
51 ULONG NamedPipeConfiguration;
52 ULONG MaximumInstances;
53 ULONG CurrentInstances;
54 ULONG InboundQuota;
55 ULONG ReadDataAvailable;
56 ULONG OutboundQuota;
57 ULONG WriteQuotaAvailable;
58 ULONG NamedPipeState;
59 ULONG NamedPipeEnd;
60} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
61
62typedef struct _IO_STATUS_BLOCK
63{
64 union {
65 DWORD Status;
66 PVOID Pointer;
67 } u;
68 ULONG_PTR Information;
69} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
70
71typedef enum _FILE_INFORMATION_CLASS {
72 FilePipeLocalInformation = 24
73} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
74
75typedef DWORD (WINAPI *PNtQueryInformationFile)
76 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
77
78#ifndef PIPE_BUF
79#define PIPE_BUF 512
80#endif
81
82static BOOL IsConsoleHandle (HANDLE h)
83{
84 DWORD mode;
85 return GetConsoleMode (h, &mode) != 0;
86}
87
88static BOOL
89IsSocketHandle (HANDLE h)
90{
91 WSANETWORKEVENTS ev;
92
93 if (IsConsoleHandle (h))
94 return FALSE;
95
96 /* Under Wine, it seems that getsockopt returns 0 for pipes too.
97 WSAEnumNetworkEvents instead distinguishes the two correctly. */
98 ev.lNetworkEvents = 0xDEADBEEF;
99 WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
100 return ev.lNetworkEvents != 0xDEADBEEF;
101}
102
103/* Compute output fd_sets for libc descriptor FD (whose Windows handle is
104 H). */
105
106static int
107windows_poll_handle (HANDLE h, int fd,
108 struct bitset *rbits,
109 struct bitset *wbits,
110 struct bitset *xbits)
111{
112 BOOL read, write, except;
113 int i, ret;
114 INPUT_RECORD *irbuffer;
115 DWORD avail, nbuffer;
116 BOOL bRet;
117 IO_STATUS_BLOCK iosb;
118 FILE_PIPE_LOCAL_INFORMATION fpli;
119 static PNtQueryInformationFile NtQueryInformationFile;
120 static BOOL once_only;
121
122 read = write = except = FALSE;
123 switch (GetFileType (h))
124 {
125 case FILE_TYPE_DISK:
126 read = TRUE;
127 write = TRUE;
128 break;
129
130 case FILE_TYPE_PIPE:
131 if (!once_only)
132 {
133 NtQueryInformationFile = (PNtQueryInformationFile)
134 GetProcAddress (GetModuleHandle ("ntdll.dll"),
135 "NtQueryInformationFile");
136 once_only = TRUE;
137 }
138
139 if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
140 {
141 if (avail)
142 read = TRUE;
143 }
144 else if (GetLastError () == ERROR_BROKEN_PIPE)
145 read = TRUE;
146
147 else
148 {
149 /* It was the write-end of the pipe. Check if it is writable.
150 If NtQueryInformationFile fails, optimistically assume the pipe is
151 writable. This could happen on Windows 9x, where
152 NtQueryInformationFile is not available, or if we inherit a pipe
153 that doesn't permit FILE_READ_ATTRIBUTES access on the write end
154 (I think this should not happen since Windows XP SP2; WINE seems
155 fine too). Otherwise, ensure that enough space is available for
156 atomic writes. */
157 memset (&iosb, 0, sizeof (iosb));
158 memset (&fpli, 0, sizeof (fpli));
159
160 if (!NtQueryInformationFile
161 || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
162 FilePipeLocalInformation)
163 || fpli.WriteQuotaAvailable >= PIPE_BUF
164 || (fpli.OutboundQuota < PIPE_BUF &&
165 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
166 write = TRUE;
167 }
168 break;
169
170 case FILE_TYPE_CHAR:
171 write = TRUE;
172 if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
173 break;
174
175 ret = WaitForSingleObject (h, 0);
176 if (ret == WAIT_OBJECT_0)
177 {
178 if (!IsConsoleHandle (h))
179 {
180 read = TRUE;
181 break;
182 }
183
184 nbuffer = avail = 0;
185 bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
186
187 /* Screen buffers handles are filtered earlier. */
188 assert (bRet);
189 if (nbuffer == 0)
190 {
191 except = TRUE;
192 break;
193 }
194
195 irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
196 bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
197 if (!bRet || avail == 0)
198 {
199 except = TRUE;
200 break;
201 }
202
203 for (i = 0; i < avail; i++)
204 if (irbuffer[i].EventType == KEY_EVENT &&
205 irbuffer[i].Event.KeyEvent.bKeyDown)
206 read = TRUE;
207 }
208 break;
209
210 default:
211 ret = WaitForSingleObject (h, 0);
212 write = TRUE;
213 if (ret == WAIT_OBJECT_0)
214 read = TRUE;
215
216 break;
217 }
218
219 ret = 0;
220 if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
221 {
222 rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
223 ret++;
224 }
225
226 if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
227 {
228 wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
229 ret++;
230 }
231
232 if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
233 {
234 xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
235 ret++;
236 }
237
238 return ret;
239}
240
241int
242mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
243 struct timeval *timeout)
244#undef timeval
245{
246 static struct timeval tv0;
247 static HANDLE hEvent;
248 HANDLE h, handle_array[FD_SETSIZE + 2];
249 fd_set handle_rfds, handle_wfds, handle_xfds;
250 struct bitset rbits, wbits, xbits;
251 unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
252 DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
253 MSG msg;
254 int i, fd, rc;
255 clock_t tend;
256
257 if (nfds > FD_SETSIZE)
258 nfds = FD_SETSIZE;
259
260 if (!timeout)
261 wait_timeout = INFINITE;
262 else
263 {
264 wait_timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
265
266 /* select is also used as a portable usleep. */
267 if (!rfds && !wfds && !xfds)
268 {
269 Sleep (wait_timeout);
270 return 0;
271 }
272 }
273
274 if (!hEvent)
275 hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
276
277 handle_array[0] = hEvent;
278 nhandles = 1;
279 nsock = 0;
280
281 /* Copy descriptors to bitsets. At the same time, eliminate
282 bits in the "wrong" direction for console input buffers
283 and screen buffers, because screen buffers are waitable
284 and they will block until a character is available. */
285 memset (&rbits, 0, sizeof (rbits));
286 memset (&wbits, 0, sizeof (wbits));
287 memset (&xbits, 0, sizeof (xbits));
288 memset (anyfds_in, 0, sizeof (anyfds_in));
289 if (rfds)
290 for (i = 0; i < rfds->fd_count; i++)
291 {
292 fd = rfds->fd_array[i];
293 h = (HANDLE) _get_osfhandle (fd);
294 if (IsConsoleHandle (h)
295 && !GetNumberOfConsoleInputEvents (h, &nbuffer))
296 continue;
297
298 rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
299 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
300 }
301 else
302 rfds = (fd_set *) alloca (sizeof (fd_set));
303
304 if (wfds)
305 for (i = 0; i < wfds->fd_count; i++)
306 {
307 fd = wfds->fd_array[i];
308 h = (HANDLE) _get_osfhandle (fd);
309 if (IsConsoleHandle (h)
310 && GetNumberOfConsoleInputEvents (h, &nbuffer))
311 continue;
312
313 wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
314 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
315 }
316 else
317 wfds = (fd_set *) alloca (sizeof (fd_set));
318
319 if (xfds)
320 for (i = 0; i < xfds->fd_count; i++)
321 {
322 fd = xfds->fd_array[i];
323 xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
324 anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
325 }
326 else
327 xfds = (fd_set *) alloca (sizeof (fd_set));
328
329 /* Zero all the fd_sets, including the application's. */
330 FD_ZERO (rfds);
331 FD_ZERO (wfds);
332 FD_ZERO (xfds);
333 FD_ZERO (&handle_rfds);
334 FD_ZERO (&handle_wfds);
335 FD_ZERO (&handle_xfds);
336
337 /* Classify handles. Create fd sets for sockets, poll the others. */
338 for (i = 0; i < nfds; i++)
339 {
340 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
341 continue;
342
343 h = (HANDLE) _get_osfhandle (i);
344 if (!h)
345 {
346 errno = EBADF;
347 return -1;
348 }
349
350 if (IsSocketHandle (h))
351 {
352 int requested = FD_CLOSE;
353
354 /* See above; socket handles are mapped onto select, but we
355 need to map descriptors to handles. */
356 if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
357 {
358 requested |= FD_READ | FD_ACCEPT;
359 FD_SET ((SOCKET) h, rfds);
360 FD_SET ((SOCKET) h, &handle_rfds);
361 }
362 if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
363 {
364 requested |= FD_WRITE | FD_CONNECT;
365 FD_SET ((SOCKET) h, wfds);
366 FD_SET ((SOCKET) h, &handle_wfds);
367 }
368 if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
369 {
370 requested |= FD_OOB;
371 FD_SET ((SOCKET) h, xfds);
372 FD_SET ((SOCKET) h, &handle_xfds);
373 }
374
375 WSAEventSelect ((SOCKET) h, hEvent, requested);
376 nsock++;
377 }
378 else
379 {
380 handle_array[nhandles++] = h;
381
382 /* Poll now. If we get an event, do not wait below. */
383 if (wait_timeout != 0
384 && windows_poll_handle (h, i, &rbits, &wbits, &xbits))
385 wait_timeout = 0;
386 }
387 }
388
389 /* Place a sentinel at the end of the array. */
390 handle_array[nhandles] = NULL;
391
392 /* When will the waiting period expire? */
393 if (wait_timeout != INFINITE)
394 tend = clock () + wait_timeout;
395
396restart:
397 if (wait_timeout == 0 || nsock == 0)
398 rc = 0;
399 else
400 {
401 /* See if we need to wait in the loop below. If any select is ready,
402 do MsgWaitForMultipleObjects anyway to dispatch messages, but
403 no need to call select again. */
404 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
405 if (rc == 0)
406 {
407 /* Restore the fd_sets for the other select we do below. */
408 memcpy (&handle_rfds, rfds, sizeof (fd_set));
409 memcpy (&handle_wfds, wfds, sizeof (fd_set));
410 memcpy (&handle_xfds, xfds, sizeof (fd_set));
411 }
412 else
413 wait_timeout = 0;
414 }
415
416 /* How much is left to wait? */
417 if (wait_timeout != INFINITE)
418 {
419 clock_t tnow = clock ();
420 if (tend >= tnow)
421 wait_timeout = tend - tnow;
422 else
423 wait_timeout = 0;
424 }
425
426 for (;;)
427 {
428 ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
429 wait_timeout, QS_ALLINPUT);
430
431 if (ret == WAIT_OBJECT_0 + nhandles)
432 {
433 /* new input of some other kind */
434 BOOL bRet;
435 while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
436 {
437 TranslateMessage (&msg);
438 DispatchMessage (&msg);
439 }
440 }
441 else
442 break;
443 }
444
445 /* If we haven't done it yet, check the status of the sockets. */
446 if (rc == 0 && nsock > 0)
447 rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
448
449 if (nhandles > 1)
450 {
451 /* Count results that are not counted in the return value of select. */
452 nhandles = 1;
453 for (i = 0; i < nfds; i++)
454 {
455 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
456 continue;
457
458 h = (HANDLE) _get_osfhandle (i);
459 if (h == handle_array[nhandles])
460 {
461 /* Not a socket. */
462 nhandles++;
463 windows_poll_handle (h, i, &rbits, &wbits, &xbits);
464 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
465 || wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
466 || xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
467 rc++;
468 }
469 }
470
471 if (rc == 0
472 && (wait_timeout == INFINITE
473 /* If NHANDLES > 1, but no bits are set, it means we've
474 been told incorrectly that some handle was signaled.
475 This happens with anonymous pipes, which always cause
476 MsgWaitForMultipleObjects to exit immediately, but no
477 data is found ready to be read by windows_poll_handle.
478 To avoid a total failure (whereby we return zero and
479 don't wait at all), let's poll in a more busy loop. */
480 || (wait_timeout != 0 && nhandles > 1)))
481 {
482 /* Sleep 1 millisecond to avoid busy wait and retry with the
483 original fd_sets. */
484 memcpy (&handle_rfds, rfds, sizeof (fd_set));
485 memcpy (&handle_wfds, wfds, sizeof (fd_set));
486 memcpy (&handle_xfds, xfds, sizeof (fd_set));
487 SleepEx (1, TRUE);
488 goto restart;
489 }
490 if (timeout && wait_timeout == 0 && rc == 0)
491 timeout->tv_sec = timeout->tv_usec = 0;
492 }
493
494 /* Now fill in the results. */
495 FD_ZERO (rfds);
496 FD_ZERO (wfds);
497 FD_ZERO (xfds);
498 nhandles = 1;
499 for (i = 0; i < nfds; i++)
500 {
501 if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
502 continue;
503
504 h = (HANDLE) _get_osfhandle (i);
505 if (h != handle_array[nhandles])
506 {
507 /* Perform handle->descriptor mapping. */
508 WSAEventSelect ((SOCKET) h, NULL, 0);
509 if (FD_ISSET (h, &handle_rfds))
510 FD_SET (i, rfds);
511 if (FD_ISSET (h, &handle_wfds))
512 FD_SET (i, wfds);
513 if (FD_ISSET (h, &handle_xfds))
514 FD_SET (i, xfds);
515 }
516 else
517 {
518 /* Not a socket. */
519 nhandles++;
520 if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
521 FD_SET (i, rfds);
522 if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
523 FD_SET (i, wfds);
524 if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
525 FD_SET (i, xfds);
526 }
527 }
528
529 return rc;
530}
531
532#else /* ! Native Windows. */
533
534#include <sys/select.h>
535#include <stddef.h> /* NULL */
536#include <errno.h>
537#include <unistd.h>
538
539#undef select
540
541int
542rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
543 struct timeval *timeout)
544{
545 int i;
546
547 /* FreeBSD 8.2 has a bug: it does not always detect invalid fds. */
548 if (nfds < 0 || nfds > FD_SETSIZE)
549 {
550 errno = EINVAL;
551 return -1;
552 }
553 for (i = 0; i < nfds; i++)
554 {
555 if (((rfds && FD_ISSET (i, rfds))
556 || (wfds && FD_ISSET (i, wfds))
557 || (xfds && FD_ISSET (i, xfds)))
558 && dup2 (i, i) != i)
559 return -1;
560 }
561
562 /* Interix 3.5 has a bug: it does not support nfds == 0. */
563 if (nfds == 0)
564 {
565 nfds = 1;
566 rfds = NULL;
567 wfds = NULL;
568 xfds = NULL;
569 }
570 return select (nfds, rfds, wfds, xfds, timeout);
571}
572
573#endif
diff --git a/win32/statfs.c b/win32/statfs.c
new file mode 100644
index 000000000..a35c9adea
--- /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 fsname[100];
14 struct mntent *mnt;
15
16 if ( (mnt=find_mount_point(file, 0)) == NULL ) {
17 return -1;
18 }
19
20 file = mnt->mnt_dir;
21 if ( !GetDiskFreeSpaceEx(file, (PULARGE_INTEGER) &free_bytes_available,
22 (PULARGE_INTEGER) &total_number_of_bytes,
23 (PULARGE_INTEGER) &total_number_of_free_bytes) ) {
24 errno = err_win_to_posix(GetLastError());
25 return -1;
26 }
27
28 if ( !GetVolumeInformation(file, NULL, 0, &serial, &namelen, &flags,
29 fsname, 100) ) {
30 errno = err_win_to_posix(GetLastError());
31 return -1;
32 }
33
34 /* XXX I couldn't determine how to get block size. MSDN has a
35 * unhelpful hard-coded list here:
36 * http://support.microsoft.com/kb/140365
37 * but this depends on the filesystem type, the size of the disk and
38 * the version of Windows. So this code assumes the disk is NTFS
39 * and the version of Windows is >= Win2K.
40 */
41 if (total_number_of_bytes < UINT64_C(16) * 1024 * 1024 * 1024 * 1024)
42 buf->f_bsize = 4096;
43 else if (total_number_of_bytes < UINT64_C(32) * 1024 * 1024 * 1024 * 1024)
44 buf->f_bsize = 8192;
45 else if (total_number_of_bytes < UINT64_C(64) * 1024 * 1024 * 1024 * 1024)
46 buf->f_bsize = 16384;
47 else if (total_number_of_bytes < UINT64_C(128) * 1024 * 1024 * 1024 * 1024)
48 buf->f_bsize = 32768;
49 else
50 buf->f_bsize = 65536;
51
52 /*
53 * Valid filesystem names don't seem to be documented. The following
54 * are present in Wine.
55 */
56 if ( strcmp(fsname, "NTFS") == 0 ) {
57 buf->f_type = 0x5346544e;
58 }
59 else if ( strcmp(fsname, "FAT") == 0 || strcmp(fsname, "FAT32") == 0 ) {
60 buf->f_type = 0x4006;
61 }
62 else if ( strcmp(fsname, "CDFS") == 0 ) {
63 buf->f_type = 0x9660;
64 }
65 else {
66 buf->f_type = 0;
67 }
68
69 buf->f_frsize = buf->f_bsize;
70 buf->f_blocks = total_number_of_bytes / buf->f_bsize;
71 buf->f_bfree = total_number_of_free_bytes / buf->f_bsize;
72 buf->f_bavail = free_bytes_available / buf->f_bsize;
73 buf->f_files = UINT32_MAX;
74 buf->f_ffree = UINT32_MAX;
75 buf->f_fsid = serial;
76 buf->f_flag = UINT64_MAX;
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/prctl.h b/win32/sys/prctl.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/win32/sys/prctl.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..498f41e50
--- /dev/null
+++ b/win32/sys/statfs.h
@@ -0,0 +1,22 @@
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_fsid;
16 uint64_t f_flag;
17 uint64_t f_namelen;
18};
19
20extern int statfs(const char *file, struct statfs *buf);
21
22#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..02aaaa0a1
--- /dev/null
+++ b/win32/system.c
@@ -0,0 +1,22 @@
1#include "libbb.h"
2
3int mingw_system(const char *cmd)
4{
5 const char *argv[4] = { "sh", "-c", cmd, NULL };
6 intptr_t proc;
7 HANDLE h;
8 DWORD ret = 0;
9
10 if (cmd == NULL)
11 return 1;
12
13 if ((proc=mingw_spawn_proc((char **)argv)) == -1)
14 return -1;
15
16 h = (HANDLE)proc;
17 WaitForSingleObject(h, INFINITE);
18 GetExitCodeProcess(h, &ret);
19 CloseHandle(h);
20
21 return ret << 8;
22}
diff --git a/win32/termios.c b/win32/termios.c
new file mode 100644
index 000000000..658af4a26
--- /dev/null
+++ b/win32/termios.c
@@ -0,0 +1,83 @@
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 }
71 continue;
72 }
73 if ( (record.Event.KeyEvent.uChar.AsciiChar & 0x80) == 0x80 ) {
74 s = &record.Event.KeyEvent.uChar.AsciiChar;
75 OemToCharBuff(s, s, 1);
76 }
77 ret = record.Event.KeyEvent.uChar.AsciiChar;
78 break;
79 }
80 done:
81 SetConsoleMode(cin, mode);
82 return ret;
83}
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..3b3e21f8d
--- /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, "%u.%u", (unsigned int)os_info.dwMajorVersion,
24 (unsigned int)os_info.dwMinorVersion);
25 sprintf(name->version, "%u", (unsigned int)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..7c7e1a626
--- /dev/null
+++ b/win32/winansi.c
@@ -0,0 +1,735 @@
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 vfprintf
13#undef vprintf
14#undef printf
15#undef fprintf
16#undef fputs
17#undef putchar
18#undef fwrite
19#undef puts
20#undef write
21#undef read
22#undef getc
23
24/*
25 ANSI codes used by git: m, K
26
27 This file is git-specific. Therefore, this file does not attempt
28 to implement any codes that are not used by git.
29*/
30
31static HANDLE console;
32static HANDLE console_in;
33static WORD plain_attr;
34static WORD attr;
35static int negative;
36
37static void init(void)
38{
39 CONSOLE_SCREEN_BUFFER_INFO sbi;
40
41 static int initialized = 0;
42 if (initialized)
43 return;
44
45 console_in = GetStdHandle(STD_INPUT_HANDLE);
46 if (console_in == INVALID_HANDLE_VALUE)
47 console_in = NULL;
48
49 console = GetStdHandle(STD_OUTPUT_HANDLE);
50 if (console == INVALID_HANDLE_VALUE)
51 console = NULL;
52
53 if (!console)
54 return;
55
56 GetConsoleScreenBufferInfo(console, &sbi);
57 attr = plain_attr = sbi.wAttributes;
58 negative = 0;
59
60 initialized = 1;
61}
62
63static int skip_ansi_emulation(void)
64{
65 static char *var = NULL;
66 static int got_var = FALSE;
67
68 if (!got_var) {
69 var = getenv("BB_SKIP_ANSI_EMULATION");
70 got_var = TRUE;
71 }
72
73 return var != NULL;
74}
75
76
77#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
78#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
79
80static void set_console_attr(void)
81{
82 WORD attributes = attr;
83 if (negative) {
84 attributes &= ~FOREGROUND_ALL;
85 attributes &= ~BACKGROUND_ALL;
86
87 /* This could probably use a bitmask
88 instead of a series of ifs */
89 if (attr & FOREGROUND_RED)
90 attributes |= BACKGROUND_RED;
91 if (attr & FOREGROUND_GREEN)
92 attributes |= BACKGROUND_GREEN;
93 if (attr & FOREGROUND_BLUE)
94 attributes |= BACKGROUND_BLUE;
95
96 if (attr & BACKGROUND_RED)
97 attributes |= FOREGROUND_RED;
98 if (attr & BACKGROUND_GREEN)
99 attributes |= FOREGROUND_GREEN;
100 if (attr & BACKGROUND_BLUE)
101 attributes |= FOREGROUND_BLUE;
102 }
103 SetConsoleTextAttribute(console, attributes);
104}
105
106static void erase_in_line(void)
107{
108 CONSOLE_SCREEN_BUFFER_INFO sbi;
109 DWORD dummy; /* Needed for Windows 7 (or Vista) regression */
110
111 if (!console)
112 return;
113
114 GetConsoleScreenBufferInfo(console, &sbi);
115 FillConsoleOutputCharacterA(console, ' ',
116 sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
117 &dummy);
118 FillConsoleOutputAttribute(console, plain_attr,
119 sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
120 &dummy);
121}
122
123static void erase_till_end_of_screen(void)
124{
125 CONSOLE_SCREEN_BUFFER_INFO sbi;
126 DWORD dummy, len;
127
128 if (!console)
129 return;
130
131 GetConsoleScreenBufferInfo(console, &sbi);
132 len = sbi.dwSize.X - sbi.dwCursorPosition.X +
133 sbi.dwSize.X * (sbi.srWindow.Bottom - sbi.dwCursorPosition.Y);
134
135 FillConsoleOutputCharacterA(console, ' ', len, sbi.dwCursorPosition,
136 &dummy);
137 FillConsoleOutputAttribute(console, plain_attr, len, sbi.dwCursorPosition,
138 &dummy);
139}
140
141void reset_screen(void)
142{
143 CONSOLE_SCREEN_BUFFER_INFO sbi;
144 COORD pos;
145 DWORD dummy, len;
146
147 if (!console)
148 return;
149
150 /* move to start of screen buffer and clear it all */
151 GetConsoleScreenBufferInfo(console, &sbi);
152 pos.X = 0;
153 pos.Y = 0;
154 SetConsoleCursorPosition(console, pos);
155 len = sbi.dwSize.X * sbi.dwSize.Y;
156 FillConsoleOutputCharacterA(console, ' ', len, pos, &dummy);
157 FillConsoleOutputAttribute(console, plain_attr, len, pos, &dummy);
158}
159
160void move_cursor_row(int n)
161{
162 CONSOLE_SCREEN_BUFFER_INFO sbi;
163
164 if (!console)
165 return;
166
167 GetConsoleScreenBufferInfo(console, &sbi);
168 sbi.dwCursorPosition.Y += n;
169 SetConsoleCursorPosition(console, sbi.dwCursorPosition);
170}
171
172static void move_cursor_column(int n)
173{
174 CONSOLE_SCREEN_BUFFER_INFO sbi;
175
176 if (!console)
177 return;
178
179 GetConsoleScreenBufferInfo(console, &sbi);
180 sbi.dwCursorPosition.X += n;
181 SetConsoleCursorPosition(console, sbi.dwCursorPosition);
182}
183
184static void move_cursor(int x, int y)
185{
186 COORD pos;
187 CONSOLE_SCREEN_BUFFER_INFO sbi;
188
189 if (!console)
190 return;
191
192 GetConsoleScreenBufferInfo(console, &sbi);
193 pos.X = sbi.srWindow.Left + x;
194 pos.Y = sbi.srWindow.Top + y;
195 SetConsoleCursorPosition(console, pos);
196}
197
198static const char *set_attr(const char *str)
199{
200 const char *func;
201 size_t len = strspn(str, "0123456789;");
202 func = str + len;
203
204 switch (*func) {
205 case 'm':
206 do {
207 long val = strtol(str, (char **)&str, 10);
208 switch (val) {
209 case 0: /* reset */
210 attr = plain_attr;
211 negative = 0;
212 break;
213 case 1: /* bold */
214 attr |= FOREGROUND_INTENSITY;
215 break;
216 case 2: /* faint */
217 case 22: /* normal */
218 attr &= ~FOREGROUND_INTENSITY;
219 break;
220 case 3: /* italic */
221 /* Unsupported */
222 break;
223 case 4: /* underline */
224 case 21: /* double underline */
225 /* Wikipedia says this flag does nothing */
226 /* Furthermore, mingw doesn't define this flag
227 attr |= COMMON_LVB_UNDERSCORE; */
228 break;
229 case 24: /* no underline */
230 /* attr &= ~COMMON_LVB_UNDERSCORE; */
231 break;
232 case 5: /* slow blink */
233 case 6: /* fast blink */
234 /* We don't have blink, but we do have
235 background intensity */
236 attr |= BACKGROUND_INTENSITY;
237 break;
238 case 25: /* no blink */
239 attr &= ~BACKGROUND_INTENSITY;
240 break;
241 case 7: /* negative */
242 negative = 1;
243 break;
244 case 27: /* positive */
245 negative = 0;
246 break;
247 case 8: /* conceal */
248 case 28: /* reveal */
249 /* Unsupported */
250 break;
251 case 30: /* Black */
252 attr &= ~FOREGROUND_ALL;
253 break;
254 case 31: /* Red */
255 attr &= ~FOREGROUND_ALL;
256 attr |= FOREGROUND_RED;
257 break;
258 case 32: /* Green */
259 attr &= ~FOREGROUND_ALL;
260 attr |= FOREGROUND_GREEN;
261 break;
262 case 33: /* Yellow */
263 attr &= ~FOREGROUND_ALL;
264 attr |= FOREGROUND_RED | FOREGROUND_GREEN;
265 break;
266 case 34: /* Blue */
267 attr &= ~FOREGROUND_ALL;
268 attr |= FOREGROUND_BLUE;
269 break;
270 case 35: /* Magenta */
271 attr &= ~FOREGROUND_ALL;
272 attr |= FOREGROUND_RED | FOREGROUND_BLUE;
273 break;
274 case 36: /* Cyan */
275 attr &= ~FOREGROUND_ALL;
276 attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
277 break;
278 case 37: /* White */
279 attr |= FOREGROUND_RED |
280 FOREGROUND_GREEN |
281 FOREGROUND_BLUE;
282 break;
283 case 38: /* Unknown */
284 break;
285 case 39: /* reset */
286 attr &= ~FOREGROUND_ALL;
287 attr |= (plain_attr & FOREGROUND_ALL);
288 break;
289 case 40: /* Black */
290 attr &= ~BACKGROUND_ALL;
291 break;
292 case 41: /* Red */
293 attr &= ~BACKGROUND_ALL;
294 attr |= BACKGROUND_RED;
295 break;
296 case 42: /* Green */
297 attr &= ~BACKGROUND_ALL;
298 attr |= BACKGROUND_GREEN;
299 break;
300 case 43: /* Yellow */
301 attr &= ~BACKGROUND_ALL;
302 attr |= BACKGROUND_RED | BACKGROUND_GREEN;
303 break;
304 case 44: /* Blue */
305 attr &= ~BACKGROUND_ALL;
306 attr |= BACKGROUND_BLUE;
307 break;
308 case 45: /* Magenta */
309 attr &= ~BACKGROUND_ALL;
310 attr |= BACKGROUND_RED | BACKGROUND_BLUE;
311 break;
312 case 46: /* Cyan */
313 attr &= ~BACKGROUND_ALL;
314 attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
315 break;
316 case 47: /* White */
317 attr |= BACKGROUND_RED |
318 BACKGROUND_GREEN |
319 BACKGROUND_BLUE;
320 break;
321 case 48: /* Unknown */
322 break;
323 case 49: /* reset */
324 attr &= ~BACKGROUND_ALL;
325 attr |= (plain_attr & BACKGROUND_ALL);
326 break;
327 default:
328 /* Unsupported code */
329 break;
330 }
331 str++;
332 } while (*(str-1) == ';');
333
334 set_console_attr();
335 break;
336 case 'A': /* up */
337 move_cursor_row(-strtol(str, (char **)&str, 10));
338 break;
339 case 'B': /* down */
340 move_cursor_row(strtol(str, (char **)&str, 10));
341 break;
342 case 'C': /* forward */
343 move_cursor_column(strtol(str, (char **)&str, 10));
344 break;
345 case 'D': /* back */
346 move_cursor_column(-strtol(str, (char **)&str, 10));
347 break;
348 case 'H':
349 if (!len)
350 move_cursor(0, 0);
351 else {
352 int row, col = 1;
353
354 row = strtol(str, (char **)&str, 10);
355 if (*str == ';') {
356 col = strtol(str+1, (char **)&str, 10);
357 }
358 move_cursor(col > 0 ? col-1 : 0, row > 0 ? row-1 : 0);
359 }
360 break;
361 case 'J':
362 erase_till_end_of_screen();
363 break;
364 case 'K':
365 erase_in_line();
366 break;
367 case '?':
368 /* skip this to avoid ugliness when vi is shut down */
369 ++str;
370 while (isdigit(*str))
371 ++str;
372 func = str;
373 break;
374 default:
375 /* Unsupported code */
376 break;
377 }
378
379 return func + 1;
380}
381
382static int ansi_emulate(const char *s, FILE *stream)
383{
384 int rv = 0;
385 const char *t;
386 char *pos, *str;
387 size_t out_len, cur_len;
388 static size_t max_len = 0;
389 static char *mem = NULL;
390
391 /* if no special treatment is required output the string as-is */
392 for ( t=s; *t; ++t ) {
393 if ( *t == '\033' || *t > 0x7f ) {
394 break;
395 }
396 }
397
398 if ( *t == '\0' ) {
399 return fputs(s, stream) == EOF ? EOF : strlen(s);
400 }
401
402 /* make a writable copy of the string and retain it for reuse */
403 cur_len = strlen(s);
404 if ( cur_len == 0 || cur_len > max_len ) {
405 free(mem);
406 mem = strdup(s);
407 max_len = cur_len;
408 }
409 else {
410 strcpy(mem, s);
411 }
412 pos = str = mem;
413
414 while (*pos) {
415 pos = strstr(str, "\033[");
416 if (pos && !skip_ansi_emulation()) {
417 size_t len = pos - str;
418
419 if (len) {
420 CharToOemBuff(str, str, len);
421 out_len = fwrite(str, 1, len, stream);
422 rv += out_len;
423 if (out_len < len)
424 return rv;
425 }
426
427 str = pos + 2;
428 rv += 2;
429
430 fflush(stream);
431
432 pos = (char *)set_attr(str);
433 rv += pos - str;
434 str = pos;
435 } else {
436 rv += strlen(str);
437 CharToOem(str, str);
438 fputs(str, stream);
439 return rv;
440 }
441 }
442 return rv;
443}
444
445int winansi_putchar(int c)
446{
447 char t = c;
448 char *s = &t;
449
450 if (!isatty(STDOUT_FILENO))
451 return putchar(c);
452
453 init();
454
455 if (!console)
456 return putchar(c);
457
458 CharToOemBuff(s, s, 1);
459 return putchar(t) == EOF ? EOF : c;
460}
461
462int winansi_puts(const char *s)
463{
464 int rv;
465
466 if (!isatty(STDOUT_FILENO))
467 return puts(s);
468
469 init();
470
471 if (!console)
472 return puts(s);
473
474 rv = ansi_emulate(s, stdout);
475 putchar('\n');
476
477 return rv;
478}
479
480size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
481{
482 size_t lsize, lmemb;
483 char *str;
484 int rv;
485
486 lsize = MIN(size, nmemb);
487 lmemb = MAX(size, nmemb);
488 if (lsize != 1)
489 return fwrite(ptr, size, nmemb, stream);
490
491 if (!isatty(fileno(stream)))
492 return fwrite(ptr, size, nmemb, stream);
493
494 init();
495
496 if (!console)
497 return fwrite(ptr, size, nmemb, stream);
498
499 str = xmalloc(lmemb+1);
500 memcpy(str, ptr, lmemb);
501 str[lmemb] = '\0';
502
503 rv = ansi_emulate(str, stream);
504 free(str);
505
506 return rv;
507}
508
509int winansi_fputs(const char *str, FILE *stream)
510{
511 int rv;
512
513 if (!isatty(fileno(stream)))
514 return fputs(str, stream);
515
516 init();
517
518 if (!console)
519 return fputs(str, stream);
520
521 rv = ansi_emulate(str, stream);
522
523 if (rv >= 0)
524 return 0;
525 else
526 return EOF;
527}
528
529int winansi_vfprintf(FILE *stream, const char *format, va_list list)
530{
531 int len, rv;
532 char small_buf[256];
533 char *buf = small_buf;
534 va_list cp;
535
536 if (!isatty(fileno(stream)))
537 goto abort;
538
539 init();
540
541 if (!console)
542 goto abort;
543
544 va_copy(cp, list);
545 len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
546 va_end(cp);
547
548 if (len > sizeof(small_buf) - 1) {
549 buf = malloc(len + 1);
550 if (!buf)
551 goto abort;
552
553 va_copy(cp, list);
554 len = vsnprintf(buf, len + 1, format, cp);
555 va_end(cp);
556 }
557
558 if (len == -1)
559 goto abort;
560
561 rv = ansi_emulate(buf, stream);
562
563 if (buf != small_buf)
564 free(buf);
565 return rv;
566
567abort:
568 rv = vfprintf(stream, format, list);
569 return rv;
570}
571
572int winansi_fprintf(FILE *stream, const char *format, ...)
573{
574 va_list list;
575 int rv;
576
577 va_start(list, format);
578 rv = winansi_vfprintf(stream, format, list);
579 va_end(list);
580
581 return rv;
582}
583
584int winansi_printf(const char *format, ...)
585{
586 va_list list;
587 int rv;
588
589 va_start(list, format);
590 rv = winansi_vfprintf(stdout, format, list);
591 va_end(list);
592
593 return rv;
594}
595
596int winansi_get_terminal_width_height(struct winsize *win)
597{
598 BOOL ret;
599 CONSOLE_SCREEN_BUFFER_INFO sbi;
600
601 init();
602
603 win->ws_row = 0;
604 win->ws_col = 0;
605 if ((ret=GetConsoleScreenBufferInfo(console, &sbi)) != 0) {
606 win->ws_row = sbi.srWindow.Bottom - sbi.srWindow.Top + 1;
607 win->ws_col = sbi.srWindow.Right - sbi.srWindow.Left + 1;
608 }
609
610 return ret ? 0 : -1;
611}
612
613static int ansi_emulate_write(int fd, const void *buf, size_t count)
614{
615 int rv = 0, i;
616 int special = FALSE, has_null = FALSE;
617 const char *s = (const char *)buf;
618 char *pos, *str;
619 size_t len, out_len;
620 static size_t max_len = 0;
621 static char *mem = NULL;
622
623 for ( i=0; i<count; ++i ) {
624 if ( s[i] == '\033' || s[i] > 0x7f ) {
625 special = TRUE;
626 }
627 else if ( !s[i] ) {
628 has_null = TRUE;
629 }
630 }
631
632 /*
633 * If no special treatment is required or the data contains NUL
634 * characters output the string as-is.
635 */
636 if ( !special || has_null ) {
637 return write(fd, buf, count);
638 }
639
640 /* make a writable copy of the data and retain it for reuse */
641 if ( count > max_len ) {
642 free(mem);
643 mem = malloc(count+1);
644 max_len = count;
645 }
646 memcpy(mem, buf, count);
647 mem[count] = '\0';
648 pos = str = mem;
649
650 /* we've checked the data doesn't contain any NULs */
651 while (*pos) {
652 pos = strstr(str, "\033[");
653 if (pos && !skip_ansi_emulation()) {
654 len = pos - str;
655
656 if (len) {
657 CharToOemBuff(str, str, len);
658 out_len = write(fd, str, len);
659 rv += out_len;
660 if (out_len < len)
661 return rv;
662 }
663
664 str = pos + 2;
665 rv += 2;
666
667 pos = (char *)set_attr(str);
668 rv += pos - str;
669 str = pos;
670 } else {
671 len = strlen(str);
672 rv += len;
673 CharToOem(str, str);
674 write(fd, str, len);
675 return rv;
676 }
677 }
678 return rv;
679}
680
681int winansi_write(int fd, const void *buf, size_t count)
682{
683 if (!isatty(fd))
684 return write(fd, buf, count);
685
686 init();
687
688 if (!console)
689 return write(fd, buf, count);
690
691 return ansi_emulate_write(fd, buf, count);
692}
693
694int winansi_read(int fd, void *buf, size_t count)
695{
696 int rv;
697
698 rv = read(fd, buf, count);
699 if (!isatty(fd))
700 return rv;
701
702 init();
703
704 if (!console_in)
705 return rv;
706
707 if ( rv > 0 ) {
708 OemToCharBuff(buf, buf, rv);
709 }
710
711 return rv;
712}
713
714int winansi_getc(FILE *stream)
715{
716 int rv;
717
718 rv = getc(stream);
719 if (!isatty(fileno(stream)))
720 return rv;
721
722 init();
723
724 if (!console_in)
725 return rv;
726
727 if ( rv != EOF ) {
728 unsigned char c = (unsigned char)rv;
729 char *s = (char *)&c;
730 OemToCharBuff(s, s, 1);
731 rv = (int)c;
732 }
733
734 return rv;
735}