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.c3
-rw-r--r--configs/mingw32_defconfig1119
-rw-r--r--configs/mingw64_defconfig1119
-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.c20
-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.h43
-rw-r--r--include/mingw.h483
-rw-r--r--include/platform.h40
-rw-r--r--libbb/Kbuild.src21
-rw-r--r--libbb/appletlib.c92
-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.c126
-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.c1391
-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.c439
-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/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.c77
-rw-r--r--win32/termios.c83
-rw-r--r--win32/termios.h129
-rw-r--r--win32/uname.c48
-rw-r--r--win32/winansi.c735
129 files changed, 22907 insertions, 183 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 cf72287be..0353a0525 100644
--- a/Config.in
+++ b/Config.in
@@ -9,6 +9,20 @@ config HAVE_DOT_CONFIG
9 bool 9 bool
10 default y 10 default y
11 11
12choice
13 prompt "Target platform"
14 default PLATFORM_POSIX
15 help
16 Target platform you are building busybox for
17
18config PLATFORM_POSIX
19 bool "POSIX"
20
21config PLATFORM_MINGW32
22 bool "MS Windows (MinGW port)"
23
24endchoice
25
12menu "Busybox Settings" 26menu "Busybox Settings"
13 27
14config DESKTOP 28config DESKTOP
@@ -98,6 +112,28 @@ config LFS
98 cp, mount, tar, and many others. If you want to access files larger 112 cp, mount, tar, and many others. If you want to access files larger
99 than 2 Gigabytes, enable this option. 113 than 2 Gigabytes, enable this option.
100 114
115config GLOBBING
116 bool "Allow busybox.exe to expand wildcards"
117 default n
118 depends on PLATFORM_MINGW32
119 help
120 In Microsoft Windows expansion of wildcards on the command line
121 ('globbing') is handled by the C runtime while the BusyBox shell
122 does its own wildcard expansion. For best results when using the
123 shell globbing by the C runtime should be turned off. If you want
124 the BusyBox binary to handle wildcard expansion using the C runtime
125 set this to 'Y'.
126
127config SAFE_ENV
128 bool "Manipulate the environment through safe API calls"
129 default n
130 depends on PLATFORM_MINGW32
131 help
132 Enable this option to use safe API calls when clearing environment
133 variables. This is necessary if BusyBox is to run on ReactOS or
134 64-bit Windows. The default is 'N', which must be used if BusyBox
135 is to run on Windows XP.
136
101config PAM 137config PAM
102 bool "Support PAM (Pluggable Authentication Modules)" 138 bool "Support PAM (Pluggable Authentication Modules)"
103 default n 139 default n
diff --git a/Makefile b/Makefile
index 0a5f86929..8f3bc7ec0 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 d119c75ad..f9f712fde 100644
--- a/archival/ar.c
+++ b/archival/ar.c
@@ -165,6 +165,7 @@ static int write_ar_archive(archive_handle_t *handle)
165{ 165{
166 struct stat st; 166 struct stat st;
167 archive_handle_t *out_handle; 167 archive_handle_t *out_handle;
168 char *temp_fn = NULL;
168 169
169 xfstat(handle->src_fd, &st, handle->ar__name); 170 xfstat(handle->src_fd, &st, handle->ar__name);
170 171
@@ -173,8 +174,14 @@ static int write_ar_archive(archive_handle_t *handle)
173 */ 174 */
174 if (st.st_size != 0) { 175 if (st.st_size != 0) {
175 out_handle = init_handle(); 176 out_handle = init_handle();
177#if !ENABLE_PLATFORM_MINGW32
176 xunlink(handle->ar__name); 178 xunlink(handle->ar__name);
177 out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC); 179 out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC);
180#else
181 /* can't unlink open file, create temporary output file */
182 temp_fn = xasprintf("%sXXXXXX", handle->ar__name);
183 out_handle->src_fd = xmkstemp(temp_fn);
184#endif
178 out_handle->accept = handle->accept; 185 out_handle->accept = handle->accept;
179 } else { 186 } else {
180 out_handle = handle; 187 out_handle = handle;
@@ -196,12 +203,19 @@ static int write_ar_archive(archive_handle_t *handle)
196 continue; 203 continue;
197 204
198 /* optional, since we exit right after we return */ 205 /* optional, since we exit right after we return */
199 if (ENABLE_FEATURE_CLEAN_UP) { 206 if (ENABLE_FEATURE_CLEAN_UP || ENABLE_PLATFORM_MINGW32) {
200 close(handle->src_fd); 207 close(handle->src_fd);
201 if (out_handle->src_fd != handle->src_fd) 208 if (out_handle->src_fd != handle->src_fd)
202 close(out_handle->src_fd); 209 close(out_handle->src_fd);
203 } 210 }
204 211
212#if ENABLE_PLATFORM_MINGW32
213 if ( temp_fn != NULL ) {
214 xrename(temp_fn, handle->ar__name);
215 free(temp_fn);
216 }
217#endif
218
205 return EXIT_SUCCESS; 219 return EXIT_SUCCESS;
206} 220}
207#endif /* FEATURE_AR_CREATE */ 221#endif /* FEATURE_AR_CREATE */
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index b3b85b5d9..1e3d6e586 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 7598b71e3..c11b735d5 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -543,6 +543,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
543 } 543 }
544 } 544 }
545 545
546#if !ENABLE_PLATFORM_MINGW32
546 /* It is a bad idea to store the archive we are in the process of creating, 547 /* It is a bad idea to store the archive we are in the process of creating,
547 * so check the device and inode to be sure that this particular file isn't 548 * so check the device and inode to be sure that this particular file isn't
548 * the new tarball */ 549 * the new tarball */
@@ -552,6 +553,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
552 bb_error_msg("%s: file is the archive; skipping", fileName); 553 bb_error_msg("%s: file is the archive; skipping", fileName);
553 return TRUE; 554 return TRUE;
554 } 555 }
556#endif
555 557
556 if (exclude_file(tbInfo->excludeList, header_name)) 558 if (exclude_file(tbInfo->excludeList, header_name))
557 return SKIP; 559 return SKIP;
@@ -609,6 +611,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
609} 611}
610 612
611#if SEAMLESS_COMPRESSION 613#if SEAMLESS_COMPRESSION
614#if !ENABLE_PLATFORM_MINGW32
612/* Don't inline: vfork scares gcc and pessimizes code */ 615/* Don't inline: vfork scares gcc and pessimizes code */
613static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) 616static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
614{ 617{
@@ -668,6 +671,27 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
668 bb_perror_msg_and_die("can't execute '%s'", gzip); 671 bb_perror_msg_and_die("can't execute '%s'", gzip);
669 } 672 }
670} 673}
674#else
675static pid_t vfork_compressor(int tar_fd, const char *gzip)
676{
677 char *cmd;
678 int fd1;
679 pid_t pid;
680
681 if (find_applet_by_name(gzip) >= 0) {
682 cmd = xasprintf("%s --busybox %s -cf -", bb_busybox_exec_path, gzip);
683 }
684 else {
685 cmd = xasprintf("%s -cf -", gzip);
686 }
687 if ( (fd1=mingw_popen_fd(cmd, "w", tar_fd, &pid)) == -1 ) {
688 bb_perror_msg_and_die("can't execute '%s'", gzip);
689 }
690 free(cmd);
691 xmove_fd(fd1, tar_fd);
692 return pid;
693}
694#endif /* ENABLE_PLATFORM_MINGW32 */
671#endif /* SEAMLESS_COMPRESSION */ 695#endif /* SEAMLESS_COMPRESSION */
672 696
673 697
@@ -683,6 +707,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
683{ 707{
684 int errorFlag = FALSE; 708 int errorFlag = FALSE;
685 struct TarBallInfo tbInfo; 709 struct TarBallInfo tbInfo;
710 IF_PLATFORM_MINGW32(pid_t pid = 0;)
686 711
687 tbInfo.hlInfoHead = NULL; 712 tbInfo.hlInfoHead = NULL;
688 tbInfo.tarFd = tar_fd; 713 tbInfo.tarFd = tar_fd;
@@ -694,7 +719,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
694 719
695#if SEAMLESS_COMPRESSION 720#if SEAMLESS_COMPRESSION
696 if (gzip) 721 if (gzip)
697 vfork_compressor(tbInfo.tarFd, gzip); 722 IF_PLATFORM_MINGW32(pid = )vfork_compressor(tbInfo.tarFd, gzip);
698#endif 723#endif
699 724
700 tbInfo.excludeList = exclude; 725 tbInfo.excludeList = exclude;
@@ -730,7 +755,11 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
730#if SEAMLESS_COMPRESSION 755#if SEAMLESS_COMPRESSION
731 if (gzip) { 756 if (gzip) {
732 int status; 757 int status;
758#if !ENABLE_PLATFORM_MINGW32
733 if (safe_waitpid(-1, &status, 0) == -1) 759 if (safe_waitpid(-1, &status, 0) == -1)
760#else
761 if (safe_waitpid(pid, &status, 0) == -1)
762#endif
734 bb_perror_msg("waitpid"); 763 bb_perror_msg("waitpid");
735 else if (!WIFEXITED(status) || WEXITSTATUS(status)) 764 else if (!WIFEXITED(status) || WEXITSTATUS(status))
736 /* gzip was killed or has exited with nonzero! */ 765 /* gzip was killed or has exited with nonzero! */
diff --git a/archival/unzip.c b/archival/unzip.c
index 488dcf31d..8dfc4e678 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -69,6 +69,9 @@
69 69
70#include "libbb.h" 70#include "libbb.h"
71#include "bb_archive.h" 71#include "bb_archive.h"
72#if ENABLE_PLATFORM_MINGW32 && __GNUC__
73#pragma pack(2)
74#endif
72 75
73#if 0 76#if 0
74# define dbg(...) bb_error_msg(__VA_ARGS__) 77# define dbg(...) bb_error_msg(__VA_ARGS__)
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
new file mode 100644
index 000000000..48e90e527
--- /dev/null
+++ b/configs/mingw32_defconfig
@@ -0,0 +1,1119 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.27.0.git
4# Mon May 29 14:39:07 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_USE_PORTABLE_CODE=y
17CONFIG_SHOW_USAGE=y
18CONFIG_FEATURE_VERBOSE_USAGE=y
19CONFIG_FEATURE_COMPRESS_USAGE=y
20CONFIG_BUSYBOX=y
21CONFIG_FEATURE_INSTALLER=y
22# CONFIG_INSTALL_NO_USR is not set
23# CONFIG_PAM is not set
24CONFIG_LONG_OPTS=y
25# CONFIG_FEATURE_DEVPTS is not set
26# CONFIG_FEATURE_CLEAN_UP is not set
27# CONFIG_FEATURE_UTMP is not set
28# CONFIG_FEATURE_WTMP is not set
29# CONFIG_FEATURE_PIDFILE is not set
30CONFIG_PID_FILE_PATH=""
31# CONFIG_FEATURE_SUID is not set
32# CONFIG_FEATURE_SUID_CONFIG is not set
33# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
34# CONFIG_SELINUX is not set
35CONFIG_FEATURE_PREFER_APPLETS=y
36CONFIG_BUSYBOX_EXEC_PATH=""
37# CONFIG_FEATURE_SYSLOG is not set
38# CONFIG_FEATURE_HAVE_RPC is not set
39# CONFIG_PLATFORM_LINUX is not set
40
41#
42# Build Options
43#
44# CONFIG_STATIC is not set
45# CONFIG_PIE is not set
46# CONFIG_NOMMU is not set
47# CONFIG_BUILD_LIBBUSYBOX is not set
48# CONFIG_FEATURE_INDIVIDUAL is not set
49# CONFIG_FEATURE_SHARED_BUSYBOX is not set
50CONFIG_LFS=y
51# CONFIG_GLOBBING is not set
52# CONFIG_SAFE_ENV is not set
53CONFIG_CROSS_COMPILER_PREFIX="i686-w64-mingw32-"
54CONFIG_SYSROOT=""
55CONFIG_EXTRA_CFLAGS=""
56CONFIG_EXTRA_LDFLAGS=""
57CONFIG_EXTRA_LDLIBS=""
58
59#
60# Installation Options ("make install" behavior)
61#
62CONFIG_INSTALL_APPLET_SYMLINKS=y
63# CONFIG_INSTALL_APPLET_HARDLINKS is not set
64# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
65# CONFIG_INSTALL_APPLET_DONT is not set
66# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
67# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
68# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
69CONFIG_PREFIX=""
70
71#
72# Debugging Options
73#
74CONFIG_DEBUG=y
75# CONFIG_DEBUG_PESSIMIZE is not set
76# CONFIG_DEBUG_SANITIZE is not set
77# CONFIG_UNIT_TEST is not set
78# CONFIG_WERROR is not set
79CONFIG_NO_DEBUG_LIB=y
80# CONFIG_DMALLOC is not set
81# CONFIG_EFENCE is not set
82
83#
84# Busybox Library Tuning
85#
86# CONFIG_FEATURE_USE_BSS_TAIL is not set
87CONFIG_FEATURE_RTMINMAX=y
88CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
89# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
90# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
91CONFIG_PASSWORD_MINLEN=6
92CONFIG_MD5_SMALL=1
93CONFIG_SHA3_SMALL=1
94# CONFIG_FEATURE_FAST_TOP is not set
95# CONFIG_FEATURE_ETC_NETWORKS is not set
96CONFIG_FEATURE_EDITING=y
97CONFIG_FEATURE_EDITING_MAX_LEN=1024
98CONFIG_FEATURE_EDITING_VI=y
99CONFIG_FEATURE_EDITING_HISTORY=255
100CONFIG_FEATURE_EDITING_SAVEHISTORY=y
101# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
102CONFIG_FEATURE_REVERSE_SEARCH=y
103CONFIG_FEATURE_TAB_COMPLETION=y
104CONFIG_FEATURE_USERNAME_COMPLETION=y
105CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
106# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
107# CONFIG_LOCALE_SUPPORT is not set
108# CONFIG_UNICODE_SUPPORT is not set
109# CONFIG_UNICODE_USING_LOCALE is not set
110# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
111CONFIG_SUBST_WCHAR=0
112CONFIG_LAST_SUPPORTED_WCHAR=0
113# CONFIG_UNICODE_COMBINING_WCHARS is not set
114# CONFIG_UNICODE_WIDE_WCHARS is not set
115# CONFIG_UNICODE_BIDI_SUPPORT is not set
116# CONFIG_UNICODE_NEUTRAL_TABLE is not set
117# CONFIG_UNICODE_PRESERVE_BROKEN is not set
118CONFIG_FEATURE_NON_POSIX_CP=y
119# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
120# CONFIG_FEATURE_USE_SENDFILE is not set
121CONFIG_FEATURE_COPYBUF_KB=4
122CONFIG_FEATURE_SKIP_ROOTFS=y
123# CONFIG_MONOTONIC_SYSCALL is not set
124CONFIG_IOCTL_HEX2STR_ERROR=y
125# CONFIG_FEATURE_HWIB is not set
126
127#
128# Applets
129#
130
131#
132# Archival Utilities
133#
134CONFIG_FEATURE_SEAMLESS_XZ=y
135CONFIG_FEATURE_SEAMLESS_LZMA=y
136CONFIG_FEATURE_SEAMLESS_BZ2=y
137CONFIG_FEATURE_SEAMLESS_GZ=y
138CONFIG_FEATURE_SEAMLESS_Z=y
139CONFIG_AR=y
140CONFIG_FEATURE_AR_LONG_FILENAMES=y
141CONFIG_FEATURE_AR_CREATE=y
142CONFIG_UNCOMPRESS=y
143CONFIG_GUNZIP=y
144CONFIG_ZCAT=y
145CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
146CONFIG_BUNZIP2=y
147CONFIG_BZCAT=y
148CONFIG_UNLZMA=y
149CONFIG_LZCAT=y
150CONFIG_LZMA=y
151CONFIG_FEATURE_LZMA_FAST=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
190
191#
192# Coreutils
193#
194CONFIG_BASENAME=y
195CONFIG_CAT=y
196CONFIG_FEATURE_CATV=y
197# CONFIG_CHGRP is not set
198CONFIG_CHMOD=y
199# CONFIG_CHOWN is not set
200# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
201# CONFIG_CHROOT is not set
202CONFIG_CKSUM=y
203CONFIG_COMM=y
204CONFIG_CP=y
205CONFIG_FEATURE_CP_LONG_OPTIONS=y
206CONFIG_CUT=y
207CONFIG_DATE=y
208CONFIG_FEATURE_DATE_ISOFMT=y
209# CONFIG_FEATURE_DATE_NANO is not set
210CONFIG_FEATURE_DATE_COMPAT=y
211CONFIG_DD=y
212# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
213# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
214CONFIG_FEATURE_DD_IBS_OBS=y
215CONFIG_FEATURE_DD_STATUS=y
216CONFIG_DF=y
217# CONFIG_FEATURE_DF_FANCY is not set
218CONFIG_DIRNAME=y
219CONFIG_DOS2UNIX=y
220CONFIG_UNIX2DOS=y
221CONFIG_DU=y
222CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
223CONFIG_ECHO=y
224CONFIG_FEATURE_FANCY_ECHO=y
225CONFIG_ENV=y
226CONFIG_FEATURE_ENV_LONG_OPTIONS=y
227CONFIG_EXPAND=y
228CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
229CONFIG_UNEXPAND=y
230CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
231CONFIG_EXPR=y
232CONFIG_EXPR_MATH_SUPPORT_64=y
233CONFIG_FACTOR=y
234CONFIG_FALSE=y
235CONFIG_FOLD=y
236# CONFIG_FSYNC is not set
237CONFIG_HEAD=y
238CONFIG_FEATURE_FANCY_HEAD=y
239# CONFIG_HOSTID is not set
240CONFIG_ID=y
241CONFIG_GROUPS=y
242# CONFIG_INSTALL is not set
243# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
244CONFIG_LINK=y
245CONFIG_LN=y
246CONFIG_LOGNAME=y
247CONFIG_LS=y
248CONFIG_FEATURE_LS_FILETYPES=y
249CONFIG_FEATURE_LS_FOLLOWLINKS=y
250CONFIG_FEATURE_LS_RECURSIVE=y
251CONFIG_FEATURE_LS_WIDTH=y
252CONFIG_FEATURE_LS_SORTFILES=y
253CONFIG_FEATURE_LS_TIMESTAMPS=y
254CONFIG_FEATURE_LS_USERNAME=y
255CONFIG_FEATURE_LS_COLOR=y
256CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
257CONFIG_MD5SUM=y
258CONFIG_SHA1SUM=y
259CONFIG_SHA256SUM=y
260CONFIG_SHA512SUM=y
261CONFIG_SHA3SUM=y
262
263#
264# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
265#
266CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
267CONFIG_MKDIR=y
268CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
269# CONFIG_MKFIFO is not set
270# CONFIG_MKNOD is not set
271CONFIG_MKTEMP=y
272CONFIG_MV=y
273CONFIG_FEATURE_MV_LONG_OPTIONS=y
274# CONFIG_NICE is not set
275CONFIG_NL=y
276# CONFIG_NOHUP is not set
277# CONFIG_NPROC is not set
278CONFIG_OD=y
279CONFIG_PASTE=y
280CONFIG_PRINTENV=y
281CONFIG_PRINTF=y
282CONFIG_PWD=y
283# CONFIG_READLINK is not set
284# CONFIG_FEATURE_READLINK_FOLLOW is not set
285# CONFIG_REALPATH is not set
286CONFIG_RM=y
287CONFIG_RMDIR=y
288CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
289CONFIG_SEQ=y
290# CONFIG_SHRED is not set
291CONFIG_SHUF=y
292CONFIG_SLEEP=y
293CONFIG_FEATURE_FANCY_SLEEP=y
294CONFIG_FEATURE_FLOAT_SLEEP=y
295CONFIG_SORT=y
296CONFIG_FEATURE_SORT_BIG=y
297CONFIG_SPLIT=y
298CONFIG_FEATURE_SPLIT_FANCY=y
299CONFIG_STAT=y
300CONFIG_FEATURE_STAT_FORMAT=y
301CONFIG_FEATURE_STAT_FILESYSTEM=y
302# CONFIG_STTY is not set
303CONFIG_SUM=y
304# CONFIG_SYNC is not set
305# CONFIG_FEATURE_SYNC_FANCY is not set
306CONFIG_TAC=y
307CONFIG_TAIL=y
308CONFIG_FEATURE_FANCY_TAIL=y
309CONFIG_TEE=y
310CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
311CONFIG_TEST=y
312CONFIG_TEST1=y
313CONFIG_TEST2=y
314CONFIG_FEATURE_TEST_64=y
315# CONFIG_TIMEOUT is not set
316CONFIG_TOUCH=y
317# CONFIG_FEATURE_TOUCH_NODEREF is not set
318CONFIG_FEATURE_TOUCH_SUSV3=y
319CONFIG_TR=y
320CONFIG_FEATURE_TR_CLASSES=y
321CONFIG_FEATURE_TR_EQUIV=y
322CONFIG_TRUE=y
323CONFIG_TRUNCATE=y
324# CONFIG_TTY is not set
325CONFIG_UNAME=y
326CONFIG_UNAME_OSNAME="MS/Windows"
327CONFIG_UNIQ=y
328CONFIG_UNLINK=y
329CONFIG_USLEEP=y
330CONFIG_UUDECODE=y
331CONFIG_BASE64=y
332CONFIG_UUENCODE=y
333CONFIG_WC=y
334CONFIG_FEATURE_WC_LARGE=y
335CONFIG_WHOAMI=y
336# CONFIG_WHO is not set
337# CONFIG_W is not set
338# CONFIG_USERS is not set
339CONFIG_YES=y
340
341#
342# Common options
343#
344CONFIG_FEATURE_VERBOSE=y
345
346#
347# Common options for cp and mv
348#
349# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
350
351#
352# Common options for df, du, ls
353#
354CONFIG_FEATURE_HUMAN_READABLE=y
355
356#
357# Console Utilities
358#
359# CONFIG_CHVT is not set
360CONFIG_CLEAR=y
361# CONFIG_DEALLOCVT is not set
362# CONFIG_DUMPKMAP is not set
363# CONFIG_FGCONSOLE is not set
364# CONFIG_KBD_MODE is not set
365# CONFIG_LOADFONT is not set
366# CONFIG_SETFONT is not set
367# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
368CONFIG_DEFAULT_SETFONT_DIR=""
369# CONFIG_FEATURE_LOADFONT_PSF2 is not set
370# CONFIG_FEATURE_LOADFONT_RAW is not set
371# CONFIG_LOADKMAP is not set
372# CONFIG_OPENVT is not set
373# CONFIG_RESET is not set
374# CONFIG_RESIZE is not set
375# CONFIG_FEATURE_RESIZE_PRINT is not set
376# CONFIG_SETCONSOLE is not set
377# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
378# CONFIG_SETKEYCODES is not set
379# CONFIG_SETLOGCONS is not set
380# CONFIG_SHOWKEY is not set
381
382#
383# Debian Utilities
384#
385# CONFIG_PIPE_PROGRESS is not set
386# CONFIG_RUN_PARTS is not set
387# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
388# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
389# CONFIG_START_STOP_DAEMON is not set
390# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
391# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
392CONFIG_WHICH=y
393
394#
395# Editors
396#
397CONFIG_AWK=y
398CONFIG_FEATURE_AWK_LIBM=y
399CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
400CONFIG_CMP=y
401CONFIG_DIFF=y
402CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
403CONFIG_FEATURE_DIFF_DIR=y
404CONFIG_ED=y
405CONFIG_PATCH=y
406CONFIG_SED=y
407CONFIG_VI=y
408CONFIG_FEATURE_VI_MAX_LEN=4096
409CONFIG_FEATURE_VI_8BIT=y
410CONFIG_FEATURE_VI_COLON=y
411CONFIG_FEATURE_VI_YANKMARK=y
412CONFIG_FEATURE_VI_SEARCH=y
413# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
414# CONFIG_FEATURE_VI_USE_SIGNALS is not set
415CONFIG_FEATURE_VI_DOT_CMD=y
416CONFIG_FEATURE_VI_READONLY=y
417CONFIG_FEATURE_VI_SETOPTS=y
418CONFIG_FEATURE_VI_SET=y
419CONFIG_FEATURE_VI_WIN_RESIZE=y
420CONFIG_FEATURE_VI_ASK_TERMINAL=y
421CONFIG_FEATURE_VI_UNDO=y
422CONFIG_FEATURE_VI_UNDO_QUEUE=y
423CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
424CONFIG_FEATURE_ALLOW_EXEC=y
425
426#
427# Finding Utilities
428#
429CONFIG_FIND=y
430CONFIG_FEATURE_FIND_PRINT0=y
431CONFIG_FEATURE_FIND_MTIME=y
432CONFIG_FEATURE_FIND_MMIN=y
433CONFIG_FEATURE_FIND_PERM=y
434CONFIG_FEATURE_FIND_TYPE=y
435# CONFIG_FEATURE_FIND_XDEV is not set
436CONFIG_FEATURE_FIND_MAXDEPTH=y
437CONFIG_FEATURE_FIND_NEWER=y
438# CONFIG_FEATURE_FIND_INUM is not set
439# CONFIG_FEATURE_FIND_EXEC is not set
440# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
441# CONFIG_FEATURE_FIND_USER is not set
442# CONFIG_FEATURE_FIND_GROUP is not set
443CONFIG_FEATURE_FIND_NOT=y
444CONFIG_FEATURE_FIND_DEPTH=y
445CONFIG_FEATURE_FIND_PAREN=y
446CONFIG_FEATURE_FIND_SIZE=y
447CONFIG_FEATURE_FIND_PRUNE=y
448CONFIG_FEATURE_FIND_DELETE=y
449CONFIG_FEATURE_FIND_PATH=y
450CONFIG_FEATURE_FIND_REGEX=y
451# CONFIG_FEATURE_FIND_CONTEXT is not set
452# CONFIG_FEATURE_FIND_LINKS is not set
453CONFIG_GREP=y
454CONFIG_EGREP=y
455CONFIG_FGREP=y
456CONFIG_FEATURE_GREP_CONTEXT=y
457CONFIG_XARGS=y
458CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
459CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
460CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
461CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
462CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
463
464#
465# Init Utilities
466#
467# CONFIG_BOOTCHARTD is not set
468# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
469# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
470# CONFIG_HALT is not set
471# CONFIG_POWEROFF is not set
472# CONFIG_REBOOT is not set
473# CONFIG_FEATURE_CALL_TELINIT is not set
474CONFIG_TELINIT_PATH=""
475# CONFIG_INIT is not set
476# CONFIG_LINUXRC is not set
477# CONFIG_FEATURE_USE_INITTAB is not set
478# CONFIG_FEATURE_KILL_REMOVED is not set
479CONFIG_FEATURE_KILL_DELAY=0
480# CONFIG_FEATURE_INIT_SCTTY is not set
481# CONFIG_FEATURE_INIT_SYSLOG is not set
482# CONFIG_FEATURE_INIT_QUIET is not set
483# CONFIG_FEATURE_INIT_COREDUMPS is not set
484CONFIG_INIT_TERMINAL_TYPE=""
485# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
486
487#
488# Login/Password Management Utilities
489#
490# CONFIG_FEATURE_SHADOWPASSWDS is not set
491# CONFIG_USE_BB_PWD_GRP is not set
492# CONFIG_USE_BB_SHADOW is not set
493# CONFIG_USE_BB_CRYPT is not set
494# CONFIG_USE_BB_CRYPT_SHA is not set
495# CONFIG_ADDGROUP is not set
496# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
497# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
498# CONFIG_ADD_SHELL is not set
499# CONFIG_REMOVE_SHELL is not set
500# CONFIG_ADDUSER is not set
501# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
502# CONFIG_FEATURE_CHECK_NAMES is not set
503CONFIG_LAST_ID=0
504CONFIG_FIRST_SYSTEM_ID=0
505CONFIG_LAST_SYSTEM_ID=0
506# CONFIG_CHPASSWD is not set
507CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
508# CONFIG_CRYPTPW is not set
509# CONFIG_MKPASSWD is not set
510# CONFIG_DELUSER is not set
511# CONFIG_DELGROUP is not set
512# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
513# CONFIG_GETTY is not set
514# CONFIG_LOGIN is not set
515# CONFIG_LOGIN_SESSION_AS_CHILD is not set
516# CONFIG_LOGIN_SCRIPTS is not set
517# CONFIG_FEATURE_NOLOGIN is not set
518# CONFIG_FEATURE_SECURETTY is not set
519# CONFIG_PASSWD is not set
520# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
521# CONFIG_SU is not set
522# CONFIG_FEATURE_SU_SYSLOG is not set
523# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
524# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
525# CONFIG_SULOGIN is not set
526# CONFIG_VLOCK is not set
527
528#
529# Linux Ext2 FS Progs
530#
531# CONFIG_CHATTR is not set
532# CONFIG_FSCK is not set
533# CONFIG_LSATTR is not set
534# CONFIG_TUNE2FS is not set
535
536#
537# Linux Module Utilities
538#
539# CONFIG_MODPROBE_SMALL is not set
540# CONFIG_DEPMOD is not set
541# CONFIG_INSMOD is not set
542# CONFIG_LSMOD is not set
543# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
544# CONFIG_MODINFO is not set
545# CONFIG_MODPROBE is not set
546# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
547# CONFIG_RMMOD is not set
548
549#
550# Options common to multiple modutils
551#
552# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
553# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
554# CONFIG_FEATURE_2_4_MODULES is not set
555# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
556# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
557# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
558# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
559# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
560# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
561# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
562# CONFIG_FEATURE_MODUTILS_ALIAS is not set
563# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
564CONFIG_DEFAULT_MODULES_DIR=""
565CONFIG_DEFAULT_DEPMOD_FILE=""
566
567#
568# Linux System Utilities
569#
570# CONFIG_ACPID is not set
571# CONFIG_FEATURE_ACPID_COMPAT is not set
572# CONFIG_BLKDISCARD is not set
573# CONFIG_BLKID is not set
574# CONFIG_FEATURE_BLKID_TYPE is not set
575# CONFIG_BLOCKDEV is not set
576CONFIG_CAL=y
577# CONFIG_CHRT is not set
578# CONFIG_DMESG is not set
579# CONFIG_FEATURE_DMESG_PRETTY is not set
580# CONFIG_EJECT is not set
581# CONFIG_FEATURE_EJECT_SCSI is not set
582# CONFIG_FALLOCATE is not set
583# CONFIG_FATATTR is not set
584# CONFIG_FBSET is not set
585# CONFIG_FEATURE_FBSET_FANCY is not set
586# CONFIG_FEATURE_FBSET_READMODE is not set
587# CONFIG_FDFORMAT is not set
588# CONFIG_FDISK is not set
589# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
590# CONFIG_FEATURE_FDISK_WRITABLE is not set
591# CONFIG_FEATURE_AIX_LABEL is not set
592# CONFIG_FEATURE_SGI_LABEL is not set
593# CONFIG_FEATURE_SUN_LABEL is not set
594# CONFIG_FEATURE_OSF_LABEL is not set
595# CONFIG_FEATURE_GPT_LABEL is not set
596# CONFIG_FEATURE_FDISK_ADVANCED is not set
597# CONFIG_FINDFS is not set
598# CONFIG_FLOCK is not set
599# CONFIG_FDFLUSH is not set
600# CONFIG_FREERAMDISK is not set
601# CONFIG_FSCK_MINIX is not set
602# CONFIG_FSFREEZE is not set
603# CONFIG_FSTRIM is not set
604CONFIG_GETOPT=y
605CONFIG_FEATURE_GETOPT_LONG=y
606CONFIG_HEXDUMP=y
607CONFIG_FEATURE_HEXDUMP_REVERSE=y
608CONFIG_HD=y
609CONFIG_XXD=y
610# CONFIG_HWCLOCK is not set
611# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
612# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
613# CONFIG_IONICE is not set
614# CONFIG_IPCRM is not set
615# CONFIG_IPCS is not set
616# CONFIG_LAST is not set
617# CONFIG_FEATURE_LAST_FANCY is not set
618# CONFIG_LOSETUP is not set
619# CONFIG_LSPCI is not set
620# CONFIG_LSUSB is not set
621# CONFIG_MDEV is not set
622# CONFIG_FEATURE_MDEV_CONF is not set
623# CONFIG_FEATURE_MDEV_RENAME is not set
624# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
625# CONFIG_FEATURE_MDEV_EXEC is not set
626# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
627# CONFIG_MESG is not set
628# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
629# CONFIG_MKE2FS is not set
630# CONFIG_MKFS_EXT2 is not set
631# CONFIG_MKFS_MINIX is not set
632# CONFIG_FEATURE_MINIX2 is not set
633# CONFIG_MKFS_REISER is not set
634# CONFIG_MKDOSFS is not set
635# CONFIG_MKFS_VFAT is not set
636# CONFIG_MKSWAP is not set
637# CONFIG_FEATURE_MKSWAP_UUID is not set
638# CONFIG_MORE is not set
639# CONFIG_MOUNT is not set
640# CONFIG_FEATURE_MOUNT_FAKE is not set
641# CONFIG_FEATURE_MOUNT_VERBOSE is not set
642# CONFIG_FEATURE_MOUNT_HELPERS is not set
643# CONFIG_FEATURE_MOUNT_LABEL is not set
644# CONFIG_FEATURE_MOUNT_NFS is not set
645# CONFIG_FEATURE_MOUNT_CIFS is not set
646# CONFIG_FEATURE_MOUNT_FLAGS is not set
647# CONFIG_FEATURE_MOUNT_FSTAB is not set
648# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
649# CONFIG_MOUNTPOINT is not set
650# CONFIG_NSENTER is not set
651# CONFIG_FEATURE_NSENTER_LONG_OPTS is not set
652# CONFIG_PIVOT_ROOT is not set
653# CONFIG_RDATE is not set
654# CONFIG_RDEV is not set
655# CONFIG_READPROFILE is not set
656# CONFIG_RENICE is not set
657CONFIG_REV=y
658# CONFIG_RTCWAKE is not set
659# CONFIG_SCRIPT is not set
660# CONFIG_SCRIPTREPLAY is not set
661# CONFIG_SETARCH is not set
662# CONFIG_LINUX32 is not set
663# CONFIG_LINUX64 is not set
664# CONFIG_SETSID is not set
665# CONFIG_SWAPON is not set
666# CONFIG_FEATURE_SWAPON_DISCARD is not set
667# CONFIG_FEATURE_SWAPON_PRI is not set
668# CONFIG_SWAPOFF is not set
669# CONFIG_SWITCH_ROOT is not set
670# CONFIG_TASKSET is not set
671# CONFIG_FEATURE_TASKSET_FANCY is not set
672# CONFIG_UEVENT is not set
673# CONFIG_UMOUNT is not set
674# CONFIG_FEATURE_UMOUNT_ALL is not set
675# CONFIG_UNSHARE is not set
676# CONFIG_WALL is not set
677# CONFIG_FEATURE_MOUNT_LOOP is not set
678# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
679# CONFIG_FEATURE_MTAB_SUPPORT is not set
680# CONFIG_VOLUMEID is not set
681# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
682# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
683# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
684# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
685# CONFIG_FEATURE_VOLUMEID_EXT is not set
686# CONFIG_FEATURE_VOLUMEID_F2FS is not set
687# CONFIG_FEATURE_VOLUMEID_FAT is not set
688# CONFIG_FEATURE_VOLUMEID_HFS is not set
689# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
690# CONFIG_FEATURE_VOLUMEID_JFS is not set
691# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
692# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
693# CONFIG_FEATURE_VOLUMEID_LUKS is not set
694# CONFIG_FEATURE_VOLUMEID_NILFS is not set
695# CONFIG_FEATURE_VOLUMEID_NTFS is not set
696# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
697# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
698# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
699# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
700# CONFIG_FEATURE_VOLUMEID_SYSV is not set
701# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
702# CONFIG_FEATURE_VOLUMEID_UDF is not set
703# CONFIG_FEATURE_VOLUMEID_XFS is not set
704
705#
706# Miscellaneous Utilities
707#
708# CONFIG_ADJTIMEX is not set
709# CONFIG_BBCONFIG is not set
710# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
711# CONFIG_BEEP is not set
712CONFIG_FEATURE_BEEP_FREQ=0
713CONFIG_FEATURE_BEEP_LENGTH_MS=0
714# CONFIG_CHAT is not set
715# CONFIG_FEATURE_CHAT_NOFAIL is not set
716# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
717# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
718# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
719# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
720# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
721# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
722# CONFIG_CONSPY is not set
723# CONFIG_CROND is not set
724# CONFIG_FEATURE_CROND_D is not set
725# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
726CONFIG_FEATURE_CROND_DIR=""
727# CONFIG_CRONTAB is not set
728CONFIG_DC=y
729CONFIG_FEATURE_DC_LIBM=y
730# CONFIG_DEVFSD is not set
731# CONFIG_DEVFSD_MODLOAD is not set
732# CONFIG_DEVFSD_FG_NP is not set
733# CONFIG_DEVFSD_VERBOSE is not set
734# CONFIG_FEATURE_DEVFS is not set
735# CONFIG_DEVMEM is not set
736# CONFIG_FBSPLASH is not set
737# CONFIG_FLASHCP is not set
738# CONFIG_FLASH_ERASEALL is not set
739# CONFIG_FLASH_LOCK is not set
740# CONFIG_FLASH_UNLOCK is not set
741# CONFIG_HDPARM is not set
742# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
743# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
744# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
745# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
746# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
747# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
748# CONFIG_I2CGET is not set
749# CONFIG_I2CSET is not set
750# CONFIG_I2CDUMP is not set
751# CONFIG_I2CDETECT is not set
752# CONFIG_INOTIFYD is not set
753CONFIG_LESS=y
754CONFIG_FEATURE_LESS_MAXLINES=9999999
755CONFIG_FEATURE_LESS_BRACKETS=y
756CONFIG_FEATURE_LESS_FLAGS=y
757CONFIG_FEATURE_LESS_TRUNCATE=y
758CONFIG_FEATURE_LESS_MARKS=y
759CONFIG_FEATURE_LESS_REGEXP=y
760# CONFIG_FEATURE_LESS_WINCH is not set
761# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
762CONFIG_FEATURE_LESS_DASHCMD=y
763CONFIG_FEATURE_LESS_LINENUMS=y
764# CONFIG_LSSCSI is not set
765# CONFIG_MAKEDEVS is not set
766# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
767# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
768CONFIG_MAN=y
769# CONFIG_MICROCOM is not set
770# CONFIG_MT is not set
771# CONFIG_NANDWRITE is not set
772# CONFIG_NANDDUMP is not set
773# CONFIG_PARTPROBE is not set
774# CONFIG_RAIDAUTORUN is not set
775# CONFIG_READAHEAD is not set
776# CONFIG_RFKILL is not set
777# CONFIG_RUNLEVEL is not set
778# CONFIG_RX is not set
779# CONFIG_SETSERIAL is not set
780CONFIG_STRINGS=y
781# CONFIG_TIME is not set
782# CONFIG_TTYSIZE is not set
783# CONFIG_UBIRENAME is not set
784# CONFIG_UBIATTACH is not set
785# CONFIG_UBIDETACH is not set
786# CONFIG_UBIMKVOL is not set
787# CONFIG_UBIRMVOL is not set
788# CONFIG_UBIRSVOL is not set
789# CONFIG_UBIUPDATEVOL is not set
790# CONFIG_VOLNAME is not set
791# CONFIG_WATCHDOG is not set
792
793#
794# Networking Utilities
795#
796CONFIG_FEATURE_IPV6=y
797# CONFIG_FEATURE_UNIX_LOCAL is not set
798CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
799# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
800# CONFIG_ARP is not set
801# CONFIG_ARPING is not set
802# CONFIG_BRCTL is not set
803# CONFIG_FEATURE_BRCTL_FANCY is not set
804# CONFIG_FEATURE_BRCTL_SHOW is not set
805# CONFIG_DNSD is not set
806# CONFIG_ETHER_WAKE is not set
807# CONFIG_FTPD is not set
808# CONFIG_FEATURE_FTPD_WRITE is not set
809# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
810# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
811CONFIG_FTPGET=y
812CONFIG_FTPPUT=y
813CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
814# CONFIG_HOSTNAME is not set
815# CONFIG_DNSDOMAINNAME is not set
816# CONFIG_HTTPD is not set
817# CONFIG_FEATURE_HTTPD_RANGES is not set
818# CONFIG_FEATURE_HTTPD_SETUID is not set
819# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
820# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
821# CONFIG_FEATURE_HTTPD_CGI is not set
822# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
823# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
824# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
825# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
826# CONFIG_FEATURE_HTTPD_PROXY is not set
827# CONFIG_FEATURE_HTTPD_GZIP is not set
828# CONFIG_IFCONFIG is not set
829# CONFIG_FEATURE_IFCONFIG_STATUS is not set
830# CONFIG_FEATURE_IFCONFIG_SLIP is not set
831# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
832# CONFIG_FEATURE_IFCONFIG_HW is not set
833# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
834# CONFIG_IFENSLAVE is not set
835# CONFIG_IFPLUGD is not set
836# CONFIG_IFUP is not set
837# CONFIG_IFDOWN is not set
838CONFIG_IFUPDOWN_IFSTATE_PATH=""
839# CONFIG_FEATURE_IFUPDOWN_IP is not set
840# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
841# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
842# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
843# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
844# CONFIG_INETD is not set
845# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
846# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
847# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
848# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
849# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
850# CONFIG_FEATURE_INETD_RPC is not set
851# CONFIG_IP is not set
852# CONFIG_IPADDR is not set
853# CONFIG_IPLINK is not set
854# CONFIG_IPROUTE is not set
855# CONFIG_IPTUNNEL is not set
856# CONFIG_IPRULE is not set
857# CONFIG_IPNEIGH is not set
858# CONFIG_FEATURE_IP_ADDRESS is not set
859# CONFIG_FEATURE_IP_LINK is not set
860# CONFIG_FEATURE_IP_ROUTE is not set
861CONFIG_FEATURE_IP_ROUTE_DIR=""
862# CONFIG_FEATURE_IP_TUNNEL is not set
863# CONFIG_FEATURE_IP_RULE is not set
864# CONFIG_FEATURE_IP_NEIGH is not set
865# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
866CONFIG_IPCALC=y
867CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
868CONFIG_FEATURE_IPCALC_FANCY=y
869# CONFIG_FAKEIDENTD is not set
870# CONFIG_NAMEIF is not set
871# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
872# CONFIG_NBDCLIENT is not set
873CONFIG_NC=y
874CONFIG_NC_SERVER=y
875# CONFIG_NC_EXTRA is not set
876# CONFIG_NC_110_COMPAT is not set
877# CONFIG_NETSTAT is not set
878# CONFIG_FEATURE_NETSTAT_WIDE is not set
879# CONFIG_FEATURE_NETSTAT_PRG is not set
880# CONFIG_NSLOOKUP is not set
881# CONFIG_NTPD is not set
882# CONFIG_FEATURE_NTPD_SERVER is not set
883# CONFIG_FEATURE_NTPD_CONF is not set
884# CONFIG_PING is not set
885# CONFIG_PING6 is not set
886# CONFIG_FEATURE_FANCY_PING is not set
887# CONFIG_PSCAN is not set
888# CONFIG_ROUTE is not set
889# CONFIG_SLATTACH is not set
890# CONFIG_SSL_CLIENT is not set
891# CONFIG_TCPSVD is not set
892# CONFIG_UDPSVD is not set
893# CONFIG_TELNET is not set
894# CONFIG_FEATURE_TELNET_TTYPE is not set
895# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
896# CONFIG_FEATURE_TELNET_WIDTH is not set
897# CONFIG_TELNETD is not set
898# CONFIG_FEATURE_TELNETD_STANDALONE is not set
899# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
900# CONFIG_TFTP is not set
901# CONFIG_TFTPD is not set
902# CONFIG_FEATURE_TFTP_GET is not set
903# CONFIG_FEATURE_TFTP_PUT is not set
904# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
905# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
906# CONFIG_TFTP_DEBUG is not set
907# CONFIG_TLS is not set
908# CONFIG_TRACEROUTE is not set
909# CONFIG_TRACEROUTE6 is not set
910# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
911# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
912# CONFIG_TUNCTL is not set
913# CONFIG_FEATURE_TUNCTL_UG is not set
914# CONFIG_VCONFIG is not set
915CONFIG_WGET=y
916CONFIG_FEATURE_WGET_LONG_OPTIONS=y
917# CONFIG_FEATURE_WGET_STATUSBAR is not set
918# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
919# CONFIG_FEATURE_WGET_TIMEOUT is not set
920# CONFIG_FEATURE_WGET_HTTPS is not set
921# CONFIG_FEATURE_WGET_OPENSSL is not set
922CONFIG_WHOIS=y
923# CONFIG_ZCIP is not set
924# CONFIG_UDHCPC6 is not set
925# CONFIG_UDHCPD is not set
926# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
927# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
928CONFIG_DHCPD_LEASES_FILE=""
929# CONFIG_DUMPLEASES is not set
930# CONFIG_DHCPRELAY is not set
931# CONFIG_UDHCPC is not set
932# CONFIG_FEATURE_UDHCPC_ARPING is not set
933# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
934CONFIG_UDHCPC_DEFAULT_SCRIPT=""
935# CONFIG_FEATURE_UDHCP_PORT is not set
936CONFIG_UDHCP_DEBUG=0
937# CONFIG_FEATURE_UDHCP_RFC3397 is not set
938# CONFIG_FEATURE_UDHCP_8021Q is not set
939CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
940CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
941
942#
943# Print Utilities
944#
945# CONFIG_LPD is not set
946# CONFIG_LPR is not set
947# CONFIG_LPQ is not set
948
949#
950# Mail Utilities
951#
952# CONFIG_MAKEMIME is not set
953# CONFIG_POPMAILDIR is not set
954# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
955# CONFIG_REFORMIME is not set
956# CONFIG_FEATURE_REFORMIME_COMPAT is not set
957# CONFIG_SENDMAIL is not set
958CONFIG_FEATURE_MIME_CHARSET=""
959
960#
961# Process Utilities
962#
963# CONFIG_FREE is not set
964# CONFIG_FUSER is not set
965# CONFIG_IOSTAT is not set
966CONFIG_KILL=y
967CONFIG_KILLALL=y
968# CONFIG_KILLALL5 is not set
969# CONFIG_LSOF is not set
970# CONFIG_MPSTAT is not set
971# CONFIG_NMETER is not set
972CONFIG_PGREP=y
973# CONFIG_PKILL is not set
974CONFIG_PIDOF=y
975CONFIG_FEATURE_PIDOF_SINGLE=y
976CONFIG_FEATURE_PIDOF_OMIT=y
977# CONFIG_PMAP is not set
978# CONFIG_POWERTOP is not set
979# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
980CONFIG_PS=y
981# CONFIG_FEATURE_PS_WIDE is not set
982# CONFIG_FEATURE_PS_LONG is not set
983# CONFIG_FEATURE_PS_TIME is not set
984# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
985# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
986# CONFIG_PSTREE is not set
987# CONFIG_PWDX is not set
988# CONFIG_SMEMCAP is not set
989# CONFIG_BB_SYSCTL is not set
990# CONFIG_TOP is not set
991# CONFIG_FEATURE_TOP_INTERACTIVE is not set
992# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
993# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
994# CONFIG_FEATURE_TOP_SMP_CPU is not set
995# CONFIG_FEATURE_TOP_DECIMALS is not set
996# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
997# CONFIG_FEATURE_TOPMEM is not set
998# CONFIG_UPTIME is not set
999# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1000# CONFIG_WATCH is not set
1001# CONFIG_FEATURE_SHOW_THREADS is not set
1002
1003#
1004# Runit Utilities
1005#
1006# CONFIG_CHPST is not set
1007# CONFIG_SETUIDGID is not set
1008# CONFIG_ENVUIDGID is not set
1009# CONFIG_ENVDIR is not set
1010# CONFIG_SOFTLIMIT is not set
1011# CONFIG_RUNSV is not set
1012# CONFIG_RUNSVDIR is not set
1013# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1014# CONFIG_SV is not set
1015CONFIG_SV_DEFAULT_SERVICE_DIR=""
1016# CONFIG_SVC is not set
1017# CONFIG_SVLOGD is not set
1018# CONFIG_CHCON is not set
1019# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
1020# CONFIG_GETENFORCE is not set
1021# CONFIG_GETSEBOOL is not set
1022# CONFIG_LOAD_POLICY is not set
1023# CONFIG_MATCHPATHCON is not set
1024# CONFIG_RUNCON is not set
1025# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
1026# CONFIG_SELINUXENABLED is not set
1027# CONFIG_SESTATUS is not set
1028# CONFIG_SETENFORCE is not set
1029# CONFIG_SETFILES is not set
1030# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1031# CONFIG_RESTORECON is not set
1032# CONFIG_SETSEBOOL is not set
1033
1034#
1035# Shells
1036#
1037CONFIG_SH_IS_ASH=y
1038# CONFIG_SH_IS_HUSH is not set
1039# CONFIG_SH_IS_NONE is not set
1040CONFIG_BASH_IS_ASH=y
1041# CONFIG_BASH_IS_HUSH is not set
1042# CONFIG_BASH_IS_NONE is not set
1043CONFIG_ASH=y
1044CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1045CONFIG_ASH_INTERNAL_GLOB=y
1046CONFIG_ASH_BASH_COMPAT=y
1047# CONFIG_ASH_JOB_CONTROL is not set
1048CONFIG_ASH_ALIAS=y
1049CONFIG_ASH_RANDOM_SUPPORT=y
1050CONFIG_ASH_EXPAND_PRMT=y
1051# CONFIG_ASH_IDLE_TIMEOUT is not set
1052# CONFIG_ASH_MAIL is not set
1053CONFIG_ASH_ECHO=y
1054CONFIG_ASH_PRINTF=y
1055CONFIG_ASH_TEST=y
1056CONFIG_ASH_HELP=y
1057CONFIG_ASH_GETOPTS=y
1058CONFIG_ASH_CMDCMD=y
1059CONFIG_ASH_NOCONSOLE=y
1060# CONFIG_CTTYHACK is not set
1061# CONFIG_HUSH is not set
1062# CONFIG_HUSH_BASH_COMPAT is not set
1063# CONFIG_HUSH_BRACE_EXPANSION is not set
1064# CONFIG_HUSH_INTERACTIVE is not set
1065# CONFIG_HUSH_SAVEHISTORY is not set
1066# CONFIG_HUSH_JOB is not set
1067# CONFIG_HUSH_TICK is not set
1068# CONFIG_HUSH_IF is not set
1069# CONFIG_HUSH_LOOPS is not set
1070# CONFIG_HUSH_CASE is not set
1071# CONFIG_HUSH_FUNCTIONS is not set
1072# CONFIG_HUSH_LOCAL is not set
1073# CONFIG_HUSH_RANDOM_SUPPORT is not set
1074# CONFIG_HUSH_MODE_X is not set
1075# CONFIG_HUSH_ECHO is not set
1076# CONFIG_HUSH_PRINTF is not set
1077# CONFIG_HUSH_TEST is not set
1078# CONFIG_HUSH_HELP is not set
1079# CONFIG_HUSH_EXPORT is not set
1080# CONFIG_HUSH_EXPORT_N is not set
1081# CONFIG_HUSH_KILL is not set
1082# CONFIG_HUSH_WAIT is not set
1083# CONFIG_HUSH_TRAP is not set
1084# CONFIG_HUSH_TYPE is not set
1085# CONFIG_HUSH_READ is not set
1086# CONFIG_HUSH_SET is not set
1087# CONFIG_HUSH_UNSET is not set
1088# CONFIG_HUSH_ULIMIT is not set
1089# CONFIG_HUSH_UMASK is not set
1090# CONFIG_HUSH_MEMLEAK is not set
1091# CONFIG_MSH is not set
1092
1093#
1094# Options common to all shells
1095#
1096CONFIG_FEATURE_SH_MATH=y
1097CONFIG_FEATURE_SH_MATH_64=y
1098CONFIG_FEATURE_SH_EXTRA_QUIET=y
1099CONFIG_FEATURE_SH_STANDALONE=y
1100CONFIG_FEATURE_SH_NOFORK=y
1101CONFIG_FEATURE_SH_HISTFILESIZE=y
1102
1103#
1104# System Logging Utilities
1105#
1106# CONFIG_KLOGD is not set
1107# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1108# CONFIG_LOGGER is not set
1109# CONFIG_LOGREAD is not set
1110# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1111# CONFIG_SYSLOGD is not set
1112# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1113# CONFIG_FEATURE_REMOTE_LOG is not set
1114# CONFIG_FEATURE_SYSLOGD_DUP is not set
1115# CONFIG_FEATURE_SYSLOGD_CFG is not set
1116CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1117# CONFIG_FEATURE_IPC_SYSLOG is not set
1118CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1119# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
new file mode 100644
index 000000000..d29345411
--- /dev/null
+++ b/configs/mingw64_defconfig
@@ -0,0 +1,1119 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.27.0.git
4# Mon May 29 14:39:07 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_USE_PORTABLE_CODE=y
17CONFIG_SHOW_USAGE=y
18CONFIG_FEATURE_VERBOSE_USAGE=y
19CONFIG_FEATURE_COMPRESS_USAGE=y
20CONFIG_BUSYBOX=y
21CONFIG_FEATURE_INSTALLER=y
22# CONFIG_INSTALL_NO_USR is not set
23# CONFIG_PAM is not set
24CONFIG_LONG_OPTS=y
25# CONFIG_FEATURE_DEVPTS is not set
26# CONFIG_FEATURE_CLEAN_UP is not set
27# CONFIG_FEATURE_UTMP is not set
28# CONFIG_FEATURE_WTMP is not set
29# CONFIG_FEATURE_PIDFILE is not set
30CONFIG_PID_FILE_PATH=""
31# CONFIG_FEATURE_SUID is not set
32# CONFIG_FEATURE_SUID_CONFIG is not set
33# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
34# CONFIG_SELINUX is not set
35CONFIG_FEATURE_PREFER_APPLETS=y
36CONFIG_BUSYBOX_EXEC_PATH=""
37# CONFIG_FEATURE_SYSLOG is not set
38# CONFIG_FEATURE_HAVE_RPC is not set
39# CONFIG_PLATFORM_LINUX is not set
40
41#
42# Build Options
43#
44# CONFIG_STATIC is not set
45# CONFIG_PIE is not set
46# CONFIG_NOMMU is not set
47# CONFIG_BUILD_LIBBUSYBOX is not set
48# CONFIG_FEATURE_INDIVIDUAL is not set
49# CONFIG_FEATURE_SHARED_BUSYBOX is not set
50CONFIG_LFS=y
51# CONFIG_GLOBBING is not set
52CONFIG_SAFE_ENV=y
53CONFIG_CROSS_COMPILER_PREFIX="x86_64-w64-mingw32-"
54CONFIG_SYSROOT=""
55CONFIG_EXTRA_CFLAGS="-funwind-tables -fasynchronous-unwind-tables"
56CONFIG_EXTRA_LDFLAGS=""
57CONFIG_EXTRA_LDLIBS=""
58
59#
60# Installation Options ("make install" behavior)
61#
62CONFIG_INSTALL_APPLET_SYMLINKS=y
63# CONFIG_INSTALL_APPLET_HARDLINKS is not set
64# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
65# CONFIG_INSTALL_APPLET_DONT is not set
66# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
67# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
68# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
69CONFIG_PREFIX=""
70
71#
72# Debugging Options
73#
74CONFIG_DEBUG=y
75# CONFIG_DEBUG_PESSIMIZE is not set
76# CONFIG_DEBUG_SANITIZE is not set
77# CONFIG_UNIT_TEST is not set
78# CONFIG_WERROR is not set
79CONFIG_NO_DEBUG_LIB=y
80# CONFIG_DMALLOC is not set
81# CONFIG_EFENCE is not set
82
83#
84# Busybox Library Tuning
85#
86# CONFIG_FEATURE_USE_BSS_TAIL is not set
87CONFIG_FEATURE_RTMINMAX=y
88CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
89# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
90# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
91CONFIG_PASSWORD_MINLEN=6
92CONFIG_MD5_SMALL=1
93CONFIG_SHA3_SMALL=1
94# CONFIG_FEATURE_FAST_TOP is not set
95# CONFIG_FEATURE_ETC_NETWORKS is not set
96CONFIG_FEATURE_EDITING=y
97CONFIG_FEATURE_EDITING_MAX_LEN=1024
98CONFIG_FEATURE_EDITING_VI=y
99CONFIG_FEATURE_EDITING_HISTORY=255
100CONFIG_FEATURE_EDITING_SAVEHISTORY=y
101# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
102CONFIG_FEATURE_REVERSE_SEARCH=y
103CONFIG_FEATURE_TAB_COMPLETION=y
104CONFIG_FEATURE_USERNAME_COMPLETION=y
105CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
106# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
107# CONFIG_LOCALE_SUPPORT is not set
108# CONFIG_UNICODE_SUPPORT is not set
109# CONFIG_UNICODE_USING_LOCALE is not set
110# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
111CONFIG_SUBST_WCHAR=0
112CONFIG_LAST_SUPPORTED_WCHAR=0
113# CONFIG_UNICODE_COMBINING_WCHARS is not set
114# CONFIG_UNICODE_WIDE_WCHARS is not set
115# CONFIG_UNICODE_BIDI_SUPPORT is not set
116# CONFIG_UNICODE_NEUTRAL_TABLE is not set
117# CONFIG_UNICODE_PRESERVE_BROKEN is not set
118CONFIG_FEATURE_NON_POSIX_CP=y
119# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
120# CONFIG_FEATURE_USE_SENDFILE is not set
121CONFIG_FEATURE_COPYBUF_KB=4
122CONFIG_FEATURE_SKIP_ROOTFS=y
123# CONFIG_MONOTONIC_SYSCALL is not set
124CONFIG_IOCTL_HEX2STR_ERROR=y
125# CONFIG_FEATURE_HWIB is not set
126
127#
128# Applets
129#
130
131#
132# Archival Utilities
133#
134CONFIG_FEATURE_SEAMLESS_XZ=y
135CONFIG_FEATURE_SEAMLESS_LZMA=y
136CONFIG_FEATURE_SEAMLESS_BZ2=y
137CONFIG_FEATURE_SEAMLESS_GZ=y
138CONFIG_FEATURE_SEAMLESS_Z=y
139CONFIG_AR=y
140CONFIG_FEATURE_AR_LONG_FILENAMES=y
141CONFIG_FEATURE_AR_CREATE=y
142CONFIG_UNCOMPRESS=y
143CONFIG_GUNZIP=y
144CONFIG_ZCAT=y
145CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
146CONFIG_BUNZIP2=y
147CONFIG_BZCAT=y
148CONFIG_UNLZMA=y
149CONFIG_LZCAT=y
150CONFIG_LZMA=y
151CONFIG_FEATURE_LZMA_FAST=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
190
191#
192# Coreutils
193#
194CONFIG_BASENAME=y
195CONFIG_CAT=y
196CONFIG_FEATURE_CATV=y
197# CONFIG_CHGRP is not set
198CONFIG_CHMOD=y
199# CONFIG_CHOWN is not set
200# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
201# CONFIG_CHROOT is not set
202CONFIG_CKSUM=y
203CONFIG_COMM=y
204CONFIG_CP=y
205CONFIG_FEATURE_CP_LONG_OPTIONS=y
206CONFIG_CUT=y
207CONFIG_DATE=y
208CONFIG_FEATURE_DATE_ISOFMT=y
209# CONFIG_FEATURE_DATE_NANO is not set
210CONFIG_FEATURE_DATE_COMPAT=y
211CONFIG_DD=y
212# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
213# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
214CONFIG_FEATURE_DD_IBS_OBS=y
215CONFIG_FEATURE_DD_STATUS=y
216CONFIG_DF=y
217# CONFIG_FEATURE_DF_FANCY is not set
218CONFIG_DIRNAME=y
219CONFIG_DOS2UNIX=y
220CONFIG_UNIX2DOS=y
221CONFIG_DU=y
222CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
223CONFIG_ECHO=y
224CONFIG_FEATURE_FANCY_ECHO=y
225CONFIG_ENV=y
226CONFIG_FEATURE_ENV_LONG_OPTIONS=y
227CONFIG_EXPAND=y
228CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
229CONFIG_UNEXPAND=y
230CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
231CONFIG_EXPR=y
232CONFIG_EXPR_MATH_SUPPORT_64=y
233CONFIG_FACTOR=y
234CONFIG_FALSE=y
235CONFIG_FOLD=y
236# CONFIG_FSYNC is not set
237CONFIG_HEAD=y
238CONFIG_FEATURE_FANCY_HEAD=y
239# CONFIG_HOSTID is not set
240CONFIG_ID=y
241CONFIG_GROUPS=y
242# CONFIG_INSTALL is not set
243# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
244CONFIG_LINK=y
245CONFIG_LN=y
246CONFIG_LOGNAME=y
247CONFIG_LS=y
248CONFIG_FEATURE_LS_FILETYPES=y
249CONFIG_FEATURE_LS_FOLLOWLINKS=y
250CONFIG_FEATURE_LS_RECURSIVE=y
251CONFIG_FEATURE_LS_WIDTH=y
252CONFIG_FEATURE_LS_SORTFILES=y
253CONFIG_FEATURE_LS_TIMESTAMPS=y
254CONFIG_FEATURE_LS_USERNAME=y
255CONFIG_FEATURE_LS_COLOR=y
256CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
257CONFIG_MD5SUM=y
258CONFIG_SHA1SUM=y
259CONFIG_SHA256SUM=y
260CONFIG_SHA512SUM=y
261CONFIG_SHA3SUM=y
262
263#
264# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
265#
266CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
267CONFIG_MKDIR=y
268CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
269# CONFIG_MKFIFO is not set
270# CONFIG_MKNOD is not set
271CONFIG_MKTEMP=y
272CONFIG_MV=y
273CONFIG_FEATURE_MV_LONG_OPTIONS=y
274# CONFIG_NICE is not set
275CONFIG_NL=y
276# CONFIG_NOHUP is not set
277# CONFIG_NPROC is not set
278CONFIG_OD=y
279CONFIG_PASTE=y
280CONFIG_PRINTENV=y
281CONFIG_PRINTF=y
282CONFIG_PWD=y
283# CONFIG_READLINK is not set
284# CONFIG_FEATURE_READLINK_FOLLOW is not set
285# CONFIG_REALPATH is not set
286CONFIG_RM=y
287CONFIG_RMDIR=y
288CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
289CONFIG_SEQ=y
290# CONFIG_SHRED is not set
291CONFIG_SHUF=y
292CONFIG_SLEEP=y
293CONFIG_FEATURE_FANCY_SLEEP=y
294CONFIG_FEATURE_FLOAT_SLEEP=y
295CONFIG_SORT=y
296CONFIG_FEATURE_SORT_BIG=y
297CONFIG_SPLIT=y
298CONFIG_FEATURE_SPLIT_FANCY=y
299CONFIG_STAT=y
300CONFIG_FEATURE_STAT_FORMAT=y
301CONFIG_FEATURE_STAT_FILESYSTEM=y
302# CONFIG_STTY is not set
303CONFIG_SUM=y
304# CONFIG_SYNC is not set
305# CONFIG_FEATURE_SYNC_FANCY is not set
306CONFIG_TAC=y
307CONFIG_TAIL=y
308CONFIG_FEATURE_FANCY_TAIL=y
309CONFIG_TEE=y
310CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
311CONFIG_TEST=y
312CONFIG_TEST1=y
313CONFIG_TEST2=y
314CONFIG_FEATURE_TEST_64=y
315# CONFIG_TIMEOUT is not set
316CONFIG_TOUCH=y
317# CONFIG_FEATURE_TOUCH_NODEREF is not set
318CONFIG_FEATURE_TOUCH_SUSV3=y
319CONFIG_TR=y
320CONFIG_FEATURE_TR_CLASSES=y
321CONFIG_FEATURE_TR_EQUIV=y
322CONFIG_TRUE=y
323CONFIG_TRUNCATE=y
324# CONFIG_TTY is not set
325CONFIG_UNAME=y
326CONFIG_UNAME_OSNAME="MS/Windows"
327CONFIG_UNIQ=y
328CONFIG_UNLINK=y
329CONFIG_USLEEP=y
330CONFIG_UUDECODE=y
331CONFIG_BASE64=y
332CONFIG_UUENCODE=y
333CONFIG_WC=y
334CONFIG_FEATURE_WC_LARGE=y
335CONFIG_WHOAMI=y
336# CONFIG_WHO is not set
337# CONFIG_W is not set
338# CONFIG_USERS is not set
339CONFIG_YES=y
340
341#
342# Common options
343#
344CONFIG_FEATURE_VERBOSE=y
345
346#
347# Common options for cp and mv
348#
349# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
350
351#
352# Common options for df, du, ls
353#
354CONFIG_FEATURE_HUMAN_READABLE=y
355
356#
357# Console Utilities
358#
359# CONFIG_CHVT is not set
360CONFIG_CLEAR=y
361# CONFIG_DEALLOCVT is not set
362# CONFIG_DUMPKMAP is not set
363# CONFIG_FGCONSOLE is not set
364# CONFIG_KBD_MODE is not set
365# CONFIG_LOADFONT is not set
366# CONFIG_SETFONT is not set
367# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
368CONFIG_DEFAULT_SETFONT_DIR=""
369# CONFIG_FEATURE_LOADFONT_PSF2 is not set
370# CONFIG_FEATURE_LOADFONT_RAW is not set
371# CONFIG_LOADKMAP is not set
372# CONFIG_OPENVT is not set
373# CONFIG_RESET is not set
374# CONFIG_RESIZE is not set
375# CONFIG_FEATURE_RESIZE_PRINT is not set
376# CONFIG_SETCONSOLE is not set
377# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
378# CONFIG_SETKEYCODES is not set
379# CONFIG_SETLOGCONS is not set
380# CONFIG_SHOWKEY is not set
381
382#
383# Debian Utilities
384#
385# CONFIG_PIPE_PROGRESS is not set
386# CONFIG_RUN_PARTS is not set
387# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
388# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
389# CONFIG_START_STOP_DAEMON is not set
390# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
391# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
392CONFIG_WHICH=y
393
394#
395# Editors
396#
397CONFIG_AWK=y
398CONFIG_FEATURE_AWK_LIBM=y
399CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
400CONFIG_CMP=y
401CONFIG_DIFF=y
402CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
403CONFIG_FEATURE_DIFF_DIR=y
404CONFIG_ED=y
405CONFIG_PATCH=y
406CONFIG_SED=y
407CONFIG_VI=y
408CONFIG_FEATURE_VI_MAX_LEN=4096
409CONFIG_FEATURE_VI_8BIT=y
410CONFIG_FEATURE_VI_COLON=y
411CONFIG_FEATURE_VI_YANKMARK=y
412CONFIG_FEATURE_VI_SEARCH=y
413# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
414# CONFIG_FEATURE_VI_USE_SIGNALS is not set
415CONFIG_FEATURE_VI_DOT_CMD=y
416CONFIG_FEATURE_VI_READONLY=y
417CONFIG_FEATURE_VI_SETOPTS=y
418CONFIG_FEATURE_VI_SET=y
419CONFIG_FEATURE_VI_WIN_RESIZE=y
420CONFIG_FEATURE_VI_ASK_TERMINAL=y
421CONFIG_FEATURE_VI_UNDO=y
422CONFIG_FEATURE_VI_UNDO_QUEUE=y
423CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
424CONFIG_FEATURE_ALLOW_EXEC=y
425
426#
427# Finding Utilities
428#
429CONFIG_FIND=y
430CONFIG_FEATURE_FIND_PRINT0=y
431CONFIG_FEATURE_FIND_MTIME=y
432CONFIG_FEATURE_FIND_MMIN=y
433CONFIG_FEATURE_FIND_PERM=y
434CONFIG_FEATURE_FIND_TYPE=y
435# CONFIG_FEATURE_FIND_XDEV is not set
436CONFIG_FEATURE_FIND_MAXDEPTH=y
437CONFIG_FEATURE_FIND_NEWER=y
438# CONFIG_FEATURE_FIND_INUM is not set
439# CONFIG_FEATURE_FIND_EXEC is not set
440# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
441# CONFIG_FEATURE_FIND_USER is not set
442# CONFIG_FEATURE_FIND_GROUP is not set
443CONFIG_FEATURE_FIND_NOT=y
444CONFIG_FEATURE_FIND_DEPTH=y
445CONFIG_FEATURE_FIND_PAREN=y
446CONFIG_FEATURE_FIND_SIZE=y
447CONFIG_FEATURE_FIND_PRUNE=y
448CONFIG_FEATURE_FIND_DELETE=y
449CONFIG_FEATURE_FIND_PATH=y
450CONFIG_FEATURE_FIND_REGEX=y
451# CONFIG_FEATURE_FIND_CONTEXT is not set
452# CONFIG_FEATURE_FIND_LINKS is not set
453CONFIG_GREP=y
454CONFIG_EGREP=y
455CONFIG_FGREP=y
456CONFIG_FEATURE_GREP_CONTEXT=y
457CONFIG_XARGS=y
458CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
459CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
460CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
461CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
462CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
463
464#
465# Init Utilities
466#
467# CONFIG_BOOTCHARTD is not set
468# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
469# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
470# CONFIG_HALT is not set
471# CONFIG_POWEROFF is not set
472# CONFIG_REBOOT is not set
473# CONFIG_FEATURE_CALL_TELINIT is not set
474CONFIG_TELINIT_PATH=""
475# CONFIG_INIT is not set
476# CONFIG_LINUXRC is not set
477# CONFIG_FEATURE_USE_INITTAB is not set
478# CONFIG_FEATURE_KILL_REMOVED is not set
479CONFIG_FEATURE_KILL_DELAY=0
480# CONFIG_FEATURE_INIT_SCTTY is not set
481# CONFIG_FEATURE_INIT_SYSLOG is not set
482# CONFIG_FEATURE_INIT_QUIET is not set
483# CONFIG_FEATURE_INIT_COREDUMPS is not set
484CONFIG_INIT_TERMINAL_TYPE=""
485# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
486
487#
488# Login/Password Management Utilities
489#
490# CONFIG_FEATURE_SHADOWPASSWDS is not set
491# CONFIG_USE_BB_PWD_GRP is not set
492# CONFIG_USE_BB_SHADOW is not set
493# CONFIG_USE_BB_CRYPT is not set
494# CONFIG_USE_BB_CRYPT_SHA is not set
495# CONFIG_ADDGROUP is not set
496# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
497# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
498# CONFIG_ADD_SHELL is not set
499# CONFIG_REMOVE_SHELL is not set
500# CONFIG_ADDUSER is not set
501# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
502# CONFIG_FEATURE_CHECK_NAMES is not set
503CONFIG_LAST_ID=0
504CONFIG_FIRST_SYSTEM_ID=0
505CONFIG_LAST_SYSTEM_ID=0
506# CONFIG_CHPASSWD is not set
507CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
508# CONFIG_CRYPTPW is not set
509# CONFIG_MKPASSWD is not set
510# CONFIG_DELUSER is not set
511# CONFIG_DELGROUP is not set
512# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
513# CONFIG_GETTY is not set
514# CONFIG_LOGIN is not set
515# CONFIG_LOGIN_SESSION_AS_CHILD is not set
516# CONFIG_LOGIN_SCRIPTS is not set
517# CONFIG_FEATURE_NOLOGIN is not set
518# CONFIG_FEATURE_SECURETTY is not set
519# CONFIG_PASSWD is not set
520# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
521# CONFIG_SU is not set
522# CONFIG_FEATURE_SU_SYSLOG is not set
523# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
524# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
525# CONFIG_SULOGIN is not set
526# CONFIG_VLOCK is not set
527
528#
529# Linux Ext2 FS Progs
530#
531# CONFIG_CHATTR is not set
532# CONFIG_FSCK is not set
533# CONFIG_LSATTR is not set
534# CONFIG_TUNE2FS is not set
535
536#
537# Linux Module Utilities
538#
539# CONFIG_MODPROBE_SMALL is not set
540# CONFIG_DEPMOD is not set
541# CONFIG_INSMOD is not set
542# CONFIG_LSMOD is not set
543# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
544# CONFIG_MODINFO is not set
545# CONFIG_MODPROBE is not set
546# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
547# CONFIG_RMMOD is not set
548
549#
550# Options common to multiple modutils
551#
552# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
553# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
554# CONFIG_FEATURE_2_4_MODULES is not set
555# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
556# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
557# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
558# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
559# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
560# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
561# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
562# CONFIG_FEATURE_MODUTILS_ALIAS is not set
563# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
564CONFIG_DEFAULT_MODULES_DIR=""
565CONFIG_DEFAULT_DEPMOD_FILE=""
566
567#
568# Linux System Utilities
569#
570# CONFIG_ACPID is not set
571# CONFIG_FEATURE_ACPID_COMPAT is not set
572# CONFIG_BLKDISCARD is not set
573# CONFIG_BLKID is not set
574# CONFIG_FEATURE_BLKID_TYPE is not set
575# CONFIG_BLOCKDEV is not set
576CONFIG_CAL=y
577# CONFIG_CHRT is not set
578# CONFIG_DMESG is not set
579# CONFIG_FEATURE_DMESG_PRETTY is not set
580# CONFIG_EJECT is not set
581# CONFIG_FEATURE_EJECT_SCSI is not set
582# CONFIG_FALLOCATE is not set
583# CONFIG_FATATTR is not set
584# CONFIG_FBSET is not set
585# CONFIG_FEATURE_FBSET_FANCY is not set
586# CONFIG_FEATURE_FBSET_READMODE is not set
587# CONFIG_FDFORMAT is not set
588# CONFIG_FDISK is not set
589# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
590# CONFIG_FEATURE_FDISK_WRITABLE is not set
591# CONFIG_FEATURE_AIX_LABEL is not set
592# CONFIG_FEATURE_SGI_LABEL is not set
593# CONFIG_FEATURE_SUN_LABEL is not set
594# CONFIG_FEATURE_OSF_LABEL is not set
595# CONFIG_FEATURE_GPT_LABEL is not set
596# CONFIG_FEATURE_FDISK_ADVANCED is not set
597# CONFIG_FINDFS is not set
598# CONFIG_FLOCK is not set
599# CONFIG_FDFLUSH is not set
600# CONFIG_FREERAMDISK is not set
601# CONFIG_FSCK_MINIX is not set
602# CONFIG_FSFREEZE is not set
603# CONFIG_FSTRIM is not set
604CONFIG_GETOPT=y
605CONFIG_FEATURE_GETOPT_LONG=y
606CONFIG_HEXDUMP=y
607CONFIG_FEATURE_HEXDUMP_REVERSE=y
608CONFIG_HD=y
609CONFIG_XXD=y
610# CONFIG_HWCLOCK is not set
611# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
612# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
613# CONFIG_IONICE is not set
614# CONFIG_IPCRM is not set
615# CONFIG_IPCS is not set
616# CONFIG_LAST is not set
617# CONFIG_FEATURE_LAST_FANCY is not set
618# CONFIG_LOSETUP is not set
619# CONFIG_LSPCI is not set
620# CONFIG_LSUSB is not set
621# CONFIG_MDEV is not set
622# CONFIG_FEATURE_MDEV_CONF is not set
623# CONFIG_FEATURE_MDEV_RENAME is not set
624# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
625# CONFIG_FEATURE_MDEV_EXEC is not set
626# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
627# CONFIG_MESG is not set
628# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
629# CONFIG_MKE2FS is not set
630# CONFIG_MKFS_EXT2 is not set
631# CONFIG_MKFS_MINIX is not set
632# CONFIG_FEATURE_MINIX2 is not set
633# CONFIG_MKFS_REISER is not set
634# CONFIG_MKDOSFS is not set
635# CONFIG_MKFS_VFAT is not set
636# CONFIG_MKSWAP is not set
637# CONFIG_FEATURE_MKSWAP_UUID is not set
638# CONFIG_MORE is not set
639# CONFIG_MOUNT is not set
640# CONFIG_FEATURE_MOUNT_FAKE is not set
641# CONFIG_FEATURE_MOUNT_VERBOSE is not set
642# CONFIG_FEATURE_MOUNT_HELPERS is not set
643# CONFIG_FEATURE_MOUNT_LABEL is not set
644# CONFIG_FEATURE_MOUNT_NFS is not set
645# CONFIG_FEATURE_MOUNT_CIFS is not set
646# CONFIG_FEATURE_MOUNT_FLAGS is not set
647# CONFIG_FEATURE_MOUNT_FSTAB is not set
648# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
649# CONFIG_MOUNTPOINT is not set
650# CONFIG_NSENTER is not set
651# CONFIG_FEATURE_NSENTER_LONG_OPTS is not set
652# CONFIG_PIVOT_ROOT is not set
653# CONFIG_RDATE is not set
654# CONFIG_RDEV is not set
655# CONFIG_READPROFILE is not set
656# CONFIG_RENICE is not set
657CONFIG_REV=y
658# CONFIG_RTCWAKE is not set
659# CONFIG_SCRIPT is not set
660# CONFIG_SCRIPTREPLAY is not set
661# CONFIG_SETARCH is not set
662# CONFIG_LINUX32 is not set
663# CONFIG_LINUX64 is not set
664# CONFIG_SETSID is not set
665# CONFIG_SWAPON is not set
666# CONFIG_FEATURE_SWAPON_DISCARD is not set
667# CONFIG_FEATURE_SWAPON_PRI is not set
668# CONFIG_SWAPOFF is not set
669# CONFIG_SWITCH_ROOT is not set
670# CONFIG_TASKSET is not set
671# CONFIG_FEATURE_TASKSET_FANCY is not set
672# CONFIG_UEVENT is not set
673# CONFIG_UMOUNT is not set
674# CONFIG_FEATURE_UMOUNT_ALL is not set
675# CONFIG_UNSHARE is not set
676# CONFIG_WALL is not set
677# CONFIG_FEATURE_MOUNT_LOOP is not set
678# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
679# CONFIG_FEATURE_MTAB_SUPPORT is not set
680# CONFIG_VOLUMEID is not set
681# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
682# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
683# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
684# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
685# CONFIG_FEATURE_VOLUMEID_EXT is not set
686# CONFIG_FEATURE_VOLUMEID_F2FS is not set
687# CONFIG_FEATURE_VOLUMEID_FAT is not set
688# CONFIG_FEATURE_VOLUMEID_HFS is not set
689# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
690# CONFIG_FEATURE_VOLUMEID_JFS is not set
691# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
692# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
693# CONFIG_FEATURE_VOLUMEID_LUKS is not set
694# CONFIG_FEATURE_VOLUMEID_NILFS is not set
695# CONFIG_FEATURE_VOLUMEID_NTFS is not set
696# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
697# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
698# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
699# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
700# CONFIG_FEATURE_VOLUMEID_SYSV is not set
701# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
702# CONFIG_FEATURE_VOLUMEID_UDF is not set
703# CONFIG_FEATURE_VOLUMEID_XFS is not set
704
705#
706# Miscellaneous Utilities
707#
708# CONFIG_ADJTIMEX is not set
709# CONFIG_BBCONFIG is not set
710# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
711# CONFIG_BEEP is not set
712CONFIG_FEATURE_BEEP_FREQ=0
713CONFIG_FEATURE_BEEP_LENGTH_MS=0
714# CONFIG_CHAT is not set
715# CONFIG_FEATURE_CHAT_NOFAIL is not set
716# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
717# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
718# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
719# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
720# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
721# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
722# CONFIG_CONSPY is not set
723# CONFIG_CROND is not set
724# CONFIG_FEATURE_CROND_D is not set
725# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
726CONFIG_FEATURE_CROND_DIR=""
727# CONFIG_CRONTAB is not set
728CONFIG_DC=y
729CONFIG_FEATURE_DC_LIBM=y
730# CONFIG_DEVFSD is not set
731# CONFIG_DEVFSD_MODLOAD is not set
732# CONFIG_DEVFSD_FG_NP is not set
733# CONFIG_DEVFSD_VERBOSE is not set
734# CONFIG_FEATURE_DEVFS is not set
735# CONFIG_DEVMEM is not set
736# CONFIG_FBSPLASH is not set
737# CONFIG_FLASHCP is not set
738# CONFIG_FLASH_ERASEALL is not set
739# CONFIG_FLASH_LOCK is not set
740# CONFIG_FLASH_UNLOCK is not set
741# CONFIG_HDPARM is not set
742# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
743# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
744# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
745# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
746# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
747# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
748# CONFIG_I2CGET is not set
749# CONFIG_I2CSET is not set
750# CONFIG_I2CDUMP is not set
751# CONFIG_I2CDETECT is not set
752# CONFIG_INOTIFYD is not set
753CONFIG_LESS=y
754CONFIG_FEATURE_LESS_MAXLINES=9999999
755CONFIG_FEATURE_LESS_BRACKETS=y
756CONFIG_FEATURE_LESS_FLAGS=y
757CONFIG_FEATURE_LESS_TRUNCATE=y
758CONFIG_FEATURE_LESS_MARKS=y
759CONFIG_FEATURE_LESS_REGEXP=y
760# CONFIG_FEATURE_LESS_WINCH is not set
761# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
762CONFIG_FEATURE_LESS_DASHCMD=y
763CONFIG_FEATURE_LESS_LINENUMS=y
764# CONFIG_LSSCSI is not set
765# CONFIG_MAKEDEVS is not set
766# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
767# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
768CONFIG_MAN=y
769# CONFIG_MICROCOM is not set
770# CONFIG_MT is not set
771# CONFIG_NANDWRITE is not set
772# CONFIG_NANDDUMP is not set
773# CONFIG_PARTPROBE is not set
774# CONFIG_RAIDAUTORUN is not set
775# CONFIG_READAHEAD is not set
776# CONFIG_RFKILL is not set
777# CONFIG_RUNLEVEL is not set
778# CONFIG_RX is not set
779# CONFIG_SETSERIAL is not set
780CONFIG_STRINGS=y
781# CONFIG_TIME is not set
782# CONFIG_TTYSIZE is not set
783# CONFIG_UBIRENAME is not set
784# CONFIG_UBIATTACH is not set
785# CONFIG_UBIDETACH is not set
786# CONFIG_UBIMKVOL is not set
787# CONFIG_UBIRMVOL is not set
788# CONFIG_UBIRSVOL is not set
789# CONFIG_UBIUPDATEVOL is not set
790# CONFIG_VOLNAME is not set
791# CONFIG_WATCHDOG is not set
792
793#
794# Networking Utilities
795#
796CONFIG_FEATURE_IPV6=y
797# CONFIG_FEATURE_UNIX_LOCAL is not set
798CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
799# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
800# CONFIG_ARP is not set
801# CONFIG_ARPING is not set
802# CONFIG_BRCTL is not set
803# CONFIG_FEATURE_BRCTL_FANCY is not set
804# CONFIG_FEATURE_BRCTL_SHOW is not set
805# CONFIG_DNSD is not set
806# CONFIG_ETHER_WAKE is not set
807# CONFIG_FTPD is not set
808# CONFIG_FEATURE_FTPD_WRITE is not set
809# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
810# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
811CONFIG_FTPGET=y
812CONFIG_FTPPUT=y
813CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
814# CONFIG_HOSTNAME is not set
815# CONFIG_DNSDOMAINNAME is not set
816# CONFIG_HTTPD is not set
817# CONFIG_FEATURE_HTTPD_RANGES is not set
818# CONFIG_FEATURE_HTTPD_SETUID is not set
819# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
820# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
821# CONFIG_FEATURE_HTTPD_CGI is not set
822# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
823# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
824# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
825# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
826# CONFIG_FEATURE_HTTPD_PROXY is not set
827# CONFIG_FEATURE_HTTPD_GZIP is not set
828# CONFIG_IFCONFIG is not set
829# CONFIG_FEATURE_IFCONFIG_STATUS is not set
830# CONFIG_FEATURE_IFCONFIG_SLIP is not set
831# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
832# CONFIG_FEATURE_IFCONFIG_HW is not set
833# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
834# CONFIG_IFENSLAVE is not set
835# CONFIG_IFPLUGD is not set
836# CONFIG_IFUP is not set
837# CONFIG_IFDOWN is not set
838CONFIG_IFUPDOWN_IFSTATE_PATH=""
839# CONFIG_FEATURE_IFUPDOWN_IP is not set
840# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
841# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
842# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
843# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
844# CONFIG_INETD is not set
845# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
846# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
847# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
848# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
849# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
850# CONFIG_FEATURE_INETD_RPC is not set
851# CONFIG_IP is not set
852# CONFIG_IPADDR is not set
853# CONFIG_IPLINK is not set
854# CONFIG_IPROUTE is not set
855# CONFIG_IPTUNNEL is not set
856# CONFIG_IPRULE is not set
857# CONFIG_IPNEIGH is not set
858# CONFIG_FEATURE_IP_ADDRESS is not set
859# CONFIG_FEATURE_IP_LINK is not set
860# CONFIG_FEATURE_IP_ROUTE is not set
861CONFIG_FEATURE_IP_ROUTE_DIR=""
862# CONFIG_FEATURE_IP_TUNNEL is not set
863# CONFIG_FEATURE_IP_RULE is not set
864# CONFIG_FEATURE_IP_NEIGH is not set
865# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
866CONFIG_IPCALC=y
867CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
868CONFIG_FEATURE_IPCALC_FANCY=y
869# CONFIG_FAKEIDENTD is not set
870# CONFIG_NAMEIF is not set
871# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
872# CONFIG_NBDCLIENT is not set
873CONFIG_NC=y
874CONFIG_NC_SERVER=y
875# CONFIG_NC_EXTRA is not set
876# CONFIG_NC_110_COMPAT is not set
877# CONFIG_NETSTAT is not set
878# CONFIG_FEATURE_NETSTAT_WIDE is not set
879# CONFIG_FEATURE_NETSTAT_PRG is not set
880# CONFIG_NSLOOKUP is not set
881# CONFIG_NTPD is not set
882# CONFIG_FEATURE_NTPD_SERVER is not set
883# CONFIG_FEATURE_NTPD_CONF is not set
884# CONFIG_PING is not set
885# CONFIG_PING6 is not set
886# CONFIG_FEATURE_FANCY_PING is not set
887# CONFIG_PSCAN is not set
888# CONFIG_ROUTE is not set
889# CONFIG_SLATTACH is not set
890# CONFIG_SSL_CLIENT is not set
891# CONFIG_TCPSVD is not set
892# CONFIG_UDPSVD is not set
893# CONFIG_TELNET is not set
894# CONFIG_FEATURE_TELNET_TTYPE is not set
895# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
896# CONFIG_FEATURE_TELNET_WIDTH is not set
897# CONFIG_TELNETD is not set
898# CONFIG_FEATURE_TELNETD_STANDALONE is not set
899# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
900# CONFIG_TFTP is not set
901# CONFIG_TFTPD is not set
902# CONFIG_FEATURE_TFTP_GET is not set
903# CONFIG_FEATURE_TFTP_PUT is not set
904# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
905# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
906# CONFIG_TFTP_DEBUG is not set
907# CONFIG_TLS is not set
908# CONFIG_TRACEROUTE is not set
909# CONFIG_TRACEROUTE6 is not set
910# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
911# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
912# CONFIG_TUNCTL is not set
913# CONFIG_FEATURE_TUNCTL_UG is not set
914# CONFIG_VCONFIG is not set
915CONFIG_WGET=y
916CONFIG_FEATURE_WGET_LONG_OPTIONS=y
917# CONFIG_FEATURE_WGET_STATUSBAR is not set
918# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
919# CONFIG_FEATURE_WGET_TIMEOUT is not set
920# CONFIG_FEATURE_WGET_HTTPS is not set
921# CONFIG_FEATURE_WGET_OPENSSL is not set
922CONFIG_WHOIS=y
923# CONFIG_ZCIP is not set
924# CONFIG_UDHCPC6 is not set
925# CONFIG_UDHCPD is not set
926# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
927# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
928CONFIG_DHCPD_LEASES_FILE=""
929# CONFIG_DUMPLEASES is not set
930# CONFIG_DHCPRELAY is not set
931# CONFIG_UDHCPC is not set
932# CONFIG_FEATURE_UDHCPC_ARPING is not set
933# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
934CONFIG_UDHCPC_DEFAULT_SCRIPT=""
935# CONFIG_FEATURE_UDHCP_PORT is not set
936CONFIG_UDHCP_DEBUG=0
937# CONFIG_FEATURE_UDHCP_RFC3397 is not set
938# CONFIG_FEATURE_UDHCP_8021Q is not set
939CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
940CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
941
942#
943# Print Utilities
944#
945# CONFIG_LPD is not set
946# CONFIG_LPR is not set
947# CONFIG_LPQ is not set
948
949#
950# Mail Utilities
951#
952# CONFIG_MAKEMIME is not set
953# CONFIG_POPMAILDIR is not set
954# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
955# CONFIG_REFORMIME is not set
956# CONFIG_FEATURE_REFORMIME_COMPAT is not set
957# CONFIG_SENDMAIL is not set
958CONFIG_FEATURE_MIME_CHARSET=""
959
960#
961# Process Utilities
962#
963# CONFIG_FREE is not set
964# CONFIG_FUSER is not set
965# CONFIG_IOSTAT is not set
966CONFIG_KILL=y
967CONFIG_KILLALL=y
968# CONFIG_KILLALL5 is not set
969# CONFIG_LSOF is not set
970# CONFIG_MPSTAT is not set
971# CONFIG_NMETER is not set
972CONFIG_PGREP=y
973# CONFIG_PKILL is not set
974CONFIG_PIDOF=y
975CONFIG_FEATURE_PIDOF_SINGLE=y
976CONFIG_FEATURE_PIDOF_OMIT=y
977# CONFIG_PMAP is not set
978# CONFIG_POWERTOP is not set
979# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
980CONFIG_PS=y
981# CONFIG_FEATURE_PS_WIDE is not set
982# CONFIG_FEATURE_PS_LONG is not set
983# CONFIG_FEATURE_PS_TIME is not set
984# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
985# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
986# CONFIG_PSTREE is not set
987# CONFIG_PWDX is not set
988# CONFIG_SMEMCAP is not set
989# CONFIG_BB_SYSCTL is not set
990# CONFIG_TOP is not set
991# CONFIG_FEATURE_TOP_INTERACTIVE is not set
992# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
993# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
994# CONFIG_FEATURE_TOP_SMP_CPU is not set
995# CONFIG_FEATURE_TOP_DECIMALS is not set
996# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
997# CONFIG_FEATURE_TOPMEM is not set
998# CONFIG_UPTIME is not set
999# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
1000# CONFIG_WATCH is not set
1001# CONFIG_FEATURE_SHOW_THREADS is not set
1002
1003#
1004# Runit Utilities
1005#
1006# CONFIG_CHPST is not set
1007# CONFIG_SETUIDGID is not set
1008# CONFIG_ENVUIDGID is not set
1009# CONFIG_ENVDIR is not set
1010# CONFIG_SOFTLIMIT is not set
1011# CONFIG_RUNSV is not set
1012# CONFIG_RUNSVDIR is not set
1013# CONFIG_FEATURE_RUNSVDIR_LOG is not set
1014# CONFIG_SV is not set
1015CONFIG_SV_DEFAULT_SERVICE_DIR=""
1016# CONFIG_SVC is not set
1017# CONFIG_SVLOGD is not set
1018# CONFIG_CHCON is not set
1019# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
1020# CONFIG_GETENFORCE is not set
1021# CONFIG_GETSEBOOL is not set
1022# CONFIG_LOAD_POLICY is not set
1023# CONFIG_MATCHPATHCON is not set
1024# CONFIG_RUNCON is not set
1025# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
1026# CONFIG_SELINUXENABLED is not set
1027# CONFIG_SESTATUS is not set
1028# CONFIG_SETENFORCE is not set
1029# CONFIG_SETFILES is not set
1030# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1031# CONFIG_RESTORECON is not set
1032# CONFIG_SETSEBOOL is not set
1033
1034#
1035# Shells
1036#
1037CONFIG_SH_IS_ASH=y
1038# CONFIG_SH_IS_HUSH is not set
1039# CONFIG_SH_IS_NONE is not set
1040CONFIG_BASH_IS_ASH=y
1041# CONFIG_BASH_IS_HUSH is not set
1042# CONFIG_BASH_IS_NONE is not set
1043CONFIG_ASH=y
1044CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1045CONFIG_ASH_INTERNAL_GLOB=y
1046CONFIG_ASH_BASH_COMPAT=y
1047# CONFIG_ASH_JOB_CONTROL is not set
1048CONFIG_ASH_ALIAS=y
1049CONFIG_ASH_RANDOM_SUPPORT=y
1050CONFIG_ASH_EXPAND_PRMT=y
1051# CONFIG_ASH_IDLE_TIMEOUT is not set
1052# CONFIG_ASH_MAIL is not set
1053CONFIG_ASH_ECHO=y
1054CONFIG_ASH_PRINTF=y
1055CONFIG_ASH_TEST=y
1056CONFIG_ASH_HELP=y
1057CONFIG_ASH_GETOPTS=y
1058CONFIG_ASH_CMDCMD=y
1059# CONFIG_ASH_NOCONSOLE is not set
1060# CONFIG_CTTYHACK is not set
1061# CONFIG_HUSH is not set
1062# CONFIG_HUSH_BASH_COMPAT is not set
1063# CONFIG_HUSH_BRACE_EXPANSION is not set
1064# CONFIG_HUSH_INTERACTIVE is not set
1065# CONFIG_HUSH_SAVEHISTORY is not set
1066# CONFIG_HUSH_JOB is not set
1067# CONFIG_HUSH_TICK is not set
1068# CONFIG_HUSH_IF is not set
1069# CONFIG_HUSH_LOOPS is not set
1070# CONFIG_HUSH_CASE is not set
1071# CONFIG_HUSH_FUNCTIONS is not set
1072# CONFIG_HUSH_LOCAL is not set
1073# CONFIG_HUSH_RANDOM_SUPPORT is not set
1074# CONFIG_HUSH_MODE_X is not set
1075# CONFIG_HUSH_ECHO is not set
1076# CONFIG_HUSH_PRINTF is not set
1077# CONFIG_HUSH_TEST is not set
1078# CONFIG_HUSH_HELP is not set
1079# CONFIG_HUSH_EXPORT is not set
1080# CONFIG_HUSH_EXPORT_N is not set
1081# CONFIG_HUSH_KILL is not set
1082# CONFIG_HUSH_WAIT is not set
1083# CONFIG_HUSH_TRAP is not set
1084# CONFIG_HUSH_TYPE is not set
1085# CONFIG_HUSH_READ is not set
1086# CONFIG_HUSH_SET is not set
1087# CONFIG_HUSH_UNSET is not set
1088# CONFIG_HUSH_ULIMIT is not set
1089# CONFIG_HUSH_UMASK is not set
1090# CONFIG_HUSH_MEMLEAK is not set
1091# CONFIG_MSH is not set
1092
1093#
1094# Options common to all shells
1095#
1096CONFIG_FEATURE_SH_MATH=y
1097CONFIG_FEATURE_SH_MATH_64=y
1098CONFIG_FEATURE_SH_EXTRA_QUIET=y
1099CONFIG_FEATURE_SH_STANDALONE=y
1100CONFIG_FEATURE_SH_NOFORK=y
1101CONFIG_FEATURE_SH_HISTFILESIZE=y
1102
1103#
1104# System Logging Utilities
1105#
1106# CONFIG_KLOGD is not set
1107# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1108# CONFIG_LOGGER is not set
1109# CONFIG_LOGREAD is not set
1110# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1111# CONFIG_SYSLOGD is not set
1112# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1113# CONFIG_FEATURE_REMOTE_LOG is not set
1114# CONFIG_FEATURE_SYSLOGD_DUP is not set
1115# CONFIG_FEATURE_SYSLOGD_CFG is not set
1116CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1117# CONFIG_FEATURE_IPC_SYSLOG is not set
1118CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1119# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 630852205..b37615313 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 5d2fbf2f7..639d29a55 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 205cdc053..8782d3d1e 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 6780057da..61b4409a7 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 f13bdfc11..b02fb09bd 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 b918ec62e..109b5258c 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 c55293dc9..2a91f963c 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 edcf2a2d8..d4f93312a 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 81d875589..ce6a90fc0 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 c0f897809..af33ba72e 100644
--- a/debianutils/which.c
+++ b/debianutils/which.c
@@ -43,17 +43,33 @@ 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_PREFER_APPLETS
49 if (find_applet_by_name(*argv) >= 0 || strcmp(*argv, "busybox") == 0) {
50 missing = 0;
51 puts(*argv);
52 if (!option_mask32) /* -a not set */
53 break;
54 }
55#endif
46 56
47 /* If file contains a slash don't use PATH */ 57 /* If file contains a slash don't use PATH */
48 if (strchr(*argv, '/')) { 58 if (strchr(*argv, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(*argv, '\\'))) {
49 if (file_is_executable(*argv)) { 59 if (file_is_executable(*argv)) {
50 missing = 0; 60 missing = 0;
51 puts(*argv); 61 puts(*argv);
52 } 62 }
63#if ENABLE_PLATFORM_MINGW32
64 else if ((p=file_is_win32_executable(*argv)) != NULL) {
65 missing = 0;
66 puts(p);
67 free(p);
68 }
69#endif
53 } else { 70 } else {
54 char *path; 71 char *path;
55 char *tmp; 72 char *tmp;
56 char *p;
57 73
58 path = tmp = xstrdup(env_path); 74 path = tmp = xstrdup(env_path);
59 while ((p = find_executable(*argv, &tmp)) != NULL) { 75 while ((p = find_executable(*argv, &tmp)) != NULL) {
diff --git a/editors/awk.c b/editors/awk.c
index 685e8bed8..e8e2c96f8 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -728,7 +728,11 @@ static char *skip_spaces(char *p)
728 if (*p == '\\' && p[1] == '\n') { 728 if (*p == '\\' && p[1] == '\n') {
729 p++; 729 p++;
730 t_lineno++; 730 t_lineno++;
731#if !ENABLE_PLATFORM_MINGW32
731 } else if (*p != ' ' && *p != '\t') { 732 } else if (*p != ' ' && *p != '\t') {
733#else
734 } else if (*p != ' ' && *p != '\t' && *p != '\r') {
735#endif
732 break; 736 break;
733 } 737 }
734 p++; 738 p++;
@@ -2074,7 +2078,7 @@ static int fmt_num(char *b, int size, const char *format, double n, int int_as_i
2074 const char *s = format; 2078 const char *s = format;
2075 2079
2076 if (int_as_int && n == (long long)n) { 2080 if (int_as_int && n == (long long)n) {
2077 r = snprintf(b, size, "%lld", (long long)n); 2081 r = snprintf(b, size, "%"LL_FMT"d", (long long)n);
2078 } else { 2082 } else {
2079 do { c = *s; } while (c && *++s); 2083 do { c = *s; } while (c && *++s);
2080 if (strchr("diouxX", c)) { 2084 if (strchr("diouxX", c)) {
diff --git a/editors/diff.c b/editors/diff.c
index 7687518f3..975bc4603 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 ca9ab2054..b2c7ba829 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 76d1f261b..900b41cb5 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 ae01a49be..eca1185ec 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 2b9c5f04c..9bbf59bb8 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 0317c7d6a..c58cbc250 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#if defined(__GLIBC__) && __GLIBC__ < 2 178#if defined(__GLIBC__) && __GLIBC__ < 2
171int vdprintf(int d, const char *format, va_list ap); 179int vdprintf(int d, const char *format, va_list ap);
172#endif 180#endif
@@ -179,6 +187,9 @@ int klogctl(int type, char *b, int len);
179# define BUFSIZ 4096 187# define BUFSIZ 4096
180#endif 188#endif
181 189
190#if ENABLE_PLATFORM_MINGW32
191# include "mingw.h"
192#endif
182 193
183/* Busybox does not use threads, we can speed up stdio. */ 194/* Busybox does not use threads, we can speed up stdio. */
184#ifdef HAVE_UNLOCKED_STDIO 195#ifdef HAVE_UNLOCKED_STDIO
@@ -241,6 +252,13 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
241 : ((T)1 << (sizeof(T)*8-1)) \ 252 : ((T)1 << (sizeof(T)*8-1)) \
242 ) 253 )
243 254
255#if ENABLE_PLATFORM_MINGW32 && \
256 (!defined(__USE_MINGW_ANSI_STDIO) || !__USE_MINGW_ANSI_STDIO)
257#define LL_FMT "I64"
258#else
259#define LL_FMT "ll"
260#endif
261
244/* Large file support */ 262/* Large file support */
245/* Note that CONFIG_LFS=y forces bbox to be built with all common ops 263/* Note that CONFIG_LFS=y forces bbox to be built with all common ops
246 * (stat, lseek etc) mapped to "largefile" variants by libc. 264 * (stat, lseek etc) mapped to "largefile" variants by libc.
@@ -266,7 +284,7 @@ typedef unsigned long long uoff_t;
266# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX) 284# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX)
267# define BB_STRTOOFF bb_strtoull 285# define BB_STRTOOFF bb_strtoull
268# define STRTOOFF strtoull 286# define STRTOOFF strtoull
269# define OFF_FMT "ll" 287# define OFF_FMT LL_FMT
270# endif 288# endif
271#else 289#else
272/* CONFIG_LFS is off */ 290/* CONFIG_LFS is off */
@@ -513,6 +531,7 @@ enum {
513 + (1LL << SIGUSR2) 531 + (1LL << SIGUSR2)
514 + 0), 532 + 0),
515}; 533};
534#if !ENABLE_PLATFORM_MINGW32
516void bb_signals(int sigs, void (*f)(int)) FAST_FUNC; 535void bb_signals(int sigs, void (*f)(int)) FAST_FUNC;
517/* Unlike signal() and bb_signals, sets handler with sigaction() 536/* Unlike signal() and bb_signals, sets handler with sigaction()
518 * and in a way that while signal handler is run, no other signals 537 * and in a way that while signal handler is run, no other signals
@@ -530,6 +549,10 @@ void sig_unblock(int sig) FAST_FUNC;
530int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC; 549int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC;
531/* SIG_BLOCK/SIG_UNBLOCK all signals: */ 550/* SIG_BLOCK/SIG_UNBLOCK all signals: */
532int sigprocmask_allsigs(int how) FAST_FUNC; 551int sigprocmask_allsigs(int how) FAST_FUNC;
552#else
553#define bb_signals(s, f)
554#define kill_myself_with_sig(s)
555#endif
533/* Standard handler which just records signo */ 556/* Standard handler which just records signo */
534extern smallint bb_got_signal; 557extern smallint bb_got_signal;
535void record_signo(int signo); /* not FAST_FUNC! */ 558void record_signo(int signo); /* not FAST_FUNC! */
@@ -609,7 +632,7 @@ char *strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC;
609int xsocket(int domain, int type, int protocol) FAST_FUNC; 632int xsocket(int domain, int type, int protocol) FAST_FUNC;
610void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; 633void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC;
611void xlisten(int s, int backlog) FAST_FUNC; 634void xlisten(int s, int backlog) FAST_FUNC;
612void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) FAST_FUNC; 635void xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen) FAST_FUNC;
613ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, 636ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
614 socklen_t tolen) FAST_FUNC; 637 socklen_t tolen) FAST_FUNC;
615 638
@@ -944,6 +967,9 @@ char *safe_gethostname(void) FAST_FUNC;
944char* str_tolower(char *str) FAST_FUNC; 967char* str_tolower(char *str) FAST_FUNC;
945 968
946char *utoa(unsigned n) FAST_FUNC; 969char *utoa(unsigned n) FAST_FUNC;
970#if ENABLE_PLATFORM_MINGW32
971# define itoa bb_itoa
972#endif
947char *itoa(int n) FAST_FUNC; 973char *itoa(int n) FAST_FUNC;
948/* Returns a pointer past the formatted number, does NOT null-terminate */ 974/* Returns a pointer past the formatted number, does NOT null-terminate */
949char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; 975char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC;
@@ -1202,7 +1228,7 @@ extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC;
1202 * 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
1203 * (to interpret it as if optreset was set). 1229 * (to interpret it as if optreset was set).
1204 */ 1230 */
1205#ifdef __GLIBC__ 1231#if defined(__GLIBC__) || ENABLE_PLATFORM_MINGW32
1206#define GETOPT_RESET() (optind = 0) 1232#define GETOPT_RESET() (optind = 0)
1207#else /* BSD style */ 1233#else /* BSD style */
1208#define GETOPT_RESET() (optind = 1) 1234#define GETOPT_RESET() (optind = 1)
@@ -1776,6 +1802,9 @@ typedef struct procps_status_t {
1776#if ENABLE_FEATURE_TOP_SMP_PROCESS 1802#if ENABLE_FEATURE_TOP_SMP_PROCESS
1777 int last_seen_on_cpu; 1803 int last_seen_on_cpu;
1778#endif 1804#endif
1805#if ENABLE_PLATFORM_MINGW32
1806 HANDLE snapshot;
1807#endif
1779} procps_status_t; 1808} procps_status_t;
1780/* flag bits for procps_scan(xx, flags) calls */ 1809/* flag bits for procps_scan(xx, flags) calls */
1781enum { 1810enum {
@@ -1814,7 +1843,11 @@ void free_procps_scan(procps_status_t* sp) FAST_FUNC;
1814procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; 1843procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC;
1815/* Format cmdline (up to col chars) into char buf[size] */ 1844/* Format cmdline (up to col chars) into char buf[size] */
1816/* Puts [comm] if cmdline is empty (-> process is a kernel thread) */ 1845/* Puts [comm] if cmdline is empty (-> process is a kernel thread) */
1846#if !ENABLE_PLATFORM_MINGW32
1817void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; 1847void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC;
1848#else
1849#define read_cmdline(buf, size, pid, comm) snprintf(buf, size, "[%s]", comm)
1850#endif
1818pid_t *find_pid_by_name(const char* procName) FAST_FUNC; 1851pid_t *find_pid_by_name(const char* procName) FAST_FUNC;
1819pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; 1852pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC;
1820int starts_with_cpu(const char *str) FAST_FUNC; 1853int starts_with_cpu(const char *str) FAST_FUNC;
@@ -1958,7 +1991,11 @@ extern const char bb_path_wtmp_file[] ALIGN1;
1958#define bb_path_motd_file "/etc/motd" 1991#define bb_path_motd_file "/etc/motd"
1959 1992
1960#define bb_dev_null "/dev/null" 1993#define bb_dev_null "/dev/null"
1994#if ENABLE_PLATFORM_MINGW32
1995#define bb_busybox_exec_path get_busybox_exec_path()
1996#else
1961extern const char bb_busybox_exec_path[] ALIGN1; 1997extern const char bb_busybox_exec_path[] ALIGN1;
1998#endif
1962/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 1999/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
1963 * but I want to save a few bytes here */ 2000 * but I want to save a few bytes here */
1964extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ 2001extern 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..df52bbd25
--- /dev/null
+++ b/include/mingw.h
@@ -0,0 +1,483 @@
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 04000
37
38/*
39 * grp.h
40 */
41
42struct group {
43 char *gr_name;
44 char *gr_passwd;
45 gid_t gr_gid;
46 char **gr_mem;
47};
48IMPL(getgrnam,struct group *,NULL,const char *name UNUSED_PARAM);
49struct group *getgrgid(gid_t gid);
50NOIMPL(initgroups,const char *group UNUSED_PARAM,gid_t gid UNUSED_PARAM);
51static inline void endgrent(void) {}
52int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups);
53
54/*
55 * limits.h
56 */
57#define NAME_MAX 255
58#define MAXSYMLINKS 20
59
60/*
61 * netdb.h
62 */
63
64typedef int sa_family_t;
65
66/*
67 * linux/un.h
68 */
69struct sockaddr_un {
70 sa_family_t sun_family;
71 char sun_path[1]; /* to make compiler happy, don't bother */
72};
73
74/*
75 * pwd.h
76 */
77struct passwd {
78 char *pw_name;
79 char *pw_passwd;
80 char *pw_gecos;
81 char *pw_dir;
82 char *pw_shell;
83 uid_t pw_uid;
84 gid_t pw_gid;
85};
86
87struct passwd *getpwnam(const char *name);
88struct passwd *getpwuid(uid_t uid);
89static inline void setpwent(void) {}
90static inline void endpwent(void) {}
91IMPL(getpwent_r,int,ENOENT,struct passwd *pwbuf UNUSED_PARAM,char *buf UNUSED_PARAM,size_t buflen UNUSED_PARAM,struct passwd **pwbufp UNUSED_PARAM);
92IMPL(getpwent,struct passwd *,NULL,void)
93
94/*
95 * signal.h
96 */
97#define SIGHUP 1
98#define SIGQUIT 3
99#define SIGKILL 9
100#define SIGUSR1 10
101#define SIGUSR2 12
102#define SIGPIPE 13
103#define SIGALRM 14
104#define SIGCHLD 17
105#define SIGCONT 18
106#define SIGSTOP 19
107#define SIGTSTP 20
108#define SIGTTIN 21
109#define SIGTTOU 22
110#define SIGXCPU 24
111#define SIGXFSZ 25
112#define SIGVTALRM 26
113#define SIGWINCH 28
114
115#define SIG_UNBLOCK 1
116
117typedef void (__cdecl *sighandler_t)(int);
118struct sigaction {
119 sighandler_t sa_handler;
120 unsigned sa_flags;
121 int sa_mask;
122};
123#define sigemptyset(x) (void)0
124#define SA_RESTART 0
125
126NOIMPL(sigaction,int sig UNUSED_PARAM, struct sigaction *in UNUSED_PARAM, struct sigaction *out UNUSED_PARAM);
127NOIMPL(sigfillset,int *mask UNUSED_PARAM);
128NOIMPL(FAST_FUNC sigprocmask_allsigs, int how UNUSED_PARAM);
129NOIMPL(FAST_FUNC sigaction_set,int signo UNUSED_PARAM, const struct sigaction *sa UNUSED_PARAM);
130
131/*
132 * stdio.h
133 */
134#undef fseeko
135#define fseeko(f,o,w) fseek(f,o,w)
136
137int fdprintf(int fd, const char *format, ...);
138FILE* mingw_fopen(const char *filename, const char *mode);
139int mingw_rename(const char*, const char*);
140#define fopen mingw_fopen
141#define rename mingw_rename
142
143FILE *mingw_popen(const char *cmd, const char *mode);
144int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid);
145int mingw_pclose(FILE *fd);
146#undef popen
147#undef pclose
148#define popen mingw_popen
149#define pclose mingw_pclose
150
151#define setlinebuf(fd) setvbuf(fd, (char *) NULL, _IOLBF, 0)
152
153/*
154 * ANSI emulation wrappers
155 */
156
157void move_cursor_row(int n);
158void reset_screen(void);
159int winansi_putchar(int c);
160int winansi_puts(const char *s);
161size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
162int winansi_fputs(const char *str, FILE *stream);
163int winansi_vfprintf(FILE *stream, const char *format, va_list list);
164int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2)));
165int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3)));
166int winansi_write(int fd, const void *buf, size_t count);
167int winansi_read(int fd, void *buf, size_t count);
168int winansi_getc(FILE *stream);
169#define putchar winansi_putchar
170#define puts winansi_puts
171#define fwrite winansi_fwrite
172#define fputs winansi_fputs
173#define vfprintf(stream, ...) winansi_vfprintf(stream, __VA_ARGS__)
174#define vprintf(...) winansi_vfprintf(stdout, __VA_ARGS__)
175#define printf(...) winansi_printf(__VA_ARGS__)
176#define fprintf(...) winansi_fprintf(__VA_ARGS__)
177#define write winansi_write
178#define read winansi_read
179#define getc winansi_getc
180
181int winansi_get_terminal_width_height(struct winsize *win);
182
183/*
184 * stdlib.h
185 */
186#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */
187#define WEXITSTATUS(x) ((x) & 0xff)
188#define WIFSIGNALED(x) ((unsigned)(x) > 259)
189#define WTERMSIG(x) ((x) & 0x7f)
190#define WCOREDUMP(x) 0
191
192int mingw_system(const char *cmd);
193#define system mingw_system
194
195int clearenv(void);
196char *mingw_getenv(const char *name);
197int mingw_putenv(const char *env);
198char *mingw_mktemp(char *template);
199int mkstemp(char *template);
200char *realpath(const char *path, char *resolved_path);
201int setenv(const char *name, const char *value, int replace);
202#if ENABLE_SAFE_ENV
203int unsetenv(const char *env);
204#else
205void unsetenv(const char *env);
206#endif
207
208#define getenv mingw_getenv
209#if ENABLE_SAFE_ENV
210#define putenv mingw_putenv
211#endif
212#define mktemp mingw_mktemp
213
214/*
215 * string.h
216 */
217void *mempcpy(void *dest, const void *src, size_t n);
218
219/*
220 * strings.h
221 */
222int ffs(int i);
223
224/*
225 * sys/ioctl.h
226 */
227
228#define TIOCGWINSZ 0x5413
229
230int ioctl(int fd, int code, ...);
231
232/*
233 * sys/socket.h
234 */
235#define hstrerror strerror
236
237#define SHUT_WR SD_SEND
238
239int mingw_socket(int domain, int type, int protocol);
240int mingw_connect(int sockfd, const struct sockaddr *sa, size_t sz);
241int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
242int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
243int mingw_shutdown(int sockfd, int how);
244int mingw_listen(int sockfd, int backlog);
245int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz);
246int mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
247 struct timeval *timeout);
248
249NOIMPL(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);
250
251#define socket mingw_socket
252#define connect mingw_connect
253#define sendto mingw_sendto
254#define listen mingw_listen
255#define bind mingw_bind
256#define setsockopt mingw_setsockopt
257#define shutdown mingw_shutdown
258#define accept mingw_accept
259#define select mingw_select
260
261/*
262 * sys/stat.h
263 */
264#define S_ISUID 04000
265#define S_ISGID 02000
266#define S_ISVTX 01000
267#ifndef S_IRWXU
268#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
269#endif
270#define S_IRWXG (S_IRWXU >> 3)
271#define S_IRWXO (S_IRWXG >> 3)
272
273#define S_IFSOCK 0140000
274#define S_IFLNK 0120000 /* Symbolic link */
275#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
276#define S_ISSOCK(x) 0
277
278#define S_IRGRP (S_IRUSR >> 3)
279#define S_IWGRP (S_IWUSR >> 3)
280#define S_IXGRP (S_IXUSR >> 3)
281#define S_IROTH (S_IRGRP >> 3)
282#define S_IWOTH (S_IWGRP >> 3)
283#define S_IXOTH (S_IXGRP >> 3)
284
285IMPL(fchmod,int,0,int fildes UNUSED_PARAM, mode_t mode UNUSED_PARAM);
286NOIMPL(fchown,int fd UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
287int mingw_mkdir(const char *path, int mode);
288int mingw_chmod(const char *path, int mode);
289
290#define mkdir mingw_mkdir
291#define chmod mingw_chmod
292
293#if ENABLE_LFS && !defined(__MINGW64_VERSION_MAJOR)
294# define off_t off64_t
295#endif
296
297typedef int nlink_t;
298typedef int blksize_t;
299typedef off_t blkcnt_t;
300
301struct mingw_stat {
302 dev_t st_dev;
303 ino_t st_ino;
304 mode_t st_mode;
305 nlink_t st_nlink;
306 uid_t st_uid;
307 gid_t st_gid;
308 dev_t st_rdev;
309 off_t st_size;
310 time_t st_atime;
311 time_t st_mtime;
312 time_t st_ctime;
313 blksize_t st_blksize;
314 blkcnt_t st_blocks;
315};
316
317int mingw_lstat(const char *file_name, struct mingw_stat *buf);
318int mingw_stat(const char *file_name, struct mingw_stat *buf);
319int mingw_fstat(int fd, struct mingw_stat *buf);
320#undef lstat
321#undef stat
322#undef fstat
323#define lstat mingw_lstat
324#define stat mingw_stat
325#define fstat mingw_fstat
326
327/*
328 * sys/sysmacros.h
329 */
330#define makedev(a,b) 0*(a)*(b) /* avoid unused warning */
331#define minor(x) 0
332#define major(x) 0
333
334/*
335 * sys/time.h
336 */
337#ifndef _TIMESPEC_DEFINED
338#define _TIMESPEC_DEFINED
339struct timespec {
340 time_t tv_sec;
341 long int tv_nsec;
342};
343#endif
344
345int nanosleep(const struct timespec *req, struct timespec *rem);
346
347/*
348 * sys/wait.h
349 */
350#define WNOHANG 1
351#define WUNTRACED 2
352int waitpid(pid_t pid, int *status, int options);
353
354/*
355 * time.h
356 */
357struct tm *gmtime_r(const time_t *timep, struct tm *result);
358struct tm *localtime_r(const time_t *timep, struct tm *result);
359char *strptime(const char *s, const char *format, struct tm *tm);
360size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm);
361int stime(time_t *t);
362
363#define strftime mingw_strftime
364
365/*
366 * times.h
367 */
368#define clock_t long
369
370struct tms {
371 clock_t tms_utime; /* user CPU time */
372 clock_t tms_stime; /* system CPU time */
373 clock_t tms_cutime; /* user CPU time of children */
374 clock_t tms_cstime; /* system CPU time of children */
375};
376
377clock_t times(struct tms *buf);
378
379/*
380 * unistd.h
381 */
382#define PIPE_BUF 8192
383
384#define _SC_CLK_TCK 2
385
386IMPL(alarm,unsigned int,0,unsigned int seconds UNUSED_PARAM);
387IMPL(chown,int,0,const char *path UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
388NOIMPL(chroot,const char *root UNUSED_PARAM);
389NOIMPL(fchdir,int fd UNUSED_PARAM);
390int mingw_dup2 (int fd, int fdto);
391char *mingw_getcwd(char *pointer, int len);
392off_t mingw_lseek(int fd, off_t offset, int whence);
393
394
395IMPL(getgid,int,DEFAULT_GID,void);
396int getgroups(int n, gid_t *groups);
397IMPL(getppid,int,1,void);
398IMPL(getegid,int,DEFAULT_GID,void);
399IMPL(geteuid,int,DEFAULT_UID,void);
400NOIMPL(getsid,pid_t pid UNUSED_PARAM);
401IMPL(getuid,int,DEFAULT_UID,void);
402int getlogin_r(char *buf, size_t len);
403int fcntl(int fd, int cmd, ...);
404#define fork() -1
405IMPL(fsync,int,0,int fd UNUSED_PARAM);
406int kill(pid_t pid, int sig);
407int link(const char *oldpath, const char *newpath);
408NOIMPL(mknod,const char *name UNUSED_PARAM, mode_t mode UNUSED_PARAM, dev_t device UNUSED_PARAM);
409int mingw_open (const char *filename, int oflags, ...);
410int pipe(int filedes[2]);
411NOIMPL(readlink,const char *path UNUSED_PARAM, char *buf UNUSED_PARAM, size_t bufsiz UNUSED_PARAM);
412NOIMPL(setgid,gid_t gid UNUSED_PARAM);
413NOIMPL(setegid,gid_t gid UNUSED_PARAM);
414NOIMPL(setsid,void);
415NOIMPL(setuid,uid_t gid UNUSED_PARAM);
416NOIMPL(seteuid,uid_t gid UNUSED_PARAM);
417unsigned int sleep(unsigned int seconds);
418NOIMPL(symlink,const char *oldpath UNUSED_PARAM, const char *newpath UNUSED_PARAM);
419static inline void sync(void) {}
420long sysconf(int name);
421NOIMPL(ttyname_r,int fd UNUSED_PARAM, char *buf UNUSED_PARAM, int sz UNUSED_PARAM);
422int mingw_unlink(const char *pathname);
423NOIMPL(vfork,void);
424int mingw_access(const char *name, int mode);
425int mingw_rmdir(const char *name);
426
427#define dup2 mingw_dup2
428#define getcwd mingw_getcwd
429#define lchown chown
430#define open mingw_open
431#define unlink mingw_unlink
432#define rmdir mingw_rmdir
433#undef lseek
434#define lseek mingw_lseek
435
436#undef access
437#define access mingw_access
438
439/*
440 * utime.h
441 */
442int utimes(const char *file_name, const struct timeval times[2]);
443
444/*
445 * dirent.h
446 */
447DIR *mingw_opendir(const char *path);
448#define opendir mingw_opendir
449
450/*
451 * MinGW specific
452 */
453#define is_dir_sep(c) ((c) == '/' || (c) == '\\')
454#define PRIuMAX "I64u"
455
456pid_t FAST_FUNC mingw_spawn(char **argv);
457intptr_t FAST_FUNC mingw_spawn_proc(char **argv);
458int mingw_execv(const char *cmd, const char *const *argv);
459int mingw_execvp(const char *cmd, const char *const *argv);
460int mingw_execve(const char *cmd, const char *const *argv, const char *const *envp);
461#define spawn mingw_spawn
462#define execvp mingw_execvp
463#define execve mingw_execve
464#define execv mingw_execv
465
466const char * next_path_sep(const char *path);
467#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
468#define is_absolute_path(path) ((path)[0] == '/' || (path)[0] == '\\' || has_dos_drive_prefix(path))
469
470/*
471 * helpers
472 */
473
474char **copy_environ(const char *const *env);
475void free_environ(char **env);
476char **env_setenv(char **env, const char *name);
477
478const char *get_busybox_exec_path(void);
479void init_winsock(void);
480
481char *file_is_win32_executable(const char *p);
482
483int err_win_to_posix(DWORD winerr);
diff --git a/include/platform.h b/include/platform.h
index 8210e5c49..5ae82427a 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
@@ -124,7 +133,7 @@
124 133
125/* Make all declarations hidden (-fvisibility flag only affects definitions) */ 134/* Make all declarations hidden (-fvisibility flag only affects definitions) */
126/* (don't include system headers after this until corresponding pop!) */ 135/* (don't include system headers after this until corresponding pop!) */
127#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) 136#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) && !ENABLE_PLATFORM_MINGW32
128# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)") 137# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)")
129# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop") 138# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop")
130#else 139#else
@@ -153,6 +162,14 @@
153# define bswap_64 __bswap64 162# define bswap_64 __bswap64
154# define bswap_32 __bswap32 163# define bswap_32 __bswap32
155# define bswap_16 __bswap16 164# define bswap_16 __bswap16
165# define __BIG_ENDIAN__ (_BYTE_ORDER == _BIG_ENDIAN)
166#elif ENABLE_PLATFORM_MINGW32
167# define __BIG_ENDIAN 0
168# define __LITTLE_ENDIAN 1
169# define __BYTE_ORDER __LITTLE_ENDIAN
170# define bswap_16(x) ((((x) & 0xFF00) >> 8) | (((x) & 0xFF) << 8))
171# define bswap_32(x) ((bswap_16(((x) & 0xFFFF0000L) >> 16)) | (bswap_16((x) & 0xFFFFL) << 16))
172# define bswap_64(x) ((bswap_32(((x) & 0xFFFFFFFF00000000LL) >> 32)) | (bswap_32((x) & 0xFFFFFFFFLL) << 32))
156#else 173#else
157# include <byteswap.h> 174# include <byteswap.h>
158# include <endian.h> 175# include <endian.h>
@@ -411,6 +428,25 @@ typedef unsigned smalluint;
411# endif 428# endif
412#endif 429#endif
413 430
431#if ENABLE_PLATFORM_MINGW32
432# undef HAVE_DPRINTF
433# undef HAVE_GETLINE
434# undef HAVE_MEMRCHR
435# undef HAVE_MKDTEMP
436# undef HAVE_SETBIT
437# undef HAVE_STPCPY
438# undef HAVE_STRCASESTR
439# undef HAVE_STRCHRNUL
440# undef HAVE_STRSEP
441# undef HAVE_STRSIGNAL
442# undef HAVE_STRVERSCMP
443#if !defined(__MINGW64_VERSION_MAJOR)
444# undef HAVE_VASPRINTF
445#endif
446# undef HAVE_UNLOCKED_STDIO
447# undef HAVE_UNLOCKED_LINE_OPS
448#endif
449
414#if defined(__WATCOMC__) 450#if defined(__WATCOMC__)
415# undef HAVE_DPRINTF 451# undef HAVE_DPRINTF
416# undef HAVE_GETLINE 452# undef HAVE_GETLINE
@@ -522,6 +558,7 @@ extern int dprintf(int fd, const char *format, ...);
522#endif 558#endif
523 559
524#ifndef HAVE_MEMRCHR 560#ifndef HAVE_MEMRCHR
561#include <stddef.h>
525extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC; 562extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC;
526#endif 563#endif
527 564
@@ -581,6 +618,7 @@ extern int usleep(unsigned) FAST_FUNC;
581#endif 618#endif
582 619
583#ifndef HAVE_VASPRINTF 620#ifndef HAVE_VASPRINTF
621# include <stdarg.h>
584extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC; 622extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC;
585#endif 623#endif
586 624
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index 49493c501..0d7dd2a2c 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
@@ -110,10 +103,20 @@ lib-y += xfuncs.o
110lib-y += xfuncs_printf.o 103lib-y += xfuncs_printf.o
111lib-y += xfunc_die.o 104lib-y += xfunc_die.o
112lib-y += xgetcwd.o 105lib-y += xgetcwd.o
113lib-y += xgethostbyname.o
114lib-y += xreadlink.o 106lib-y += xreadlink.o
115lib-y += xrealloc_vector.o 107lib-y += xrealloc_vector.o
116 108
109lib-$(CONFIG_PLATFORM_POSIX) += get_console.o
110lib-$(CONFIG_PLATFORM_POSIX) += getpty.o
111lib-$(CONFIG_PLATFORM_POSIX) += inet_common.o
112lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o
113lib-$(CONFIG_PLATFORM_POSIX) += login.o
114lib-$(CONFIG_PLATFORM_POSIX) += makedev.o
115lib-$(CONFIG_PLATFORM_POSIX) += read_key.o
116lib-$(CONFIG_PLATFORM_POSIX) += signals.o
117lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o
118lib-$(CONFIG_PLATFORM_POSIX) += xgethostbyname.o
119
117lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o 120lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o
118 121
119lib-$(CONFIG_FEATURE_UTMP) += utmp.o 122lib-$(CONFIG_FEATURE_UTMP) += utmp.o
@@ -125,7 +128,7 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
125lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o 128lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o
126lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o 129lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
127 130
128lib-$(CONFIG_NC) += udp_io.o 131lib-$(CONFIG_NC_110_COMPAT) += udp_io.o
129lib-$(CONFIG_DNSD) += udp_io.o 132lib-$(CONFIG_DNSD) += udp_io.o
130lib-$(CONFIG_NTPD) += udp_io.o 133lib-$(CONFIG_NTPD) += udp_io.o
131lib-$(CONFIG_TFTP) += udp_io.o 134lib-$(CONFIG_TFTP) += udp_io.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index b9fbbd1f2..34b73afa5 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -98,6 +98,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
98#if ENABLE_FEATURE_COMPRESS_USAGE 98#if ENABLE_FEATURE_COMPRESS_USAGE
99 99
100static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; 100static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
101#define BB_ARCHIVE_PUBLIC
101# include "bb_archive.h" 102# include "bb_archive.h"
102static const char *unpack_usage_messages(void) 103static const char *unpack_usage_messages(void)
103{ 104{
@@ -318,6 +319,10 @@ void lbb_prepare(const char *applet
318 if (ENABLE_LOCALE_SUPPORT) 319 if (ENABLE_LOCALE_SUPPORT)
319 setlocale(LC_ALL, ""); 320 setlocale(LC_ALL, "");
320 321
322#if ENABLE_PLATFORM_MINGW32
323 init_winsock();
324#endif
325
321#if ENABLE_FEATURE_INDIVIDUAL 326#if ENABLE_FEATURE_INDIVIDUAL
322 /* Redundant for busybox (run_applet_and_exit covers that case) 327 /* Redundant for busybox (run_applet_and_exit covers that case)
323 * but needed for "individual applet" mode */ 328 * but needed for "individual applet" mode */
@@ -708,6 +713,7 @@ static void check_suid(int applet_no)
708 713
709 714
710# if ENABLE_FEATURE_INSTALLER 715# if ENABLE_FEATURE_INSTALLER
716# if !ENABLE_PLATFORM_MINGW32
711static const char usr_bin [] ALIGN1 = "/usr/bin/"; 717static const char usr_bin [] ALIGN1 = "/usr/bin/";
712static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; 718static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
713static const char *const install_dir[] = { 719static const char *const install_dir[] = {
@@ -752,6 +758,29 @@ static void install_links(const char *busybox, int use_symbolic_links,
752 continue; 758 continue;
753 } 759 }
754} 760}
761# else /* ENABLE_PLATFORM_MINGW32 */
762static void install_links(const char *busybox,
763 int use_symbolic_links UNUSED_PARAM, char *custom_install_dir)
764{
765 char *fpc;
766 const char *appname = applet_names;
767 int rc;
768
769 if (!is_directory(custom_install_dir, FALSE))
770 bb_error_msg_and_die("'%s' is not a directory", custom_install_dir);
771
772 while (*appname) {
773 fpc = xasprintf("%s/%s.exe", custom_install_dir, appname);
774 rc = link(busybox, fpc);
775 if (rc != 0 && errno != EEXIST) {
776 bb_simple_perror_msg(fpc);
777 }
778 free(fpc);
779 while (*appname++ != '\0')
780 continue;
781 }
782}
783# endif
755# elif ENABLE_BUSYBOX 784# elif ENABLE_BUSYBOX
756static void install_links(const char *busybox UNUSED_PARAM, 785static void install_links(const char *busybox UNUSED_PARAM,
757 int use_symbolic_links UNUSED_PARAM, 786 int use_symbolic_links UNUSED_PARAM,
@@ -777,15 +806,25 @@ static int busybox_main(char **argv)
777 dup2(1, 2); 806 dup2(1, 2);
778 full_write2_str(bb_banner); /* reuse const string */ 807 full_write2_str(bb_banner); /* reuse const string */
779 full_write2_str(" multi-call binary.\n"); /* reuse */ 808 full_write2_str(" multi-call binary.\n"); /* reuse */
809#if defined(MINGW_VER)
810 if (strlen(MINGW_VER)) {
811 full_write2_str(MINGW_VER "\n\n");
812 }
813#endif
780 full_write2_str( 814 full_write2_str(
781 "BusyBox is copyrighted by many authors between 1998-2015.\n" 815 "BusyBox is copyrighted by many authors between 1998-2015.\n"
782 "Licensed under GPLv2. See source distribution for detailed\n" 816 "Licensed under GPLv2. See source distribution for detailed\n"
783 "copyright notices.\n" 817 "copyright notices.\n"
784 "\n" 818 "\n"
785 "Usage: busybox [function [arguments]...]\n" 819 "Usage: busybox [function [arguments]...]\n"
820 IF_NOT_PLATFORM_MINGW32(
786 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" 821 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
822 )
823 IF_PLATFORM_MINGW32(
824 " or: busybox --list\n"
825 )
787 IF_FEATURE_INSTALLER( 826 IF_FEATURE_INSTALLER(
788 " or: busybox --install [-s] [DIR]\n" 827 " or: busybox --install "IF_NOT_PLATFORM_MINGW32("[-s] ")"[DIR]\n"
789 ) 828 )
790 " or: function [arguments]...\n" 829 " or: function [arguments]...\n"
791 "\n" 830 "\n"
@@ -803,6 +842,11 @@ static int busybox_main(char **argv)
803 "\tTo run external program, use full path (/sbin/ip instead of ip).\n" 842 "\tTo run external program, use full path (/sbin/ip instead of ip).\n"
804 ) 843 )
805 "\n" 844 "\n"
845#if ENABLE_GLOBBING
846 "\tSupport for native Windows wildcards is enabled. In some\n"
847 "\tcases this may result in wildcards being processed twice.\n"
848 "\n"
849#endif
806 "Currently defined functions:\n" 850 "Currently defined functions:\n"
807 ); 851 );
808 col = 0; 852 col = 0;
@@ -834,7 +878,7 @@ static int busybox_main(char **argv)
834 const char *a = applet_names; 878 const char *a = applet_names;
835 dup2(1, 2); 879 dup2(1, 2);
836 while (*a) { 880 while (*a) {
837# if ENABLE_FEATURE_INSTALLER 881# if ENABLE_FEATURE_INSTALLER && !ENABLE_PLATFORM_MINGW32
838 if (argv[1][6]) /* --list-full? */ 882 if (argv[1][6]) /* --list-full? */
839 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); 883 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
840# endif 884# endif
@@ -848,6 +892,7 @@ static int busybox_main(char **argv)
848 } 892 }
849 893
850 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { 894 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
895#if !ENABLE_PLATFORM_MINGW32
851 int use_symbolic_links; 896 int use_symbolic_links;
852 const char *busybox; 897 const char *busybox;
853 898
@@ -868,6 +913,14 @@ static int busybox_main(char **argv)
868 */ 913 */
869 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv); 914 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv);
870 install_links(busybox, use_symbolic_links, argv[2]); 915 install_links(busybox, use_symbolic_links, argv[2]);
916#else
917 /* busybox --install [DIR]
918 * where DIR is the directory to install to. If DIR is not
919 * provided put the links in the same directory as busybox.
920 */
921 install_links(bb_busybox_exec_path, FALSE, argv[2] ? argv[2] :
922 dirname(xstrdup(bb_busybox_exec_path)));
923#endif
871 return 0; 924 return 0;
872 } 925 }
873 926
@@ -1009,6 +1062,18 @@ int main(int argc UNUSED_PARAM, char **argv)
1009 } 1062 }
1010#endif 1063#endif
1011 1064
1065#if defined(__MINGW64_VERSION_MAJOR)
1066 if ( stdin ) {
1067 _setmode(fileno(stdin), _O_BINARY);
1068 }
1069 if ( stdout ) {
1070 _setmode(fileno(stdout), _O_BINARY);
1071 }
1072 if ( stderr ) {
1073 _setmode(fileno(stderr), _O_BINARY);
1074 }
1075#endif
1076
1012#if defined(SINGLE_APPLET_MAIN) 1077#if defined(SINGLE_APPLET_MAIN)
1013 1078
1014 /* Only one applet is selected in .config */ 1079 /* Only one applet is selected in .config */
@@ -1040,6 +1105,29 @@ int main(int argc UNUSED_PARAM, char **argv)
1040 applet_name = argv[0]; 1105 applet_name = argv[0];
1041 if (applet_name[0] == '-') 1106 if (applet_name[0] == '-')
1042 applet_name++; 1107 applet_name++;
1108 if (ENABLE_PLATFORM_MINGW32) {
1109 const char *applet_name_env = getenv("BUSYBOX_APPLET_NAME");
1110 if (applet_name_env && *applet_name_env) {
1111 applet_name = applet_name_env;
1112 unsetenv("BUSYBOX_APPLET_NAME");
1113 }
1114 else if ( argv[1] && argv[2] && strcmp(argv[1], "--busybox") == 0 ) {
1115 argv += 2;
1116 applet_name = argv[0];
1117 }
1118 else {
1119 char *s = argv[0];
1120 int i, len = strlen(s);
1121
1122 for ( i=0; i < len; ++i ) {
1123 s[i] = tolower(s[i]);
1124 }
1125 if (len > 4 && !strcmp(s+len-4, ".exe")) {
1126 len -= 4;
1127 s[len] = '\0';
1128 }
1129 }
1130 }
1043 applet_name = bb_basename(applet_name); 1131 applet_name = bb_basename(applet_name);
1044 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */ 1132 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
1045 run_applet_and_exit(applet_name, argv); 1133 run_applet_and_exit(applet_name, argv);
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 2a5d4e704..670a1b194 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
@@ -638,6 +680,14 @@ static void add_match(char *matched)
638 num_matches++; 680 num_matches++;
639} 681}
640 682
683#if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
684static void add_partial_match(const char *part, const char *full, int plen)
685{
686 if (strncmp(part, full, plen) == 0)
687 add_match(xstrdup(full));
688}
689#endif
690
641# if ENABLE_FEATURE_USERNAME_COMPLETION 691# if ENABLE_FEATURE_USERNAME_COMPLETION
642/* Replace "~user/..." with "/homedir/...". 692/* Replace "~user/..." with "/homedir/...".
643 * The parameter is malloced, free it or return it 693 * The parameter is malloced, free it or return it
@@ -718,7 +768,11 @@ static int path_parse(char ***p)
718 tmp = (char*)pth; 768 tmp = (char*)pth;
719 npth = 1; /* path component count */ 769 npth = 1; /* path component count */
720 while (1) { 770 while (1) {
771#if ENABLE_PLATFORM_MINGW32
772 tmp = (char *)next_path_sep(tmp);
773#else
721 tmp = strchr(tmp, ':'); 774 tmp = strchr(tmp, ':');
775#endif
722 if (!tmp) 776 if (!tmp)
723 break; 777 break;
724 tmp++; 778 tmp++;
@@ -731,7 +785,11 @@ static int path_parse(char ***p)
731 res[0] = tmp = xstrdup(pth); 785 res[0] = tmp = xstrdup(pth);
732 npth = 1; 786 npth = 1;
733 while (1) { 787 while (1) {
788#if ENABLE_PLATFORM_MINGW32
789 tmp = (char *)next_path_sep(tmp);
790#else
734 tmp = strchr(tmp, ':'); 791 tmp = strchr(tmp, ':');
792#endif
735 if (!tmp) 793 if (!tmp)
736 break; 794 break;
737 *tmp++ = '\0'; /* ':' -> '\0' */ 795 *tmp++ = '\0'; /* ':' -> '\0' */
@@ -781,11 +839,11 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
781 const char *p = applet_names; 839 const char *p = applet_names;
782 840
783 while (*p) { 841 while (*p) {
784 if (strncmp(pfind, p, pf_len) == 0) 842 add_partial_match(pfind, p, pf_len);
785 add_match(xstrdup(p));
786 while (*p++ != '\0') 843 while (*p++ != '\0')
787 continue; 844 continue;
788 } 845 }
846 add_partial_match(pfind, "busybox", pf_len);
789 } 847 }
790#endif 848#endif
791 849
@@ -817,6 +875,9 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
817 if (stat(found, &st) && lstat(found, &st)) 875 if (stat(found, &st) && lstat(found, &st))
818 goto cont; /* hmm, remove in progress? */ 876 goto cont; /* hmm, remove in progress? */
819 877
878 if (type == FIND_EXE_ONLY && !file_is_executable(found))
879 goto cont;
880
820 /* Save only name */ 881 /* Save only name */
821 len = strlen(name_found); 882 len = strlen(name_found);
822 found = xrealloc(found, len + 2); /* +2: for slash and NUL */ 883 found = xrealloc(found, len + 2); /* +2: for slash and NUL */
@@ -1898,7 +1959,16 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1898 char *after_home_user; 1959 char *after_home_user;
1899 1960
1900 /* /home/user[/something] -> ~[/something] */ 1961 /* /home/user[/something] -> ~[/something] */
1962#if !ENABLE_PLATFORM_MINGW32
1901 after_home_user = is_prefixed_with(cwd_buf, home_pwd_buf); 1963 after_home_user = is_prefixed_with(cwd_buf, home_pwd_buf);
1964#else
1965 after_home_user = NULL;
1966 l = strlen(home_pwd_buf);
1967 if (l != 0
1968 && strncasecmp(home_pwd_buf, cwd_buf, l) == 0) {
1969 after_home_user = cwd_buf + l;
1970 }
1971#endif
1902 if (after_home_user 1972 if (after_home_user
1903 && (*after_home_user == '/' || *after_home_user == '\0') 1973 && (*after_home_user == '/' || *after_home_user == '\0')
1904 ) { 1974 ) {
@@ -2272,9 +2342,16 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2272 2342
2273 INIT_S(); 2343 INIT_S();
2274 2344
2345#if ENABLE_PLATFORM_MINGW32
2346 memset(initial_settings.c_cc, 0, sizeof(initial_settings.c_cc));
2347 initial_settings.c_cc[VINTR] = CTRL('C');
2348 initial_settings.c_cc[VEOF] = CTRL('D');
2349 if (!isatty(0) || !isatty(1)) {
2350#else
2275 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0 2351 if (tcgetattr(STDIN_FILENO, &initial_settings) < 0
2276 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON 2352 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON
2277 ) { 2353 ) {
2354#endif
2278 /* Happens when e.g. stty -echo was run before. 2355 /* Happens when e.g. stty -echo was run before.
2279 * But if ICANON is not set, we don't come here. 2356 * But if ICANON is not set, we don't come here.
2280 * (example: interactive python ^Z-backgrounded, 2357 * (example: interactive python ^Z-backgrounded,
@@ -2383,6 +2460,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2383 } 2460 }
2384 2461
2385 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); 2462 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
2463#if ENABLE_PLATFORM_MINGW32
2464 /* scroll to cursor position on any keypress */
2465 if (isatty(fileno(stdin)) && isatty(fileno(stdout)))
2466 move_cursor_row(0);
2467#endif
2386 2468
2387#if ENABLE_FEATURE_REVERSE_SEARCH 2469#if ENABLE_FEATURE_REVERSE_SEARCH
2388 again: 2470 again:
@@ -2650,6 +2732,44 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2650 vi_cmdmode = 1; 2732 vi_cmdmode = 1;
2651 input_backward(1); 2733 input_backward(1);
2652 } 2734 }
2735 /* Handle a few ESC-<key> combinations the same way
2736 * standard readline bindings (IOW: bash) do.
2737 * Often, Alt-<key> generates ESC-<key>.
2738 */
2739 ic = lineedit_read_key(read_key_buffer, 20);
2740 switch (ic) {
2741 //case KEYCODE_LEFT: - bash doesn't do this
2742 case 'b':
2743 ctrl_left();
2744 break;
2745 //case KEYCODE_RIGHT: - bash doesn't do this
2746 case 'f':
2747 ctrl_right();
2748 break;
2749 //case KEYCODE_DELETE: - bash doesn't do this
2750 case 'd': /* Alt-D */
2751 {
2752 /* Delete word forward */
2753 int nc, sc = cursor;
2754 ctrl_right();
2755 nc = cursor - sc;
2756 input_backward(nc);
2757 while (--nc >= 0)
2758 input_delete(1);
2759 break;
2760 }
2761 case '\b': /* Alt-Backspace(?) */
2762 case '\x7f': /* Alt-Backspace(?) */
2763 //case 'w': - bash doesn't do this
2764 {
2765 /* Delete word backward */
2766 int sc = cursor;
2767 ctrl_left();
2768 while (sc-- > cursor)
2769 input_delete(1);
2770 break;
2771 }
2772 }
2653 break; 2773 break;
2654#endif /* FEATURE_COMMAND_EDITING_VI */ 2774#endif /* FEATURE_COMMAND_EDITING_VI */
2655 2775
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 4781a4276..5320c6966 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 7986fef5f..6b8364dd9 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 507e579c4..16be1447e 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 6a636f1ec..741980961 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 35b4e4b64..3eadd752d 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 d2b1ddcce..1b70434ac 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 252f94dc6..b9d840328 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 c290c594b..2db343f69 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 6028903fa..8a79fd8ba 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 e8b122c5a..f7242f2d5 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);
@@ -366,6 +371,7 @@ static void func_tty(char *buf, int size, const procps_status_t *ps)
366 if (ps->tty_major) /* tty field of "0" means "no tty" */ 371 if (ps->tty_major) /* tty field of "0" means "no tty" */
367 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor); 372 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
368} 373}
374#endif
369 375
370#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 376#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
371 377
@@ -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,11 +467,13 @@ 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 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE }, 474 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE },
462 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, 475 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS },
476#endif
463#if ENABLE_SELINUX 477#if ENABLE_SELINUX
464 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, 478 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT },
465#endif 479#endif
@@ -598,6 +612,8 @@ static void format_process(const procps_status_t *ps)
598#if ENABLE_SELINUX 612#if ENABLE_SELINUX
599# define SELINUX_O_PREFIX "label," 613# define SELINUX_O_PREFIX "label,"
600# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") 614# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args")
615#elif ENABLE_PLATFORM_MINGW32
616# define DEFAULT_O_STR ("pid,comm")
601#else 617#else
602# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") 618# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args")
603#endif 619#endif
diff --git a/procps/smemcap.c b/procps/smemcap.c
index 9d1126a49..b2b32198f 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 aaf0561b8..6cc29d25e 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" 34//config: bool "ash"
20//config: default y 35//config: default y
@@ -133,6 +148,18 @@
133//config: you to run the specified command or builtin, 148//config: you to run the specified command or builtin,
134//config: even when there is a function with the same name. 149//config: even when there is a function with the same name.
135//config: 150//config:
151//config:
152//config:config ASH_NOCONSOLE
153//config: bool "'noconsole' option"
154//config: default y
155//config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32
156//config: help
157//config: Enable support for the 'noconsole' option, which attempts to
158//config: hide the console normally associated with a command line
159//config: application. This may be useful when running a shell script
160//config: from a GUI application. Disable this if your platform doesn't
161//config: support the required APIs.
162//config:
136//config:endif # ash options 163//config:endif # ash options
137 164
138//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) 165//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
@@ -238,10 +265,58 @@
238# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 265# define PIPE_BUF 4096 /* amount of buffering in a pipe */
239#endif 266#endif
240 267
268#if !ENABLE_PLATFORM_MINGW32
269# define is_absolute_path(path) ((path)[0] == '/')
270#endif
271
241#if !BB_MMU 272#if !BB_MMU
242# error "Do not even bother, ash will not run on NOMMU machine" 273# error "Do not even bother, ash will not run on NOMMU machine"
243#endif 274#endif
244 275
276#if ENABLE_PLATFORM_MINGW32
277union node;
278struct strlist;
279struct job;
280
281struct forkshell {
282 /* filled by forkshell_copy() */
283 struct globals_var *gvp;
284 struct globals_misc *gmp;
285 struct tblentry **cmdtable;
286 /* struct alias **atab; */
287 /* struct parsefile *g_parsefile; */
288 HANDLE hMapFile;
289 void *old_base;
290 int nodeptr_offset;
291 int size;
292
293 /* type of forkshell */
294 int fpid;
295
296 /* optional data, used by forkshell_child */
297 int flags;
298 int fd[10];
299 union node *n;
300 char **argv;
301 char *string;
302 struct strlist *strlist;
303};
304
305enum {
306 FS_OPENHERE,
307 FS_EVALBACKCMD,
308 FS_EVALSUBSHELL,
309 FS_EVALPIPE,
310 FS_SHELLEXEC
311};
312
313static struct forkshell* forkshell_prepare(struct forkshell *fs);
314static void forkshell_init(const char *idstr);
315static void forkshell_child(struct forkshell *fs);
316static void sticky_free(void *p);
317#define free(p) sticky_free(p)
318static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
319#endif
245 320
246/* ============ Hash table sizes. Configurable. */ 321/* ============ Hash table sizes. Configurable. */
247 322
@@ -274,6 +349,12 @@ static const char *const optletters_optnames[] = {
274 ,"\0" "nolog" 349 ,"\0" "nolog"
275 ,"\0" "debug" 350 ,"\0" "debug"
276#endif 351#endif
352#if ENABLE_PLATFORM_MINGW32
353 ,"X" "winxp"
354#endif
355#if ENABLE_ASH_NOCONSOLE
356 ,"\0" "noconsole"
357#endif
277}; 358};
278 359
279#define optletters(n) optletters_optnames[n][0] 360#define optletters(n) optletters_optnames[n][0]
@@ -353,6 +434,12 @@ struct globals_misc {
353# define nolog optlist[14 + BASH_PIPEFAIL] 434# define nolog optlist[14 + BASH_PIPEFAIL]
354# define debug optlist[15 + BASH_PIPEFAIL] 435# define debug optlist[15 + BASH_PIPEFAIL]
355#endif 436#endif
437#if ENABLE_PLATFORM_MINGW32
438# define winxp optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
439#endif
440#if ENABLE_ASH_NOCONSOLE
441# define noconsole optlist[15 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
442#endif
356 443
357 /* trap handler commands */ 444 /* trap handler commands */
358 /* 445 /*
@@ -2406,10 +2493,22 @@ path_advance(const char **path, const char *name)
2406 if (*path == NULL) 2493 if (*path == NULL)
2407 return NULL; 2494 return NULL;
2408 start = *path; 2495 start = *path;
2496#if ENABLE_PLATFORM_MINGW32
2497 p = next_path_sep(start);
2498 q = strchr(start, '%');
2499 if ((p && q && q < p) || (!p && q))
2500 p = q;
2501 if (!p)
2502 for (p = start; *p; p++)
2503 continue;
2504#else
2409 for (p = start; *p && *p != ':' && *p != '%'; p++) 2505 for (p = start; *p && *p != ':' && *p != '%'; p++)
2410 continue; 2506 continue;
2507#endif
2411 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2508 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2412 while (stackblocksize() < len) 2509
2510 /* preserve space for .exe too */
2511 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2413 growstackblock(); 2512 growstackblock();
2414 q = stackblock(); 2513 q = stackblock();
2415 if (p != start) { 2514 if (p != start) {
@@ -2421,10 +2520,19 @@ path_advance(const char **path, const char *name)
2421 pathopt = NULL; 2520 pathopt = NULL;
2422 if (*p == '%') { 2521 if (*p == '%') {
2423 pathopt = ++p; 2522 pathopt = ++p;
2523#if ENABLE_PLATFORM_MINGW32
2524 p = next_path_sep(start);
2525
2526 /* *p != ':' and '*' would suffice */
2527 if (!p)
2528 p = pathopt - 1;
2529#else
2424 while (*p && *p != ':') 2530 while (*p && *p != ':')
2425 p++; 2531 p++;
2532#endif
2426 } 2533 }
2427 if (*p == ':') 2534 if (*p == ':' ||
2535 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2428 *path = p + 1; 2536 *path = p + 1;
2429 else 2537 else
2430 *path = NULL; 2538 *path = NULL;
@@ -2521,6 +2629,106 @@ cdopt(void)
2521static const char * 2629static const char *
2522updatepwd(const char *dir) 2630updatepwd(const char *dir)
2523{ 2631{
2632#if ENABLE_PLATFORM_MINGW32
2633#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2634#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1]))
2635 /*
2636 * Due to Windows drive notion, getting pwd is a completely
2637 * different thing. Handle it in a separate routine
2638 */
2639
2640 char *new;
2641 char *p;
2642 char *cdcomppath;
2643 const char *lim;
2644 /*
2645 * There are five cases that make some kind of sense
2646 * absdrive + abspath: c:/path
2647 * absdrive + !abspath: c:path
2648 * !absdrive + abspath: /path
2649 * !absdrive + uncpath: //host/share
2650 * !absdrive + !abspath: path
2651 *
2652 * Damn DOS!
2653 * c:path behaviour is "undefined"
2654 * To properly handle this case, I have to keep track of cwd
2655 * of every drive, which is too painful to do.
2656 * So when c:path is given, I assume it's c:${curdir}path
2657 * with ${curdir} comes from the current drive
2658 */
2659 int absdrive = *dir && dir[1] == ':';
2660 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2661
2662 cdcomppath = sstrdup(dir);
2663 STARTSTACKSTR(new);
2664 if (!absdrive && curdir == nullstr)
2665 return 0;
2666 if (!abspath) {
2667 if (curdir == nullstr)
2668 return 0;
2669 new = stack_putstr(curdir, new);
2670 }
2671 new = makestrspace(strlen(dir) + 2, new);
2672
2673 if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) {
2674 lim = (char *)stackblock() + 1;
2675 }
2676 else {
2677 char *drive = stackblock();
2678 if (absdrive) {
2679 *drive = *dir;
2680 cdcomppath += 2;
2681 dir += 2;
2682 } else {
2683 *drive = *curdir;
2684 }
2685 drive[1] = ':'; /* in case of absolute drive+path */
2686
2687 if (abspath)
2688 new = drive + 2;
2689 lim = drive + 3;
2690 }
2691
2692 if (!abspath) {
2693 if (!is_path_sep(new[-1]))
2694 USTPUTC('/', new);
2695 if (new > lim && is_path_sep(*lim))
2696 lim++;
2697 } else {
2698 USTPUTC('/', new);
2699 cdcomppath ++;
2700 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2701 USTPUTC('/', new);
2702 cdcomppath++;
2703 lim++;
2704 }
2705 }
2706 p = strtok(cdcomppath, "/\\");
2707 while (p) {
2708 switch (*p) {
2709 case '.':
2710 if (p[1] == '.' && p[2] == '\0') {
2711 while (new > lim) {
2712 STUNPUTC(new);
2713 if (is_path_sep(new[-1]))
2714 break;
2715 }
2716 break;
2717 }
2718 if (p[1] == '\0')
2719 break;
2720 /* fall through */
2721 default:
2722 new = stack_putstr(p, new);
2723 USTPUTC('/', new);
2724 }
2725 p = strtok(0, "/\\");
2726 }
2727 if (new > lim)
2728 STUNPUTC(new);
2729 *new = 0;
2730 return stackblock();
2731#else
2524 char *new; 2732 char *new;
2525 char *p; 2733 char *p;
2526 char *cdcomppath; 2734 char *cdcomppath;
@@ -2574,6 +2782,7 @@ updatepwd(const char *dir)
2574 STUNPUTC(new); 2782 STUNPUTC(new);
2575 *new = 0; 2783 *new = 0;
2576 return stackblock(); 2784 return stackblock();
2785#endif
2577} 2786}
2578 2787
2579/* 2788/*
@@ -2668,7 +2877,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2668 } 2877 }
2669 if (!dest) 2878 if (!dest)
2670 dest = nullstr; 2879 dest = nullstr;
2671 if (*dest == '/') 2880 if (is_absolute_path(dest))
2672 goto step6; 2881 goto step6;
2673 if (*dest == '.') { 2882 if (*dest == '.') {
2674 c = dest[1]; 2883 c = dest[1];
@@ -3377,6 +3586,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3377 */ 3586 */
3378struct procstat { 3587struct procstat {
3379 pid_t ps_pid; /* process id */ 3588 pid_t ps_pid; /* process id */
3589#if ENABLE_PLATFORM_MINGW32
3590 HANDLE ps_proc;
3591#endif
3380 int ps_status; /* last process status from wait() */ 3592 int ps_status; /* last process status from wait() */
3381 char *ps_cmd; /* text of command being run */ 3593 char *ps_cmd; /* text of command being run */
3382}; 3594};
@@ -3405,7 +3617,9 @@ struct job {
3405}; 3617};
3406 3618
3407static struct job *makejob(/*union node *,*/ int); 3619static struct job *makejob(/*union node *,*/ int);
3620#if !ENABLE_PLATFORM_MINGW32
3408static int forkshell(struct job *, union node *, int); 3621static int forkshell(struct job *, union node *, int);
3622#endif
3409static int waitforjob(struct job *); 3623static int waitforjob(struct job *);
3410 3624
3411#if !JOBS 3625#if !JOBS
@@ -3430,6 +3644,7 @@ ignoresig(int signo)
3430 sigmode[signo - 1] = S_HARD_IGN; 3644 sigmode[signo - 1] = S_HARD_IGN;
3431} 3645}
3432 3646
3647#if !ENABLE_PLATFORM_MINGW32
3433/* 3648/*
3434 * Only one usage site - in setsignal() 3649 * Only one usage site - in setsignal()
3435 */ 3650 */
@@ -3554,6 +3769,9 @@ setsignal(int signo)
3554 3769
3555 *t = new_act; 3770 *t = new_act;
3556} 3771}
3772#else
3773#define setsignal(s)
3774#endif
3557 3775
3558/* mode flags for set_curjob */ 3776/* mode flags for set_curjob */
3559#define CUR_DELETE 2 3777#define CUR_DELETE 2
@@ -4051,6 +4269,97 @@ sprint_status48(char *s, int status, int sigonly)
4051 return col; 4269 return col;
4052} 4270}
4053 4271
4272#if ENABLE_PLATFORM_MINGW32
4273
4274HANDLE hSIGINT; /* Ctrl-C is pressed */
4275
4276static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4277{
4278 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4279 SetEvent(hSIGINT);
4280 return TRUE;
4281 }
4282 return FALSE;
4283}
4284
4285/*
4286 * Windows does not know about parent-child relationship
4287 * They don't support waitpid(-1)
4288 */
4289static pid_t
4290waitpid_child(int *status, int wait_flags)
4291{
4292 pid_t *pidlist;
4293 HANDLE *proclist;
4294 int pid_nr = 0;
4295 pid_t pid;
4296 DWORD win_status, idx;
4297 struct job *jb;
4298
4299 for (jb = curjob; jb; jb = jb->prev_job) {
4300 if (jb->state != JOBDONE)
4301 pid_nr += jb->nprocs;
4302 }
4303 if ( pid_nr++ == 0 )
4304 return -1;
4305
4306 pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4307 proclist = ckmalloc(sizeof(*proclist)*pid_nr);
4308
4309 pidlist[0] = -1;
4310 proclist[0] = hSIGINT;
4311 pid_nr = 1;
4312 for (jb = curjob; jb; jb = jb->prev_job) {
4313 struct procstat *ps, *psend;
4314 if (jb->state == JOBDONE)
4315 continue;
4316 ps = jb->ps;
4317 psend = ps + jb->nprocs;
4318 while (ps < psend) {
4319 if (ps->ps_pid != -1 && ps->ps_proc != NULL) {
4320 pidlist[pid_nr] = ps->ps_pid;
4321 proclist[pid_nr++] = ps->ps_proc;
4322 }
4323 ps++;
4324 }
4325 }
4326
4327 if (pid_nr == 1) {
4328 free(pidlist);
4329 free(proclist);
4330 return -1;
4331 }
4332
4333 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE,
4334 wait_flags|WNOHANG ? 1 : INFINITE);
4335 if (idx >= pid_nr) {
4336 free(pidlist);
4337 free(proclist);
4338 return -1;
4339 }
4340 if (!idx) { /* hSIGINT */
4341 int i;
4342 ResetEvent(hSIGINT);
4343 for (i = 1; i < pid_nr; i++)
4344 TerminateProcess(proclist[i], 1);
4345 pid = pidlist[1];
4346 free(pidlist);
4347 free(proclist);
4348 *status = 260; /* terminated by a signal */
4349 return pid;
4350 }
4351 GetExitCodeProcess(proclist[idx], &win_status);
4352 pid = pidlist[idx];
4353 free(pidlist);
4354 free(proclist);
4355 *status = (int)win_status;
4356 return pid;
4357}
4358#define waitpid(p, s, f) waitpid_child(s, f)
4359#define wait_block_or_sig(s) waitpid_child(s, 0)
4360
4361#else
4362
4054static int 4363static int
4055wait_block_or_sig(int *status) 4364wait_block_or_sig(int *status)
4056{ 4365{
@@ -4083,6 +4392,7 @@ wait_block_or_sig(int *status)
4083 4392
4084 return pid; 4393 return pid;
4085} 4394}
4395#endif
4086 4396
4087#define DOWAIT_NONBLOCK 0 4397#define DOWAIT_NONBLOCK 0
4088#define DOWAIT_BLOCK 1 4398#define DOWAIT_BLOCK 1
@@ -4151,6 +4461,11 @@ dowait(int block, struct job *job)
4151 jobno(jp), pid, ps->ps_status, status)); 4461 jobno(jp), pid, ps->ps_status, status));
4152 ps->ps_status = status; 4462 ps->ps_status = status;
4153 thisjob = jp; 4463 thisjob = jp;
4464#if ENABLE_PLATFORM_MINGW32
4465 ps->ps_pid = -1;
4466 CloseHandle(ps->ps_proc);
4467 ps->ps_proc = NULL;
4468#endif
4154 } 4469 }
4155 if (ps->ps_status == -1) 4470 if (ps->ps_status == -1)
4156 jobstate = JOBRUNNING; 4471 jobstate = JOBRUNNING;
@@ -4826,6 +5141,7 @@ commandtext(union node *n)
4826 * 5141 *
4827 * Called with interrupts off. 5142 * Called with interrupts off.
4828 */ 5143 */
5144#if !ENABLE_PLATFORM_MINGW32
4829/* 5145/*
4830 * Clear traps on a fork. 5146 * Clear traps on a fork.
4831 */ 5147 */
@@ -4975,16 +5291,24 @@ forkchild(struct job *jp, union node *n, int mode)
4975 freejob(jp); 5291 freejob(jp);
4976 jobless = 0; 5292 jobless = 0;
4977} 5293}
5294#endif
4978 5295
4979/* Called after fork(), in parent */ 5296/* Called after fork(), in parent */
4980#if !JOBS 5297#if !JOBS
4981#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) 5298#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4982#endif 5299#endif
4983static void 5300static void
5301#if !ENABLE_PLATFORM_MINGW32
4984forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5302forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5303#else
5304forkparent(struct job *jp, union node *n, int mode, HANDLE proc)
5305#endif
4985{ 5306{
5307#if ENABLE_PLATFORM_MINGW32
5308 pid_t pid = GetProcessId(proc);
5309#endif
4986 TRACE(("In parent shell: child = %d\n", pid)); 5310 TRACE(("In parent shell: child = %d\n", pid));
4987 if (!jp) { 5311 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
4988 /* jp is NULL when called by openhere() for heredoc support */ 5312 /* jp is NULL when called by openhere() for heredoc support */
4989 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5313 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4990 continue; 5314 continue;
@@ -5010,6 +5334,9 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5010 if (jp) { 5334 if (jp) {
5011 struct procstat *ps = &jp->ps[jp->nprocs++]; 5335 struct procstat *ps = &jp->ps[jp->nprocs++];
5012 ps->ps_pid = pid; 5336 ps->ps_pid = pid;
5337#if ENABLE_PLATFORM_MINGW32
5338 ps->ps_proc = proc;
5339#endif
5013 ps->ps_status = -1; 5340 ps->ps_status = -1;
5014 ps->ps_cmd = nullstr; 5341 ps->ps_cmd = nullstr;
5015#if JOBS 5342#if JOBS
@@ -5019,6 +5346,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5019 } 5346 }
5020} 5347}
5021 5348
5349#if !ENABLE_PLATFORM_MINGW32
5022/* jp and n are NULL when called by openhere() for heredoc support */ 5350/* jp and n are NULL when called by openhere() for heredoc support */
5023static int 5351static int
5024forkshell(struct job *jp, union node *n, int mode) 5352forkshell(struct job *jp, union node *n, int mode)
@@ -5041,6 +5369,7 @@ forkshell(struct job *jp, union node *n, int mode)
5041 } 5369 }
5042 return pid; 5370 return pid;
5043} 5371}
5372#endif
5044 5373
5045/* 5374/*
5046 * Wait for job to finish. 5375 * Wait for job to finish.
@@ -5234,6 +5563,7 @@ openhere(union node *redir)
5234{ 5563{
5235 int pip[2]; 5564 int pip[2];
5236 size_t len = 0; 5565 size_t len = 0;
5566 IF_PLATFORM_MINGW32(struct forkshell fs);
5237 5567
5238 if (pipe(pip) < 0) 5568 if (pipe(pip) < 0)
5239 ash_msg_and_raise_error("pipe call failed"); 5569 ash_msg_and_raise_error("pipe call failed");
@@ -5244,6 +5574,15 @@ openhere(union node *redir)
5244 goto out; 5574 goto out;
5245 } 5575 }
5246 } 5576 }
5577#if ENABLE_PLATFORM_MINGW32
5578 memset(&fs, 0, sizeof(fs));
5579 fs.fpid = FS_OPENHERE;
5580 fs.n = redir;
5581 fs.fd[0] = pip[0];
5582 fs.fd[1] = pip[1];
5583 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5584 ash_msg_and_raise_error("unable to spawn shell");
5585#else
5247 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5586 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5248 /* child */ 5587 /* child */
5249 close(pip[0]); 5588 close(pip[0]);
@@ -5258,6 +5597,7 @@ openhere(union node *redir)
5258 expandhere(redir->nhere.doc, pip[1]); 5597 expandhere(redir->nhere.doc, pip[1]);
5259 _exit(EXIT_SUCCESS); 5598 _exit(EXIT_SUCCESS);
5260 } 5599 }
5600#endif
5261 out: 5601 out:
5262 close(pip[1]); 5602 close(pip[1]);
5263 return pip[0]; 5603 return pip[0];
@@ -5283,6 +5623,31 @@ openredirect(union node *redir)
5283 * allocated space. Do it only when we know it is safe. 5623 * allocated space. Do it only when we know it is safe.
5284 */ 5624 */
5285 fname = redir->nfile.expfname; 5625 fname = redir->nfile.expfname;
5626#if ENABLE_PLATFORM_MINGW32
5627 /* Support for /dev/null */
5628 switch (redir->nfile.type) {
5629 case NFROM:
5630 if (!strcmp(fname, "/dev/null"))
5631 return open("nul",O_RDWR);
5632 if (!strncmp(fname, "/dev/", 5)) {
5633 ash_msg("Unhandled device %s\n", fname);
5634 return -1;
5635 }
5636 break;
5637
5638 case NFROMTO:
5639 case NTO:
5640 case NCLOBBER:
5641 case NAPPEND:
5642 if (!strcmp(fname, "/dev/null"))
5643 return open("nul",O_RDWR);
5644 if (!strncmp(fname, "/dev/", 5)) {
5645 ash_msg("Unhandled device %s\n", fname);
5646 return -1;
5647 }
5648 break;
5649 }
5650#endif
5286 5651
5287 switch (redir->nfile.type) { 5652 switch (redir->nfile.type) {
5288 default: 5653 default:
@@ -5320,6 +5685,9 @@ openredirect(union node *redir)
5320 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5685 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5321 if (f < 0) 5686 if (f < 0)
5322 goto ecreate; 5687 goto ecreate;
5688#if ENABLE_PLATFORM_MINGW32
5689 lseek(f, 0, SEEK_END);
5690#endif
5323 break; 5691 break;
5324 } 5692 }
5325 5693
@@ -6157,6 +6525,7 @@ struct backcmd { /* result of evalbackcmd */
6157 int fd; /* file descriptor to read from */ 6525 int fd; /* file descriptor to read from */
6158 int nleft; /* number of chars in buffer */ 6526 int nleft; /* number of chars in buffer */
6159 char *buf; /* buffer */ 6527 char *buf; /* buffer */
6528 IF_PLATFORM_MINGW32(struct forkshell fs);
6160 struct job *jp; /* job structure for command */ 6529 struct job *jp; /* job structure for command */
6161}; 6530};
6162 6531
@@ -6173,6 +6542,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6173 result->fd = -1; 6542 result->fd = -1;
6174 result->buf = NULL; 6543 result->buf = NULL;
6175 result->nleft = 0; 6544 result->nleft = 0;
6545 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
6176 result->jp = NULL; 6546 result->jp = NULL;
6177 if (n == NULL) { 6547 if (n == NULL) {
6178 goto out; 6548 goto out;
@@ -6181,6 +6551,14 @@ evalbackcmd(union node *n, struct backcmd *result)
6181 if (pipe(pip) < 0) 6551 if (pipe(pip) < 0)
6182 ash_msg_and_raise_error("pipe call failed"); 6552 ash_msg_and_raise_error("pipe call failed");
6183 jp = makejob(/*n,*/ 1); 6553 jp = makejob(/*n,*/ 1);
6554#if ENABLE_PLATFORM_MINGW32
6555 result->fs.fpid = FS_EVALBACKCMD;
6556 result->fs.n = n;
6557 result->fs.fd[0] = pip[0];
6558 result->fs.fd[1] = pip[1];
6559 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6560 ash_msg_and_raise_error("unable to spawn shell");
6561#else
6184 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6562 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6185 /* child */ 6563 /* child */
6186 FORCE_INT_ON; 6564 FORCE_INT_ON;
@@ -6203,6 +6581,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6203 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 6581 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6204 /* NOTREACHED */ 6582 /* NOTREACHED */
6205 } 6583 }
6584#endif
6206 /* parent */ 6585 /* parent */
6207 close(pip[1]); 6586 close(pip[1]);
6208 result->fd = pip[0]; 6587 result->fd = pip[0];
@@ -6259,7 +6638,8 @@ expbackq(union node *cmd, int flag)
6259 6638
6260 /* Eat all trailing newlines */ 6639 /* Eat all trailing newlines */
6261 dest = expdest; 6640 dest = expdest;
6262 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6641 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6642 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
6263 STUNPUTC(dest); 6643 STUNPUTC(dest);
6264 expdest = dest; 6644 expdest = dest;
6265 6645
@@ -7793,7 +8173,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
7793 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ 8173 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7794 8174
7795 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 8175 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7796 if (strchr(prog, '/') != NULL 8176 if ((strchr(prog, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(prog, '\\')))
7797#if ENABLE_FEATURE_SH_STANDALONE 8177#if ENABLE_FEATURE_SH_STANDALONE
7798 || (applet_no = find_applet_by_name(prog)) >= 0 8178 || (applet_no = find_applet_by_name(prog)) >= 0
7799#endif 8179#endif
@@ -7807,6 +8187,11 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
7807 goto try_PATH; 8187 goto try_PATH;
7808 } 8188 }
7809 e = errno; 8189 e = errno;
8190#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
8191 } else if (strcmp(argv[0], "busybox") == 0) {
8192 tryexec(-1, bb_busybox_exec_path, argv, envp);
8193 e = errno;
8194#endif
7810 } else { 8195 } else {
7811 try_PATH: 8196 try_PATH:
7812 e = ENOENT; 8197 e = ENOENT;
@@ -8377,10 +8762,14 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8377#endif 8762#endif
8378 8763
8379 8764
8380/*static int funcblocksize; // size of structures in function */ 8765static int funcblocksize; /* size of structures in function */
8381/*static int funcstringsize; // size of strings in node */ 8766static int funcstringsize; /* size of strings in node */
8382static void *funcblock; /* block to allocate function from */ 8767static void *funcblock; /* block to allocate function from */
8383static char *funcstring_end; /* end of block to allocate strings from */ 8768static char *funcstring; /* block to allocate strings from */
8769#if ENABLE_PLATFORM_MINGW32
8770static int nodeptrsize;
8771static char **nodeptr;
8772#endif
8384 8773
8385/* flags in argument to evaltree */ 8774/* flags in argument to evaltree */
8386#define EV_EXIT 01 /* exit after evaluating tree */ 8775#define EV_EXIT 01 /* exit after evaluating tree */
@@ -8418,72 +8807,81 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8418 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), 8807 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8419}; 8808};
8420 8809
8421static int calcsize(int funcblocksize, union node *n); 8810static void calcsize(union node *n);
8422 8811
8423static int 8812static void
8424sizenodelist(int funcblocksize, struct nodelist *lp) 8813sizenodelist(struct nodelist *lp)
8425{ 8814{
8426 while (lp) { 8815 while (lp) {
8427 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8816 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8428 funcblocksize = calcsize(funcblocksize, lp->n); 8817 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8818 calcsize(lp->n);
8429 lp = lp->next; 8819 lp = lp->next;
8430 } 8820 }
8431 return funcblocksize;
8432} 8821}
8433 8822
8434static int 8823static void
8435calcsize(int funcblocksize, union node *n) 8824calcsize(union node *n)
8436{ 8825{
8437 if (n == NULL) 8826 if (n == NULL)
8438 return funcblocksize; 8827 return;
8439 funcblocksize += nodesize[n->type]; 8828 funcblocksize += nodesize[n->type];
8440 switch (n->type) { 8829 switch (n->type) {
8441 case NCMD: 8830 case NCMD:
8442 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect); 8831 calcsize(n->ncmd.redirect);
8443 funcblocksize = calcsize(funcblocksize, n->ncmd.args); 8832 calcsize(n->ncmd.args);
8444 funcblocksize = calcsize(funcblocksize, n->ncmd.assign); 8833 calcsize(n->ncmd.assign);
8834 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8445 break; 8835 break;
8446 case NPIPE: 8836 case NPIPE:
8447 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist); 8837 sizenodelist(n->npipe.cmdlist);
8838 IF_PLATFORM_MINGW32(nodeptrsize++);
8448 break; 8839 break;
8449 case NREDIR: 8840 case NREDIR:
8450 case NBACKGND: 8841 case NBACKGND:
8451 case NSUBSHELL: 8842 case NSUBSHELL:
8452 funcblocksize = calcsize(funcblocksize, n->nredir.redirect); 8843 calcsize(n->nredir.redirect);
8453 funcblocksize = calcsize(funcblocksize, n->nredir.n); 8844 calcsize(n->nredir.n);
8845 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8454 break; 8846 break;
8455 case NAND: 8847 case NAND:
8456 case NOR: 8848 case NOR:
8457 case NSEMI: 8849 case NSEMI:
8458 case NWHILE: 8850 case NWHILE:
8459 case NUNTIL: 8851 case NUNTIL:
8460 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2); 8852 calcsize(n->nbinary.ch2);
8461 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1); 8853 calcsize(n->nbinary.ch1);
8854 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8462 break; 8855 break;
8463 case NIF: 8856 case NIF:
8464 funcblocksize = calcsize(funcblocksize, n->nif.elsepart); 8857 calcsize(n->nif.elsepart);
8465 funcblocksize = calcsize(funcblocksize, n->nif.ifpart); 8858 calcsize(n->nif.ifpart);
8466 funcblocksize = calcsize(funcblocksize, n->nif.test); 8859 calcsize(n->nif.test);
8860 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8467 break; 8861 break;
8468 case NFOR: 8862 case NFOR:
8469 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */ 8863 funcstringsize += strlen(n->nfor.var) + 1;
8470 funcblocksize = calcsize(funcblocksize, n->nfor.body); 8864 calcsize(n->nfor.body);
8471 funcblocksize = calcsize(funcblocksize, n->nfor.args); 8865 calcsize(n->nfor.args);
8866 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8472 break; 8867 break;
8473 case NCASE: 8868 case NCASE:
8474 funcblocksize = calcsize(funcblocksize, n->ncase.cases); 8869 calcsize(n->ncase.cases);
8475 funcblocksize = calcsize(funcblocksize, n->ncase.expr); 8870 calcsize(n->ncase.expr);
8871 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8476 break; 8872 break;
8477 case NCLIST: 8873 case NCLIST:
8478 funcblocksize = calcsize(funcblocksize, n->nclist.body); 8874 calcsize(n->nclist.body);
8479 funcblocksize = calcsize(funcblocksize, n->nclist.pattern); 8875 calcsize(n->nclist.pattern);
8480 funcblocksize = calcsize(funcblocksize, n->nclist.next); 8876 calcsize(n->nclist.next);
8877 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8481 break; 8878 break;
8482 case NDEFUN: 8879 case NDEFUN:
8483 case NARG: 8880 case NARG:
8484 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); 8881 sizenodelist(n->narg.backquote);
8485 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ 8882 funcstringsize += strlen(n->narg.text) + 1;
8486 funcblocksize = calcsize(funcblocksize, n->narg.next); 8883 calcsize(n->narg.next);
8884 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8487 break; 8885 break;
8488 case NTO: 8886 case NTO:
8489#if BASH_REDIR_OUTPUT 8887#if BASH_REDIR_OUTPUT
@@ -8493,35 +8891,55 @@ calcsize(int funcblocksize, union node *n)
8493 case NFROM: 8891 case NFROM:
8494 case NFROMTO: 8892 case NFROMTO:
8495 case NAPPEND: 8893 case NAPPEND:
8496 funcblocksize = calcsize(funcblocksize, n->nfile.fname); 8894 calcsize(n->nfile.fname);
8497 funcblocksize = calcsize(funcblocksize, n->nfile.next); 8895 calcsize(n->nfile.next);
8896 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8498 break; 8897 break;
8499 case NTOFD: 8898 case NTOFD:
8500 case NFROMFD: 8899 case NFROMFD:
8501 funcblocksize = calcsize(funcblocksize, n->ndup.vname); 8900 calcsize(n->ndup.vname);
8502 funcblocksize = calcsize(funcblocksize, n->ndup.next); 8901 calcsize(n->ndup.next);
8902 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8503 break; 8903 break;
8504 case NHERE: 8904 case NHERE:
8505 case NXHERE: 8905 case NXHERE:
8506 funcblocksize = calcsize(funcblocksize, n->nhere.doc); 8906 calcsize(n->nhere.doc);
8507 funcblocksize = calcsize(funcblocksize, n->nhere.next); 8907 calcsize(n->nhere.next);
8908 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8508 break; 8909 break;
8509 case NNOT: 8910 case NNOT:
8510 funcblocksize = calcsize(funcblocksize, n->nnot.com); 8911 calcsize(n->nnot.com);
8912 IF_PLATFORM_MINGW32(nodeptrsize++);
8511 break; 8913 break;
8512 }; 8914 };
8513 return funcblocksize;
8514} 8915}
8515 8916
8516static char * 8917static char *
8517nodeckstrdup(char *s) 8918nodeckstrdup(const char *s)
8518{ 8919{
8519 funcstring_end -= SHELL_ALIGN(strlen(s) + 1); 8920 char *rtn = funcstring;
8520 return strcpy(funcstring_end, s); 8921
8922 if (!s)
8923 return NULL;
8924 strcpy(funcstring, s);
8925 funcstring += strlen(s) + 1;
8926 return rtn;
8521} 8927}
8522 8928
8523static union node *copynode(union node *); 8929static union node *copynode(union node *);
8524 8930
8931#if ENABLE_PLATFORM_MINGW32
8932# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char *)&(dst);}
8933# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);}}
8934# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);}}
8935# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);*nodeptr++ = (char *)&(dst4);}}
8936#else
8937# define SAVE_PTR(dst)
8938# define SAVE_PTR2(dst,dst2)
8939# define SAVE_PTR3(dst,dst2,dst3)
8940# define SAVE_PTR4(dst,dst2,dst3,dst4)
8941#endif
8942
8525static struct nodelist * 8943static struct nodelist *
8526copynodelist(struct nodelist *lp) 8944copynodelist(struct nodelist *lp)
8527{ 8945{
@@ -8533,6 +8951,7 @@ copynodelist(struct nodelist *lp)
8533 *lpp = funcblock; 8951 *lpp = funcblock;
8534 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 8952 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8535 (*lpp)->n = copynode(lp->n); 8953 (*lpp)->n = copynode(lp->n);
8954 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8536 lp = lp->next; 8955 lp = lp->next;
8537 lpp = &(*lpp)->next; 8956 lpp = &(*lpp)->next;
8538 } 8957 }
@@ -8555,16 +8974,19 @@ copynode(union node *n)
8555 new->ncmd.redirect = copynode(n->ncmd.redirect); 8974 new->ncmd.redirect = copynode(n->ncmd.redirect);
8556 new->ncmd.args = copynode(n->ncmd.args); 8975 new->ncmd.args = copynode(n->ncmd.args);
8557 new->ncmd.assign = copynode(n->ncmd.assign); 8976 new->ncmd.assign = copynode(n->ncmd.assign);
8977 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8558 break; 8978 break;
8559 case NPIPE: 8979 case NPIPE:
8560 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8980 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8561 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 8981 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8982 SAVE_PTR(new->npipe.cmdlist);
8562 break; 8983 break;
8563 case NREDIR: 8984 case NREDIR:
8564 case NBACKGND: 8985 case NBACKGND:
8565 case NSUBSHELL: 8986 case NSUBSHELL:
8566 new->nredir.redirect = copynode(n->nredir.redirect); 8987 new->nredir.redirect = copynode(n->nredir.redirect);
8567 new->nredir.n = copynode(n->nredir.n); 8988 new->nredir.n = copynode(n->nredir.n);
8989 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8568 break; 8990 break;
8569 case NAND: 8991 case NAND:
8570 case NOR: 8992 case NOR:
@@ -8573,31 +8995,37 @@ copynode(union node *n)
8573 case NUNTIL: 8995 case NUNTIL:
8574 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8996 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8575 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8997 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8998 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8576 break; 8999 break;
8577 case NIF: 9000 case NIF:
8578 new->nif.elsepart = copynode(n->nif.elsepart); 9001 new->nif.elsepart = copynode(n->nif.elsepart);
8579 new->nif.ifpart = copynode(n->nif.ifpart); 9002 new->nif.ifpart = copynode(n->nif.ifpart);
8580 new->nif.test = copynode(n->nif.test); 9003 new->nif.test = copynode(n->nif.test);
9004 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8581 break; 9005 break;
8582 case NFOR: 9006 case NFOR:
8583 new->nfor.var = nodeckstrdup(n->nfor.var); 9007 new->nfor.var = nodeckstrdup(n->nfor.var);
8584 new->nfor.body = copynode(n->nfor.body); 9008 new->nfor.body = copynode(n->nfor.body);
8585 new->nfor.args = copynode(n->nfor.args); 9009 new->nfor.args = copynode(n->nfor.args);
9010 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8586 break; 9011 break;
8587 case NCASE: 9012 case NCASE:
8588 new->ncase.cases = copynode(n->ncase.cases); 9013 new->ncase.cases = copynode(n->ncase.cases);
8589 new->ncase.expr = copynode(n->ncase.expr); 9014 new->ncase.expr = copynode(n->ncase.expr);
9015 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8590 break; 9016 break;
8591 case NCLIST: 9017 case NCLIST:
8592 new->nclist.body = copynode(n->nclist.body); 9018 new->nclist.body = copynode(n->nclist.body);
8593 new->nclist.pattern = copynode(n->nclist.pattern); 9019 new->nclist.pattern = copynode(n->nclist.pattern);
8594 new->nclist.next = copynode(n->nclist.next); 9020 new->nclist.next = copynode(n->nclist.next);
9021 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8595 break; 9022 break;
8596 case NDEFUN: 9023 case NDEFUN:
8597 case NARG: 9024 case NARG:
8598 new->narg.backquote = copynodelist(n->narg.backquote); 9025 new->narg.backquote = copynodelist(n->narg.backquote);
8599 new->narg.text = nodeckstrdup(n->narg.text); 9026 new->narg.text = nodeckstrdup(n->narg.text);
8600 new->narg.next = copynode(n->narg.next); 9027 new->narg.next = copynode(n->narg.next);
9028 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8601 break; 9029 break;
8602 case NTO: 9030 case NTO:
8603#if BASH_REDIR_OUTPUT 9031#if BASH_REDIR_OUTPUT
@@ -8610,6 +9038,7 @@ copynode(union node *n)
8610 new->nfile.fname = copynode(n->nfile.fname); 9038 new->nfile.fname = copynode(n->nfile.fname);
8611 new->nfile.fd = n->nfile.fd; 9039 new->nfile.fd = n->nfile.fd;
8612 new->nfile.next = copynode(n->nfile.next); 9040 new->nfile.next = copynode(n->nfile.next);
9041 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8613 break; 9042 break;
8614 case NTOFD: 9043 case NTOFD:
8615 case NFROMFD: 9044 case NFROMFD:
@@ -8617,15 +9046,18 @@ copynode(union node *n)
8617 new->ndup.dupfd = n->ndup.dupfd; 9046 new->ndup.dupfd = n->ndup.dupfd;
8618 new->ndup.fd = n->ndup.fd; 9047 new->ndup.fd = n->ndup.fd;
8619 new->ndup.next = copynode(n->ndup.next); 9048 new->ndup.next = copynode(n->ndup.next);
9049 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8620 break; 9050 break;
8621 case NHERE: 9051 case NHERE:
8622 case NXHERE: 9052 case NXHERE:
8623 new->nhere.doc = copynode(n->nhere.doc); 9053 new->nhere.doc = copynode(n->nhere.doc);
8624 new->nhere.fd = n->nhere.fd; 9054 new->nhere.fd = n->nhere.fd;
8625 new->nhere.next = copynode(n->nhere.next); 9055 new->nhere.next = copynode(n->nhere.next);
9056 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8626 break; 9057 break;
8627 case NNOT: 9058 case NNOT:
8628 new->nnot.com = copynode(n->nnot.com); 9059 new->nnot.com = copynode(n->nnot.com);
9060 SAVE_PTR(new->nnot.com);
8629 break; 9061 break;
8630 }; 9062 };
8631 new->type = n->type; 9063 new->type = n->type;
@@ -8641,13 +9073,16 @@ copyfunc(union node *n)
8641 struct funcnode *f; 9073 struct funcnode *f;
8642 size_t blocksize; 9074 size_t blocksize;
8643 9075
8644 /*funcstringsize = 0;*/ 9076 funcblocksize = offsetof(struct funcnode, n);
8645 blocksize = offsetof(struct funcnode, n) + calcsize(0, n); 9077 funcstringsize = 0;
8646 f = ckzalloc(blocksize /* + funcstringsize */); 9078 calcsize(n);
9079 blocksize = funcblocksize;
9080 f = ckmalloc(blocksize + funcstringsize);
8647 funcblock = (char *) f + offsetof(struct funcnode, n); 9081 funcblock = (char *) f + offsetof(struct funcnode, n);
8648 funcstring_end = (char *) f + blocksize; 9082 funcstring = (char *) f + blocksize;
9083 IF_PLATFORM_MINGW32(nodeptr = NULL);
8649 copynode(n); 9084 copynode(n);
8650 /* f->count = 0; - ckzalloc did it */ 9085 f->count = 0;
8651 return f; 9086 return f;
8652} 9087}
8653 9088
@@ -8987,6 +9422,7 @@ evalcase(union node *n, int flags)
8987static int 9422static int
8988evalsubshell(union node *n, int flags) 9423evalsubshell(union node *n, int flags)
8989{ 9424{
9425 IF_PLATFORM_MINGW32(struct forkshell fs;)
8990 struct job *jp; 9426 struct job *jp;
8991 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ 9427 int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */
8992 int status; 9428 int status;
@@ -8998,12 +9434,22 @@ evalsubshell(union node *n, int flags)
8998 if (backgnd == FORK_FG) 9434 if (backgnd == FORK_FG)
8999 get_tty_state(); 9435 get_tty_state();
9000 jp = makejob(/*n,*/ 1); 9436 jp = makejob(/*n,*/ 1);
9437#if ENABLE_PLATFORM_MINGW32
9438 memset(&fs, 0, sizeof(fs));
9439 fs.fpid = FS_EVALSUBSHELL;
9440 fs.n = n;
9441 fs.flags = flags;
9442 if (spawn_forkshell(jp, &fs, backgnd) < 0)
9443 ash_msg_and_raise_error("unable to spawn shell");
9444 if ( 0 ) {
9445#else
9001 if (forkshell(jp, n, backgnd) == 0) { 9446 if (forkshell(jp, n, backgnd) == 0) {
9002 /* child */ 9447 /* child */
9003 INT_ON; 9448 INT_ON;
9004 flags |= EV_EXIT; 9449 flags |= EV_EXIT;
9005 if (backgnd) 9450 if (backgnd)
9006 flags &= ~EV_TESTED; 9451 flags &= ~EV_TESTED;
9452#endif
9007 nofork: 9453 nofork:
9008 redirect(n->nredir.redirect, 0); 9454 redirect(n->nredir.redirect, 0);
9009 evaltreenr(n->nredir.n, flags); 9455 evaltreenr(n->nredir.n, flags);
@@ -9090,6 +9536,7 @@ expredir(union node *n)
9090static int 9536static int
9091evalpipe(union node *n, int flags) 9537evalpipe(union node *n, int flags)
9092{ 9538{
9539 IF_PLATFORM_MINGW32(struct forkshell fs;)
9093 struct job *jp; 9540 struct job *jp;
9094 struct nodelist *lp; 9541 struct nodelist *lp;
9095 int pipelen; 9542 int pipelen;
@@ -9116,6 +9563,17 @@ evalpipe(union node *n, int flags)
9116 ash_msg_and_raise_error("pipe call failed"); 9563 ash_msg_and_raise_error("pipe call failed");
9117 } 9564 }
9118 } 9565 }
9566#if ENABLE_PLATFORM_MINGW32
9567 memset(&fs, 0, sizeof(fs));
9568 fs.fpid = FS_EVALPIPE;
9569 fs.flags = flags;
9570 fs.n = lp->n;
9571 fs.fd[0] = pip[0];
9572 fs.fd[1] = pip[1];
9573 fs.fd[2] = prevfd;
9574 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9575 ash_msg_and_raise_error("unable to spawn shell");
9576#else
9119 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9577 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
9120 /* child */ 9578 /* child */
9121 INT_ON; 9579 INT_ON;
@@ -9133,6 +9591,7 @@ evalpipe(union node *n, int flags)
9133 evaltreenr(lp->n, flags); 9591 evaltreenr(lp->n, flags);
9134 /* never returns */ 9592 /* never returns */
9135 } 9593 }
9594#endif
9136 /* parent */ 9595 /* parent */
9137 if (prevfd >= 0) 9596 if (prevfd >= 0)
9138 close(prevfd); 9597 close(prevfd);
@@ -9610,6 +10069,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9610 * as POSIX mandates */ 10069 * as POSIX mandates */
9611 return back_exitstatus; 10070 return back_exitstatus;
9612} 10071}
10072
9613static int 10073static int
9614evalcommand(union node *cmd, int flags) 10074evalcommand(union node *cmd, int flags)
9615{ 10075{
@@ -9794,6 +10254,27 @@ evalcommand(union node *cmd, int flags)
9794 * in a script or a subshell does not need forking, 10254 * in a script or a subshell does not need forking,
9795 * we can just exec it. 10255 * we can just exec it.
9796 */ 10256 */
10257#if ENABLE_PLATFORM_MINGW32
10258 if (!(flags & EV_EXIT) || trap[0]) {
10259 /* No, forking off a child is necessary */
10260 struct forkshell fs;
10261
10262 memset(&fs, 0, sizeof(fs));
10263 fs.fpid = FS_SHELLEXEC;
10264 fs.argv = argv;
10265 fs.string = (char*)path;
10266 fs.fd[0] = cmdentry.u.index;
10267 fs.strlist = varlist.list;
10268 jp = makejob(/*cmd,*/ 1);
10269 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
10270 ash_msg_and_raise_error("unable to spawn shell");
10271 status = waitforjob(jp);
10272 INT_ON;
10273 TRACE(("forked child exited with %d\n", exitstatus));
10274 break;
10275 }
10276 /* goes through to shellexec() */
10277#else
9797 if (!(flags & EV_EXIT) || may_have_traps) { 10278 if (!(flags & EV_EXIT) || may_have_traps) {
9798 /* No, forking off a child is necessary */ 10279 /* No, forking off a child is necessary */
9799 INT_OFF; 10280 INT_OFF;
@@ -9810,6 +10291,7 @@ evalcommand(union node *cmd, int flags)
9810 FORCE_INT_ON; 10291 FORCE_INT_ON;
9811 /* fall through to exec'ing external program */ 10292 /* fall through to exec'ing external program */
9812 } 10293 }
10294#endif
9813 listsetvar(varlist.list, VEXPORT|VSTACK); 10295 listsetvar(varlist.list, VEXPORT|VSTACK);
9814 shellexec(argv[0], argv, path, cmdentry.u.index); 10296 shellexec(argv[0], argv, path, cmdentry.u.index);
9815 /* NOTREACHED */ 10297 /* NOTREACHED */
@@ -10195,7 +10677,7 @@ preadbuffer(void)
10195 more--; 10677 more--;
10196 10678
10197 c = *q; 10679 c = *q;
10198 if (c == '\0') { 10680 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
10199 memmove(q, q + 1, more); 10681 memmove(q, q + 1, more);
10200 } else { 10682 } else {
10201 q++; 10683 q++;
@@ -10382,6 +10864,7 @@ popallfiles(void)
10382 popfile(); 10864 popfile();
10383} 10865}
10384 10866
10867#if !ENABLE_PLATFORM_MINGW32
10385/* 10868/*
10386 * Close the file(s) that the shell is reading commands from. Called 10869 * Close the file(s) that the shell is reading commands from. Called
10387 * after a fork is done. 10870 * after a fork is done.
@@ -10395,6 +10878,7 @@ closescript(void)
10395 g_parsefile->pf_fd = 0; 10878 g_parsefile->pf_fd = 0;
10396 } 10879 }
10397} 10880}
10881#endif
10398 10882
10399/* 10883/*
10400 * Like setinputfile, but takes an open file descriptor. Call this with 10884 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -12668,7 +13152,7 @@ find_dot_file(char *name)
12668 struct stat statb; 13152 struct stat statb;
12669 13153
12670 /* don't try this for absolute or relative paths */ 13154 /* don't try this for absolute or relative paths */
12671 if (strchr(name, '/')) 13155 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12672 return name; 13156 return name;
12673 13157
12674 while ((fullname = path_advance(&path, name)) != NULL) { 13158 while ((fullname = path_advance(&path, name)) != NULL) {
@@ -12782,10 +13266,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12782 struct stat statb; 13266 struct stat statb;
12783 int e; 13267 int e;
12784 int updatetbl; 13268 int updatetbl;
13269 IF_PLATFORM_MINGW32(int len;)
12785 struct builtincmd *bcmd; 13270 struct builtincmd *bcmd;
12786 13271
12787 /* If name contains a slash, don't use PATH or hash table */ 13272 /* If name contains a slash, don't use PATH or hash table */
12788 if (strchr(name, '/') != NULL) { 13273 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12789 entry->u.index = -1; 13274 entry->u.index = -1;
12790 if (act & DO_ABS) { 13275 if (act & DO_ABS) {
12791 while (stat(name, &statb) < 0) { 13276 while (stat(name, &statb) < 0) {
@@ -12854,7 +13339,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12854#if ENABLE_FEATURE_SH_STANDALONE 13339#if ENABLE_FEATURE_SH_STANDALONE
12855 { 13340 {
12856 int applet_no = find_applet_by_name(name); 13341 int applet_no = find_applet_by_name(name);
12857 if (applet_no >= 0) { 13342 if (applet_no >= 0 ||
13343 /* requires find_applet_by_name to return -1 on no match */
13344 (ENABLE_PLATFORM_MINGW32 && strcmp(name, "busybox") == 0)) {
12858 entry->cmdtype = CMDNORMAL; 13345 entry->cmdtype = CMDNORMAL;
12859 entry->u.index = -2 - applet_no; 13346 entry->u.index = -2 - applet_no;
12860 return; 13347 return;
@@ -12892,12 +13379,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12892 } 13379 }
12893 } 13380 }
12894 /* if rehash, don't redo absolute path names */ 13381 /* if rehash, don't redo absolute path names */
12895 if (fullname[0] == '/' && idx <= prev) { 13382 if (is_absolute_path(fullname) && idx <= prev) {
12896 if (idx < prev) 13383 if (idx < prev)
12897 continue; 13384 continue;
12898 TRACE(("searchexec \"%s\": no change\n", name)); 13385 TRACE(("searchexec \"%s\": no change\n", name));
12899 goto success; 13386 goto success;
12900 } 13387 }
13388#if ENABLE_PLATFORM_MINGW32
13389 len = strlen(fullname);
13390 if (len > 4 &&
13391 (!strcasecmp(fullname+len-4, ".exe") ||
13392 !strcasecmp(fullname+len-4, ".com"))) {
13393 if (stat(fullname, &statb) < 0) {
13394 if (errno != ENOENT && errno != ENOTDIR)
13395 e = errno;
13396 goto loop;
13397 }
13398 }
13399 else {
13400 /* path_advance() has reserved space for .exe */
13401 memcpy(fullname+len, ".exe", 5);
13402 if (stat(fullname, &statb) < 0) {
13403 if (errno != ENOENT && errno != ENOTDIR)
13404 e = errno;
13405 memcpy(fullname+len, ".com", 5);
13406 if (stat(fullname, &statb) < 0) {
13407 if (errno != ENOENT && errno != ENOTDIR)
13408 e = errno;
13409 fullname[len] = '\0';
13410 if (stat(fullname, &statb) < 0) {
13411 if (errno != ENOENT && errno != ENOTDIR)
13412 e = errno;
13413 goto loop;
13414 }
13415 if (!file_is_executable(fullname)) {
13416 e = ENOEXEC;
13417 goto loop;
13418 }
13419 }
13420 }
13421 fullname[len] = '\0';
13422 }
13423#else
12901 while (stat(fullname, &statb) < 0) { 13424 while (stat(fullname, &statb) < 0) {
12902#ifdef SYSV 13425#ifdef SYSV
12903 if (errno == EINTR) 13426 if (errno == EINTR)
@@ -12907,6 +13430,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12907 e = errno; 13430 e = errno;
12908 goto loop; 13431 goto loop;
12909 } 13432 }
13433#endif
12910 e = EACCES; /* if we fail, this will be the error */ 13434 e = EACCES; /* if we fail, this will be the error */
12911 if (!S_ISREG(statb.st_mode)) 13435 if (!S_ISREG(statb.st_mode))
12912 continue; 13436 continue;
@@ -13421,7 +13945,11 @@ exitshell(void)
13421} 13945}
13422 13946
13423static void 13947static void
13948#if ENABLE_PLATFORM_MINGW32
13949init(int xp)
13950#else
13424init(void) 13951init(void)
13952#endif
13425{ 13953{
13426 /* we will never free this */ 13954 /* we will never free this */
13427 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 13955 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
@@ -13440,6 +13968,86 @@ init(void)
13440 struct stat st1, st2; 13968 struct stat st1, st2;
13441 13969
13442 initvar(); 13970 initvar();
13971
13972#if ENABLE_PLATFORM_MINGW32
13973 /*
13974 * case insensitive env names from Windows world
13975 *
13976 * Some standard env names such as PATH is named Path and so on
13977 * ash itself is case sensitive, so "Path" will confuse it, as
13978 * MSVC getenv() is case insensitive.
13979 *
13980 * We may end up having both Path and PATH. Then Path will be chosen
13981 * because it appears first.
13982 */
13983 for (envp = environ; envp && *envp; envp++) {
13984 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
13985 strncmp(*envp, "PATH=", 5) != 0) {
13986 break;
13987 }
13988 }
13989
13990 if (envp && *envp) {
13991 /*
13992 * If we get here it's because the environment contains a path
13993 * variable called something other than PATH. This suggests we
13994 * haven't been invoked from an earlier instance of BusyBox.
13995 */
13996 char *start, *end, *s;
13997 struct passwd *pw;
13998
13999 for (envp = environ; envp && *envp; envp++) {
14000 if (!(end=strchr(*envp, '=')))
14001 continue;
14002
14003 /* make all variable names uppercase */
14004 for (start = *envp;start < end;start++)
14005 *start = toupper(*start);
14006
14007 /* skip conversion of variables known to cause problems */
14008 if ( strncmp(*envp, "SYSTEMROOT=", 11) == 0 ||
14009 strncmp(*envp, "COMSPEC=", 8) == 0 ) {
14010 continue;
14011 }
14012
14013 /* convert backslashes to forward slashes in value */
14014 if (!xp) {
14015 for ( s=end+1; *s; ++s ) {
14016 if ( *s == '\\' ) {
14017 *s = '/';
14018 }
14019 }
14020 }
14021
14022 /* check for invalid characters in name */
14023 for (start = *envp;start < end;start++) {
14024 if (!isdigit(*start) && !isalpha(*start) && *start != '_') {
14025 break;
14026 }
14027 }
14028
14029 if (start != end) {
14030 /*
14031 * Make a copy of the variable, replacing invalid
14032 * characters in the name with underscores.
14033 */
14034 char *var = xstrdup(*envp);
14035
14036 for (start = var;*start != '=';start++) {
14037 if (!isdigit(*start) && !isalpha(*start)) {
14038 *start = '_';
14039 }
14040 }
14041 setvareq(var, VEXPORT|VNOSAVE);
14042 }
14043 }
14044
14045 /* some initialisation normally performed at login */
14046 pw = xgetpwuid(getuid());
14047 setup_environment(pw->pw_shell,
14048 SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw);
14049 }
14050#endif
13443 for (envp = environ; envp && *envp; envp++) { 14051 for (envp = environ; envp && *envp; envp++) {
13444 p = endofname(*envp); 14052 p = endofname(*envp);
13445 if (p != *envp && *p == '=') { 14053 if (p != *envp && *p == '=') {
@@ -13644,19 +14252,45 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13644 exception_handler = &jmploc; 14252 exception_handler = &jmploc;
13645 rootpid = getpid(); 14253 rootpid = getpid();
13646 14254
13647 init(); 14255 init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0));
13648 setstackmark(&smark); 14256 setstackmark(&smark);
14257
14258#if ENABLE_PLATFORM_MINGW32
14259 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
14260 SetConsoleCtrlHandler(ctrl_handler, TRUE);
14261 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
14262 forkshell_init(argv[2]);
14263
14264 /* NOTREACHED */
14265 bb_error_msg_and_die("subshell ended unexpectedly");
14266 }
14267#endif
13649 procargs(argv); 14268 procargs(argv);
13650#if DEBUG 14269#if DEBUG
13651 TRACE(("Shell args: ")); 14270 TRACE(("Shell args: "));
13652 trace_puts_args(argv); 14271 trace_puts_args(argv);
13653#endif 14272#endif
13654 14273
14274#if ENABLE_ASH_NOCONSOLE
14275 if ( noconsole ) {
14276 DWORD dummy;
14277
14278 if ( GetConsoleProcessList(&dummy, 1) == 1 ) {
14279 ShowWindow(GetConsoleWindow(), SW_HIDE);
14280 }
14281 }
14282#endif
14283
13655 if (argv[0] && argv[0][0] == '-') 14284 if (argv[0] && argv[0][0] == '-')
13656 isloginsh = 1; 14285 isloginsh = 1;
13657 if (isloginsh) { 14286 if (isloginsh) {
13658 const char *hp; 14287 const char *hp;
13659 14288
14289#if ENABLE_PLATFORM_MINGW32
14290 chdir(xgetpwuid(getuid())->pw_dir);
14291 setpwd(NULL, 0);
14292#endif
14293
13660 state = 1; 14294 state = 1;
13661 read_profile("/etc/profile"); 14295 read_profile("/etc/profile");
13662 state1: 14296 state1:
@@ -13731,6 +14365,641 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13731 /* NOTREACHED */ 14365 /* NOTREACHED */
13732} 14366}
13733 14367
14368#if ENABLE_PLATFORM_MINGW32
14369static void
14370forkshell_openhere(struct forkshell *fs)
14371{
14372 union node *redir = fs->n;
14373 int pip[2];
14374
14375 pip[0] = fs->fd[0];
14376 pip[1] = fs->fd[1];
14377
14378 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14379
14380 close(pip[0]);
14381 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
14382 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
14383 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
14384 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
14385 signal(SIGPIPE, SIG_DFL);
14386 if (redir->type == NHERE) {
14387 size_t len = strlen(redir->nhere.doc->narg.text);
14388 full_write(pip[1], redir->nhere.doc->narg.text, len);
14389 } else /* NXHERE */
14390 expandhere(redir->nhere.doc, pip[1]);
14391 _exit(EXIT_SUCCESS);
14392}
14393
14394static void
14395forkshell_evalbackcmd(struct forkshell *fs)
14396{
14397 union node *n = fs->n;
14398 int pip[2] = {fs->fd[0], fs->fd[1]};
14399
14400 FORCE_INT_ON;
14401 close(pip[0]);
14402 if (pip[1] != 1) {
14403 /*close(1);*/
14404 dup2_or_raise(pip[1], 1);
14405 close(pip[1]);
14406 }
14407 eflag = 0;
14408 evaltree(n, EV_EXIT); /* actually evaltreenr... */
14409 /* NOTREACHED */
14410}
14411
14412static void
14413forkshell_evalsubshell(struct forkshell *fs)
14414{
14415 union node *n = fs->n;
14416 int flags = fs->flags;
14417
14418 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14419 INT_ON;
14420 flags |= EV_EXIT;
14421 expredir(n->nredir.redirect);
14422 redirect(n->nredir.redirect, 0);
14423 evaltreenr(n->nredir.n, flags);
14424 /* never returns */
14425}
14426
14427static void
14428forkshell_evalpipe(struct forkshell *fs)
14429{
14430 union node *n = fs->n;
14431 int flags = fs->flags;
14432 int prevfd = fs->fd[2];
14433 int pip[2] = {fs->fd[0], fs->fd[1]};
14434
14435 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14436 INT_ON;
14437 if (pip[1] >= 0) {
14438 close(pip[0]);
14439 }
14440 if (prevfd > 0) {
14441 dup2(prevfd, 0);
14442 close(prevfd);
14443 }
14444 if (pip[1] > 1) {
14445 dup2(pip[1], 1);
14446 close(pip[1]);
14447 }
14448 evaltreenr(n, flags);
14449}
14450
14451static void
14452forkshell_shellexec(struct forkshell *fs)
14453{
14454 int idx = fs->fd[0];
14455 struct strlist *varlist = fs->strlist;
14456 char **argv = fs->argv;
14457 char *path = fs->string;
14458
14459 listsetvar(varlist, VEXPORT|VSTACK);
14460 shellexec(argv[0], argv, path, idx);
14461}
14462
14463static void
14464forkshell_child(struct forkshell *fs)
14465{
14466 switch ( fs->fpid ) {
14467 case FS_OPENHERE:
14468 forkshell_openhere(fs);
14469 break;
14470 case FS_EVALBACKCMD:
14471 forkshell_evalbackcmd(fs);
14472 break;
14473 case FS_EVALSUBSHELL:
14474 forkshell_evalsubshell(fs);
14475 break;
14476 case FS_EVALPIPE:
14477 forkshell_evalpipe(fs);
14478 break;
14479 case FS_SHELLEXEC:
14480 forkshell_shellexec(fs);
14481 break;
14482 }
14483}
14484
14485/*
14486 * Reset the pointers to the builtin environment variables in the hash
14487 * table to point to varinit rather than the bogus copy created during
14488 * forkshell_prepare.
14489 */
14490static void
14491reinitvar(void)
14492{
14493 struct var *vp;
14494 struct var *end;
14495 struct var **vpp;
14496 struct var **old;
14497
14498 vp = varinit;
14499 end = vp + ARRAY_SIZE(varinit);
14500 do {
14501 vpp = hashvar(vp->var_text);
14502 if ( (old=findvar(vpp, vp->var_text)) != NULL ) {
14503 vp->next = (*old)->next;
14504 *old = vp;
14505 }
14506 } while (++vp < end);
14507}
14508
14509/* FIXME: should consider running forkparent() and forkchild() */
14510static int
14511spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
14512{
14513 struct forkshell *new;
14514 char buf[16];
14515 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
14516 intptr_t ret;
14517
14518 new = forkshell_prepare(fs);
14519 sprintf(buf, "%x", (unsigned int)new->hMapFile);
14520 argv[2] = buf;
14521 ret = mingw_spawn_proc(argv);
14522 CloseHandle(new->hMapFile);
14523 UnmapViewOfFile(new);
14524 if (ret == -1) {
14525 free(jp);
14526 return -1;
14527 }
14528 forkparent(jp, fs->node, mode, (HANDLE)ret);
14529 return ret == -1 ? -1 : 0;
14530}
14531
14532/*
14533 * forkshell_prepare() and friends
14534 *
14535 * The sequence is as follows:
14536 * - funcblocksize, funcstringsize, nodeptrsize are initialized
14537 * - forkshell_size(fs) is called to calculate the exact memory needed
14538 * - a new struct is allocated
14539 * - funcblock, funcstring, nodeptr are initialized from the new block
14540 * - forkshell_copy(fs) is called to copy recursively everything over
14541 * it will record all pointers along the way, to nodeptr
14542 *
14543 * When this memory is mapped elsewhere, pointer fixup will be needed
14544 */
14545#define SLIST_SIZE_BEGIN(name,type) \
14546static void \
14547name(type *p) \
14548{ \
14549 while (p) { \
14550 funcblocksize += sizeof(type);
14551 /* do something here with p */
14552#define SLIST_SIZE_END() \
14553 nodeptrsize++; \
14554 p = p->next; \
14555 } \
14556}
14557
14558#define SLIST_COPY_BEGIN(name,type) \
14559static type * \
14560name(type *vp) \
14561{ \
14562 type *start; \
14563 type **vpp; \
14564 vpp = &start; \
14565 while (vp) { \
14566 *vpp = funcblock; \
14567 funcblock = (char *) funcblock + sizeof(type);
14568 /* do something here with vpp and vp */
14569#define SLIST_COPY_END() \
14570 SAVE_PTR((*vpp)->next); \
14571 vp = vp->next; \
14572 vpp = &(*vpp)->next; \
14573 } \
14574 *vpp = NULL; \
14575 return start; \
14576}
14577
14578/*
14579 * struct var
14580 */
14581SLIST_SIZE_BEGIN(var_size,struct var)
14582funcstringsize += strlen(p->var_text) + 1;
14583nodeptrsize++; /* p->text */
14584SLIST_SIZE_END()
14585
14586SLIST_COPY_BEGIN(var_copy,struct var)
14587(*vpp)->var_text = nodeckstrdup(vp->var_text);
14588(*vpp)->flags = vp->flags;
14589/*
14590 * The only place that can set struct var#func is varinit[],
14591 * which will be fixed by forkshell_init()
14592 */
14593(*vpp)->var_func = NULL;
14594SAVE_PTR((*vpp)->var_text);
14595SLIST_COPY_END()
14596
14597/*
14598 * struct strlist
14599 */
14600SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14601funcstringsize += strlen(p->text) + 1;
14602nodeptrsize++; /* p->text */
14603SLIST_SIZE_END()
14604
14605SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14606(*vpp)->text = nodeckstrdup(vp->text);
14607SAVE_PTR((*vpp)->text);
14608SLIST_COPY_END()
14609
14610/*
14611 * struct tblentry
14612 */
14613static void
14614tblentry_size(struct tblentry *tep)
14615{
14616 while (tep) {
14617 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14618 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14619 if (tep->cmdtype == CMDFUNCTION) {
14620 funcblocksize += offsetof(struct funcnode, n);
14621 calcsize(&tep->param.func->n);
14622 nodeptrsize++; /* tep->param.func */
14623 }
14624 nodeptrsize++; /* tep->next */
14625 tep = tep->next;
14626 }
14627}
14628
14629static struct tblentry *
14630tblentry_copy(struct tblentry *tep)
14631{
14632 struct tblentry *start;
14633 struct tblentry **newp;
14634 int size;
14635
14636 newp = &start;
14637 while (tep) {
14638 *newp = funcblock;
14639 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14640
14641 funcblock = (char *) funcblock + size;
14642 memcpy(*newp, tep, size);
14643 switch (tep->cmdtype) {
14644 case CMDBUILTIN:
14645 /* No pointer saving, this field must be fixed by forkshell_init() */
14646 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14647 break;
14648 case CMDFUNCTION:
14649 (*newp)->param.func = funcblock;
14650 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14651 copynode(&tep->param.func->n);
14652 SAVE_PTR((*newp)->param.func);
14653 break;
14654 default:
14655 break;
14656 }
14657 SAVE_PTR((*newp)->next);
14658 tep = tep->next;
14659 newp = &(*newp)->next;
14660 }
14661 *newp = NULL;
14662 return start;
14663}
14664
14665static void
14666cmdtable_size(struct tblentry **cmdtablep)
14667{
14668 int i;
14669 nodeptrsize += CMDTABLESIZE;
14670 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14671 for (i = 0; i < CMDTABLESIZE; i++)
14672 tblentry_size(cmdtablep[i]);
14673}
14674
14675static struct tblentry **
14676cmdtable_copy(struct tblentry **cmdtablep)
14677{
14678 struct tblentry **new = funcblock;
14679 int i;
14680
14681 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14682 for (i = 0; i < CMDTABLESIZE; i++) {
14683 new[i] = tblentry_copy(cmdtablep[i]);
14684 SAVE_PTR(new[i]);
14685 }
14686 return new;
14687}
14688
14689/*
14690 * char **
14691 */
14692static void
14693argv_size(char **p)
14694{
14695 while (p && *p) {
14696 funcblocksize += sizeof(char *);
14697 funcstringsize += strlen(*p)+1;
14698 nodeptrsize++;
14699 p++;
14700 }
14701 funcblocksize += sizeof(char *);
14702}
14703
14704static char **
14705argv_copy(char **p)
14706{
14707 char **new, **start = funcblock;
14708
14709 while (p && *p) {
14710 new = funcblock;
14711 funcblock = (char *) funcblock + sizeof(char *);
14712 *new = nodeckstrdup(*p);
14713 SAVE_PTR(*new);
14714 p++;
14715 new++;
14716 }
14717 new = funcblock;
14718 funcblock = (char *) funcblock + sizeof(char *);
14719 *new = NULL;
14720 return start;
14721}
14722
14723/*
14724 * struct redirtab
14725 */
14726static void
14727redirtab_size(struct redirtab *rdtp)
14728{
14729 while (rdtp) {
14730 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14731 rdtp = rdtp->next;
14732 nodeptrsize++; /* rdtp->next */
14733 }
14734}
14735
14736static struct redirtab *
14737redirtab_copy(struct redirtab *rdtp)
14738{
14739 struct redirtab *start;
14740 struct redirtab **vpp;
14741
14742 vpp = &start;
14743 while (rdtp) {
14744 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14745 *vpp = funcblock;
14746 funcblock = (char *) funcblock + size;
14747 memcpy(*vpp, rdtp, size);
14748 SAVE_PTR((*vpp)->next);
14749 rdtp = rdtp->next;
14750 vpp = &(*vpp)->next;
14751 }
14752 *vpp = NULL;
14753 return start;
14754}
14755
14756#undef shellparam
14757#undef redirlist
14758#undef varinit
14759#undef vartab
14760static void
14761globals_var_size(struct globals_var *gvp)
14762{
14763 int i;
14764
14765 funcblocksize += sizeof(struct globals_var);
14766 argv_size(gvp->shellparam.p);
14767 redirtab_size(gvp->redirlist);
14768 for (i = 0; i < VTABSIZE; i++)
14769 var_size(gvp->vartab[i]);
14770 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14771 var_size(gvp->varinit+i);
14772 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14773}
14774
14775#undef preverrout_fd
14776static struct globals_var *
14777globals_var_copy(struct globals_var *gvp)
14778{
14779 int i;
14780 struct globals_var *new;
14781
14782 new = funcblock;
14783 funcblock = (char *) funcblock + sizeof(struct globals_var);
14784
14785 /* shparam */
14786 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14787 new->shellparam.malloced = 0;
14788 new->shellparam.p = argv_copy(gvp->shellparam.p);
14789 SAVE_PTR(new->shellparam.p);
14790
14791 new->redirlist = redirtab_copy(gvp->redirlist);
14792 SAVE_PTR(new->redirlist);
14793
14794 new->preverrout_fd = gvp->preverrout_fd;
14795 for (i = 0; i < VTABSIZE; i++) {
14796 new->vartab[i] = var_copy(gvp->vartab[i]);
14797 SAVE_PTR(new->vartab[i]);
14798 }
14799
14800 /* Can't use var_copy because varinit is already allocated */
14801 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14802 new->varinit[i].next = NULL;
14803 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14804 SAVE_PTR(new->varinit[i].var_text);
14805 new->varinit[i].flags = gvp->varinit[i].flags;
14806 new->varinit[i].var_func = gvp->varinit[i].var_func;
14807 }
14808 return new;
14809}
14810
14811#undef minusc
14812#undef curdir
14813#undef physdir
14814#undef arg0
14815#undef nullstr
14816static void
14817globals_misc_size(struct globals_misc *p)
14818{
14819 funcblocksize += sizeof(struct globals_misc);
14820 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14821 if (p->curdir != p->nullstr)
14822 funcstringsize += strlen(p->curdir) + 1;
14823 if (p->physdir != p->nullstr)
14824 funcstringsize += strlen(p->physdir) + 1;
14825 funcstringsize += strlen(p->arg0) + 1;
14826 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14827}
14828
14829static struct globals_misc *
14830globals_misc_copy(struct globals_misc *p)
14831{
14832 struct globals_misc *new = funcblock;
14833
14834 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14835 memcpy(new, p, sizeof(struct globals_misc));
14836
14837 new->minusc = nodeckstrdup(p->minusc);
14838 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14839 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14840 new->arg0 = nodeckstrdup(p->arg0);
14841 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14842 return new;
14843}
14844
14845static void
14846forkshell_size(struct forkshell *fs)
14847{
14848 funcblocksize += sizeof(struct forkshell);
14849 globals_var_size(fs->gvp);
14850 globals_misc_size(fs->gmp);
14851 cmdtable_size(fs->cmdtable);
14852 /* optlist_transfer(sending, fd); */
14853 /* misc_transfer(sending, fd); */
14854
14855 calcsize(fs->n);
14856 argv_size(fs->argv);
14857 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14858 strlist_size(fs->strlist);
14859
14860 nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */
14861}
14862
14863static struct forkshell *
14864forkshell_copy(struct forkshell *fs)
14865{
14866 struct forkshell *new;
14867
14868 new = funcblock;
14869 funcblock = (char *) funcblock + sizeof(struct forkshell);
14870
14871 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
14872 new->gvp = globals_var_copy(fs->gvp);
14873 new->gmp = globals_misc_copy(fs->gmp);
14874 new->cmdtable = cmdtable_copy(fs->cmdtable);
14875 SAVE_PTR3(new->gvp, new->gmp, new->cmdtable);
14876
14877 new->n = copynode(fs->n);
14878 new->argv = argv_copy(fs->argv);
14879 new->string = nodeckstrdup(fs->string);
14880 new->strlist = strlist_copy(fs->strlist);
14881 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
14882 return new;
14883}
14884
14885static struct forkshell *
14886forkshell_prepare(struct forkshell *fs)
14887{
14888 struct forkshell *new;
14889 int size, nodeptr_offset;
14890 HANDLE h;
14891 SECURITY_ATTRIBUTES sa;
14892
14893 /* Calculate size of "new" */
14894 fs->gvp = ash_ptr_to_globals_var;
14895 fs->gmp = ash_ptr_to_globals_misc;
14896 fs->cmdtable = cmdtable;
14897
14898 nodeptrsize = 1; /* NULL terminated */
14899 funcblocksize = 0;
14900 funcstringsize = 0;
14901 forkshell_size(fs);
14902 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(char *);
14903
14904 /* Allocate, initialize pointers */
14905 memset(&sa, 0, sizeof(sa));
14906 sa.nLength = sizeof(sa);
14907 sa.lpSecurityDescriptor = NULL;
14908 sa.bInheritHandle = TRUE;
14909 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
14910 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14911 /* new = ckmalloc(size); */
14912 funcblock = new;
14913 funcstring = (char *) funcblock + funcblocksize;
14914 nodeptr = (char **)((char *)funcstring + funcstringsize);
14915 nodeptr_offset = (char *)nodeptr - (char *)new;
14916
14917 /* Now pack them all */
14918 forkshell_copy(fs);
14919
14920 /* Finish it up */
14921 *nodeptr = NULL;
14922 new->size = size;
14923 new->nodeptr_offset = nodeptr_offset;
14924 new->old_base = new;
14925 new->hMapFile = h;
14926 return new;
14927}
14928
14929#undef exception_handler
14930#undef trap
14931#undef trap_ptr
14932static void *sticky_mem_start, *sticky_mem_end;
14933static void
14934forkshell_init(const char *idstr)
14935{
14936 struct forkshell *fs;
14937 int map_handle;
14938 HANDLE h;
14939 struct globals_var **gvpp;
14940 struct globals_misc **gmpp;
14941 int i;
14942 char **ptr;
14943
14944 if (sscanf(idstr, "%x", &map_handle) != 1)
14945 bb_error_msg_and_die("invalid forkshell ID");
14946
14947 h = (HANDLE)map_handle;
14948 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14949 if (!fs)
14950 bb_error_msg_and_die("Invalid forkshell memory");
14951
14952 /* this memory can't be freed */
14953 sticky_mem_start = fs;
14954 sticky_mem_end = (char *) fs + fs->size;
14955
14956 /* pointer fixup */
14957 nodeptr = (char **)((char *)fs + fs->nodeptr_offset);
14958 for ( i=0; nodeptr[i]; ++i ) {
14959 ptr = (char **)((char *)fs + (nodeptr[i] - (char *)fs->old_base));
14960 if (*ptr)
14961 *ptr = (char *)fs + (*ptr - (char *)fs->old_base);
14962 }
14963
14964 /* Now fix up stuff that can't be transferred */
14965 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14966 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
14967 for (i = 0; i < CMDTABLESIZE; i++) {
14968 struct tblentry *e = fs->cmdtable[i];
14969 while (e) {
14970 if (e->cmdtype == CMDBUILTIN)
14971 e->param.cmd = builtintab + (int)e->param.cmd;
14972 e = e->next;
14973 }
14974 }
14975 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
14976 for (i = 0; i < NSIG; i++)
14977 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
14978 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
14979
14980 /* Switch global variables */
14981 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
14982 *gvpp = fs->gvp;
14983 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
14984 *gmpp = fs->gmp;
14985 cmdtable = fs->cmdtable;
14986
14987 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
14988
14989 reinitvar();
14990
14991 forkshell_child(fs);
14992}
14993
14994#undef free
14995static void
14996sticky_free(void *base)
14997{
14998 if (base >= sticky_mem_start && base < sticky_mem_end)
14999 return;
15000 free(base);
15001}
15002#endif
13734 15003
13735/*- 15004/*-
13736 * Copyright (c) 1989, 1991, 1993, 1994 15005 * 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 bf56f3d78..154b860f8 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
@@ -187,6 +191,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
187 * regardless of SA_RESTART-ness of that signal! 191 * regardless of SA_RESTART-ness of that signal!
188 */ 192 */
189 errno = 0; 193 errno = 0;
194#if !ENABLE_PLATFORM_MINGW32
190 pfd[0].fd = fd; 195 pfd[0].fd = fd;
191 pfd[0].events = POLLIN; 196 pfd[0].events = POLLIN;
192 if (poll(pfd, 1, timeout) != 1) { 197 if (poll(pfd, 1, timeout) != 1) {
@@ -195,6 +200,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
195 retval = (const char *)(uintptr_t)1; 200 retval = (const char *)(uintptr_t)1;
196 goto ret; 201 goto ret;
197 } 202 }
203#endif
198 if (read(fd, &buffer[bufpos], 1) != 1) { 204 if (read(fd, &buffer[bufpos], 1) != 1) {
199 err = errno; 205 err = errno;
200 retval = (const char *)(uintptr_t)1; 206 retval = (const char *)(uintptr_t)1;
@@ -202,7 +208,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
202 } 208 }
203 209
204 c = buffer[bufpos]; 210 c = buffer[bufpos];
205 if (c == '\0') 211 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r'))
206 continue; 212 continue;
207 if (!(read_flags & BUILTIN_READ_RAW)) { 213 if (!(read_flags & BUILTIN_READ_RAW)) {
208 if (backslash) { 214 if (backslash) {
@@ -276,6 +282,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
276 282
277/* ulimit builtin */ 283/* ulimit builtin */
278 284
285#if !ENABLE_PLATFORM_MINGW32
279struct limits { 286struct limits {
280 uint8_t cmd; /* RLIMIT_xxx fit into it */ 287 uint8_t cmd; /* RLIMIT_xxx fit into it */
281 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 288 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
@@ -492,3 +499,9 @@ shell_builtin_ulimit(char **argv)
492 499
493 return 0; 500 return 0;
494} 501}
502#else
503int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM)
504{
505 return 1;
506}
507#endif
diff --git a/util-linux/more.c b/util-linux/more.c
index debad81bd..a032a1e7f 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 c22505314..d34838a35 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..9a4b05597
--- /dev/null
+++ b/win32/process.c
@@ -0,0 +1,439 @@
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
238static intptr_t
239mingw_spawn_applet(int mode,
240 const char *applet,
241 const char *const *argv,
242 const char *const *envp)
243{
244 char **env = copy_environ(envp);
245 char path[MAX_PATH+20];
246 intptr_t ret;
247
248 sprintf(path, "BUSYBOX_APPLET_NAME=%s", applet);
249 env = env_setenv(env, path);
250 ret = spawnveq(mode, get_busybox_exec_path(), argv, (const char *const *)env);
251 free_environ(env);
252 return ret;
253}
254
255static intptr_t
256mingw_spawn_interpreter(int mode, const char *prog, const char *const *argv, const char *const *envp)
257{
258 intptr_t ret;
259 char **opts;
260 int nopts;
261 const char *interpr = parse_interpreter(prog, &opts, &nopts);
262 const char **new_argv;
263 int argc = 0;
264
265 if (!interpr)
266 return spawnveq(mode, prog, argv, envp);
267
268
269 while (argv[argc])
270 argc++;
271 new_argv = malloc(sizeof(*argv)*(argc+nopts+2));
272 memcpy(new_argv+1, opts, sizeof(*opts)*nopts);
273 memcpy(new_argv+nopts+2, argv+1, sizeof(*argv)*argc);
274 new_argv[nopts+1] = prog; /* pass absolute path */
275
276 if (ENABLE_FEATURE_PREFER_APPLETS && find_applet_by_name(interpr) >= 0) {
277 new_argv[0] = interpr;
278 ret = mingw_spawn_applet(mode, interpr, new_argv, envp);
279 }
280 else {
281 char *path = xstrdup(getenv("PATH"));
282 char *tmp = path;
283 char *iprog = find_executable(interpr, &tmp);
284 free(path);
285 if (!iprog) {
286 free(new_argv);
287 errno = ENOENT;
288 return -1;
289 }
290 new_argv[0] = iprog;
291 ret = spawnveq(mode, iprog, new_argv, envp);
292 free(iprog);
293 }
294
295 free(new_argv);
296 return ret;
297}
298
299static intptr_t
300mingw_spawn_1(int mode, const char *cmd, const char *const *argv, const char *const *envp)
301{
302 intptr_t ret;
303
304 if (ENABLE_FEATURE_PREFER_APPLETS &&
305 find_applet_by_name(cmd) >= 0)
306 return mingw_spawn_applet(mode, cmd, argv, envp);
307 else if (is_absolute_path(cmd))
308 return mingw_spawn_interpreter(mode, cmd, argv, envp);
309 else {
310 char *tmp, *path = getenv("PATH");
311 char *prog;
312
313 if (!path) {
314 errno = ENOENT;
315 return -1;
316 }
317
318 /* executable_exists() does not return new file name */
319 tmp = path = xstrdup(path);
320 prog = find_executable(cmd, &tmp);
321 free(path);
322 if (!prog) {
323 errno = ENOENT;
324 return -1;
325 }
326 ret = mingw_spawn_interpreter(mode, prog, argv, envp);
327 free(prog);
328 }
329 return ret;
330}
331
332pid_t FAST_FUNC
333mingw_spawn(char **argv)
334{
335 intptr_t ret;
336
337 ret = mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)argv,
338 (const char *const *)environ);
339
340 return ret == -1 ? -1 : GetProcessId((HANDLE)ret);
341}
342
343intptr_t FAST_FUNC
344mingw_spawn_proc(char **argv)
345{
346 return mingw_spawn_1(P_NOWAIT, argv[0], (const char *const *)argv,
347 (const char *const *)environ);
348}
349
350int
351mingw_execvp(const char *cmd, const char *const *argv)
352{
353 int ret = (int)mingw_spawn_1(P_WAIT, cmd, argv, (const char *const *)environ);
354 if (ret != -1)
355 exit(ret);
356 return ret;
357}
358
359int
360mingw_execve(const char *cmd, const char *const *argv, const char *const *envp)
361{
362 int ret;
363 int mode = P_WAIT;
364
365 if (ENABLE_FEATURE_PREFER_APPLETS &&
366 find_applet_by_name(cmd) >= 0)
367 ret = mingw_spawn_applet(mode, cmd, argv, envp);
368 /*
369 * execve(bb_busybox_exec_path, argv, envp) won't work
370 * because argv[0] will be replaced to bb_busybox_exec_path
371 * by MSVC runtime
372 */
373 else if (argv && cmd != argv[0] && cmd == bb_busybox_exec_path)
374 ret = mingw_spawn_applet(mode, argv[0], argv, envp);
375 else
376 ret = mingw_spawn_interpreter(mode, cmd, argv, envp);
377 if (ret != -1)
378 exit(ret);
379 return ret;
380}
381
382int
383mingw_execv(const char *cmd, const char *const *argv)
384{
385 return mingw_execve(cmd, argv, (const char *const *)environ);
386}
387
388/* POSIX version in libbb/procps.c */
389procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags UNUSED_PARAM)
390{
391 PROCESSENTRY32 pe;
392
393 pe.dwSize = sizeof(pe);
394 if (!sp) {
395 sp = xzalloc(sizeof(struct procps_status_t));
396 sp->snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
397 if (sp->snapshot == INVALID_HANDLE_VALUE) {
398 free(sp);
399 return NULL;
400 }
401 if (!Process32First(sp->snapshot, &pe)) {
402 CloseHandle(sp->snapshot);
403 free(sp);
404 return NULL;
405 }
406 }
407 else {
408 if (!Process32Next(sp->snapshot, &pe)) {
409 CloseHandle(sp->snapshot);
410 free(sp);
411 return NULL;
412 }
413 }
414
415 sp->pid = pe.th32ProcessID;
416 safe_strncpy(sp->comm, pe.szExeFile, COMM_LEN);
417 return sp;
418}
419
420int kill(pid_t pid, int sig)
421{
422 HANDLE h;
423
424 if (pid > 0 && sig == SIGTERM) {
425 if ((h=OpenProcess(PROCESS_TERMINATE, FALSE, pid)) != NULL &&
426 TerminateProcess(h, 0)) {
427 CloseHandle(h);
428 return 0;
429 }
430
431 errno = err_win_to_posix(GetLastError());
432 if (h != NULL)
433 CloseHandle(h);
434 return -1;
435 }
436
437 errno = EINVAL;
438 return -1;
439}
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/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..c3e2c316e
--- /dev/null
+++ b/win32/system.c
@@ -0,0 +1,77 @@
1#include "libbb.h"
2
3int mingw_system(const char *cmd)
4{
5 STARTUPINFO siStartInfo;
6 PROCESS_INFORMATION piProcInfo;
7 int success;
8 int len, count;
9 char *cmd_buff = NULL;
10 const char *s;
11 char *t;
12 DWORD ret;
13
14 if ( cmd == NULL ) {
15 return 1;
16 }
17
18 /* count double quotes */
19 count = 0;
20 for ( s=cmd; *s; ++s ) {
21 if ( *s == '"' ) {
22 ++count;
23 }
24 }
25
26 len = strlen(cmd) + 10 + count;
27 if ( (cmd_buff=malloc(len)) == NULL ) {
28 return -1;
29 }
30
31 /* escape double quotes */
32 strcpy(cmd_buff, "sh -c \"");
33 for ( s=cmd,t=cmd_buff+strlen(cmd_buff); *s; ++s ) {
34 if ( *s == '"' ) {
35 *t++ = '\\';
36 }
37 *t++ = *s;
38 }
39 *t++ = '"';
40 *t = '\0';
41
42 /* Now create the child process */
43 ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
44 siStartInfo.cb = sizeof(STARTUPINFO);
45 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
46 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
47 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
48 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
49
50 success = CreateProcess(NULL,
51 (LPTSTR)cmd_buff, /* command line */
52 NULL, /* process security attributes */
53 NULL, /* primary thread security attributes */
54 TRUE, /* handles are inherited */
55 0, /* creation flags */
56 NULL, /* use parent's environment */
57 NULL, /* use parent's current directory */
58 &siStartInfo, /* STARTUPINFO pointer */
59 &piProcInfo); /* receives PROCESS_INFORMATION */
60
61 if ( !success ) {
62 free(cmd_buff);
63 return 127;
64 }
65
66 free(cmd_buff);
67
68 WaitForSingleObject(piProcInfo.hProcess, INFINITE);
69
70 ret = 0;
71 GetExitCodeProcess(piProcInfo.hProcess, &ret);
72
73 CloseHandle(piProcInfo.hProcess);
74 CloseHandle(piProcInfo.hThread);
75
76 return ret;
77}
diff --git a/win32/termios.c b/win32/termios.c
new file mode 100644
index 000000000..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}