aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore1
-rw-r--r--Config.in36
-rw-r--r--Makefile12
-rw-r--r--Makefile.flags9
-rw-r--r--README1
-rw-r--r--README.md22
-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_defconfig1084
-rw-r--r--configs/mingw64_defconfig1084
-rw-r--r--coreutils/dd.c20
-rw-r--r--coreutils/od_bloaty.c7
-rw-r--r--coreutils/stat.c1
-rw-r--r--coreutils/test.c15
-rw-r--r--coreutils/yes.c4
-rw-r--r--debianutils/which.c20
-rw-r--r--editors/awk.c4
-rw-r--r--editors/diff.c21
-rw-r--r--editors/sed.c5
-rw-r--r--editors/vi.c59
-rw-r--r--findutils/grep.c8
-rw-r--r--findutils/xargs.c13
-rw-r--r--include/bb_archive.h10
-rw-r--r--include/libbb.h32
-rw-r--r--include/mingw.h482
-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/getopt32.c2
-rw-r--r--libbb/inode_hash.c2
-rw-r--r--libbb/lineedit.c126
-rw-r--r--libbb/make_directory.c25
-rw-r--r--libbb/messages.c2
-rw-r--r--libbb/printable_string.c2
-rw-r--r--libbb/procps.c3
-rw-r--r--libbb/read_printf.c5
-rw-r--r--libbb/setup_environment.c11
-rw-r--r--libbb/vfork_daemon_rexec.c4
-rw-r--r--libbb/xconnect.c12
-rw-r--r--libbb/xreadlink.c2
-rw-r--r--miscutils/bbconfig.c1
-rw-r--r--miscutils/less.c78
-rw-r--r--miscutils/man.c4
-rw-r--r--networking/ftpgetput.c6
-rw-r--r--networking/wget.c6
-rw-r--r--procps/ps.c16
-rw-r--r--procps/smemcap.c1
-rw-r--r--scripts/basic/fixdep.c51
-rw-r--r--shell/ash.c1377
-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.c1046
-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/regex.c4929
-rw-r--r--win32/regex.h490
-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.c734
108 files changed, 16568 insertions, 113 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 924a197da..594b16b76 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
@@ -467,6 +481,28 @@ config LFS
467 cp, mount, tar, and many others. If you want to access files larger 481 cp, mount, tar, and many others. If you want to access files larger
468 than 2 Gigabytes, enable this option. Otherwise, leave it set to 'N'. 482 than 2 Gigabytes, enable this option. Otherwise, leave it set to 'N'.
469 483
484config GLOBBING
485 bool "Allow busybox.exe to expand wildcards"
486 default n
487 depends on PLATFORM_MINGW32
488 help
489 In Microsoft Windows expansion of wildcards on the command line
490 ('globbing') is handled by the C runtime while the BusyBox shell
491 does its own wildcard expansion. For best results when using the
492 shell globbing by the C runtime should be turned off. If you want
493 the BusyBox binary to handle wildcard expansion using the C runtime
494 set this to 'Y'.
495
496config SAFE_ENV
497 bool "Manipulate the environment through safe API calls"
498 default n
499 depends on PLATFORM_MINGW32
500 help
501 Enable this option to use safe API calls when clearing environment
502 variables. This is necessary if BusyBox is to run on ReactOS or
503 64-bit Windows. The default is 'N', which must be used if BusyBox
504 is to run on Windows XP.
505
470config CROSS_COMPILER_PREFIX 506config CROSS_COMPILER_PREFIX
471 string "Cross Compiler prefix" 507 string "Cross Compiler prefix"
472 default "" 508 default ""
diff --git a/Makefile b/Makefile
index 971e68e87..d4d8db667 100644
--- a/Makefile
+++ b/Makefile
@@ -312,6 +312,7 @@ AFLAGS_MODULE = $(MODFLAGS)
312LDFLAGS_MODULE = -r 312LDFLAGS_MODULE = -r
313CFLAGS_KERNEL = 313CFLAGS_KERNEL =
314AFLAGS_KERNEL = 314AFLAGS_KERNEL =
315EXEEXT =
315 316
316 317
317# Use LINUXINCLUDE when you must reference the include/ directory. 318# Use LINUXINCLUDE when you must reference the include/ directory.
@@ -491,6 +492,7 @@ libs-y := \
491 sysklogd/ \ 492 sysklogd/ \
492 util-linux/ \ 493 util-linux/ \
493 util-linux/volume_id/ \ 494 util-linux/volume_id/ \
495 win32/ \
494 496
495endif # KBUILD_EXTMOD 497endif # KBUILD_EXTMOD
496 498
@@ -529,7 +531,7 @@ endif
529# command line. 531# command line.
530# This allow a user to issue only 'make' to build a kernel including modules 532# This allow a user to issue only 'make' to build a kernel including modules
531# Defaults busybox but it is usually overridden in the arch makefile 533# Defaults busybox but it is usually overridden in the arch makefile
532all: busybox doc 534all: busybox$(EXEEXT) doc
533 535
534-include $(srctree)/arch/$(ARCH)/Makefile 536-include $(srctree)/arch/$(ARCH)/Makefile
535 537
@@ -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 65021de25..4fb57d7b4 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -15,7 +15,8 @@ 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))" -DBB_BT=AUTOCONF_TIMESTAMP 18 -D"BB_VER=KBUILD_STR($(BB_VER))" -DBB_BT=AUTOCONF_TIMESTAMP \
19 -D"MINGW_VER=KBUILD_STR($(MINGW_VER))"
19 20
20CFLAGS += $(call cc-option,-Wall,) 21CFLAGS += $(call cc-option,-Wall,)
21CFLAGS += $(call cc-option,-Wshadow,) 22CFLAGS += $(call cc-option,-Wshadow,)
@@ -123,6 +124,12 @@ CFLAGS += --sysroot=$(CONFIG_SYSROOT)
123export SYSROOT=$(CONFIG_SYSROOT) 124export SYSROOT=$(CONFIG_SYSROOT)
124endif 125endif
125 126
127ifeq ($(CONFIG_PLATFORM_MINGW32),y)
128CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-ident
129EXEEXT = .exe
130LDLIBS += userenv ws2_32 mingwex -l:libssp.a
131endif
132
126# Android has no separate crypt library 133# Android has no separate crypt library
127# gcc-4.2.1 fails if we try to feed C source on stdin: 134# 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 - 135# 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..f83900cc7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
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.
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 e49d5cb2b..a850868f6 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 60a837e22..343aec9bd 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -183,6 +183,8 @@ int FAST_FUNC bbunpack(char **argv,
183 /* Delete _source_ file */ 183 /* Delete _source_ file */
184 del = filename; 184 del = filename;
185 } 185 }
186 if (ENABLE_PLATFORM_MINGW32)
187 xclose(STDIN_FILENO);
186 xunlink(del); 188 xunlink(del);
187 free_name: 189 free_name:
188 if (new_name != filename) 190 if (new_name != filename)
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 8e315c610..c87d23597 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -554,6 +554,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
554 } 554 }
555 } 555 }
556 556
557#if !ENABLE_PLATFORM_MINGW32
557 /* It is a bad idea to store the archive we are in the process of creating, 558 /* It is a bad idea to store the archive we are in the process of creating,
558 * so check the device and inode to be sure that this particular file isn't 559 * so check the device and inode to be sure that this particular file isn't
559 * the new tarball */ 560 * the new tarball */
@@ -563,6 +564,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
563 bb_error_msg("%s: file is the archive; skipping", fileName); 564 bb_error_msg("%s: file is the archive; skipping", fileName);
564 return TRUE; 565 return TRUE;
565 } 566 }
567#endif
566 568
567 if (exclude_file(tbInfo->excludeList, header_name)) 569 if (exclude_file(tbInfo->excludeList, header_name))
568 return SKIP; 570 return SKIP;
@@ -620,6 +622,7 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb
620} 622}
621 623
622#if SEAMLESS_COMPRESSION 624#if SEAMLESS_COMPRESSION
625#if !ENABLE_PLATFORM_MINGW32
623/* Don't inline: vfork scares gcc and pessimizes code */ 626/* Don't inline: vfork scares gcc and pessimizes code */
624static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) 627static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
625{ 628{
@@ -679,6 +682,27 @@ static void NOINLINE vfork_compressor(int tar_fd, const char *gzip)
679 bb_perror_msg_and_die("can't execute '%s'", gzip); 682 bb_perror_msg_and_die("can't execute '%s'", gzip);
680 } 683 }
681} 684}
685#else
686static pid_t vfork_compressor(int tar_fd, const char *gzip)
687{
688 char *cmd;
689 int fd1;
690 pid_t pid;
691
692 if (find_applet_by_name(gzip) >= 0) {
693 cmd = xasprintf("%s --busybox %s -cf -", bb_busybox_exec_path, gzip);
694 }
695 else {
696 cmd = xasprintf("%s -cf -", gzip);
697 }
698 if ( (fd1=mingw_popen_fd(cmd, "w", tar_fd, &pid)) == -1 ) {
699 bb_perror_msg_and_die("can't execute '%s'", gzip);
700 }
701 free(cmd);
702 xmove_fd(fd1, tar_fd);
703 return pid;
704}
705#endif /* ENABLE_PLATFORM_MINGW32 */
682#endif /* SEAMLESS_COMPRESSION */ 706#endif /* SEAMLESS_COMPRESSION */
683 707
684 708
@@ -694,6 +718,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
694{ 718{
695 int errorFlag = FALSE; 719 int errorFlag = FALSE;
696 struct TarBallInfo tbInfo; 720 struct TarBallInfo tbInfo;
721 IF_PLATFORM_MINGW32(pid_t pid = 0;)
697 722
698 tbInfo.hlInfoHead = NULL; 723 tbInfo.hlInfoHead = NULL;
699 tbInfo.tarFd = tar_fd; 724 tbInfo.tarFd = tar_fd;
@@ -705,7 +730,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
705 730
706#if SEAMLESS_COMPRESSION 731#if SEAMLESS_COMPRESSION
707 if (gzip) 732 if (gzip)
708 vfork_compressor(tbInfo.tarFd, gzip); 733 IF_PLATFORM_MINGW32(pid = )vfork_compressor(tbInfo.tarFd, gzip);
709#endif 734#endif
710 735
711 tbInfo.excludeList = exclude; 736 tbInfo.excludeList = exclude;
@@ -741,7 +766,11 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag,
741#if SEAMLESS_COMPRESSION 766#if SEAMLESS_COMPRESSION
742 if (gzip) { 767 if (gzip) {
743 int status; 768 int status;
769#if !ENABLE_PLATFORM_MINGW32
744 if (safe_waitpid(-1, &status, 0) == -1) 770 if (safe_waitpid(-1, &status, 0) == -1)
771#else
772 if (safe_waitpid(pid, &status, 0) == -1)
773#endif
745 bb_perror_msg("waitpid"); 774 bb_perror_msg("waitpid");
746 else if (!WIFEXITED(status) || WEXITSTATUS(status)) 775 else if (!WIFEXITED(status) || WEXITSTATUS(status))
747 /* gzip was killed or has exited with nonzero! */ 776 /* gzip was killed or has exited with nonzero! */
diff --git a/archival/unzip.c b/archival/unzip.c
index c540485ac..27adb3420 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -44,6 +44,9 @@
44 44
45#include "libbb.h" 45#include "libbb.h"
46#include "bb_archive.h" 46#include "bb_archive.h"
47#if ENABLE_PLATFORM_MINGW32 && __GNUC__
48#pragma pack(2)
49#endif
47 50
48#if 0 51#if 0
49# define dbg(...) bb_error_msg(__VA_ARGS__) 52# define dbg(...) bb_error_msg(__VA_ARGS__)
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
new file mode 100644
index 000000000..5801e26a2
--- /dev/null
+++ b/configs/mingw32_defconfig
@@ -0,0 +1,1084 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.26.0.git
4# Tue Nov 29 11:42:12 2016
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
14CONFIG_EXTRA_COMPAT=y
15# CONFIG_INCLUDE_SUSv2 is not set
16CONFIG_USE_PORTABLE_CODE=y
17# CONFIG_PLATFORM_LINUX is not set
18CONFIG_SHOW_USAGE=y
19CONFIG_FEATURE_VERBOSE_USAGE=y
20CONFIG_FEATURE_COMPRESS_USAGE=y
21CONFIG_BUSYBOX=y
22CONFIG_FEATURE_INSTALLER=y
23# CONFIG_INSTALL_NO_USR is not set
24# CONFIG_PAM is not set
25CONFIG_LONG_OPTS=y
26# CONFIG_FEATURE_DEVPTS is not set
27# CONFIG_FEATURE_CLEAN_UP is not set
28# CONFIG_FEATURE_UTMP is not set
29# CONFIG_FEATURE_WTMP is not set
30# CONFIG_FEATURE_PIDFILE is not set
31CONFIG_PID_FILE_PATH=""
32# CONFIG_FEATURE_SUID is not set
33# CONFIG_FEATURE_SUID_CONFIG is not set
34# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
35# CONFIG_SELINUX is not set
36CONFIG_FEATURE_PREFER_APPLETS=y
37CONFIG_BUSYBOX_EXEC_PATH=""
38# CONFIG_FEATURE_SYSLOG is not set
39# CONFIG_FEATURE_HAVE_RPC 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
96# CONFIG_FEATURE_USE_TERMIOS is not set
97CONFIG_FEATURE_EDITING=y
98CONFIG_FEATURE_EDITING_MAX_LEN=1024
99CONFIG_FEATURE_EDITING_VI=y
100CONFIG_FEATURE_EDITING_HISTORY=255
101CONFIG_FEATURE_EDITING_SAVEHISTORY=y
102# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
103CONFIG_FEATURE_REVERSE_SEARCH=y
104CONFIG_FEATURE_TAB_COMPLETION=y
105CONFIG_FEATURE_USERNAME_COMPLETION=y
106CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
107# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
108# CONFIG_LOCALE_SUPPORT is not set
109# CONFIG_UNICODE_SUPPORT is not set
110# CONFIG_UNICODE_USING_LOCALE is not set
111# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
112CONFIG_SUBST_WCHAR=0
113CONFIG_LAST_SUPPORTED_WCHAR=0
114# CONFIG_UNICODE_COMBINING_WCHARS is not set
115# CONFIG_UNICODE_WIDE_WCHARS is not set
116# CONFIG_UNICODE_BIDI_SUPPORT is not set
117# CONFIG_UNICODE_NEUTRAL_TABLE is not set
118# CONFIG_UNICODE_PRESERVE_BROKEN is not set
119CONFIG_FEATURE_NON_POSIX_CP=y
120# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
121# CONFIG_FEATURE_USE_SENDFILE is not set
122CONFIG_FEATURE_COPYBUF_KB=4
123CONFIG_FEATURE_SKIP_ROOTFS=y
124# CONFIG_MONOTONIC_SYSCALL is not set
125CONFIG_IOCTL_HEX2STR_ERROR=y
126# CONFIG_FEATURE_HWIB is not set
127
128#
129# Applets
130#
131
132#
133# Archival Utilities
134#
135CONFIG_FEATURE_SEAMLESS_XZ=y
136CONFIG_FEATURE_SEAMLESS_LZMA=y
137CONFIG_FEATURE_SEAMLESS_BZ2=y
138CONFIG_FEATURE_SEAMLESS_GZ=y
139CONFIG_FEATURE_SEAMLESS_Z=y
140CONFIG_AR=y
141CONFIG_FEATURE_AR_LONG_FILENAMES=y
142CONFIG_FEATURE_AR_CREATE=y
143CONFIG_UNCOMPRESS=y
144CONFIG_GUNZIP=y
145CONFIG_ZCAT=y
146CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
147CONFIG_BUNZIP2=y
148CONFIG_BZCAT=y
149CONFIG_UNLZMA=y
150CONFIG_LZCAT=y
151CONFIG_LZMA=y
152CONFIG_FEATURE_LZMA_FAST=y
153CONFIG_UNXZ=y
154CONFIG_XZCAT=y
155CONFIG_XZ=y
156CONFIG_BZIP2=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_LZOP=y
167CONFIG_UNLZOP=y
168CONFIG_LZOPCAT=y
169# CONFIG_LZOP_COMPR_HIGH is not set
170CONFIG_RPM2CPIO=y
171# CONFIG_RPM is not set
172CONFIG_TAR=y
173CONFIG_FEATURE_TAR_CREATE=y
174CONFIG_FEATURE_TAR_AUTODETECT=y
175CONFIG_FEATURE_TAR_FROM=y
176CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
177# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
178CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
179CONFIG_FEATURE_TAR_LONG_OPTIONS=y
180# CONFIG_FEATURE_TAR_TO_COMMAND is not set
181# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
182CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
183# CONFIG_FEATURE_TAR_SELINUX is not set
184CONFIG_UNZIP=y
185
186#
187# Coreutils
188#
189CONFIG_BASENAME=y
190CONFIG_CAL=y
191CONFIG_CAT=y
192CONFIG_CATV=y
193# CONFIG_CHGRP is not set
194CONFIG_CHMOD=y
195# CONFIG_CHOWN is not set
196# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
197# CONFIG_CHROOT is not set
198CONFIG_CKSUM=y
199CONFIG_COMM=y
200CONFIG_CP=y
201CONFIG_FEATURE_CP_LONG_OPTIONS=y
202CONFIG_CUT=y
203CONFIG_DATE=y
204CONFIG_FEATURE_DATE_ISOFMT=y
205# CONFIG_FEATURE_DATE_NANO is not set
206CONFIG_FEATURE_DATE_COMPAT=y
207CONFIG_DD=y
208# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
209# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
210CONFIG_FEATURE_DD_IBS_OBS=y
211CONFIG_FEATURE_DD_STATUS=y
212CONFIG_DF=y
213# CONFIG_FEATURE_DF_FANCY is not set
214CONFIG_DIRNAME=y
215CONFIG_DOS2UNIX=y
216CONFIG_UNIX2DOS=y
217CONFIG_DU=y
218CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
219CONFIG_ECHO=y
220CONFIG_FEATURE_FANCY_ECHO=y
221CONFIG_ENV=y
222CONFIG_FEATURE_ENV_LONG_OPTIONS=y
223CONFIG_EXPAND=y
224CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
225CONFIG_UNEXPAND=y
226CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
227CONFIG_EXPR=y
228CONFIG_EXPR_MATH_SUPPORT_64=y
229CONFIG_FALSE=y
230CONFIG_FOLD=y
231# CONFIG_FSYNC is not set
232CONFIG_HEAD=y
233CONFIG_FEATURE_FANCY_HEAD=y
234# CONFIG_HOSTID is not set
235CONFIG_ID=y
236CONFIG_GROUPS=y
237# CONFIG_INSTALL is not set
238# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
239CONFIG_LN=y
240CONFIG_LOGNAME=y
241CONFIG_LS=y
242CONFIG_FEATURE_LS_FILETYPES=y
243CONFIG_FEATURE_LS_FOLLOWLINKS=y
244CONFIG_FEATURE_LS_RECURSIVE=y
245CONFIG_FEATURE_LS_SORTFILES=y
246CONFIG_FEATURE_LS_TIMESTAMPS=y
247CONFIG_FEATURE_LS_USERNAME=y
248CONFIG_FEATURE_LS_COLOR=y
249CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
250CONFIG_MD5SUM=y
251CONFIG_SHA1SUM=y
252CONFIG_SHA256SUM=y
253CONFIG_SHA512SUM=y
254CONFIG_SHA3SUM=y
255
256#
257# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
258#
259CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
260CONFIG_MKDIR=y
261CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
262# CONFIG_MKFIFO is not set
263# CONFIG_MKNOD is not set
264CONFIG_MV=y
265CONFIG_FEATURE_MV_LONG_OPTIONS=y
266# CONFIG_NICE is not set
267# CONFIG_NOHUP is not set
268CONFIG_OD=y
269CONFIG_PRINTENV=y
270CONFIG_PRINTF=y
271CONFIG_PWD=y
272# CONFIG_READLINK is not set
273# CONFIG_FEATURE_READLINK_FOLLOW is not set
274# CONFIG_REALPATH is not set
275CONFIG_RM=y
276CONFIG_RMDIR=y
277CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
278CONFIG_SEQ=y
279CONFIG_SHUF=y
280CONFIG_SLEEP=y
281CONFIG_FEATURE_FANCY_SLEEP=y
282# CONFIG_FEATURE_FLOAT_SLEEP is not set
283CONFIG_SORT=y
284CONFIG_FEATURE_SORT_BIG=y
285CONFIG_SPLIT=y
286CONFIG_FEATURE_SPLIT_FANCY=y
287CONFIG_STAT=y
288CONFIG_FEATURE_STAT_FORMAT=y
289CONFIG_FEATURE_STAT_FILESYSTEM=y
290# CONFIG_STTY is not set
291CONFIG_SUM=y
292# CONFIG_SYNC is not set
293# CONFIG_FEATURE_SYNC_FANCY is not set
294CONFIG_TAC=y
295CONFIG_TAIL=y
296CONFIG_FEATURE_FANCY_TAIL=y
297CONFIG_TEE=y
298CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
299CONFIG_TEST=y
300CONFIG_TEST1=y
301CONFIG_TEST2=y
302CONFIG_FEATURE_TEST_64=y
303CONFIG_TOUCH=y
304# CONFIG_FEATURE_TOUCH_NODEREF is not set
305CONFIG_FEATURE_TOUCH_SUSV3=y
306CONFIG_TR=y
307CONFIG_FEATURE_TR_CLASSES=y
308CONFIG_FEATURE_TR_EQUIV=y
309CONFIG_TRUE=y
310CONFIG_TRUNCATE=y
311# CONFIG_TTY is not set
312CONFIG_UNAME=y
313CONFIG_UNAME_OSNAME="MS/Windows"
314CONFIG_UNIQ=y
315CONFIG_UNLINK=y
316CONFIG_USLEEP=y
317CONFIG_UUDECODE=y
318CONFIG_BASE64=y
319CONFIG_UUENCODE=y
320CONFIG_WC=y
321CONFIG_FEATURE_WC_LARGE=y
322CONFIG_WHOAMI=y
323# CONFIG_WHO is not set
324# CONFIG_USERS is not set
325CONFIG_YES=y
326
327#
328# Common options
329#
330CONFIG_FEATURE_VERBOSE=y
331
332#
333# Common options for cp and mv
334#
335# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
336
337#
338# Common options for ls, more and telnet
339#
340CONFIG_FEATURE_AUTOWIDTH=y
341
342#
343# Common options for df, du, ls
344#
345CONFIG_FEATURE_HUMAN_READABLE=y
346
347#
348# Console Utilities
349#
350# CONFIG_CHVT is not set
351CONFIG_CLEAR=y
352# CONFIG_DEALLOCVT is not set
353# CONFIG_DUMPKMAP is not set
354# CONFIG_FGCONSOLE is not set
355# CONFIG_KBD_MODE is not set
356# CONFIG_LOADFONT is not set
357# CONFIG_SETFONT is not set
358# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
359CONFIG_DEFAULT_SETFONT_DIR=""
360# CONFIG_FEATURE_LOADFONT_PSF2 is not set
361# CONFIG_FEATURE_LOADFONT_RAW is not set
362# CONFIG_LOADKMAP is not set
363# CONFIG_OPENVT is not set
364# CONFIG_RESET is not set
365# CONFIG_RESIZE is not set
366# CONFIG_FEATURE_RESIZE_PRINT is not set
367# CONFIG_SETCONSOLE is not set
368# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
369# CONFIG_SETKEYCODES is not set
370# CONFIG_SETLOGCONS is not set
371# CONFIG_SHOWKEY is not set
372
373#
374# Debian Utilities
375#
376CONFIG_MKTEMP=y
377# CONFIG_PIPE_PROGRESS is not set
378# CONFIG_RUN_PARTS is not set
379# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
380# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
381# CONFIG_START_STOP_DAEMON is not set
382# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
383# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
384CONFIG_WHICH=y
385
386#
387# Editors
388#
389CONFIG_AWK=y
390CONFIG_FEATURE_AWK_LIBM=y
391CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
392CONFIG_CMP=y
393CONFIG_DIFF=y
394CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
395CONFIG_FEATURE_DIFF_DIR=y
396CONFIG_ED=y
397CONFIG_PATCH=y
398CONFIG_SED=y
399CONFIG_VI=y
400CONFIG_FEATURE_VI_MAX_LEN=4096
401CONFIG_FEATURE_VI_8BIT=y
402CONFIG_FEATURE_VI_COLON=y
403CONFIG_FEATURE_VI_YANKMARK=y
404CONFIG_FEATURE_VI_SEARCH=y
405# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
406# CONFIG_FEATURE_VI_USE_SIGNALS is not set
407CONFIG_FEATURE_VI_DOT_CMD=y
408CONFIG_FEATURE_VI_READONLY=y
409CONFIG_FEATURE_VI_SETOPTS=y
410CONFIG_FEATURE_VI_SET=y
411CONFIG_FEATURE_VI_WIN_RESIZE=y
412CONFIG_FEATURE_VI_ASK_TERMINAL=y
413CONFIG_FEATURE_VI_UNDO=y
414CONFIG_FEATURE_VI_UNDO_QUEUE=y
415CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
416CONFIG_FEATURE_ALLOW_EXEC=y
417
418#
419# Finding Utilities
420#
421CONFIG_FIND=y
422CONFIG_FEATURE_FIND_PRINT0=y
423CONFIG_FEATURE_FIND_MTIME=y
424CONFIG_FEATURE_FIND_MMIN=y
425CONFIG_FEATURE_FIND_PERM=y
426CONFIG_FEATURE_FIND_TYPE=y
427# CONFIG_FEATURE_FIND_XDEV is not set
428CONFIG_FEATURE_FIND_MAXDEPTH=y
429CONFIG_FEATURE_FIND_NEWER=y
430# CONFIG_FEATURE_FIND_INUM is not set
431# CONFIG_FEATURE_FIND_EXEC is not set
432# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
433# CONFIG_FEATURE_FIND_USER is not set
434# CONFIG_FEATURE_FIND_GROUP is not set
435CONFIG_FEATURE_FIND_NOT=y
436CONFIG_FEATURE_FIND_DEPTH=y
437CONFIG_FEATURE_FIND_PAREN=y
438CONFIG_FEATURE_FIND_SIZE=y
439CONFIG_FEATURE_FIND_PRUNE=y
440CONFIG_FEATURE_FIND_DELETE=y
441CONFIG_FEATURE_FIND_PATH=y
442CONFIG_FEATURE_FIND_REGEX=y
443# CONFIG_FEATURE_FIND_CONTEXT is not set
444# CONFIG_FEATURE_FIND_LINKS is not set
445CONFIG_GREP=y
446CONFIG_EGREP=y
447CONFIG_FGREP=y
448CONFIG_FEATURE_GREP_CONTEXT=y
449CONFIG_XARGS=y
450CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
451CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
452CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
453CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
454CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
455
456#
457# Init Utilities
458#
459# CONFIG_BOOTCHARTD is not set
460# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
461# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
462# CONFIG_HALT is not set
463# CONFIG_POWEROFF is not set
464# CONFIG_REBOOT is not set
465# CONFIG_FEATURE_CALL_TELINIT is not set
466CONFIG_TELINIT_PATH=""
467# CONFIG_INIT is not set
468# CONFIG_LINUXRC is not set
469# CONFIG_FEATURE_USE_INITTAB is not set
470# CONFIG_FEATURE_KILL_REMOVED is not set
471CONFIG_FEATURE_KILL_DELAY=0
472# CONFIG_FEATURE_INIT_SCTTY is not set
473# CONFIG_FEATURE_INIT_SYSLOG is not set
474# CONFIG_FEATURE_EXTRA_QUIET is not set
475# CONFIG_FEATURE_INIT_COREDUMPS is not set
476CONFIG_INIT_TERMINAL_TYPE=""
477# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
478# CONFIG_MESG is not set
479# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
480
481#
482# Login/Password Management Utilities
483#
484# CONFIG_FEATURE_SHADOWPASSWDS is not set
485# CONFIG_USE_BB_PWD_GRP is not set
486# CONFIG_USE_BB_SHADOW is not set
487# CONFIG_USE_BB_CRYPT is not set
488# CONFIG_USE_BB_CRYPT_SHA is not set
489# CONFIG_ADDGROUP is not set
490# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
491# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
492# CONFIG_ADD_SHELL is not set
493# CONFIG_REMOVE_SHELL is not set
494# CONFIG_ADDUSER is not set
495# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
496# CONFIG_FEATURE_CHECK_NAMES is not set
497CONFIG_LAST_ID=0
498CONFIG_FIRST_SYSTEM_ID=0
499CONFIG_LAST_SYSTEM_ID=0
500# CONFIG_CHPASSWD is not set
501CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
502# CONFIG_CRYPTPW is not set
503# CONFIG_MKPASSWD is not set
504# CONFIG_DELUSER is not set
505# CONFIG_DELGROUP is not set
506# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
507# CONFIG_GETTY is not set
508# CONFIG_LOGIN is not set
509# CONFIG_LOGIN_SESSION_AS_CHILD is not set
510# CONFIG_LOGIN_SCRIPTS is not set
511# CONFIG_FEATURE_NOLOGIN is not set
512# CONFIG_FEATURE_SECURETTY is not set
513# CONFIG_PASSWD is not set
514# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
515# CONFIG_SU is not set
516# CONFIG_FEATURE_SU_SYSLOG is not set
517# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
518# CONFIG_SULOGIN is not set
519# CONFIG_VLOCK is not set
520
521#
522# Linux Ext2 FS Progs
523#
524# CONFIG_CHATTR is not set
525# CONFIG_FSCK is not set
526# CONFIG_LSATTR is not set
527# CONFIG_TUNE2FS is not set
528
529#
530# Linux Module Utilities
531#
532# CONFIG_DEPMOD is not set
533# CONFIG_INSMOD is not set
534# CONFIG_LSMOD is not set
535# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
536# CONFIG_MODINFO is not set
537# CONFIG_MODPROBE is not set
538# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
539# CONFIG_MODPROBE_SMALL is not set
540# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set
541# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
542# CONFIG_RMMOD is not set
543
544#
545# Options common to multiple modutils
546#
547# CONFIG_FEATURE_2_4_MODULES is not set
548# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
549# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
550# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
551# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
552# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
553# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
554# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
555# CONFIG_FEATURE_MODUTILS_ALIAS is not set
556# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
557CONFIG_DEFAULT_MODULES_DIR=""
558CONFIG_DEFAULT_DEPMOD_FILE=""
559
560#
561# Linux System Utilities
562#
563# CONFIG_ACPID is not set
564# CONFIG_FEATURE_ACPID_COMPAT is not set
565# CONFIG_BLKDISCARD is not set
566# CONFIG_BLKID is not set
567# CONFIG_FEATURE_BLKID_TYPE is not set
568# CONFIG_BLOCKDEV is not set
569# CONFIG_DMESG is not set
570# CONFIG_FEATURE_DMESG_PRETTY is not set
571# CONFIG_FATATTR is not set
572# CONFIG_FBSET is not set
573# CONFIG_FEATURE_FBSET_FANCY is not set
574# CONFIG_FEATURE_FBSET_READMODE is not set
575# CONFIG_FDFORMAT is not set
576# CONFIG_FDISK is not set
577# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
578# CONFIG_FEATURE_FDISK_WRITABLE is not set
579# CONFIG_FEATURE_AIX_LABEL is not set
580# CONFIG_FEATURE_SGI_LABEL is not set
581# CONFIG_FEATURE_SUN_LABEL is not set
582# CONFIG_FEATURE_OSF_LABEL is not set
583# CONFIG_FEATURE_GPT_LABEL is not set
584# CONFIG_FEATURE_FDISK_ADVANCED is not set
585# CONFIG_FINDFS is not set
586# CONFIG_FLOCK is not set
587# CONFIG_FDFLUSH is not set
588# CONFIG_FREERAMDISK is not set
589# CONFIG_FSCK_MINIX is not set
590# CONFIG_FSTRIM is not set
591CONFIG_GETOPT=y
592CONFIG_FEATURE_GETOPT_LONG=y
593CONFIG_HEXDUMP=y
594CONFIG_FEATURE_HEXDUMP_REVERSE=y
595CONFIG_HD=y
596# CONFIG_HWCLOCK is not set
597# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
598# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
599# CONFIG_IPCRM is not set
600# CONFIG_IPCS is not set
601# CONFIG_LOSETUP is not set
602# CONFIG_LSPCI is not set
603# CONFIG_LSUSB is not set
604# CONFIG_MDEV is not set
605# CONFIG_FEATURE_MDEV_CONF is not set
606# CONFIG_FEATURE_MDEV_RENAME is not set
607# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
608# CONFIG_FEATURE_MDEV_EXEC is not set
609# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
610# CONFIG_MKE2FS is not set
611# CONFIG_MKFS_EXT2 is not set
612# CONFIG_MKFS_MINIX is not set
613# CONFIG_FEATURE_MINIX2 is not set
614# CONFIG_MKFS_REISER is not set
615# CONFIG_MKDOSFS is not set
616# CONFIG_MKFS_VFAT is not set
617# CONFIG_MKSWAP is not set
618# CONFIG_FEATURE_MKSWAP_UUID is not set
619# CONFIG_MORE is not set
620# CONFIG_MOUNT is not set
621# CONFIG_FEATURE_MOUNT_FAKE is not set
622# CONFIG_FEATURE_MOUNT_VERBOSE is not set
623# CONFIG_FEATURE_MOUNT_HELPERS is not set
624# CONFIG_FEATURE_MOUNT_LABEL is not set
625# CONFIG_FEATURE_MOUNT_NFS is not set
626# CONFIG_FEATURE_MOUNT_CIFS is not set
627# CONFIG_FEATURE_MOUNT_FLAGS is not set
628# CONFIG_FEATURE_MOUNT_FSTAB is not set
629# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
630# CONFIG_NSENTER is not set
631# CONFIG_FEATURE_NSENTER_LONG_OPTS is not set
632# CONFIG_PIVOT_ROOT is not set
633# CONFIG_RDATE is not set
634# CONFIG_RDEV is not set
635# CONFIG_READPROFILE is not set
636CONFIG_REV=y
637# CONFIG_RTCWAKE is not set
638# CONFIG_SCRIPT is not set
639# CONFIG_SCRIPTREPLAY is not set
640# CONFIG_SETARCH is not set
641# CONFIG_LINUX32 is not set
642# CONFIG_LINUX64 is not set
643# CONFIG_SWAPON is not set
644# CONFIG_FEATURE_SWAPON_DISCARD is not set
645# CONFIG_FEATURE_SWAPON_PRI is not set
646# CONFIG_SWAPOFF is not set
647# CONFIG_SWITCH_ROOT is not set
648# CONFIG_UEVENT is not set
649# CONFIG_UMOUNT is not set
650# CONFIG_FEATURE_UMOUNT_ALL is not set
651# CONFIG_UNSHARE is not set
652# CONFIG_FEATURE_MOUNT_LOOP is not set
653# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
654# CONFIG_FEATURE_MTAB_SUPPORT is not set
655# CONFIG_VOLUMEID is not set
656# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
657# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
658# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
659# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
660# CONFIG_FEATURE_VOLUMEID_EXT is not set
661# CONFIG_FEATURE_VOLUMEID_F2FS is not set
662# CONFIG_FEATURE_VOLUMEID_FAT is not set
663# CONFIG_FEATURE_VOLUMEID_HFS is not set
664# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
665# CONFIG_FEATURE_VOLUMEID_JFS is not set
666# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
667# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
668# CONFIG_FEATURE_VOLUMEID_LUKS is not set
669# CONFIG_FEATURE_VOLUMEID_NILFS is not set
670# CONFIG_FEATURE_VOLUMEID_NTFS is not set
671# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
672# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
673# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
674# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
675# CONFIG_FEATURE_VOLUMEID_SYSV is not set
676# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
677# CONFIG_FEATURE_VOLUMEID_UDF is not set
678# CONFIG_FEATURE_VOLUMEID_XFS is not set
679
680#
681# Miscellaneous Utilities
682#
683# CONFIG_ADJTIMEX is not set
684# CONFIG_BBCONFIG is not set
685# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
686# CONFIG_BEEP is not set
687CONFIG_FEATURE_BEEP_FREQ=0
688CONFIG_FEATURE_BEEP_LENGTH_MS=0
689# CONFIG_CHAT is not set
690# CONFIG_FEATURE_CHAT_NOFAIL is not set
691# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
692# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
693# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
694# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
695# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
696# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
697# CONFIG_CHRT is not set
698# CONFIG_CONSPY is not set
699# CONFIG_CROND is not set
700# CONFIG_FEATURE_CROND_D is not set
701# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
702CONFIG_FEATURE_CROND_DIR=""
703# CONFIG_CRONTAB is not set
704CONFIG_DC=y
705CONFIG_FEATURE_DC_LIBM=y
706# CONFIG_DEVFSD is not set
707# CONFIG_DEVFSD_MODLOAD is not set
708# CONFIG_DEVFSD_FG_NP is not set
709# CONFIG_DEVFSD_VERBOSE is not set
710# CONFIG_FEATURE_DEVFS is not set
711# CONFIG_DEVMEM is not set
712# CONFIG_EJECT is not set
713# CONFIG_FEATURE_EJECT_SCSI is not set
714# CONFIG_FBSPLASH is not set
715# CONFIG_FLASHCP is not set
716# CONFIG_FLASH_ERASEALL is not set
717# CONFIG_FLASH_LOCK is not set
718# CONFIG_FLASH_UNLOCK is not set
719# CONFIG_HDPARM is not set
720# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
721# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
722# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
723# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
724# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
725# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
726# CONFIG_I2CGET is not set
727# CONFIG_I2CSET is not set
728# CONFIG_I2CDUMP is not set
729# CONFIG_I2CDETECT is not set
730# CONFIG_INOTIFYD is not set
731# CONFIG_IONICE is not set
732# CONFIG_LAST is not set
733# CONFIG_FEATURE_LAST_FANCY is not set
734CONFIG_LESS=y
735CONFIG_FEATURE_LESS_MAXLINES=9999999
736CONFIG_FEATURE_LESS_BRACKETS=y
737CONFIG_FEATURE_LESS_FLAGS=y
738CONFIG_FEATURE_LESS_TRUNCATE=y
739CONFIG_FEATURE_LESS_MARKS=y
740CONFIG_FEATURE_LESS_REGEXP=y
741# CONFIG_FEATURE_LESS_WINCH is not set
742# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
743CONFIG_FEATURE_LESS_DASHCMD=y
744CONFIG_FEATURE_LESS_LINENUMS=y
745# CONFIG_MAKEDEVS is not set
746# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
747# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
748CONFIG_MAN=y
749# CONFIG_MICROCOM is not set
750# CONFIG_MOUNTPOINT is not set
751# CONFIG_MT is not set
752# CONFIG_NANDWRITE is not set
753# CONFIG_NANDDUMP is not set
754# CONFIG_RAIDAUTORUN is not set
755# CONFIG_READAHEAD is not set
756# CONFIG_RFKILL is not set
757# CONFIG_RUNLEVEL is not set
758# CONFIG_RX is not set
759# CONFIG_SETSERIAL is not set
760# CONFIG_SETSID is not set
761CONFIG_STRINGS=y
762# CONFIG_TASKSET is not set
763# CONFIG_FEATURE_TASKSET_FANCY is not set
764# CONFIG_TIME is not set
765# CONFIG_TIMEOUT is not set
766# CONFIG_TTYSIZE is not set
767# CONFIG_UBIRENAME is not set
768# CONFIG_UBIATTACH is not set
769# CONFIG_UBIDETACH is not set
770# CONFIG_UBIMKVOL is not set
771# CONFIG_UBIRMVOL is not set
772# CONFIG_UBIRSVOL is not set
773# CONFIG_UBIUPDATEVOL is not set
774# CONFIG_VOLNAME is not set
775# CONFIG_WALL is not set
776# CONFIG_WATCHDOG is not set
777
778#
779# Networking Utilities
780#
781CONFIG_FEATURE_IPV6=y
782# CONFIG_FEATURE_UNIX_LOCAL is not set
783CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
784# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
785# CONFIG_ARP is not set
786# CONFIG_ARPING is not set
787# CONFIG_BRCTL is not set
788# CONFIG_FEATURE_BRCTL_FANCY is not set
789# CONFIG_FEATURE_BRCTL_SHOW is not set
790# CONFIG_DNSD is not set
791# CONFIG_ETHER_WAKE is not set
792# CONFIG_FTPD is not set
793# CONFIG_FEATURE_FTPD_WRITE is not set
794# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
795# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
796CONFIG_FTPGET=y
797CONFIG_FTPPUT=y
798CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
799# CONFIG_HOSTNAME is not set
800# CONFIG_DNSDOMAINNAME is not set
801# CONFIG_HTTPD is not set
802# CONFIG_FEATURE_HTTPD_RANGES is not set
803# CONFIG_FEATURE_HTTPD_SETUID is not set
804# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
805# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
806# CONFIG_FEATURE_HTTPD_CGI is not set
807# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
808# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
809# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
810# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
811# CONFIG_FEATURE_HTTPD_PROXY is not set
812# CONFIG_FEATURE_HTTPD_GZIP is not set
813# CONFIG_IFCONFIG is not set
814# CONFIG_FEATURE_IFCONFIG_STATUS is not set
815# CONFIG_FEATURE_IFCONFIG_SLIP is not set
816# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
817# CONFIG_FEATURE_IFCONFIG_HW is not set
818# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
819# CONFIG_IFENSLAVE is not set
820# CONFIG_IFPLUGD is not set
821# CONFIG_IFUP is not set
822# CONFIG_IFDOWN is not set
823CONFIG_IFUPDOWN_IFSTATE_PATH=""
824# CONFIG_FEATURE_IFUPDOWN_IP is not set
825# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set
826# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
827# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
828# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
829# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
830# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
831# CONFIG_INETD is not set
832# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
833# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
834# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
835# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
836# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
837# CONFIG_FEATURE_INETD_RPC is not set
838# CONFIG_IP is not set
839# CONFIG_FEATURE_IP_ADDRESS is not set
840# CONFIG_FEATURE_IP_LINK is not set
841# CONFIG_FEATURE_IP_ROUTE is not set
842CONFIG_FEATURE_IP_ROUTE_DIR=""
843# CONFIG_FEATURE_IP_TUNNEL is not set
844# CONFIG_FEATURE_IP_RULE is not set
845# CONFIG_FEATURE_IP_NEIGH is not set
846# CONFIG_FEATURE_IP_SHORT_FORMS is not set
847# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
848# CONFIG_IPADDR is not set
849# CONFIG_IPLINK is not set
850# CONFIG_IPROUTE is not set
851# CONFIG_IPTUNNEL is not set
852# CONFIG_IPRULE is not set
853# CONFIG_IPNEIGH is not set
854CONFIG_IPCALC=y
855CONFIG_FEATURE_IPCALC_FANCY=y
856CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
857# CONFIG_FAKEIDENTD is not set
858# CONFIG_NAMEIF is not set
859# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
860# CONFIG_NBDCLIENT is not set
861CONFIG_NC=y
862CONFIG_NC_SERVER=y
863# CONFIG_NC_EXTRA is not set
864# CONFIG_NC_110_COMPAT is not set
865# CONFIG_NETSTAT is not set
866# CONFIG_FEATURE_NETSTAT_WIDE is not set
867# CONFIG_FEATURE_NETSTAT_PRG is not set
868# CONFIG_NSLOOKUP is not set
869# CONFIG_NTPD is not set
870# CONFIG_FEATURE_NTPD_SERVER is not set
871# CONFIG_FEATURE_NTPD_CONF is not set
872# CONFIG_PING is not set
873# CONFIG_PING6 is not set
874# CONFIG_FEATURE_FANCY_PING is not set
875# CONFIG_PSCAN is not set
876# CONFIG_ROUTE is not set
877# CONFIG_SLATTACH is not set
878# CONFIG_TCPSVD is not set
879# CONFIG_UDPSVD is not set
880# CONFIG_TELNET is not set
881# CONFIG_FEATURE_TELNET_TTYPE is not set
882# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
883# CONFIG_TELNETD is not set
884# CONFIG_FEATURE_TELNETD_STANDALONE is not set
885# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
886# CONFIG_TFTP is not set
887# CONFIG_TFTPD is not set
888# CONFIG_FEATURE_TFTP_GET is not set
889# CONFIG_FEATURE_TFTP_PUT is not set
890# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
891# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
892# CONFIG_TFTP_DEBUG is not set
893# CONFIG_TRACEROUTE is not set
894# CONFIG_TRACEROUTE6 is not set
895# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
896# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
897# CONFIG_TUNCTL is not set
898# CONFIG_FEATURE_TUNCTL_UG is not set
899# CONFIG_VCONFIG is not set
900CONFIG_WGET=y
901# CONFIG_FEATURE_WGET_STATUSBAR is not set
902# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
903CONFIG_FEATURE_WGET_LONG_OPTIONS=y
904# CONFIG_FEATURE_WGET_TIMEOUT is not set
905# CONFIG_FEATURE_WGET_OPENSSL is not set
906# CONFIG_FEATURE_WGET_SSL_HELPER is not set
907CONFIG_WHOIS=y
908# CONFIG_ZCIP is not set
909# CONFIG_UDHCPC6 is not set
910# CONFIG_UDHCPD is not set
911# CONFIG_DHCPRELAY is not set
912# CONFIG_DUMPLEASES is not set
913# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
914# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
915CONFIG_DHCPD_LEASES_FILE=""
916# CONFIG_UDHCPC is not set
917# CONFIG_FEATURE_UDHCPC_ARPING is not set
918# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
919# CONFIG_FEATURE_UDHCP_PORT is not set
920CONFIG_UDHCP_DEBUG=0
921# CONFIG_FEATURE_UDHCP_RFC3397 is not set
922# CONFIG_FEATURE_UDHCP_8021Q is not set
923CONFIG_UDHCPC_DEFAULT_SCRIPT=""
924CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
925CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
926
927#
928# Print Utilities
929#
930# CONFIG_LPD is not set
931# CONFIG_LPR is not set
932# CONFIG_LPQ is not set
933
934#
935# Mail Utilities
936#
937# CONFIG_MAKEMIME is not set
938# CONFIG_POPMAILDIR is not set
939# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
940# CONFIG_REFORMIME is not set
941# CONFIG_FEATURE_REFORMIME_COMPAT is not set
942# CONFIG_SENDMAIL is not set
943CONFIG_FEATURE_MIME_CHARSET=""
944
945#
946# Process Utilities
947#
948# CONFIG_FREE is not set
949# CONFIG_FUSER is not set
950# CONFIG_IOSTAT is not set
951CONFIG_KILL=y
952CONFIG_KILLALL=y
953# CONFIG_KILLALL5 is not set
954# CONFIG_LSOF is not set
955# CONFIG_MPSTAT is not set
956# CONFIG_NMETER is not set
957CONFIG_PGREP=y
958# CONFIG_PKILL is not set
959CONFIG_PIDOF=y
960CONFIG_FEATURE_PIDOF_SINGLE=y
961CONFIG_FEATURE_PIDOF_OMIT=y
962# CONFIG_PMAP is not set
963# CONFIG_POWERTOP is not set
964CONFIG_PS=y
965# CONFIG_FEATURE_PS_WIDE is not set
966# CONFIG_FEATURE_PS_LONG is not set
967# CONFIG_FEATURE_PS_TIME is not set
968# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
969# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
970# CONFIG_PSTREE is not set
971# CONFIG_PWDX is not set
972# CONFIG_RENICE is not set
973# CONFIG_SMEMCAP is not set
974# CONFIG_BB_SYSCTL is not set
975# CONFIG_TOP is not set
976# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
977# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
978# CONFIG_FEATURE_TOP_SMP_CPU is not set
979# CONFIG_FEATURE_TOP_DECIMALS is not set
980# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
981# CONFIG_FEATURE_TOPMEM is not set
982# CONFIG_UPTIME is not set
983# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
984# CONFIG_WATCH is not set
985# CONFIG_FEATURE_SHOW_THREADS is not set
986
987#
988# Runit Utilities
989#
990# CONFIG_CHPST is not set
991# CONFIG_SETUIDGID is not set
992# CONFIG_ENVUIDGID is not set
993# CONFIG_ENVDIR is not set
994# CONFIG_SOFTLIMIT is not set
995# CONFIG_RUNSV is not set
996# CONFIG_RUNSVDIR is not set
997# CONFIG_FEATURE_RUNSVDIR_LOG is not set
998# CONFIG_SV is not set
999CONFIG_SV_DEFAULT_SERVICE_DIR=""
1000# CONFIG_SVC is not set
1001# CONFIG_SVLOGD is not set
1002# CONFIG_CHCON is not set
1003# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
1004# CONFIG_GETENFORCE is not set
1005# CONFIG_GETSEBOOL is not set
1006# CONFIG_LOAD_POLICY is not set
1007# CONFIG_MATCHPATHCON is not set
1008# CONFIG_RUNCON is not set
1009# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
1010# CONFIG_SELINUXENABLED is not set
1011# CONFIG_SESTATUS is not set
1012# CONFIG_SETENFORCE is not set
1013# CONFIG_SETFILES is not set
1014# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1015# CONFIG_RESTORECON is not set
1016# CONFIG_SETSEBOOL is not set
1017
1018#
1019# Shells
1020#
1021CONFIG_ASH=y
1022CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1023CONFIG_ASH_INTERNAL_GLOB=y
1024CONFIG_ASH_RANDOM_SUPPORT=y
1025CONFIG_ASH_EXPAND_PRMT=y
1026CONFIG_ASH_BASH_COMPAT=y
1027# CONFIG_ASH_IDLE_TIMEOUT is not set
1028# CONFIG_ASH_JOB_CONTROL is not set
1029CONFIG_ASH_ALIAS=y
1030CONFIG_ASH_GETOPTS=y
1031CONFIG_ASH_BUILTIN_ECHO=y
1032CONFIG_ASH_BUILTIN_PRINTF=y
1033CONFIG_ASH_BUILTIN_TEST=y
1034CONFIG_ASH_HELP=y
1035CONFIG_ASH_CMDCMD=y
1036# CONFIG_ASH_MAIL is not set
1037# CONFIG_CTTYHACK is not set
1038# CONFIG_HUSH is not set
1039# CONFIG_HUSH_BASH_COMPAT is not set
1040# CONFIG_HUSH_BRACE_EXPANSION is not set
1041# CONFIG_HUSH_HELP is not set
1042# CONFIG_HUSH_INTERACTIVE is not set
1043# CONFIG_HUSH_SAVEHISTORY is not set
1044# CONFIG_HUSH_JOB is not set
1045# CONFIG_HUSH_TICK is not set
1046# CONFIG_HUSH_IF is not set
1047# CONFIG_HUSH_LOOPS is not set
1048# CONFIG_HUSH_CASE is not set
1049# CONFIG_HUSH_FUNCTIONS is not set
1050# CONFIG_HUSH_LOCAL is not set
1051# CONFIG_HUSH_RANDOM_SUPPORT is not set
1052# CONFIG_HUSH_EXPORT_N is not set
1053# CONFIG_HUSH_MODE_X is not set
1054# CONFIG_MSH is not set
1055CONFIG_FEATURE_SH_IS_ASH=y
1056# CONFIG_FEATURE_SH_IS_HUSH is not set
1057# CONFIG_FEATURE_SH_IS_NONE is not set
1058CONFIG_FEATURE_BASH_IS_ASH=y
1059# CONFIG_FEATURE_BASH_IS_HUSH is not set
1060# CONFIG_FEATURE_BASH_IS_NONE is not set
1061CONFIG_SH_MATH_SUPPORT=y
1062CONFIG_SH_MATH_SUPPORT_64=y
1063CONFIG_FEATURE_SH_EXTRA_QUIET=y
1064CONFIG_FEATURE_SH_STANDALONE=y
1065CONFIG_FEATURE_SH_NOFORK=y
1066CONFIG_FEATURE_SH_HISTFILESIZE=y
1067
1068#
1069# System Logging Utilities
1070#
1071# CONFIG_KLOGD is not set
1072# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1073# CONFIG_LOGGER is not set
1074# CONFIG_LOGREAD is not set
1075# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1076# CONFIG_SYSLOGD is not set
1077# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1078# CONFIG_FEATURE_REMOTE_LOG is not set
1079# CONFIG_FEATURE_SYSLOGD_DUP is not set
1080# CONFIG_FEATURE_SYSLOGD_CFG is not set
1081CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1082# CONFIG_FEATURE_IPC_SYSLOG is not set
1083CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1084# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
new file mode 100644
index 000000000..558c07d56
--- /dev/null
+++ b/configs/mingw64_defconfig
@@ -0,0 +1,1084 @@
1#
2# Automatically generated make config: don't edit
3# Busybox version: 1.26.0.git
4# Tue Nov 29 11:42:12 2016
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
14CONFIG_EXTRA_COMPAT=y
15# CONFIG_INCLUDE_SUSv2 is not set
16CONFIG_USE_PORTABLE_CODE=y
17# CONFIG_PLATFORM_LINUX is not set
18CONFIG_SHOW_USAGE=y
19CONFIG_FEATURE_VERBOSE_USAGE=y
20CONFIG_FEATURE_COMPRESS_USAGE=y
21CONFIG_BUSYBOX=y
22CONFIG_FEATURE_INSTALLER=y
23# CONFIG_INSTALL_NO_USR is not set
24# CONFIG_PAM is not set
25CONFIG_LONG_OPTS=y
26# CONFIG_FEATURE_DEVPTS is not set
27# CONFIG_FEATURE_CLEAN_UP is not set
28# CONFIG_FEATURE_UTMP is not set
29# CONFIG_FEATURE_WTMP is not set
30# CONFIG_FEATURE_PIDFILE is not set
31CONFIG_PID_FILE_PATH=""
32# CONFIG_FEATURE_SUID is not set
33# CONFIG_FEATURE_SUID_CONFIG is not set
34# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
35# CONFIG_SELINUX is not set
36CONFIG_FEATURE_PREFER_APPLETS=y
37CONFIG_BUSYBOX_EXEC_PATH=""
38# CONFIG_FEATURE_SYSLOG is not set
39# CONFIG_FEATURE_HAVE_RPC 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
96# CONFIG_FEATURE_USE_TERMIOS is not set
97CONFIG_FEATURE_EDITING=y
98CONFIG_FEATURE_EDITING_MAX_LEN=1024
99CONFIG_FEATURE_EDITING_VI=y
100CONFIG_FEATURE_EDITING_HISTORY=255
101CONFIG_FEATURE_EDITING_SAVEHISTORY=y
102# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
103CONFIG_FEATURE_REVERSE_SEARCH=y
104CONFIG_FEATURE_TAB_COMPLETION=y
105CONFIG_FEATURE_USERNAME_COMPLETION=y
106CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
107# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
108# CONFIG_LOCALE_SUPPORT is not set
109# CONFIG_UNICODE_SUPPORT is not set
110# CONFIG_UNICODE_USING_LOCALE is not set
111# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
112CONFIG_SUBST_WCHAR=0
113CONFIG_LAST_SUPPORTED_WCHAR=0
114# CONFIG_UNICODE_COMBINING_WCHARS is not set
115# CONFIG_UNICODE_WIDE_WCHARS is not set
116# CONFIG_UNICODE_BIDI_SUPPORT is not set
117# CONFIG_UNICODE_NEUTRAL_TABLE is not set
118# CONFIG_UNICODE_PRESERVE_BROKEN is not set
119CONFIG_FEATURE_NON_POSIX_CP=y
120# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
121# CONFIG_FEATURE_USE_SENDFILE is not set
122CONFIG_FEATURE_COPYBUF_KB=4
123CONFIG_FEATURE_SKIP_ROOTFS=y
124# CONFIG_MONOTONIC_SYSCALL is not set
125CONFIG_IOCTL_HEX2STR_ERROR=y
126# CONFIG_FEATURE_HWIB is not set
127
128#
129# Applets
130#
131
132#
133# Archival Utilities
134#
135CONFIG_FEATURE_SEAMLESS_XZ=y
136CONFIG_FEATURE_SEAMLESS_LZMA=y
137CONFIG_FEATURE_SEAMLESS_BZ2=y
138CONFIG_FEATURE_SEAMLESS_GZ=y
139CONFIG_FEATURE_SEAMLESS_Z=y
140CONFIG_AR=y
141CONFIG_FEATURE_AR_LONG_FILENAMES=y
142CONFIG_FEATURE_AR_CREATE=y
143CONFIG_UNCOMPRESS=y
144CONFIG_GUNZIP=y
145CONFIG_ZCAT=y
146CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
147CONFIG_BUNZIP2=y
148CONFIG_BZCAT=y
149CONFIG_UNLZMA=y
150CONFIG_LZCAT=y
151CONFIG_LZMA=y
152CONFIG_FEATURE_LZMA_FAST=y
153CONFIG_UNXZ=y
154CONFIG_XZCAT=y
155CONFIG_XZ=y
156CONFIG_BZIP2=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_LZOP=y
167CONFIG_UNLZOP=y
168CONFIG_LZOPCAT=y
169# CONFIG_LZOP_COMPR_HIGH is not set
170CONFIG_RPM2CPIO=y
171# CONFIG_RPM is not set
172CONFIG_TAR=y
173CONFIG_FEATURE_TAR_CREATE=y
174CONFIG_FEATURE_TAR_AUTODETECT=y
175CONFIG_FEATURE_TAR_FROM=y
176CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
177# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
178CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
179CONFIG_FEATURE_TAR_LONG_OPTIONS=y
180# CONFIG_FEATURE_TAR_TO_COMMAND is not set
181# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
182CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
183# CONFIG_FEATURE_TAR_SELINUX is not set
184CONFIG_UNZIP=y
185
186#
187# Coreutils
188#
189CONFIG_BASENAME=y
190CONFIG_CAL=y
191CONFIG_CAT=y
192CONFIG_CATV=y
193# CONFIG_CHGRP is not set
194CONFIG_CHMOD=y
195# CONFIG_CHOWN is not set
196# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
197# CONFIG_CHROOT is not set
198CONFIG_CKSUM=y
199CONFIG_COMM=y
200CONFIG_CP=y
201CONFIG_FEATURE_CP_LONG_OPTIONS=y
202CONFIG_CUT=y
203CONFIG_DATE=y
204CONFIG_FEATURE_DATE_ISOFMT=y
205# CONFIG_FEATURE_DATE_NANO is not set
206CONFIG_FEATURE_DATE_COMPAT=y
207CONFIG_DD=y
208# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
209# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
210CONFIG_FEATURE_DD_IBS_OBS=y
211CONFIG_FEATURE_DD_STATUS=y
212CONFIG_DF=y
213# CONFIG_FEATURE_DF_FANCY is not set
214CONFIG_DIRNAME=y
215CONFIG_DOS2UNIX=y
216CONFIG_UNIX2DOS=y
217CONFIG_DU=y
218CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
219CONFIG_ECHO=y
220CONFIG_FEATURE_FANCY_ECHO=y
221CONFIG_ENV=y
222CONFIG_FEATURE_ENV_LONG_OPTIONS=y
223CONFIG_EXPAND=y
224CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
225CONFIG_UNEXPAND=y
226CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
227CONFIG_EXPR=y
228CONFIG_EXPR_MATH_SUPPORT_64=y
229CONFIG_FALSE=y
230CONFIG_FOLD=y
231# CONFIG_FSYNC is not set
232CONFIG_HEAD=y
233CONFIG_FEATURE_FANCY_HEAD=y
234# CONFIG_HOSTID is not set
235CONFIG_ID=y
236CONFIG_GROUPS=y
237# CONFIG_INSTALL is not set
238# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
239CONFIG_LN=y
240CONFIG_LOGNAME=y
241CONFIG_LS=y
242CONFIG_FEATURE_LS_FILETYPES=y
243CONFIG_FEATURE_LS_FOLLOWLINKS=y
244CONFIG_FEATURE_LS_RECURSIVE=y
245CONFIG_FEATURE_LS_SORTFILES=y
246CONFIG_FEATURE_LS_TIMESTAMPS=y
247CONFIG_FEATURE_LS_USERNAME=y
248CONFIG_FEATURE_LS_COLOR=y
249CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
250CONFIG_MD5SUM=y
251CONFIG_SHA1SUM=y
252CONFIG_SHA256SUM=y
253CONFIG_SHA512SUM=y
254CONFIG_SHA3SUM=y
255
256#
257# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
258#
259CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
260CONFIG_MKDIR=y
261CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
262# CONFIG_MKFIFO is not set
263# CONFIG_MKNOD is not set
264CONFIG_MV=y
265CONFIG_FEATURE_MV_LONG_OPTIONS=y
266# CONFIG_NICE is not set
267# CONFIG_NOHUP is not set
268CONFIG_OD=y
269CONFIG_PRINTENV=y
270CONFIG_PRINTF=y
271CONFIG_PWD=y
272# CONFIG_READLINK is not set
273# CONFIG_FEATURE_READLINK_FOLLOW is not set
274# CONFIG_REALPATH is not set
275CONFIG_RM=y
276CONFIG_RMDIR=y
277CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
278CONFIG_SEQ=y
279CONFIG_SHUF=y
280CONFIG_SLEEP=y
281CONFIG_FEATURE_FANCY_SLEEP=y
282# CONFIG_FEATURE_FLOAT_SLEEP is not set
283CONFIG_SORT=y
284CONFIG_FEATURE_SORT_BIG=y
285CONFIG_SPLIT=y
286CONFIG_FEATURE_SPLIT_FANCY=y
287CONFIG_STAT=y
288CONFIG_FEATURE_STAT_FORMAT=y
289CONFIG_FEATURE_STAT_FILESYSTEM=y
290# CONFIG_STTY is not set
291CONFIG_SUM=y
292# CONFIG_SYNC is not set
293# CONFIG_FEATURE_SYNC_FANCY is not set
294CONFIG_TAC=y
295CONFIG_TAIL=y
296CONFIG_FEATURE_FANCY_TAIL=y
297CONFIG_TEE=y
298CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
299CONFIG_TEST=y
300CONFIG_TEST1=y
301CONFIG_TEST2=y
302CONFIG_FEATURE_TEST_64=y
303CONFIG_TOUCH=y
304# CONFIG_FEATURE_TOUCH_NODEREF is not set
305CONFIG_FEATURE_TOUCH_SUSV3=y
306CONFIG_TR=y
307CONFIG_FEATURE_TR_CLASSES=y
308CONFIG_FEATURE_TR_EQUIV=y
309CONFIG_TRUE=y
310CONFIG_TRUNCATE=y
311# CONFIG_TTY is not set
312CONFIG_UNAME=y
313CONFIG_UNAME_OSNAME="MS/Windows"
314CONFIG_UNIQ=y
315CONFIG_UNLINK=y
316CONFIG_USLEEP=y
317CONFIG_UUDECODE=y
318CONFIG_BASE64=y
319CONFIG_UUENCODE=y
320CONFIG_WC=y
321CONFIG_FEATURE_WC_LARGE=y
322CONFIG_WHOAMI=y
323# CONFIG_WHO is not set
324# CONFIG_USERS is not set
325CONFIG_YES=y
326
327#
328# Common options
329#
330CONFIG_FEATURE_VERBOSE=y
331
332#
333# Common options for cp and mv
334#
335# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
336
337#
338# Common options for ls, more and telnet
339#
340CONFIG_FEATURE_AUTOWIDTH=y
341
342#
343# Common options for df, du, ls
344#
345CONFIG_FEATURE_HUMAN_READABLE=y
346
347#
348# Console Utilities
349#
350# CONFIG_CHVT is not set
351CONFIG_CLEAR=y
352# CONFIG_DEALLOCVT is not set
353# CONFIG_DUMPKMAP is not set
354# CONFIG_FGCONSOLE is not set
355# CONFIG_KBD_MODE is not set
356# CONFIG_LOADFONT is not set
357# CONFIG_SETFONT is not set
358# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
359CONFIG_DEFAULT_SETFONT_DIR=""
360# CONFIG_FEATURE_LOADFONT_PSF2 is not set
361# CONFIG_FEATURE_LOADFONT_RAW is not set
362# CONFIG_LOADKMAP is not set
363# CONFIG_OPENVT is not set
364# CONFIG_RESET is not set
365# CONFIG_RESIZE is not set
366# CONFIG_FEATURE_RESIZE_PRINT is not set
367# CONFIG_SETCONSOLE is not set
368# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
369# CONFIG_SETKEYCODES is not set
370# CONFIG_SETLOGCONS is not set
371# CONFIG_SHOWKEY is not set
372
373#
374# Debian Utilities
375#
376CONFIG_MKTEMP=y
377# CONFIG_PIPE_PROGRESS is not set
378# CONFIG_RUN_PARTS is not set
379# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
380# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
381# CONFIG_START_STOP_DAEMON is not set
382# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
383# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
384CONFIG_WHICH=y
385
386#
387# Editors
388#
389CONFIG_AWK=y
390CONFIG_FEATURE_AWK_LIBM=y
391CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
392CONFIG_CMP=y
393CONFIG_DIFF=y
394CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
395CONFIG_FEATURE_DIFF_DIR=y
396CONFIG_ED=y
397CONFIG_PATCH=y
398CONFIG_SED=y
399CONFIG_VI=y
400CONFIG_FEATURE_VI_MAX_LEN=4096
401CONFIG_FEATURE_VI_8BIT=y
402CONFIG_FEATURE_VI_COLON=y
403CONFIG_FEATURE_VI_YANKMARK=y
404CONFIG_FEATURE_VI_SEARCH=y
405# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
406# CONFIG_FEATURE_VI_USE_SIGNALS is not set
407CONFIG_FEATURE_VI_DOT_CMD=y
408CONFIG_FEATURE_VI_READONLY=y
409CONFIG_FEATURE_VI_SETOPTS=y
410CONFIG_FEATURE_VI_SET=y
411CONFIG_FEATURE_VI_WIN_RESIZE=y
412CONFIG_FEATURE_VI_ASK_TERMINAL=y
413CONFIG_FEATURE_VI_UNDO=y
414CONFIG_FEATURE_VI_UNDO_QUEUE=y
415CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
416CONFIG_FEATURE_ALLOW_EXEC=y
417
418#
419# Finding Utilities
420#
421CONFIG_FIND=y
422CONFIG_FEATURE_FIND_PRINT0=y
423CONFIG_FEATURE_FIND_MTIME=y
424CONFIG_FEATURE_FIND_MMIN=y
425CONFIG_FEATURE_FIND_PERM=y
426CONFIG_FEATURE_FIND_TYPE=y
427# CONFIG_FEATURE_FIND_XDEV is not set
428CONFIG_FEATURE_FIND_MAXDEPTH=y
429CONFIG_FEATURE_FIND_NEWER=y
430# CONFIG_FEATURE_FIND_INUM is not set
431# CONFIG_FEATURE_FIND_EXEC is not set
432# CONFIG_FEATURE_FIND_EXEC_PLUS is not set
433# CONFIG_FEATURE_FIND_USER is not set
434# CONFIG_FEATURE_FIND_GROUP is not set
435CONFIG_FEATURE_FIND_NOT=y
436CONFIG_FEATURE_FIND_DEPTH=y
437CONFIG_FEATURE_FIND_PAREN=y
438CONFIG_FEATURE_FIND_SIZE=y
439CONFIG_FEATURE_FIND_PRUNE=y
440CONFIG_FEATURE_FIND_DELETE=y
441CONFIG_FEATURE_FIND_PATH=y
442CONFIG_FEATURE_FIND_REGEX=y
443# CONFIG_FEATURE_FIND_CONTEXT is not set
444# CONFIG_FEATURE_FIND_LINKS is not set
445CONFIG_GREP=y
446CONFIG_EGREP=y
447CONFIG_FGREP=y
448CONFIG_FEATURE_GREP_CONTEXT=y
449CONFIG_XARGS=y
450CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
451CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
452CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
453CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
454CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
455
456#
457# Init Utilities
458#
459# CONFIG_BOOTCHARTD is not set
460# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
461# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
462# CONFIG_HALT is not set
463# CONFIG_POWEROFF is not set
464# CONFIG_REBOOT is not set
465# CONFIG_FEATURE_CALL_TELINIT is not set
466CONFIG_TELINIT_PATH=""
467# CONFIG_INIT is not set
468# CONFIG_LINUXRC is not set
469# CONFIG_FEATURE_USE_INITTAB is not set
470# CONFIG_FEATURE_KILL_REMOVED is not set
471CONFIG_FEATURE_KILL_DELAY=0
472# CONFIG_FEATURE_INIT_SCTTY is not set
473# CONFIG_FEATURE_INIT_SYSLOG is not set
474# CONFIG_FEATURE_EXTRA_QUIET is not set
475# CONFIG_FEATURE_INIT_COREDUMPS is not set
476CONFIG_INIT_TERMINAL_TYPE=""
477# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
478# CONFIG_MESG is not set
479# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
480
481#
482# Login/Password Management Utilities
483#
484# CONFIG_FEATURE_SHADOWPASSWDS is not set
485# CONFIG_USE_BB_PWD_GRP is not set
486# CONFIG_USE_BB_SHADOW is not set
487# CONFIG_USE_BB_CRYPT is not set
488# CONFIG_USE_BB_CRYPT_SHA is not set
489# CONFIG_ADDGROUP is not set
490# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
491# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
492# CONFIG_ADD_SHELL is not set
493# CONFIG_REMOVE_SHELL is not set
494# CONFIG_ADDUSER is not set
495# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
496# CONFIG_FEATURE_CHECK_NAMES is not set
497CONFIG_LAST_ID=0
498CONFIG_FIRST_SYSTEM_ID=0
499CONFIG_LAST_SYSTEM_ID=0
500# CONFIG_CHPASSWD is not set
501CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
502# CONFIG_CRYPTPW is not set
503# CONFIG_MKPASSWD is not set
504# CONFIG_DELUSER is not set
505# CONFIG_DELGROUP is not set
506# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
507# CONFIG_GETTY is not set
508# CONFIG_LOGIN is not set
509# CONFIG_LOGIN_SESSION_AS_CHILD is not set
510# CONFIG_LOGIN_SCRIPTS is not set
511# CONFIG_FEATURE_NOLOGIN is not set
512# CONFIG_FEATURE_SECURETTY is not set
513# CONFIG_PASSWD is not set
514# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
515# CONFIG_SU is not set
516# CONFIG_FEATURE_SU_SYSLOG is not set
517# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
518# CONFIG_SULOGIN is not set
519# CONFIG_VLOCK is not set
520
521#
522# Linux Ext2 FS Progs
523#
524# CONFIG_CHATTR is not set
525# CONFIG_FSCK is not set
526# CONFIG_LSATTR is not set
527# CONFIG_TUNE2FS is not set
528
529#
530# Linux Module Utilities
531#
532# CONFIG_DEPMOD is not set
533# CONFIG_INSMOD is not set
534# CONFIG_LSMOD is not set
535# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
536# CONFIG_MODINFO is not set
537# CONFIG_MODPROBE is not set
538# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
539# CONFIG_MODPROBE_SMALL is not set
540# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set
541# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
542# CONFIG_RMMOD is not set
543
544#
545# Options common to multiple modutils
546#
547# CONFIG_FEATURE_2_4_MODULES is not set
548# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
549# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
550# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
551# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
552# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
553# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
554# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
555# CONFIG_FEATURE_MODUTILS_ALIAS is not set
556# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
557CONFIG_DEFAULT_MODULES_DIR=""
558CONFIG_DEFAULT_DEPMOD_FILE=""
559
560#
561# Linux System Utilities
562#
563# CONFIG_ACPID is not set
564# CONFIG_FEATURE_ACPID_COMPAT is not set
565# CONFIG_BLKDISCARD is not set
566# CONFIG_BLKID is not set
567# CONFIG_FEATURE_BLKID_TYPE is not set
568# CONFIG_BLOCKDEV is not set
569# CONFIG_DMESG is not set
570# CONFIG_FEATURE_DMESG_PRETTY is not set
571# CONFIG_FATATTR is not set
572# CONFIG_FBSET is not set
573# CONFIG_FEATURE_FBSET_FANCY is not set
574# CONFIG_FEATURE_FBSET_READMODE is not set
575# CONFIG_FDFORMAT is not set
576# CONFIG_FDISK is not set
577# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
578# CONFIG_FEATURE_FDISK_WRITABLE is not set
579# CONFIG_FEATURE_AIX_LABEL is not set
580# CONFIG_FEATURE_SGI_LABEL is not set
581# CONFIG_FEATURE_SUN_LABEL is not set
582# CONFIG_FEATURE_OSF_LABEL is not set
583# CONFIG_FEATURE_GPT_LABEL is not set
584# CONFIG_FEATURE_FDISK_ADVANCED is not set
585# CONFIG_FINDFS is not set
586# CONFIG_FLOCK is not set
587# CONFIG_FDFLUSH is not set
588# CONFIG_FREERAMDISK is not set
589# CONFIG_FSCK_MINIX is not set
590# CONFIG_FSTRIM is not set
591CONFIG_GETOPT=y
592CONFIG_FEATURE_GETOPT_LONG=y
593CONFIG_HEXDUMP=y
594CONFIG_FEATURE_HEXDUMP_REVERSE=y
595CONFIG_HD=y
596# CONFIG_HWCLOCK is not set
597# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
598# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
599# CONFIG_IPCRM is not set
600# CONFIG_IPCS is not set
601# CONFIG_LOSETUP is not set
602# CONFIG_LSPCI is not set
603# CONFIG_LSUSB is not set
604# CONFIG_MDEV is not set
605# CONFIG_FEATURE_MDEV_CONF is not set
606# CONFIG_FEATURE_MDEV_RENAME is not set
607# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
608# CONFIG_FEATURE_MDEV_EXEC is not set
609# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
610# CONFIG_MKE2FS is not set
611# CONFIG_MKFS_EXT2 is not set
612# CONFIG_MKFS_MINIX is not set
613# CONFIG_FEATURE_MINIX2 is not set
614# CONFIG_MKFS_REISER is not set
615# CONFIG_MKDOSFS is not set
616# CONFIG_MKFS_VFAT is not set
617# CONFIG_MKSWAP is not set
618# CONFIG_FEATURE_MKSWAP_UUID is not set
619# CONFIG_MORE is not set
620# CONFIG_MOUNT is not set
621# CONFIG_FEATURE_MOUNT_FAKE is not set
622# CONFIG_FEATURE_MOUNT_VERBOSE is not set
623# CONFIG_FEATURE_MOUNT_HELPERS is not set
624# CONFIG_FEATURE_MOUNT_LABEL is not set
625# CONFIG_FEATURE_MOUNT_NFS is not set
626# CONFIG_FEATURE_MOUNT_CIFS is not set
627# CONFIG_FEATURE_MOUNT_FLAGS is not set
628# CONFIG_FEATURE_MOUNT_FSTAB is not set
629# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
630# CONFIG_NSENTER is not set
631# CONFIG_FEATURE_NSENTER_LONG_OPTS is not set
632# CONFIG_PIVOT_ROOT is not set
633# CONFIG_RDATE is not set
634# CONFIG_RDEV is not set
635# CONFIG_READPROFILE is not set
636CONFIG_REV=y
637# CONFIG_RTCWAKE is not set
638# CONFIG_SCRIPT is not set
639# CONFIG_SCRIPTREPLAY is not set
640# CONFIG_SETARCH is not set
641# CONFIG_LINUX32 is not set
642# CONFIG_LINUX64 is not set
643# CONFIG_SWAPON is not set
644# CONFIG_FEATURE_SWAPON_DISCARD is not set
645# CONFIG_FEATURE_SWAPON_PRI is not set
646# CONFIG_SWAPOFF is not set
647# CONFIG_SWITCH_ROOT is not set
648# CONFIG_UEVENT is not set
649# CONFIG_UMOUNT is not set
650# CONFIG_FEATURE_UMOUNT_ALL is not set
651# CONFIG_UNSHARE is not set
652# CONFIG_FEATURE_MOUNT_LOOP is not set
653# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
654# CONFIG_FEATURE_MTAB_SUPPORT is not set
655# CONFIG_VOLUMEID is not set
656# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
657# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
658# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
659# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
660# CONFIG_FEATURE_VOLUMEID_EXT is not set
661# CONFIG_FEATURE_VOLUMEID_F2FS is not set
662# CONFIG_FEATURE_VOLUMEID_FAT is not set
663# CONFIG_FEATURE_VOLUMEID_HFS is not set
664# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
665# CONFIG_FEATURE_VOLUMEID_JFS is not set
666# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
667# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
668# CONFIG_FEATURE_VOLUMEID_LUKS is not set
669# CONFIG_FEATURE_VOLUMEID_NILFS is not set
670# CONFIG_FEATURE_VOLUMEID_NTFS is not set
671# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
672# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
673# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
674# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
675# CONFIG_FEATURE_VOLUMEID_SYSV is not set
676# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
677# CONFIG_FEATURE_VOLUMEID_UDF is not set
678# CONFIG_FEATURE_VOLUMEID_XFS is not set
679
680#
681# Miscellaneous Utilities
682#
683# CONFIG_ADJTIMEX is not set
684# CONFIG_BBCONFIG is not set
685# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
686# CONFIG_BEEP is not set
687CONFIG_FEATURE_BEEP_FREQ=0
688CONFIG_FEATURE_BEEP_LENGTH_MS=0
689# CONFIG_CHAT is not set
690# CONFIG_FEATURE_CHAT_NOFAIL is not set
691# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
692# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
693# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
694# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
695# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
696# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
697# CONFIG_CHRT is not set
698# CONFIG_CONSPY is not set
699# CONFIG_CROND is not set
700# CONFIG_FEATURE_CROND_D is not set
701# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
702CONFIG_FEATURE_CROND_DIR=""
703# CONFIG_CRONTAB is not set
704CONFIG_DC=y
705CONFIG_FEATURE_DC_LIBM=y
706# CONFIG_DEVFSD is not set
707# CONFIG_DEVFSD_MODLOAD is not set
708# CONFIG_DEVFSD_FG_NP is not set
709# CONFIG_DEVFSD_VERBOSE is not set
710# CONFIG_FEATURE_DEVFS is not set
711# CONFIG_DEVMEM is not set
712# CONFIG_EJECT is not set
713# CONFIG_FEATURE_EJECT_SCSI is not set
714# CONFIG_FBSPLASH is not set
715# CONFIG_FLASHCP is not set
716# CONFIG_FLASH_ERASEALL is not set
717# CONFIG_FLASH_LOCK is not set
718# CONFIG_FLASH_UNLOCK is not set
719# CONFIG_HDPARM is not set
720# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
721# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
722# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
723# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
724# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
725# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
726# CONFIG_I2CGET is not set
727# CONFIG_I2CSET is not set
728# CONFIG_I2CDUMP is not set
729# CONFIG_I2CDETECT is not set
730# CONFIG_INOTIFYD is not set
731# CONFIG_IONICE is not set
732# CONFIG_LAST is not set
733# CONFIG_FEATURE_LAST_FANCY is not set
734CONFIG_LESS=y
735CONFIG_FEATURE_LESS_MAXLINES=9999999
736CONFIG_FEATURE_LESS_BRACKETS=y
737CONFIG_FEATURE_LESS_FLAGS=y
738CONFIG_FEATURE_LESS_TRUNCATE=y
739CONFIG_FEATURE_LESS_MARKS=y
740CONFIG_FEATURE_LESS_REGEXP=y
741# CONFIG_FEATURE_LESS_WINCH is not set
742# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
743CONFIG_FEATURE_LESS_DASHCMD=y
744CONFIG_FEATURE_LESS_LINENUMS=y
745# CONFIG_MAKEDEVS is not set
746# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
747# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
748CONFIG_MAN=y
749# CONFIG_MICROCOM is not set
750# CONFIG_MOUNTPOINT is not set
751# CONFIG_MT is not set
752# CONFIG_NANDWRITE is not set
753# CONFIG_NANDDUMP is not set
754# CONFIG_RAIDAUTORUN is not set
755# CONFIG_READAHEAD is not set
756# CONFIG_RFKILL is not set
757# CONFIG_RUNLEVEL is not set
758# CONFIG_RX is not set
759# CONFIG_SETSERIAL is not set
760# CONFIG_SETSID is not set
761CONFIG_STRINGS=y
762# CONFIG_TASKSET is not set
763# CONFIG_FEATURE_TASKSET_FANCY is not set
764# CONFIG_TIME is not set
765# CONFIG_TIMEOUT is not set
766# CONFIG_TTYSIZE is not set
767# CONFIG_UBIRENAME is not set
768# CONFIG_UBIATTACH is not set
769# CONFIG_UBIDETACH is not set
770# CONFIG_UBIMKVOL is not set
771# CONFIG_UBIRMVOL is not set
772# CONFIG_UBIRSVOL is not set
773# CONFIG_UBIUPDATEVOL is not set
774# CONFIG_VOLNAME is not set
775# CONFIG_WALL is not set
776# CONFIG_WATCHDOG is not set
777
778#
779# Networking Utilities
780#
781CONFIG_FEATURE_IPV6=y
782# CONFIG_FEATURE_UNIX_LOCAL is not set
783CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
784# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
785# CONFIG_ARP is not set
786# CONFIG_ARPING is not set
787# CONFIG_BRCTL is not set
788# CONFIG_FEATURE_BRCTL_FANCY is not set
789# CONFIG_FEATURE_BRCTL_SHOW is not set
790# CONFIG_DNSD is not set
791# CONFIG_ETHER_WAKE is not set
792# CONFIG_FTPD is not set
793# CONFIG_FEATURE_FTPD_WRITE is not set
794# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
795# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
796CONFIG_FTPGET=y
797CONFIG_FTPPUT=y
798CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
799# CONFIG_HOSTNAME is not set
800# CONFIG_DNSDOMAINNAME is not set
801# CONFIG_HTTPD is not set
802# CONFIG_FEATURE_HTTPD_RANGES is not set
803# CONFIG_FEATURE_HTTPD_SETUID is not set
804# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
805# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
806# CONFIG_FEATURE_HTTPD_CGI is not set
807# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
808# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
809# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
810# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
811# CONFIG_FEATURE_HTTPD_PROXY is not set
812# CONFIG_FEATURE_HTTPD_GZIP is not set
813# CONFIG_IFCONFIG is not set
814# CONFIG_FEATURE_IFCONFIG_STATUS is not set
815# CONFIG_FEATURE_IFCONFIG_SLIP is not set
816# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
817# CONFIG_FEATURE_IFCONFIG_HW is not set
818# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
819# CONFIG_IFENSLAVE is not set
820# CONFIG_IFPLUGD is not set
821# CONFIG_IFUP is not set
822# CONFIG_IFDOWN is not set
823CONFIG_IFUPDOWN_IFSTATE_PATH=""
824# CONFIG_FEATURE_IFUPDOWN_IP is not set
825# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set
826# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
827# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
828# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
829# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
830# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
831# CONFIG_INETD is not set
832# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
833# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
834# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
835# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
836# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
837# CONFIG_FEATURE_INETD_RPC is not set
838# CONFIG_IP is not set
839# CONFIG_FEATURE_IP_ADDRESS is not set
840# CONFIG_FEATURE_IP_LINK is not set
841# CONFIG_FEATURE_IP_ROUTE is not set
842CONFIG_FEATURE_IP_ROUTE_DIR=""
843# CONFIG_FEATURE_IP_TUNNEL is not set
844# CONFIG_FEATURE_IP_RULE is not set
845# CONFIG_FEATURE_IP_NEIGH is not set
846# CONFIG_FEATURE_IP_SHORT_FORMS is not set
847# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
848# CONFIG_IPADDR is not set
849# CONFIG_IPLINK is not set
850# CONFIG_IPROUTE is not set
851# CONFIG_IPTUNNEL is not set
852# CONFIG_IPRULE is not set
853# CONFIG_IPNEIGH is not set
854CONFIG_IPCALC=y
855CONFIG_FEATURE_IPCALC_FANCY=y
856CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y
857# CONFIG_FAKEIDENTD is not set
858# CONFIG_NAMEIF is not set
859# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
860# CONFIG_NBDCLIENT is not set
861CONFIG_NC=y
862CONFIG_NC_SERVER=y
863# CONFIG_NC_EXTRA is not set
864# CONFIG_NC_110_COMPAT is not set
865# CONFIG_NETSTAT is not set
866# CONFIG_FEATURE_NETSTAT_WIDE is not set
867# CONFIG_FEATURE_NETSTAT_PRG is not set
868# CONFIG_NSLOOKUP is not set
869# CONFIG_NTPD is not set
870# CONFIG_FEATURE_NTPD_SERVER is not set
871# CONFIG_FEATURE_NTPD_CONF is not set
872# CONFIG_PING is not set
873# CONFIG_PING6 is not set
874# CONFIG_FEATURE_FANCY_PING is not set
875# CONFIG_PSCAN is not set
876# CONFIG_ROUTE is not set
877# CONFIG_SLATTACH is not set
878# CONFIG_TCPSVD is not set
879# CONFIG_UDPSVD is not set
880# CONFIG_TELNET is not set
881# CONFIG_FEATURE_TELNET_TTYPE is not set
882# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
883# CONFIG_TELNETD is not set
884# CONFIG_FEATURE_TELNETD_STANDALONE is not set
885# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
886# CONFIG_TFTP is not set
887# CONFIG_TFTPD is not set
888# CONFIG_FEATURE_TFTP_GET is not set
889# CONFIG_FEATURE_TFTP_PUT is not set
890# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
891# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
892# CONFIG_TFTP_DEBUG is not set
893# CONFIG_TRACEROUTE is not set
894# CONFIG_TRACEROUTE6 is not set
895# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
896# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
897# CONFIG_TUNCTL is not set
898# CONFIG_FEATURE_TUNCTL_UG is not set
899# CONFIG_VCONFIG is not set
900CONFIG_WGET=y
901# CONFIG_FEATURE_WGET_STATUSBAR is not set
902# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
903CONFIG_FEATURE_WGET_LONG_OPTIONS=y
904# CONFIG_FEATURE_WGET_TIMEOUT is not set
905# CONFIG_FEATURE_WGET_OPENSSL is not set
906# CONFIG_FEATURE_WGET_SSL_HELPER is not set
907CONFIG_WHOIS=y
908# CONFIG_ZCIP is not set
909# CONFIG_UDHCPC6 is not set
910# CONFIG_UDHCPD is not set
911# CONFIG_DHCPRELAY is not set
912# CONFIG_DUMPLEASES is not set
913# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
914# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
915CONFIG_DHCPD_LEASES_FILE=""
916# CONFIG_UDHCPC is not set
917# CONFIG_FEATURE_UDHCPC_ARPING is not set
918# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
919# CONFIG_FEATURE_UDHCP_PORT is not set
920CONFIG_UDHCP_DEBUG=0
921# CONFIG_FEATURE_UDHCP_RFC3397 is not set
922# CONFIG_FEATURE_UDHCP_8021Q is not set
923CONFIG_UDHCPC_DEFAULT_SCRIPT=""
924CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
925CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
926
927#
928# Print Utilities
929#
930# CONFIG_LPD is not set
931# CONFIG_LPR is not set
932# CONFIG_LPQ is not set
933
934#
935# Mail Utilities
936#
937# CONFIG_MAKEMIME is not set
938# CONFIG_POPMAILDIR is not set
939# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
940# CONFIG_REFORMIME is not set
941# CONFIG_FEATURE_REFORMIME_COMPAT is not set
942# CONFIG_SENDMAIL is not set
943CONFIG_FEATURE_MIME_CHARSET=""
944
945#
946# Process Utilities
947#
948# CONFIG_FREE is not set
949# CONFIG_FUSER is not set
950# CONFIG_IOSTAT is not set
951CONFIG_KILL=y
952CONFIG_KILLALL=y
953# CONFIG_KILLALL5 is not set
954# CONFIG_LSOF is not set
955# CONFIG_MPSTAT is not set
956# CONFIG_NMETER is not set
957CONFIG_PGREP=y
958# CONFIG_PKILL is not set
959CONFIG_PIDOF=y
960CONFIG_FEATURE_PIDOF_SINGLE=y
961CONFIG_FEATURE_PIDOF_OMIT=y
962# CONFIG_PMAP is not set
963# CONFIG_POWERTOP is not set
964CONFIG_PS=y
965# CONFIG_FEATURE_PS_WIDE is not set
966# CONFIG_FEATURE_PS_LONG is not set
967# CONFIG_FEATURE_PS_TIME is not set
968# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
969# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
970# CONFIG_PSTREE is not set
971# CONFIG_PWDX is not set
972# CONFIG_RENICE is not set
973# CONFIG_SMEMCAP is not set
974# CONFIG_BB_SYSCTL is not set
975# CONFIG_TOP is not set
976# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set
977# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set
978# CONFIG_FEATURE_TOP_SMP_CPU is not set
979# CONFIG_FEATURE_TOP_DECIMALS is not set
980# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
981# CONFIG_FEATURE_TOPMEM is not set
982# CONFIG_UPTIME is not set
983# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
984# CONFIG_WATCH is not set
985# CONFIG_FEATURE_SHOW_THREADS is not set
986
987#
988# Runit Utilities
989#
990# CONFIG_CHPST is not set
991# CONFIG_SETUIDGID is not set
992# CONFIG_ENVUIDGID is not set
993# CONFIG_ENVDIR is not set
994# CONFIG_SOFTLIMIT is not set
995# CONFIG_RUNSV is not set
996# CONFIG_RUNSVDIR is not set
997# CONFIG_FEATURE_RUNSVDIR_LOG is not set
998# CONFIG_SV is not set
999CONFIG_SV_DEFAULT_SERVICE_DIR=""
1000# CONFIG_SVC is not set
1001# CONFIG_SVLOGD is not set
1002# CONFIG_CHCON is not set
1003# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
1004# CONFIG_GETENFORCE is not set
1005# CONFIG_GETSEBOOL is not set
1006# CONFIG_LOAD_POLICY is not set
1007# CONFIG_MATCHPATHCON is not set
1008# CONFIG_RUNCON is not set
1009# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
1010# CONFIG_SELINUXENABLED is not set
1011# CONFIG_SESTATUS is not set
1012# CONFIG_SETENFORCE is not set
1013# CONFIG_SETFILES is not set
1014# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
1015# CONFIG_RESTORECON is not set
1016# CONFIG_SETSEBOOL is not set
1017
1018#
1019# Shells
1020#
1021CONFIG_ASH=y
1022CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
1023CONFIG_ASH_INTERNAL_GLOB=y
1024CONFIG_ASH_RANDOM_SUPPORT=y
1025CONFIG_ASH_EXPAND_PRMT=y
1026CONFIG_ASH_BASH_COMPAT=y
1027# CONFIG_ASH_IDLE_TIMEOUT is not set
1028# CONFIG_ASH_JOB_CONTROL is not set
1029CONFIG_ASH_ALIAS=y
1030CONFIG_ASH_GETOPTS=y
1031CONFIG_ASH_BUILTIN_ECHO=y
1032CONFIG_ASH_BUILTIN_PRINTF=y
1033CONFIG_ASH_BUILTIN_TEST=y
1034CONFIG_ASH_HELP=y
1035CONFIG_ASH_CMDCMD=y
1036# CONFIG_ASH_MAIL is not set
1037# CONFIG_CTTYHACK is not set
1038# CONFIG_HUSH is not set
1039# CONFIG_HUSH_BASH_COMPAT is not set
1040# CONFIG_HUSH_BRACE_EXPANSION is not set
1041# CONFIG_HUSH_HELP is not set
1042# CONFIG_HUSH_INTERACTIVE is not set
1043# CONFIG_HUSH_SAVEHISTORY is not set
1044# CONFIG_HUSH_JOB is not set
1045# CONFIG_HUSH_TICK is not set
1046# CONFIG_HUSH_IF is not set
1047# CONFIG_HUSH_LOOPS is not set
1048# CONFIG_HUSH_CASE is not set
1049# CONFIG_HUSH_FUNCTIONS is not set
1050# CONFIG_HUSH_LOCAL is not set
1051# CONFIG_HUSH_RANDOM_SUPPORT is not set
1052# CONFIG_HUSH_EXPORT_N is not set
1053# CONFIG_HUSH_MODE_X is not set
1054# CONFIG_MSH is not set
1055CONFIG_FEATURE_SH_IS_ASH=y
1056# CONFIG_FEATURE_SH_IS_HUSH is not set
1057# CONFIG_FEATURE_SH_IS_NONE is not set
1058CONFIG_FEATURE_BASH_IS_ASH=y
1059# CONFIG_FEATURE_BASH_IS_HUSH is not set
1060# CONFIG_FEATURE_BASH_IS_NONE is not set
1061CONFIG_SH_MATH_SUPPORT=y
1062CONFIG_SH_MATH_SUPPORT_64=y
1063CONFIG_FEATURE_SH_EXTRA_QUIET=y
1064CONFIG_FEATURE_SH_STANDALONE=y
1065CONFIG_FEATURE_SH_NOFORK=y
1066CONFIG_FEATURE_SH_HISTFILESIZE=y
1067
1068#
1069# System Logging Utilities
1070#
1071# CONFIG_KLOGD is not set
1072# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
1073# CONFIG_LOGGER is not set
1074# CONFIG_LOGREAD is not set
1075# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
1076# CONFIG_SYSLOGD is not set
1077# CONFIG_FEATURE_ROTATE_LOGFILE is not set
1078# CONFIG_FEATURE_REMOTE_LOG is not set
1079# CONFIG_FEATURE_SYSLOGD_DUP is not set
1080# CONFIG_FEATURE_SYSLOGD_CFG is not set
1081CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
1082# CONFIG_FEATURE_IPC_SYSLOG is not set
1083CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
1084# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 3d1ba2ee6..8c144cfd2 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -294,6 +294,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
294#endif 294#endif
295 }; 295 };
296 smallint exitcode = EXIT_FAILURE; 296 smallint exitcode = EXIT_FAILURE;
297 int devzero = 0;
297 int i; 298 int i;
298 size_t ibs = 512; 299 size_t ibs = 512;
299 char *ibuf; 300 char *ibuf;
@@ -420,7 +421,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
420#endif 421#endif
421 422
422 if (infile) { 423 if (infile) {
423 xmove_fd(xopen(infile, O_RDONLY), ifd); 424 if (ENABLE_PLATFORM_MINGW32 && !strcmp(infile, "/dev/zero")) {
425 G.flags |= FLAG_NOERROR;
426 devzero = 1;
427 } else {
428 xmove_fd(xopen(infile, O_RDONLY), ifd);
429 }
424 } else { 430 } else {
425 infile = bb_msg_standard_input; 431 infile = bb_msg_standard_input;
426 } 432 }
@@ -447,7 +453,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
447 } else { 453 } else {
448 outfile = bb_msg_standard_output; 454 outfile = bb_msg_standard_output;
449 } 455 }
450 if (skip) { 456 if (skip && !devzero) {
451 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; 457 size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs;
452 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { 458 if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) {
453 do { 459 do {
@@ -467,7 +473,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
467 while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { 473 while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
468 ssize_t n; 474 ssize_t n;
469 475
470 n = safe_read(ifd, ibuf, ibs); 476 if (devzero) {
477 memset(ibuf, 0, ibs);
478 n = ibs;
479 }
480 else
481 n = safe_read(ifd, ibuf, ibs);
471 if (n == 0) 482 if (n == 0)
472 break; 483 break;
473 if (n < 0) { 484 if (n < 0) {
@@ -543,7 +554,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
543 if (write_and_stats(obuf, oc, obs, outfile)) 554 if (write_and_stats(obuf, oc, obs, outfile))
544 goto out_status; 555 goto out_status;
545 } 556 }
546 if (close(ifd) < 0) { 557
558 if (!devzero && close(ifd) < 0) {
547 die_infile: 559 die_infile:
548 bb_simple_perror_msg_and_die(infile); 560 bb_simple_perror_msg_and_die(infile);
549 } 561 }
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/test.c b/coreutils/test.c
index 288f66508..67fdfde4f 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -657,6 +657,21 @@ static int filstat(char *nm, enum token mode)
657 return 0; 657 return 0;
658 } 658 }
659 659
660#if ENABLE_PLATFORM_MINGW32
661 if (mode == FILEX) {
662 char *p;
663
664 if (file_is_executable(nm)) {
665 return 1;
666 }
667 else if ((p=file_is_win32_executable(nm))) {
668 free(p);
669 return 1;
670 }
671 return 0;
672 }
673#endif
674
660 if (stat(nm, &s) != 0) 675 if (stat(nm, &s) != 0)
661 return 0; 676 return 0;
662 if (mode == FILEXIST) 677 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..84ba125cd 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++;
diff --git a/editors/diff.c b/editors/diff.c
index 75229ad8c..0ae7e20b3 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -724,6 +724,10 @@ static int diffreg(char *file[2])
724 FILE *fp[2]; 724 FILE *fp[2];
725 bool binary = false, differ = false; 725 bool binary = false, differ = false;
726 int status = STATUS_SAME, i; 726 int status = STATUS_SAME, i;
727#if ENABLE_PLATFORM_MINGW32
728 char *tmpfile[2] = { NULL, NULL };
729 char *tmpdir;
730#endif
727 731
728 fp[0] = stdin; 732 fp[0] = stdin;
729 fp[1] = stdin; 733 fp[1] = stdin;
@@ -735,10 +739,19 @@ static int diffreg(char *file[2])
735 * When we meet non-seekable file, we must make a temp copy. 739 * When we meet non-seekable file, we must make a temp copy.
736 */ 740 */
737 if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) { 741 if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) {
742#if !ENABLE_PLATFORM_MINGW32
738 char name[] = "/tmp/difXXXXXX"; 743 char name[] = "/tmp/difXXXXXX";
739 int fd_tmp = xmkstemp(name); 744 int fd_tmp = xmkstemp(name);
740 745
741 unlink(name); 746 unlink(name);
747#else
748 int fd_tmp;
749
750 if (!(tmpdir=getenv("TMPDIR")))
751 goto out;
752 tmpfile[i] = xasprintf("%s/difXXXXXX", tmpdir);
753 fd_tmp = xmkstemp(tmpfile[i]);
754#endif
742 if (bb_copyfd_eof(fd, fd_tmp) < 0) 755 if (bb_copyfd_eof(fd, fd_tmp) < 0)
743 xfunc_die(); 756 xfunc_die();
744 if (fd != STDIN_FILENO) 757 if (fd != STDIN_FILENO)
@@ -781,6 +794,14 @@ static int diffreg(char *file[2])
781out: 794out:
782 fclose_if_not_stdin(fp[0]); 795 fclose_if_not_stdin(fp[0]);
783 fclose_if_not_stdin(fp[1]); 796 fclose_if_not_stdin(fp[1]);
797#if ENABLE_PLATFORM_MINGW32
798 for (i = 0; i < 2; i++) {
799 if (tmpfile[i]) {
800 unlink(tmpfile[i]);
801 free(tmpfile[i]);
802 }
803 }
804#endif
784 805
785 return status; 806 return status;
786} 807}
diff --git a/editors/sed.c b/editors/sed.c
index 637a6851b..86230ea42 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 38a4692fd..b81f2b92d 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -2801,6 +2801,14 @@ static void catch_sig(int sig)
2801 2801
2802static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready 2802static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
2803{ 2803{
2804#if ENABLE_PLATFORM_MINGW32
2805 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
2806 DWORD ret;
2807
2808 fflush(stdout);
2809 ret = WaitForSingleObject(h, hund*10);
2810 return ret != WAIT_TIMEOUT;
2811#else
2804 struct pollfd pfd[1]; 2812 struct pollfd pfd[1];
2805 2813
2806 if (hund != 0) 2814 if (hund != 0)
@@ -2809,6 +2817,7 @@ static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
2809 pfd[0].fd = STDIN_FILENO; 2817 pfd[0].fd = STDIN_FILENO;
2810 pfd[0].events = POLLIN; 2818 pfd[0].events = POLLIN;
2811 return safe_poll(pfd, 1, hund*10) > 0; 2819 return safe_poll(pfd, 1, hund*10) > 0;
2820#endif
2812} 2821}
2813 2822
2814//----- IO Routines -------------------------------------------- 2823//----- IO Routines --------------------------------------------
@@ -2930,6 +2939,9 @@ static int file_insert(const char *fn, char *p, int initial)
2930 status_line_bold("'%s' is not a regular file", fn); 2939 status_line_bold("'%s' is not a regular file", fn);
2931 goto fi; 2940 goto fi;
2932 } 2941 }
2942#if ENABLE_PLATFORM_MINGW32
2943 _setmode(fd, _O_TEXT);
2944#endif
2933 size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX); 2945 size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX);
2934 p += text_hole_make(p, size); 2946 p += text_hole_make(p, size);
2935 cnt = full_read(fd, p, size); 2947 cnt = full_read(fd, p, size);
@@ -2938,8 +2950,25 @@ static int file_insert(const char *fn, char *p, int initial)
2938 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert 2950 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert
2939 } else if (cnt < size) { 2951 } else if (cnt < size) {
2940 // There was a partial read, shrink unused space 2952 // There was a partial read, shrink unused space
2953#if ENABLE_PLATFORM_MINGW32
2954 int i, newline;
2955
2956 newline = 0;
2957 for ( i=0; i<cnt; ++i ) {
2958 if ( p[i] == '\n' ) {
2959 ++newline;
2960 }
2961 }
2962#endif
2941 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO); 2963 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO);
2964#if ENABLE_PLATFORM_MINGW32
2965 // on WIN32 a partial read might just mean CRs have been removed
2966 if ( cnt+newline != size ) {
2967 status_line_bold("can't read '%s'", fn);
2968 }
2969#else
2942 status_line_bold("can't read '%s'", fn); 2970 status_line_bold("can't read '%s'", fn);
2971#endif
2943 } 2972 }
2944 fi: 2973 fi:
2945 close(fd); 2974 close(fd);
@@ -2961,6 +2990,9 @@ static int file_insert(const char *fn, char *p, int initial)
2961static int file_write(char *fn, char *first, char *last) 2990static int file_write(char *fn, char *first, char *last)
2962{ 2991{
2963 int fd, cnt, charcnt; 2992 int fd, cnt, charcnt;
2993#if ENABLE_PLATFORM_MINGW32
2994 int i, newline;
2995#endif
2964 2996
2965 if (fn == 0) { 2997 if (fn == 0) {
2966 status_line_bold("No current filename"); 2998 status_line_bold("No current filename");
@@ -2974,8 +3006,23 @@ static int file_write(char *fn, char *first, char *last)
2974 if (fd < 0) 3006 if (fd < 0)
2975 return -1; 3007 return -1;
2976 cnt = last - first + 1; 3008 cnt = last - first + 1;
3009#if ENABLE_PLATFORM_MINGW32
3010 /* write file in text mode; this makes it bigger so adjust
3011 * the truncation to match
3012 */
3013 _setmode(fd, _O_TEXT);
3014 newline = 0;
3015 for ( i=0; i<cnt; ++i ) {
3016 if ( first[i] == '\n' ) {
3017 ++newline;
3018 }
3019 }
3020 charcnt = full_write(fd, first, cnt);
3021 ftruncate(fd, charcnt+newline);
3022#else
2977 charcnt = full_write(fd, first, cnt); 3023 charcnt = full_write(fd, first, cnt);
2978 ftruncate(fd, charcnt); 3024 ftruncate(fd, charcnt);
3025#endif
2979 if (charcnt == cnt) { 3026 if (charcnt == cnt) {
2980 // good write 3027 // good write
2981 //modified_count = FALSE; 3028 //modified_count = FALSE;
@@ -3026,7 +3073,12 @@ static void go_bottom_and_clear_to_eol(void)
3026//----- Erase from cursor to end of screen ----------------------- 3073//----- Erase from cursor to end of screen -----------------------
3027static void clear_to_eos(void) 3074static void clear_to_eos(void)
3028{ 3075{
3076#if !ENABLE_PLATFORM_MINGW32
3029 write1(ESC_CLEAR2EOS); 3077 write1(ESC_CLEAR2EOS);
3078#else
3079 /* in practice clear_to_eos() always clears the entire screen */
3080 reset_screen();
3081#endif
3030} 3082}
3031 3083
3032//----- Start standout mode ------------------------------------ 3084//----- Start standout mode ------------------------------------
@@ -3572,12 +3624,7 @@ static void do_cmd(int c)
3572 break; 3624 break;
3573 case 12: // ctrl-L force redraw whole screen 3625 case 12: // ctrl-L force redraw whole screen
3574 case 18: // ctrl-R force redraw 3626 case 18: // ctrl-R force redraw
3575 place_cursor(0, 0); 3627 redraw(TRUE); // this will redraw the entire display
3576 clear_to_eos();
3577 //mysleep(10); // why???
3578 screen_erase(); // erase the internal screen buffer
3579 last_status_cksum = 0; // force status update
3580 refresh(TRUE); // this will redraw the entire display
3581 break; 3628 break;
3582 case 13: // Carriage Return ^M 3629 case 13: // Carriage Return ^M
3583 case '+': // +- goto next line 3630 case '+': // +- goto next line
diff --git a/findutils/grep.c b/findutils/grep.c
index 547e3d576..9f84d529b 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -172,6 +172,14 @@ enum {
172#define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L) 172#define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L)
173#define NUL_DELIMITED (option_mask32 & OPT_z) 173#define NUL_DELIMITED (option_mask32 & OPT_z)
174 174
175#if ENABLE_PLATFORM_MINGW32
176# define RE_TRANSLATE_TYPE unsigned char*
177# undef ENABLE_EXTRA_COMPAT
178# define ENABLE_EXTRA_COMPAT 0
179# undef IF_EXTRA_COMPAT
180# define IF_EXTRA_COMPAT(x)
181#endif
182
175struct globals { 183struct globals {
176 int max_matches; 184 int max_matches;
177#if !ENABLE_EXTRA_COMPAT 185#if !ENABLE_EXTRA_COMPAT
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 abdc8c2b8..0b9cfb585 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
@@ -490,6 +501,7 @@ enum {
490 + (1LL << SIGUSR2) 501 + (1LL << SIGUSR2)
491 + 0), 502 + 0),
492}; 503};
504#if !ENABLE_PLATFORM_MINGW32
493void bb_signals(int sigs, void (*f)(int)) FAST_FUNC; 505void bb_signals(int sigs, void (*f)(int)) FAST_FUNC;
494/* Unlike signal() and bb_signals, sets handler with sigaction() 506/* Unlike signal() and bb_signals, sets handler with sigaction()
495 * and in a way that while signal handler is run, no other signals 507 * and in a way that while signal handler is run, no other signals
@@ -507,6 +519,10 @@ void sig_unblock(int sig) FAST_FUNC;
507int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC; 519int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC;
508/* SIG_BLOCK/SIG_UNBLOCK all signals: */ 520/* SIG_BLOCK/SIG_UNBLOCK all signals: */
509int sigprocmask_allsigs(int how) FAST_FUNC; 521int sigprocmask_allsigs(int how) FAST_FUNC;
522#else
523#define bb_signals(s, f)
524#define kill_myself_with_sig(s)
525#endif
510/* Standard handler which just records signo */ 526/* Standard handler which just records signo */
511extern smallint bb_got_signal; 527extern smallint bb_got_signal;
512void record_signo(int signo); /* not FAST_FUNC! */ 528void record_signo(int signo); /* not FAST_FUNC! */
@@ -586,7 +602,7 @@ char *strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC;
586int xsocket(int domain, int type, int protocol) FAST_FUNC; 602int xsocket(int domain, int type, int protocol) FAST_FUNC;
587void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; 603void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC;
588void xlisten(int s, int backlog) FAST_FUNC; 604void xlisten(int s, int backlog) FAST_FUNC;
589void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) FAST_FUNC; 605void xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen) FAST_FUNC;
590ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, 606ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
591 socklen_t tolen) FAST_FUNC; 607 socklen_t tolen) FAST_FUNC;
592 608
@@ -890,6 +906,9 @@ char *safe_gethostname(void) FAST_FUNC;
890char* str_tolower(char *str) FAST_FUNC; 906char* str_tolower(char *str) FAST_FUNC;
891 907
892char *utoa(unsigned n) FAST_FUNC; 908char *utoa(unsigned n) FAST_FUNC;
909#if ENABLE_PLATFORM_MINGW32
910# define itoa bb_itoa
911#endif
893char *itoa(int n) FAST_FUNC; 912char *itoa(int n) FAST_FUNC;
894/* Returns a pointer past the formatted number, does NOT null-terminate */ 913/* Returns a pointer past the formatted number, does NOT null-terminate */
895char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; 914char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC;
@@ -1664,6 +1683,9 @@ typedef struct procps_status_t {
1664#if ENABLE_FEATURE_TOP_SMP_PROCESS 1683#if ENABLE_FEATURE_TOP_SMP_PROCESS
1665 int last_seen_on_cpu; 1684 int last_seen_on_cpu;
1666#endif 1685#endif
1686#if ENABLE_PLATFORM_MINGW32
1687 HANDLE snapshot;
1688#endif
1667} procps_status_t; 1689} procps_status_t;
1668/* flag bits for procps_scan(xx, flags) calls */ 1690/* flag bits for procps_scan(xx, flags) calls */
1669enum { 1691enum {
@@ -1702,7 +1724,11 @@ void free_procps_scan(procps_status_t* sp) FAST_FUNC;
1702procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; 1724procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC;
1703/* Format cmdline (up to col chars) into char buf[size] */ 1725/* Format cmdline (up to col chars) into char buf[size] */
1704/* Puts [comm] if cmdline is empty (-> process is a kernel thread) */ 1726/* Puts [comm] if cmdline is empty (-> process is a kernel thread) */
1727#if !ENABLE_PLATFORM_MINGW32
1705void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; 1728void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC;
1729#else
1730#define read_cmdline(buf, size, pid, comm) snprintf(buf, size, "[%s]", comm)
1731#endif
1706pid_t *find_pid_by_name(const char* procName) FAST_FUNC; 1732pid_t *find_pid_by_name(const char* procName) FAST_FUNC;
1707pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; 1733pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC;
1708int starts_with_cpu(const char *str) FAST_FUNC; 1734int starts_with_cpu(const char *str) FAST_FUNC;
@@ -1842,7 +1868,11 @@ extern const char bb_path_wtmp_file[] ALIGN1;
1842#define bb_path_motd_file "/etc/motd" 1868#define bb_path_motd_file "/etc/motd"
1843 1869
1844#define bb_dev_null "/dev/null" 1870#define bb_dev_null "/dev/null"
1871#if ENABLE_PLATFORM_MINGW32
1872#define bb_busybox_exec_path get_busybox_exec_path()
1873#else
1845extern const char bb_busybox_exec_path[] ALIGN1; 1874extern const char bb_busybox_exec_path[] ALIGN1;
1875#endif
1846/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 1876/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
1847 * but I want to save a few bytes here */ 1877 * but I want to save a few bytes here */
1848extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ 1878extern 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..569c2c704
--- /dev/null
+++ b/include/mingw.h
@@ -0,0 +1,482 @@
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 vprintf(...) winansi_vfprintf(stdout, __VA_ARGS__)
174#define printf(...) winansi_printf(__VA_ARGS__)
175#define fprintf(...) winansi_fprintf(__VA_ARGS__)
176#define write winansi_write
177#define read winansi_read
178#define getc winansi_getc
179
180int winansi_get_terminal_width_height(struct winsize *win);
181
182/*
183 * stdlib.h
184 */
185#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */
186#define WEXITSTATUS(x) ((x) & 0xff)
187#define WIFSIGNALED(x) ((unsigned)(x) > 259)
188#define WTERMSIG(x) ((x) & 0x7f)
189#define WCOREDUMP(x) 0
190
191int mingw_system(const char *cmd);
192#define system mingw_system
193
194int clearenv(void);
195char *mingw_getenv(const char *name);
196int mingw_putenv(const char *env);
197char *mingw_mktemp(char *template);
198int mkstemp(char *template);
199char *realpath(const char *path, char *resolved_path);
200int setenv(const char *name, const char *value, int replace);
201#if ENABLE_SAFE_ENV
202int unsetenv(const char *env);
203#else
204void unsetenv(const char *env);
205#endif
206
207#define getenv mingw_getenv
208#if ENABLE_SAFE_ENV
209#define putenv mingw_putenv
210#endif
211#define mktemp mingw_mktemp
212
213/*
214 * string.h
215 */
216void *mempcpy(void *dest, const void *src, size_t n);
217
218/*
219 * strings.h
220 */
221int ffs(int i);
222
223/*
224 * sys/ioctl.h
225 */
226
227#define TIOCGWINSZ 0x5413
228
229int ioctl(int fd, int code, ...);
230
231/*
232 * sys/socket.h
233 */
234#define hstrerror strerror
235
236#define SHUT_WR SD_SEND
237
238int mingw_socket(int domain, int type, int protocol);
239int mingw_connect(int sockfd, const struct sockaddr *sa, size_t sz);
240int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
241int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
242int mingw_shutdown(int sockfd, int how);
243int mingw_listen(int sockfd, int backlog);
244int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz);
245int mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
246 struct timeval *timeout);
247
248NOIMPL(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);
249
250#define socket mingw_socket
251#define connect mingw_connect
252#define sendto mingw_sendto
253#define listen mingw_listen
254#define bind mingw_bind
255#define setsockopt mingw_setsockopt
256#define shutdown mingw_shutdown
257#define accept mingw_accept
258#define select mingw_select
259
260/*
261 * sys/stat.h
262 */
263#define S_ISUID 04000
264#define S_ISGID 02000
265#define S_ISVTX 01000
266#ifndef S_IRWXU
267#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
268#endif
269#define S_IRWXG (S_IRWXU >> 3)
270#define S_IRWXO (S_IRWXG >> 3)
271
272#define S_IFSOCK 0140000
273#define S_IFLNK 0120000 /* Symbolic link */
274#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
275#define S_ISSOCK(x) 0
276
277#define S_IRGRP (S_IRUSR >> 3)
278#define S_IWGRP (S_IWUSR >> 3)
279#define S_IXGRP (S_IXUSR >> 3)
280#define S_IROTH (S_IRGRP >> 3)
281#define S_IWOTH (S_IWGRP >> 3)
282#define S_IXOTH (S_IXGRP >> 3)
283
284IMPL(fchmod,int,0,int fildes UNUSED_PARAM, mode_t mode UNUSED_PARAM);
285NOIMPL(fchown,int fd UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
286int mingw_mkdir(const char *path, int mode);
287int mingw_chmod(const char *path, int mode);
288
289#define mkdir mingw_mkdir
290#define chmod mingw_chmod
291
292#if ENABLE_LFS && !defined(__MINGW64_VERSION_MAJOR)
293# define off_t off64_t
294#endif
295
296typedef int nlink_t;
297typedef int blksize_t;
298typedef off_t blkcnt_t;
299
300struct mingw_stat {
301 dev_t st_dev;
302 ino_t st_ino;
303 mode_t st_mode;
304 nlink_t st_nlink;
305 uid_t st_uid;
306 gid_t st_gid;
307 dev_t st_rdev;
308 off_t st_size;
309 time_t st_atime;
310 time_t st_mtime;
311 time_t st_ctime;
312 blksize_t st_blksize;
313 blkcnt_t st_blocks;
314};
315
316int mingw_lstat(const char *file_name, struct mingw_stat *buf);
317int mingw_stat(const char *file_name, struct mingw_stat *buf);
318int mingw_fstat(int fd, struct mingw_stat *buf);
319#undef lstat
320#undef stat
321#undef fstat
322#define lstat mingw_lstat
323#define stat mingw_stat
324#define fstat mingw_fstat
325
326/*
327 * sys/sysmacros.h
328 */
329#define makedev(a,b) 0*(a)*(b) /* avoid unused warning */
330#define minor(x) 0
331#define major(x) 0
332
333/*
334 * sys/time.h
335 */
336#ifndef _TIMESPEC_DEFINED
337#define _TIMESPEC_DEFINED
338struct timespec {
339 time_t tv_sec;
340 long int tv_nsec;
341};
342#endif
343
344/*
345 * sys/wait.h
346 */
347#define WNOHANG 1
348#define WUNTRACED 2
349int waitpid(pid_t pid, int *status, int options);
350
351/*
352 * time.h
353 */
354struct tm *gmtime_r(const time_t *timep, struct tm *result);
355struct tm *localtime_r(const time_t *timep, struct tm *result);
356char *strptime(const char *s, const char *format, struct tm *tm);
357size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm);
358int stime(time_t *t);
359
360#define strftime mingw_strftime
361
362/*
363 * times.h
364 */
365#define clock_t long
366
367struct tms {
368 clock_t tms_utime; /* user CPU time */
369 clock_t tms_stime; /* system CPU time */
370 clock_t tms_cutime; /* user CPU time of children */
371 clock_t tms_cstime; /* system CPU time of children */
372};
373
374clock_t times(struct tms *buf);
375
376/*
377 * unistd.h
378 */
379#define PIPE_BUF 8192
380
381#define _SC_CLK_TCK 2
382
383IMPL(alarm,unsigned int,0,unsigned int seconds UNUSED_PARAM);
384IMPL(chown,int,0,const char *path UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM);
385NOIMPL(chroot,const char *root UNUSED_PARAM);
386NOIMPL(fchdir,int fd UNUSED_PARAM);
387int mingw_dup2 (int fd, int fdto);
388char *mingw_getcwd(char *pointer, int len);
389off_t mingw_lseek(int fd, off_t offset, int whence);
390
391
392IMPL(getgid,int,DEFAULT_GID,void);
393int getgroups(int n, gid_t *groups);
394IMPL(getppid,int,1,void);
395IMPL(getegid,int,DEFAULT_GID,void);
396IMPL(geteuid,int,DEFAULT_UID,void);
397NOIMPL(getsid,pid_t pid UNUSED_PARAM);
398IMPL(getuid,int,DEFAULT_UID,void);
399int getlogin_r(char *buf, size_t len);
400int fcntl(int fd, int cmd, ...);
401#define fork() -1
402IMPL(fsync,int,0,int fd UNUSED_PARAM);
403int kill(pid_t pid, int sig);
404int link(const char *oldpath, const char *newpath);
405NOIMPL(mknod,const char *name UNUSED_PARAM, mode_t mode UNUSED_PARAM, dev_t device UNUSED_PARAM);
406int mingw_open (const char *filename, int oflags, ...);
407int pipe(int filedes[2]);
408NOIMPL(readlink,const char *path UNUSED_PARAM, char *buf UNUSED_PARAM, size_t bufsiz UNUSED_PARAM);
409NOIMPL(setgid,gid_t gid UNUSED_PARAM);
410NOIMPL(setegid,gid_t gid UNUSED_PARAM);
411NOIMPL(setsid,void);
412NOIMPL(setuid,uid_t gid UNUSED_PARAM);
413NOIMPL(seteuid,uid_t gid UNUSED_PARAM);
414unsigned int sleep(unsigned int seconds);
415NOIMPL(symlink,const char *oldpath UNUSED_PARAM, const char *newpath UNUSED_PARAM);
416static inline void sync(void) {}
417long sysconf(int name);
418NOIMPL(ttyname_r,int fd UNUSED_PARAM, char *buf UNUSED_PARAM, int sz UNUSED_PARAM);
419int mingw_unlink(const char *pathname);
420NOIMPL(vfork,void);
421int mingw_access(const char *name, int mode);
422int mingw_rmdir(const char *name);
423
424#define dup2 mingw_dup2
425#define getcwd mingw_getcwd
426#define lchown chown
427#define open mingw_open
428#define unlink mingw_unlink
429#define rmdir mingw_rmdir
430#undef lseek
431#define lseek mingw_lseek
432
433#undef access
434#define access mingw_access
435
436/*
437 * utime.h
438 */
439int utimes(const char *file_name, const struct timeval times[2]);
440
441/*
442 * dirent.h
443 */
444DIR *mingw_opendir(const char *path);
445#define opendir mingw_opendir
446
447/*
448 * MinGW specific
449 */
450#define is_dir_sep(c) ((c) == '/' || (c) == '\\')
451#ifndef PRIuMAX
452#define PRIuMAX "I64u"
453#endif
454
455pid_t FAST_FUNC mingw_spawn(char **argv);
456intptr_t FAST_FUNC mingw_spawn_proc(char **argv);
457int mingw_execv(const char *cmd, const char *const *argv);
458int mingw_execvp(const char *cmd, const char *const *argv);
459int mingw_execve(const char *cmd, const char *const *argv, const char *const *envp);
460#define spawn mingw_spawn
461#define execvp mingw_execvp
462#define execve mingw_execve
463#define execv mingw_execv
464
465const char * next_path_sep(const char *path);
466#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
467#define is_absolute_path(path) ((path)[0] == '/' || (path)[0] == '\\' || has_dos_drive_prefix(path))
468
469/*
470 * helpers
471 */
472
473char **copy_environ(const char *const *env);
474void free_environ(char **env);
475char **env_setenv(char **env, const char *name);
476
477const char *get_busybox_exec_path(void);
478void init_winsock(void);
479
480char *file_is_win32_executable(const char *p);
481
482int err_win_to_posix(DWORD winerr);
diff --git a/include/platform.h b/include/platform.h
index c987d418c..94368539e 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -7,6 +7,15 @@
7#ifndef BB_PLATFORM_H 7#ifndef BB_PLATFORM_H
8#define BB_PLATFORM_H 1 8#define BB_PLATFORM_H 1
9 9
10#if ENABLE_PLATFORM_MINGW32
11# if !defined(__MINGW32__) /* HOSTCC is called */
12# undef ENABLE_PLATFORM_MINGW32
13# endif
14#else
15# if defined(__MINGW32__)
16# error "You must select target platform MS Windows, or it won't build"
17# endif
18#endif
10 19
11/* Convenience macros to test the version of gcc. */ 20/* Convenience macros to test the version of gcc. */
12#undef __GNUC_PREREQ 21#undef __GNUC_PREREQ
@@ -119,7 +128,7 @@
119 128
120/* Make all declarations hidden (-fvisibility flag only affects definitions) */ 129/* Make all declarations hidden (-fvisibility flag only affects definitions) */
121/* (don't include system headers after this until corresponding pop!) */ 130/* (don't include system headers after this until corresponding pop!) */
122#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) 131#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) && !ENABLE_PLATFORM_MINGW32
123# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)") 132# define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)")
124# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop") 133# define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop")
125#else 134#else
@@ -148,6 +157,14 @@
148# define bswap_64 __bswap64 157# define bswap_64 __bswap64
149# define bswap_32 __bswap32 158# define bswap_32 __bswap32
150# define bswap_16 __bswap16 159# define bswap_16 __bswap16
160# define __BIG_ENDIAN__ (_BYTE_ORDER == _BIG_ENDIAN)
161#elif ENABLE_PLATFORM_MINGW32
162# define __BIG_ENDIAN 0
163# define __LITTLE_ENDIAN 1
164# define __BYTE_ORDER __LITTLE_ENDIAN
165# define bswap_16(x) ((((x) & 0xFF00) >> 8) | (((x) & 0xFF) << 8))
166# define bswap_32(x) ((bswap_16(((x) & 0xFFFF0000L) >> 16)) | (bswap_16((x) & 0xFFFFL) << 16))
167# define bswap_64(x) ((bswap_32(((x) & 0xFFFFFFFF00000000LL) >> 32)) | (bswap_32((x) & 0xFFFFFFFFLL) << 32))
151#else 168#else
152# include <byteswap.h> 169# include <byteswap.h>
153# include <endian.h> 170# include <endian.h>
@@ -400,6 +417,25 @@ typedef unsigned smalluint;
400# endif 417# endif
401#endif 418#endif
402 419
420#if ENABLE_PLATFORM_MINGW32
421# undef HAVE_DPRINTF
422# undef HAVE_GETLINE
423# undef HAVE_MEMRCHR
424# undef HAVE_MKDTEMP
425# undef HAVE_SETBIT
426# undef HAVE_STPCPY
427# undef HAVE_STRCASESTR
428# undef HAVE_STRCHRNUL
429# undef HAVE_STRSEP
430# undef HAVE_STRSIGNAL
431# undef HAVE_STRVERSCMP
432#if !defined(__MINGW64_VERSION_MAJOR)
433# undef HAVE_VASPRINTF
434#endif
435# undef HAVE_UNLOCKED_STDIO
436# undef HAVE_UNLOCKED_LINE_OPS
437#endif
438
403#if defined(__WATCOMC__) 439#if defined(__WATCOMC__)
404# undef HAVE_DPRINTF 440# undef HAVE_DPRINTF
405# undef HAVE_GETLINE 441# undef HAVE_GETLINE
@@ -511,6 +547,7 @@ extern int dprintf(int fd, const char *format, ...);
511#endif 547#endif
512 548
513#ifndef HAVE_MEMRCHR 549#ifndef HAVE_MEMRCHR
550#include <stddef.h>
514extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC; 551extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC;
515#endif 552#endif
516 553
@@ -570,6 +607,7 @@ extern int usleep(unsigned) FAST_FUNC;
570#endif 607#endif
571 608
572#ifndef HAVE_VASPRINTF 609#ifndef HAVE_VASPRINTF
610# include <stdarg.h>
573extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC; 611extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC;
574#endif 612#endif
575 613
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index 898a51a89..fc9371db1 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
@@ -84,7 +78,6 @@ lib-y += safe_poll.o
84lib-y += safe_strncpy.o 78lib-y += safe_strncpy.o
85lib-y += safe_write.o 79lib-y += safe_write.o
86lib-y += setup_environment.o 80lib-y += setup_environment.o
87lib-y += signals.o
88lib-y += simplify_path.o 81lib-y += simplify_path.o
89lib-y += single_argv.o 82lib-y += single_argv.o
90lib-y += skip_whitespace.o 83lib-y += skip_whitespace.o
@@ -109,10 +102,20 @@ lib-y += xfuncs.o
109lib-y += xfuncs_printf.o 102lib-y += xfuncs_printf.o
110lib-y += xfunc_die.o 103lib-y += xfunc_die.o
111lib-y += xgetcwd.o 104lib-y += xgetcwd.o
112lib-y += xgethostbyname.o
113lib-y += xreadlink.o 105lib-y += xreadlink.o
114lib-y += xrealloc_vector.o 106lib-y += xrealloc_vector.o
115 107
108lib-$(CONFIG_PLATFORM_POSIX) += get_console.o
109lib-$(CONFIG_PLATFORM_POSIX) += getpty.o
110lib-$(CONFIG_PLATFORM_POSIX) += inet_common.o
111lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o
112lib-$(CONFIG_PLATFORM_POSIX) += login.o
113lib-$(CONFIG_PLATFORM_POSIX) += makedev.o
114lib-$(CONFIG_PLATFORM_POSIX) += read_key.o
115lib-$(CONFIG_PLATFORM_POSIX) += signals.o
116lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o
117lib-$(CONFIG_PLATFORM_POSIX) += xgethostbyname.o
118
116lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o 119lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o
117 120
118lib-$(CONFIG_FEATURE_UTMP) += utmp.o 121lib-$(CONFIG_FEATURE_UTMP) += utmp.o
@@ -124,7 +127,7 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
124lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o 127lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o
125lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o 128lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
126 129
127lib-$(CONFIG_NC) += udp_io.o 130lib-$(CONFIG_NC_110_COMPAT) += udp_io.o
128lib-$(CONFIG_DNSD) += udp_io.o 131lib-$(CONFIG_DNSD) += udp_io.o
129lib-$(CONFIG_NTPD) += udp_io.o 132lib-$(CONFIG_NTPD) += udp_io.o
130lib-$(CONFIG_TFTP) += udp_io.o 133lib-$(CONFIG_TFTP) += udp_io.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index ee8b4ec14..ac3e414f5 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -61,6 +61,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
61#if ENABLE_FEATURE_COMPRESS_USAGE 61#if ENABLE_FEATURE_COMPRESS_USAGE
62 62
63static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; 63static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
64#define BB_ARCHIVE_PUBLIC
64# include "bb_archive.h" 65# include "bb_archive.h"
65static const char *unpack_usage_messages(void) 66static const char *unpack_usage_messages(void)
66{ 67{
@@ -281,6 +282,10 @@ void lbb_prepare(const char *applet
281 if (ENABLE_LOCALE_SUPPORT) 282 if (ENABLE_LOCALE_SUPPORT)
282 setlocale(LC_ALL, ""); 283 setlocale(LC_ALL, "");
283 284
285#if ENABLE_PLATFORM_MINGW32
286 init_winsock();
287#endif
288
284#if ENABLE_FEATURE_INDIVIDUAL 289#if ENABLE_FEATURE_INDIVIDUAL
285 /* Redundant for busybox (run_applet_and_exit covers that case) 290 /* Redundant for busybox (run_applet_and_exit covers that case)
286 * but needed for "individual applet" mode */ 291 * but needed for "individual applet" mode */
@@ -656,6 +661,7 @@ static void check_suid(int applet_no)
656 661
657 662
658# if ENABLE_FEATURE_INSTALLER 663# if ENABLE_FEATURE_INSTALLER
664# if !ENABLE_PLATFORM_MINGW32
659static const char usr_bin [] ALIGN1 = "/usr/bin/"; 665static const char usr_bin [] ALIGN1 = "/usr/bin/";
660static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; 666static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
661static const char *const install_dir[] = { 667static const char *const install_dir[] = {
@@ -700,6 +706,29 @@ static void install_links(const char *busybox, int use_symbolic_links,
700 continue; 706 continue;
701 } 707 }
702} 708}
709# else /* ENABLE_PLATFORM_MINGW32 */
710static void install_links(const char *busybox,
711 int use_symbolic_links UNUSED_PARAM, char *custom_install_dir)
712{
713 char *fpc;
714 const char *appname = applet_names;
715 int rc;
716
717 if (!is_directory(custom_install_dir, FALSE))
718 bb_error_msg_and_die("'%s' is not a directory", custom_install_dir);
719
720 while (*appname) {
721 fpc = xasprintf("%s/%s.exe", custom_install_dir, appname);
722 rc = link(busybox, fpc);
723 if (rc != 0 && errno != EEXIST) {
724 bb_simple_perror_msg(fpc);
725 }
726 free(fpc);
727 while (*appname++ != '\0')
728 continue;
729 }
730}
731# endif
703# elif ENABLE_BUSYBOX 732# elif ENABLE_BUSYBOX
704static void install_links(const char *busybox UNUSED_PARAM, 733static void install_links(const char *busybox UNUSED_PARAM,
705 int use_symbolic_links UNUSED_PARAM, 734 int use_symbolic_links UNUSED_PARAM,
@@ -729,15 +758,25 @@ static int busybox_main(char **argv)
729 dup2(1, 2); 758 dup2(1, 2);
730 full_write2_str(bb_banner); /* reuse const string */ 759 full_write2_str(bb_banner); /* reuse const string */
731 full_write2_str(" multi-call binary.\n"); /* reuse */ 760 full_write2_str(" multi-call binary.\n"); /* reuse */
761#if defined(MINGW_VER)
762 if (strlen(MINGW_VER)) {
763 full_write2_str(MINGW_VER "\n\n");
764 }
765#endif
732 full_write2_str( 766 full_write2_str(
733 "BusyBox is copyrighted by many authors between 1998-2015.\n" 767 "BusyBox is copyrighted by many authors between 1998-2015.\n"
734 "Licensed under GPLv2. See source distribution for detailed\n" 768 "Licensed under GPLv2. See source distribution for detailed\n"
735 "copyright notices.\n" 769 "copyright notices.\n"
736 "\n" 770 "\n"
737 "Usage: busybox [function [arguments]...]\n" 771 "Usage: busybox [function [arguments]...]\n"
772 IF_NOT_PLATFORM_MINGW32(
738 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" 773 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
774 )
775 IF_PLATFORM_MINGW32(
776 " or: busybox --list\n"
777 )
739 IF_FEATURE_INSTALLER( 778 IF_FEATURE_INSTALLER(
740 " or: busybox --install [-s] [DIR]\n" 779 " or: busybox --install "IF_NOT_PLATFORM_MINGW32("[-s] ")"[DIR]\n"
741 ) 780 )
742 " or: function [arguments]...\n" 781 " or: function [arguments]...\n"
743 "\n" 782 "\n"
@@ -755,6 +794,11 @@ static int busybox_main(char **argv)
755 "\tTo run external program, use full path (/sbin/ip instead of ip).\n" 794 "\tTo run external program, use full path (/sbin/ip instead of ip).\n"
756 ) 795 )
757 "\n" 796 "\n"
797#if ENABLE_GLOBBING
798 "\tSupport for native Windows wildcards is enabled. In some\n"
799 "\tcases this may result in wildcards being processed twice.\n"
800 "\n"
801#endif
758 "Currently defined functions:\n" 802 "Currently defined functions:\n"
759 ); 803 );
760 col = 0; 804 col = 0;
@@ -786,7 +830,7 @@ static int busybox_main(char **argv)
786 const char *a = applet_names; 830 const char *a = applet_names;
787 dup2(1, 2); 831 dup2(1, 2);
788 while (*a) { 832 while (*a) {
789# if ENABLE_FEATURE_INSTALLER 833# if ENABLE_FEATURE_INSTALLER && !ENABLE_PLATFORM_MINGW32
790 if (argv[1][6]) /* --list-full? */ 834 if (argv[1][6]) /* --list-full? */
791 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); 835 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
792# endif 836# endif
@@ -800,6 +844,7 @@ static int busybox_main(char **argv)
800 } 844 }
801 845
802 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { 846 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
847#if !ENABLE_PLATFORM_MINGW32
803 int use_symbolic_links; 848 int use_symbolic_links;
804 const char *busybox; 849 const char *busybox;
805 850
@@ -820,6 +865,14 @@ static int busybox_main(char **argv)
820 */ 865 */
821 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv); 866 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv);
822 install_links(busybox, use_symbolic_links, argv[2]); 867 install_links(busybox, use_symbolic_links, argv[2]);
868#else
869 /* busybox --install [DIR]
870 * where DIR is the directory to install to. If DIR is not
871 * provided put the links in the same directory as busybox.
872 */
873 install_links(bb_busybox_exec_path, FALSE, argv[2] ? argv[2] :
874 dirname(xstrdup(bb_busybox_exec_path)));
875#endif
823 return 0; 876 return 0;
824 } 877 }
825 878
@@ -960,6 +1013,18 @@ int main(int argc UNUSED_PARAM, char **argv)
960 } 1013 }
961#endif 1014#endif
962 1015
1016#if defined(__MINGW64_VERSION_MAJOR)
1017 if ( stdin ) {
1018 _setmode(fileno(stdin), _O_BINARY);
1019 }
1020 if ( stdout ) {
1021 _setmode(fileno(stdout), _O_BINARY);
1022 }
1023 if ( stderr ) {
1024 _setmode(fileno(stderr), _O_BINARY);
1025 }
1026#endif
1027
963#if defined(SINGLE_APPLET_MAIN) 1028#if defined(SINGLE_APPLET_MAIN)
964 1029
965 /* Only one applet is selected in .config */ 1030 /* Only one applet is selected in .config */
@@ -987,6 +1052,29 @@ int main(int argc UNUSED_PARAM, char **argv)
987 applet_name = argv[0]; 1052 applet_name = argv[0];
988 if (applet_name[0] == '-') 1053 if (applet_name[0] == '-')
989 applet_name++; 1054 applet_name++;
1055 if (ENABLE_PLATFORM_MINGW32) {
1056 const char *applet_name_env = getenv("BUSYBOX_APPLET_NAME");
1057 if (applet_name_env && *applet_name_env) {
1058 applet_name = applet_name_env;
1059 unsetenv("BUSYBOX_APPLET_NAME");
1060 }
1061 else if ( argv[1] && argv[2] && strcmp(argv[1], "--busybox") == 0 ) {
1062 argv += 2;
1063 applet_name = argv[0];
1064 }
1065 else {
1066 char *s = argv[0];
1067 int i, len = strlen(s);
1068
1069 for ( i=0; i < len; ++i ) {
1070 s[i] = tolower(s[i]);
1071 }
1072 if (len > 4 && !strcmp(s+len-4, ".exe")) {
1073 len -= 4;
1074 s[len] = '\0';
1075 }
1076 }
1077 }
990 applet_name = bb_basename(applet_name); 1078 applet_name = bb_basename(applet_name);
991 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */ 1079 parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */
992 run_applet_and_exit(applet_name, argv); 1080 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/getopt32.c b/libbb/getopt32.c
index 15b6efc09..ed9352191 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -576,7 +576,7 @@ getopt32(char **argv, const char *applet_opts, ...)
576 * run_nofork_applet() does this, but we might end up here 576 * run_nofork_applet() does this, but we might end up here
577 * also via gunzip_main() -> gzip_main(). Play safe. 577 * also via gunzip_main() -> gzip_main(). Play safe.
578 */ 578 */
579#ifdef __GLIBC__ 579#if defined(__GLIBC__) || ENABLE_PLATFORM_MINGW32
580 optind = 0; 580 optind = 0;
581#else /* BSD style */ 581#else /* BSD style */
582 optind = 1; 582 optind = 1;
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
index f11c2afb2..64f43b885 100644
--- a/libbb/inode_hash.c
+++ b/libbb/inode_hash.c
@@ -59,6 +59,7 @@ char* FAST_FUNC is_in_ino_dev_hashtable(const struct stat *statbuf)
59/* Add statbuf to statbuf hash table */ 59/* Add statbuf to statbuf hash table */
60void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) 60void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
61{ 61{
62#if !ENABLE_PLATFORM_MINGW32
62 int i; 63 int i;
63 ino_dev_hashtable_bucket_t *bucket; 64 ino_dev_hashtable_bucket_t *bucket;
64 65
@@ -76,6 +77,7 @@ void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *
76 i = hash_inode(statbuf->st_ino); 77 i = hash_inode(statbuf->st_ino);
77 bucket->next = ino_dev_hashtable[i]; 78 bucket->next = ino_dev_hashtable[i];
78 ino_dev_hashtable[i] = bucket; 79 ino_dev_hashtable[i] = bucket;
80#endif
79} 81}
80 82
81#if ENABLE_DU || ENABLE_FEATURE_CLEAN_UP 83#if ENABLE_DU || ENABLE_FEATURE_CLEAN_UP
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 31e392147..5d9080131 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..840c525b0 100644
--- a/libbb/make_directory.c
+++ b/libbb/make_directory.c
@@ -56,6 +56,31 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
56 c = '\0'; 56 c = '\0';
57 57
58 if (flags & FILEUTILS_RECUR) { /* Get the parent */ 58 if (flags & FILEUTILS_RECUR) { /* Get the parent */
59#if ENABLE_PLATFORM_MINGW32
60 if (s == path && *s && s[1] == ':') {
61 /* skip drive letter */
62 s += 2;
63 }
64 else if (s == path && s[0] == '/' && s[1] == '/' ) {
65 /* skip UNC server and share */
66 int count = 0;
67 s += 2;
68 while (*s) {
69 if (*s == '/') {
70 do {
71 ++s;
72 } while (*s == '/');
73 if (++count == 2) {
74 --s;
75 break;
76 }
77 }
78 else {
79 ++s;
80 }
81 }
82 }
83#endif
59 /* Bypass leading non-'/'s and then subsequent '/'s */ 84 /* Bypass leading non-'/'s and then subsequent '/'s */
60 while (*s) { 85 while (*s) {
61 if (*s == '/') { 86 if (*s == '/') {
diff --git a/libbb/messages.c b/libbb/messages.c
index cb0836de8..d74c237e7 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -35,7 +35,9 @@ const char bb_msg_standard_output[] ALIGN1 = "standard output";
35 35
36const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; 36const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
37 37
38#if !ENABLE_PLATFORM_MINGW32
38const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; 39const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
40#endif
39const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; 41const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
40/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 42/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
41 * but I want to save a few bytes here. Check libbb.h before changing! */ 43 * but I want to save a few bytes here. Check libbb.h before changing! */
diff --git a/libbb/printable_string.c b/libbb/printable_string.c
index 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 4edc54d48..452b50b82 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
@@ -618,6 +619,8 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
618 } 619 }
619} 620}
620 621
622#endif /* ENABLE_PLATFORM_MINGW32 */
623
621/* from kernel: 624/* from kernel:
622 // pid comm S ppid pgid sid tty_nr tty_pgrp flg 625 // pid comm S ppid pgid sid tty_nr tty_pgrp flg
623 sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ 626 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 c192829b5..766a89e5f 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -17,6 +17,7 @@
17 17
18#include "busybox.h" /* uses applet tables */ 18#include "busybox.h" /* uses applet tables */
19 19
20#if !ENABLE_PLATFORM_MINGW32
20/* This does a fork/exec in one call, using vfork(). Returns PID of new child, 21/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
21 * -1 for failure. Runs argv[0], searching path if that has no / in it. */ 22 * -1 for failure. Runs argv[0], searching path if that has no / in it. */
22pid_t FAST_FUNC spawn(char **argv) 23pid_t FAST_FUNC spawn(char **argv)
@@ -58,6 +59,7 @@ pid_t FAST_FUNC spawn(char **argv)
58 } 59 }
59 return pid; 60 return pid;
60} 61}
62#endif
61 63
62/* Die with an error message if we can't spawn a child process. */ 64/* Die with an error message if we can't spawn a child process. */
63pid_t FAST_FUNC xspawn(char **argv) 65pid_t FAST_FUNC xspawn(char **argv)
@@ -194,7 +196,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
194 { 196 {
195 return run_nofork_applet(a, argv); 197 return run_nofork_applet(a, argv);
196 } 198 }
197# if BB_MMU 199# if BB_MMU && !ENABLE_PLATFORM_MINGW32
198 /* MMU only */ 200 /* MMU only */
199 /* a->noexec is true */ 201 /* a->noexec is true */
200 rc = fork(); 202 rc = fork();
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/less.c b/miscutils/less.c
index e90691b49..8f9b329ba 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -130,6 +130,10 @@
130 130
131#include <sched.h> /* sched_yield() */ 131#include <sched.h> /* sched_yield() */
132 132
133#if ENABLE_PLATFORM_MINGW32
134#include <conio.h>
135#endif
136
133#include "libbb.h" 137#include "libbb.h"
134#include "common_bufsiz.h" 138#include "common_bufsiz.h"
135#if ENABLE_FEATURE_LESS_REGEXP 139#if ENABLE_FEATURE_LESS_REGEXP
@@ -536,6 +540,11 @@ static void read_lines(void)
536 last_line_pos = 0; 540 last_line_pos = 0;
537 break; 541 break;
538 } 542 }
543#if ENABLE_PLATFORM_MINGW32
544 if (c == '\r') {
545 continue;
546 }
547#endif
539 /* NUL is substituted by '\n'! */ 548 /* NUL is substituted by '\n'! */
540 if (c == '\0') c = '\n'; 549 if (c == '\0') c = '\n';
541 *p++ = c; 550 *p++ = c;
@@ -632,7 +641,12 @@ static void update_num_lines(void)
632 /* only do this for regular files */ 641 /* only do this for regular files */
633 if (num_lines == REOPEN_AND_COUNT || num_lines == REOPEN_STDIN) { 642 if (num_lines == REOPEN_AND_COUNT || num_lines == REOPEN_STDIN) {
634 count = 0; 643 count = 0;
644#if !ENABLE_PLATFORM_MINGW32
635 fd = open("/proc/self/fd/0", O_RDONLY); 645 fd = open("/proc/self/fd/0", O_RDONLY);
646#else
647 /* don't even try to access /proc on WIN32 */
648 fd = -1;
649#endif
636 if (fd < 0 && num_lines == REOPEN_AND_COUNT) { 650 if (fd < 0 && num_lines == REOPEN_AND_COUNT) {
637 /* "filename" is valid only if REOPEN_AND_COUNT */ 651 /* "filename" is valid only if REOPEN_AND_COUNT */
638 fd = open(filename, O_RDONLY); 652 fd = open(filename, O_RDONLY);
@@ -815,7 +829,12 @@ static void print_found(const char *line)
815 match_status = 1; 829 match_status = 1;
816 } 830 }
817 831
832#if !ENABLE_PLATFORM_MINGW32
818 printf("%s%s\n", growline ? growline : "", str); 833 printf("%s%s\n", growline ? growline : "", str);
834#else
835 /* skip newline, we use explicit positioning on WIN32 */
836 printf("%s%s", growline ? growline : "", str);
837#endif
819 free(growline); 838 free(growline);
820} 839}
821#else 840#else
@@ -851,7 +870,12 @@ static void print_ascii(const char *str)
851 *p = '\0'; 870 *p = '\0';
852 print_hilite(buf); 871 print_hilite(buf);
853 } 872 }
873#if !ENABLE_PLATFORM_MINGW32
854 puts(str); 874 puts(str);
875#else
876 /* skip newline, we use explicit positioning on WIN32 */
877 printf("%s", str);
878#endif
855} 879}
856 880
857/* Print the buffer */ 881/* Print the buffer */
@@ -861,6 +885,10 @@ static void buffer_print(void)
861 885
862 move_cursor(0, 0); 886 move_cursor(0, 0);
863 for (i = 0; i <= max_displayed_line; i++) { 887 for (i = 0; i <= max_displayed_line; i++) {
888#if ENABLE_PLATFORM_MINGW32
889 /* make sure we're on the right line */
890 move_cursor(i+1, 0);
891#endif
864 printf(CLEAR_2_EOL); 892 printf(CLEAR_2_EOL);
865 if (option_mask32 & FLAG_N) 893 if (option_mask32 & FLAG_N)
866 print_lineno(buffer[i]); 894 print_lineno(buffer[i]);
@@ -1047,9 +1075,13 @@ static void reinitialize(void)
1047 if (G.winsize_err) 1075 if (G.winsize_err)
1048 printf("\033[999;999H" "\033[6n"); 1076 printf("\033[999;999H" "\033[6n");
1049#endif 1077#endif
1078#if ENABLE_PLATFORM_MINGW32
1079 reset_screen();
1080#endif
1050 buffer_fill_and_print(); 1081 buffer_fill_and_print();
1051} 1082}
1052 1083
1084#if !ENABLE_PLATFORM_MINGW32
1053static int64_t getch_nowait(void) 1085static int64_t getch_nowait(void)
1054{ 1086{
1055 int rd; 1087 int rd;
@@ -1111,6 +1143,46 @@ static int64_t getch_nowait(void)
1111 set_tty_cooked(); 1143 set_tty_cooked();
1112 return key64; 1144 return key64;
1113} 1145}
1146#else
1147static int64_t getch_nowait(void)
1148{
1149 int64_t c;
1150
1151retry:
1152 c = _getch();
1153 if (c == 0 || c == 0xe0) {
1154 switch (_getch()) {
1155 case 0x48:
1156 c = KEYCODE_UP;
1157 break;
1158 case 0x50:
1159 c = KEYCODE_DOWN;
1160 break;
1161 case 0x49:
1162 c = KEYCODE_PAGEUP;
1163 break;
1164 case 0x51:
1165 c = KEYCODE_PAGEDOWN;
1166 break;
1167 case 0x47:
1168 c = KEYCODE_HOME;
1169 break;
1170 case 0x4f:
1171 c = KEYCODE_END;
1172 break;
1173 default:
1174 goto retry;
1175 }
1176 }
1177
1178 /* Position cursor if line input is done */
1179 if (less_gets_pos >= 0)
1180 move_cursor(max_displayed_line + 2, less_gets_pos + 1);
1181 fflush_all();
1182
1183 return c;
1184}
1185#endif
1114 1186
1115/* Grab a character from input without requiring the return key. 1187/* Grab a character from input without requiring the return key.
1116 * May return KEYCODE_xxx values. 1188 * May return KEYCODE_xxx values.
@@ -1766,8 +1838,10 @@ static void sigwinch_handler(int sig UNUSED_PARAM)
1766int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1838int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1767int less_main(int argc, char **argv) 1839int less_main(int argc, char **argv)
1768{ 1840{
1841#if !ENABLE_PLATFORM_MINGW32
1769 char *tty_name; 1842 char *tty_name;
1770 int tty_fd; 1843 int tty_fd;
1844#endif
1771 1845
1772 INIT_G(); 1846 INIT_G();
1773 1847
@@ -1801,6 +1875,7 @@ int less_main(int argc, char **argv)
1801 if (option_mask32 & FLAG_TILDE) 1875 if (option_mask32 & FLAG_TILDE)
1802 empty_line_marker = ""; 1876 empty_line_marker = "";
1803 1877
1878#if !ENABLE_PLATFORM_MINGW32
1804 /* Some versions of less can survive w/o controlling tty, 1879 /* Some versions of less can survive w/o controlling tty,
1805 * try to do the same. This also allows to specify an alternative 1880 * try to do the same. This also allows to specify an alternative
1806 * tty via "less 1<>TTY". 1881 * tty via "less 1<>TTY".
@@ -1826,6 +1901,9 @@ int less_main(int argc, char **argv)
1826 } 1901 }
1827 G.kbd_fd_orig_flags = ndelay_on(tty_fd); 1902 G.kbd_fd_orig_flags = ndelay_on(tty_fd);
1828 kbd_fd = tty_fd; /* save in a global */ 1903 kbd_fd = tty_fd; /* save in a global */
1904#else
1905 kbd_fd = 0;
1906#endif
1829 1907
1830 tcgetattr(kbd_fd, &term_orig); 1908 tcgetattr(kbd_fd, &term_orig);
1831 term_less = term_orig; 1909 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 40a3271ab..0b06f85b4 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -125,6 +125,9 @@ static int ftpcmd(const char *s1, const char *s2)
125 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3), 125 fprintf(control_stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3),
126 s1, s2); 126 s1, s2);
127 fflush(control_stream); 127 fflush(control_stream);
128#if ENABLE_PLATFORM_MINGW32
129 fseek(control_stream, 0L, SEEK_CUR);
130#endif
128 } 131 }
129 132
130 do { 133 do {
@@ -133,6 +136,9 @@ static int ftpcmd(const char *s1, const char *s2)
133 ftp_die(NULL); 136 ftp_die(NULL);
134 } 137 }
135 } while (!isdigit(buf[0]) || buf[3] != ' '); 138 } while (!isdigit(buf[0]) || buf[3] != ' ');
139#if ENABLE_PLATFORM_MINGW32
140 fseek(control_stream, 0L, SEEK_CUR);
141#endif
136 142
137 buf[3] = '\0'; 143 buf[3] = '\0';
138 n = xatou(buf); 144 n = xatou(buf);
diff --git a/networking/wget.c b/networking/wget.c
index b082a0f59..460b4b833 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -425,11 +425,17 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp)
425 fprintf(fp, "%s%s\r\n", s1, s2); 425 fprintf(fp, "%s%s\r\n", s1, s2);
426 fflush(fp); 426 fflush(fp);
427 log_io("> %s%s", s1, s2); 427 log_io("> %s%s", s1, s2);
428#if ENABLE_PLATFORM_MINGW32
429 fseek(fp, 0L, SEEK_CUR);
430#endif
428 } 431 }
429 432
430 do { 433 do {
431 fgets_and_trim(fp); 434 fgets_and_trim(fp);
432 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); 435 } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' ');
436#if ENABLE_PLATFORM_MINGW32
437 fseek(fp, 0L, SEEK_CUR);
438#endif
433 439
434 G.wget_buf[3] = '\0'; 440 G.wget_buf[3] = '\0';
435 result = xatoi_positive(G.wget_buf); 441 result = xatoi_positive(G.wget_buf);
diff --git a/procps/ps.c b/procps/ps.c
index e291ecd7e..902811f31 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -290,6 +290,7 @@ static unsigned get_kernel_HZ(void)
290 290
291/* Print value to buf, max size+1 chars (including trailing '\0') */ 291/* Print value to buf, max size+1 chars (including trailing '\0') */
292 292
293#if !ENABLE_PLATFORM_MINGW32
293static void func_user(char *buf, int size, const procps_status_t *ps) 294static void func_user(char *buf, int size, const procps_status_t *ps)
294{ 295{
295#if 1 296#if 1
@@ -313,12 +314,14 @@ static void func_group(char *buf, int size, const procps_status_t *ps)
313{ 314{
314 safe_strncpy(buf, get_cached_groupname(ps->gid), size+1); 315 safe_strncpy(buf, get_cached_groupname(ps->gid), size+1);
315} 316}
317#endif
316 318
317static void func_comm(char *buf, int size, const procps_status_t *ps) 319static void func_comm(char *buf, int size, const procps_status_t *ps)
318{ 320{
319 safe_strncpy(buf, ps->comm, size+1); 321 safe_strncpy(buf, ps->comm, size+1);
320} 322}
321 323
324#if !ENABLE_PLATFORM_MINGW32
322static void func_state(char *buf, int size, const procps_status_t *ps) 325static void func_state(char *buf, int size, const procps_status_t *ps)
323{ 326{
324 safe_strncpy(buf, ps->state, size+1); 327 safe_strncpy(buf, ps->state, size+1);
@@ -328,12 +331,14 @@ static void func_args(char *buf, int size, const procps_status_t *ps)
328{ 331{
329 read_cmdline(buf, size+1, ps->pid, ps->comm); 332 read_cmdline(buf, size+1, ps->pid, ps->comm);
330} 333}
334#endif
331 335
332static void func_pid(char *buf, int size, const procps_status_t *ps) 336static void func_pid(char *buf, int size, const procps_status_t *ps)
333{ 337{
334 sprintf(buf, "%*u", size, ps->pid); 338 sprintf(buf, "%*u", size, ps->pid);
335} 339}
336 340
341#if !ENABLE_PLATFORM_MINGW32
337static void func_ppid(char *buf, int size, const procps_status_t *ps) 342static void func_ppid(char *buf, int size, const procps_status_t *ps)
338{ 343{
339 sprintf(buf, "%*u", size, ps->ppid); 344 sprintf(buf, "%*u", size, ps->ppid);
@@ -370,6 +375,7 @@ static void func_tty(char *buf, int size, const procps_status_t *ps)
370 if (ps->tty_major) /* tty field of "0" means "no tty" */ 375 if (ps->tty_major) /* tty field of "0" means "no tty" */
371 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor); 376 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
372} 377}
378#endif
373 379
374#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 380#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
375 381
@@ -440,13 +446,19 @@ static void func_pcpu(char *buf, int size, const procps_status_t *ps)
440 446
441static const ps_out_t out_spec[] = { 447static const ps_out_t out_spec[] = {
442/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */ 448/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */
449#if !ENABLE_PLATFORM_MINGW32
443 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, 450 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID },
444 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, 451 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID },
452#endif
445 { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, 453 { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM },
454#if !ENABLE_PLATFORM_MINGW32
446 { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM }, 455 { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM },
456#endif
447 { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID }, 457 { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID },
458#if !ENABLE_PLATFORM_MINGW32
448 { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID }, 459 { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID },
449 { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID }, 460 { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID },
461#endif
450#if ENABLE_FEATURE_PS_TIME 462#if ENABLE_FEATURE_PS_TIME
451 { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME }, 463 { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME },
452#endif 464#endif
@@ -459,11 +471,13 @@ static const ps_out_t out_spec[] = {
459#if ENABLE_FEATURE_PS_TIME 471#if ENABLE_FEATURE_PS_TIME
460 { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, 472 { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME },
461#endif 473#endif
474#if !ENABLE_PLATFORM_MINGW32
462 { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, 475 { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY },
463 { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, 476 { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ },
464/* Not mandated, but useful: */ 477/* Not mandated, but useful: */
465 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE }, 478 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE },
466 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, 479 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS },
480#endif
467#if ENABLE_SELINUX 481#if ENABLE_SELINUX
468 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, 482 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT },
469#endif 483#endif
@@ -602,6 +616,8 @@ static void format_process(const procps_status_t *ps)
602#if ENABLE_SELINUX 616#if ENABLE_SELINUX
603# define SELINUX_O_PREFIX "label," 617# define SELINUX_O_PREFIX "label,"
604# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") 618# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args")
619#elif ENABLE_PLATFORM_MINGW32
620# define DEFAULT_O_STR ("pid,comm")
605#else 621#else
606# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") 622# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args")
607#endif 623#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/fixdep.c b/scripts/basic/fixdep.c
index 19f82df09..f012551af 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -104,7 +104,9 @@
104 104
105#include <sys/types.h> 105#include <sys/types.h>
106#include <sys/stat.h> 106#include <sys/stat.h>
107#ifndef __MINGW32__
107#include <sys/mman.h> 108#include <sys/mman.h>
109#endif
108#include <unistd.h> 110#include <unistd.h>
109#include <fcntl.h> 111#include <fcntl.h>
110#include <string.h> 112#include <string.h>
@@ -112,7 +114,9 @@
112#include <stdio.h> 114#include <stdio.h>
113#include <limits.h> 115#include <limits.h>
114#include <ctype.h> 116#include <ctype.h>
117#ifndef __MINGW32__
115#include <arpa/inet.h> 118#include <arpa/inet.h>
119#endif
116//bbox disabled: #include <alloca.h> 120//bbox disabled: #include <alloca.h>
117 121
118/* bbox: not needed 122/* bbox: not needed
@@ -122,6 +126,53 @@
122#define INT_FIG_ ntohl(0x4649475f) 126#define INT_FIG_ ntohl(0x4649475f)
123*/ 127*/
124 128
129#ifdef __MINGW32__
130#define UNUSED __attribute__ ((__unused__))
131
132/* Workaround specifically for fixdep */
133#define PROT_READ 0
134#define MAP_PRIVATE 0
135void *mmap(void *start UNUSED, size_t size, int prot UNUSED,
136 int flags UNUSED, int fd, off_t offset UNUSED)
137{
138 void *p;
139 void *curP;
140 ssize_t readB;
141
142 p = malloc(size);
143 if (!p)
144 return (void*)((long)-1);
145
146 curP = p;
147
148 while (size > 0)
149 {
150 readB = read(fd, curP, size);
151
152 if (readB == 0)
153 {
154 /* EOF reached */
155 break;
156 }
157 else if (readB < 0)
158 {
159 perror("fixdep: read config");
160 free(p);
161 return (void*)((long)-1);
162 }
163
164 size -= readB;
165 curP += readB;
166 }
167
168 return p;
169}
170void munmap(void *p, size_t size UNUSED)
171{
172 free(p);
173}
174#endif
175
125char *target; 176char *target;
126char *depfile; 177char *depfile;
127char *cmdline; 178char *cmdline;
diff --git a/shell/ash.c b/shell/ash.c
index e6d02f69c..af1157709 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
@@ -202,7 +217,7 @@
202 217
203#include "unicode.h" 218#include "unicode.h"
204#include "shell_common.h" 219#include "shell_common.h"
205#if ENABLE_FEATURE_SH_MATH 220#if CONFIG_FEATURE_SH_MATH
206# include "math.h" 221# include "math.h"
207#endif 222#endif
208#if ENABLE_ASH_RANDOM_SUPPORT 223#if ENABLE_ASH_RANDOM_SUPPORT
@@ -227,10 +242,58 @@
227# define PIPE_BUF 4096 /* amount of buffering in a pipe */ 242# define PIPE_BUF 4096 /* amount of buffering in a pipe */
228#endif 243#endif
229 244
245#if !ENABLE_PLATFORM_MINGW32
246# define is_absolute_path(path) ((path)[0] == '/')
247#endif
248
230#if !BB_MMU 249#if !BB_MMU
231# error "Do not even bother, ash will not run on NOMMU machine" 250# error "Do not even bother, ash will not run on NOMMU machine"
232#endif 251#endif
233 252
253#if ENABLE_PLATFORM_MINGW32
254union node;
255struct strlist;
256struct job;
257
258struct forkshell {
259 /* filled by forkshell_copy() */
260 struct globals_var *gvp;
261 struct globals_misc *gmp;
262 struct tblentry **cmdtable;
263 /* struct alias **atab; */
264 /* struct parsefile *g_parsefile; */
265 HANDLE hMapFile;
266 void *old_base;
267 int nodeptr_offset;
268 int size;
269
270 /* type of forkshell */
271 int fpid;
272
273 /* optional data, used by forkshell_child */
274 int flags;
275 int fd[10];
276 union node *n;
277 char **argv;
278 char *string;
279 struct strlist *strlist;
280};
281
282enum {
283 FS_OPENHERE,
284 FS_EVALBACKCMD,
285 FS_EVALSUBSHELL,
286 FS_EVALPIPE,
287 FS_SHELLEXEC
288};
289
290static struct forkshell* forkshell_prepare(struct forkshell *fs);
291static void forkshell_init(const char *idstr);
292static void forkshell_child(struct forkshell *fs);
293static void sticky_free(void *p);
294#define free(p) sticky_free(p)
295static int spawn_forkshell(struct job *jp, struct forkshell *fs, int mode);
296#endif
234 297
235/* ============ Hash table sizes. Configurable. */ 298/* ============ Hash table sizes. Configurable. */
236 299
@@ -263,6 +326,10 @@ static const char *const optletters_optnames[] = {
263 ,"\0" "nolog" 326 ,"\0" "nolog"
264 ,"\0" "debug" 327 ,"\0" "debug"
265#endif 328#endif
329#if ENABLE_PLATFORM_MINGW32
330 ,"\0" "noconsole"
331 ,"X" "winxp"
332#endif
266}; 333};
267 334
268#define optletters(n) optletters_optnames[n][0] 335#define optletters(n) optletters_optnames[n][0]
@@ -342,6 +409,10 @@ struct globals_misc {
342# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT] 409# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
343# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT] 410# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
344#endif 411#endif
412#if ENABLE_PLATFORM_MINGW32
413# define noconsole optlist[14 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
414# define winxp optlist[15 + ENABLE_ASH_BASH_COMPAT + 2*DEBUG]
415#endif
345 416
346 /* trap handler commands */ 417 /* trap handler commands */
347 /* 418 /*
@@ -2393,10 +2464,22 @@ path_advance(const char **path, const char *name)
2393 if (*path == NULL) 2464 if (*path == NULL)
2394 return NULL; 2465 return NULL;
2395 start = *path; 2466 start = *path;
2467#if ENABLE_PLATFORM_MINGW32
2468 p = next_path_sep(start);
2469 q = strchr(start, '%');
2470 if ((p && q && q < p) || (!p && q))
2471 p = q;
2472 if (!p)
2473 for (p = start; *p; p++)
2474 continue;
2475#else
2396 for (p = start; *p && *p != ':' && *p != '%'; p++) 2476 for (p = start; *p && *p != ':' && *p != '%'; p++)
2397 continue; 2477 continue;
2478#endif
2398 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2479 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2399 while (stackblocksize() < len) 2480
2481 /* preserve space for .exe too */
2482 while (stackblocksize() < (ENABLE_PLATFORM_MINGW32 ? len+4 : len))
2400 growstackblock(); 2483 growstackblock();
2401 q = stackblock(); 2484 q = stackblock();
2402 if (p != start) { 2485 if (p != start) {
@@ -2408,10 +2491,19 @@ path_advance(const char **path, const char *name)
2408 pathopt = NULL; 2491 pathopt = NULL;
2409 if (*p == '%') { 2492 if (*p == '%') {
2410 pathopt = ++p; 2493 pathopt = ++p;
2494#if ENABLE_PLATFORM_MINGW32
2495 p = next_path_sep(start);
2496
2497 /* *p != ':' and '*' would suffice */
2498 if (!p)
2499 p = pathopt - 1;
2500#else
2411 while (*p && *p != ':') 2501 while (*p && *p != ':')
2412 p++; 2502 p++;
2503#endif
2413 } 2504 }
2414 if (*p == ':') 2505 if (*p == ':' ||
2506 (ENABLE_PLATFORM_MINGW32 && *p == ';'))
2415 *path = p + 1; 2507 *path = p + 1;
2416 else 2508 else
2417 *path = NULL; 2509 *path = NULL;
@@ -2512,6 +2604,106 @@ cdopt(void)
2512static const char * 2604static const char *
2513updatepwd(const char *dir) 2605updatepwd(const char *dir)
2514{ 2606{
2607#if ENABLE_PLATFORM_MINGW32
2608#define is_path_sep(x) ((x) == '/' || (x) == '\\')
2609#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1]))
2610 /*
2611 * Due to Windows drive notion, getting pwd is a completely
2612 * different thing. Handle it in a separate routine
2613 */
2614
2615 char *new;
2616 char *p;
2617 char *cdcomppath;
2618 const char *lim;
2619 /*
2620 * There are five cases that make some kind of sense
2621 * absdrive + abspath: c:/path
2622 * absdrive + !abspath: c:path
2623 * !absdrive + abspath: /path
2624 * !absdrive + uncpath: //host/share
2625 * !absdrive + !abspath: path
2626 *
2627 * Damn DOS!
2628 * c:path behaviour is "undefined"
2629 * To properly handle this case, I have to keep track of cwd
2630 * of every drive, which is too painful to do.
2631 * So when c:path is given, I assume it's c:${curdir}path
2632 * with ${curdir} comes from the current drive
2633 */
2634 int absdrive = *dir && dir[1] == ':';
2635 int abspath = absdrive ? is_path_sep(dir[2]) : is_path_sep(*dir);
2636
2637 cdcomppath = sstrdup(dir);
2638 STARTSTACKSTR(new);
2639 if (!absdrive && curdir == nullstr)
2640 return 0;
2641 if (!abspath) {
2642 if (curdir == nullstr)
2643 return 0;
2644 new = stack_putstr(curdir, new);
2645 }
2646 new = makestrspace(strlen(dir) + 2, new);
2647
2648 if ( is_unc_path(dir) || (!absdrive && !abspath && is_unc_path(curdir)) ) {
2649 lim = (char *)stackblock() + 1;
2650 }
2651 else {
2652 char *drive = stackblock();
2653 if (absdrive) {
2654 *drive = *dir;
2655 cdcomppath += 2;
2656 dir += 2;
2657 } else {
2658 *drive = *curdir;
2659 }
2660 drive[1] = ':'; /* in case of absolute drive+path */
2661
2662 if (abspath)
2663 new = drive + 2;
2664 lim = drive + 3;
2665 }
2666
2667 if (!abspath) {
2668 if (!is_path_sep(new[-1]))
2669 USTPUTC('/', new);
2670 if (new > lim && is_path_sep(*lim))
2671 lim++;
2672 } else {
2673 USTPUTC('/', new);
2674 cdcomppath ++;
2675 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
2676 USTPUTC('/', new);
2677 cdcomppath++;
2678 lim++;
2679 }
2680 }
2681 p = strtok(cdcomppath, "/\\");
2682 while (p) {
2683 switch (*p) {
2684 case '.':
2685 if (p[1] == '.' && p[2] == '\0') {
2686 while (new > lim) {
2687 STUNPUTC(new);
2688 if (is_path_sep(new[-1]))
2689 break;
2690 }
2691 break;
2692 }
2693 if (p[1] == '\0')
2694 break;
2695 /* fall through */
2696 default:
2697 new = stack_putstr(p, new);
2698 USTPUTC('/', new);
2699 }
2700 p = strtok(0, "/\\");
2701 }
2702 if (new > lim)
2703 STUNPUTC(new);
2704 *new = 0;
2705 return stackblock();
2706#else
2515 char *new; 2707 char *new;
2516 char *p; 2708 char *p;
2517 char *cdcomppath; 2709 char *cdcomppath;
@@ -2565,6 +2757,7 @@ updatepwd(const char *dir)
2565 STUNPUTC(new); 2757 STUNPUTC(new);
2566 *new = 0; 2758 *new = 0;
2567 return stackblock(); 2759 return stackblock();
2760#endif
2568} 2761}
2569 2762
2570/* 2763/*
@@ -2659,7 +2852,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
2659 } 2852 }
2660 if (!dest) 2853 if (!dest)
2661 dest = nullstr; 2854 dest = nullstr;
2662 if (*dest == '/') 2855 if (is_absolute_path(dest))
2663 goto step6; 2856 goto step6;
2664 if (*dest == '.') { 2857 if (*dest == '.') {
2665 c = dest[1]; 2858 c = dest[1];
@@ -3370,6 +3563,9 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
3370 */ 3563 */
3371struct procstat { 3564struct procstat {
3372 pid_t ps_pid; /* process id */ 3565 pid_t ps_pid; /* process id */
3566#if ENABLE_PLATFORM_MINGW32
3567 HANDLE ps_proc;
3568#endif
3373 int ps_status; /* last process status from wait() */ 3569 int ps_status; /* last process status from wait() */
3374 char *ps_cmd; /* text of command being run */ 3570 char *ps_cmd; /* text of command being run */
3375}; 3571};
@@ -3397,7 +3593,9 @@ struct job {
3397}; 3593};
3398 3594
3399static struct job *makejob(/*union node *,*/ int); 3595static struct job *makejob(/*union node *,*/ int);
3596#if !ENABLE_PLATFORM_MINGW32
3400static int forkshell(struct job *, union node *, int); 3597static int forkshell(struct job *, union node *, int);
3598#endif
3401static int waitforjob(struct job *); 3599static int waitforjob(struct job *);
3402 3600
3403#if !JOBS 3601#if !JOBS
@@ -3422,6 +3620,7 @@ ignoresig(int signo)
3422 sigmode[signo - 1] = S_HARD_IGN; 3620 sigmode[signo - 1] = S_HARD_IGN;
3423} 3621}
3424 3622
3623#if !ENABLE_PLATFORM_MINGW32
3425/* 3624/*
3426 * Only one usage site - in setsignal() 3625 * Only one usage site - in setsignal()
3427 */ 3626 */
@@ -3546,6 +3745,9 @@ setsignal(int signo)
3546 3745
3547 *t = new_act; 3746 *t = new_act;
3548} 3747}
3748#else
3749#define setsignal(s)
3750#endif
3549 3751
3550/* mode flags for set_curjob */ 3752/* mode flags for set_curjob */
3551#define CUR_DELETE 2 3753#define CUR_DELETE 2
@@ -3971,6 +4173,97 @@ sprint_status48(char *s, int status, int sigonly)
3971 return col; 4173 return col;
3972} 4174}
3973 4175
4176#if ENABLE_PLATFORM_MINGW32
4177
4178HANDLE hSIGINT; /* Ctrl-C is pressed */
4179
4180static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4181{
4182 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
4183 SetEvent(hSIGINT);
4184 return TRUE;
4185 }
4186 return FALSE;
4187}
4188
4189/*
4190 * Windows does not know about parent-child relationship
4191 * They don't support waitpid(-1)
4192 */
4193static pid_t
4194waitpid_child(int *status, int wait_flags)
4195{
4196 pid_t *pidlist;
4197 HANDLE *proclist;
4198 int pid_nr = 0;
4199 pid_t pid;
4200 DWORD win_status, idx;
4201 struct job *jb;
4202
4203 for (jb = curjob; jb; jb = jb->prev_job) {
4204 if (jb->state != JOBDONE)
4205 pid_nr += jb->nprocs;
4206 }
4207 if ( pid_nr++ == 0 )
4208 return -1;
4209
4210 pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4211 proclist = ckmalloc(sizeof(*proclist)*pid_nr);
4212
4213 pidlist[0] = -1;
4214 proclist[0] = hSIGINT;
4215 pid_nr = 1;
4216 for (jb = curjob; jb; jb = jb->prev_job) {
4217 struct procstat *ps, *psend;
4218 if (jb->state == JOBDONE)
4219 continue;
4220 ps = jb->ps;
4221 psend = ps + jb->nprocs;
4222 while (ps < psend) {
4223 if (ps->ps_pid != -1 && ps->ps_proc != NULL) {
4224 pidlist[pid_nr] = ps->ps_pid;
4225 proclist[pid_nr++] = ps->ps_proc;
4226 }
4227 ps++;
4228 }
4229 }
4230
4231 if (pid_nr == 1) {
4232 free(pidlist);
4233 free(proclist);
4234 return -1;
4235 }
4236
4237 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE,
4238 wait_flags|WNOHANG ? 1 : INFINITE);
4239 if (idx >= pid_nr) {
4240 free(pidlist);
4241 free(proclist);
4242 return -1;
4243 }
4244 if (!idx) { /* hSIGINT */
4245 int i;
4246 ResetEvent(hSIGINT);
4247 for (i = 1; i < pid_nr; i++)
4248 TerminateProcess(proclist[i], 1);
4249 pid = pidlist[1];
4250 free(pidlist);
4251 free(proclist);
4252 *status = 260; /* terminated by a signal */
4253 return pid;
4254 }
4255 GetExitCodeProcess(proclist[idx], &win_status);
4256 pid = pidlist[idx];
4257 free(pidlist);
4258 free(proclist);
4259 *status = (int)win_status;
4260 return pid;
4261}
4262#define waitpid(p, s, f) waitpid_child(s, f)
4263#define wait_block_or_sig(s) waitpid_child(s, 0)
4264
4265#else
4266
3974static int 4267static int
3975wait_block_or_sig(int *status) 4268wait_block_or_sig(int *status)
3976{ 4269{
@@ -4003,6 +4296,7 @@ wait_block_or_sig(int *status)
4003 4296
4004 return pid; 4297 return pid;
4005} 4298}
4299#endif
4006 4300
4007#define DOWAIT_NONBLOCK 0 4301#define DOWAIT_NONBLOCK 0
4008#define DOWAIT_BLOCK 1 4302#define DOWAIT_BLOCK 1
@@ -4071,6 +4365,11 @@ dowait(int block, struct job *job)
4071 jobno(jp), pid, ps->ps_status, status)); 4365 jobno(jp), pid, ps->ps_status, status));
4072 ps->ps_status = status; 4366 ps->ps_status = status;
4073 thisjob = jp; 4367 thisjob = jp;
4368 if (ENABLE_PLATFORM_MINGW32) {
4369 ps->ps_pid = -1;
4370 CloseHandle(ps->ps_proc);
4371 ps->ps_proc = NULL;
4372 }
4074 } 4373 }
4075 if (ps->ps_status == -1) 4374 if (ps->ps_status == -1)
4076 jobstate = JOBRUNNING; 4375 jobstate = JOBRUNNING;
@@ -4743,6 +5042,7 @@ commandtext(union node *n)
4743 * 5042 *
4744 * Called with interrupts off. 5043 * Called with interrupts off.
4745 */ 5044 */
5045#if !ENABLE_PLATFORM_MINGW32
4746/* 5046/*
4747 * Clear traps on a fork. 5047 * Clear traps on a fork.
4748 */ 5048 */
@@ -4892,16 +5192,24 @@ forkchild(struct job *jp, union node *n, int mode)
4892 freejob(jp); 5192 freejob(jp);
4893 jobless = 0; 5193 jobless = 0;
4894} 5194}
5195#endif
4895 5196
4896/* Called after fork(), in parent */ 5197/* Called after fork(), in parent */
4897#if !JOBS 5198#if !JOBS
4898#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid) 5199#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4899#endif 5200#endif
4900static void 5201static void
5202#if !ENABLE_PLATFORM_MINGW32
4901forkparent(struct job *jp, union node *n, int mode, pid_t pid) 5203forkparent(struct job *jp, union node *n, int mode, pid_t pid)
5204#else
5205forkparent(struct job *jp, union node *n, int mode, HANDLE proc)
5206#endif
4902{ 5207{
5208#if ENABLE_PLATFORM_MINGW32
5209 pid_t pid = GetProcessId(proc);
5210#endif
4903 TRACE(("In parent shell: child = %d\n", pid)); 5211 TRACE(("In parent shell: child = %d\n", pid));
4904 if (!jp) { 5212 if (!jp && !ENABLE_PLATFORM_MINGW32) { /* FIXME not quite understand this */
4905 /* jp is NULL when called by openhere() for heredoc support */ 5213 /* jp is NULL when called by openhere() for heredoc support */
4906 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0) 5214 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4907 continue; 5215 continue;
@@ -4927,6 +5235,9 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4927 if (jp) { 5235 if (jp) {
4928 struct procstat *ps = &jp->ps[jp->nprocs++]; 5236 struct procstat *ps = &jp->ps[jp->nprocs++];
4929 ps->ps_pid = pid; 5237 ps->ps_pid = pid;
5238#if ENABLE_PLATFORM_MINGW32
5239 ps->ps_proc = proc;
5240#endif
4930 ps->ps_status = -1; 5241 ps->ps_status = -1;
4931 ps->ps_cmd = nullstr; 5242 ps->ps_cmd = nullstr;
4932#if JOBS 5243#if JOBS
@@ -4936,6 +5247,7 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4936 } 5247 }
4937} 5248}
4938 5249
5250#if !ENABLE_PLATFORM_MINGW32
4939/* jp and n are NULL when called by openhere() for heredoc support */ 5251/* jp and n are NULL when called by openhere() for heredoc support */
4940static int 5252static int
4941forkshell(struct job *jp, union node *n, int mode) 5253forkshell(struct job *jp, union node *n, int mode)
@@ -4958,6 +5270,7 @@ forkshell(struct job *jp, union node *n, int mode)
4958 } 5270 }
4959 return pid; 5271 return pid;
4960} 5272}
5273#endif
4961 5274
4962/* 5275/*
4963 * Wait for job to finish. 5276 * Wait for job to finish.
@@ -5149,6 +5462,7 @@ openhere(union node *redir)
5149{ 5462{
5150 int pip[2]; 5463 int pip[2];
5151 size_t len = 0; 5464 size_t len = 0;
5465 IF_PLATFORM_MINGW32(struct forkshell fs);
5152 5466
5153 if (pipe(pip) < 0) 5467 if (pipe(pip) < 0)
5154 ash_msg_and_raise_error("pipe call failed"); 5468 ash_msg_and_raise_error("pipe call failed");
@@ -5159,6 +5473,15 @@ openhere(union node *redir)
5159 goto out; 5473 goto out;
5160 } 5474 }
5161 } 5475 }
5476#if ENABLE_PLATFORM_MINGW32
5477 memset(&fs, 0, sizeof(fs));
5478 fs.fpid = FS_OPENHERE;
5479 fs.n = redir;
5480 fs.fd[0] = pip[0];
5481 fs.fd[1] = pip[1];
5482 if (spawn_forkshell(NULL, &fs, FORK_NOJOB) < 0)
5483 ash_msg_and_raise_error("unable to spawn shell");
5484#else
5162 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 5485 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
5163 /* child */ 5486 /* child */
5164 close(pip[0]); 5487 close(pip[0]);
@@ -5173,6 +5496,7 @@ openhere(union node *redir)
5173 expandhere(redir->nhere.doc, pip[1]); 5496 expandhere(redir->nhere.doc, pip[1]);
5174 _exit(EXIT_SUCCESS); 5497 _exit(EXIT_SUCCESS);
5175 } 5498 }
5499#endif
5176 out: 5500 out:
5177 close(pip[1]); 5501 close(pip[1]);
5178 return pip[0]; 5502 return pip[0];
@@ -5198,6 +5522,31 @@ openredirect(union node *redir)
5198 * allocated space. Do it only when we know it is safe. 5522 * allocated space. Do it only when we know it is safe.
5199 */ 5523 */
5200 fname = redir->nfile.expfname; 5524 fname = redir->nfile.expfname;
5525#if ENABLE_PLATFORM_MINGW32
5526 /* Support for /dev/null */
5527 switch (redir->nfile.type) {
5528 case NFROM:
5529 if (!strcmp(fname, "/dev/null"))
5530 return open("nul",O_RDWR);
5531 if (!strncmp(fname, "/dev/", 5)) {
5532 ash_msg("Unhandled device %s\n", fname);
5533 return -1;
5534 }
5535 break;
5536
5537 case NFROMTO:
5538 case NTO:
5539 case NCLOBBER:
5540 case NAPPEND:
5541 if (!strcmp(fname, "/dev/null"))
5542 return open("nul",O_RDWR);
5543 if (!strncmp(fname, "/dev/", 5)) {
5544 ash_msg("Unhandled device %s\n", fname);
5545 return -1;
5546 }
5547 break;
5548 }
5549#endif
5201 5550
5202 switch (redir->nfile.type) { 5551 switch (redir->nfile.type) {
5203 default: 5552 default:
@@ -5235,6 +5584,9 @@ openredirect(union node *redir)
5235 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5584 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5236 if (f < 0) 5585 if (f < 0)
5237 goto ecreate; 5586 goto ecreate;
5587#if ENABLE_PLATFORM_MINGW32
5588 lseek(f, 0, SEEK_END);
5589#endif
5238 break; 5590 break;
5239 } 5591 }
5240 5592
@@ -6045,6 +6397,7 @@ struct backcmd { /* result of evalbackcmd */
6045 int fd; /* file descriptor to read from */ 6397 int fd; /* file descriptor to read from */
6046 int nleft; /* number of chars in buffer */ 6398 int nleft; /* number of chars in buffer */
6047 char *buf; /* buffer */ 6399 char *buf; /* buffer */
6400 IF_PLATFORM_MINGW32(struct forkshell fs);
6048 struct job *jp; /* job structure for command */ 6401 struct job *jp; /* job structure for command */
6049}; 6402};
6050 6403
@@ -6061,6 +6414,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6061 result->fd = -1; 6414 result->fd = -1;
6062 result->buf = NULL; 6415 result->buf = NULL;
6063 result->nleft = 0; 6416 result->nleft = 0;
6417 IF_PLATFORM_MINGW32(memset(&result->fs, 0, sizeof(result->fs)));
6064 result->jp = NULL; 6418 result->jp = NULL;
6065 if (n == NULL) { 6419 if (n == NULL) {
6066 goto out; 6420 goto out;
@@ -6069,6 +6423,14 @@ evalbackcmd(union node *n, struct backcmd *result)
6069 if (pipe(pip) < 0) 6423 if (pipe(pip) < 0)
6070 ash_msg_and_raise_error("pipe call failed"); 6424 ash_msg_and_raise_error("pipe call failed");
6071 jp = makejob(/*n,*/ 1); 6425 jp = makejob(/*n,*/ 1);
6426#if ENABLE_PLATFORM_MINGW32
6427 result->fs.fpid = FS_EVALBACKCMD;
6428 result->fs.n = n;
6429 result->fs.fd[0] = pip[0];
6430 result->fs.fd[1] = pip[1];
6431 if (spawn_forkshell(jp, &result->fs, FORK_NOJOB) < 0)
6432 ash_msg_and_raise_error("unable to spawn shell");
6433#else
6072 if (forkshell(jp, n, FORK_NOJOB) == 0) { 6434 if (forkshell(jp, n, FORK_NOJOB) == 0) {
6073 /* child */ 6435 /* child */
6074 FORCE_INT_ON; 6436 FORCE_INT_ON;
@@ -6091,6 +6453,7 @@ evalbackcmd(union node *n, struct backcmd *result)
6091 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 6453 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6092 /* NOTREACHED */ 6454 /* NOTREACHED */
6093 } 6455 }
6456#endif
6094 /* parent */ 6457 /* parent */
6095 close(pip[1]); 6458 close(pip[1]);
6096 result->fd = pip[0]; 6459 result->fd = pip[0];
@@ -6147,7 +6510,8 @@ expbackq(union node *cmd, int flag)
6147 6510
6148 /* Eat all trailing newlines */ 6511 /* Eat all trailing newlines */
6149 dest = expdest; 6512 dest = expdest;
6150 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 6513 for (; dest > (char *)stackblock() && (dest[-1] == '\n' ||
6514 (ENABLE_PLATFORM_MINGW32 && dest[-1] == '\r'));)
6151 STUNPUTC(dest); 6515 STUNPUTC(dest);
6152 expdest = dest; 6516 expdest = dest;
6153 6517
@@ -7629,7 +7993,7 @@ shellexec(char **argv, const char *path, int idx)
7629 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ 7993 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
7630 7994
7631 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); 7995 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
7632 if (strchr(argv[0], '/') != NULL 7996 if ((strchr(argv[0], '/') || (ENABLE_PLATFORM_MINGW32 && strchr(argv[0], '\\')))
7633#if ENABLE_FEATURE_SH_STANDALONE 7997#if ENABLE_FEATURE_SH_STANDALONE
7634 || (applet_no = find_applet_by_name(argv[0])) >= 0 7998 || (applet_no = find_applet_by_name(argv[0])) >= 0
7635#endif 7999#endif
@@ -7643,6 +8007,11 @@ shellexec(char **argv, const char *path, int idx)
7643 goto try_PATH; 8007 goto try_PATH;
7644 } 8008 }
7645 e = errno; 8009 e = errno;
8010#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_SH_STANDALONE
8011 } else if (strcmp(argv[0], "busybox") == 0) {
8012 tryexec(-1, bb_busybox_exec_path, argv, envp);
8013 e = errno;
8014#endif
7646 } else { 8015 } else {
7647 try_PATH: 8016 try_PATH:
7648 e = ENOENT; 8017 e = ENOENT;
@@ -8223,10 +8592,14 @@ commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
8223#endif 8592#endif
8224 8593
8225 8594
8226/*static int funcblocksize; // size of structures in function */ 8595static int funcblocksize; /* size of structures in function */
8227/*static int funcstringsize; // size of strings in node */ 8596static int funcstringsize; /* size of strings in node */
8228static void *funcblock; /* block to allocate function from */ 8597static void *funcblock; /* block to allocate function from */
8229static char *funcstring_end; /* end of block to allocate strings from */ 8598static char *funcstring; /* block to allocate strings from */
8599#if ENABLE_PLATFORM_MINGW32
8600static int nodeptrsize;
8601static char **nodeptr;
8602#endif
8230 8603
8231/* flags in argument to evaltree */ 8604/* flags in argument to evaltree */
8232#define EV_EXIT 01 /* exit after evaluating tree */ 8605#define EV_EXIT 01 /* exit after evaluating tree */
@@ -8264,72 +8637,81 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
8264 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)), 8637 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
8265}; 8638};
8266 8639
8267static int calcsize(int funcblocksize, union node *n); 8640static void calcsize(union node *n);
8268 8641
8269static int 8642static void
8270sizenodelist(int funcblocksize, struct nodelist *lp) 8643sizenodelist(struct nodelist *lp)
8271{ 8644{
8272 while (lp) { 8645 while (lp) {
8273 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8646 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8274 funcblocksize = calcsize(funcblocksize, lp->n); 8647 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8648 calcsize(lp->n);
8275 lp = lp->next; 8649 lp = lp->next;
8276 } 8650 }
8277 return funcblocksize;
8278} 8651}
8279 8652
8280static int 8653static void
8281calcsize(int funcblocksize, union node *n) 8654calcsize(union node *n)
8282{ 8655{
8283 if (n == NULL) 8656 if (n == NULL)
8284 return funcblocksize; 8657 return;
8285 funcblocksize += nodesize[n->type]; 8658 funcblocksize += nodesize[n->type];
8286 switch (n->type) { 8659 switch (n->type) {
8287 case NCMD: 8660 case NCMD:
8288 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect); 8661 calcsize(n->ncmd.redirect);
8289 funcblocksize = calcsize(funcblocksize, n->ncmd.args); 8662 calcsize(n->ncmd.args);
8290 funcblocksize = calcsize(funcblocksize, n->ncmd.assign); 8663 calcsize(n->ncmd.assign);
8664 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8291 break; 8665 break;
8292 case NPIPE: 8666 case NPIPE:
8293 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist); 8667 sizenodelist(n->npipe.cmdlist);
8668 IF_PLATFORM_MINGW32(nodeptrsize++);
8294 break; 8669 break;
8295 case NREDIR: 8670 case NREDIR:
8296 case NBACKGND: 8671 case NBACKGND:
8297 case NSUBSHELL: 8672 case NSUBSHELL:
8298 funcblocksize = calcsize(funcblocksize, n->nredir.redirect); 8673 calcsize(n->nredir.redirect);
8299 funcblocksize = calcsize(funcblocksize, n->nredir.n); 8674 calcsize(n->nredir.n);
8675 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8300 break; 8676 break;
8301 case NAND: 8677 case NAND:
8302 case NOR: 8678 case NOR:
8303 case NSEMI: 8679 case NSEMI:
8304 case NWHILE: 8680 case NWHILE:
8305 case NUNTIL: 8681 case NUNTIL:
8306 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2); 8682 calcsize(n->nbinary.ch2);
8307 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1); 8683 calcsize(n->nbinary.ch1);
8684 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8308 break; 8685 break;
8309 case NIF: 8686 case NIF:
8310 funcblocksize = calcsize(funcblocksize, n->nif.elsepart); 8687 calcsize(n->nif.elsepart);
8311 funcblocksize = calcsize(funcblocksize, n->nif.ifpart); 8688 calcsize(n->nif.ifpart);
8312 funcblocksize = calcsize(funcblocksize, n->nif.test); 8689 calcsize(n->nif.test);
8690 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8313 break; 8691 break;
8314 case NFOR: 8692 case NFOR:
8315 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */ 8693 funcstringsize += strlen(n->nfor.var) + 1;
8316 funcblocksize = calcsize(funcblocksize, n->nfor.body); 8694 calcsize(n->nfor.body);
8317 funcblocksize = calcsize(funcblocksize, n->nfor.args); 8695 calcsize(n->nfor.args);
8696 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8318 break; 8697 break;
8319 case NCASE: 8698 case NCASE:
8320 funcblocksize = calcsize(funcblocksize, n->ncase.cases); 8699 calcsize(n->ncase.cases);
8321 funcblocksize = calcsize(funcblocksize, n->ncase.expr); 8700 calcsize(n->ncase.expr);
8701 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8322 break; 8702 break;
8323 case NCLIST: 8703 case NCLIST:
8324 funcblocksize = calcsize(funcblocksize, n->nclist.body); 8704 calcsize(n->nclist.body);
8325 funcblocksize = calcsize(funcblocksize, n->nclist.pattern); 8705 calcsize(n->nclist.pattern);
8326 funcblocksize = calcsize(funcblocksize, n->nclist.next); 8706 calcsize(n->nclist.next);
8707 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8327 break; 8708 break;
8328 case NDEFUN: 8709 case NDEFUN:
8329 case NARG: 8710 case NARG:
8330 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote); 8711 sizenodelist(n->narg.backquote);
8331 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */ 8712 funcstringsize += strlen(n->narg.text) + 1;
8332 funcblocksize = calcsize(funcblocksize, n->narg.next); 8713 calcsize(n->narg.next);
8714 IF_PLATFORM_MINGW32(nodeptrsize += 3);
8333 break; 8715 break;
8334 case NTO: 8716 case NTO:
8335#if ENABLE_ASH_BASH_COMPAT 8717#if ENABLE_ASH_BASH_COMPAT
@@ -8339,35 +8721,55 @@ calcsize(int funcblocksize, union node *n)
8339 case NFROM: 8721 case NFROM:
8340 case NFROMTO: 8722 case NFROMTO:
8341 case NAPPEND: 8723 case NAPPEND:
8342 funcblocksize = calcsize(funcblocksize, n->nfile.fname); 8724 calcsize(n->nfile.fname);
8343 funcblocksize = calcsize(funcblocksize, n->nfile.next); 8725 calcsize(n->nfile.next);
8726 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8344 break; 8727 break;
8345 case NTOFD: 8728 case NTOFD:
8346 case NFROMFD: 8729 case NFROMFD:
8347 funcblocksize = calcsize(funcblocksize, n->ndup.vname); 8730 calcsize(n->ndup.vname);
8348 funcblocksize = calcsize(funcblocksize, n->ndup.next); 8731 calcsize(n->ndup.next);
8732 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8349 break; 8733 break;
8350 case NHERE: 8734 case NHERE:
8351 case NXHERE: 8735 case NXHERE:
8352 funcblocksize = calcsize(funcblocksize, n->nhere.doc); 8736 calcsize(n->nhere.doc);
8353 funcblocksize = calcsize(funcblocksize, n->nhere.next); 8737 calcsize(n->nhere.next);
8738 IF_PLATFORM_MINGW32(nodeptrsize += 2);
8354 break; 8739 break;
8355 case NNOT: 8740 case NNOT:
8356 funcblocksize = calcsize(funcblocksize, n->nnot.com); 8741 calcsize(n->nnot.com);
8742 IF_PLATFORM_MINGW32(nodeptrsize++);
8357 break; 8743 break;
8358 }; 8744 };
8359 return funcblocksize;
8360} 8745}
8361 8746
8362static char * 8747static char *
8363nodeckstrdup(char *s) 8748nodeckstrdup(const char *s)
8364{ 8749{
8365 funcstring_end -= SHELL_ALIGN(strlen(s) + 1); 8750 char *rtn = funcstring;
8366 return strcpy(funcstring_end, s); 8751
8752 if (!s)
8753 return NULL;
8754 strcpy(funcstring, s);
8755 funcstring += strlen(s) + 1;
8756 return rtn;
8367} 8757}
8368 8758
8369static union node *copynode(union node *); 8759static union node *copynode(union node *);
8370 8760
8761#if ENABLE_PLATFORM_MINGW32
8762# define SAVE_PTR(dst) {if (nodeptr) *nodeptr++ = (char *)&(dst);}
8763# define SAVE_PTR2(dst1,dst2) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);}}
8764# define SAVE_PTR3(dst1,dst2,dst3) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);}}
8765# define SAVE_PTR4(dst1,dst2,dst3,dst4) {if (nodeptr) { *nodeptr++ = (char *)&(dst1);*nodeptr++ = (char *)&(dst2);*nodeptr++ = (char *)&(dst3);*nodeptr++ = (char *)&(dst4);}}
8766#else
8767# define SAVE_PTR(dst)
8768# define SAVE_PTR2(dst,dst2)
8769# define SAVE_PTR3(dst,dst2,dst3)
8770# define SAVE_PTR4(dst,dst2,dst3,dst4)
8771#endif
8772
8371static struct nodelist * 8773static struct nodelist *
8372copynodelist(struct nodelist *lp) 8774copynodelist(struct nodelist *lp)
8373{ 8775{
@@ -8379,6 +8781,7 @@ copynodelist(struct nodelist *lp)
8379 *lpp = funcblock; 8781 *lpp = funcblock;
8380 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 8782 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8381 (*lpp)->n = copynode(lp->n); 8783 (*lpp)->n = copynode(lp->n);
8784 SAVE_PTR2((*lpp)->n, (*lpp)->next);
8382 lp = lp->next; 8785 lp = lp->next;
8383 lpp = &(*lpp)->next; 8786 lpp = &(*lpp)->next;
8384 } 8787 }
@@ -8401,16 +8804,19 @@ copynode(union node *n)
8401 new->ncmd.redirect = copynode(n->ncmd.redirect); 8804 new->ncmd.redirect = copynode(n->ncmd.redirect);
8402 new->ncmd.args = copynode(n->ncmd.args); 8805 new->ncmd.args = copynode(n->ncmd.args);
8403 new->ncmd.assign = copynode(n->ncmd.assign); 8806 new->ncmd.assign = copynode(n->ncmd.assign);
8807 SAVE_PTR3(new->ncmd.redirect,new->ncmd.args, new->ncmd.assign);
8404 break; 8808 break;
8405 case NPIPE: 8809 case NPIPE:
8406 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8810 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8407 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd; 8811 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
8812 SAVE_PTR(new->npipe.cmdlist);
8408 break; 8813 break;
8409 case NREDIR: 8814 case NREDIR:
8410 case NBACKGND: 8815 case NBACKGND:
8411 case NSUBSHELL: 8816 case NSUBSHELL:
8412 new->nredir.redirect = copynode(n->nredir.redirect); 8817 new->nredir.redirect = copynode(n->nredir.redirect);
8413 new->nredir.n = copynode(n->nredir.n); 8818 new->nredir.n = copynode(n->nredir.n);
8819 SAVE_PTR2(new->nredir.redirect,new->nredir.n);
8414 break; 8820 break;
8415 case NAND: 8821 case NAND:
8416 case NOR: 8822 case NOR:
@@ -8419,31 +8825,37 @@ copynode(union node *n)
8419 case NUNTIL: 8825 case NUNTIL:
8420 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8826 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8421 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8827 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8828 SAVE_PTR2(new->nbinary.ch1,new->nbinary.ch2);
8422 break; 8829 break;
8423 case NIF: 8830 case NIF:
8424 new->nif.elsepart = copynode(n->nif.elsepart); 8831 new->nif.elsepart = copynode(n->nif.elsepart);
8425 new->nif.ifpart = copynode(n->nif.ifpart); 8832 new->nif.ifpart = copynode(n->nif.ifpart);
8426 new->nif.test = copynode(n->nif.test); 8833 new->nif.test = copynode(n->nif.test);
8834 SAVE_PTR3(new->nif.elsepart,new->nif.ifpart,new->nif.test);
8427 break; 8835 break;
8428 case NFOR: 8836 case NFOR:
8429 new->nfor.var = nodeckstrdup(n->nfor.var); 8837 new->nfor.var = nodeckstrdup(n->nfor.var);
8430 new->nfor.body = copynode(n->nfor.body); 8838 new->nfor.body = copynode(n->nfor.body);
8431 new->nfor.args = copynode(n->nfor.args); 8839 new->nfor.args = copynode(n->nfor.args);
8840 SAVE_PTR3(new->nfor.var,new->nfor.body,new->nfor.args);
8432 break; 8841 break;
8433 case NCASE: 8842 case NCASE:
8434 new->ncase.cases = copynode(n->ncase.cases); 8843 new->ncase.cases = copynode(n->ncase.cases);
8435 new->ncase.expr = copynode(n->ncase.expr); 8844 new->ncase.expr = copynode(n->ncase.expr);
8845 SAVE_PTR2(new->ncase.cases,new->ncase.expr);
8436 break; 8846 break;
8437 case NCLIST: 8847 case NCLIST:
8438 new->nclist.body = copynode(n->nclist.body); 8848 new->nclist.body = copynode(n->nclist.body);
8439 new->nclist.pattern = copynode(n->nclist.pattern); 8849 new->nclist.pattern = copynode(n->nclist.pattern);
8440 new->nclist.next = copynode(n->nclist.next); 8850 new->nclist.next = copynode(n->nclist.next);
8851 SAVE_PTR3(new->nclist.body,new->nclist.pattern,new->nclist.next);
8441 break; 8852 break;
8442 case NDEFUN: 8853 case NDEFUN:
8443 case NARG: 8854 case NARG:
8444 new->narg.backquote = copynodelist(n->narg.backquote); 8855 new->narg.backquote = copynodelist(n->narg.backquote);
8445 new->narg.text = nodeckstrdup(n->narg.text); 8856 new->narg.text = nodeckstrdup(n->narg.text);
8446 new->narg.next = copynode(n->narg.next); 8857 new->narg.next = copynode(n->narg.next);
8858 SAVE_PTR3(new->narg.backquote,new->narg.text,new->narg.next);
8447 break; 8859 break;
8448 case NTO: 8860 case NTO:
8449#if ENABLE_ASH_BASH_COMPAT 8861#if ENABLE_ASH_BASH_COMPAT
@@ -8456,6 +8868,7 @@ copynode(union node *n)
8456 new->nfile.fname = copynode(n->nfile.fname); 8868 new->nfile.fname = copynode(n->nfile.fname);
8457 new->nfile.fd = n->nfile.fd; 8869 new->nfile.fd = n->nfile.fd;
8458 new->nfile.next = copynode(n->nfile.next); 8870 new->nfile.next = copynode(n->nfile.next);
8871 SAVE_PTR2(new->nfile.fname,new->nfile.next);
8459 break; 8872 break;
8460 case NTOFD: 8873 case NTOFD:
8461 case NFROMFD: 8874 case NFROMFD:
@@ -8463,15 +8876,18 @@ copynode(union node *n)
8463 new->ndup.dupfd = n->ndup.dupfd; 8876 new->ndup.dupfd = n->ndup.dupfd;
8464 new->ndup.fd = n->ndup.fd; 8877 new->ndup.fd = n->ndup.fd;
8465 new->ndup.next = copynode(n->ndup.next); 8878 new->ndup.next = copynode(n->ndup.next);
8879 SAVE_PTR2(new->ndup.vname,new->ndup.next);
8466 break; 8880 break;
8467 case NHERE: 8881 case NHERE:
8468 case NXHERE: 8882 case NXHERE:
8469 new->nhere.doc = copynode(n->nhere.doc); 8883 new->nhere.doc = copynode(n->nhere.doc);
8470 new->nhere.fd = n->nhere.fd; 8884 new->nhere.fd = n->nhere.fd;
8471 new->nhere.next = copynode(n->nhere.next); 8885 new->nhere.next = copynode(n->nhere.next);
8886 SAVE_PTR2(new->nhere.doc,new->nhere.next);
8472 break; 8887 break;
8473 case NNOT: 8888 case NNOT:
8474 new->nnot.com = copynode(n->nnot.com); 8889 new->nnot.com = copynode(n->nnot.com);
8890 SAVE_PTR(new->nnot.com);
8475 break; 8891 break;
8476 }; 8892 };
8477 new->type = n->type; 8893 new->type = n->type;
@@ -8487,13 +8903,16 @@ copyfunc(union node *n)
8487 struct funcnode *f; 8903 struct funcnode *f;
8488 size_t blocksize; 8904 size_t blocksize;
8489 8905
8490 /*funcstringsize = 0;*/ 8906 funcblocksize = offsetof(struct funcnode, n);
8491 blocksize = offsetof(struct funcnode, n) + calcsize(0, n); 8907 funcstringsize = 0;
8492 f = ckzalloc(blocksize /* + funcstringsize */); 8908 calcsize(n);
8909 blocksize = funcblocksize;
8910 f = ckmalloc(blocksize + funcstringsize);
8493 funcblock = (char *) f + offsetof(struct funcnode, n); 8911 funcblock = (char *) f + offsetof(struct funcnode, n);
8494 funcstring_end = (char *) f + blocksize; 8912 funcstring = (char *) f + blocksize;
8913 IF_PLATFORM_MINGW32(nodeptr = NULL);
8495 copynode(n); 8914 copynode(n);
8496 /* f->count = 0; - ckzalloc did it */ 8915 f->count = 0;
8497 return f; 8916 return f;
8498} 8917}
8499 8918
@@ -8833,6 +9252,7 @@ evalcase(union node *n, int flags)
8833static int 9252static int
8834evalsubshell(union node *n, int flags) 9253evalsubshell(union node *n, int flags)
8835{ 9254{
9255 IF_PLATFORM_MINGW32(struct forkshell fs;)
8836 struct job *jp; 9256 struct job *jp;
8837 int backgnd = (n->type == NBACKGND); 9257 int backgnd = (n->type == NBACKGND);
8838 int status; 9258 int status;
@@ -8842,12 +9262,22 @@ evalsubshell(union node *n, int flags)
8842 goto nofork; 9262 goto nofork;
8843 INT_OFF; 9263 INT_OFF;
8844 jp = makejob(/*n,*/ 1); 9264 jp = makejob(/*n,*/ 1);
9265#if ENABLE_PLATFORM_MINGW32
9266 memset(&fs, 0, sizeof(fs));
9267 fs.fpid = FS_EVALSUBSHELL;
9268 fs.n = n;
9269 fs.flags = flags;
9270 if (spawn_forkshell(jp, &fs, backgnd) < 0)
9271 ash_msg_and_raise_error("unable to spawn shell");
9272 if ( 0 ) {
9273#else
8845 if (forkshell(jp, n, backgnd) == 0) { 9274 if (forkshell(jp, n, backgnd) == 0) {
8846 /* child */ 9275 /* child */
8847 INT_ON; 9276 INT_ON;
8848 flags |= EV_EXIT; 9277 flags |= EV_EXIT;
8849 if (backgnd) 9278 if (backgnd)
8850 flags &= ~EV_TESTED; 9279 flags &= ~EV_TESTED;
9280#endif
8851 nofork: 9281 nofork:
8852 redirect(n->nredir.redirect, 0); 9282 redirect(n->nredir.redirect, 0);
8853 evaltreenr(n->nredir.n, flags); 9283 evaltreenr(n->nredir.n, flags);
@@ -8934,6 +9364,7 @@ expredir(union node *n)
8934static int 9364static int
8935evalpipe(union node *n, int flags) 9365evalpipe(union node *n, int flags)
8936{ 9366{
9367 IF_PLATFORM_MINGW32(struct forkshell fs;)
8937 struct job *jp; 9368 struct job *jp;
8938 struct nodelist *lp; 9369 struct nodelist *lp;
8939 int pipelen; 9370 int pipelen;
@@ -8958,6 +9389,17 @@ evalpipe(union node *n, int flags)
8958 ash_msg_and_raise_error("pipe call failed"); 9389 ash_msg_and_raise_error("pipe call failed");
8959 } 9390 }
8960 } 9391 }
9392#if ENABLE_PLATFORM_MINGW32
9393 memset(&fs, 0, sizeof(fs));
9394 fs.fpid = FS_EVALPIPE;
9395 fs.flags = flags;
9396 fs.n = lp->n;
9397 fs.fd[0] = pip[0];
9398 fs.fd[1] = pip[1];
9399 fs.fd[2] = prevfd;
9400 if (spawn_forkshell(jp, &fs, n->npipe.pipe_backgnd) < 0)
9401 ash_msg_and_raise_error("unable to spawn shell");
9402#else
8961 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) { 9403 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
8962 /* child */ 9404 /* child */
8963 INT_ON; 9405 INT_ON;
@@ -8975,6 +9417,7 @@ evalpipe(union node *n, int flags)
8975 evaltreenr(lp->n, flags); 9417 evaltreenr(lp->n, flags);
8976 /* never returns */ 9418 /* never returns */
8977 } 9419 }
9420#endif
8978 /* parent */ 9421 /* parent */
8979 if (prevfd >= 0) 9422 if (prevfd >= 0)
8980 close(prevfd); 9423 close(prevfd);
@@ -9442,6 +9885,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
9442 * as POSIX mandates */ 9885 * as POSIX mandates */
9443 return back_exitstatus; 9886 return back_exitstatus;
9444} 9887}
9888
9445static int 9889static int
9446evalcommand(union node *cmd, int flags) 9890evalcommand(union node *cmd, int flags)
9447{ 9891{
@@ -9626,6 +10070,27 @@ evalcommand(union node *cmd, int flags)
9626 * in a script or a subshell does not need forking, 10070 * in a script or a subshell does not need forking,
9627 * we can just exec it. 10071 * we can just exec it.
9628 */ 10072 */
10073#if ENABLE_PLATFORM_MINGW32
10074 if (!(flags & EV_EXIT) || trap[0]) {
10075 /* No, forking off a child is necessary */
10076 struct forkshell fs;
10077
10078 memset(&fs, 0, sizeof(fs));
10079 fs.fpid = FS_SHELLEXEC;
10080 fs.argv = argv;
10081 fs.string = (char*)path;
10082 fs.fd[0] = cmdentry.u.index;
10083 fs.strlist = varlist.list;
10084 jp = makejob(/*cmd,*/ 1);
10085 if (spawn_forkshell(jp, &fs, FORK_FG) < 0)
10086 ash_msg_and_raise_error("unable to spawn shell");
10087 status = waitforjob(jp);
10088 INT_ON;
10089 TRACE(("forked child exited with %d\n", exitstatus));
10090 break;
10091 }
10092 /* goes through to shellexec() */
10093#else
9629 if (!(flags & EV_EXIT) || may_have_traps) { 10094 if (!(flags & EV_EXIT) || may_have_traps) {
9630 /* No, forking off a child is necessary */ 10095 /* No, forking off a child is necessary */
9631 INT_OFF; 10096 INT_OFF;
@@ -9641,6 +10106,7 @@ evalcommand(union node *cmd, int flags)
9641 FORCE_INT_ON; 10106 FORCE_INT_ON;
9642 /* fall through to exec'ing external program */ 10107 /* fall through to exec'ing external program */
9643 } 10108 }
10109#endif
9644 listsetvar(varlist.list, VEXPORT|VSTACK); 10110 listsetvar(varlist.list, VEXPORT|VSTACK);
9645 shellexec(argv, path, cmdentry.u.index); 10111 shellexec(argv, path, cmdentry.u.index);
9646 /* NOTREACHED */ 10112 /* NOTREACHED */
@@ -10026,7 +10492,7 @@ preadbuffer(void)
10026 more--; 10492 more--;
10027 10493
10028 c = *q; 10494 c = *q;
10029 if (c == '\0') { 10495 if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) {
10030 memmove(q, q + 1, more); 10496 memmove(q, q + 1, more);
10031 } else { 10497 } else {
10032 q++; 10498 q++;
@@ -10213,6 +10679,7 @@ popallfiles(void)
10213 popfile(); 10679 popfile();
10214} 10680}
10215 10681
10682#if !ENABLE_PLATFORM_MINGW32
10216/* 10683/*
10217 * Close the file(s) that the shell is reading commands from. Called 10684 * Close the file(s) that the shell is reading commands from. Called
10218 * after a fork is done. 10685 * after a fork is done.
@@ -10226,6 +10693,7 @@ closescript(void)
10226 g_parsefile->pf_fd = 0; 10693 g_parsefile->pf_fd = 0;
10227 } 10694 }
10228} 10695}
10696#endif
10229 10697
10230/* 10698/*
10231 * Like setinputfile, but takes an open file descriptor. Call this with 10699 * Like setinputfile, but takes an open file descriptor. Call this with
@@ -12505,7 +12973,7 @@ find_dot_file(char *name)
12505 struct stat statb; 12973 struct stat statb;
12506 12974
12507 /* don't try this for absolute or relative paths */ 12975 /* don't try this for absolute or relative paths */
12508 if (strchr(name, '/')) 12976 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\')))
12509 return name; 12977 return name;
12510 12978
12511 /* IIRC standards do not say whether . is to be searched. 12979 /* IIRC standards do not say whether . is to be searched.
@@ -12626,10 +13094,11 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12626 struct stat statb; 13094 struct stat statb;
12627 int e; 13095 int e;
12628 int updatetbl; 13096 int updatetbl;
13097 IF_PLATFORM_MINGW32(int len;)
12629 struct builtincmd *bcmd; 13098 struct builtincmd *bcmd;
12630 13099
12631 /* If name contains a slash, don't use PATH or hash table */ 13100 /* If name contains a slash, don't use PATH or hash table */
12632 if (strchr(name, '/') != NULL) { 13101 if (strchr(name, '/') || (ENABLE_PLATFORM_MINGW32 && strchr(name, '\\'))) {
12633 entry->u.index = -1; 13102 entry->u.index = -1;
12634 if (act & DO_ABS) { 13103 if (act & DO_ABS) {
12635 while (stat(name, &statb) < 0) { 13104 while (stat(name, &statb) < 0) {
@@ -12698,7 +13167,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12698#if ENABLE_FEATURE_SH_STANDALONE 13167#if ENABLE_FEATURE_SH_STANDALONE
12699 { 13168 {
12700 int applet_no = find_applet_by_name(name); 13169 int applet_no = find_applet_by_name(name);
12701 if (applet_no >= 0) { 13170 if (applet_no >= 0 ||
13171 /* requires find_applet_by_name to return -1 on no match */
13172 (ENABLE_PLATFORM_MINGW32 && strcmp(name, "busybox") == 0)) {
12702 entry->cmdtype = CMDNORMAL; 13173 entry->cmdtype = CMDNORMAL;
12703 entry->u.index = -2 - applet_no; 13174 entry->u.index = -2 - applet_no;
12704 return; 13175 return;
@@ -12736,12 +13207,48 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12736 } 13207 }
12737 } 13208 }
12738 /* if rehash, don't redo absolute path names */ 13209 /* if rehash, don't redo absolute path names */
12739 if (fullname[0] == '/' && idx <= prev) { 13210 if (is_absolute_path(fullname) && idx <= prev) {
12740 if (idx < prev) 13211 if (idx < prev)
12741 continue; 13212 continue;
12742 TRACE(("searchexec \"%s\": no change\n", name)); 13213 TRACE(("searchexec \"%s\": no change\n", name));
12743 goto success; 13214 goto success;
12744 } 13215 }
13216#if ENABLE_PLATFORM_MINGW32
13217 len = strlen(fullname);
13218 if (len > 4 &&
13219 (!strcasecmp(fullname+len-4, ".exe") ||
13220 !strcasecmp(fullname+len-4, ".com"))) {
13221 if (stat(fullname, &statb) < 0) {
13222 if (errno != ENOENT && errno != ENOTDIR)
13223 e = errno;
13224 goto loop;
13225 }
13226 }
13227 else {
13228 /* path_advance() has reserved space for .exe */
13229 memcpy(fullname+len, ".exe", 5);
13230 if (stat(fullname, &statb) < 0) {
13231 if (errno != ENOENT && errno != ENOTDIR)
13232 e = errno;
13233 memcpy(fullname+len, ".com", 5);
13234 if (stat(fullname, &statb) < 0) {
13235 if (errno != ENOENT && errno != ENOTDIR)
13236 e = errno;
13237 fullname[len] = '\0';
13238 if (stat(fullname, &statb) < 0) {
13239 if (errno != ENOENT && errno != ENOTDIR)
13240 e = errno;
13241 goto loop;
13242 }
13243 if (!file_is_executable(fullname)) {
13244 e = ENOEXEC;
13245 goto loop;
13246 }
13247 }
13248 }
13249 fullname[len] = '\0';
13250 }
13251#else
12745 while (stat(fullname, &statb) < 0) { 13252 while (stat(fullname, &statb) < 0) {
12746#ifdef SYSV 13253#ifdef SYSV
12747 if (errno == EINTR) 13254 if (errno == EINTR)
@@ -12751,6 +13258,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
12751 e = errno; 13258 e = errno;
12752 goto loop; 13259 goto loop;
12753 } 13260 }
13261#endif
12754 e = EACCES; /* if we fail, this will be the error */ 13262 e = EACCES; /* if we fail, this will be the error */
12755 if (!S_ISREG(statb.st_mode)) 13263 if (!S_ISREG(statb.st_mode))
12756 continue; 13264 continue;
@@ -13258,7 +13766,11 @@ exitshell(void)
13258} 13766}
13259 13767
13260static void 13768static void
13769#if ENABLE_PLATFORM_MINGW32
13770init(int xp)
13771#else
13261init(void) 13772init(void)
13773#endif
13262{ 13774{
13263 /* we will never free this */ 13775 /* we will never free this */
13264 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 13776 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
@@ -13277,6 +13789,86 @@ init(void)
13277 struct stat st1, st2; 13789 struct stat st1, st2;
13278 13790
13279 initvar(); 13791 initvar();
13792
13793#if ENABLE_PLATFORM_MINGW32
13794 /*
13795 * case insensitive env names from Windows world
13796 *
13797 * Some standard env names such as PATH is named Path and so on
13798 * ash itself is case sensitive, so "Path" will confuse it, as
13799 * MSVC getenv() is case insensitive.
13800 *
13801 * We may end up having both Path and PATH. Then Path will be chosen
13802 * because it appears first.
13803 */
13804 for (envp = environ; envp && *envp; envp++) {
13805 if (strncasecmp(*envp, "PATH=", 5) == 0 &&
13806 strncmp(*envp, "PATH=", 5) != 0) {
13807 break;
13808 }
13809 }
13810
13811 if (envp && *envp) {
13812 /*
13813 * If we get here it's because the environment contains a path
13814 * variable called something other than PATH. This suggests we
13815 * haven't been invoked from an earlier instance of BusyBox.
13816 */
13817 char *start, *end, *s;
13818 struct passwd *pw;
13819
13820 for (envp = environ; envp && *envp; envp++) {
13821 if (!(end=strchr(*envp, '=')))
13822 continue;
13823
13824 /* make all variable names uppercase */
13825 for (start = *envp;start < end;start++)
13826 *start = toupper(*start);
13827
13828 /* skip conversion of variables known to cause problems */
13829 if ( strncmp(*envp, "SYSTEMROOT=", 11) == 0 ||
13830 strncmp(*envp, "COMSPEC=", 8) == 0 ) {
13831 continue;
13832 }
13833
13834 /* convert backslashes to forward slashes in value */
13835 if (!xp) {
13836 for ( s=end+1; *s; ++s ) {
13837 if ( *s == '\\' ) {
13838 *s = '/';
13839 }
13840 }
13841 }
13842
13843 /* check for invalid characters in name */
13844 for (start = *envp;start < end;start++) {
13845 if (!isdigit(*start) && !isalpha(*start) && *start != '_') {
13846 break;
13847 }
13848 }
13849
13850 if (start != end) {
13851 /*
13852 * Make a copy of the variable, replacing invalid
13853 * characters in the name with underscores.
13854 */
13855 char *var = xstrdup(*envp);
13856
13857 for (start = var;*start != '=';start++) {
13858 if (!isdigit(*start) && !isalpha(*start)) {
13859 *start = '_';
13860 }
13861 }
13862 setvareq(var, VEXPORT|VNOSAVE);
13863 }
13864 }
13865
13866 /* some initialisation normally performed at login */
13867 pw = xgetpwuid(getuid());
13868 setup_environment(pw->pw_shell,
13869 SETUP_ENV_CHANGEENV|SETUP_ENV_NO_CHDIR, pw);
13870 }
13871#endif
13280 for (envp = environ; envp && *envp; envp++) { 13872 for (envp = environ; envp && *envp; envp++) {
13281 p = endofname(*envp); 13873 p = endofname(*envp);
13282 if (p != *envp && *p == '=') { 13874 if (p != *envp && *p == '=') {
@@ -13479,19 +14071,45 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13479 exception_handler = &jmploc; 14071 exception_handler = &jmploc;
13480 rootpid = getpid(); 14072 rootpid = getpid();
13481 14073
13482 init(); 14074 init(IF_PLATFORM_MINGW32(argc >= 2 && strcmp(argv[1], "-X") == 0));
13483 setstackmark(&smark); 14075 setstackmark(&smark);
14076
14077#if ENABLE_PLATFORM_MINGW32
14078 hSIGINT = CreateEvent(NULL, TRUE, FALSE, NULL);
14079 SetConsoleCtrlHandler(ctrl_handler, TRUE);
14080 if (argc == 3 && !strcmp(argv[1], "--forkshell")) {
14081 forkshell_init(argv[2]);
14082
14083 /* NOTREACHED */
14084 bb_error_msg_and_die("subshell ended unexpectedly");
14085 }
14086#endif
13484 procargs(argv); 14087 procargs(argv);
13485#if DEBUG 14088#if DEBUG
13486 TRACE(("Shell args: ")); 14089 TRACE(("Shell args: "));
13487 trace_puts_args(argv); 14090 trace_puts_args(argv);
13488#endif 14091#endif
13489 14092
14093#if ENABLE_PLATFORM_MINGW32
14094 if ( noconsole ) {
14095 DWORD dummy;
14096
14097 if ( GetConsoleProcessList(&dummy, 1) == 1 ) {
14098 ShowWindow(GetConsoleWindow(), SW_HIDE);
14099 }
14100 }
14101#endif
14102
13490 if (argv[0] && argv[0][0] == '-') 14103 if (argv[0] && argv[0][0] == '-')
13491 isloginsh = 1; 14104 isloginsh = 1;
13492 if (isloginsh) { 14105 if (isloginsh) {
13493 const char *hp; 14106 const char *hp;
13494 14107
14108#if ENABLE_PLATFORM_MINGW32
14109 chdir(xgetpwuid(getuid())->pw_dir);
14110 setpwd(NULL, 0);
14111#endif
14112
13495 state = 1; 14113 state = 1;
13496 read_profile("/etc/profile"); 14114 read_profile("/etc/profile");
13497 state1: 14115 state1:
@@ -13564,6 +14182,641 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
13564 /* NOTREACHED */ 14182 /* NOTREACHED */
13565} 14183}
13566 14184
14185#if ENABLE_PLATFORM_MINGW32
14186static void
14187forkshell_openhere(struct forkshell *fs)
14188{
14189 union node *redir = fs->n;
14190 int pip[2];
14191
14192 pip[0] = fs->fd[0];
14193 pip[1] = fs->fd[1];
14194
14195 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14196
14197 close(pip[0]);
14198 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
14199 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
14200 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
14201 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
14202 signal(SIGPIPE, SIG_DFL);
14203 if (redir->type == NHERE) {
14204 size_t len = strlen(redir->nhere.doc->narg.text);
14205 full_write(pip[1], redir->nhere.doc->narg.text, len);
14206 } else /* NXHERE */
14207 expandhere(redir->nhere.doc, pip[1]);
14208 _exit(EXIT_SUCCESS);
14209}
14210
14211static void
14212forkshell_evalbackcmd(struct forkshell *fs)
14213{
14214 union node *n = fs->n;
14215 int pip[2] = {fs->fd[0], fs->fd[1]};
14216
14217 FORCE_INT_ON;
14218 close(pip[0]);
14219 if (pip[1] != 1) {
14220 /*close(1);*/
14221 dup2_or_raise(pip[1], 1);
14222 close(pip[1]);
14223 }
14224 eflag = 0;
14225 evaltree(n, EV_EXIT); /* actually evaltreenr... */
14226 /* NOTREACHED */
14227}
14228
14229static void
14230forkshell_evalsubshell(struct forkshell *fs)
14231{
14232 union node *n = fs->n;
14233 int flags = fs->flags;
14234
14235 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14236 INT_ON;
14237 flags |= EV_EXIT;
14238 expredir(n->nredir.redirect);
14239 redirect(n->nredir.redirect, 0);
14240 evaltreenr(n->nredir.n, flags);
14241 /* never returns */
14242}
14243
14244static void
14245forkshell_evalpipe(struct forkshell *fs)
14246{
14247 union node *n = fs->n;
14248 int flags = fs->flags;
14249 int prevfd = fs->fd[2];
14250 int pip[2] = {fs->fd[0], fs->fd[1]};
14251
14252 TRACE(("ash: subshell: %s\n",__PRETTY_FUNCTION__));
14253 INT_ON;
14254 if (pip[1] >= 0) {
14255 close(pip[0]);
14256 }
14257 if (prevfd > 0) {
14258 dup2(prevfd, 0);
14259 close(prevfd);
14260 }
14261 if (pip[1] > 1) {
14262 dup2(pip[1], 1);
14263 close(pip[1]);
14264 }
14265 evaltreenr(n, flags);
14266}
14267
14268static void
14269forkshell_shellexec(struct forkshell *fs)
14270{
14271 int idx = fs->fd[0];
14272 struct strlist *varlist = fs->strlist;
14273 char **argv = fs->argv;
14274 char *path = fs->string;
14275
14276 listsetvar(varlist, VEXPORT|VSTACK);
14277 shellexec(argv, path, idx);
14278}
14279
14280static void
14281forkshell_child(struct forkshell *fs)
14282{
14283 switch ( fs->fpid ) {
14284 case FS_OPENHERE:
14285 forkshell_openhere(fs);
14286 break;
14287 case FS_EVALBACKCMD:
14288 forkshell_evalbackcmd(fs);
14289 break;
14290 case FS_EVALSUBSHELL:
14291 forkshell_evalsubshell(fs);
14292 break;
14293 case FS_EVALPIPE:
14294 forkshell_evalpipe(fs);
14295 break;
14296 case FS_SHELLEXEC:
14297 forkshell_shellexec(fs);
14298 break;
14299 }
14300}
14301
14302/*
14303 * Reset the pointers to the builtin environment variables in the hash
14304 * table to point to varinit rather than the bogus copy created during
14305 * forkshell_prepare.
14306 */
14307static void
14308reinitvar(void)
14309{
14310 struct var *vp;
14311 struct var *end;
14312 struct var **vpp;
14313 struct var **old;
14314
14315 vp = varinit;
14316 end = vp + ARRAY_SIZE(varinit);
14317 do {
14318 vpp = hashvar(vp->var_text);
14319 if ( (old=findvar(vpp, vp->var_text)) != NULL ) {
14320 vp->next = (*old)->next;
14321 *old = vp;
14322 }
14323 } while (++vp < end);
14324}
14325
14326/* FIXME: should consider running forkparent() and forkchild() */
14327static int
14328spawn_forkshell(struct job *jp, struct forkshell *fs, int mode)
14329{
14330 struct forkshell *new;
14331 char buf[16];
14332 const char *argv[] = { "sh", "--forkshell", NULL, NULL };
14333 intptr_t ret;
14334
14335 new = forkshell_prepare(fs);
14336 sprintf(buf, "%x", (unsigned int)new->hMapFile);
14337 argv[2] = buf;
14338 ret = mingw_spawn_proc(argv);
14339 CloseHandle(new->hMapFile);
14340 UnmapViewOfFile(new);
14341 if (ret == -1) {
14342 free(jp);
14343 return -1;
14344 }
14345 forkparent(jp, fs->node, mode, (HANDLE)ret);
14346 return ret == -1 ? -1 : 0;
14347}
14348
14349/*
14350 * forkshell_prepare() and friends
14351 *
14352 * The sequence is as follows:
14353 * - funcblocksize, funcstringsize, nodeptrsize are initialized
14354 * - forkshell_size(fs) is called to calculate the exact memory needed
14355 * - a new struct is allocated
14356 * - funcblock, funcstring, nodeptr are initialized from the new block
14357 * - forkshell_copy(fs) is called to copy recursively everything over
14358 * it will record all pointers along the way, to nodeptr
14359 *
14360 * When this memory is mapped elsewhere, pointer fixup will be needed
14361 */
14362#define SLIST_SIZE_BEGIN(name,type) \
14363static void \
14364name(type *p) \
14365{ \
14366 while (p) { \
14367 funcblocksize += sizeof(type);
14368 /* do something here with p */
14369#define SLIST_SIZE_END() \
14370 nodeptrsize++; \
14371 p = p->next; \
14372 } \
14373}
14374
14375#define SLIST_COPY_BEGIN(name,type) \
14376static type * \
14377name(type *vp) \
14378{ \
14379 type *start; \
14380 type **vpp; \
14381 vpp = &start; \
14382 while (vp) { \
14383 *vpp = funcblock; \
14384 funcblock = (char *) funcblock + sizeof(type);
14385 /* do something here with vpp and vp */
14386#define SLIST_COPY_END() \
14387 SAVE_PTR((*vpp)->next); \
14388 vp = vp->next; \
14389 vpp = &(*vpp)->next; \
14390 } \
14391 *vpp = NULL; \
14392 return start; \
14393}
14394
14395/*
14396 * struct var
14397 */
14398SLIST_SIZE_BEGIN(var_size,struct var)
14399funcstringsize += strlen(p->var_text) + 1;
14400nodeptrsize++; /* p->text */
14401SLIST_SIZE_END()
14402
14403SLIST_COPY_BEGIN(var_copy,struct var)
14404(*vpp)->var_text = nodeckstrdup(vp->var_text);
14405(*vpp)->flags = vp->flags;
14406/*
14407 * The only place that can set struct var#func is varinit[],
14408 * which will be fixed by forkshell_init()
14409 */
14410(*vpp)->var_func = NULL;
14411SAVE_PTR((*vpp)->var_text);
14412SLIST_COPY_END()
14413
14414/*
14415 * struct strlist
14416 */
14417SLIST_SIZE_BEGIN(strlist_size,struct strlist)
14418funcstringsize += strlen(p->text) + 1;
14419nodeptrsize++; /* p->text */
14420SLIST_SIZE_END()
14421
14422SLIST_COPY_BEGIN(strlist_copy,struct strlist)
14423(*vpp)->text = nodeckstrdup(vp->text);
14424SAVE_PTR((*vpp)->text);
14425SLIST_COPY_END()
14426
14427/*
14428 * struct tblentry
14429 */
14430static void
14431tblentry_size(struct tblentry *tep)
14432{
14433 while (tep) {
14434 funcblocksize += sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14435 /* CMDBUILTIN, e->param.cmd needs no pointer relocation */
14436 if (tep->cmdtype == CMDFUNCTION) {
14437 funcblocksize += offsetof(struct funcnode, n);
14438 calcsize(&tep->param.func->n);
14439 nodeptrsize++; /* tep->param.func */
14440 }
14441 nodeptrsize++; /* tep->next */
14442 tep = tep->next;
14443 }
14444}
14445
14446static struct tblentry *
14447tblentry_copy(struct tblentry *tep)
14448{
14449 struct tblentry *start;
14450 struct tblentry **newp;
14451 int size;
14452
14453 newp = &start;
14454 while (tep) {
14455 *newp = funcblock;
14456 size = sizeof(struct tblentry) + strlen(tep->cmdname) + 1;
14457
14458 funcblock = (char *) funcblock + size;
14459 memcpy(*newp, tep, size);
14460 switch (tep->cmdtype) {
14461 case CMDBUILTIN:
14462 /* No pointer saving, this field must be fixed by forkshell_init() */
14463 (*newp)->param.cmd = (const struct builtincmd *)(tep->param.cmd - builtintab);
14464 break;
14465 case CMDFUNCTION:
14466 (*newp)->param.func = funcblock;
14467 funcblock = (char *) funcblock + offsetof(struct funcnode, n);
14468 copynode(&tep->param.func->n);
14469 SAVE_PTR((*newp)->param.func);
14470 break;
14471 default:
14472 break;
14473 }
14474 SAVE_PTR((*newp)->next);
14475 tep = tep->next;
14476 newp = &(*newp)->next;
14477 }
14478 *newp = NULL;
14479 return start;
14480}
14481
14482static void
14483cmdtable_size(struct tblentry **cmdtablep)
14484{
14485 int i;
14486 nodeptrsize += CMDTABLESIZE;
14487 funcblocksize += sizeof(struct tblentry *)*CMDTABLESIZE;
14488 for (i = 0; i < CMDTABLESIZE; i++)
14489 tblentry_size(cmdtablep[i]);
14490}
14491
14492static struct tblentry **
14493cmdtable_copy(struct tblentry **cmdtablep)
14494{
14495 struct tblentry **new = funcblock;
14496 int i;
14497
14498 funcblock = (char *) funcblock + sizeof(struct tblentry *)*CMDTABLESIZE;
14499 for (i = 0; i < CMDTABLESIZE; i++) {
14500 new[i] = tblentry_copy(cmdtablep[i]);
14501 SAVE_PTR(new[i]);
14502 }
14503 return new;
14504}
14505
14506/*
14507 * char **
14508 */
14509static void
14510argv_size(char **p)
14511{
14512 while (p && *p) {
14513 funcblocksize += sizeof(char *);
14514 funcstringsize += strlen(*p)+1;
14515 nodeptrsize++;
14516 p++;
14517 }
14518 funcblocksize += sizeof(char *);
14519}
14520
14521static char **
14522argv_copy(char **p)
14523{
14524 char **new, **start = funcblock;
14525
14526 while (p && *p) {
14527 new = funcblock;
14528 funcblock = (char *) funcblock + sizeof(char *);
14529 *new = nodeckstrdup(*p);
14530 SAVE_PTR(*new);
14531 p++;
14532 new++;
14533 }
14534 new = funcblock;
14535 funcblock = (char *) funcblock + sizeof(char *);
14536 *new = NULL;
14537 return start;
14538}
14539
14540/*
14541 * struct redirtab
14542 */
14543static void
14544redirtab_size(struct redirtab *rdtp)
14545{
14546 while (rdtp) {
14547 funcblocksize += sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14548 rdtp = rdtp->next;
14549 nodeptrsize++; /* rdtp->next */
14550 }
14551}
14552
14553static struct redirtab *
14554redirtab_copy(struct redirtab *rdtp)
14555{
14556 struct redirtab *start;
14557 struct redirtab **vpp;
14558
14559 vpp = &start;
14560 while (rdtp) {
14561 int size = sizeof(*rdtp)+sizeof(rdtp->two_fd[0])*rdtp->pair_count;
14562 *vpp = funcblock;
14563 funcblock = (char *) funcblock + size;
14564 memcpy(*vpp, rdtp, size);
14565 SAVE_PTR((*vpp)->next);
14566 rdtp = rdtp->next;
14567 vpp = &(*vpp)->next;
14568 }
14569 *vpp = NULL;
14570 return start;
14571}
14572
14573#undef shellparam
14574#undef redirlist
14575#undef varinit
14576#undef vartab
14577static void
14578globals_var_size(struct globals_var *gvp)
14579{
14580 int i;
14581
14582 funcblocksize += sizeof(struct globals_var);
14583 argv_size(gvp->shellparam.p);
14584 redirtab_size(gvp->redirlist);
14585 for (i = 0; i < VTABSIZE; i++)
14586 var_size(gvp->vartab[i]);
14587 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14588 var_size(gvp->varinit+i);
14589 nodeptrsize += 2 + VTABSIZE; /* gvp->redirlist, gvp->shellparam.p, vartab */
14590}
14591
14592#undef preverrout_fd
14593static struct globals_var *
14594globals_var_copy(struct globals_var *gvp)
14595{
14596 int i;
14597 struct globals_var *new;
14598
14599 new = funcblock;
14600 funcblock = (char *) funcblock + sizeof(struct globals_var);
14601
14602 /* shparam */
14603 memcpy(&new->shellparam, &gvp->shellparam, sizeof(struct shparam));
14604 new->shellparam.malloced = 0;
14605 new->shellparam.p = argv_copy(gvp->shellparam.p);
14606 SAVE_PTR(new->shellparam.p);
14607
14608 new->redirlist = redirtab_copy(gvp->redirlist);
14609 SAVE_PTR(new->redirlist);
14610
14611 new->preverrout_fd = gvp->preverrout_fd;
14612 for (i = 0; i < VTABSIZE; i++) {
14613 new->vartab[i] = var_copy(gvp->vartab[i]);
14614 SAVE_PTR(new->vartab[i]);
14615 }
14616
14617 /* Can't use var_copy because varinit is already allocated */
14618 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) {
14619 new->varinit[i].next = NULL;
14620 new->varinit[i].var_text = nodeckstrdup(gvp->varinit[i].var_text);
14621 SAVE_PTR(new->varinit[i].var_text);
14622 new->varinit[i].flags = gvp->varinit[i].flags;
14623 new->varinit[i].var_func = gvp->varinit[i].var_func;
14624 }
14625 return new;
14626}
14627
14628#undef minusc
14629#undef curdir
14630#undef physdir
14631#undef arg0
14632#undef nullstr
14633static void
14634globals_misc_size(struct globals_misc *p)
14635{
14636 funcblocksize += sizeof(struct globals_misc);
14637 funcstringsize += p->minusc ? strlen(p->minusc) + 1 : 1;
14638 if (p->curdir != p->nullstr)
14639 funcstringsize += strlen(p->curdir) + 1;
14640 if (p->physdir != p->nullstr)
14641 funcstringsize += strlen(p->physdir) + 1;
14642 funcstringsize += strlen(p->arg0) + 1;
14643 nodeptrsize += 4; /* minusc, curdir, physdir, arg0 */
14644}
14645
14646static struct globals_misc *
14647globals_misc_copy(struct globals_misc *p)
14648{
14649 struct globals_misc *new = funcblock;
14650
14651 funcblock = (char *) funcblock + sizeof(struct globals_misc);
14652 memcpy(new, p, sizeof(struct globals_misc));
14653
14654 new->minusc = nodeckstrdup(p->minusc);
14655 new->curdir = p->curdir != p->nullstr ? nodeckstrdup(p->curdir) : new->nullstr;
14656 new->physdir = p->physdir != p->nullstr ? nodeckstrdup(p->physdir) : new->nullstr;
14657 new->arg0 = nodeckstrdup(p->arg0);
14658 SAVE_PTR4(new->minusc, new->curdir, new->physdir, new->arg0);
14659 return new;
14660}
14661
14662static void
14663forkshell_size(struct forkshell *fs)
14664{
14665 funcblocksize += sizeof(struct forkshell);
14666 globals_var_size(fs->gvp);
14667 globals_misc_size(fs->gmp);
14668 cmdtable_size(fs->cmdtable);
14669 /* optlist_transfer(sending, fd); */
14670 /* misc_transfer(sending, fd); */
14671
14672 calcsize(fs->n);
14673 argv_size(fs->argv);
14674 funcstringsize += (fs->string ? strlen(fs->string) : 0) + 1;
14675 strlist_size(fs->strlist);
14676
14677 nodeptrsize += 7; /* gvp, gmp, cmdtable, n, argv, string, strlist */
14678}
14679
14680static struct forkshell *
14681forkshell_copy(struct forkshell *fs)
14682{
14683 struct forkshell *new;
14684
14685 new = funcblock;
14686 funcblock = (char *) funcblock + sizeof(struct forkshell);
14687
14688 memcpy(new, fs, sizeof(struct forkshell)); /* non-pointer stuff */
14689 new->gvp = globals_var_copy(fs->gvp);
14690 new->gmp = globals_misc_copy(fs->gmp);
14691 new->cmdtable = cmdtable_copy(fs->cmdtable);
14692 SAVE_PTR3(new->gvp, new->gmp, new->cmdtable);
14693
14694 new->n = copynode(fs->n);
14695 new->argv = argv_copy(fs->argv);
14696 new->string = nodeckstrdup(fs->string);
14697 new->strlist = strlist_copy(fs->strlist);
14698 SAVE_PTR4(new->n, new->argv, new->string, new->strlist);
14699 return new;
14700}
14701
14702static struct forkshell *
14703forkshell_prepare(struct forkshell *fs)
14704{
14705 struct forkshell *new;
14706 int size, nodeptr_offset;
14707 HANDLE h;
14708 SECURITY_ATTRIBUTES sa;
14709
14710 /* Calculate size of "new" */
14711 fs->gvp = ash_ptr_to_globals_var;
14712 fs->gmp = ash_ptr_to_globals_misc;
14713 fs->cmdtable = cmdtable;
14714
14715 nodeptrsize = 1; /* NULL terminated */
14716 funcblocksize = 0;
14717 funcstringsize = 0;
14718 forkshell_size(fs);
14719 size = funcblocksize + funcstringsize + nodeptrsize*sizeof(char *);
14720
14721 /* Allocate, initialize pointers */
14722 memset(&sa, 0, sizeof(sa));
14723 sa.nLength = sizeof(sa);
14724 sa.lpSecurityDescriptor = NULL;
14725 sa.bInheritHandle = TRUE;
14726 h = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, size, NULL);
14727 new = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14728 /* new = ckmalloc(size); */
14729 funcblock = new;
14730 funcstring = (char *) funcblock + funcblocksize;
14731 nodeptr = (char **)((char *)funcstring + funcstringsize);
14732 nodeptr_offset = (char *)nodeptr - (char *)new;
14733
14734 /* Now pack them all */
14735 forkshell_copy(fs);
14736
14737 /* Finish it up */
14738 *nodeptr = NULL;
14739 new->size = size;
14740 new->nodeptr_offset = nodeptr_offset;
14741 new->old_base = new;
14742 new->hMapFile = h;
14743 return new;
14744}
14745
14746#undef exception_handler
14747#undef trap
14748#undef trap_ptr
14749static void *sticky_mem_start, *sticky_mem_end;
14750static void
14751forkshell_init(const char *idstr)
14752{
14753 struct forkshell *fs;
14754 int map_handle;
14755 HANDLE h;
14756 struct globals_var **gvpp;
14757 struct globals_misc **gmpp;
14758 int i;
14759 char **ptr;
14760
14761 if (sscanf(idstr, "%x", &map_handle) != 1)
14762 bb_error_msg_and_die("invalid forkshell ID");
14763
14764 h = (HANDLE)map_handle;
14765 fs = (struct forkshell *)MapViewOfFile(h, FILE_MAP_WRITE, 0,0, 0);
14766 if (!fs)
14767 bb_error_msg_and_die("Invalid forkshell memory");
14768
14769 /* this memory can't be freed */
14770 sticky_mem_start = fs;
14771 sticky_mem_end = (char *) fs + fs->size;
14772
14773 /* pointer fixup */
14774 nodeptr = (char **)((char *)fs + fs->nodeptr_offset);
14775 for ( i=0; nodeptr[i]; ++i ) {
14776 ptr = (char **)((char *)fs + (nodeptr[i] - (char *)fs->old_base));
14777 if (*ptr)
14778 *ptr = (char *)fs + (*ptr - (char *)fs->old_base);
14779 }
14780
14781 /* Now fix up stuff that can't be transferred */
14782 for (i = 0; i < ARRAY_SIZE(varinit_data); i++)
14783 fs->gvp->varinit[i].var_func = varinit_data[i].var_func;
14784 for (i = 0; i < CMDTABLESIZE; i++) {
14785 struct tblentry *e = fs->cmdtable[i];
14786 while (e) {
14787 if (e->cmdtype == CMDBUILTIN)
14788 e->param.cmd = builtintab + (int)e->param.cmd;
14789 e = e->next;
14790 }
14791 }
14792 fs->gmp->exception_handler = ash_ptr_to_globals_misc->exception_handler;
14793 for (i = 0; i < NSIG; i++)
14794 fs->gmp->trap[i] = ash_ptr_to_globals_misc->trap[i];
14795 fs->gmp->trap_ptr = ash_ptr_to_globals_misc->trap_ptr;
14796
14797 /* Switch global variables */
14798 gvpp = (struct globals_var **)&ash_ptr_to_globals_var;
14799 *gvpp = fs->gvp;
14800 gmpp = (struct globals_misc **)&ash_ptr_to_globals_misc;
14801 *gmpp = fs->gmp;
14802 cmdtable = fs->cmdtable;
14803
14804 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
14805
14806 reinitvar();
14807
14808 forkshell_child(fs);
14809}
14810
14811#undef free
14812static void
14813sticky_free(void *base)
14814{
14815 if (base >= sticky_mem_start && base < sticky_mem_end)
14816 return;
14817 free(base);
14818}
14819#endif
13567 14820
13568/*- 14821/*-
13569 * Copyright (c) 1989, 1991, 1993, 1994 14822 * Copyright (c) 1989, 1991, 1993, 1994
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 98d862744..5a5b1780d 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 (backslash) { 213 if (backslash) {
208 backslash = 0; 214 backslash = 0;
@@ -274,6 +280,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
274 280
275/* ulimit builtin */ 281/* ulimit builtin */
276 282
283#if !ENABLE_PLATFORM_MINGW32
277struct limits { 284struct limits {
278 uint8_t cmd; /* RLIMIT_xxx fit into it */ 285 uint8_t cmd; /* RLIMIT_xxx fit into it */
279 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 286 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
@@ -498,3 +505,9 @@ shell_builtin_ulimit(char **argv)
498 505
499 return 0; 506 return 0;
500} 507}
508#else
509int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM)
510{
511 return 1;
512}
513#endif
diff --git a/util-linux/more.c b/util-linux/more.c
index 934b30f8a..d04c17f90 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
@@ -100,9 +103,13 @@ int more_main(int argc UNUSED_PARAM, char **argv)
100 * is not a tty and turns into cat. This makes sense. */ 103 * is not a tty and turns into cat. This makes sense. */
101 if (!isatty(STDOUT_FILENO)) 104 if (!isatty(STDOUT_FILENO))
102 return bb_cat(argv); 105 return bb_cat(argv);
106#if !ENABLE_PLATFORM_MINGW32
103 cin = fopen_for_read(CURRENT_TTY); 107 cin = fopen_for_read(CURRENT_TTY);
104 if (!cin) 108 if (!cin)
105 return bb_cat(argv); 109 return bb_cat(argv);
110#else
111 cin = stdin;
112#endif
106 113
107 if (ENABLE_FEATURE_USE_TERMIOS) { 114 if (ENABLE_FEATURE_USE_TERMIOS) {
108 cin_fileno = fileno(cin); 115 cin_fileno = fileno(cin);
@@ -158,7 +165,11 @@ int more_main(int argc UNUSED_PARAM, char **argv)
158 * to get input from the user. 165 * to get input from the user.
159 */ 166 */
160 for (;;) { 167 for (;;) {
168#if !ENABLE_PLATFORM_MINGW32
161 input = getc(cin); 169 input = getc(cin);
170#else
171 input = _getch();
172#endif
162 input = tolower(input); 173 input = tolower(input);
163 if (!ENABLE_FEATURE_USE_TERMIOS) 174 if (!ENABLE_FEATURE_USE_TERMIOS)
164 printf("\033[A"); /* cursor up */ 175 printf("\033[A"); /* cursor up */
@@ -172,6 +183,10 @@ int more_main(int argc UNUSED_PARAM, char **argv)
172 * commands, else we show help msg. */ 183 * commands, else we show help msg. */
173 if (input == ' ' || input == '\n' || input == 'q' || input == 'r') 184 if (input == ' ' || input == '\n' || input == 'q' || input == 'r')
174 break; 185 break;
186#if ENABLE_PLATFORM_MINGW32
187 if (input == '\r')
188 break;
189#endif
175 len = printf("(Enter:next line Space:next page Q:quit R:show the rest)"); 190 len = printf("(Enter:next line Space:next page Q:quit R:show the rest)");
176 } 191 }
177 len = 0; 192 len = 0;
@@ -212,6 +227,10 @@ int more_main(int argc UNUSED_PARAM, char **argv)
212 * will move us to a new line. */ 227 * will move us to a new line. */
213 if (++lines >= terminal_height || input == '\n') 228 if (++lines >= terminal_height || input == '\n')
214 please_display_more_prompt = 1; 229 please_display_more_prompt = 1;
230#if ENABLE_PLATFORM_MINGW32
231 if (input == '\r')
232 please_display_more_prompt = 1;
233#endif
215 len = 0; 234 len = 0;
216 } 235 }
217 if (c != '\n' && wrap) { 236 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..23ca5d3dd
--- /dev/null
+++ b/win32/mingw.c
@@ -0,0 +1,1046 @@
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
455/*
456 * Windows' mktemp returns NULL on error whereas POSIX always returns the
457 * template and signals an error by making it an empty string.
458 */
459#undef mktemp
460char *mingw_mktemp(char *template)
461{
462 if ( mktemp(template) == NULL ) {
463 template[0] = '\0';
464 }
465
466 return template;
467}
468
469int mkstemp(char *template)
470{
471 char *filename = mktemp(template);
472 if (filename == NULL)
473 return -1;
474 return open(filename, O_RDWR | O_CREAT, 0600);
475}
476
477int gettimeofday(struct timeval *tv, void *tz UNUSED_PARAM)
478{
479 FILETIME ft;
480 long long hnsec;
481
482 GetSystemTimeAsFileTime(&ft);
483 hnsec = filetime_to_hnsec(&ft);
484 tv->tv_sec = hnsec / 10000000;
485 tv->tv_usec = (hnsec % 10000000) / 10;
486 return 0;
487}
488
489int pipe(int filedes[2])
490{
491 if (_pipe(filedes, PIPE_BUF, 0) < 0)
492 return -1;
493 return 0;
494}
495
496struct tm *gmtime_r(const time_t *timep, struct tm *result)
497{
498 /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */
499 memcpy(result, gmtime(timep), sizeof(struct tm));
500 return result;
501}
502
503struct tm *localtime_r(const time_t *timep, struct tm *result)
504{
505 /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */
506 memcpy(result, localtime(timep), sizeof(struct tm));
507 return result;
508}
509
510#undef getcwd
511char *mingw_getcwd(char *pointer, int len)
512{
513 int i;
514 char *ret = getcwd(pointer, len);
515 if (!ret)
516 return ret;
517 for (i = 0; ret[i]; i++)
518 if (ret[i] == '\\')
519 ret[i] = '/';
520 return ret;
521}
522
523#undef rename
524int mingw_rename(const char *pold, const char *pnew)
525{
526 DWORD attrs;
527
528 /*
529 * Try native rename() first to get errno right.
530 * It is based on MoveFile(), which cannot overwrite existing files.
531 */
532 if (!rename(pold, pnew))
533 return 0;
534 if (errno != EEXIST)
535 return -1;
536 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
537 return 0;
538 /* TODO: translate more errors */
539 if (GetLastError() == ERROR_ACCESS_DENIED &&
540 (attrs = GetFileAttributes(pnew)) != INVALID_FILE_ATTRIBUTES) {
541 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
542 errno = EISDIR;
543 return -1;
544 }
545 if ((attrs & FILE_ATTRIBUTE_READONLY) &&
546 SetFileAttributes(pnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
547 if (MoveFileEx(pold, pnew, MOVEFILE_REPLACE_EXISTING))
548 return 0;
549 /* revert file attributes on failure */
550 SetFileAttributes(pnew, attrs);
551 }
552 }
553 errno = EACCES;
554 return -1;
555}
556
557static char *gethomedir(void)
558{
559 static char buf[PATH_MAX];
560 DWORD len = sizeof(buf);
561 HANDLE h;
562 char *s;
563
564 buf[0] = '\0';
565 if ( !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h) )
566 return buf;
567
568 if ( !GetUserProfileDirectory(h, buf, &len) ) {
569 CloseHandle(h);
570 return buf;
571 }
572
573 CloseHandle(h);
574
575 for ( s=buf; *s; ++s ) {
576 if ( *s == '\\' ) {
577 *s = '/';
578 }
579 }
580
581 return buf;
582}
583
584static char *get_user_name(void)
585{
586 static char user_name[100] = "";
587 char *s;
588 DWORD len = sizeof(user_name);
589
590 if ( user_name[0] != '\0' ) {
591 return user_name;
592 }
593
594 if ( !GetUserName(user_name, &len) ) {
595 return NULL;
596 }
597
598 for ( s=user_name; *s; ++s ) {
599 if ( *s == ' ' ) {
600 *s = '_';
601 }
602 }
603
604 return user_name;
605}
606
607struct passwd *getpwnam(const char *name)
608{
609 const char *myname;
610
611 if ( (myname=get_user_name()) != NULL &&
612 strcmp(myname, name) == 0 ) {
613 return getpwuid(DEFAULT_UID);
614 }
615
616 return NULL;
617}
618
619struct passwd *getpwuid(uid_t uid UNUSED_PARAM)
620{
621 static struct passwd p;
622
623 if ( (p.pw_name=get_user_name()) == NULL ) {
624 return NULL;
625 }
626 p.pw_passwd = (char *)"secret";
627 p.pw_gecos = (char *)"unknown";
628 p.pw_dir = gethomedir();
629 p.pw_shell = NULL;
630 p.pw_uid = DEFAULT_UID;
631 p.pw_gid = DEFAULT_GID;
632
633 return &p;
634}
635
636struct group *getgrgid(gid_t gid UNUSED_PARAM)
637{
638 static char *members[2] = { NULL, NULL };
639 static struct group g;
640
641 if ( (g.gr_name=get_user_name()) == NULL ) {
642 return NULL;
643 }
644 g.gr_passwd = (char *)"secret";
645 g.gr_gid = DEFAULT_GID;
646 members[0] = g.gr_name;
647 g.gr_mem = members;
648
649 return &g;
650}
651
652int getgrouplist(const char *user UNUSED_PARAM, gid_t group UNUSED_PARAM,
653 gid_t *groups, int *ngroups)
654{
655 if ( *ngroups == 0 ) {
656 *ngroups = 1;
657 return -1;
658 }
659
660 *ngroups = 1;
661 groups[0] = DEFAULT_GID;
662 return 1;
663}
664
665int getgroups(int n, gid_t *groups)
666{
667 if ( n == 0 ) {
668 return 1;
669 }
670
671 groups[0] = DEFAULT_GID;
672 return 1;
673}
674
675int getlogin_r(char *buf, size_t len)
676{
677 char *name;
678
679 if ( (name=get_user_name()) == NULL ) {
680 return -1;
681 }
682
683 if ( strlen(name) >= len ) {
684 errno = ERANGE;
685 return -1;
686 }
687
688 strcpy(buf, name);
689 return 0;
690}
691
692long sysconf(int name)
693{
694 if ( name == _SC_CLK_TCK ) {
695 return 100;
696 }
697 errno = EINVAL;
698 return -1;
699}
700
701clock_t times(struct tms *buf)
702{
703 buf->tms_utime = 0;
704 buf->tms_stime = 0;
705 buf->tms_cutime = 0;
706 buf->tms_cstime = 0;
707
708 return 0;
709}
710
711int link(const char *oldpath, const char *newpath)
712{
713 typedef BOOL (WINAPI *T)(const char*, const char*, LPSECURITY_ATTRIBUTES);
714 static T create_hard_link = NULL;
715 if (!create_hard_link) {
716 create_hard_link = (T) GetProcAddress(
717 GetModuleHandle("kernel32.dll"), "CreateHardLinkA");
718 if (!create_hard_link)
719 create_hard_link = (T)-1;
720 }
721 if (create_hard_link == (T)-1) {
722 errno = ENOSYS;
723 return -1;
724 }
725 if (!create_hard_link(newpath, oldpath, NULL)) {
726 errno = err_win_to_posix(GetLastError());
727 return -1;
728 }
729 return 0;
730}
731
732char *realpath(const char *path, char *resolved_path)
733{
734 /* FIXME: need normalization */
735 return strcpy(resolved_path, path);
736}
737
738const char *get_busybox_exec_path(void)
739{
740 static char path[PATH_MAX] = "";
741
742 if (!*path)
743 GetModuleFileName(NULL, path, PATH_MAX);
744 return path;
745}
746
747#undef mkdir
748int mingw_mkdir(const char *path, int mode UNUSED_PARAM)
749{
750 int ret;
751 struct stat st;
752 int lerrno = 0;
753
754 if ( (ret=mkdir(path)) < 0 ) {
755 lerrno = errno;
756 if ( lerrno == EACCES && stat(path, &st) == 0 ) {
757 ret = 0;
758 lerrno = 0;
759 }
760 }
761
762 errno = lerrno;
763 return ret;
764}
765
766#undef chmod
767int mingw_chmod(const char *path, int mode)
768{
769 WIN32_FILE_ATTRIBUTE_DATA fdata;
770
771 if ( get_file_attr(path, &fdata) == 0 &&
772 fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
773 mode |= 0222;
774 }
775
776 return chmod(path, mode);
777}
778
779int fcntl(int fd, int cmd, ...)
780{
781 va_list arg;
782 int result = -1;
783 char *fds;
784 int target, i, newfd;
785
786 va_start(arg, cmd);
787
788 switch (cmd) {
789 case F_GETFD:
790 case F_SETFD:
791 case F_GETFL:
792 /*
793 * Our fake F_GETFL won't matter if the return value is used as
794 * fcntl(fd, F_SETFL, ret|something);
795 * because F_SETFL isn't supported either.
796 */
797 result = 0;
798 break;
799 case F_DUPFD:
800 target = va_arg(arg, int);
801 fds = xzalloc(target);
802 while ((newfd = dup(fd)) < target && newfd >= 0) {
803 fds[newfd] = 1;
804 }
805 for (i = 0; i < target; ++i) {
806 if (fds[i]) {
807 close(i);
808 }
809 }
810 free(fds);
811 result = newfd;
812 break;
813 default:
814 errno = ENOSYS;
815 break;
816 }
817
818 va_end(arg);
819 return result;
820}
821
822#undef unlink
823int mingw_unlink(const char *pathname)
824{
825 /* read-only files cannot be removed */
826 chmod(pathname, 0666);
827 return unlink(pathname);
828}
829
830#undef strftime
831size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm)
832{
833 size_t ret;
834 char day[3];
835 char *t;
836 char *fmt, *newfmt;
837 struct tm tm2;
838 int m;
839
840 /*
841 * Emulate the '%e' and '%s' formats that Windows' strftime lacks.
842 * Happily, the string that replaces '%e' is two characters long.
843 * '%s' is a bit more complicated.
844 */
845 fmt = xstrdup(format);
846 for ( t=fmt; *t; ++t ) {
847 if ( *t == '%' ) {
848 if ( t[1] == 'e' ) {
849 if ( tm->tm_mday >= 0 && tm->tm_mday <= 99 ) {
850 sprintf(day, "%2d", tm->tm_mday);
851 }
852 else {
853 strcpy(day, " ");
854 }
855 memcpy(t++, day, 2);
856 }
857 else if ( t[1] == 's' ) {
858 *t = '\0';
859 m = t - fmt;
860 tm2 = *tm;
861 newfmt = xasprintf("%s%d%s", fmt, (int)mktime(&tm2), t+2);
862 free(fmt);
863 t = newfmt + m + 1;
864 fmt = newfmt;
865 }
866 else if ( t[1] == 'z' ) {
867 char buffer[16] = "";
868
869 *t = '\0';
870 m = t - fmt;
871 _tzset();
872 if ( tm->tm_isdst >= 0 ) {
873 int offset = (int)_timezone - (tm->tm_isdst > 0 ? 3600 : 0);
874 int hr, min;
875
876 if ( offset > 0 ) {
877 buffer[0] = '-';
878 }
879 else {
880 buffer[0] = '+';
881 offset = -offset;
882 }
883
884 hr = offset / 3600;
885 min = (offset % 3600) / 60;
886 sprintf(buffer+1, "%02d%02d", hr, min);
887 }
888 newfmt = xasprintf("%s%s%s", fmt, buffer, t+2);
889 free(fmt);
890 t = newfmt + m + 1;
891 fmt = newfmt;
892 }
893 else if ( t[1] != '\0' ) {
894 ++t;
895 }
896 }
897 }
898
899 ret = strftime(buf, max, fmt, tm);
900 free(fmt);
901
902 return ret;
903}
904
905int stime(time_t *t UNUSED_PARAM)
906{
907 errno = EPERM;
908 return -1;
909}
910
911#undef access
912int mingw_access(const char *name, int mode)
913{
914 int ret;
915 struct stat s;
916 int fd, n, sig;
917 unsigned int offset;
918 unsigned char buf[1024];
919
920 /* Windows can only handle test for existence, read or write */
921 if (mode == F_OK || (mode & ~X_OK)) {
922 ret = _access(name, mode & ~X_OK);
923 if (ret < 0 || !(mode & X_OK)) {
924 return ret;
925 }
926 }
927
928 if (!mingw_stat(name, &s) && S_ISREG(s.st_mode)) {
929
930 /* stat marks .exe and .com files as executable */
931 if ((s.st_mode&S_IEXEC)) {
932 return 0;
933 }
934
935 fd = open(name, O_RDONLY);
936 if (fd < 0)
937 return -1;
938 n = read(fd, buf, sizeof(buf)-1);
939 close(fd);
940 if (n < 4) /* at least '#!/x' and not error */
941 return -1;
942
943 /* shell script */
944 if (buf[0] == '#' && buf[1] == '!') {
945 return 0;
946 }
947
948 /*
949 * Poke about in file to see if it's a PE binary. I've just copied
950 * the magic from the file command.
951 */
952 if (buf[0] == 'M' && buf[1] == 'Z') {
953 offset = (buf[0x19] << 8) + buf[0x18];
954 if (offset > 0x3f) {
955 offset = (buf[0x3f] << 24) + (buf[0x3e] << 16) +
956 (buf[0x3d] << 8) + buf[0x3c];
957 if (offset < sizeof(buf)-100) {
958 if (memcmp(buf+offset, "PE\0\0", 4) == 0) {
959 sig = (buf[offset+25] << 8) + buf[offset+24];
960 if (sig == 0x10b || sig == 0x20b) {
961 sig = (buf[offset+23] << 8) + buf[offset+22];
962 if ((sig & 0x2000) != 0) {
963 /* DLL */
964 return -1;
965 }
966 sig = buf[offset+92];
967 return !(sig == 1 || sig == 2 ||
968 sig == 3 || sig == 7);
969 }
970 }
971 }
972 }
973 }
974 }
975
976 return -1;
977}
978
979#undef rmdir
980int mingw_rmdir(const char *path)
981{
982 /* read-only directories cannot be removed */
983 chmod(path, 0666);
984 return rmdir(path);
985}
986
987/* check if path can be made into an executable by adding a suffix;
988 * return an allocated string containing the path if it can;
989 * return NULL if not.
990 *
991 * if path already has a suffix don't even bother trying
992 */
993char *file_is_win32_executable(const char *p)
994{
995 char *path;
996 int len = strlen(p);
997
998 if (len > 4 && (!strcasecmp(p+len-4, ".exe") ||
999 !strcasecmp(p+len-4, ".com"))) {
1000 return NULL;
1001 }
1002
1003 if ( (path=malloc(len+5)) != NULL ) {
1004 memcpy(path, p, len);
1005 memcpy(path+len, ".exe", 5);
1006 if (file_is_executable(path)) {
1007 return path;
1008 }
1009 memcpy(path+len, ".com", 5);
1010 if (file_is_executable(path)) {
1011 return path;
1012 }
1013 free(path);
1014 }
1015
1016 return NULL;
1017}
1018
1019#undef opendir
1020DIR *mingw_opendir(const char *path)
1021{
1022 char name[4];
1023
1024 if (isalpha(path[0]) && path[1] == ':' && path[2] == '\0') {
1025 strcpy(name, path);
1026 name[2] = '/';
1027 name[3] = '\0';
1028 path = name;
1029 }
1030
1031 return opendir(path);
1032}
1033
1034off_t mingw_lseek(int fd, off_t offset, int whence)
1035{
1036 HANDLE h = (HANDLE)_get_osfhandle(fd);
1037 if (h == INVALID_HANDLE_VALUE) {
1038 errno = EBADF;
1039 return -1;
1040 }
1041 if (GetFileType(h) != FILE_TYPE_DISK) {
1042 errno = ESPIPE;
1043 return -1;
1044 }
1045 return _lseeki64(fd, offset, whence);
1046}
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/regex.c b/win32/regex.c
new file mode 100644
index 000000000..2cca16934
--- /dev/null
+++ b/win32/regex.c
@@ -0,0 +1,4929 @@
1/* Extended regular expression matching and search library,
2 version 0.12.
3 (Implements POSIX draft P10003.2/D11.2, except for
4 internationalization features.)
5
6 Copyright (C) 1993 Free Software Foundation, Inc.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22/* AIX requires this to be the first thing in the file. */
23#if defined (_AIX) && !defined (REGEX_MALLOC)
24 #pragma alloca
25#endif
26
27#ifndef _GNU_SOURCE
28#define _GNU_SOURCE
29#endif
30
31/* We need this for `regex.h', and perhaps for the Emacs include files. */
32#include <sys/types.h>
33
34/* We used to test for `BSTRING' here, but only GCC and Emacs define
35 `BSTRING', as far as I know, and neither of them use this code. */
36#include <string.h>
37#ifndef bcmp
38#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
39#endif
40#ifndef bcopy
41#define bcopy(s, d, n) memcpy ((d), (s), (n))
42#endif
43#ifndef bzero
44#define bzero(s, n) memset ((s), 0, (n))
45#endif
46
47#include <stdlib.h>
48
49
50/* Define the syntax stuff for \<, \>, etc. */
51
52/* This must be nonzero for the wordchar and notwordchar pattern
53 commands in re_match_2. */
54#ifndef Sword
55#define Sword 1
56#endif
57
58#ifdef SYNTAX_TABLE
59
60extern char *re_syntax_table;
61
62#else /* not SYNTAX_TABLE */
63
64/* How many characters in the character set. */
65#define CHAR_SET_SIZE 256
66
67static char re_syntax_table[CHAR_SET_SIZE];
68
69static void
70init_syntax_once ()
71{
72 register int c;
73 static int done = 0;
74
75 if (done)
76 return;
77
78 bzero (re_syntax_table, sizeof re_syntax_table);
79
80 for (c = 'a'; c <= 'z'; c++)
81 re_syntax_table[c] = Sword;
82
83 for (c = 'A'; c <= 'Z'; c++)
84 re_syntax_table[c] = Sword;
85
86 for (c = '0'; c <= '9'; c++)
87 re_syntax_table[c] = Sword;
88
89 re_syntax_table['_'] = Sword;
90
91 done = 1;
92}
93
94#endif /* not SYNTAX_TABLE */
95
96#define SYNTAX(c) re_syntax_table[c]
97
98
99/* Get the interface, including the syntax bits. */
100#include "regex.h"
101
102/* isalpha etc. are used for the character classes. */
103#include <ctype.h>
104
105#ifndef isascii
106#define isascii(c) 1
107#endif
108
109#ifdef isblank
110#define ISBLANK(c) (isascii (c) && isblank (c))
111#else
112#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
113#endif
114#ifdef isgraph
115#define ISGRAPH(c) (isascii (c) && isgraph (c))
116#else
117#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c))
118#endif
119
120#define ISPRINT(c) (isascii (c) && isprint (c))
121#define ISDIGIT(c) (isascii (c) && isdigit (c))
122#define ISALNUM(c) (isascii (c) && isalnum (c))
123#define ISALPHA(c) (isascii (c) && isalpha (c))
124#define ISCNTRL(c) (isascii (c) && iscntrl (c))
125#define ISLOWER(c) (isascii (c) && islower (c))
126#define ISPUNCT(c) (isascii (c) && ispunct (c))
127#define ISSPACE(c) (isascii (c) && isspace (c))
128#define ISUPPER(c) (isascii (c) && isupper (c))
129#define ISXDIGIT(c) (isascii (c) && isxdigit (c))
130
131#ifndef NULL
132#define NULL 0
133#endif
134
135/* We remove any previous definition of `SIGN_EXTEND_CHAR',
136 since ours (we hope) works properly with all combinations of
137 machines, compilers, `char' and `unsigned char' argument types.
138 (Per Bothner suggested the basic approach.) */
139#undef SIGN_EXTEND_CHAR
140#if __STDC__
141#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
142#else /* not __STDC__ */
143/* As in Harbison and Steele. */
144#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
145#endif
146
147/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
148 use `alloca' instead of `malloc'. This is because using malloc in
149 re_search* or re_match* could cause memory leaks when C-g is used in
150 Emacs; also, malloc is slower and causes storage fragmentation. On
151 the other hand, malloc is more portable, and easier to debug.
152
153 Because we sometimes use alloca, some routines have to be macros,
154 not functions -- `alloca'-allocated space disappears at the end of the
155 function it is called in. */
156
157#ifdef REGEX_MALLOC
158
159#define REGEX_ALLOCATE malloc
160#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
161
162#else /* not REGEX_MALLOC */
163
164/* Emacs already defines alloca, sometimes. */
165#ifndef alloca
166
167/* Make alloca work the best possible way. */
168#ifdef __GNUC__
169#define alloca __builtin_alloca
170#else /* not __GNUC__ */
171#if HAVE_ALLOCA_H
172#include <alloca.h>
173#else /* not __GNUC__ or HAVE_ALLOCA_H */
174#ifndef _AIX /* Already did AIX, up at the top. */
175char *alloca ();
176#endif /* not _AIX */
177#endif /* not HAVE_ALLOCA_H */
178#endif /* not __GNUC__ */
179
180#endif /* not alloca */
181
182#define REGEX_ALLOCATE alloca
183
184/* Assumes a `char *destination' variable. */
185#define REGEX_REALLOCATE(source, osize, nsize) \
186 (destination = (char *) alloca (nsize), \
187 bcopy (source, destination, osize), \
188 destination)
189
190#endif /* not REGEX_MALLOC */
191
192
193/* True if `size1' is non-NULL and PTR is pointing anywhere inside
194 `string1' or just past its end. This works if PTR is NULL, which is
195 a good thing. */
196#define FIRST_STRING_P(ptr) \
197 (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
198
199/* (Re)Allocate N items of type T using malloc, or fail. */
200#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
201#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
202#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
203
204#define BYTEWIDTH 8 /* In bits. */
205
206#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
207
208#define MAX(a, b) ((a) > (b) ? (a) : (b))
209#define MIN(a, b) ((a) < (b) ? (a) : (b))
210
211typedef char boolean;
212#define false 0
213#define true 1
214
215/* These are the command codes that appear in compiled regular
216 expressions. Some opcodes are followed by argument bytes. A
217 command code can specify any interpretation whatsoever for its
218 arguments. Zero bytes may appear in the compiled regular expression.
219
220 The value of `exactn' is needed in search.c (search_buffer) in Emacs.
221 So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of
222 `exactn' we use here must also be 1. */
223
224typedef enum
225{
226 no_op = 0,
227
228 /* Followed by one byte giving n, then by n literal bytes. */
229 exactn = 1,
230
231 /* Matches any (more or less) character. */
232 anychar,
233
234 /* Matches any one char belonging to specified set. First
235 following byte is number of bitmap bytes. Then come bytes
236 for a bitmap saying which chars are in. Bits in each byte
237 are ordered low-bit-first. A character is in the set if its
238 bit is 1. A character too large to have a bit in the map is
239 automatically not in the set. */
240 charset,
241
242 /* Same parameters as charset, but match any character that is
243 not one of those specified. */
244 charset_not,
245
246 /* Start remembering the text that is matched, for storing in a
247 register. Followed by one byte with the register number, in
248 the range 0 to one less than the pattern buffer's re_nsub
249 field. Then followed by one byte with the number of groups
250 inner to this one. (This last has to be part of the
251 start_memory only because we need it in the on_failure_jump
252 of re_match_2.) */
253 start_memory,
254
255 /* Stop remembering the text that is matched and store it in a
256 memory register. Followed by one byte with the register
257 number, in the range 0 to one less than `re_nsub' in the
258 pattern buffer, and one byte with the number of inner groups,
259 just like `start_memory'. (We need the number of inner
260 groups here because we don't have any easy way of finding the
261 corresponding start_memory when we're at a stop_memory.) */
262 stop_memory,
263
264 /* Match a duplicate of something remembered. Followed by one
265 byte containing the register number. */
266 duplicate,
267
268 /* Fail unless at beginning of line. */
269 begline,
270
271 /* Fail unless at end of line. */
272 endline,
273
274 /* Succeeds if at beginning of buffer (if emacs) or at beginning
275 of string to be matched (if not). */
276 begbuf,
277
278 /* Analogously, for end of buffer/string. */
279 endbuf,
280
281 /* Followed by two byte relative address to which to jump. */
282 jump,
283
284 /* Same as jump, but marks the end of an alternative. */
285 jump_past_alt,
286
287 /* Followed by two-byte relative address of place to resume at
288 in case of failure. */
289 on_failure_jump,
290
291 /* Like on_failure_jump, but pushes a placeholder instead of the
292 current string position when executed. */
293 on_failure_keep_string_jump,
294
295 /* Throw away latest failure point and then jump to following
296 two-byte relative address. */
297 pop_failure_jump,
298
299 /* Change to pop_failure_jump if know won't have to backtrack to
300 match; otherwise change to jump. This is used to jump
301 back to the beginning of a repeat. If what follows this jump
302 clearly won't match what the repeat does, such that we can be
303 sure that there is no use backtracking out of repetitions
304 already matched, then we change it to a pop_failure_jump.
305 Followed by two-byte address. */
306 maybe_pop_jump,
307
308 /* Jump to following two-byte address, and push a dummy failure
309 point. This failure point will be thrown away if an attempt
310 is made to use it for a failure. A `+' construct makes this
311 before the first repeat. Also used as an intermediary kind
312 of jump when compiling an alternative. */
313 dummy_failure_jump,
314
315 /* Push a dummy failure point and continue. Used at the end of
316 alternatives. */
317 push_dummy_failure,
318
319 /* Followed by two-byte relative address and two-byte number n.
320 After matching N times, jump to the address upon failure. */
321 succeed_n,
322
323 /* Followed by two-byte relative address, and two-byte number n.
324 Jump to the address N times, then fail. */
325 jump_n,
326
327 /* Set the following two-byte relative address to the
328 subsequent two-byte number. The address *includes* the two
329 bytes of number. */
330 set_number_at,
331
332 wordchar, /* Matches any word-constituent character. */
333 notwordchar, /* Matches any char that is not a word-constituent. */
334
335 wordbeg, /* Succeeds if at word beginning. */
336 wordend, /* Succeeds if at word end. */
337
338 wordbound, /* Succeeds if at a word boundary. */
339 notwordbound /* Succeeds if not at a word boundary. */
340
341#ifdef emacs
342 ,before_dot, /* Succeeds if before point. */
343 at_dot, /* Succeeds if at point. */
344 after_dot, /* Succeeds if after point. */
345
346 /* Matches any character whose syntax is specified. Followed by
347 a byte which contains a syntax code, e.g., Sword. */
348 syntaxspec,
349
350 /* Matches any character whose syntax is not that specified. */
351 notsyntaxspec
352#endif /* emacs */
353} re_opcode_t;
354
355/* Common operations on the compiled pattern. */
356
357/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
358
359#define STORE_NUMBER(destination, number) \
360 do { \
361 (destination)[0] = (number) & 0377; \
362 (destination)[1] = (number) >> 8; \
363 } while (0)
364
365/* Same as STORE_NUMBER, except increment DESTINATION to
366 the byte after where the number is stored. Therefore, DESTINATION
367 must be an lvalue. */
368
369#define STORE_NUMBER_AND_INCR(destination, number) \
370 do { \
371 STORE_NUMBER (destination, number); \
372 (destination) += 2; \
373 } while (0)
374
375/* Put into DESTINATION a number stored in two contiguous bytes starting
376 at SOURCE. */
377
378#define EXTRACT_NUMBER(destination, source) \
379 do { \
380 (destination) = *(source) & 0377; \
381 (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
382 } while (0)
383
384#ifdef DEBUG
385static void
386extract_number (dest, source)
387 int *dest;
388 unsigned char *source;
389{
390 int temp = SIGN_EXTEND_CHAR (*(source + 1));
391 *dest = *source & 0377;
392 *dest += temp << 8;
393}
394
395#ifndef EXTRACT_MACROS /* To debug the macros. */
396#undef EXTRACT_NUMBER
397#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
398#endif /* not EXTRACT_MACROS */
399
400#endif /* DEBUG */
401
402/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
403 SOURCE must be an lvalue. */
404
405#define EXTRACT_NUMBER_AND_INCR(destination, source) \
406 do { \
407 EXTRACT_NUMBER (destination, source); \
408 (source) += 2; \
409 } while (0)
410
411#ifdef DEBUG
412static void
413extract_number_and_incr (destination, source)
414 int *destination;
415 unsigned char **source;
416{
417 extract_number (destination, *source);
418 *source += 2;
419}
420
421#ifndef EXTRACT_MACROS
422#undef EXTRACT_NUMBER_AND_INCR
423#define EXTRACT_NUMBER_AND_INCR(dest, src) \
424 extract_number_and_incr (&dest, &src)
425#endif /* not EXTRACT_MACROS */
426
427#endif /* DEBUG */
428
429/* If DEBUG is defined, Regex prints many voluminous messages about what
430 it is doing (if the variable `debug' is nonzero). If linked with the
431 main program in `iregex.c', you can enter patterns and strings
432 interactively. And if linked with the main program in `main.c' and
433 the other test files, you can run the already-written tests. */
434
435#ifdef DEBUG
436
437/* We use standard I/O for debugging. */
438#include <stdio.h>
439
440/* It is useful to test things that ``must'' be true when debugging. */
441#include <assert.h>
442
443static int debug = 0;
444
445#define DEBUG_STATEMENT(e) e
446#define DEBUG_PRINT1(x) if (debug) printf (x)
447#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
448#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
449#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
450#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
451 if (debug) print_partial_compiled_pattern (s, e)
452#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
453 if (debug) print_double_string (w, s1, sz1, s2, sz2)
454
455
456extern void printchar ();
457
458/* Print the fastmap in human-readable form. */
459
460void
461print_fastmap (fastmap)
462 char *fastmap;
463{
464 unsigned was_a_range = 0;
465 unsigned i = 0;
466
467 while (i < (1 << BYTEWIDTH))
468 {
469 if (fastmap[i++])
470 {
471 was_a_range = 0;
472 printchar (i - 1);
473 while (i < (1 << BYTEWIDTH) && fastmap[i])
474 {
475 was_a_range = 1;
476 i++;
477 }
478 if (was_a_range)
479 {
480 printf ("-");
481 printchar (i - 1);
482 }
483 }
484 }
485 putchar ('\n');
486}
487
488
489/* Print a compiled pattern string in human-readable form, starting at
490 the START pointer into it and ending just before the pointer END. */
491
492void
493print_partial_compiled_pattern (start, end)
494 unsigned char *start;
495 unsigned char *end;
496{
497 int mcnt, mcnt2;
498 unsigned char *p = start;
499 unsigned char *pend = end;
500
501 if (start == NULL)
502 {
503 printf ("(null)\n");
504 return;
505 }
506
507 /* Loop over pattern commands. */
508 while (p < pend)
509 {
510 switch ((re_opcode_t) *p++)
511 {
512 case no_op:
513 printf ("/no_op");
514 break;
515
516 case exactn:
517 mcnt = *p++;
518 printf ("/exactn/%d", mcnt);
519 do
520 {
521 putchar ('/');
522 printchar (*p++);
523 }
524 while (--mcnt);
525 break;
526
527 case start_memory:
528 mcnt = *p++;
529 printf ("/start_memory/%d/%d", mcnt, *p++);
530 break;
531
532 case stop_memory:
533 mcnt = *p++;
534 printf ("/stop_memory/%d/%d", mcnt, *p++);
535 break;
536
537 case duplicate:
538 printf ("/duplicate/%d", *p++);
539 break;
540
541 case anychar:
542 printf ("/anychar");
543 break;
544
545 case charset:
546 case charset_not:
547 {
548 register int c;
549
550 printf ("/charset%s",
551 (re_opcode_t) *(p - 1) == charset_not ? "_not" : "");
552
553 assert (p + *p < pend);
554
555 for (c = 0; c < *p; c++)
556 {
557 unsigned bit;
558 unsigned char map_byte = p[1 + c];
559
560 putchar ('/');
561
562 for (bit = 0; bit < BYTEWIDTH; bit++)
563 if (map_byte & (1 << bit))
564 printchar (c * BYTEWIDTH + bit);
565 }
566 p += 1 + *p;
567 break;
568 }
569
570 case begline:
571 printf ("/begline");
572 break;
573
574 case endline:
575 printf ("/endline");
576 break;
577
578 case on_failure_jump:
579 extract_number_and_incr (&mcnt, &p);
580 printf ("/on_failure_jump/0/%d", mcnt);
581 break;
582
583 case on_failure_keep_string_jump:
584 extract_number_and_incr (&mcnt, &p);
585 printf ("/on_failure_keep_string_jump/0/%d", mcnt);
586 break;
587
588 case dummy_failure_jump:
589 extract_number_and_incr (&mcnt, &p);
590 printf ("/dummy_failure_jump/0/%d", mcnt);
591 break;
592
593 case push_dummy_failure:
594 printf ("/push_dummy_failure");
595 break;
596
597 case maybe_pop_jump:
598 extract_number_and_incr (&mcnt, &p);
599 printf ("/maybe_pop_jump/0/%d", mcnt);
600 break;
601
602 case pop_failure_jump:
603 extract_number_and_incr (&mcnt, &p);
604 printf ("/pop_failure_jump/0/%d", mcnt);
605 break;
606
607 case jump_past_alt:
608 extract_number_and_incr (&mcnt, &p);
609 printf ("/jump_past_alt/0/%d", mcnt);
610 break;
611
612 case jump:
613 extract_number_and_incr (&mcnt, &p);
614 printf ("/jump/0/%d", mcnt);
615 break;
616
617 case succeed_n:
618 extract_number_and_incr (&mcnt, &p);
619 extract_number_and_incr (&mcnt2, &p);
620 printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2);
621 break;
622
623 case jump_n:
624 extract_number_and_incr (&mcnt, &p);
625 extract_number_and_incr (&mcnt2, &p);
626 printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2);
627 break;
628
629 case set_number_at:
630 extract_number_and_incr (&mcnt, &p);
631 extract_number_and_incr (&mcnt2, &p);
632 printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2);
633 break;
634
635 case wordbound:
636 printf ("/wordbound");
637 break;
638
639 case notwordbound:
640 printf ("/notwordbound");
641 break;
642
643 case wordbeg:
644 printf ("/wordbeg");
645 break;
646
647 case wordend:
648 printf ("/wordend");
649
650#ifdef emacs
651 case before_dot:
652 printf ("/before_dot");
653 break;
654
655 case at_dot:
656 printf ("/at_dot");
657 break;
658
659 case after_dot:
660 printf ("/after_dot");
661 break;
662
663 case syntaxspec:
664 printf ("/syntaxspec");
665 mcnt = *p++;
666 printf ("/%d", mcnt);
667 break;
668
669 case notsyntaxspec:
670 printf ("/notsyntaxspec");
671 mcnt = *p++;
672 printf ("/%d", mcnt);
673 break;
674#endif /* emacs */
675
676 case wordchar:
677 printf ("/wordchar");
678 break;
679
680 case notwordchar:
681 printf ("/notwordchar");
682 break;
683
684 case begbuf:
685 printf ("/begbuf");
686 break;
687
688 case endbuf:
689 printf ("/endbuf");
690 break;
691
692 default:
693 printf ("?%d", *(p-1));
694 }
695 }
696 printf ("/\n");
697}
698
699
700void
701print_compiled_pattern (bufp)
702 struct re_pattern_buffer *bufp;
703{
704 unsigned char *buffer = bufp->buffer;
705
706 print_partial_compiled_pattern (buffer, buffer + bufp->used);
707 printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
708
709 if (bufp->fastmap_accurate && bufp->fastmap)
710 {
711 printf ("fastmap: ");
712 print_fastmap (bufp->fastmap);
713 }
714
715 printf ("re_nsub: %d\t", bufp->re_nsub);
716 printf ("regs_alloc: %d\t", bufp->regs_allocated);
717 printf ("can_be_null: %d\t", bufp->can_be_null);
718 printf ("newline_anchor: %d\n", bufp->newline_anchor);
719 printf ("no_sub: %d\t", bufp->no_sub);
720 printf ("not_bol: %d\t", bufp->not_bol);
721 printf ("not_eol: %d\t", bufp->not_eol);
722 printf ("syntax: %d\n", bufp->syntax);
723 /* Perhaps we should print the translate table? */
724}
725
726
727void
728print_double_string (where, string1, size1, string2, size2)
729 const char *where;
730 const char *string1;
731 const char *string2;
732 int size1;
733 int size2;
734{
735 unsigned this_char;
736
737 if (where == NULL)
738 printf ("(null)");
739 else
740 {
741 if (FIRST_STRING_P (where))
742 {
743 for (this_char = where - string1; this_char < size1; this_char++)
744 printchar (string1[this_char]);
745
746 where = string2;
747 }
748
749 for (this_char = where - string2; this_char < size2; this_char++)
750 printchar (string2[this_char]);
751 }
752}
753
754#else /* not DEBUG */
755
756#undef assert
757#define assert(e)
758
759#define DEBUG_STATEMENT(e)
760#define DEBUG_PRINT1(x)
761#define DEBUG_PRINT2(x1, x2)
762#define DEBUG_PRINT3(x1, x2, x3)
763#define DEBUG_PRINT4(x1, x2, x3, x4)
764#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
765#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
766
767#endif /* not DEBUG */
768
769/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
770 also be assigned to arbitrarily: each pattern buffer stores its own
771 syntax, so it can be changed between regex compilations. */
772reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
773
774
775/* Specify the precise syntax of regexps for compilation. This provides
776 for compatibility for various utilities which historically have
777 different, incompatible syntaxes.
778
779 The argument SYNTAX is a bit mask comprised of the various bits
780 defined in regex.h. We return the old syntax. */
781
782reg_syntax_t
783re_set_syntax (syntax)
784 reg_syntax_t syntax;
785{
786 reg_syntax_t ret = re_syntax_options;
787
788 re_syntax_options = syntax;
789 return ret;
790}
791
792/* This table gives an error message for each of the error codes listed
793 in regex.h. Obviously the order here has to be same as there. */
794
795static const char *re_error_msg[] =
796 { NULL, /* REG_NOERROR */
797 "No match", /* REG_NOMATCH */
798 "Invalid regular expression", /* REG_BADPAT */
799 "Invalid collation character", /* REG_ECOLLATE */
800 "Invalid character class name", /* REG_ECTYPE */
801 "Trailing backslash", /* REG_EESCAPE */
802 "Invalid back reference", /* REG_ESUBREG */
803 "Unmatched [ or [^", /* REG_EBRACK */
804 "Unmatched ( or \\(", /* REG_EPAREN */
805 "Unmatched \\{", /* REG_EBRACE */
806 "Invalid content of \\{\\}", /* REG_BADBR */
807 "Invalid range end", /* REG_ERANGE */
808 "Memory exhausted", /* REG_ESPACE */
809 "Invalid preceding regular expression", /* REG_BADRPT */
810 "Premature end of regular expression", /* REG_EEND */
811 "Regular expression too big", /* REG_ESIZE */
812 "Unmatched ) or \\)", /* REG_ERPAREN */
813 };
814
815/* Subroutine declarations and macros for regex_compile. */
816
817static void store_op1 (), store_op2 ();
818static void insert_op1 (), insert_op2 ();
819static boolean at_begline_loc_p (), at_endline_loc_p ();
820static boolean group_in_compile_stack ();
821static reg_errcode_t compile_range ();
822
823/* Fetch the next character in the uncompiled pattern---translating it
824 if necessary. Also cast from a signed character in the constant
825 string passed to us by the user to an unsigned char that we can use
826 as an array index (in, e.g., `translate'). */
827#define PATFETCH(c) \
828 do {if (p == pend) return REG_EEND; \
829 c = (unsigned char) *p++; \
830 if (translate) c = translate[c]; \
831 } while (0)
832
833/* Fetch the next character in the uncompiled pattern, with no
834 translation. */
835#define PATFETCH_RAW(c) \
836 do {if (p == pend) return REG_EEND; \
837 c = (unsigned char) *p++; \
838 } while (0)
839
840/* Go backwards one character in the pattern. */
841#define PATUNFETCH p--
842
843
844/* If `translate' is non-null, return translate[D], else just D. We
845 cast the subscript to translate because some data is declared as
846 `char *', to avoid warnings when a string constant is passed. But
847 when we use a character as a subscript we must make it unsigned. */
848#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
849
850
851/* Macros for outputting the compiled pattern into `buffer'. */
852
853/* If the buffer isn't allocated when it comes in, use this. */
854#define INIT_BUF_SIZE 32
855
856/* Make sure we have at least N more bytes of space in buffer. */
857#define GET_BUFFER_SPACE(n) \
858 while (b - bufp->buffer + (n) > bufp->allocated) \
859 EXTEND_BUFFER ()
860
861/* Make sure we have one more byte of buffer space and then add C to it. */
862#define BUF_PUSH(c) \
863 do { \
864 GET_BUFFER_SPACE (1); \
865 *b++ = (unsigned char) (c); \
866 } while (0)
867
868
869/* Ensure we have two more bytes of buffer space and then append C1 and C2. */
870#define BUF_PUSH_2(c1, c2) \
871 do { \
872 GET_BUFFER_SPACE (2); \
873 *b++ = (unsigned char) (c1); \
874 *b++ = (unsigned char) (c2); \
875 } while (0)
876
877
878/* As with BUF_PUSH_2, except for three bytes. */
879#define BUF_PUSH_3(c1, c2, c3) \
880 do { \
881 GET_BUFFER_SPACE (3); \
882 *b++ = (unsigned char) (c1); \
883 *b++ = (unsigned char) (c2); \
884 *b++ = (unsigned char) (c3); \
885 } while (0)
886
887
888/* Store a jump with opcode OP at LOC to location TO. We store a
889 relative address offset by the three bytes the jump itself occupies. */
890#define STORE_JUMP(op, loc, to) \
891 store_op1 (op, loc, (to) - (loc) - 3)
892
893/* Likewise, for a two-argument jump. */
894#define STORE_JUMP2(op, loc, to, arg) \
895 store_op2 (op, loc, (to) - (loc) - 3, arg)
896
897/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */
898#define INSERT_JUMP(op, loc, to) \
899 insert_op1 (op, loc, (to) - (loc) - 3, b)
900
901/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */
902#define INSERT_JUMP2(op, loc, to, arg) \
903 insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
904
905
906/* This is not an arbitrary limit: the arguments which represent offsets
907 into the pattern are two bytes long. So if 2^16 bytes turns out to
908 be too small, many things would have to change. */
909#define MAX_BUF_SIZE (1L << 16)
910
911
912/* Extend the buffer by twice its current size via realloc and
913 reset the pointers that pointed into the old block to point to the
914 correct places in the new one. If extending the buffer results in it
915 being larger than MAX_BUF_SIZE, then flag memory exhausted. */
916#define EXTEND_BUFFER() \
917 do { \
918 unsigned char *old_buffer = bufp->buffer; \
919 if (bufp->allocated == MAX_BUF_SIZE) \
920 return REG_ESIZE; \
921 bufp->allocated <<= 1; \
922 if (bufp->allocated > MAX_BUF_SIZE) \
923 bufp->allocated = MAX_BUF_SIZE; \
924 bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
925 if (bufp->buffer == NULL) \
926 return REG_ESPACE; \
927 /* If the buffer moved, move all the pointers into it. */ \
928 if (old_buffer != bufp->buffer) \
929 { \
930 b = (b - old_buffer) + bufp->buffer; \
931 begalt = (begalt - old_buffer) + bufp->buffer; \
932 if (fixup_alt_jump) \
933 fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
934 if (laststart) \
935 laststart = (laststart - old_buffer) + bufp->buffer; \
936 if (pending_exact) \
937 pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
938 } \
939 } while (0)
940
941
942/* Since we have one byte reserved for the register number argument to
943 {start,stop}_memory, the maximum number of groups we can report
944 things about is what fits in that byte. */
945#define MAX_REGNUM 255
946
947/* But patterns can have more than `MAX_REGNUM' registers. We just
948 ignore the excess. */
949typedef unsigned regnum_t;
950
951
952/* Macros for the compile stack. */
953
954/* Since offsets can go either forwards or backwards, this type needs to
955 be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */
956typedef int pattern_offset_t;
957
958typedef struct
959{
960 pattern_offset_t begalt_offset;
961 pattern_offset_t fixup_alt_jump;
962 pattern_offset_t inner_group_offset;
963 pattern_offset_t laststart_offset;
964 regnum_t regnum;
965} compile_stack_elt_t;
966
967
968typedef struct
969{
970 compile_stack_elt_t *stack;
971 unsigned size;
972 unsigned avail; /* Offset of next open position. */
973} compile_stack_type;
974
975
976#define INIT_COMPILE_STACK_SIZE 32
977
978#define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
979#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
980
981/* The next available element. */
982#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
983
984
985/* Set the bit for character C in a list. */
986#define SET_LIST_BIT(c) \
987 (b[((unsigned char) (c)) / BYTEWIDTH] \
988 |= 1 << (((unsigned char) c) % BYTEWIDTH))
989
990
991/* Get the next unsigned number in the uncompiled pattern. */
992#define GET_UNSIGNED_NUMBER(num) \
993 { if (p != pend) \
994 { \
995 PATFETCH (c); \
996 while (ISDIGIT (c)) \
997 { \
998 if (num < 0) \
999 num = 0; \
1000 num = num * 10 + c - '0'; \
1001 if (p == pend) \
1002 break; \
1003 PATFETCH (c); \
1004 } \
1005 } \
1006 }
1007
1008#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
1009
1010#define IS_CHAR_CLASS(string) \
1011 (STREQ (string, "alpha") || STREQ (string, "upper") \
1012 || STREQ (string, "lower") || STREQ (string, "digit") \
1013 || STREQ (string, "alnum") || STREQ (string, "xdigit") \
1014 || STREQ (string, "space") || STREQ (string, "print") \
1015 || STREQ (string, "punct") || STREQ (string, "graph") \
1016 || STREQ (string, "cntrl") || STREQ (string, "blank"))
1017
1018/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
1019 Returns one of error codes defined in `regex.h', or zero for success.
1020
1021 Assumes the `allocated' (and perhaps `buffer') and `translate'
1022 fields are set in BUFP on entry.
1023
1024 If it succeeds, results are put in BUFP (if it returns an error, the
1025 contents of BUFP are undefined):
1026 `buffer' is the compiled pattern;
1027 `syntax' is set to SYNTAX;
1028 `used' is set to the length of the compiled pattern;
1029 `fastmap_accurate' is zero;
1030 `re_nsub' is the number of subexpressions in PATTERN;
1031 `not_bol' and `not_eol' are zero;
1032
1033 The `fastmap' and `newline_anchor' fields are neither
1034 examined nor set. */
1035
1036static reg_errcode_t
1037regex_compile (pattern, size, syntax, bufp)
1038 const char *pattern;
1039 int size;
1040 reg_syntax_t syntax;
1041 struct re_pattern_buffer *bufp;
1042{
1043 /* We fetch characters from PATTERN here. Even though PATTERN is
1044 `char *' (i.e., signed), we declare these variables as unsigned, so
1045 they can be reliably used as array indices. */
1046 register unsigned char c, c1;
1047
1048 /* A random tempory spot in PATTERN. */
1049 const char *p1;
1050
1051 /* Points to the end of the buffer, where we should append. */
1052 register unsigned char *b;
1053
1054 /* Keeps track of unclosed groups. */
1055 compile_stack_type compile_stack;
1056
1057 /* Points to the current (ending) position in the pattern. */
1058 const char *p = pattern;
1059 const char *pend = pattern + size;
1060
1061 /* How to translate the characters in the pattern. */
1062 char *translate = bufp->translate;
1063
1064 /* Address of the count-byte of the most recently inserted `exactn'
1065 command. This makes it possible to tell if a new exact-match
1066 character can be added to that command or if the character requires
1067 a new `exactn' command. */
1068 unsigned char *pending_exact = 0;
1069
1070 /* Address of start of the most recently finished expression.
1071 This tells, e.g., postfix * where to find the start of its
1072 operand. Reset at the beginning of groups and alternatives. */
1073 unsigned char *laststart = 0;
1074
1075 /* Address of beginning of regexp, or inside of last group. */
1076 unsigned char *begalt;
1077
1078 /* Place in the uncompiled pattern (i.e., the {) to
1079 which to go back if the interval is invalid. */
1080 const char *beg_interval;
1081
1082 /* Address of the place where a forward jump should go to the end of
1083 the containing expression. Each alternative of an `or' -- except the
1084 last -- ends with a forward jump of this sort. */
1085 unsigned char *fixup_alt_jump = 0;
1086
1087 /* Counts open-groups as they are encountered. Remembered for the
1088 matching close-group on the compile stack, so the same register
1089 number is put in the stop_memory as the start_memory. */
1090 regnum_t regnum = 0;
1091
1092#ifdef DEBUG
1093 DEBUG_PRINT1 ("\nCompiling pattern: ");
1094 if (debug)
1095 {
1096 unsigned debug_count;
1097
1098 for (debug_count = 0; debug_count < size; debug_count++)
1099 printchar (pattern[debug_count]);
1100 putchar ('\n');
1101 }
1102#endif /* DEBUG */
1103
1104 /* Initialize the compile stack. */
1105 compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
1106 if (compile_stack.stack == NULL)
1107 return REG_ESPACE;
1108
1109 compile_stack.size = INIT_COMPILE_STACK_SIZE;
1110 compile_stack.avail = 0;
1111
1112 /* Initialize the pattern buffer. */
1113 bufp->syntax = syntax;
1114 bufp->fastmap_accurate = 0;
1115 bufp->not_bol = bufp->not_eol = 0;
1116
1117 /* Set `used' to zero, so that if we return an error, the pattern
1118 printer (for debugging) will think there's no pattern. We reset it
1119 at the end. */
1120 bufp->used = 0;
1121
1122 /* Always count groups, whether or not bufp->no_sub is set. */
1123 bufp->re_nsub = 0;
1124
1125#if !defined (emacs) && !defined (SYNTAX_TABLE)
1126 /* Initialize the syntax table. */
1127 init_syntax_once ();
1128#endif
1129
1130 if (bufp->allocated == 0)
1131 {
1132 if (bufp->buffer)
1133 { /* If zero allocated, but buffer is non-null, try to realloc
1134 enough space. This loses if buffer's address is bogus, but
1135 that is the user's responsibility. */
1136 RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
1137 }
1138 else
1139 { /* Caller did not allocate a buffer. Do it for them. */
1140 bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
1141 }
1142 if (!bufp->buffer) return REG_ESPACE;
1143
1144 bufp->allocated = INIT_BUF_SIZE;
1145 }
1146
1147 begalt = b = bufp->buffer;
1148
1149 /* Loop through the uncompiled pattern until we're at the end. */
1150 while (p != pend)
1151 {
1152 PATFETCH (c);
1153
1154 switch (c)
1155 {
1156 case '^':
1157 {
1158 if ( /* If at start of pattern, it's an operator. */
1159 p == pattern + 1
1160 /* If context independent, it's an operator. */
1161 || syntax & RE_CONTEXT_INDEP_ANCHORS
1162 /* Otherwise, depends on what's come before. */
1163 || at_begline_loc_p (pattern, p, syntax))
1164 BUF_PUSH (begline);
1165 else
1166 goto normal_char;
1167 }
1168 break;
1169
1170
1171 case '$':
1172 {
1173 if ( /* If at end of pattern, it's an operator. */
1174 p == pend
1175 /* If context independent, it's an operator. */
1176 || syntax & RE_CONTEXT_INDEP_ANCHORS
1177 /* Otherwise, depends on what's next. */
1178 || at_endline_loc_p (p, pend, syntax))
1179 BUF_PUSH (endline);
1180 else
1181 goto normal_char;
1182 }
1183 break;
1184
1185
1186 case '+':
1187 case '?':
1188 if ((syntax & RE_BK_PLUS_QM)
1189 || (syntax & RE_LIMITED_OPS))
1190 goto normal_char;
1191 handle_plus:
1192 case '*':
1193 /* If there is no previous pattern... */
1194 if (!laststart)
1195 {
1196 if (syntax & RE_CONTEXT_INVALID_OPS)
1197 return REG_BADRPT;
1198 else if (!(syntax & RE_CONTEXT_INDEP_OPS))
1199 goto normal_char;
1200 }
1201
1202 {
1203 /* Are we optimizing this jump? */
1204 boolean keep_string_p = false;
1205
1206 /* 1 means zero (many) matches is allowed. */
1207 char zero_times_ok = 0, many_times_ok = 0;
1208
1209 /* If there is a sequence of repetition chars, collapse it
1210 down to just one (the right one). We can't combine
1211 interval operators with these because of, e.g., `a{2}*',
1212 which should only match an even number of `a's. */
1213
1214 for (;;)
1215 {
1216 zero_times_ok |= c != '+';
1217 many_times_ok |= c != '?';
1218
1219 if (p == pend)
1220 break;
1221
1222 PATFETCH (c);
1223
1224 if (c == '*'
1225 || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
1226 ;
1227
1228 else if (syntax & RE_BK_PLUS_QM && c == '\\')
1229 {
1230 if (p == pend) return REG_EESCAPE;
1231
1232 PATFETCH (c1);
1233 if (!(c1 == '+' || c1 == '?'))
1234 {
1235 PATUNFETCH;
1236 PATUNFETCH;
1237 break;
1238 }
1239
1240 c = c1;
1241 }
1242 else
1243 {
1244 PATUNFETCH;
1245 break;
1246 }
1247
1248 /* If we get here, we found another repeat character. */
1249 }
1250
1251 /* Star, etc. applied to an empty pattern is equivalent
1252 to an empty pattern. */
1253 if (!laststart)
1254 break;
1255
1256 /* Now we know whether or not zero matches is allowed
1257 and also whether or not two or more matches is allowed. */
1258 if (many_times_ok)
1259 { /* More than one repetition is allowed, so put in at the
1260 end a backward relative jump from `b' to before the next
1261 jump we're going to put in below (which jumps from
1262 laststart to after this jump).
1263
1264 But if we are at the `*' in the exact sequence `.*\n',
1265 insert an unconditional jump backwards to the .,
1266 instead of the beginning of the loop. This way we only
1267 push a failure point once, instead of every time
1268 through the loop. */
1269 assert (p - 1 > pattern);
1270
1271 /* Allocate the space for the jump. */
1272 GET_BUFFER_SPACE (3);
1273
1274 /* We know we are not at the first character of the pattern,
1275 because laststart was nonzero. And we've already
1276 incremented `p', by the way, to be the character after
1277 the `*'. Do we have to do something analogous here
1278 for null bytes, because of RE_DOT_NOT_NULL? */
1279 if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
1280 && zero_times_ok
1281 && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
1282 && !(syntax & RE_DOT_NEWLINE))
1283 { /* We have .*\n. */
1284 STORE_JUMP (jump, b, laststart);
1285 keep_string_p = true;
1286 }
1287 else
1288 /* Anything else. */
1289 STORE_JUMP (maybe_pop_jump, b, laststart - 3);
1290
1291 /* We've added more stuff to the buffer. */
1292 b += 3;
1293 }
1294
1295 /* On failure, jump from laststart to b + 3, which will be the
1296 end of the buffer after this jump is inserted. */
1297 GET_BUFFER_SPACE (3);
1298 INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
1299 : on_failure_jump,
1300 laststart, b + 3);
1301 pending_exact = 0;
1302 b += 3;
1303
1304 if (!zero_times_ok)
1305 {
1306 /* At least one repetition is required, so insert a
1307 `dummy_failure_jump' before the initial
1308 `on_failure_jump' instruction of the loop. This
1309 effects a skip over that instruction the first time
1310 we hit that loop. */
1311 GET_BUFFER_SPACE (3);
1312 INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
1313 b += 3;
1314 }
1315 }
1316 break;
1317
1318
1319 case '.':
1320 laststart = b;
1321 BUF_PUSH (anychar);
1322 break;
1323
1324
1325 case '[':
1326 {
1327 boolean had_char_class = false;
1328
1329 if (p == pend) return REG_EBRACK;
1330
1331 /* Ensure that we have enough space to push a charset: the
1332 opcode, the length count, and the bitset; 34 bytes in all. */
1333 GET_BUFFER_SPACE (34);
1334
1335 laststart = b;
1336
1337 /* We test `*p == '^' twice, instead of using an if
1338 statement, so we only need one BUF_PUSH. */
1339 BUF_PUSH (*p == '^' ? charset_not : charset);
1340 if (*p == '^')
1341 p++;
1342
1343 /* Remember the first position in the bracket expression. */
1344 p1 = p;
1345
1346 /* Push the number of bytes in the bitmap. */
1347 BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
1348
1349 /* Clear the whole map. */
1350 bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
1351
1352 /* charset_not matches newline according to a syntax bit. */
1353 if ((re_opcode_t) b[-2] == charset_not
1354 && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
1355 SET_LIST_BIT ('\n');
1356
1357 /* Read in characters and ranges, setting map bits. */
1358 for (;;)
1359 {
1360 if (p == pend) return REG_EBRACK;
1361
1362 PATFETCH (c);
1363
1364 /* \ might escape characters inside [...] and [^...]. */
1365 if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
1366 {
1367 if (p == pend) return REG_EESCAPE;
1368
1369 PATFETCH (c1);
1370 SET_LIST_BIT (c1);
1371 continue;
1372 }
1373
1374 /* Could be the end of the bracket expression. If it's
1375 not (i.e., when the bracket expression is `[]' so
1376 far), the ']' character bit gets set way below. */
1377 if (c == ']' && p != p1 + 1)
1378 break;
1379
1380 /* Look ahead to see if it's a range when the last thing
1381 was a character class. */
1382 if (had_char_class && c == '-' && *p != ']')
1383 return REG_ERANGE;
1384
1385 /* Look ahead to see if it's a range when the last thing
1386 was a character: if this is a hyphen not at the
1387 beginning or the end of a list, then it's the range
1388 operator. */
1389 if (c == '-'
1390 && !(p - 2 >= pattern && p[-2] == '[')
1391 && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
1392 && *p != ']')
1393 {
1394 reg_errcode_t ret
1395 = compile_range (&p, pend, translate, syntax, b);
1396 if (ret != REG_NOERROR) return ret;
1397 }
1398
1399 else if (p[0] == '-' && p[1] != ']')
1400 { /* This handles ranges made up of characters only. */
1401 reg_errcode_t ret;
1402
1403 /* Move past the `-'. */
1404 PATFETCH (c1);
1405
1406 ret = compile_range (&p, pend, translate, syntax, b);
1407 if (ret != REG_NOERROR) return ret;
1408 }
1409
1410 /* See if we're at the beginning of a possible character
1411 class. */
1412
1413 else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
1414 { /* Leave room for the null. */
1415 char str[CHAR_CLASS_MAX_LENGTH + 1];
1416
1417 PATFETCH (c);
1418 c1 = 0;
1419
1420 /* If pattern is `[[:'. */
1421 if (p == pend) return REG_EBRACK;
1422
1423 for (;;)
1424 {
1425 PATFETCH (c);
1426 if (c == ':' || c == ']' || p == pend
1427 || c1 == CHAR_CLASS_MAX_LENGTH)
1428 break;
1429 str[c1++] = c;
1430 }
1431 str[c1] = '\0';
1432
1433 /* If isn't a word bracketed by `[:' and:`]':
1434 undo the ending character, the letters, and leave
1435 the leading `:' and `[' (but set bits for them). */
1436 if (c == ':' && *p == ']')
1437 {
1438 int ch;
1439 boolean is_alnum = STREQ (str, "alnum");
1440 boolean is_alpha = STREQ (str, "alpha");
1441 boolean is_blank = STREQ (str, "blank");
1442 boolean is_cntrl = STREQ (str, "cntrl");
1443 boolean is_digit = STREQ (str, "digit");
1444 boolean is_graph = STREQ (str, "graph");
1445 boolean is_lower = STREQ (str, "lower");
1446 boolean is_print = STREQ (str, "print");
1447 boolean is_punct = STREQ (str, "punct");
1448 boolean is_space = STREQ (str, "space");
1449 boolean is_upper = STREQ (str, "upper");
1450 boolean is_xdigit = STREQ (str, "xdigit");
1451
1452 if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
1453
1454 /* Throw away the ] at the end of the character
1455 class. */
1456 PATFETCH (c);
1457
1458 if (p == pend) return REG_EBRACK;
1459
1460 for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
1461 {
1462 if ( (is_alnum && ISALNUM (ch))
1463 || (is_alpha && ISALPHA (ch))
1464 || (is_blank && ISBLANK (ch))
1465 || (is_cntrl && ISCNTRL (ch))
1466 || (is_digit && ISDIGIT (ch))
1467 || (is_graph && ISGRAPH (ch))
1468 || (is_lower && ISLOWER (ch))
1469 || (is_print && ISPRINT (ch))
1470 || (is_punct && ISPUNCT (ch))
1471 || (is_space && ISSPACE (ch))
1472 || (is_upper && ISUPPER (ch))
1473 || (is_xdigit && ISXDIGIT (ch)))
1474 SET_LIST_BIT (ch);
1475 }
1476 had_char_class = true;
1477 }
1478 else
1479 {
1480 c1++;
1481 while (c1--)
1482 PATUNFETCH;
1483 SET_LIST_BIT ('[');
1484 SET_LIST_BIT (':');
1485 had_char_class = false;
1486 }
1487 }
1488 else
1489 {
1490 had_char_class = false;
1491 SET_LIST_BIT (c);
1492 }
1493 }
1494
1495 /* Discard any (non)matching list bytes that are all 0 at the
1496 end of the map. Decrease the map-length byte too. */
1497 while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
1498 b[-1]--;
1499 b += b[-1];
1500 }
1501 break;
1502
1503
1504 case '(':
1505 if (syntax & RE_NO_BK_PARENS)
1506 goto handle_open;
1507 else
1508 goto normal_char;
1509
1510
1511 case ')':
1512 if (syntax & RE_NO_BK_PARENS)
1513 goto handle_close;
1514 else
1515 goto normal_char;
1516
1517
1518 case '\n':
1519 if (syntax & RE_NEWLINE_ALT)
1520 goto handle_alt;
1521 else
1522 goto normal_char;
1523
1524
1525 case '|':
1526 if (syntax & RE_NO_BK_VBAR)
1527 goto handle_alt;
1528 else
1529 goto normal_char;
1530
1531
1532 case '{':
1533 if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
1534 goto handle_interval;
1535 else
1536 goto normal_char;
1537
1538
1539 case '\\':
1540 if (p == pend) return REG_EESCAPE;
1541
1542 /* Do not translate the character after the \, so that we can
1543 distinguish, e.g., \B from \b, even if we normally would
1544 translate, e.g., B to b. */
1545 PATFETCH_RAW (c);
1546
1547 switch (c)
1548 {
1549 case '(':
1550 if (syntax & RE_NO_BK_PARENS)
1551 goto normal_backslash;
1552
1553 handle_open:
1554 bufp->re_nsub++;
1555 regnum++;
1556
1557 if (COMPILE_STACK_FULL)
1558 {
1559 RETALLOC (compile_stack.stack, compile_stack.size << 1,
1560 compile_stack_elt_t);
1561 if (compile_stack.stack == NULL) return REG_ESPACE;
1562
1563 compile_stack.size <<= 1;
1564 }
1565
1566 /* These are the values to restore when we hit end of this
1567 group. They are all relative offsets, so that if the
1568 whole pattern moves because of realloc, they will still
1569 be valid. */
1570 COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
1571 COMPILE_STACK_TOP.fixup_alt_jump
1572 = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
1573 COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
1574 COMPILE_STACK_TOP.regnum = regnum;
1575
1576 /* We will eventually replace the 0 with the number of
1577 groups inner to this one. But do not push a
1578 start_memory for groups beyond the last one we can
1579 represent in the compiled pattern. */
1580 if (regnum <= MAX_REGNUM)
1581 {
1582 COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
1583 BUF_PUSH_3 (start_memory, regnum, 0);
1584 }
1585
1586 compile_stack.avail++;
1587
1588 fixup_alt_jump = 0;
1589 laststart = 0;
1590 begalt = b;
1591 /* If we've reached MAX_REGNUM groups, then this open
1592 won't actually generate any code, so we'll have to
1593 clear pending_exact explicitly. */
1594 pending_exact = 0;
1595 break;
1596
1597
1598 case ')':
1599 if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
1600
1601 if (COMPILE_STACK_EMPTY)
1602 {
1603 if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
1604 goto normal_backslash;
1605 else
1606 return REG_ERPAREN;
1607 }
1608
1609 handle_close:
1610 if (fixup_alt_jump)
1611 { /* Push a dummy failure point at the end of the
1612 alternative for a possible future
1613 `pop_failure_jump' to pop. See comments at
1614 `push_dummy_failure' in `re_match_2'. */
1615 BUF_PUSH (push_dummy_failure);
1616
1617 /* We allocated space for this jump when we assigned
1618 to `fixup_alt_jump', in the `handle_alt' case below. */
1619 STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
1620 }
1621
1622 /* See similar code for backslashed left paren above. */
1623 if (COMPILE_STACK_EMPTY)
1624 {
1625 if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
1626 goto normal_char;
1627 else
1628 return REG_ERPAREN;
1629 }
1630
1631 /* Since we just checked for an empty stack above, this
1632 ``can't happen''. */
1633 assert (compile_stack.avail != 0);
1634 {
1635 /* We don't just want to restore into `regnum', because
1636 later groups should continue to be numbered higher,
1637 as in `(ab)c(de)' -- the second group is #2. */
1638 regnum_t this_group_regnum;
1639
1640 compile_stack.avail--;
1641 begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
1642 fixup_alt_jump
1643 = COMPILE_STACK_TOP.fixup_alt_jump
1644 ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
1645 : 0;
1646 laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
1647 this_group_regnum = COMPILE_STACK_TOP.regnum;
1648 /* If we've reached MAX_REGNUM groups, then this open
1649 won't actually generate any code, so we'll have to
1650 clear pending_exact explicitly. */
1651 pending_exact = 0;
1652
1653 /* We're at the end of the group, so now we know how many
1654 groups were inside this one. */
1655 if (this_group_regnum <= MAX_REGNUM)
1656 {
1657 unsigned char *inner_group_loc
1658 = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
1659
1660 *inner_group_loc = regnum - this_group_regnum;
1661 BUF_PUSH_3 (stop_memory, this_group_regnum,
1662 regnum - this_group_regnum);
1663 }
1664 }
1665 break;
1666
1667
1668 case '|': /* `\|'. */
1669 if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
1670 goto normal_backslash;
1671 handle_alt:
1672 if (syntax & RE_LIMITED_OPS)
1673 goto normal_char;
1674
1675 /* Insert before the previous alternative a jump which
1676 jumps to this alternative if the former fails. */
1677 GET_BUFFER_SPACE (3);
1678 INSERT_JUMP (on_failure_jump, begalt, b + 6);
1679 pending_exact = 0;
1680 b += 3;
1681
1682 /* The alternative before this one has a jump after it
1683 which gets executed if it gets matched. Adjust that
1684 jump so it will jump to this alternative's analogous
1685 jump (put in below, which in turn will jump to the next
1686 (if any) alternative's such jump, etc.). The last such
1687 jump jumps to the correct final destination. A picture:
1688 _____ _____
1689 | | | |
1690 | v | v
1691 a | b | c
1692
1693 If we are at `b', then fixup_alt_jump right now points to a
1694 three-byte space after `a'. We'll put in the jump, set
1695 fixup_alt_jump to right after `b', and leave behind three
1696 bytes which we'll fill in when we get to after `c'. */
1697
1698 if (fixup_alt_jump)
1699 STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
1700
1701 /* Mark and leave space for a jump after this alternative,
1702 to be filled in later either by next alternative or
1703 when know we're at the end of a series of alternatives. */
1704 fixup_alt_jump = b;
1705 GET_BUFFER_SPACE (3);
1706 b += 3;
1707
1708 laststart = 0;
1709 begalt = b;
1710 break;
1711
1712
1713 case '{':
1714 /* If \{ is a literal. */
1715 if (!(syntax & RE_INTERVALS)
1716 /* If we're at `\{' and it's not the open-interval
1717 operator. */
1718 || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
1719 || (p - 2 == pattern && p == pend))
1720 goto normal_backslash;
1721
1722 handle_interval:
1723 {
1724 /* If got here, then the syntax allows intervals. */
1725
1726 /* At least (most) this many matches must be made. */
1727 int lower_bound = -1, upper_bound = -1;
1728
1729 beg_interval = p - 1;
1730
1731 if (p == pend)
1732 {
1733 if (syntax & RE_NO_BK_BRACES)
1734 goto unfetch_interval;
1735 else
1736 return REG_EBRACE;
1737 }
1738
1739 GET_UNSIGNED_NUMBER (lower_bound);
1740
1741 if (c == ',')
1742 {
1743 GET_UNSIGNED_NUMBER (upper_bound);
1744 if (upper_bound < 0) upper_bound = RE_DUP_MAX;
1745 }
1746 else
1747 /* Interval such as `{1}' => match exactly once. */
1748 upper_bound = lower_bound;
1749
1750 if (lower_bound < 0 || upper_bound > RE_DUP_MAX
1751 || lower_bound > upper_bound)
1752 {
1753 if (syntax & RE_NO_BK_BRACES)
1754 goto unfetch_interval;
1755 else
1756 return REG_BADBR;
1757 }
1758
1759 if (!(syntax & RE_NO_BK_BRACES))
1760 {
1761 if (c != '\\') return REG_EBRACE;
1762
1763 PATFETCH (c);
1764 }
1765
1766 if (c != '}')
1767 {
1768 if (syntax & RE_NO_BK_BRACES)
1769 goto unfetch_interval;
1770 else
1771 return REG_BADBR;
1772 }
1773
1774 /* We just parsed a valid interval. */
1775
1776 /* If it's invalid to have no preceding re. */
1777 if (!laststart)
1778 {
1779 if (syntax & RE_CONTEXT_INVALID_OPS)
1780 return REG_BADRPT;
1781 else if (syntax & RE_CONTEXT_INDEP_OPS)
1782 laststart = b;
1783 else
1784 goto unfetch_interval;
1785 }
1786
1787 /* If the upper bound is zero, don't want to succeed at
1788 all; jump from `laststart' to `b + 3', which will be
1789 the end of the buffer after we insert the jump. */
1790 if (upper_bound == 0)
1791 {
1792 GET_BUFFER_SPACE (3);
1793 INSERT_JUMP (jump, laststart, b + 3);
1794 b += 3;
1795 }
1796
1797 /* Otherwise, we have a nontrivial interval. When
1798 we're all done, the pattern will look like:
1799 set_number_at <jump count> <upper bound>
1800 set_number_at <succeed_n count> <lower bound>
1801 succeed_n <after jump addr> <succed_n count>
1802 <body of loop>
1803 jump_n <succeed_n addr> <jump count>
1804 (The upper bound and `jump_n' are omitted if
1805 `upper_bound' is 1, though.) */
1806 else
1807 { /* If the upper bound is > 1, we need to insert
1808 more at the end of the loop. */
1809 unsigned nbytes = 10 + (upper_bound > 1) * 10;
1810
1811 GET_BUFFER_SPACE (nbytes);
1812
1813 /* Initialize lower bound of the `succeed_n', even
1814 though it will be set during matching by its
1815 attendant `set_number_at' (inserted next),
1816 because `re_compile_fastmap' needs to know.
1817 Jump to the `jump_n' we might insert below. */
1818 INSERT_JUMP2 (succeed_n, laststart,
1819 b + 5 + (upper_bound > 1) * 5,
1820 lower_bound);
1821 b += 5;
1822
1823 /* Code to initialize the lower bound. Insert
1824 before the `succeed_n'. The `5' is the last two
1825 bytes of this `set_number_at', plus 3 bytes of
1826 the following `succeed_n'. */
1827 insert_op2 (set_number_at, laststart, 5, lower_bound, b);
1828 b += 5;
1829
1830 if (upper_bound > 1)
1831 { /* More than one repetition is allowed, so
1832 append a backward jump to the `succeed_n'
1833 that starts this interval.
1834
1835 When we've reached this during matching,
1836 we'll have matched the interval once, so
1837 jump back only `upper_bound - 1' times. */
1838 STORE_JUMP2 (jump_n, b, laststart + 5,
1839 upper_bound - 1);
1840 b += 5;
1841
1842 /* The location we want to set is the second
1843 parameter of the `jump_n'; that is `b-2' as
1844 an absolute address. `laststart' will be
1845 the `set_number_at' we're about to insert;
1846 `laststart+3' the number to set, the source
1847 for the relative address. But we are
1848 inserting into the middle of the pattern --
1849 so everything is getting moved up by 5.
1850 Conclusion: (b - 2) - (laststart + 3) + 5,
1851 i.e., b - laststart.
1852
1853 We insert this at the beginning of the loop
1854 so that if we fail during matching, we'll
1855 reinitialize the bounds. */
1856 insert_op2 (set_number_at, laststart, b - laststart,
1857 upper_bound - 1, b);
1858 b += 5;
1859 }
1860 }
1861 pending_exact = 0;
1862 beg_interval = NULL;
1863 }
1864 break;
1865
1866 unfetch_interval:
1867 /* If an invalid interval, match the characters as literals. */
1868 assert (beg_interval);
1869 p = beg_interval;
1870 beg_interval = NULL;
1871
1872 /* normal_char and normal_backslash need `c'. */
1873 PATFETCH (c);
1874
1875 if (!(syntax & RE_NO_BK_BRACES))
1876 {
1877 if (p > pattern && p[-1] == '\\')
1878 goto normal_backslash;
1879 }
1880 goto normal_char;
1881
1882#ifdef emacs
1883 /* There is no way to specify the before_dot and after_dot
1884 operators. rms says this is ok. --karl */
1885 case '=':
1886 BUF_PUSH (at_dot);
1887 break;
1888
1889 case 's':
1890 laststart = b;
1891 PATFETCH (c);
1892 BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
1893 break;
1894
1895 case 'S':
1896 laststart = b;
1897 PATFETCH (c);
1898 BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
1899 break;
1900#endif /* emacs */
1901
1902
1903 case 'w':
1904 laststart = b;
1905 BUF_PUSH (wordchar);
1906 break;
1907
1908
1909 case 'W':
1910 laststart = b;
1911 BUF_PUSH (notwordchar);
1912 break;
1913
1914
1915 case '<':
1916 BUF_PUSH (wordbeg);
1917 break;
1918
1919 case '>':
1920 BUF_PUSH (wordend);
1921 break;
1922
1923 case 'b':
1924 BUF_PUSH (wordbound);
1925 break;
1926
1927 case 'B':
1928 BUF_PUSH (notwordbound);
1929 break;
1930
1931 case '`':
1932 BUF_PUSH (begbuf);
1933 break;
1934
1935 case '\'':
1936 BUF_PUSH (endbuf);
1937 break;
1938
1939 case '1': case '2': case '3': case '4': case '5':
1940 case '6': case '7': case '8': case '9':
1941 if (syntax & RE_NO_BK_REFS)
1942 goto normal_char;
1943
1944 c1 = c - '0';
1945
1946 if (c1 > regnum)
1947 return REG_ESUBREG;
1948
1949 /* Can't back reference to a subexpression if inside of it. */
1950 if (group_in_compile_stack (compile_stack, c1))
1951 goto normal_char;
1952
1953 laststart = b;
1954 BUF_PUSH_2 (duplicate, c1);
1955 break;
1956
1957
1958 case '+':
1959 case '?':
1960 if (syntax & RE_BK_PLUS_QM)
1961 goto handle_plus;
1962 else
1963 goto normal_backslash;
1964
1965 default:
1966 normal_backslash:
1967 /* You might think it would be useful for \ to mean
1968 not to translate; but if we don't translate it
1969 it will never match anything. */
1970 c = TRANSLATE (c);
1971 goto normal_char;
1972 }
1973 break;
1974
1975
1976 default:
1977 /* Expects the character in `c'. */
1978 normal_char:
1979 /* If no exactn currently being built. */
1980 if (!pending_exact
1981
1982 /* If last exactn not at current position. */
1983 || pending_exact + *pending_exact + 1 != b
1984
1985 /* We have only one byte following the exactn for the count. */
1986 || *pending_exact == (1 << BYTEWIDTH) - 1
1987
1988 /* If followed by a repetition operator. */
1989 || *p == '*' || *p == '^'
1990 || ((syntax & RE_BK_PLUS_QM)
1991 ? *p == '\\' && (p[1] == '+' || p[1] == '?')
1992 : (*p == '+' || *p == '?'))
1993 || ((syntax & RE_INTERVALS)
1994 && ((syntax & RE_NO_BK_BRACES)
1995 ? *p == '{'
1996 : (p[0] == '\\' && p[1] == '{'))))
1997 {
1998 /* Start building a new exactn. */
1999
2000 laststart = b;
2001
2002 BUF_PUSH_2 (exactn, 0);
2003 pending_exact = b - 1;
2004 }
2005
2006 BUF_PUSH (c);
2007 (*pending_exact)++;
2008 break;
2009 } /* switch (c) */
2010 } /* while p != pend */
2011
2012
2013 /* Through the pattern now. */
2014
2015 if (fixup_alt_jump)
2016 STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
2017
2018 if (!COMPILE_STACK_EMPTY)
2019 return REG_EPAREN;
2020
2021 free (compile_stack.stack);
2022
2023 /* We have succeeded; set the length of the buffer. */
2024 bufp->used = b - bufp->buffer;
2025
2026#ifdef DEBUG
2027 if (debug)
2028 {
2029 DEBUG_PRINT1 ("\nCompiled pattern: ");
2030 print_compiled_pattern (bufp);
2031 }
2032#endif /* DEBUG */
2033
2034 return REG_NOERROR;
2035} /* regex_compile */
2036
2037/* Subroutines for `regex_compile'. */
2038
2039/* Store OP at LOC followed by two-byte integer parameter ARG. */
2040
2041static void
2042store_op1 (op, loc, arg)
2043 re_opcode_t op;
2044 unsigned char *loc;
2045 int arg;
2046{
2047 *loc = (unsigned char) op;
2048 STORE_NUMBER (loc + 1, arg);
2049}
2050
2051
2052/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
2053
2054static void
2055store_op2 (op, loc, arg1, arg2)
2056 re_opcode_t op;
2057 unsigned char *loc;
2058 int arg1, arg2;
2059{
2060 *loc = (unsigned char) op;
2061 STORE_NUMBER (loc + 1, arg1);
2062 STORE_NUMBER (loc + 3, arg2);
2063}
2064
2065
2066/* Copy the bytes from LOC to END to open up three bytes of space at LOC
2067 for OP followed by two-byte integer parameter ARG. */
2068
2069static void
2070insert_op1 (op, loc, arg, end)
2071 re_opcode_t op;
2072 unsigned char *loc;
2073 int arg;
2074 unsigned char *end;
2075{
2076 register unsigned char *pfrom = end;
2077 register unsigned char *pto = end + 3;
2078
2079 while (pfrom != loc)
2080 *--pto = *--pfrom;
2081
2082 store_op1 (op, loc, arg);
2083}
2084
2085
2086/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
2087
2088static void
2089insert_op2 (op, loc, arg1, arg2, end)
2090 re_opcode_t op;
2091 unsigned char *loc;
2092 int arg1, arg2;
2093 unsigned char *end;
2094{
2095 register unsigned char *pfrom = end;
2096 register unsigned char *pto = end + 5;
2097
2098 while (pfrom != loc)
2099 *--pto = *--pfrom;
2100
2101 store_op2 (op, loc, arg1, arg2);
2102}
2103
2104
2105/* P points to just after a ^ in PATTERN. Return true if that ^ comes
2106 after an alternative or a begin-subexpression. We assume there is at
2107 least one character before the ^. */
2108
2109static boolean
2110at_begline_loc_p (pattern, p, syntax)
2111 const char *pattern, *p;
2112 reg_syntax_t syntax;
2113{
2114 const char *prev = p - 2;
2115 boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
2116
2117 return
2118 /* After a subexpression? */
2119 (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
2120 /* After an alternative? */
2121 || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
2122}
2123
2124
2125/* The dual of at_begline_loc_p. This one is for $. We assume there is
2126 at least one character after the $, i.e., `P < PEND'. */
2127
2128static boolean
2129at_endline_loc_p (p, pend, syntax)
2130 const char *p, *pend;
2131 int syntax;
2132{
2133 const char *next = p;
2134 boolean next_backslash = *next == '\\';
2135 const char *next_next = p + 1 < pend ? p + 1 : NULL;
2136
2137 return
2138 /* Before a subexpression? */
2139 (syntax & RE_NO_BK_PARENS ? *next == ')'
2140 : next_backslash && next_next && *next_next == ')')
2141 /* Before an alternative? */
2142 || (syntax & RE_NO_BK_VBAR ? *next == '|'
2143 : next_backslash && next_next && *next_next == '|');
2144}
2145
2146
2147/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
2148 false if it's not. */
2149
2150static boolean
2151group_in_compile_stack (compile_stack, regnum)
2152 compile_stack_type compile_stack;
2153 regnum_t regnum;
2154{
2155 int this_element;
2156
2157 for (this_element = compile_stack.avail - 1;
2158 this_element >= 0;
2159 this_element--)
2160 if (compile_stack.stack[this_element].regnum == regnum)
2161 return true;
2162
2163 return false;
2164}
2165
2166
2167/* Read the ending character of a range (in a bracket expression) from the
2168 uncompiled pattern *P_PTR (which ends at PEND). We assume the
2169 starting character is in `P[-2]'. (`P[-1]' is the character `-'.)
2170 Then we set the translation of all bits between the starting and
2171 ending characters (inclusive) in the compiled pattern B.
2172
2173 Return an error code.
2174
2175 We use these short variable names so we can use the same macros as
2176 `regex_compile' itself. */
2177
2178static reg_errcode_t
2179compile_range (p_ptr, pend, translate, syntax, b)
2180 const char **p_ptr, *pend;
2181 char *translate;
2182 reg_syntax_t syntax;
2183 unsigned char *b;
2184{
2185 unsigned this_char;
2186
2187 const char *p = *p_ptr;
2188 int range_start, range_end;
2189
2190 if (p == pend)
2191 return REG_ERANGE;
2192
2193 /* Even though the pattern is a signed `char *', we need to fetch
2194 with unsigned char *'s; if the high bit of the pattern character
2195 is set, the range endpoints will be negative if we fetch using a
2196 signed char *.
2197
2198 We also want to fetch the endpoints without translating them; the
2199 appropriate translation is done in the bit-setting loop below. */
2200 range_start = ((unsigned char *) p)[-2];
2201 range_end = ((unsigned char *) p)[0];
2202
2203 /* Have to increment the pointer into the pattern string, so the
2204 caller isn't still at the ending character. */
2205 (*p_ptr)++;
2206
2207 /* If the start is after the end, the range is empty. */
2208 if (range_start > range_end)
2209 return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
2210
2211 /* Here we see why `this_char' has to be larger than an `unsigned
2212 char' -- the range is inclusive, so if `range_end' == 0xff
2213 (assuming 8-bit characters), we would otherwise go into an infinite
2214 loop, since all characters <= 0xff. */
2215 for (this_char = range_start; this_char <= range_end; this_char++)
2216 {
2217 SET_LIST_BIT (TRANSLATE (this_char));
2218 }
2219
2220 return REG_NOERROR;
2221}
2222
2223/* Failure stack declarations and macros; both re_compile_fastmap and
2224 re_match_2 use a failure stack. These have to be macros because of
2225 REGEX_ALLOCATE. */
2226
2227
2228/* Number of failure points for which to initially allocate space
2229 when matching. If this number is exceeded, we allocate more
2230 space, so it is not a hard limit. */
2231#ifndef INIT_FAILURE_ALLOC
2232#define INIT_FAILURE_ALLOC 5
2233#endif
2234
2235/* Roughly the maximum number of failure points on the stack. Would be
2236 exactly that if always used MAX_FAILURE_SPACE each time we failed.
2237 This is a variable only so users of regex can assign to it; we never
2238 change it ourselves. */
2239int re_max_failures = 2000;
2240
2241typedef const unsigned char *fail_stack_elt_t;
2242
2243typedef struct
2244{
2245 fail_stack_elt_t *stack;
2246 unsigned size;
2247 unsigned avail; /* Offset of next open position. */
2248} fail_stack_type;
2249
2250#define FAIL_STACK_EMPTY() (fail_stack.avail == 0)
2251#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
2252#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size)
2253#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail])
2254
2255
2256/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */
2257
2258#define INIT_FAIL_STACK() \
2259 do { \
2260 fail_stack.stack = (fail_stack_elt_t *) \
2261 REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
2262 \
2263 if (fail_stack.stack == NULL) \
2264 return -2; \
2265 \
2266 fail_stack.size = INIT_FAILURE_ALLOC; \
2267 fail_stack.avail = 0; \
2268 } while (0)
2269
2270
2271/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
2272
2273 Return 1 if succeeds, and 0 if either ran out of memory
2274 allocating space for it or it was already too large.
2275
2276 REGEX_REALLOCATE requires `destination' be declared. */
2277
2278#define DOUBLE_FAIL_STACK(fail_stack) \
2279 ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \
2280 ? 0 \
2281 : ((fail_stack).stack = (fail_stack_elt_t *) \
2282 REGEX_REALLOCATE ((fail_stack).stack, \
2283 (fail_stack).size * sizeof (fail_stack_elt_t), \
2284 ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \
2285 \
2286 (fail_stack).stack == NULL \
2287 ? 0 \
2288 : ((fail_stack).size <<= 1, \
2289 1)))
2290
2291
2292/* Push PATTERN_OP on FAIL_STACK.
2293
2294 Return 1 if was able to do so and 0 if ran out of memory allocating
2295 space to do so. */
2296#define PUSH_PATTERN_OP(pattern_op, fail_stack) \
2297 ((FAIL_STACK_FULL () \
2298 && !DOUBLE_FAIL_STACK (fail_stack)) \
2299 ? 0 \
2300 : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \
2301 1))
2302
2303/* This pushes an item onto the failure stack. Must be a four-byte
2304 value. Assumes the variable `fail_stack'. Probably should only
2305 be called from within `PUSH_FAILURE_POINT'. */
2306#define PUSH_FAILURE_ITEM(item) \
2307 fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item
2308
2309/* The complement operation. Assumes `fail_stack' is nonempty. */
2310#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail]
2311
2312/* Used to omit pushing failure point id's when we're not debugging. */
2313#ifdef DEBUG
2314#define DEBUG_PUSH PUSH_FAILURE_ITEM
2315#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM ()
2316#else
2317#define DEBUG_PUSH(item)
2318#define DEBUG_POP(item_addr)
2319#endif
2320
2321
2322/* Push the information about the state we will need
2323 if we ever fail back to it.
2324
2325 Requires variables fail_stack, regstart, regend, reg_info, and
2326 num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be
2327 declared.
2328
2329 Does `return FAILURE_CODE' if runs out of memory. */
2330
2331#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \
2332 do { \
2333 char *destination; \
2334 /* Must be int, so when we don't save any registers, the arithmetic \
2335 of 0 + -1 isn't done as unsigned. */ \
2336 int this_reg; \
2337 \
2338 DEBUG_STATEMENT (failure_id++); \
2339 DEBUG_STATEMENT (nfailure_points_pushed++); \
2340 DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
2341 DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\
2342 DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\
2343 \
2344 DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \
2345 DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \
2346 \
2347 /* Ensure we have enough space allocated for what we will push. */ \
2348 while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \
2349 { \
2350 if (!DOUBLE_FAIL_STACK (fail_stack)) \
2351 return failure_code; \
2352 \
2353 DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
2354 (fail_stack).size); \
2355 DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\
2356 } \
2357 \
2358 /* Push the info, starting with the registers. */ \
2359 DEBUG_PRINT1 ("\n"); \
2360 \
2361 for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
2362 this_reg++) \
2363 { \
2364 DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
2365 DEBUG_STATEMENT (num_regs_pushed++); \
2366 \
2367 DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
2368 PUSH_FAILURE_ITEM (regstart[this_reg]); \
2369 \
2370 DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
2371 PUSH_FAILURE_ITEM (regend[this_reg]); \
2372 \
2373 DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
2374 DEBUG_PRINT2 (" match_null=%d", \
2375 REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
2376 DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
2377 DEBUG_PRINT2 (" matched_something=%d", \
2378 MATCHED_SOMETHING (reg_info[this_reg])); \
2379 DEBUG_PRINT2 (" ever_matched=%d", \
2380 EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
2381 DEBUG_PRINT1 ("\n"); \
2382 PUSH_FAILURE_ITEM (reg_info[this_reg].word); \
2383 } \
2384 \
2385 DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\
2386 PUSH_FAILURE_ITEM (lowest_active_reg); \
2387 \
2388 DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\
2389 PUSH_FAILURE_ITEM (highest_active_reg); \
2390 \
2391 DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \
2392 DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \
2393 PUSH_FAILURE_ITEM (pattern_place); \
2394 \
2395 DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \
2396 DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \
2397 size2); \
2398 DEBUG_PRINT1 ("'\n"); \
2399 PUSH_FAILURE_ITEM (string_place); \
2400 \
2401 DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \
2402 DEBUG_PUSH (failure_id); \
2403 } while (0)
2404
2405/* This is the number of items that are pushed and popped on the stack
2406 for each register. */
2407#define NUM_REG_ITEMS 3
2408
2409/* Individual items aside from the registers. */
2410#ifdef DEBUG
2411#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */
2412#else
2413#define NUM_NONREG_ITEMS 4
2414#endif
2415
2416/* We push at most this many items on the stack. */
2417#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
2418
2419/* We actually push this many items. */
2420#define NUM_FAILURE_ITEMS \
2421 ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \
2422 + NUM_NONREG_ITEMS)
2423
2424/* How many items can still be added to the stack without overflowing it. */
2425#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
2426
2427
2428/* Pops what PUSH_FAIL_STACK pushes.
2429
2430 We restore into the parameters, all of which should be lvalues:
2431 STR -- the saved data position.
2432 PAT -- the saved pattern position.
2433 LOW_REG, HIGH_REG -- the highest and lowest active registers.
2434 REGSTART, REGEND -- arrays of string positions.
2435 REG_INFO -- array of information about each subexpression.
2436
2437 Also assumes the variables `fail_stack' and (if debugging), `bufp',
2438 `pend', `string1', `size1', `string2', and `size2'. */
2439
2440#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
2441{ \
2442 DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \
2443 int this_reg; \
2444 const unsigned char *string_temp; \
2445 \
2446 assert (!FAIL_STACK_EMPTY ()); \
2447 \
2448 /* Remove failure points and point to how many regs pushed. */ \
2449 DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \
2450 DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \
2451 DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \
2452 \
2453 assert (fail_stack.avail >= NUM_NONREG_ITEMS); \
2454 \
2455 DEBUG_POP (&failure_id); \
2456 DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \
2457 \
2458 /* If the saved string location is NULL, it came from an \
2459 on_failure_keep_string_jump opcode, and we want to throw away the \
2460 saved NULL, thus retaining our current position in the string. */ \
2461 string_temp = POP_FAILURE_ITEM (); \
2462 if (string_temp != NULL) \
2463 str = (const char *) string_temp; \
2464 \
2465 DEBUG_PRINT2 (" Popping string 0x%x: `", str); \
2466 DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \
2467 DEBUG_PRINT1 ("'\n"); \
2468 \
2469 pat = (unsigned char *) POP_FAILURE_ITEM (); \
2470 DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \
2471 DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \
2472 \
2473 /* Restore register info. */ \
2474 high_reg = (unsigned) POP_FAILURE_ITEM (); \
2475 DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \
2476 \
2477 low_reg = (unsigned) POP_FAILURE_ITEM (); \
2478 DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \
2479 \
2480 for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
2481 { \
2482 DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
2483 \
2484 reg_info[this_reg].word = POP_FAILURE_ITEM (); \
2485 DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
2486 \
2487 regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \
2488 DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
2489 \
2490 regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \
2491 DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
2492 } \
2493 \
2494 DEBUG_STATEMENT (nfailure_points_popped++); \
2495} /* POP_FAILURE_POINT */
2496
2497/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
2498 BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
2499 characters can start a string that matches the pattern. This fastmap
2500 is used by re_search to skip quickly over impossible starting points.
2501
2502 The caller must supply the address of a (1 << BYTEWIDTH)-byte data
2503 area as BUFP->fastmap.
2504
2505 We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
2506 the pattern buffer.
2507
2508 Returns 0 if we succeed, -2 if an internal error. */
2509
2510int
2511re_compile_fastmap (bufp)
2512 struct re_pattern_buffer *bufp;
2513{
2514 int j, k;
2515 fail_stack_type fail_stack;
2516#ifndef REGEX_MALLOC
2517 char *destination;
2518#endif
2519 /* We don't push any register information onto the failure stack. */
2520 unsigned num_regs = 0;
2521
2522 register char *fastmap = bufp->fastmap;
2523 unsigned char *pattern = bufp->buffer;
2524 unsigned long size = bufp->used;
2525 const unsigned char *p = pattern;
2526 register unsigned char *pend = pattern + size;
2527
2528 /* Assume that each path through the pattern can be null until
2529 proven otherwise. We set this false at the bottom of switch
2530 statement, to which we get only if a particular path doesn't
2531 match the empty string. */
2532 boolean path_can_be_null = true;
2533
2534 /* We aren't doing a `succeed_n' to begin with. */
2535 boolean succeed_n_p = false;
2536
2537 assert (fastmap != NULL && p != NULL);
2538
2539 INIT_FAIL_STACK ();
2540 bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */
2541 bufp->fastmap_accurate = 1; /* It will be when we're done. */
2542 bufp->can_be_null = 0;
2543
2544 while (p != pend || !FAIL_STACK_EMPTY ())
2545 {
2546 if (p == pend)
2547 {
2548 bufp->can_be_null |= path_can_be_null;
2549
2550 /* Reset for next path. */
2551 path_can_be_null = true;
2552
2553 p = fail_stack.stack[--fail_stack.avail];
2554 }
2555
2556 /* We should never be about to go beyond the end of the pattern. */
2557 assert (p < pend);
2558
2559#ifdef SWITCH_ENUM_BUG
2560 switch ((int) ((re_opcode_t) *p++))
2561#else
2562 switch ((re_opcode_t) *p++)
2563#endif
2564 {
2565
2566 /* I guess the idea here is to simply not bother with a fastmap
2567 if a backreference is used, since it's too hard to figure out
2568 the fastmap for the corresponding group. Setting
2569 `can_be_null' stops `re_search_2' from using the fastmap, so
2570 that is all we do. */
2571 case duplicate:
2572 bufp->can_be_null = 1;
2573 return 0;
2574
2575
2576 /* Following are the cases which match a character. These end
2577 with `break'. */
2578
2579 case exactn:
2580 fastmap[p[1]] = 1;
2581 break;
2582
2583
2584 case charset:
2585 for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
2586 if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
2587 fastmap[j] = 1;
2588 break;
2589
2590
2591 case charset_not:
2592 /* Chars beyond end of map must be allowed. */
2593 for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
2594 fastmap[j] = 1;
2595
2596 for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
2597 if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
2598 fastmap[j] = 1;
2599 break;
2600
2601
2602 case wordchar:
2603 for (j = 0; j < (1 << BYTEWIDTH); j++)
2604 if (SYNTAX (j) == Sword)
2605 fastmap[j] = 1;
2606 break;
2607
2608
2609 case notwordchar:
2610 for (j = 0; j < (1 << BYTEWIDTH); j++)
2611 if (SYNTAX (j) != Sword)
2612 fastmap[j] = 1;
2613 break;
2614
2615
2616 case anychar:
2617 /* `.' matches anything ... */
2618 for (j = 0; j < (1 << BYTEWIDTH); j++)
2619 fastmap[j] = 1;
2620
2621 /* ... except perhaps newline. */
2622 if (!(bufp->syntax & RE_DOT_NEWLINE))
2623 fastmap['\n'] = 0;
2624
2625 /* Return if we have already set `can_be_null'; if we have,
2626 then the fastmap is irrelevant. Something's wrong here. */
2627 else if (bufp->can_be_null)
2628 return 0;
2629
2630 /* Otherwise, have to check alternative paths. */
2631 break;
2632
2633
2634#ifdef emacs
2635 case syntaxspec:
2636 k = *p++;
2637 for (j = 0; j < (1 << BYTEWIDTH); j++)
2638 if (SYNTAX (j) == (enum syntaxcode) k)
2639 fastmap[j] = 1;
2640 break;
2641
2642
2643 case notsyntaxspec:
2644 k = *p++;
2645 for (j = 0; j < (1 << BYTEWIDTH); j++)
2646 if (SYNTAX (j) != (enum syntaxcode) k)
2647 fastmap[j] = 1;
2648 break;
2649
2650
2651 /* All cases after this match the empty string. These end with
2652 `continue'. */
2653
2654
2655 case before_dot:
2656 case at_dot:
2657 case after_dot:
2658 continue;
2659#endif /* not emacs */
2660
2661
2662 case no_op:
2663 case begline:
2664 case endline:
2665 case begbuf:
2666 case endbuf:
2667 case wordbound:
2668 case notwordbound:
2669 case wordbeg:
2670 case wordend:
2671 case push_dummy_failure:
2672 continue;
2673
2674
2675 case jump_n:
2676 case pop_failure_jump:
2677 case maybe_pop_jump:
2678 case jump:
2679 case jump_past_alt:
2680 case dummy_failure_jump:
2681 EXTRACT_NUMBER_AND_INCR (j, p);
2682 p += j;
2683 if (j > 0)
2684 continue;
2685
2686 /* Jump backward implies we just went through the body of a
2687 loop and matched nothing. Opcode jumped to should be
2688 `on_failure_jump' or `succeed_n'. Just treat it like an
2689 ordinary jump. For a * loop, it has pushed its failure
2690 point already; if so, discard that as redundant. */
2691 if ((re_opcode_t) *p != on_failure_jump
2692 && (re_opcode_t) *p != succeed_n)
2693 continue;
2694
2695 p++;
2696 EXTRACT_NUMBER_AND_INCR (j, p);
2697 p += j;
2698
2699 /* If what's on the stack is where we are now, pop it. */
2700 if (!FAIL_STACK_EMPTY ()
2701 && fail_stack.stack[fail_stack.avail - 1] == p)
2702 fail_stack.avail--;
2703
2704 continue;
2705
2706
2707 case on_failure_jump:
2708 case on_failure_keep_string_jump:
2709 handle_on_failure_jump:
2710 EXTRACT_NUMBER_AND_INCR (j, p);
2711
2712 /* For some patterns, e.g., `(a?)?', `p+j' here points to the
2713 end of the pattern. We don't want to push such a point,
2714 since when we restore it above, entering the switch will
2715 increment `p' past the end of the pattern. We don't need
2716 to push such a point since we obviously won't find any more
2717 fastmap entries beyond `pend'. Such a pattern can match
2718 the null string, though. */
2719 if (p + j < pend)
2720 {
2721 if (!PUSH_PATTERN_OP (p + j, fail_stack))
2722 return -2;
2723 }
2724 else
2725 bufp->can_be_null = 1;
2726
2727 if (succeed_n_p)
2728 {
2729 EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
2730 succeed_n_p = false;
2731 }
2732
2733 continue;
2734
2735
2736 case succeed_n:
2737 /* Get to the number of times to succeed. */
2738 p += 2;
2739
2740 /* Increment p past the n for when k != 0. */
2741 EXTRACT_NUMBER_AND_INCR (k, p);
2742 if (k == 0)
2743 {
2744 p -= 4;
2745 succeed_n_p = true; /* Spaghetti code alert. */
2746 goto handle_on_failure_jump;
2747 }
2748 continue;
2749
2750
2751 case set_number_at:
2752 p += 4;
2753 continue;
2754
2755
2756 case start_memory:
2757 case stop_memory:
2758 p += 2;
2759 continue;
2760
2761
2762 default:
2763 abort (); /* We have listed all the cases. */
2764 } /* switch *p++ */
2765
2766 /* Getting here means we have found the possible starting
2767 characters for one path of the pattern -- and that the empty
2768 string does not match. We need not follow this path further.
2769 Instead, look at the next alternative (remembered on the
2770 stack), or quit if no more. The test at the top of the loop
2771 does these things. */
2772 path_can_be_null = false;
2773 p = pend;
2774 } /* while p */
2775
2776 /* Set `can_be_null' for the last path (also the first path, if the
2777 pattern is empty). */
2778 bufp->can_be_null |= path_can_be_null;
2779 return 0;
2780} /* re_compile_fastmap */
2781
2782/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
2783 ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
2784 this memory for recording register information. STARTS and ENDS
2785 must be allocated using the malloc library routine, and must each
2786 be at least NUM_REGS * sizeof (regoff_t) bytes long.
2787
2788 If NUM_REGS == 0, then subsequent matches should allocate their own
2789 register data.
2790
2791 Unless this function is called, the first search or match using
2792 PATTERN_BUFFER will allocate its own register data, without
2793 freeing the old data. */
2794
2795void
2796re_set_registers (bufp, regs, num_regs, starts, ends)
2797 struct re_pattern_buffer *bufp;
2798 struct re_registers *regs;
2799 unsigned num_regs;
2800 regoff_t *starts, *ends;
2801{
2802 if (num_regs)
2803 {
2804 bufp->regs_allocated = REGS_REALLOCATE;
2805 regs->num_regs = num_regs;
2806 regs->start = starts;
2807 regs->end = ends;
2808 }
2809 else
2810 {
2811 bufp->regs_allocated = REGS_UNALLOCATED;
2812 regs->num_regs = 0;
2813 regs->start = regs->end = (regoff_t) 0;
2814 }
2815}
2816
2817/* Searching routines. */
2818
2819/* Like re_search_2, below, but only one string is specified, and
2820 doesn't let you say where to stop matching. */
2821
2822int
2823re_search (bufp, string, size, startpos, range, regs)
2824 struct re_pattern_buffer *bufp;
2825 const char *string;
2826 int size, startpos, range;
2827 struct re_registers *regs;
2828{
2829 return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
2830 regs, size);
2831}
2832
2833
2834/* Using the compiled pattern in BUFP->buffer, first tries to match the
2835 virtual concatenation of STRING1 and STRING2, starting first at index
2836 STARTPOS, then at STARTPOS + 1, and so on.
2837
2838 STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
2839
2840 RANGE is how far to scan while trying to match. RANGE = 0 means try
2841 only at STARTPOS; in general, the last start tried is STARTPOS +
2842 RANGE.
2843
2844 In REGS, return the indices of the virtual concatenation of STRING1
2845 and STRING2 that matched the entire BUFP->buffer and its contained
2846 subexpressions.
2847
2848 Do not consider matching one past the index STOP in the virtual
2849 concatenation of STRING1 and STRING2.
2850
2851 We return either the position in the strings at which the match was
2852 found, -1 if no match, or -2 if error (such as failure
2853 stack overflow). */
2854
2855int
2856re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
2857 struct re_pattern_buffer *bufp;
2858 const char *string1, *string2;
2859 int size1, size2;
2860 int startpos;
2861 int range;
2862 struct re_registers *regs;
2863 int stop;
2864{
2865 int val;
2866 register char *fastmap = bufp->fastmap;
2867 register char *translate = bufp->translate;
2868 int total_size = size1 + size2;
2869 int endpos = startpos + range;
2870
2871 /* Check for out-of-range STARTPOS. */
2872 if (startpos < 0 || startpos > total_size)
2873 return -1;
2874
2875 /* Fix up RANGE if it might eventually take us outside
2876 the virtual concatenation of STRING1 and STRING2. */
2877 if (endpos < -1)
2878 range = -1 - startpos;
2879 else if (endpos > total_size)
2880 range = total_size - startpos;
2881
2882 /* If the search isn't to be a backwards one, don't waste time in a
2883 search for a pattern that must be anchored. */
2884 if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
2885 {
2886 if (startpos > 0)
2887 return -1;
2888 else
2889 range = 1;
2890 }
2891
2892 /* Update the fastmap now if not correct already. */
2893 if (fastmap && !bufp->fastmap_accurate)
2894 if (re_compile_fastmap (bufp) == -2)
2895 return -2;
2896
2897 /* Loop through the string, looking for a place to start matching. */
2898 for (;;)
2899 {
2900 /* If a fastmap is supplied, skip quickly over characters that
2901 cannot be the start of a match. If the pattern can match the
2902 null string, however, we don't need to skip characters; we want
2903 the first null string. */
2904 if (fastmap && startpos < total_size && !bufp->can_be_null)
2905 {
2906 if (range > 0) /* Searching forwards. */
2907 {
2908 register const char *d;
2909 register int lim = 0;
2910 int irange = range;
2911
2912 if (startpos < size1 && startpos + range >= size1)
2913 lim = range - (size1 - startpos);
2914
2915 d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
2916
2917 /* Written out as an if-else to avoid testing `translate'
2918 inside the loop. */
2919 if (translate)
2920 while (range > lim
2921 && !fastmap[(unsigned char)
2922 translate[(unsigned char) *d++]])
2923 range--;
2924 else
2925 while (range > lim && !fastmap[(unsigned char) *d++])
2926 range--;
2927
2928 startpos += irange - range;
2929 }
2930 else /* Searching backwards. */
2931 {
2932 register char c = (size1 == 0 || startpos >= size1
2933 ? string2[startpos - size1]
2934 : string1[startpos]);
2935
2936 if (!fastmap[(unsigned char) TRANSLATE (c)])
2937 goto advance;
2938 }
2939 }
2940
2941 /* If can't match the null string, and that's all we have left, fail. */
2942 if (range >= 0 && startpos == total_size && fastmap
2943 && !bufp->can_be_null)
2944 return -1;
2945
2946 val = re_match_2 (bufp, string1, size1, string2, size2,
2947 startpos, regs, stop);
2948 if (val >= 0)
2949 return startpos;
2950
2951 if (val == -2)
2952 return -2;
2953
2954 advance:
2955 if (!range)
2956 break;
2957 else if (range > 0)
2958 {
2959 range--;
2960 startpos++;
2961 }
2962 else
2963 {
2964 range++;
2965 startpos--;
2966 }
2967 }
2968 return -1;
2969} /* re_search_2 */
2970
2971/* Declarations and macros for re_match_2. */
2972
2973static int bcmp_translate ();
2974static boolean alt_match_null_string_p (),
2975 common_op_match_null_string_p (),
2976 group_match_null_string_p ();
2977
2978/* Structure for per-register (a.k.a. per-group) information.
2979 This must not be longer than one word, because we push this value
2980 onto the failure stack. Other register information, such as the
2981 starting and ending positions (which are addresses), and the list of
2982 inner groups (which is a bits list) are maintained in separate
2983 variables.
2984
2985 We are making a (strictly speaking) nonportable assumption here: that
2986 the compiler will pack our bit fields into something that fits into
2987 the type of `word', i.e., is something that fits into one item on the
2988 failure stack. */
2989typedef union
2990{
2991 fail_stack_elt_t word;
2992 struct
2993 {
2994 /* This field is one if this group can match the empty string,
2995 zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */
2996#define MATCH_NULL_UNSET_VALUE 3
2997 unsigned match_null_string_p : 2;
2998 unsigned is_active : 1;
2999 unsigned matched_something : 1;
3000 unsigned ever_matched_something : 1;
3001 } bits;
3002} register_info_type;
3003
3004#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p)
3005#define IS_ACTIVE(R) ((R).bits.is_active)
3006#define MATCHED_SOMETHING(R) ((R).bits.matched_something)
3007#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something)
3008
3009
3010/* Call this when have matched a real character; it sets `matched' flags
3011 for the subexpressions which we are currently inside. Also records
3012 that those subexprs have matched. */
3013#define SET_REGS_MATCHED() \
3014 do \
3015 { \
3016 unsigned r; \
3017 for (r = lowest_active_reg; r <= highest_active_reg; r++) \
3018 { \
3019 MATCHED_SOMETHING (reg_info[r]) \
3020 = EVER_MATCHED_SOMETHING (reg_info[r]) \
3021 = 1; \
3022 } \
3023 } \
3024 while (0)
3025
3026
3027/* This converts PTR, a pointer into one of the search strings `string1'
3028 and `string2' into an offset from the beginning of that string. */
3029#define POINTER_TO_OFFSET(ptr) \
3030 (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1)
3031
3032/* Registers are set to a sentinel when they haven't yet matched. */
3033#define REG_UNSET_VALUE ((char *) -1)
3034#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
3035
3036
3037/* Macros for dealing with the split strings in re_match_2. */
3038
3039#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
3040
3041/* Call before fetching a character with *d. This switches over to
3042 string2 if necessary. */
3043#define PREFETCH() \
3044 while (d == dend) \
3045 { \
3046 /* End of string2 => fail. */ \
3047 if (dend == end_match_2) \
3048 goto fail; \
3049 /* End of string1 => advance to string2. */ \
3050 d = string2; \
3051 dend = end_match_2; \
3052 }
3053
3054
3055/* Test if at very beginning or at very end of the virtual concatenation
3056 of `string1' and `string2'. If only one string, it's `string2'. */
3057#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
3058#define AT_STRINGS_END(d) ((d) == end2)
3059
3060
3061/* Test if D points to a character which is word-constituent. We have
3062 two special cases to check for: if past the end of string1, look at
3063 the first character in string2; and if before the beginning of
3064 string2, look at the last character in string1. */
3065#define WORDCHAR_P(d) \
3066 (SYNTAX ((d) == end1 ? *string2 \
3067 : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \
3068 == Sword)
3069
3070/* Test if the character before D and the one at D differ with respect
3071 to being word-constituent. */
3072#define AT_WORD_BOUNDARY(d) \
3073 (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \
3074 || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
3075
3076
3077/* Free everything we malloc. */
3078#ifdef REGEX_MALLOC
3079#define FREE_VAR(var) if (var) free (var); var = NULL
3080#define FREE_VARIABLES() \
3081 do { \
3082 FREE_VAR (fail_stack.stack); \
3083 FREE_VAR (regstart); \
3084 FREE_VAR (regend); \
3085 FREE_VAR (old_regstart); \
3086 FREE_VAR (old_regend); \
3087 FREE_VAR (best_regstart); \
3088 FREE_VAR (best_regend); \
3089 FREE_VAR (reg_info); \
3090 FREE_VAR (reg_dummy); \
3091 FREE_VAR (reg_info_dummy); \
3092 } while (0)
3093#else /* not REGEX_MALLOC */
3094/* Some MIPS systems (at least) want this to free alloca'd storage. */
3095#define FREE_VARIABLES() alloca (0)
3096#endif /* not REGEX_MALLOC */
3097
3098
3099/* These values must meet several constraints. They must not be valid
3100 register values; since we have a limit of 255 registers (because
3101 we use only one byte in the pattern for the register number), we can
3102 use numbers larger than 255. They must differ by 1, because of
3103 NUM_FAILURE_ITEMS above. And the value for the lowest register must
3104 be larger than the value for the highest register, so we do not try
3105 to actually save any registers when none are active. */
3106#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
3107#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
3108
3109/* Matching routines. */
3110
3111#ifndef emacs /* Emacs never uses this. */
3112/* re_match is like re_match_2 except it takes only a single string. */
3113
3114int
3115re_match (bufp, string, size, pos, regs)
3116 struct re_pattern_buffer *bufp;
3117 const char *string;
3118 int size, pos;
3119 struct re_registers *regs;
3120 {
3121 return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size);
3122}
3123#endif /* not emacs */
3124
3125
3126/* re_match_2 matches the compiled pattern in BUFP against the
3127 the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
3128 and SIZE2, respectively). We start matching at POS, and stop
3129 matching at STOP.
3130
3131 If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
3132 store offsets for the substring each group matched in REGS. See the
3133 documentation for exactly how many groups we fill.
3134
3135 We return -1 if no match, -2 if an internal error (such as the
3136 failure stack overflowing). Otherwise, we return the length of the
3137 matched substring. */
3138
3139int
3140re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
3141 struct re_pattern_buffer *bufp;
3142 const char *string1, *string2;
3143 int size1, size2;
3144 int pos;
3145 struct re_registers *regs;
3146 int stop;
3147{
3148 /* General temporaries. */
3149 int mcnt;
3150 unsigned char *p1;
3151
3152 /* Just past the end of the corresponding string. */
3153 const char *end1, *end2;
3154
3155 /* Pointers into string1 and string2, just past the last characters in
3156 each to consider matching. */
3157 const char *end_match_1, *end_match_2;
3158
3159 /* Where we are in the data, and the end of the current string. */
3160 const char *d, *dend;
3161
3162 /* Where we are in the pattern, and the end of the pattern. */
3163 unsigned char *p = bufp->buffer;
3164 register unsigned char *pend = p + bufp->used;
3165
3166 /* We use this to map every character in the string. */
3167 char *translate = bufp->translate;
3168
3169 /* Failure point stack. Each place that can handle a failure further
3170 down the line pushes a failure point on this stack. It consists of
3171 restart, regend, and reg_info for all registers corresponding to
3172 the subexpressions we're currently inside, plus the number of such
3173 registers, and, finally, two char *'s. The first char * is where
3174 to resume scanning the pattern; the second one is where to resume
3175 scanning the strings. If the latter is zero, the failure point is
3176 a ``dummy''; if a failure happens and the failure point is a dummy,
3177 it gets discarded and the next next one is tried. */
3178 fail_stack_type fail_stack;
3179#ifdef DEBUG
3180 static unsigned failure_id = 0;
3181 unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
3182#endif
3183
3184 /* We fill all the registers internally, independent of what we
3185 return, for use in backreferences. The number here includes
3186 an element for register zero. */
3187 unsigned num_regs = bufp->re_nsub + 1;
3188
3189 /* The currently active registers. */
3190 unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
3191 unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
3192
3193 /* Information on the contents of registers. These are pointers into
3194 the input strings; they record just what was matched (on this
3195 attempt) by a subexpression part of the pattern, that is, the
3196 regnum-th regstart pointer points to where in the pattern we began
3197 matching and the regnum-th regend points to right after where we
3198 stopped matching the regnum-th subexpression. (The zeroth register
3199 keeps track of what the whole pattern matches.) */
3200 const char **regstart = NULL, **regend = NULL;
3201
3202 /* If a group that's operated upon by a repetition operator fails to
3203 match anything, then the register for its start will need to be
3204 restored because it will have been set to wherever in the string we
3205 are when we last see its open-group operator. Similarly for a
3206 register's end. */
3207 const char **old_regstart = NULL, **old_regend = NULL;
3208
3209 /* The is_active field of reg_info helps us keep track of which (possibly
3210 nested) subexpressions we are currently in. The matched_something
3211 field of reg_info[reg_num] helps us tell whether or not we have
3212 matched any of the pattern so far this time through the reg_num-th
3213 subexpression. These two fields get reset each time through any
3214 loop their register is in. */
3215 register_info_type *reg_info = NULL;
3216
3217 /* The following record the register info as found in the above
3218 variables when we find a match better than any we've seen before.
3219 This happens as we backtrack through the failure points, which in
3220 turn happens only if we have not yet matched the entire string. */
3221 unsigned best_regs_set = false;
3222 const char **best_regstart = NULL, **best_regend = NULL;
3223
3224 /* Logically, this is `best_regend[0]'. But we don't want to have to
3225 allocate space for that if we're not allocating space for anything
3226 else (see below). Also, we never need info about register 0 for
3227 any of the other register vectors, and it seems rather a kludge to
3228 treat `best_regend' differently than the rest. So we keep track of
3229 the end of the best match so far in a separate variable. We
3230 initialize this to NULL so that when we backtrack the first time
3231 and need to test it, it's not garbage. */
3232 const char *match_end = NULL;
3233
3234 /* Used when we pop values we don't care about. */
3235 const char **reg_dummy = NULL;
3236 register_info_type *reg_info_dummy = NULL;
3237
3238#ifdef DEBUG
3239 /* Counts the total number of registers pushed. */
3240 unsigned num_regs_pushed = 0;
3241#endif
3242
3243 DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
3244
3245 INIT_FAIL_STACK ();
3246
3247 /* Do not bother to initialize all the register variables if there are
3248 no groups in the pattern, as it takes a fair amount of time. If
3249 there are groups, we include space for register 0 (the whole
3250 pattern), even though we never use it, since it simplifies the
3251 array indexing. We should fix this. */
3252 if (bufp->re_nsub)
3253 {
3254 regstart = REGEX_TALLOC (num_regs, const char *);
3255 regend = REGEX_TALLOC (num_regs, const char *);
3256 old_regstart = REGEX_TALLOC (num_regs, const char *);
3257 old_regend = REGEX_TALLOC (num_regs, const char *);
3258 best_regstart = REGEX_TALLOC (num_regs, const char *);
3259 best_regend = REGEX_TALLOC (num_regs, const char *);
3260 reg_info = REGEX_TALLOC (num_regs, register_info_type);
3261 reg_dummy = REGEX_TALLOC (num_regs, const char *);
3262 reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
3263
3264 if (!(regstart && regend && old_regstart && old_regend && reg_info
3265 && best_regstart && best_regend && reg_dummy && reg_info_dummy))
3266 {
3267 FREE_VARIABLES ();
3268 return -2;
3269 }
3270 }
3271#ifdef REGEX_MALLOC
3272 else
3273 {
3274 /* We must initialize all our variables to NULL, so that
3275 `FREE_VARIABLES' doesn't try to free them. */
3276 regstart = regend = old_regstart = old_regend = best_regstart
3277 = best_regend = reg_dummy = NULL;
3278 reg_info = reg_info_dummy = (register_info_type *) NULL;
3279 }
3280#endif /* REGEX_MALLOC */
3281
3282 /* The starting position is bogus. */
3283 if (pos < 0 || pos > size1 + size2)
3284 {
3285 FREE_VARIABLES ();
3286 return -1;
3287 }
3288
3289 /* Initialize subexpression text positions to -1 to mark ones that no
3290 start_memory/stop_memory has been seen for. Also initialize the
3291 register information struct. */
3292 for (mcnt = 1; mcnt < num_regs; mcnt++)
3293 {
3294 regstart[mcnt] = regend[mcnt]
3295 = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
3296
3297 REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
3298 IS_ACTIVE (reg_info[mcnt]) = 0;
3299 MATCHED_SOMETHING (reg_info[mcnt]) = 0;
3300 EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
3301 }
3302
3303 /* We move `string1' into `string2' if the latter's empty -- but not if
3304 `string1' is null. */
3305 if (size2 == 0 && string1 != NULL)
3306 {
3307 string2 = string1;
3308 size2 = size1;
3309 string1 = 0;
3310 size1 = 0;
3311 }
3312 end1 = string1 + size1;
3313 end2 = string2 + size2;
3314
3315 /* Compute where to stop matching, within the two strings. */
3316 if (stop <= size1)
3317 {
3318 end_match_1 = string1 + stop;
3319 end_match_2 = string2;
3320 }
3321 else
3322 {
3323 end_match_1 = end1;
3324 end_match_2 = string2 + stop - size1;
3325 }
3326
3327 /* `p' scans through the pattern as `d' scans through the data.
3328 `dend' is the end of the input string that `d' points within. `d'
3329 is advanced into the following input string whenever necessary, but
3330 this happens before fetching; therefore, at the beginning of the
3331 loop, `d' can be pointing at the end of a string, but it cannot
3332 equal `string2'. */
3333 if (size1 > 0 && pos <= size1)
3334 {
3335 d = string1 + pos;
3336 dend = end_match_1;
3337 }
3338 else
3339 {
3340 d = string2 + pos - size1;
3341 dend = end_match_2;
3342 }
3343
3344 DEBUG_PRINT1 ("The compiled pattern is: ");
3345 DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
3346 DEBUG_PRINT1 ("The string to match is: `");
3347 DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
3348 DEBUG_PRINT1 ("'\n");
3349
3350 /* This loops over pattern commands. It exits by returning from the
3351 function if the match is complete, or it drops through if the match
3352 fails at this starting point in the input data. */
3353 for (;;)
3354 {
3355 DEBUG_PRINT2 ("\n0x%x: ", p);
3356
3357 if (p == pend)
3358 { /* End of pattern means we might have succeeded. */
3359 DEBUG_PRINT1 ("end of pattern ... ");
3360
3361 /* If we haven't matched the entire string, and we want the
3362 longest match, try backtracking. */
3363 if (d != end_match_2)
3364 {
3365 DEBUG_PRINT1 ("backtracking.\n");
3366
3367 if (!FAIL_STACK_EMPTY ())
3368 { /* More failure points to try. */
3369 boolean same_str_p = (FIRST_STRING_P (match_end)
3370 == MATCHING_IN_FIRST_STRING);
3371
3372 /* If exceeds best match so far, save it. */
3373 if (!best_regs_set
3374 || (same_str_p && d > match_end)
3375 || (!same_str_p && !MATCHING_IN_FIRST_STRING))
3376 {
3377 best_regs_set = true;
3378 match_end = d;
3379
3380 DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
3381
3382 for (mcnt = 1; mcnt < num_regs; mcnt++)
3383 {
3384 best_regstart[mcnt] = regstart[mcnt];
3385 best_regend[mcnt] = regend[mcnt];
3386 }
3387 }
3388 goto fail;
3389 }
3390
3391 /* If no failure points, don't restore garbage. */
3392 else if (best_regs_set)
3393 {
3394 restore_best_regs:
3395 /* Restore best match. It may happen that `dend ==
3396 end_match_1' while the restored d is in string2.
3397 For example, the pattern `x.*y.*z' against the
3398 strings `x-' and `y-z-', if the two strings are
3399 not consecutive in memory. */
3400 DEBUG_PRINT1 ("Restoring best registers.\n");
3401
3402 d = match_end;
3403 dend = ((d >= string1 && d <= end1)
3404 ? end_match_1 : end_match_2);
3405
3406 for (mcnt = 1; mcnt < num_regs; mcnt++)
3407 {
3408 regstart[mcnt] = best_regstart[mcnt];
3409 regend[mcnt] = best_regend[mcnt];
3410 }
3411 }
3412 } /* d != end_match_2 */
3413
3414 DEBUG_PRINT1 ("Accepting match.\n");
3415
3416 /* If caller wants register contents data back, do it. */
3417 if (regs && !bufp->no_sub)
3418 {
3419 /* Have the register data arrays been allocated? */
3420 if (bufp->regs_allocated == REGS_UNALLOCATED)
3421 { /* No. So allocate them with malloc. We need one
3422 extra element beyond `num_regs' for the `-1' marker
3423 GNU code uses. */
3424 regs->num_regs = MAX (RE_NREGS, num_regs + 1);
3425 regs->start = TALLOC (regs->num_regs, regoff_t);
3426 regs->end = TALLOC (regs->num_regs, regoff_t);
3427 if (regs->start == NULL || regs->end == NULL)
3428 return -2;
3429 bufp->regs_allocated = REGS_REALLOCATE;
3430 }
3431 else if (bufp->regs_allocated == REGS_REALLOCATE)
3432 { /* Yes. If we need more elements than were already
3433 allocated, reallocate them. If we need fewer, just
3434 leave it alone. */
3435 if (regs->num_regs < num_regs + 1)
3436 {
3437 regs->num_regs = num_regs + 1;
3438 RETALLOC (regs->start, regs->num_regs, regoff_t);
3439 RETALLOC (regs->end, regs->num_regs, regoff_t);
3440 if (regs->start == NULL || regs->end == NULL)
3441 return -2;
3442 }
3443 }
3444 else
3445 assert (bufp->regs_allocated == REGS_FIXED);
3446
3447 /* Convert the pointer data in `regstart' and `regend' to
3448 indices. Register zero has to be set differently,
3449 since we haven't kept track of any info for it. */
3450 if (regs->num_regs > 0)
3451 {
3452 regs->start[0] = pos;
3453 regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1
3454 : d - string2 + size1);
3455 }
3456
3457 /* Go through the first `min (num_regs, regs->num_regs)'
3458 registers, since that is all we initialized. */
3459 for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
3460 {
3461 if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
3462 regs->start[mcnt] = regs->end[mcnt] = -1;
3463 else
3464 {
3465 regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]);
3466 regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]);
3467 }
3468 }
3469
3470 /* If the regs structure we return has more elements than
3471 were in the pattern, set the extra elements to -1. If
3472 we (re)allocated the registers, this is the case,
3473 because we always allocate enough to have at least one
3474 -1 at the end. */
3475 for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
3476 regs->start[mcnt] = regs->end[mcnt] = -1;
3477 } /* regs && !bufp->no_sub */
3478
3479 FREE_VARIABLES ();
3480 DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
3481 nfailure_points_pushed, nfailure_points_popped,
3482 nfailure_points_pushed - nfailure_points_popped);
3483 DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
3484
3485 mcnt = d - pos - (MATCHING_IN_FIRST_STRING
3486 ? string1
3487 : string2 - size1);
3488
3489 DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
3490
3491 return mcnt;
3492 }
3493
3494 /* Otherwise match next pattern command. */
3495#ifdef SWITCH_ENUM_BUG
3496 switch ((int) ((re_opcode_t) *p++))
3497#else
3498 switch ((re_opcode_t) *p++)
3499#endif
3500 {
3501 /* Ignore these. Used to ignore the n of succeed_n's which
3502 currently have n == 0. */
3503 case no_op:
3504 DEBUG_PRINT1 ("EXECUTING no_op.\n");
3505 break;
3506
3507
3508 /* Match the next n pattern characters exactly. The following
3509 byte in the pattern defines n, and the n bytes after that
3510 are the characters to match. */
3511 case exactn:
3512 mcnt = *p++;
3513 DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
3514
3515 /* This is written out as an if-else so we don't waste time
3516 testing `translate' inside the loop. */
3517 if (translate)
3518 {
3519 do
3520 {
3521 PREFETCH ();
3522 if (translate[(unsigned char) *d++] != (char) *p++)
3523 goto fail;
3524 }
3525 while (--mcnt);
3526 }
3527 else
3528 {
3529 do
3530 {
3531 PREFETCH ();
3532 if (*d++ != (char) *p++) goto fail;
3533 }
3534 while (--mcnt);
3535 }
3536 SET_REGS_MATCHED ();
3537 break;
3538
3539
3540 /* Match any character except possibly a newline or a null. */
3541 case anychar:
3542 DEBUG_PRINT1 ("EXECUTING anychar.\n");
3543
3544 PREFETCH ();
3545
3546 if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
3547 || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
3548 goto fail;
3549
3550 SET_REGS_MATCHED ();
3551 DEBUG_PRINT2 (" Matched `%d'.\n", *d);
3552 d++;
3553 break;
3554
3555
3556 case charset:
3557 case charset_not:
3558 {
3559 register unsigned char c;
3560 boolean not = (re_opcode_t) *(p - 1) == charset_not;
3561
3562 DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
3563
3564 PREFETCH ();
3565 c = TRANSLATE (*d); /* The character to match. */
3566
3567 /* Cast to `unsigned' instead of `unsigned char' in case the
3568 bit list is a full 32 bytes long. */
3569 if (c < (unsigned) (*p * BYTEWIDTH)
3570 && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
3571 not = !not;
3572
3573 p += 1 + *p;
3574
3575 if (!not) goto fail;
3576
3577 SET_REGS_MATCHED ();
3578 d++;
3579 break;
3580 }
3581
3582
3583 /* The beginning of a group is represented by start_memory.
3584 The arguments are the register number in the next byte, and the
3585 number of groups inner to this one in the next. The text
3586 matched within the group is recorded (in the internal
3587 registers data structure) under the register number. */
3588 case start_memory:
3589 DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
3590
3591 /* Find out if this group can match the empty string. */
3592 p1 = p; /* To send to group_match_null_string_p. */
3593
3594 if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
3595 REG_MATCH_NULL_STRING_P (reg_info[*p])
3596 = group_match_null_string_p (&p1, pend, reg_info);
3597
3598 /* Save the position in the string where we were the last time
3599 we were at this open-group operator in case the group is
3600 operated upon by a repetition operator, e.g., with `(a*)*b'
3601 against `ab'; then we want to ignore where we are now in
3602 the string in case this attempt to match fails. */
3603 old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
3604 ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
3605 : regstart[*p];
3606 DEBUG_PRINT2 (" old_regstart: %d\n",
3607 POINTER_TO_OFFSET (old_regstart[*p]));
3608
3609 regstart[*p] = d;
3610 DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
3611
3612 IS_ACTIVE (reg_info[*p]) = 1;
3613 MATCHED_SOMETHING (reg_info[*p]) = 0;
3614
3615 /* This is the new highest active register. */
3616 highest_active_reg = *p;
3617
3618 /* If nothing was active before, this is the new lowest active
3619 register. */
3620 if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
3621 lowest_active_reg = *p;
3622
3623 /* Move past the register number and inner group count. */
3624 p += 2;
3625 break;
3626
3627
3628 /* The stop_memory opcode represents the end of a group. Its
3629 arguments are the same as start_memory's: the register
3630 number, and the number of inner groups. */
3631 case stop_memory:
3632 DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
3633
3634 /* We need to save the string position the last time we were at
3635 this close-group operator in case the group is operated
3636 upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
3637 against `aba'; then we want to ignore where we are now in
3638 the string in case this attempt to match fails. */
3639 old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
3640 ? REG_UNSET (regend[*p]) ? d : regend[*p]
3641 : regend[*p];
3642 DEBUG_PRINT2 (" old_regend: %d\n",
3643 POINTER_TO_OFFSET (old_regend[*p]));
3644
3645 regend[*p] = d;
3646 DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
3647
3648 /* This register isn't active anymore. */
3649 IS_ACTIVE (reg_info[*p]) = 0;
3650
3651 /* If this was the only register active, nothing is active
3652 anymore. */
3653 if (lowest_active_reg == highest_active_reg)
3654 {
3655 lowest_active_reg = NO_LOWEST_ACTIVE_REG;
3656 highest_active_reg = NO_HIGHEST_ACTIVE_REG;
3657 }
3658 else
3659 { /* We must scan for the new highest active register, since
3660 it isn't necessarily one less than now: consider
3661 (a(b)c(d(e)f)g). When group 3 ends, after the f), the
3662 new highest active register is 1. */
3663 unsigned char r = *p - 1;
3664 while (r > 0 && !IS_ACTIVE (reg_info[r]))
3665 r--;
3666
3667 /* If we end up at register zero, that means that we saved
3668 the registers as the result of an `on_failure_jump', not
3669 a `start_memory', and we jumped to past the innermost
3670 `stop_memory'. For example, in ((.)*) we save
3671 registers 1 and 2 as a result of the *, but when we pop
3672 back to the second ), we are at the stop_memory 1.
3673 Thus, nothing is active. */
3674 if (r == 0)
3675 {
3676 lowest_active_reg = NO_LOWEST_ACTIVE_REG;
3677 highest_active_reg = NO_HIGHEST_ACTIVE_REG;
3678 }
3679 else
3680 highest_active_reg = r;
3681 }
3682
3683 /* If just failed to match something this time around with a
3684 group that's operated on by a repetition operator, try to
3685 force exit from the ``loop'', and restore the register
3686 information for this group that we had before trying this
3687 last match. */
3688 if ((!MATCHED_SOMETHING (reg_info[*p])
3689 || (re_opcode_t) p[-3] == start_memory)
3690 && (p + 2) < pend)
3691 {
3692 boolean is_a_jump_n = false;
3693
3694 p1 = p + 2;
3695 mcnt = 0;
3696 switch ((re_opcode_t) *p1++)
3697 {
3698 case jump_n:
3699 is_a_jump_n = true;
3700 case pop_failure_jump:
3701 case maybe_pop_jump:
3702 case jump:
3703 case dummy_failure_jump:
3704 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
3705 if (is_a_jump_n)
3706 p1 += 2;
3707 break;
3708
3709 default:
3710 /* do nothing */ ;
3711 }
3712 p1 += mcnt;
3713
3714 /* If the next operation is a jump backwards in the pattern
3715 to an on_failure_jump right before the start_memory
3716 corresponding to this stop_memory, exit from the loop
3717 by forcing a failure after pushing on the stack the
3718 on_failure_jump's jump in the pattern, and d. */
3719 if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
3720 && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
3721 {
3722 /* If this group ever matched anything, then restore
3723 what its registers were before trying this last
3724 failed match, e.g., with `(a*)*b' against `ab' for
3725 regstart[1], and, e.g., with `((a*)*(b*)*)*'
3726 against `aba' for regend[3].
3727
3728 Also restore the registers for inner groups for,
3729 e.g., `((a*)(b*))*' against `aba' (register 3 would
3730 otherwise get trashed). */
3731
3732 if (EVER_MATCHED_SOMETHING (reg_info[*p]))
3733 {
3734 unsigned r;
3735
3736 EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
3737
3738 /* Restore this and inner groups' (if any) registers. */
3739 for (r = *p; r < *p + *(p + 1); r++)
3740 {
3741 regstart[r] = old_regstart[r];
3742
3743 /* xx why this test? */
3744 if ((int) old_regend[r] >= (int) regstart[r])
3745 regend[r] = old_regend[r];
3746 }
3747 }
3748 p1++;
3749 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
3750 PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
3751
3752 goto fail;
3753 }
3754 }
3755
3756 /* Move past the register number and the inner group count. */
3757 p += 2;
3758 break;
3759
3760
3761 /* \<digit> has been turned into a `duplicate' command which is
3762 followed by the numeric value of <digit> as the register number. */
3763 case duplicate:
3764 {
3765 register const char *d2, *dend2;
3766 int regno = *p++; /* Get which register to match against. */
3767 DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
3768
3769 /* Can't back reference a group which we've never matched. */
3770 if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
3771 goto fail;
3772
3773 /* Where in input to try to start matching. */
3774 d2 = regstart[regno];
3775
3776 /* Where to stop matching; if both the place to start and
3777 the place to stop matching are in the same string, then
3778 set to the place to stop, otherwise, for now have to use
3779 the end of the first string. */
3780
3781 dend2 = ((FIRST_STRING_P (regstart[regno])
3782 == FIRST_STRING_P (regend[regno]))
3783 ? regend[regno] : end_match_1);
3784 for (;;)
3785 {
3786 /* If necessary, advance to next segment in register
3787 contents. */
3788 while (d2 == dend2)
3789 {
3790 if (dend2 == end_match_2) break;
3791 if (dend2 == regend[regno]) break;
3792
3793 /* End of string1 => advance to string2. */
3794 d2 = string2;
3795 dend2 = regend[regno];
3796 }
3797 /* At end of register contents => success */
3798 if (d2 == dend2) break;
3799
3800 /* If necessary, advance to next segment in data. */
3801 PREFETCH ();
3802
3803 /* How many characters left in this segment to match. */
3804 mcnt = dend - d;
3805
3806 /* Want how many consecutive characters we can match in
3807 one shot, so, if necessary, adjust the count. */
3808 if (mcnt > dend2 - d2)
3809 mcnt = dend2 - d2;
3810
3811 /* Compare that many; failure if mismatch, else move
3812 past them. */
3813 if (translate
3814 ? bcmp_translate (d, d2, mcnt, translate)
3815 : bcmp (d, d2, mcnt))
3816 goto fail;
3817 d += mcnt, d2 += mcnt;
3818 }
3819 }
3820 break;
3821
3822
3823 /* begline matches the empty string at the beginning of the string
3824 (unless `not_bol' is set in `bufp'), and, if
3825 `newline_anchor' is set, after newlines. */
3826 case begline:
3827 DEBUG_PRINT1 ("EXECUTING begline.\n");
3828
3829 if (AT_STRINGS_BEG (d))
3830 {
3831 if (!bufp->not_bol) break;
3832 }
3833 else if (d[-1] == '\n' && bufp->newline_anchor)
3834 {
3835 break;
3836 }
3837 /* In all other cases, we fail. */
3838 goto fail;
3839
3840
3841 /* endline is the dual of begline. */
3842 case endline:
3843 DEBUG_PRINT1 ("EXECUTING endline.\n");
3844
3845 if (AT_STRINGS_END (d))
3846 {
3847 if (!bufp->not_eol) break;
3848 }
3849
3850 /* We have to ``prefetch'' the next character. */
3851 else if ((d == end1 ? *string2 : *d) == '\n'
3852 && bufp->newline_anchor)
3853 {
3854 break;
3855 }
3856 goto fail;
3857
3858
3859 /* Match at the very beginning of the data. */
3860 case begbuf:
3861 DEBUG_PRINT1 ("EXECUTING begbuf.\n");
3862 if (AT_STRINGS_BEG (d))
3863 break;
3864 goto fail;
3865
3866
3867 /* Match at the very end of the data. */
3868 case endbuf:
3869 DEBUG_PRINT1 ("EXECUTING endbuf.\n");
3870 if (AT_STRINGS_END (d))
3871 break;
3872 goto fail;
3873
3874
3875 /* on_failure_keep_string_jump is used to optimize `.*\n'. It
3876 pushes NULL as the value for the string on the stack. Then
3877 `pop_failure_point' will keep the current value for the
3878 string, instead of restoring it. To see why, consider
3879 matching `foo\nbar' against `.*\n'. The .* matches the foo;
3880 then the . fails against the \n. But the next thing we want
3881 to do is match the \n against the \n; if we restored the
3882 string value, we would be back at the foo.
3883
3884 Because this is used only in specific cases, we don't need to
3885 check all the things that `on_failure_jump' does, to make
3886 sure the right things get saved on the stack. Hence we don't
3887 share its code. The only reason to push anything on the
3888 stack at all is that otherwise we would have to change
3889 `anychar's code to do something besides goto fail in this
3890 case; that seems worse than this. */
3891 case on_failure_keep_string_jump:
3892 DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
3893
3894 EXTRACT_NUMBER_AND_INCR (mcnt, p);
3895 DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
3896
3897 PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
3898 break;
3899
3900
3901 /* Uses of on_failure_jump:
3902
3903 Each alternative starts with an on_failure_jump that points
3904 to the beginning of the next alternative. Each alternative
3905 except the last ends with a jump that in effect jumps past
3906 the rest of the alternatives. (They really jump to the
3907 ending jump of the following alternative, because tensioning
3908 these jumps is a hassle.)
3909
3910 Repeats start with an on_failure_jump that points past both
3911 the repetition text and either the following jump or
3912 pop_failure_jump back to this on_failure_jump. */
3913 case on_failure_jump:
3914 on_failure:
3915 DEBUG_PRINT1 ("EXECUTING on_failure_jump");
3916
3917 EXTRACT_NUMBER_AND_INCR (mcnt, p);
3918 DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
3919
3920 /* If this on_failure_jump comes right before a group (i.e.,
3921 the original * applied to a group), save the information
3922 for that group and all inner ones, so that if we fail back
3923 to this point, the group's information will be correct.
3924 For example, in \(a*\)*\1, we need the preceding group,
3925 and in \(\(a*\)b*\)\2, we need the inner group. */
3926
3927 /* We can't use `p' to check ahead because we push
3928 a failure point to `p + mcnt' after we do this. */
3929 p1 = p;
3930
3931 /* We need to skip no_op's before we look for the
3932 start_memory in case this on_failure_jump is happening as
3933 the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
3934 against aba. */
3935 while (p1 < pend && (re_opcode_t) *p1 == no_op)
3936 p1++;
3937
3938 if (p1 < pend && (re_opcode_t) *p1 == start_memory)
3939 {
3940 /* We have a new highest active register now. This will
3941 get reset at the start_memory we are about to get to,
3942 but we will have saved all the registers relevant to
3943 this repetition op, as described above. */
3944 highest_active_reg = *(p1 + 1) + *(p1 + 2);
3945 if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
3946 lowest_active_reg = *(p1 + 1);
3947 }
3948
3949 DEBUG_PRINT1 (":\n");
3950 PUSH_FAILURE_POINT (p + mcnt, d, -2);
3951 break;
3952
3953
3954 /* A smart repeat ends with `maybe_pop_jump'.
3955 We change it to either `pop_failure_jump' or `jump'. */
3956 case maybe_pop_jump:
3957 EXTRACT_NUMBER_AND_INCR (mcnt, p);
3958 DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
3959 {
3960 register unsigned char *p2 = p;
3961
3962 /* Compare the beginning of the repeat with what in the
3963 pattern follows its end. If we can establish that there
3964 is nothing that they would both match, i.e., that we
3965 would have to backtrack because of (as in, e.g., `a*a')
3966 then we can change to pop_failure_jump, because we'll
3967 never have to backtrack.
3968
3969 This is not true in the case of alternatives: in
3970 `(a|ab)*' we do need to backtrack to the `ab' alternative
3971 (e.g., if the string was `ab'). But instead of trying to
3972 detect that here, the alternative has put on a dummy
3973 failure point which is what we will end up popping. */
3974
3975 /* Skip over open/close-group commands. */
3976 while (p2 + 2 < pend
3977 && ((re_opcode_t) *p2 == stop_memory
3978 || (re_opcode_t) *p2 == start_memory))
3979 p2 += 3; /* Skip over args, too. */
3980
3981 /* If we're at the end of the pattern, we can change. */
3982 if (p2 == pend)
3983 {
3984 /* Consider what happens when matching ":\(.*\)"
3985 against ":/". I don't really understand this code
3986 yet. */
3987 p[-3] = (unsigned char) pop_failure_jump;
3988 DEBUG_PRINT1
3989 (" End of pattern: change to `pop_failure_jump'.\n");
3990 }
3991
3992 else if ((re_opcode_t) *p2 == exactn
3993 || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
3994 {
3995 register unsigned char c
3996 = *p2 == (unsigned char) endline ? '\n' : p2[2];
3997 p1 = p + mcnt;
3998
3999 /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
4000 to the `maybe_finalize_jump' of this case. Examine what
4001 follows. */
4002 if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
4003 {
4004 p[-3] = (unsigned char) pop_failure_jump;
4005 DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
4006 c, p1[5]);
4007 }
4008
4009 else if ((re_opcode_t) p1[3] == charset
4010 || (re_opcode_t) p1[3] == charset_not)
4011 {
4012 int not = (re_opcode_t) p1[3] == charset_not;
4013
4014 if (c < (unsigned char) (p1[4] * BYTEWIDTH)
4015 && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
4016 not = !not;
4017
4018 /* `not' is equal to 1 if c would match, which means
4019 that we can't change to pop_failure_jump. */
4020 if (!not)
4021 {
4022 p[-3] = (unsigned char) pop_failure_jump;
4023 DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
4024 }
4025 }
4026 }
4027 }
4028 p -= 2; /* Point at relative address again. */
4029 if ((re_opcode_t) p[-1] != pop_failure_jump)
4030 {
4031 p[-1] = (unsigned char) jump;
4032 DEBUG_PRINT1 (" Match => jump.\n");
4033 goto unconditional_jump;
4034 }
4035 /* Note fall through. */
4036
4037
4038 /* The end of a simple repeat has a pop_failure_jump back to
4039 its matching on_failure_jump, where the latter will push a
4040 failure point. The pop_failure_jump takes off failure
4041 points put on by this pop_failure_jump's matching
4042 on_failure_jump; we got through the pattern to here from the
4043 matching on_failure_jump, so didn't fail. */
4044 case pop_failure_jump:
4045 {
4046 /* We need to pass separate storage for the lowest and
4047 highest registers, even though we don't care about the
4048 actual values. Otherwise, we will restore only one
4049 register from the stack, since lowest will == highest in
4050 `pop_failure_point'. */
4051 unsigned dummy_low_reg, dummy_high_reg;
4052 unsigned char *pdummy;
4053 const char *sdummy;
4054
4055 DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
4056 POP_FAILURE_POINT (sdummy, pdummy,
4057 dummy_low_reg, dummy_high_reg,
4058 reg_dummy, reg_dummy, reg_info_dummy);
4059 }
4060 /* Note fall through. */
4061
4062
4063 /* Unconditionally jump (without popping any failure points). */
4064 case jump:
4065 unconditional_jump:
4066 EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
4067 DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
4068 p += mcnt; /* Do the jump. */
4069 DEBUG_PRINT2 ("(to 0x%x).\n", p);
4070 break;
4071
4072
4073 /* We need this opcode so we can detect where alternatives end
4074 in `group_match_null_string_p' et al. */
4075 case jump_past_alt:
4076 DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
4077 goto unconditional_jump;
4078
4079
4080 /* Normally, the on_failure_jump pushes a failure point, which
4081 then gets popped at pop_failure_jump. We will end up at
4082 pop_failure_jump, also, and with a pattern of, say, `a+', we
4083 are skipping over the on_failure_jump, so we have to push
4084 something meaningless for pop_failure_jump to pop. */
4085 case dummy_failure_jump:
4086 DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
4087 /* It doesn't matter what we push for the string here. What
4088 the code at `fail' tests is the value for the pattern. */
4089 PUSH_FAILURE_POINT (0, 0, -2);
4090 goto unconditional_jump;
4091
4092
4093 /* At the end of an alternative, we need to push a dummy failure
4094 point in case we are followed by a `pop_failure_jump', because
4095 we don't want the failure point for the alternative to be
4096 popped. For example, matching `(a|ab)*' against `aab'
4097 requires that we match the `ab' alternative. */
4098 case push_dummy_failure:
4099 DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
4100 /* See comments just above at `dummy_failure_jump' about the
4101 two zeroes. */
4102 PUSH_FAILURE_POINT (0, 0, -2);
4103 break;
4104
4105 /* Have to succeed matching what follows at least n times.
4106 After that, handle like `on_failure_jump'. */
4107 case succeed_n:
4108 EXTRACT_NUMBER (mcnt, p + 2);
4109 DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
4110
4111 assert (mcnt >= 0);
4112 /* Originally, this is how many times we HAVE to succeed. */
4113 if (mcnt > 0)
4114 {
4115 mcnt--;
4116 p += 2;
4117 STORE_NUMBER_AND_INCR (p, mcnt);
4118 DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt);
4119 }
4120 else if (mcnt == 0)
4121 {
4122 DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2);
4123 p[2] = (unsigned char) no_op;
4124 p[3] = (unsigned char) no_op;
4125 goto on_failure;
4126 }
4127 break;
4128
4129 case jump_n:
4130 EXTRACT_NUMBER (mcnt, p + 2);
4131 DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
4132
4133 /* Originally, this is how many times we CAN jump. */
4134 if (mcnt)
4135 {
4136 mcnt--;
4137 STORE_NUMBER (p + 2, mcnt);
4138 goto unconditional_jump;
4139 }
4140 /* If don't have to jump any more, skip over the rest of command. */
4141 else
4142 p += 4;
4143 break;
4144
4145 case set_number_at:
4146 {
4147 DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
4148
4149 EXTRACT_NUMBER_AND_INCR (mcnt, p);
4150 p1 = p + mcnt;
4151 EXTRACT_NUMBER_AND_INCR (mcnt, p);
4152 DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
4153 STORE_NUMBER (p1, mcnt);
4154 break;
4155 }
4156
4157 case wordbound:
4158 DEBUG_PRINT1 ("EXECUTING wordbound.\n");
4159 if (AT_WORD_BOUNDARY (d))
4160 break;
4161 goto fail;
4162
4163 case notwordbound:
4164 DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
4165 if (AT_WORD_BOUNDARY (d))
4166 goto fail;
4167 break;
4168
4169 case wordbeg:
4170 DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
4171 if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
4172 break;
4173 goto fail;
4174
4175 case wordend:
4176 DEBUG_PRINT1 ("EXECUTING wordend.\n");
4177 if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
4178 && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
4179 break;
4180 goto fail;
4181
4182#ifdef emacs
4183#ifdef emacs19
4184 case before_dot:
4185 DEBUG_PRINT1 ("EXECUTING before_dot.\n");
4186 if (PTR_CHAR_POS ((unsigned char *) d) >= point)
4187 goto fail;
4188 break;
4189
4190 case at_dot:
4191 DEBUG_PRINT1 ("EXECUTING at_dot.\n");
4192 if (PTR_CHAR_POS ((unsigned char *) d) != point)
4193 goto fail;
4194 break;
4195
4196 case after_dot:
4197 DEBUG_PRINT1 ("EXECUTING after_dot.\n");
4198 if (PTR_CHAR_POS ((unsigned char *) d) <= point)
4199 goto fail;
4200 break;
4201#else /* not emacs19 */
4202 case at_dot:
4203 DEBUG_PRINT1 ("EXECUTING at_dot.\n");
4204 if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
4205 goto fail;
4206 break;
4207#endif /* not emacs19 */
4208
4209 case syntaxspec:
4210 DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
4211 mcnt = *p++;
4212 goto matchsyntax;
4213
4214 case wordchar:
4215 DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
4216 mcnt = (int) Sword;
4217 matchsyntax:
4218 PREFETCH ();
4219 if (SYNTAX (*d++) != (enum syntaxcode) mcnt)
4220 goto fail;
4221 SET_REGS_MATCHED ();
4222 break;
4223
4224 case notsyntaxspec:
4225 DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
4226 mcnt = *p++;
4227 goto matchnotsyntax;
4228
4229 case notwordchar:
4230 DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
4231 mcnt = (int) Sword;
4232 matchnotsyntax:
4233 PREFETCH ();
4234 if (SYNTAX (*d++) == (enum syntaxcode) mcnt)
4235 goto fail;
4236 SET_REGS_MATCHED ();
4237 break;
4238
4239#else /* not emacs */
4240 case wordchar:
4241 DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
4242 PREFETCH ();
4243 if (!WORDCHAR_P (d))
4244 goto fail;
4245 SET_REGS_MATCHED ();
4246 d++;
4247 break;
4248
4249 case notwordchar:
4250 DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
4251 PREFETCH ();
4252 if (WORDCHAR_P (d))
4253 goto fail;
4254 SET_REGS_MATCHED ();
4255 d++;
4256 break;
4257#endif /* not emacs */
4258
4259 default:
4260 abort ();
4261 }
4262 continue; /* Successfully executed one pattern command; keep going. */
4263
4264
4265 /* We goto here if a matching operation fails. */
4266 fail:
4267 if (!FAIL_STACK_EMPTY ())
4268 { /* A restart point is known. Restore to that state. */
4269 DEBUG_PRINT1 ("\nFAIL:\n");
4270 POP_FAILURE_POINT (d, p,
4271 lowest_active_reg, highest_active_reg,
4272 regstart, regend, reg_info);
4273
4274 /* If this failure point is a dummy, try the next one. */
4275 if (!p)
4276 goto fail;
4277
4278 /* If we failed to the end of the pattern, don't examine *p. */
4279 assert (p <= pend);
4280 if (p < pend)
4281 {
4282 boolean is_a_jump_n = false;
4283
4284 /* If failed to a backwards jump that's part of a repetition
4285 loop, need to pop this failure point and use the next one. */
4286 switch ((re_opcode_t) *p)
4287 {
4288 case jump_n:
4289 is_a_jump_n = true;
4290 case maybe_pop_jump:
4291 case pop_failure_jump:
4292 case jump:
4293 p1 = p + 1;
4294 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4295 p1 += mcnt;
4296
4297 if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
4298 || (!is_a_jump_n
4299 && (re_opcode_t) *p1 == on_failure_jump))
4300 goto fail;
4301 break;
4302 default:
4303 /* do nothing */ ;
4304 }
4305 }
4306
4307 if (d >= string1 && d <= end1)
4308 dend = end_match_1;
4309 }
4310 else
4311 break; /* Matching at this starting point really fails. */
4312 } /* for (;;) */
4313
4314 if (best_regs_set)
4315 goto restore_best_regs;
4316
4317 FREE_VARIABLES ();
4318
4319 return -1; /* Failure to match. */
4320} /* re_match_2 */
4321
4322/* Subroutine definitions for re_match_2. */
4323
4324
4325/* We are passed P pointing to a register number after a start_memory.
4326
4327 Return true if the pattern up to the corresponding stop_memory can
4328 match the empty string, and false otherwise.
4329
4330 If we find the matching stop_memory, sets P to point to one past its number.
4331 Otherwise, sets P to an undefined byte less than or equal to END.
4332
4333 We don't handle duplicates properly (yet). */
4334
4335static boolean
4336group_match_null_string_p (p, end, reg_info)
4337 unsigned char **p, *end;
4338 register_info_type *reg_info;
4339{
4340 int mcnt;
4341 /* Point to after the args to the start_memory. */
4342 unsigned char *p1 = *p + 2;
4343
4344 while (p1 < end)
4345 {
4346 /* Skip over opcodes that can match nothing, and return true or
4347 false, as appropriate, when we get to one that can't, or to the
4348 matching stop_memory. */
4349
4350 switch ((re_opcode_t) *p1)
4351 {
4352 /* Could be either a loop or a series of alternatives. */
4353 case on_failure_jump:
4354 p1++;
4355 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4356
4357 /* If the next operation is not a jump backwards in the
4358 pattern. */
4359
4360 if (mcnt >= 0)
4361 {
4362 /* Go through the on_failure_jumps of the alternatives,
4363 seeing if any of the alternatives cannot match nothing.
4364 The last alternative starts with only a jump,
4365 whereas the rest start with on_failure_jump and end
4366 with a jump, e.g., here is the pattern for `a|b|c':
4367
4368 /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
4369 /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
4370 /exactn/1/c
4371
4372 So, we have to first go through the first (n-1)
4373 alternatives and then deal with the last one separately. */
4374
4375
4376 /* Deal with the first (n-1) alternatives, which start
4377 with an on_failure_jump (see above) that jumps to right
4378 past a jump_past_alt. */
4379
4380 while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
4381 {
4382 /* `mcnt' holds how many bytes long the alternative
4383 is, including the ending `jump_past_alt' and
4384 its number. */
4385
4386 if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
4387 reg_info))
4388 return false;
4389
4390 /* Move to right after this alternative, including the
4391 jump_past_alt. */
4392 p1 += mcnt;
4393
4394 /* Break if it's the beginning of an n-th alternative
4395 that doesn't begin with an on_failure_jump. */
4396 if ((re_opcode_t) *p1 != on_failure_jump)
4397 break;
4398
4399 /* Still have to check that it's not an n-th
4400 alternative that starts with an on_failure_jump. */
4401 p1++;
4402 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4403 if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
4404 {
4405 /* Get to the beginning of the n-th alternative. */
4406 p1 -= 3;
4407 break;
4408 }
4409 }
4410
4411 /* Deal with the last alternative: go back and get number
4412 of the `jump_past_alt' just before it. `mcnt' contains
4413 the length of the alternative. */
4414 EXTRACT_NUMBER (mcnt, p1 - 2);
4415
4416 if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
4417 return false;
4418
4419 p1 += mcnt; /* Get past the n-th alternative. */
4420 } /* if mcnt > 0 */
4421 break;
4422
4423
4424 case stop_memory:
4425 assert (p1[1] == **p);
4426 *p = p1 + 2;
4427 return true;
4428
4429
4430 default:
4431 if (!common_op_match_null_string_p (&p1, end, reg_info))
4432 return false;
4433 }
4434 } /* while p1 < end */
4435
4436 return false;
4437} /* group_match_null_string_p */
4438
4439
4440/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
4441 It expects P to be the first byte of a single alternative and END one
4442 byte past the last. The alternative can contain groups. */
4443
4444static boolean
4445alt_match_null_string_p (p, end, reg_info)
4446 unsigned char *p, *end;
4447 register_info_type *reg_info;
4448{
4449 int mcnt;
4450 unsigned char *p1 = p;
4451
4452 while (p1 < end)
4453 {
4454 /* Skip over opcodes that can match nothing, and break when we get
4455 to one that can't. */
4456
4457 switch ((re_opcode_t) *p1)
4458 {
4459 /* It's a loop. */
4460 case on_failure_jump:
4461 p1++;
4462 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4463 p1 += mcnt;
4464 break;
4465
4466 default:
4467 if (!common_op_match_null_string_p (&p1, end, reg_info))
4468 return false;
4469 }
4470 } /* while p1 < end */
4471
4472 return true;
4473} /* alt_match_null_string_p */
4474
4475
4476/* Deals with the ops common to group_match_null_string_p and
4477 alt_match_null_string_p.
4478
4479 Sets P to one after the op and its arguments, if any. */
4480
4481static boolean
4482common_op_match_null_string_p (p, end, reg_info)
4483 unsigned char **p, *end;
4484 register_info_type *reg_info;
4485{
4486 int mcnt;
4487 boolean ret;
4488 int reg_no;
4489 unsigned char *p1 = *p;
4490
4491 switch ((re_opcode_t) *p1++)
4492 {
4493 case no_op:
4494 case begline:
4495 case endline:
4496 case begbuf:
4497 case endbuf:
4498 case wordbeg:
4499 case wordend:
4500 case wordbound:
4501 case notwordbound:
4502#ifdef emacs
4503 case before_dot:
4504 case at_dot:
4505 case after_dot:
4506#endif
4507 break;
4508
4509 case start_memory:
4510 reg_no = *p1;
4511 assert (reg_no > 0 && reg_no <= MAX_REGNUM);
4512 ret = group_match_null_string_p (&p1, end, reg_info);
4513
4514 /* Have to set this here in case we're checking a group which
4515 contains a group and a back reference to it. */
4516
4517 if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
4518 REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
4519
4520 if (!ret)
4521 return false;
4522 break;
4523
4524 /* If this is an optimized succeed_n for zero times, make the jump. */
4525 case jump:
4526 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4527 if (mcnt >= 0)
4528 p1 += mcnt;
4529 else
4530 return false;
4531 break;
4532
4533 case succeed_n:
4534 /* Get to the number of times to succeed. */
4535 p1 += 2;
4536 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4537
4538 if (mcnt == 0)
4539 {
4540 p1 -= 4;
4541 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
4542 p1 += mcnt;
4543 }
4544 else
4545 return false;
4546 break;
4547
4548 case duplicate:
4549 if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
4550 return false;
4551 break;
4552
4553 case set_number_at:
4554 p1 += 4;
4555
4556 default:
4557 /* All other opcodes mean we cannot match the empty string. */
4558 return false;
4559 }
4560
4561 *p = p1;
4562 return true;
4563} /* common_op_match_null_string_p */
4564
4565
4566/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
4567 bytes; nonzero otherwise. */
4568
4569static int
4570bcmp_translate(
4571 unsigned char *s1,
4572 unsigned char *s2,
4573 int len,
4574 char *translate
4575)
4576{
4577 register unsigned char *p1 = s1, *p2 = s2;
4578 while (len)
4579 {
4580 if (translate[*p1++] != translate[*p2++]) return 1;
4581 len--;
4582 }
4583 return 0;
4584}
4585
4586/* Entry points for GNU code. */
4587
4588/* re_compile_pattern is the GNU regular expression compiler: it
4589 compiles PATTERN (of length SIZE) and puts the result in BUFP.
4590 Returns 0 if the pattern was valid, otherwise an error string.
4591
4592 Assumes the `allocated' (and perhaps `buffer') and `translate' fields
4593 are set in BUFP on entry.
4594
4595 We call regex_compile to do the actual compilation. */
4596
4597const char *
4598re_compile_pattern (pattern, length, bufp)
4599 const char *pattern;
4600 int length;
4601 struct re_pattern_buffer *bufp;
4602{
4603 reg_errcode_t ret;
4604
4605 /* GNU code is written to assume at least RE_NREGS registers will be set
4606 (and at least one extra will be -1). */
4607 bufp->regs_allocated = REGS_UNALLOCATED;
4608
4609 /* And GNU code determines whether or not to get register information
4610 by passing null for the REGS argument to re_match, etc., not by
4611 setting no_sub. */
4612 bufp->no_sub = 0;
4613
4614 /* Match anchors at newline. */
4615 bufp->newline_anchor = 1;
4616
4617 ret = regex_compile (pattern, length, re_syntax_options, bufp);
4618
4619 return re_error_msg[(int) ret];
4620}
4621
4622/* Entry points compatible with 4.2 BSD regex library. We don't define
4623 them if this is an Emacs or POSIX compilation. */
4624
4625#if !defined (emacs) && !defined (_POSIX_SOURCE)
4626
4627/* BSD has one and only one pattern buffer. */
4628static struct re_pattern_buffer re_comp_buf;
4629
4630char *
4631re_comp (s)
4632 const char *s;
4633{
4634 reg_errcode_t ret;
4635
4636 if (!s)
4637 {
4638 if (!re_comp_buf.buffer)
4639 return "No previous regular expression";
4640 return 0;
4641 }
4642
4643 if (!re_comp_buf.buffer)
4644 {
4645 re_comp_buf.buffer = (unsigned char *) malloc (200);
4646 if (re_comp_buf.buffer == NULL)
4647 return "Memory exhausted";
4648 re_comp_buf.allocated = 200;
4649
4650 re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
4651 if (re_comp_buf.fastmap == NULL)
4652 return "Memory exhausted";
4653 }
4654
4655 /* Since `re_exec' always passes NULL for the `regs' argument, we
4656 don't need to initialize the pattern buffer fields which affect it. */
4657
4658 /* Match anchors at newlines. */
4659 re_comp_buf.newline_anchor = 1;
4660
4661 ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
4662
4663 /* Yes, we're discarding `const' here. */
4664 return (char *) re_error_msg[(int) ret];
4665}
4666
4667
4668int
4669re_exec (s)
4670 const char *s;
4671{
4672 const int len = strlen (s);
4673 return
4674 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
4675}
4676#endif /* not emacs and not _POSIX_SOURCE */
4677
4678/* POSIX.2 functions. Don't define these for Emacs. */
4679
4680#ifndef emacs
4681
4682/* regcomp takes a regular expression as a string and compiles it.
4683
4684 PREG is a regex_t *. We do not expect any fields to be initialized,
4685 since POSIX says we shouldn't. Thus, we set
4686
4687 `buffer' to the compiled pattern;
4688 `used' to the length of the compiled pattern;
4689 `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
4690 REG_EXTENDED bit in CFLAGS is set; otherwise, to
4691 RE_SYNTAX_POSIX_BASIC;
4692 `newline_anchor' to REG_NEWLINE being set in CFLAGS;
4693 `fastmap' and `fastmap_accurate' to zero;
4694 `re_nsub' to the number of subexpressions in PATTERN.
4695
4696 PATTERN is the address of the pattern string.
4697
4698 CFLAGS is a series of bits which affect compilation.
4699
4700 If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
4701 use POSIX basic syntax.
4702
4703 If REG_NEWLINE is set, then . and [^...] don't match newline.
4704 Also, regexec will try a match beginning after every newline.
4705
4706 If REG_ICASE is set, then we considers upper- and lowercase
4707 versions of letters to be equivalent when matching.
4708
4709 If REG_NOSUB is set, then when PREG is passed to regexec, that
4710 routine will report only success or failure, and nothing about the
4711 registers.
4712
4713 It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
4714 the return codes and their meanings.) */
4715
4716int
4717regcomp (preg, pattern, cflags)
4718 regex_t *preg;
4719 const char *pattern;
4720 int cflags;
4721{
4722 reg_errcode_t ret;
4723 unsigned syntax
4724 = (cflags & REG_EXTENDED) ?
4725 RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
4726
4727 /* regex_compile will allocate the space for the compiled pattern. */
4728 preg->buffer = 0;
4729 preg->allocated = 0;
4730
4731 /* Don't bother to use a fastmap when searching. This simplifies the
4732 REG_NEWLINE case: if we used a fastmap, we'd have to put all the
4733 characters after newlines into the fastmap. This way, we just try
4734 every character. */
4735 preg->fastmap = 0;
4736
4737 if (cflags & REG_ICASE)
4738 {
4739 unsigned i;
4740
4741 preg->translate = (char *) malloc (CHAR_SET_SIZE);
4742 if (preg->translate == NULL)
4743 return (int) REG_ESPACE;
4744
4745 /* Map uppercase characters to corresponding lowercase ones. */
4746 for (i = 0; i < CHAR_SET_SIZE; i++)
4747 preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
4748 }
4749 else
4750 preg->translate = NULL;
4751
4752 /* If REG_NEWLINE is set, newlines are treated differently. */
4753 if (cflags & REG_NEWLINE)
4754 { /* REG_NEWLINE implies neither . nor [^...] match newline. */
4755 syntax &= ~RE_DOT_NEWLINE;
4756 syntax |= RE_HAT_LISTS_NOT_NEWLINE;
4757 /* It also changes the matching behavior. */
4758 preg->newline_anchor = 1;
4759 }
4760 else
4761 preg->newline_anchor = 0;
4762
4763 preg->no_sub = !!(cflags & REG_NOSUB);
4764
4765 /* POSIX says a null character in the pattern terminates it, so we
4766 can use strlen here in compiling the pattern. */
4767 ret = regex_compile (pattern, strlen (pattern), syntax, preg);
4768
4769 /* POSIX doesn't distinguish between an unmatched open-group and an
4770 unmatched close-group: both are REG_EPAREN. */
4771 if (ret == REG_ERPAREN) ret = REG_EPAREN;
4772
4773 return (int) ret;
4774}
4775
4776
4777/* regexec searches for a given pattern, specified by PREG, in the
4778 string STRING.
4779
4780 If NMATCH is zero or REG_NOSUB was set in the cflags argument to
4781 `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
4782 least NMATCH elements, and we set them to the offsets of the
4783 corresponding matched substrings.
4784
4785 EFLAGS specifies `execution flags' which affect matching: if
4786 REG_NOTBOL is set, then ^ does not match at the beginning of the
4787 string; if REG_NOTEOL is set, then $ does not match at the end.
4788
4789 We return 0 if we find a match and REG_NOMATCH if not. */
4790
4791int
4792regexec (preg, string, nmatch, pmatch, eflags)
4793 const regex_t *preg;
4794 const char *string;
4795 size_t nmatch;
4796 regmatch_t pmatch[];
4797 int eflags;
4798{
4799 int ret;
4800 struct re_registers regs;
4801 regex_t private_preg;
4802 int len = strlen (string);
4803 boolean want_reg_info = !preg->no_sub && nmatch > 0;
4804
4805 private_preg = *preg;
4806
4807 private_preg.not_bol = !!(eflags & REG_NOTBOL);
4808 private_preg.not_eol = !!(eflags & REG_NOTEOL);
4809
4810 /* The user has told us exactly how many registers to return
4811 information about, via `nmatch'. We have to pass that on to the
4812 matching routines. */
4813 private_preg.regs_allocated = REGS_FIXED;
4814
4815 if (want_reg_info)
4816 {
4817 regs.num_regs = nmatch;
4818 regs.start = TALLOC (nmatch, regoff_t);
4819 regs.end = TALLOC (nmatch, regoff_t);
4820 if (regs.start == NULL || regs.end == NULL)
4821 return (int) REG_NOMATCH;
4822 }
4823
4824 /* Perform the searching operation. */
4825 ret = re_search (&private_preg, string, len,
4826 /* start: */ 0, /* range: */ len,
4827 want_reg_info ? &regs : (struct re_registers *) 0);
4828
4829 /* Copy the register information to the POSIX structure. */
4830 if (want_reg_info)
4831 {
4832 if (ret >= 0)
4833 {
4834 unsigned r;
4835
4836 for (r = 0; r < nmatch; r++)
4837 {
4838 pmatch[r].rm_so = regs.start[r];
4839 pmatch[r].rm_eo = regs.end[r];
4840 }
4841 }
4842
4843 /* If we needed the temporary register info, free the space now. */
4844 free (regs.start);
4845 free (regs.end);
4846 }
4847
4848 /* We want zero return to mean success, unlike `re_search'. */
4849 return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
4850}
4851
4852
4853/* Returns a message corresponding to an error code, ERRCODE, returned
4854 from either regcomp or regexec. We don't use PREG here. */
4855
4856size_t
4857regerror (errcode, preg, errbuf, errbuf_size)
4858 int errcode;
4859 const regex_t *preg;
4860 char *errbuf;
4861 size_t errbuf_size;
4862{
4863 const char *msg;
4864 size_t msg_size;
4865
4866 if (errcode < 0
4867 || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0])))
4868 /* Only error codes returned by the rest of the code should be passed
4869 to this routine. If we are given anything else, or if other regex
4870 code generates an invalid error code, then the program has a bug.
4871 Dump core so we can fix it. */
4872 abort ();
4873
4874 msg = re_error_msg[errcode];
4875
4876 /* POSIX doesn't require that we do anything in this case, but why
4877 not be nice. */
4878 if (! msg)
4879 msg = "Success";
4880
4881 msg_size = strlen (msg) + 1; /* Includes the null. */
4882
4883 if (errbuf_size != 0)
4884 {
4885 if (msg_size > errbuf_size)
4886 {
4887 strncpy (errbuf, msg, errbuf_size - 1);
4888 errbuf[errbuf_size - 1] = 0;
4889 }
4890 else
4891 strcpy (errbuf, msg);
4892 }
4893
4894 return msg_size;
4895}
4896
4897
4898/* Free dynamically allocated space used by PREG. */
4899
4900void
4901regfree (preg)
4902 regex_t *preg;
4903{
4904 if (preg->buffer != NULL)
4905 free (preg->buffer);
4906 preg->buffer = NULL;
4907
4908 preg->allocated = 0;
4909 preg->used = 0;
4910
4911 if (preg->fastmap != NULL)
4912 free (preg->fastmap);
4913 preg->fastmap = NULL;
4914 preg->fastmap_accurate = 0;
4915
4916 if (preg->translate != NULL)
4917 free (preg->translate);
4918 preg->translate = NULL;
4919}
4920
4921#endif /* not emacs */
4922
4923/*
4924Local variables:
4925make-backup-files: t
4926version-control: t
4927trim-versions-without-asking: nil
4928End:
4929*/
diff --git a/win32/regex.h b/win32/regex.h
new file mode 100644
index 000000000..6eb64f140
--- /dev/null
+++ b/win32/regex.h
@@ -0,0 +1,490 @@
1/* Definitions for data structures and routines for the regular
2 expression library, version 0.12.
3
4 Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#ifndef __REGEXP_LIBRARY_H__
21#define __REGEXP_LIBRARY_H__
22
23/* POSIX says that <sys/types.h> must be included (by the caller) before
24 <regex.h>. */
25
26#ifdef VMS
27/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
28 should be there. */
29#include <stddef.h>
30#endif
31
32
33/* The following bits are used to determine the regexp syntax we
34 recognize. The set/not-set meanings are chosen so that Emacs syntax
35 remains the value 0. The bits are given in alphabetical order, and
36 the definitions shifted by one from the previous bit; thus, when we
37 add or remove a bit, only one other definition need change. */
38typedef unsigned reg_syntax_t;
39
40/* If this bit is not set, then \ inside a bracket expression is literal.
41 If set, then such a \ quotes the following character. */
42#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
43
44/* If this bit is not set, then + and ? are operators, and \+ and \? are
45 literals.
46 If set, then \+ and \? are operators and + and ? are literals. */
47#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
48
49/* If this bit is set, then character classes are supported. They are:
50 [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
51 [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
52 If not set, then character classes are not supported. */
53#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
54
55/* If this bit is set, then ^ and $ are always anchors (outside bracket
56 expressions, of course).
57 If this bit is not set, then it depends:
58 ^ is an anchor if it is at the beginning of a regular
59 expression or after an open-group or an alternation operator;
60 $ is an anchor if it is at the end of a regular expression, or
61 before a close-group or an alternation operator.
62
63 This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
64 POSIX draft 11.2 says that * etc. in leading positions is undefined.
65 We already implemented a previous draft which made those constructs
66 invalid, though, so we haven't changed the code back. */
67#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
68
69/* If this bit is set, then special characters are always special
70 regardless of where they are in the pattern.
71 If this bit is not set, then special characters are special only in
72 some contexts; otherwise they are ordinary. Specifically,
73 * + ? and intervals are only special when not after the beginning,
74 open-group, or alternation operator. */
75#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
76
77/* If this bit is set, then *, +, ?, and { cannot be first in an re or
78 immediately after an alternation or begin-group operator. */
79#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
80
81/* If this bit is set, then . matches newline.
82 If not set, then it doesn't. */
83#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
84
85/* If this bit is set, then . doesn't match NUL.
86 If not set, then it does. */
87#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
88
89/* If this bit is set, nonmatching lists [^...] do not match newline.
90 If not set, they do. */
91#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
92
93/* If this bit is set, either \{...\} or {...} defines an
94 interval, depending on RE_NO_BK_BRACES.
95 If not set, \{, \}, {, and } are literals. */
96#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
97
98/* If this bit is set, +, ? and | aren't recognized as operators.
99 If not set, they are. */
100#define RE_LIMITED_OPS (RE_INTERVALS << 1)
101
102/* If this bit is set, newline is an alternation operator.
103 If not set, newline is literal. */
104#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
105
106/* If this bit is set, then `{...}' defines an interval, and \{ and \}
107 are literals.
108 If not set, then `\{...\}' defines an interval. */
109#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
110
111/* If this bit is set, (...) defines a group, and \( and \) are literals.
112 If not set, \(...\) defines a group, and ( and ) are literals. */
113#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
114
115/* If this bit is set, then \<digit> matches <digit>.
116 If not set, then \<digit> is a back-reference. */
117#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
118
119/* If this bit is set, then | is an alternation operator, and \| is literal.
120 If not set, then \| is an alternation operator, and | is literal. */
121#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
122
123/* If this bit is set, then an ending range point collating higher
124 than the starting range point, as in [z-a], is invalid.
125 If not set, then when ending range point collates higher than the
126 starting range point, the range is ignored. */
127#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
128
129/* If this bit is set, then an unmatched ) is ordinary.
130 If not set, then an unmatched ) is invalid. */
131#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
132
133/* This global variable defines the particular regexp syntax to use (for
134 some interfaces). When a regexp is compiled, the syntax used is
135 stored in the pattern buffer, so changing this does not affect
136 already-compiled regexps. */
137extern reg_syntax_t re_syntax_options;
138
139/* Define combinations of the above bits for the standard possibilities.
140 (The [[[ comments delimit what gets put into the Texinfo file, so
141 don't delete them!) */
142/* [[[begin syntaxes]]] */
143#define RE_SYNTAX_EMACS 0
144
145#define RE_SYNTAX_AWK \
146 (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
147 | RE_NO_BK_PARENS | RE_NO_BK_REFS \
148 | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
149 | RE_UNMATCHED_RIGHT_PAREN_ORD)
150
151#define RE_SYNTAX_POSIX_AWK \
152 (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
153
154#define RE_SYNTAX_GREP \
155 (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
156 | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
157 | RE_NEWLINE_ALT)
158
159#define RE_SYNTAX_EGREP \
160 (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
161 | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
162 | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
163 | RE_NO_BK_VBAR)
164
165#define RE_SYNTAX_POSIX_EGREP \
166 (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
167
168/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
169#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
170
171#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
172
173/* Syntax bits common to both basic and extended POSIX regex syntax. */
174#define _RE_SYNTAX_POSIX_COMMON \
175 (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
176 | RE_INTERVALS | RE_NO_EMPTY_RANGES)
177
178#define RE_SYNTAX_POSIX_BASIC \
179 (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
180
181/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
182 RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
183 isn't minimal, since other operators, such as \`, aren't disabled. */
184#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
185 (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
186
187#define RE_SYNTAX_POSIX_EXTENDED \
188 (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
189 | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
190 | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
191 | RE_UNMATCHED_RIGHT_PAREN_ORD)
192
193/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
194 replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
195#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
196 (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
197 | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
198 | RE_NO_BK_PARENS | RE_NO_BK_REFS \
199 | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
200/* [[[end syntaxes]]] */
201
202/* Maximum number of duplicates an interval can allow. Some systems
203 (erroneously) define this in other header files, but we want our
204 value, so remove any previous define. */
205#ifdef RE_DUP_MAX
206#undef RE_DUP_MAX
207#endif
208#define RE_DUP_MAX ((1 << 15) - 1)
209
210
211/* POSIX `cflags' bits (i.e., information for `regcomp'). */
212
213/* If this bit is set, then use extended regular expression syntax.
214 If not set, then use basic regular expression syntax. */
215#define REG_EXTENDED 1
216
217/* If this bit is set, then ignore case when matching.
218 If not set, then case is significant. */
219#define REG_ICASE (REG_EXTENDED << 1)
220
221/* If this bit is set, then anchors do not match at newline
222 characters in the string.
223 If not set, then anchors do match at newlines. */
224#define REG_NEWLINE (REG_ICASE << 1)
225
226/* If this bit is set, then report only success or fail in regexec.
227 If not set, then returns differ between not matching and errors. */
228#define REG_NOSUB (REG_NEWLINE << 1)
229
230
231/* POSIX `eflags' bits (i.e., information for regexec). */
232
233/* If this bit is set, then the beginning-of-line operator doesn't match
234 the beginning of the string (presumably because it's not the
235 beginning of a line).
236 If not set, then the beginning-of-line operator does match the
237 beginning of the string. */
238#define REG_NOTBOL 1
239
240/* Like REG_NOTBOL, except for the end-of-line. */
241#define REG_NOTEOL (1 << 1)
242
243
244/* If any error codes are removed, changed, or added, update the
245 `re_error_msg' table in regex.c. */
246typedef enum
247{
248 REG_NOERROR = 0, /* Success. */
249 REG_NOMATCH, /* Didn't find a match (for regexec). */
250
251 /* POSIX regcomp return error codes. (In the order listed in the
252 standard.) */
253 REG_BADPAT, /* Invalid pattern. */
254 REG_ECOLLATE, /* Not implemented. */
255 REG_ECTYPE, /* Invalid character class name. */
256 REG_EESCAPE, /* Trailing backslash. */
257 REG_ESUBREG, /* Invalid back reference. */
258 REG_EBRACK, /* Unmatched left bracket. */
259 REG_EPAREN, /* Parenthesis imbalance. */
260 REG_EBRACE, /* Unmatched \{. */
261 REG_BADBR, /* Invalid contents of \{\}. */
262 REG_ERANGE, /* Invalid range end. */
263 REG_ESPACE, /* Ran out of memory. */
264 REG_BADRPT, /* No preceding re for repetition op. */
265
266 /* Error codes we've added. */
267 REG_EEND, /* Premature end. */
268 REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
269 REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
270} reg_errcode_t;
271
272/* This data structure represents a compiled pattern. Before calling
273 the pattern compiler, the fields `buffer', `allocated', `fastmap',
274 `translate', and `no_sub' can be set. After the pattern has been
275 compiled, the `re_nsub' field is available. All other fields are
276 private to the regex routines. */
277
278struct re_pattern_buffer
279{
280/* [[[begin pattern_buffer]]] */
281 /* Space that holds the compiled pattern. It is declared as
282 `unsigned char *' because its elements are
283 sometimes used as array indexes. */
284 unsigned char *buffer;
285
286 /* Number of bytes to which `buffer' points. */
287 unsigned long allocated;
288
289 /* Number of bytes actually used in `buffer'. */
290 unsigned long used;
291
292 /* Syntax setting with which the pattern was compiled. */
293 reg_syntax_t syntax;
294
295 /* Pointer to a fastmap, if any, otherwise zero. re_search uses
296 the fastmap, if there is one, to skip over impossible
297 starting points for matches. */
298 char *fastmap;
299
300 /* Either a translate table to apply to all characters before
301 comparing them, or zero for no translation. The translation
302 is applied to a pattern when it is compiled and to a string
303 when it is matched. */
304 char *translate;
305
306 /* Number of subexpressions found by the compiler. */
307 size_t re_nsub;
308
309 /* Zero if this pattern cannot match the empty string, one else.
310 Well, in truth it's used only in `re_search_2', to see
311 whether or not we should use the fastmap, so we don't set
312 this absolutely perfectly; see `re_compile_fastmap' (the
313 `duplicate' case). */
314 unsigned can_be_null : 1;
315
316 /* If REGS_UNALLOCATED, allocate space in the `regs' structure
317 for `max (RE_NREGS, re_nsub + 1)' groups.
318 If REGS_REALLOCATE, reallocate space if necessary.
319 If REGS_FIXED, use what's there. */
320#define REGS_UNALLOCATED 0
321#define REGS_REALLOCATE 1
322#define REGS_FIXED 2
323 unsigned regs_allocated : 2;
324
325 /* Set to zero when `regex_compile' compiles a pattern; set to one
326 by `re_compile_fastmap' if it updates the fastmap. */
327 unsigned fastmap_accurate : 1;
328
329 /* If set, `re_match_2' does not return information about
330 subexpressions. */
331 unsigned no_sub : 1;
332
333 /* If set, a beginning-of-line anchor doesn't match at the
334 beginning of the string. */
335 unsigned not_bol : 1;
336
337 /* Similarly for an end-of-line anchor. */
338 unsigned not_eol : 1;
339
340 /* If true, an anchor at a newline matches. */
341 unsigned newline_anchor : 1;
342
343/* [[[end pattern_buffer]]] */
344};
345
346typedef struct re_pattern_buffer regex_t;
347
348
349/* search.c (search_buffer) in Emacs needs this one opcode value. It is
350 defined both in `regex.c' and here. */
351#define RE_EXACTN_VALUE 1
352
353/* Type for byte offsets within the string. POSIX mandates this. */
354typedef int regoff_t;
355
356
357/* This is the structure we store register match data in. See
358 regex.texinfo for a full description of what registers match. */
359struct re_registers
360{
361 unsigned num_regs;
362 regoff_t *start;
363 regoff_t *end;
364};
365
366
367/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
368 `re_match_2' returns information about at least this many registers
369 the first time a `regs' structure is passed. */
370#ifndef RE_NREGS
371#define RE_NREGS 30
372#endif
373
374
375/* POSIX specification for registers. Aside from the different names than
376 `re_registers', POSIX uses an array of structures, instead of a
377 structure of arrays. */
378typedef struct
379{
380 regoff_t rm_so; /* Byte offset from string's start to substring's start. */
381 regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
382} regmatch_t;
383
384/* Declarations for routines. */
385
386/* To avoid duplicating every routine declaration -- once with a
387 prototype (if we are ANSI), and once without (if we aren't) -- we
388 use the following macro to declare argument types. This
389 unfortunately clutters up the declarations a bit, but I think it's
390 worth it. */
391
392#if __STDC__
393
394#define _RE_ARGS(args) args
395
396#else /* not __STDC__ */
397
398#define _RE_ARGS(args) ()
399
400#endif /* not __STDC__ */
401
402/* Sets the current default syntax to SYNTAX, and return the old syntax.
403 You can also simply assign to the `re_syntax_options' variable. */
404extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
405
406/* Compile the regular expression PATTERN, with length LENGTH
407 and syntax given by the global `re_syntax_options', into the buffer
408 BUFFER. Return NULL if successful, and an error string if not. */
409extern const char *re_compile_pattern
410 _RE_ARGS ((const char *pattern, int length,
411 struct re_pattern_buffer *buffer));
412
413
414/* Compile a fastmap for the compiled pattern in BUFFER; used to
415 accelerate searches. Return 0 if successful and -2 if was an
416 internal error. */
417extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
418
419
420/* Search in the string STRING (with length LENGTH) for the pattern
421 compiled into BUFFER. Start searching at position START, for RANGE
422 characters. Return the starting position of the match, -1 for no
423 match, or -2 for an internal error. Also return register
424 information in REGS (if REGS and BUFFER->no_sub are nonzero). */
425extern int re_search
426 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
427 int length, int start, int range, struct re_registers *regs));
428
429
430/* Like `re_search', but search in the concatenation of STRING1 and
431 STRING2. Also, stop searching at index START + STOP. */
432extern int re_search_2
433 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
434 int length1, const char *string2, int length2,
435 int start, int range, struct re_registers *regs, int stop));
436
437
438/* Like `re_search', but return how many characters in STRING the regexp
439 in BUFFER matched, starting at position START. */
440extern int re_match
441 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
442 int length, int start, struct re_registers *regs));
443
444
445/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
446extern int re_match_2
447 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
448 int length1, const char *string2, int length2,
449 int start, struct re_registers *regs, int stop));
450
451
452/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
453 ENDS. Subsequent matches using BUFFER and REGS will use this memory
454 for recording register information. STARTS and ENDS must be
455 allocated with malloc, and must each be at least `NUM_REGS * sizeof
456 (regoff_t)' bytes long.
457
458 If NUM_REGS == 0, then subsequent matches should allocate their own
459 register data.
460
461 Unless this function is called, the first search or match using
462 PATTERN_BUFFER will allocate its own register data, without
463 freeing the old data. */
464extern void re_set_registers
465 _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
466 unsigned num_regs, regoff_t *starts, regoff_t *ends));
467
468/* 4.2 bsd compatibility. */
469extern char *re_comp _RE_ARGS ((const char *));
470extern int re_exec _RE_ARGS ((const char *));
471
472/* POSIX compatibility. */
473extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
474extern int regexec
475 _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
476 regmatch_t pmatch[], int eflags));
477extern size_t regerror
478 _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
479 size_t errbuf_size));
480extern void regfree _RE_ARGS ((regex_t *preg));
481
482#endif /* not __REGEXP_LIBRARY_H__ */
483
484/*
485Local variables:
486make-backup-files: t
487version-control: t
488trim-versions-without-asking: nil
489End:
490*/
diff --git a/win32/sched.h b/win32/sched.h
new file mode 100644
index 000000000..128bfe698
--- /dev/null
+++ b/win32/sched.h
@@ -0,0 +1 @@
static inline void sched_yield(void) {}
diff --git a/win32/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..e95b9c846
--- /dev/null
+++ b/win32/winansi.c
@@ -0,0 +1,734 @@
1/*
2 * Copyright 2008 Peter Harris <git@peter.is-a-geek.org>
3 */
4
5#include "libbb.h"
6#include <windows.h>
7#undef PACKED
8
9/*
10 Functions to be wrapped:
11*/
12#undef vprintf
13#undef printf
14#undef fprintf
15#undef fputs
16#undef putchar
17#undef fwrite
18#undef puts
19#undef write
20#undef read
21#undef getc
22
23/*
24 ANSI codes used by git: m, K
25
26 This file is git-specific. Therefore, this file does not attempt
27 to implement any codes that are not used by git.
28*/
29
30static HANDLE console;
31static HANDLE console_in;
32static WORD plain_attr;
33static WORD attr;
34static int negative;
35
36static void init(void)
37{
38 CONSOLE_SCREEN_BUFFER_INFO sbi;
39
40 static int initialized = 0;
41 if (initialized)
42 return;
43
44 console_in = GetStdHandle(STD_INPUT_HANDLE);
45 if (console_in == INVALID_HANDLE_VALUE)
46 console_in = NULL;
47
48 console = GetStdHandle(STD_OUTPUT_HANDLE);
49 if (console == INVALID_HANDLE_VALUE)
50 console = NULL;
51
52 if (!console)
53 return;
54
55 GetConsoleScreenBufferInfo(console, &sbi);
56 attr = plain_attr = sbi.wAttributes;
57 negative = 0;
58
59 initialized = 1;
60}
61
62static int skip_ansi_emulation(void)
63{
64 static char *var = NULL;
65 static int got_var = FALSE;
66
67 if (!got_var) {
68 var = getenv("BB_SKIP_ANSI_EMULATION");
69 got_var = TRUE;
70 }
71
72 return var != NULL;
73}
74
75
76#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
77#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
78
79static void set_console_attr(void)
80{
81 WORD attributes = attr;
82 if (negative) {
83 attributes &= ~FOREGROUND_ALL;
84 attributes &= ~BACKGROUND_ALL;
85
86 /* This could probably use a bitmask
87 instead of a series of ifs */
88 if (attr & FOREGROUND_RED)
89 attributes |= BACKGROUND_RED;
90 if (attr & FOREGROUND_GREEN)
91 attributes |= BACKGROUND_GREEN;
92 if (attr & FOREGROUND_BLUE)
93 attributes |= BACKGROUND_BLUE;
94
95 if (attr & BACKGROUND_RED)
96 attributes |= FOREGROUND_RED;
97 if (attr & BACKGROUND_GREEN)
98 attributes |= FOREGROUND_GREEN;
99 if (attr & BACKGROUND_BLUE)
100 attributes |= FOREGROUND_BLUE;
101 }
102 SetConsoleTextAttribute(console, attributes);
103}
104
105static void erase_in_line(void)
106{
107 CONSOLE_SCREEN_BUFFER_INFO sbi;
108 DWORD dummy; /* Needed for Windows 7 (or Vista) regression */
109
110 if (!console)
111 return;
112
113 GetConsoleScreenBufferInfo(console, &sbi);
114 FillConsoleOutputCharacterA(console, ' ',
115 sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
116 &dummy);
117 FillConsoleOutputAttribute(console, plain_attr,
118 sbi.dwSize.X - sbi.dwCursorPosition.X, sbi.dwCursorPosition,
119 &dummy);
120}
121
122static void erase_till_end_of_screen(void)
123{
124 CONSOLE_SCREEN_BUFFER_INFO sbi;
125 DWORD dummy, len;
126
127 if (!console)
128 return;
129
130 GetConsoleScreenBufferInfo(console, &sbi);
131 len = sbi.dwSize.X - sbi.dwCursorPosition.X +
132 sbi.dwSize.X * (sbi.srWindow.Bottom - sbi.dwCursorPosition.Y);
133
134 FillConsoleOutputCharacterA(console, ' ', len, sbi.dwCursorPosition,
135 &dummy);
136 FillConsoleOutputAttribute(console, plain_attr, len, sbi.dwCursorPosition,
137 &dummy);
138}
139
140void reset_screen(void)
141{
142 CONSOLE_SCREEN_BUFFER_INFO sbi;
143 COORD pos;
144 DWORD dummy, len;
145
146 if (!console)
147 return;
148
149 /* move to start of screen buffer and clear it all */
150 GetConsoleScreenBufferInfo(console, &sbi);
151 pos.X = 0;
152 pos.Y = 0;
153 SetConsoleCursorPosition(console, pos);
154 len = sbi.dwSize.X * sbi.dwSize.Y;
155 FillConsoleOutputCharacterA(console, ' ', len, pos, &dummy);
156 FillConsoleOutputAttribute(console, plain_attr, len, pos, &dummy);
157}
158
159void move_cursor_row(int n)
160{
161 CONSOLE_SCREEN_BUFFER_INFO sbi;
162
163 if (!console)
164 return;
165
166 GetConsoleScreenBufferInfo(console, &sbi);
167 sbi.dwCursorPosition.Y += n;
168 SetConsoleCursorPosition(console, sbi.dwCursorPosition);
169}
170
171static void move_cursor_column(int n)
172{
173 CONSOLE_SCREEN_BUFFER_INFO sbi;
174
175 if (!console)
176 return;
177
178 GetConsoleScreenBufferInfo(console, &sbi);
179 sbi.dwCursorPosition.X += n;
180 SetConsoleCursorPosition(console, sbi.dwCursorPosition);
181}
182
183static void move_cursor(int x, int y)
184{
185 COORD pos;
186 CONSOLE_SCREEN_BUFFER_INFO sbi;
187
188 if (!console)
189 return;
190
191 GetConsoleScreenBufferInfo(console, &sbi);
192 pos.X = sbi.srWindow.Left + x;
193 pos.Y = sbi.srWindow.Top + y;
194 SetConsoleCursorPosition(console, pos);
195}
196
197static const char *set_attr(const char *str)
198{
199 const char *func;
200 size_t len = strspn(str, "0123456789;");
201 func = str + len;
202
203 switch (*func) {
204 case 'm':
205 do {
206 long val = strtol(str, (char **)&str, 10);
207 switch (val) {
208 case 0: /* reset */
209 attr = plain_attr;
210 negative = 0;
211 break;
212 case 1: /* bold */
213 attr |= FOREGROUND_INTENSITY;
214 break;
215 case 2: /* faint */
216 case 22: /* normal */
217 attr &= ~FOREGROUND_INTENSITY;
218 break;
219 case 3: /* italic */
220 /* Unsupported */
221 break;
222 case 4: /* underline */
223 case 21: /* double underline */
224 /* Wikipedia says this flag does nothing */
225 /* Furthermore, mingw doesn't define this flag
226 attr |= COMMON_LVB_UNDERSCORE; */
227 break;
228 case 24: /* no underline */
229 /* attr &= ~COMMON_LVB_UNDERSCORE; */
230 break;
231 case 5: /* slow blink */
232 case 6: /* fast blink */
233 /* We don't have blink, but we do have
234 background intensity */
235 attr |= BACKGROUND_INTENSITY;
236 break;
237 case 25: /* no blink */
238 attr &= ~BACKGROUND_INTENSITY;
239 break;
240 case 7: /* negative */
241 negative = 1;
242 break;
243 case 27: /* positive */
244 negative = 0;
245 break;
246 case 8: /* conceal */
247 case 28: /* reveal */
248 /* Unsupported */
249 break;
250 case 30: /* Black */
251 attr &= ~FOREGROUND_ALL;
252 break;
253 case 31: /* Red */
254 attr &= ~FOREGROUND_ALL;
255 attr |= FOREGROUND_RED;
256 break;
257 case 32: /* Green */
258 attr &= ~FOREGROUND_ALL;
259 attr |= FOREGROUND_GREEN;
260 break;
261 case 33: /* Yellow */
262 attr &= ~FOREGROUND_ALL;
263 attr |= FOREGROUND_RED | FOREGROUND_GREEN;
264 break;
265 case 34: /* Blue */
266 attr &= ~FOREGROUND_ALL;
267 attr |= FOREGROUND_BLUE;
268 break;
269 case 35: /* Magenta */
270 attr &= ~FOREGROUND_ALL;
271 attr |= FOREGROUND_RED | FOREGROUND_BLUE;
272 break;
273 case 36: /* Cyan */
274 attr &= ~FOREGROUND_ALL;
275 attr |= FOREGROUND_GREEN | FOREGROUND_BLUE;
276 break;
277 case 37: /* White */
278 attr |= FOREGROUND_RED |
279 FOREGROUND_GREEN |
280 FOREGROUND_BLUE;
281 break;
282 case 38: /* Unknown */
283 break;
284 case 39: /* reset */
285 attr &= ~FOREGROUND_ALL;
286 attr |= (plain_attr & FOREGROUND_ALL);
287 break;
288 case 40: /* Black */
289 attr &= ~BACKGROUND_ALL;
290 break;
291 case 41: /* Red */
292 attr &= ~BACKGROUND_ALL;
293 attr |= BACKGROUND_RED;
294 break;
295 case 42: /* Green */
296 attr &= ~BACKGROUND_ALL;
297 attr |= BACKGROUND_GREEN;
298 break;
299 case 43: /* Yellow */
300 attr &= ~BACKGROUND_ALL;
301 attr |= BACKGROUND_RED | BACKGROUND_GREEN;
302 break;
303 case 44: /* Blue */
304 attr &= ~BACKGROUND_ALL;
305 attr |= BACKGROUND_BLUE;
306 break;
307 case 45: /* Magenta */
308 attr &= ~BACKGROUND_ALL;
309 attr |= BACKGROUND_RED | BACKGROUND_BLUE;
310 break;
311 case 46: /* Cyan */
312 attr &= ~BACKGROUND_ALL;
313 attr |= BACKGROUND_GREEN | BACKGROUND_BLUE;
314 break;
315 case 47: /* White */
316 attr |= BACKGROUND_RED |
317 BACKGROUND_GREEN |
318 BACKGROUND_BLUE;
319 break;
320 case 48: /* Unknown */
321 break;
322 case 49: /* reset */
323 attr &= ~BACKGROUND_ALL;
324 attr |= (plain_attr & BACKGROUND_ALL);
325 break;
326 default:
327 /* Unsupported code */
328 break;
329 }
330 str++;
331 } while (*(str-1) == ';');
332
333 set_console_attr();
334 break;
335 case 'A': /* up */
336 move_cursor_row(-strtol(str, (char **)&str, 10));
337 break;
338 case 'B': /* down */
339 move_cursor_row(strtol(str, (char **)&str, 10));
340 break;
341 case 'C': /* forward */
342 move_cursor_column(strtol(str, (char **)&str, 10));
343 break;
344 case 'D': /* back */
345 move_cursor_column(-strtol(str, (char **)&str, 10));
346 break;
347 case 'H':
348 if (!len)
349 move_cursor(0, 0);
350 else {
351 int row, col = 1;
352
353 row = strtol(str, (char **)&str, 10);
354 if (*str == ';') {
355 col = strtol(str+1, (char **)&str, 10);
356 }
357 move_cursor(col > 0 ? col-1 : 0, row > 0 ? row-1 : 0);
358 }
359 break;
360 case 'J':
361 erase_till_end_of_screen();
362 break;
363 case 'K':
364 erase_in_line();
365 break;
366 case '?':
367 /* skip this to avoid ugliness when vi is shut down */
368 ++str;
369 while (isdigit(*str))
370 ++str;
371 func = str;
372 break;
373 default:
374 /* Unsupported code */
375 break;
376 }
377
378 return func + 1;
379}
380
381static int ansi_emulate(const char *s, FILE *stream)
382{
383 int rv = 0;
384 const char *t;
385 char *pos, *str;
386 size_t out_len, cur_len;
387 static size_t max_len = 0;
388 static char *mem = NULL;
389
390 /* if no special treatment is required output the string as-is */
391 for ( t=s; *t; ++t ) {
392 if ( *t == '\033' || *t > 0x7f ) {
393 break;
394 }
395 }
396
397 if ( *t == '\0' ) {
398 return fputs(s, stream) == EOF ? EOF : strlen(s);
399 }
400
401 /* make a writable copy of the string and retain it for reuse */
402 cur_len = strlen(s);
403 if ( cur_len == 0 || cur_len > max_len ) {
404 free(mem);
405 mem = strdup(s);
406 max_len = cur_len;
407 }
408 else {
409 strcpy(mem, s);
410 }
411 pos = str = mem;
412
413 while (*pos) {
414 pos = strstr(str, "\033[");
415 if (pos && !skip_ansi_emulation()) {
416 size_t len = pos - str;
417
418 if (len) {
419 CharToOemBuff(str, str, len);
420 out_len = fwrite(str, 1, len, stream);
421 rv += out_len;
422 if (out_len < len)
423 return rv;
424 }
425
426 str = pos + 2;
427 rv += 2;
428
429 fflush(stream);
430
431 pos = (char *)set_attr(str);
432 rv += pos - str;
433 str = pos;
434 } else {
435 rv += strlen(str);
436 CharToOem(str, str);
437 fputs(str, stream);
438 return rv;
439 }
440 }
441 return rv;
442}
443
444int winansi_putchar(int c)
445{
446 char t = c;
447 char *s = &t;
448
449 if (!isatty(STDOUT_FILENO))
450 return putchar(c);
451
452 init();
453
454 if (!console)
455 return putchar(c);
456
457 CharToOemBuff(s, s, 1);
458 return putchar(t) == EOF ? EOF : c;
459}
460
461int winansi_puts(const char *s)
462{
463 int rv;
464
465 if (!isatty(STDOUT_FILENO))
466 return puts(s);
467
468 init();
469
470 if (!console)
471 return puts(s);
472
473 rv = ansi_emulate(s, stdout);
474 putchar('\n');
475
476 return rv;
477}
478
479size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
480{
481 size_t lsize, lmemb;
482 char *str;
483 int rv;
484
485 lsize = MIN(size, nmemb);
486 lmemb = MAX(size, nmemb);
487 if (lsize != 1)
488 return fwrite(ptr, size, nmemb, stream);
489
490 if (!isatty(fileno(stream)))
491 return fwrite(ptr, size, nmemb, stream);
492
493 init();
494
495 if (!console)
496 return fwrite(ptr, size, nmemb, stream);
497
498 str = xmalloc(lmemb+1);
499 memcpy(str, ptr, lmemb);
500 str[lmemb] = '\0';
501
502 rv = ansi_emulate(str, stream);
503 free(str);
504
505 return rv;
506}
507
508int winansi_fputs(const char *str, FILE *stream)
509{
510 int rv;
511
512 if (!isatty(fileno(stream)))
513 return fputs(str, stream);
514
515 init();
516
517 if (!console)
518 return fputs(str, stream);
519
520 rv = ansi_emulate(str, stream);
521
522 if (rv >= 0)
523 return 0;
524 else
525 return EOF;
526}
527
528int winansi_vfprintf(FILE *stream, const char *format, va_list list)
529{
530 int len, rv;
531 char small_buf[256];
532 char *buf = small_buf;
533 va_list cp;
534
535 if (!isatty(fileno(stream)))
536 goto abort;
537
538 init();
539
540 if (!console)
541 goto abort;
542
543 va_copy(cp, list);
544 len = vsnprintf(small_buf, sizeof(small_buf), format, cp);
545 va_end(cp);
546
547 if (len > sizeof(small_buf) - 1) {
548 buf = malloc(len + 1);
549 if (!buf)
550 goto abort;
551
552 va_copy(cp, list);
553 len = vsnprintf(buf, len + 1, format, cp);
554 va_end(cp);
555 }
556
557 if (len == -1)
558 goto abort;
559
560 rv = ansi_emulate(buf, stream);
561
562 if (buf != small_buf)
563 free(buf);
564 return rv;
565
566abort:
567 rv = vfprintf(stream, format, list);
568 return rv;
569}
570
571int winansi_fprintf(FILE *stream, const char *format, ...)
572{
573 va_list list;
574 int rv;
575
576 va_start(list, format);
577 rv = winansi_vfprintf(stream, format, list);
578 va_end(list);
579
580 return rv;
581}
582
583int winansi_printf(const char *format, ...)
584{
585 va_list list;
586 int rv;
587
588 va_start(list, format);
589 rv = winansi_vfprintf(stdout, format, list);
590 va_end(list);
591
592 return rv;
593}
594
595int winansi_get_terminal_width_height(struct winsize *win)
596{
597 BOOL ret;
598 CONSOLE_SCREEN_BUFFER_INFO sbi;
599
600 init();
601
602 win->ws_row = 0;
603 win->ws_col = 0;
604 if ((ret=GetConsoleScreenBufferInfo(console, &sbi)) != 0) {
605 win->ws_row = sbi.srWindow.Bottom - sbi.srWindow.Top + 1;
606 win->ws_col = sbi.srWindow.Right - sbi.srWindow.Left + 1;
607 }
608
609 return ret ? 0 : -1;
610}
611
612static int ansi_emulate_write(int fd, const void *buf, size_t count)
613{
614 int rv = 0, i;
615 int special = FALSE, has_null = FALSE;
616 const char *s = (const char *)buf;
617 char *pos, *str;
618 size_t len, out_len;
619 static size_t max_len = 0;
620 static char *mem = NULL;
621
622 for ( i=0; i<count; ++i ) {
623 if ( s[i] == '\033' || s[i] > 0x7f ) {
624 special = TRUE;
625 }
626 else if ( !s[i] ) {
627 has_null = TRUE;
628 }
629 }
630
631 /*
632 * If no special treatment is required or the data contains NUL
633 * characters output the string as-is.
634 */
635 if ( !special || has_null ) {
636 return write(fd, buf, count);
637 }
638
639 /* make a writable copy of the data and retain it for reuse */
640 if ( count > max_len ) {
641 free(mem);
642 mem = malloc(count+1);
643 max_len = count;
644 }
645 memcpy(mem, buf, count);
646 mem[count] = '\0';
647 pos = str = mem;
648
649 /* we've checked the data doesn't contain any NULs */
650 while (*pos) {
651 pos = strstr(str, "\033[");
652 if (pos && !skip_ansi_emulation()) {
653 len = pos - str;
654
655 if (len) {
656 CharToOemBuff(str, str, len);
657 out_len = write(fd, str, len);
658 rv += out_len;
659 if (out_len < len)
660 return rv;
661 }
662
663 str = pos + 2;
664 rv += 2;
665
666 pos = (char *)set_attr(str);
667 rv += pos - str;
668 str = pos;
669 } else {
670 len = strlen(str);
671 rv += len;
672 CharToOem(str, str);
673 write(fd, str, len);
674 return rv;
675 }
676 }
677 return rv;
678}
679
680int winansi_write(int fd, const void *buf, size_t count)
681{
682 if (!isatty(fd))
683 return write(fd, buf, count);
684
685 init();
686
687 if (!console)
688 return write(fd, buf, count);
689
690 return ansi_emulate_write(fd, buf, count);
691}
692
693int winansi_read(int fd, void *buf, size_t count)
694{
695 int rv;
696
697 rv = read(fd, buf, count);
698 if (!isatty(fd))
699 return rv;
700
701 init();
702
703 if (!console_in)
704 return rv;
705
706 if ( rv > 0 ) {
707 OemToCharBuff(buf, buf, rv);
708 }
709
710 return rv;
711}
712
713int winansi_getc(FILE *stream)
714{
715 int rv;
716
717 rv = getc(stream);
718 if (!isatty(fileno(stream)))
719 return rv;
720
721 init();
722
723 if (!console_in)
724 return rv;
725
726 if ( rv != EOF ) {
727 unsigned char c = (unsigned char)rv;
728 char *s = (char *)&c;
729 OemToCharBuff(s, s, 1);
730 rv = (int)c;
731 }
732
733 return rv;
734}