diff options
Diffstat (limited to '')
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 | ||
@@ -9,6 +9,20 @@ config HAVE_DOT_CONFIG | |||
9 | bool | 9 | bool |
10 | default y | 10 | default y |
11 | 11 | ||
12 | choice | ||
13 | prompt "Target platform" | ||
14 | default PLATFORM_POSIX | ||
15 | help | ||
16 | Target platform you are building busybox for | ||
17 | |||
18 | config PLATFORM_POSIX | ||
19 | bool "POSIX" | ||
20 | |||
21 | config PLATFORM_MINGW32 | ||
22 | bool "MS Windows (MinGW port)" | ||
23 | |||
24 | endchoice | ||
25 | |||
12 | menu "Busybox Settings" | 26 | menu "Busybox Settings" |
13 | 27 | ||
14 | config DESKTOP | 28 | config 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 | ||
484 | config 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 | |||
496 | config 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 | |||
470 | config CROSS_COMPILER_PREFIX | 506 | config CROSS_COMPILER_PREFIX |
471 | string "Cross Compiler prefix" | 507 | string "Cross Compiler prefix" |
472 | default "" | 508 | default "" |
@@ -312,6 +312,7 @@ AFLAGS_MODULE = $(MODFLAGS) | |||
312 | LDFLAGS_MODULE = -r | 312 | LDFLAGS_MODULE = -r |
313 | CFLAGS_KERNEL = | 313 | CFLAGS_KERNEL = |
314 | AFLAGS_KERNEL = | 314 | AFLAGS_KERNEL = |
315 | EXEEXT = | ||
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 | ||
495 | endif # KBUILD_EXTMOD | 497 | endif # 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 |
532 | all: busybox doc | 534 | all: 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) | |||
713 | endif # ifdef CONFIG_KALLSYMS | 715 | endif # ifdef CONFIG_KALLSYMS |
714 | 716 | ||
715 | # busybox image - including updated kernel symbols | 717 | # busybox image - including updated kernel symbols |
716 | busybox_unstripped: $(busybox-all) FORCE | 718 | busybox_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 | ||
720 | busybox: busybox_unstripped | 722 | busybox$(EXEEXT): busybox_unstripped$(EXEEXT) |
721 | ifeq ($(SKIP_STRIP),y) | 723 | ifeq ($(SKIP_STRIP),y) |
722 | $(Q)cp $< $@ | 724 | $(Q)cp $< $@ |
723 | else | 725 | else |
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 $@ |
728 | endif | 730 | endif |
@@ -961,7 +963,7 @@ endif # CONFIG_MODULES | |||
961 | 963 | ||
962 | # Directories & files removed with 'make clean' | 964 | # Directories & files removed with 'make clean' |
963 | CLEAN_DIRS += $(MODVERDIR) _install 0_lib | 965 | CLEAN_DIRS += $(MODVERDIR) _install 0_lib |
964 | CLEAN_FILES += busybox busybox_unstripped* busybox.links \ | 966 | CLEAN_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 | ||
20 | CFLAGS += $(call cc-option,-Wall,) | 21 | CFLAGS += $(call cc-option,-Wall,) |
21 | CFLAGS += $(call cc-option,-Wshadow,) | 22 | CFLAGS += $(call cc-option,-Wshadow,) |
@@ -123,6 +124,12 @@ CFLAGS += --sysroot=$(CONFIG_SYSROOT) | |||
123 | export SYSROOT=$(CONFIG_SYSROOT) | 124 | export SYSROOT=$(CONFIG_SYSROOT) |
124 | endif | 125 | endif |
125 | 126 | ||
127 | ifeq ($(CONFIG_PLATFORM_MINGW32),y) | ||
128 | CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-ident | ||
129 | EXEEXT = .exe | ||
130 | LDLIBS += userenv ws2_32 mingwex -l:libssp.a | ||
131 | endif | ||
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 - |
@@ -1,3 +1,4 @@ | |||
1 | Please see README.md for Windows-specific info. | ||
1 | Please see the LICENSE file for details on copying and usage. | 2 | Please see the LICENSE file for details on copying and usage. |
2 | Please refer to the INSTALL file for instructions on how to build. | 3 | Please 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 | |||
3 | Things may work for you, or may not. Things may never work because of huge differences between Linux and Windows. Or things may work in future, if you report the problem to https://github.com/rmyorston/busybox-w32. If you don't have a GitHub account you can email me: rmy@pobox.com. | ||
4 | |||
5 | ### Building | ||
6 | |||
7 | You 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 | |||
9 | To start, run `make mingw32_defconfig` or `make mingw64_defconfig`. You can then customize your build with `make menuconfig`. | ||
10 | |||
11 | In particular you may need to adjust the compiler by going to Busybox Settings -> Build Options -> Cross Compiler Prefix | ||
12 | |||
13 | Then 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 | ||
1121 | static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) | 1124 | static 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 | ||
1193 | IF_DESKTOP(long long) int FAST_FUNC | 1199 | IF_DESKTOP(long long) int FAST_FUNC |
1194 | unpack_gz_stream(transformer_state_t *xstate) | 1200 | unpack_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 | ||
68 | void check_errors_in_children(int signo) | 69 | void 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 */ | ||
156 | void check_errors_in_children(int signo UNUSED_PARAM) | ||
157 | { | ||
158 | bb_got_signal = 0; | ||
159 | } | ||
160 | |||
161 | void 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 */ |
624 | static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) | 627 | static 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 | ||
686 | static 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 | # | ||
6 | CONFIG_HAVE_DOT_CONFIG=y | ||
7 | # CONFIG_PLATFORM_POSIX is not set | ||
8 | CONFIG_PLATFORM_MINGW32=y | ||
9 | |||
10 | # | ||
11 | # Busybox Settings | ||
12 | # | ||
13 | CONFIG_DESKTOP=y | ||
14 | CONFIG_EXTRA_COMPAT=y | ||
15 | # CONFIG_INCLUDE_SUSv2 is not set | ||
16 | CONFIG_USE_PORTABLE_CODE=y | ||
17 | # CONFIG_PLATFORM_LINUX is not set | ||
18 | CONFIG_SHOW_USAGE=y | ||
19 | CONFIG_FEATURE_VERBOSE_USAGE=y | ||
20 | CONFIG_FEATURE_COMPRESS_USAGE=y | ||
21 | CONFIG_BUSYBOX=y | ||
22 | CONFIG_FEATURE_INSTALLER=y | ||
23 | # CONFIG_INSTALL_NO_USR is not set | ||
24 | # CONFIG_PAM is not set | ||
25 | CONFIG_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 | ||
31 | CONFIG_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 | ||
36 | CONFIG_FEATURE_PREFER_APPLETS=y | ||
37 | CONFIG_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 | ||
50 | CONFIG_LFS=y | ||
51 | # CONFIG_GLOBBING is not set | ||
52 | # CONFIG_SAFE_ENV is not set | ||
53 | CONFIG_CROSS_COMPILER_PREFIX="i686-w64-mingw32-" | ||
54 | CONFIG_SYSROOT="" | ||
55 | CONFIG_EXTRA_CFLAGS="" | ||
56 | CONFIG_EXTRA_LDFLAGS="" | ||
57 | CONFIG_EXTRA_LDLIBS="" | ||
58 | |||
59 | # | ||
60 | # Installation Options ("make install" behavior) | ||
61 | # | ||
62 | CONFIG_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 | ||
69 | CONFIG_PREFIX="" | ||
70 | |||
71 | # | ||
72 | # Debugging Options | ||
73 | # | ||
74 | CONFIG_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 | ||
79 | CONFIG_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 | ||
87 | CONFIG_FEATURE_RTMINMAX=y | ||
88 | CONFIG_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 | ||
91 | CONFIG_PASSWORD_MINLEN=6 | ||
92 | CONFIG_MD5_SMALL=1 | ||
93 | CONFIG_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 | ||
97 | CONFIG_FEATURE_EDITING=y | ||
98 | CONFIG_FEATURE_EDITING_MAX_LEN=1024 | ||
99 | CONFIG_FEATURE_EDITING_VI=y | ||
100 | CONFIG_FEATURE_EDITING_HISTORY=255 | ||
101 | CONFIG_FEATURE_EDITING_SAVEHISTORY=y | ||
102 | # CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set | ||
103 | CONFIG_FEATURE_REVERSE_SEARCH=y | ||
104 | CONFIG_FEATURE_TAB_COMPLETION=y | ||
105 | CONFIG_FEATURE_USERNAME_COMPLETION=y | ||
106 | CONFIG_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 | ||
112 | CONFIG_SUBST_WCHAR=0 | ||
113 | CONFIG_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 | ||
119 | CONFIG_FEATURE_NON_POSIX_CP=y | ||
120 | # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set | ||
121 | # CONFIG_FEATURE_USE_SENDFILE is not set | ||
122 | CONFIG_FEATURE_COPYBUF_KB=4 | ||
123 | CONFIG_FEATURE_SKIP_ROOTFS=y | ||
124 | # CONFIG_MONOTONIC_SYSCALL is not set | ||
125 | CONFIG_IOCTL_HEX2STR_ERROR=y | ||
126 | # CONFIG_FEATURE_HWIB is not set | ||
127 | |||
128 | # | ||
129 | # Applets | ||
130 | # | ||
131 | |||
132 | # | ||
133 | # Archival Utilities | ||
134 | # | ||
135 | CONFIG_FEATURE_SEAMLESS_XZ=y | ||
136 | CONFIG_FEATURE_SEAMLESS_LZMA=y | ||
137 | CONFIG_FEATURE_SEAMLESS_BZ2=y | ||
138 | CONFIG_FEATURE_SEAMLESS_GZ=y | ||
139 | CONFIG_FEATURE_SEAMLESS_Z=y | ||
140 | CONFIG_AR=y | ||
141 | CONFIG_FEATURE_AR_LONG_FILENAMES=y | ||
142 | CONFIG_FEATURE_AR_CREATE=y | ||
143 | CONFIG_UNCOMPRESS=y | ||
144 | CONFIG_GUNZIP=y | ||
145 | CONFIG_ZCAT=y | ||
146 | CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y | ||
147 | CONFIG_BUNZIP2=y | ||
148 | CONFIG_BZCAT=y | ||
149 | CONFIG_UNLZMA=y | ||
150 | CONFIG_LZCAT=y | ||
151 | CONFIG_LZMA=y | ||
152 | CONFIG_FEATURE_LZMA_FAST=y | ||
153 | CONFIG_UNXZ=y | ||
154 | CONFIG_XZCAT=y | ||
155 | CONFIG_XZ=y | ||
156 | CONFIG_BZIP2=y | ||
157 | CONFIG_CPIO=y | ||
158 | CONFIG_FEATURE_CPIO_O=y | ||
159 | CONFIG_FEATURE_CPIO_P=y | ||
160 | # CONFIG_DPKG is not set | ||
161 | CONFIG_DPKG_DEB=y | ||
162 | CONFIG_GZIP=y | ||
163 | CONFIG_FEATURE_GZIP_LONG_OPTIONS=y | ||
164 | CONFIG_GZIP_FAST=2 | ||
165 | CONFIG_FEATURE_GZIP_LEVELS=y | ||
166 | CONFIG_LZOP=y | ||
167 | CONFIG_UNLZOP=y | ||
168 | CONFIG_LZOPCAT=y | ||
169 | # CONFIG_LZOP_COMPR_HIGH is not set | ||
170 | CONFIG_RPM2CPIO=y | ||
171 | # CONFIG_RPM is not set | ||
172 | CONFIG_TAR=y | ||
173 | CONFIG_FEATURE_TAR_CREATE=y | ||
174 | CONFIG_FEATURE_TAR_AUTODETECT=y | ||
175 | CONFIG_FEATURE_TAR_FROM=y | ||
176 | CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y | ||
177 | # CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set | ||
178 | CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y | ||
179 | CONFIG_FEATURE_TAR_LONG_OPTIONS=y | ||
180 | # CONFIG_FEATURE_TAR_TO_COMMAND is not set | ||
181 | # CONFIG_FEATURE_TAR_UNAME_GNAME is not set | ||
182 | CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y | ||
183 | # CONFIG_FEATURE_TAR_SELINUX is not set | ||
184 | CONFIG_UNZIP=y | ||
185 | |||
186 | # | ||
187 | # Coreutils | ||
188 | # | ||
189 | CONFIG_BASENAME=y | ||
190 | CONFIG_CAL=y | ||
191 | CONFIG_CAT=y | ||
192 | CONFIG_CATV=y | ||
193 | # CONFIG_CHGRP is not set | ||
194 | CONFIG_CHMOD=y | ||
195 | # CONFIG_CHOWN is not set | ||
196 | # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set | ||
197 | # CONFIG_CHROOT is not set | ||
198 | CONFIG_CKSUM=y | ||
199 | CONFIG_COMM=y | ||
200 | CONFIG_CP=y | ||
201 | CONFIG_FEATURE_CP_LONG_OPTIONS=y | ||
202 | CONFIG_CUT=y | ||
203 | CONFIG_DATE=y | ||
204 | CONFIG_FEATURE_DATE_ISOFMT=y | ||
205 | # CONFIG_FEATURE_DATE_NANO is not set | ||
206 | CONFIG_FEATURE_DATE_COMPAT=y | ||
207 | CONFIG_DD=y | ||
208 | # CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set | ||
209 | # CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set | ||
210 | CONFIG_FEATURE_DD_IBS_OBS=y | ||
211 | CONFIG_FEATURE_DD_STATUS=y | ||
212 | CONFIG_DF=y | ||
213 | # CONFIG_FEATURE_DF_FANCY is not set | ||
214 | CONFIG_DIRNAME=y | ||
215 | CONFIG_DOS2UNIX=y | ||
216 | CONFIG_UNIX2DOS=y | ||
217 | CONFIG_DU=y | ||
218 | CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y | ||
219 | CONFIG_ECHO=y | ||
220 | CONFIG_FEATURE_FANCY_ECHO=y | ||
221 | CONFIG_ENV=y | ||
222 | CONFIG_FEATURE_ENV_LONG_OPTIONS=y | ||
223 | CONFIG_EXPAND=y | ||
224 | CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y | ||
225 | CONFIG_UNEXPAND=y | ||
226 | CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y | ||
227 | CONFIG_EXPR=y | ||
228 | CONFIG_EXPR_MATH_SUPPORT_64=y | ||
229 | CONFIG_FALSE=y | ||
230 | CONFIG_FOLD=y | ||
231 | # CONFIG_FSYNC is not set | ||
232 | CONFIG_HEAD=y | ||
233 | CONFIG_FEATURE_FANCY_HEAD=y | ||
234 | # CONFIG_HOSTID is not set | ||
235 | CONFIG_ID=y | ||
236 | CONFIG_GROUPS=y | ||
237 | # CONFIG_INSTALL is not set | ||
238 | # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set | ||
239 | CONFIG_LN=y | ||
240 | CONFIG_LOGNAME=y | ||
241 | CONFIG_LS=y | ||
242 | CONFIG_FEATURE_LS_FILETYPES=y | ||
243 | CONFIG_FEATURE_LS_FOLLOWLINKS=y | ||
244 | CONFIG_FEATURE_LS_RECURSIVE=y | ||
245 | CONFIG_FEATURE_LS_SORTFILES=y | ||
246 | CONFIG_FEATURE_LS_TIMESTAMPS=y | ||
247 | CONFIG_FEATURE_LS_USERNAME=y | ||
248 | CONFIG_FEATURE_LS_COLOR=y | ||
249 | CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y | ||
250 | CONFIG_MD5SUM=y | ||
251 | CONFIG_SHA1SUM=y | ||
252 | CONFIG_SHA256SUM=y | ||
253 | CONFIG_SHA512SUM=y | ||
254 | CONFIG_SHA3SUM=y | ||
255 | |||
256 | # | ||
257 | # Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum | ||
258 | # | ||
259 | CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y | ||
260 | CONFIG_MKDIR=y | ||
261 | CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y | ||
262 | # CONFIG_MKFIFO is not set | ||
263 | # CONFIG_MKNOD is not set | ||
264 | CONFIG_MV=y | ||
265 | CONFIG_FEATURE_MV_LONG_OPTIONS=y | ||
266 | # CONFIG_NICE is not set | ||
267 | # CONFIG_NOHUP is not set | ||
268 | CONFIG_OD=y | ||
269 | CONFIG_PRINTENV=y | ||
270 | CONFIG_PRINTF=y | ||
271 | CONFIG_PWD=y | ||
272 | # CONFIG_READLINK is not set | ||
273 | # CONFIG_FEATURE_READLINK_FOLLOW is not set | ||
274 | # CONFIG_REALPATH is not set | ||
275 | CONFIG_RM=y | ||
276 | CONFIG_RMDIR=y | ||
277 | CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y | ||
278 | CONFIG_SEQ=y | ||
279 | CONFIG_SHUF=y | ||
280 | CONFIG_SLEEP=y | ||
281 | CONFIG_FEATURE_FANCY_SLEEP=y | ||
282 | # CONFIG_FEATURE_FLOAT_SLEEP is not set | ||
283 | CONFIG_SORT=y | ||
284 | CONFIG_FEATURE_SORT_BIG=y | ||
285 | CONFIG_SPLIT=y | ||
286 | CONFIG_FEATURE_SPLIT_FANCY=y | ||
287 | CONFIG_STAT=y | ||
288 | CONFIG_FEATURE_STAT_FORMAT=y | ||
289 | CONFIG_FEATURE_STAT_FILESYSTEM=y | ||
290 | # CONFIG_STTY is not set | ||
291 | CONFIG_SUM=y | ||
292 | # CONFIG_SYNC is not set | ||
293 | # CONFIG_FEATURE_SYNC_FANCY is not set | ||
294 | CONFIG_TAC=y | ||
295 | CONFIG_TAIL=y | ||
296 | CONFIG_FEATURE_FANCY_TAIL=y | ||
297 | CONFIG_TEE=y | ||
298 | CONFIG_FEATURE_TEE_USE_BLOCK_IO=y | ||
299 | CONFIG_TEST=y | ||
300 | CONFIG_TEST1=y | ||
301 | CONFIG_TEST2=y | ||
302 | CONFIG_FEATURE_TEST_64=y | ||
303 | CONFIG_TOUCH=y | ||
304 | # CONFIG_FEATURE_TOUCH_NODEREF is not set | ||
305 | CONFIG_FEATURE_TOUCH_SUSV3=y | ||
306 | CONFIG_TR=y | ||
307 | CONFIG_FEATURE_TR_CLASSES=y | ||
308 | CONFIG_FEATURE_TR_EQUIV=y | ||
309 | CONFIG_TRUE=y | ||
310 | CONFIG_TRUNCATE=y | ||
311 | # CONFIG_TTY is not set | ||
312 | CONFIG_UNAME=y | ||
313 | CONFIG_UNAME_OSNAME="MS/Windows" | ||
314 | CONFIG_UNIQ=y | ||
315 | CONFIG_UNLINK=y | ||
316 | CONFIG_USLEEP=y | ||
317 | CONFIG_UUDECODE=y | ||
318 | CONFIG_BASE64=y | ||
319 | CONFIG_UUENCODE=y | ||
320 | CONFIG_WC=y | ||
321 | CONFIG_FEATURE_WC_LARGE=y | ||
322 | CONFIG_WHOAMI=y | ||
323 | # CONFIG_WHO is not set | ||
324 | # CONFIG_USERS is not set | ||
325 | CONFIG_YES=y | ||
326 | |||
327 | # | ||
328 | # Common options | ||
329 | # | ||
330 | CONFIG_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 | # | ||
340 | CONFIG_FEATURE_AUTOWIDTH=y | ||
341 | |||
342 | # | ||
343 | # Common options for df, du, ls | ||
344 | # | ||
345 | CONFIG_FEATURE_HUMAN_READABLE=y | ||
346 | |||
347 | # | ||
348 | # Console Utilities | ||
349 | # | ||
350 | # CONFIG_CHVT is not set | ||
351 | CONFIG_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 | ||
359 | CONFIG_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 | # | ||
376 | CONFIG_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 | ||
384 | CONFIG_WHICH=y | ||
385 | |||
386 | # | ||
387 | # Editors | ||
388 | # | ||
389 | CONFIG_AWK=y | ||
390 | CONFIG_FEATURE_AWK_LIBM=y | ||
391 | CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y | ||
392 | CONFIG_CMP=y | ||
393 | CONFIG_DIFF=y | ||
394 | CONFIG_FEATURE_DIFF_LONG_OPTIONS=y | ||
395 | CONFIG_FEATURE_DIFF_DIR=y | ||
396 | CONFIG_ED=y | ||
397 | CONFIG_PATCH=y | ||
398 | CONFIG_SED=y | ||
399 | CONFIG_VI=y | ||
400 | CONFIG_FEATURE_VI_MAX_LEN=4096 | ||
401 | CONFIG_FEATURE_VI_8BIT=y | ||
402 | CONFIG_FEATURE_VI_COLON=y | ||
403 | CONFIG_FEATURE_VI_YANKMARK=y | ||
404 | CONFIG_FEATURE_VI_SEARCH=y | ||
405 | # CONFIG_FEATURE_VI_REGEX_SEARCH is not set | ||
406 | # CONFIG_FEATURE_VI_USE_SIGNALS is not set | ||
407 | CONFIG_FEATURE_VI_DOT_CMD=y | ||
408 | CONFIG_FEATURE_VI_READONLY=y | ||
409 | CONFIG_FEATURE_VI_SETOPTS=y | ||
410 | CONFIG_FEATURE_VI_SET=y | ||
411 | CONFIG_FEATURE_VI_WIN_RESIZE=y | ||
412 | CONFIG_FEATURE_VI_ASK_TERMINAL=y | ||
413 | CONFIG_FEATURE_VI_UNDO=y | ||
414 | CONFIG_FEATURE_VI_UNDO_QUEUE=y | ||
415 | CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 | ||
416 | CONFIG_FEATURE_ALLOW_EXEC=y | ||
417 | |||
418 | # | ||
419 | # Finding Utilities | ||
420 | # | ||
421 | CONFIG_FIND=y | ||
422 | CONFIG_FEATURE_FIND_PRINT0=y | ||
423 | CONFIG_FEATURE_FIND_MTIME=y | ||
424 | CONFIG_FEATURE_FIND_MMIN=y | ||
425 | CONFIG_FEATURE_FIND_PERM=y | ||
426 | CONFIG_FEATURE_FIND_TYPE=y | ||
427 | # CONFIG_FEATURE_FIND_XDEV is not set | ||
428 | CONFIG_FEATURE_FIND_MAXDEPTH=y | ||
429 | CONFIG_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 | ||
435 | CONFIG_FEATURE_FIND_NOT=y | ||
436 | CONFIG_FEATURE_FIND_DEPTH=y | ||
437 | CONFIG_FEATURE_FIND_PAREN=y | ||
438 | CONFIG_FEATURE_FIND_SIZE=y | ||
439 | CONFIG_FEATURE_FIND_PRUNE=y | ||
440 | CONFIG_FEATURE_FIND_DELETE=y | ||
441 | CONFIG_FEATURE_FIND_PATH=y | ||
442 | CONFIG_FEATURE_FIND_REGEX=y | ||
443 | # CONFIG_FEATURE_FIND_CONTEXT is not set | ||
444 | # CONFIG_FEATURE_FIND_LINKS is not set | ||
445 | CONFIG_GREP=y | ||
446 | CONFIG_EGREP=y | ||
447 | CONFIG_FGREP=y | ||
448 | CONFIG_FEATURE_GREP_CONTEXT=y | ||
449 | CONFIG_XARGS=y | ||
450 | CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y | ||
451 | CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y | ||
452 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y | ||
453 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y | ||
454 | CONFIG_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 | ||
466 | CONFIG_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 | ||
471 | CONFIG_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 | ||
476 | CONFIG_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 | ||
497 | CONFIG_LAST_ID=0 | ||
498 | CONFIG_FIRST_SYSTEM_ID=0 | ||
499 | CONFIG_LAST_SYSTEM_ID=0 | ||
500 | # CONFIG_CHPASSWD is not set | ||
501 | CONFIG_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 | ||
557 | CONFIG_DEFAULT_MODULES_DIR="" | ||
558 | CONFIG_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 | ||
591 | CONFIG_GETOPT=y | ||
592 | CONFIG_FEATURE_GETOPT_LONG=y | ||
593 | CONFIG_HEXDUMP=y | ||
594 | CONFIG_FEATURE_HEXDUMP_REVERSE=y | ||
595 | CONFIG_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 | ||
636 | CONFIG_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 | ||
687 | CONFIG_FEATURE_BEEP_FREQ=0 | ||
688 | CONFIG_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 | ||
702 | CONFIG_FEATURE_CROND_DIR="" | ||
703 | # CONFIG_CRONTAB is not set | ||
704 | CONFIG_DC=y | ||
705 | CONFIG_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 | ||
734 | CONFIG_LESS=y | ||
735 | CONFIG_FEATURE_LESS_MAXLINES=9999999 | ||
736 | CONFIG_FEATURE_LESS_BRACKETS=y | ||
737 | CONFIG_FEATURE_LESS_FLAGS=y | ||
738 | CONFIG_FEATURE_LESS_TRUNCATE=y | ||
739 | CONFIG_FEATURE_LESS_MARKS=y | ||
740 | CONFIG_FEATURE_LESS_REGEXP=y | ||
741 | # CONFIG_FEATURE_LESS_WINCH is not set | ||
742 | # CONFIG_FEATURE_LESS_ASK_TERMINAL is not set | ||
743 | CONFIG_FEATURE_LESS_DASHCMD=y | ||
744 | CONFIG_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 | ||
748 | CONFIG_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 | ||
761 | CONFIG_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 | # | ||
781 | CONFIG_FEATURE_IPV6=y | ||
782 | # CONFIG_FEATURE_UNIX_LOCAL is not set | ||
783 | CONFIG_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 | ||
796 | CONFIG_FTPGET=y | ||
797 | CONFIG_FTPPUT=y | ||
798 | CONFIG_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 | ||
823 | CONFIG_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 | ||
842 | CONFIG_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 | ||
854 | CONFIG_IPCALC=y | ||
855 | CONFIG_FEATURE_IPCALC_FANCY=y | ||
856 | CONFIG_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 | ||
861 | CONFIG_NC=y | ||
862 | CONFIG_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 | ||
900 | CONFIG_WGET=y | ||
901 | # CONFIG_FEATURE_WGET_STATUSBAR is not set | ||
902 | # CONFIG_FEATURE_WGET_AUTHENTICATION is not set | ||
903 | CONFIG_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 | ||
907 | CONFIG_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 | ||
915 | CONFIG_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 | ||
920 | CONFIG_UDHCP_DEBUG=0 | ||
921 | # CONFIG_FEATURE_UDHCP_RFC3397 is not set | ||
922 | # CONFIG_FEATURE_UDHCP_8021Q is not set | ||
923 | CONFIG_UDHCPC_DEFAULT_SCRIPT="" | ||
924 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 | ||
925 | CONFIG_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 | ||
943 | CONFIG_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 | ||
951 | CONFIG_KILL=y | ||
952 | CONFIG_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 | ||
957 | CONFIG_PGREP=y | ||
958 | # CONFIG_PKILL is not set | ||
959 | CONFIG_PIDOF=y | ||
960 | CONFIG_FEATURE_PIDOF_SINGLE=y | ||
961 | CONFIG_FEATURE_PIDOF_OMIT=y | ||
962 | # CONFIG_PMAP is not set | ||
963 | # CONFIG_POWERTOP is not set | ||
964 | CONFIG_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 | ||
999 | CONFIG_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 | # | ||
1021 | CONFIG_ASH=y | ||
1022 | CONFIG_ASH_OPTIMIZE_FOR_SIZE=y | ||
1023 | CONFIG_ASH_INTERNAL_GLOB=y | ||
1024 | CONFIG_ASH_RANDOM_SUPPORT=y | ||
1025 | CONFIG_ASH_EXPAND_PRMT=y | ||
1026 | CONFIG_ASH_BASH_COMPAT=y | ||
1027 | # CONFIG_ASH_IDLE_TIMEOUT is not set | ||
1028 | # CONFIG_ASH_JOB_CONTROL is not set | ||
1029 | CONFIG_ASH_ALIAS=y | ||
1030 | CONFIG_ASH_GETOPTS=y | ||
1031 | CONFIG_ASH_BUILTIN_ECHO=y | ||
1032 | CONFIG_ASH_BUILTIN_PRINTF=y | ||
1033 | CONFIG_ASH_BUILTIN_TEST=y | ||
1034 | CONFIG_ASH_HELP=y | ||
1035 | CONFIG_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 | ||
1055 | CONFIG_FEATURE_SH_IS_ASH=y | ||
1056 | # CONFIG_FEATURE_SH_IS_HUSH is not set | ||
1057 | # CONFIG_FEATURE_SH_IS_NONE is not set | ||
1058 | CONFIG_FEATURE_BASH_IS_ASH=y | ||
1059 | # CONFIG_FEATURE_BASH_IS_HUSH is not set | ||
1060 | # CONFIG_FEATURE_BASH_IS_NONE is not set | ||
1061 | CONFIG_SH_MATH_SUPPORT=y | ||
1062 | CONFIG_SH_MATH_SUPPORT_64=y | ||
1063 | CONFIG_FEATURE_SH_EXTRA_QUIET=y | ||
1064 | CONFIG_FEATURE_SH_STANDALONE=y | ||
1065 | CONFIG_FEATURE_SH_NOFORK=y | ||
1066 | CONFIG_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 | ||
1081 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 | ||
1082 | # CONFIG_FEATURE_IPC_SYSLOG is not set | ||
1083 | CONFIG_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 | # | ||
6 | CONFIG_HAVE_DOT_CONFIG=y | ||
7 | # CONFIG_PLATFORM_POSIX is not set | ||
8 | CONFIG_PLATFORM_MINGW32=y | ||
9 | |||
10 | # | ||
11 | # Busybox Settings | ||
12 | # | ||
13 | CONFIG_DESKTOP=y | ||
14 | CONFIG_EXTRA_COMPAT=y | ||
15 | # CONFIG_INCLUDE_SUSv2 is not set | ||
16 | CONFIG_USE_PORTABLE_CODE=y | ||
17 | # CONFIG_PLATFORM_LINUX is not set | ||
18 | CONFIG_SHOW_USAGE=y | ||
19 | CONFIG_FEATURE_VERBOSE_USAGE=y | ||
20 | CONFIG_FEATURE_COMPRESS_USAGE=y | ||
21 | CONFIG_BUSYBOX=y | ||
22 | CONFIG_FEATURE_INSTALLER=y | ||
23 | # CONFIG_INSTALL_NO_USR is not set | ||
24 | # CONFIG_PAM is not set | ||
25 | CONFIG_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 | ||
31 | CONFIG_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 | ||
36 | CONFIG_FEATURE_PREFER_APPLETS=y | ||
37 | CONFIG_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 | ||
50 | CONFIG_LFS=y | ||
51 | # CONFIG_GLOBBING is not set | ||
52 | CONFIG_SAFE_ENV=y | ||
53 | CONFIG_CROSS_COMPILER_PREFIX="x86_64-w64-mingw32-" | ||
54 | CONFIG_SYSROOT="" | ||
55 | CONFIG_EXTRA_CFLAGS="-funwind-tables -fasynchronous-unwind-tables" | ||
56 | CONFIG_EXTRA_LDFLAGS="" | ||
57 | CONFIG_EXTRA_LDLIBS="" | ||
58 | |||
59 | # | ||
60 | # Installation Options ("make install" behavior) | ||
61 | # | ||
62 | CONFIG_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 | ||
69 | CONFIG_PREFIX="" | ||
70 | |||
71 | # | ||
72 | # Debugging Options | ||
73 | # | ||
74 | CONFIG_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 | ||
79 | CONFIG_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 | ||
87 | CONFIG_FEATURE_RTMINMAX=y | ||
88 | CONFIG_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 | ||
91 | CONFIG_PASSWORD_MINLEN=6 | ||
92 | CONFIG_MD5_SMALL=1 | ||
93 | CONFIG_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 | ||
97 | CONFIG_FEATURE_EDITING=y | ||
98 | CONFIG_FEATURE_EDITING_MAX_LEN=1024 | ||
99 | CONFIG_FEATURE_EDITING_VI=y | ||
100 | CONFIG_FEATURE_EDITING_HISTORY=255 | ||
101 | CONFIG_FEATURE_EDITING_SAVEHISTORY=y | ||
102 | # CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set | ||
103 | CONFIG_FEATURE_REVERSE_SEARCH=y | ||
104 | CONFIG_FEATURE_TAB_COMPLETION=y | ||
105 | CONFIG_FEATURE_USERNAME_COMPLETION=y | ||
106 | CONFIG_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 | ||
112 | CONFIG_SUBST_WCHAR=0 | ||
113 | CONFIG_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 | ||
119 | CONFIG_FEATURE_NON_POSIX_CP=y | ||
120 | # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set | ||
121 | # CONFIG_FEATURE_USE_SENDFILE is not set | ||
122 | CONFIG_FEATURE_COPYBUF_KB=4 | ||
123 | CONFIG_FEATURE_SKIP_ROOTFS=y | ||
124 | # CONFIG_MONOTONIC_SYSCALL is not set | ||
125 | CONFIG_IOCTL_HEX2STR_ERROR=y | ||
126 | # CONFIG_FEATURE_HWIB is not set | ||
127 | |||
128 | # | ||
129 | # Applets | ||
130 | # | ||
131 | |||
132 | # | ||
133 | # Archival Utilities | ||
134 | # | ||
135 | CONFIG_FEATURE_SEAMLESS_XZ=y | ||
136 | CONFIG_FEATURE_SEAMLESS_LZMA=y | ||
137 | CONFIG_FEATURE_SEAMLESS_BZ2=y | ||
138 | CONFIG_FEATURE_SEAMLESS_GZ=y | ||
139 | CONFIG_FEATURE_SEAMLESS_Z=y | ||
140 | CONFIG_AR=y | ||
141 | CONFIG_FEATURE_AR_LONG_FILENAMES=y | ||
142 | CONFIG_FEATURE_AR_CREATE=y | ||
143 | CONFIG_UNCOMPRESS=y | ||
144 | CONFIG_GUNZIP=y | ||
145 | CONFIG_ZCAT=y | ||
146 | CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y | ||
147 | CONFIG_BUNZIP2=y | ||
148 | CONFIG_BZCAT=y | ||
149 | CONFIG_UNLZMA=y | ||
150 | CONFIG_LZCAT=y | ||
151 | CONFIG_LZMA=y | ||
152 | CONFIG_FEATURE_LZMA_FAST=y | ||
153 | CONFIG_UNXZ=y | ||
154 | CONFIG_XZCAT=y | ||
155 | CONFIG_XZ=y | ||
156 | CONFIG_BZIP2=y | ||
157 | CONFIG_CPIO=y | ||
158 | CONFIG_FEATURE_CPIO_O=y | ||
159 | CONFIG_FEATURE_CPIO_P=y | ||
160 | # CONFIG_DPKG is not set | ||
161 | CONFIG_DPKG_DEB=y | ||
162 | CONFIG_GZIP=y | ||
163 | CONFIG_FEATURE_GZIP_LONG_OPTIONS=y | ||
164 | CONFIG_GZIP_FAST=2 | ||
165 | CONFIG_FEATURE_GZIP_LEVELS=y | ||
166 | CONFIG_LZOP=y | ||
167 | CONFIG_UNLZOP=y | ||
168 | CONFIG_LZOPCAT=y | ||
169 | # CONFIG_LZOP_COMPR_HIGH is not set | ||
170 | CONFIG_RPM2CPIO=y | ||
171 | # CONFIG_RPM is not set | ||
172 | CONFIG_TAR=y | ||
173 | CONFIG_FEATURE_TAR_CREATE=y | ||
174 | CONFIG_FEATURE_TAR_AUTODETECT=y | ||
175 | CONFIG_FEATURE_TAR_FROM=y | ||
176 | CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y | ||
177 | # CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set | ||
178 | CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y | ||
179 | CONFIG_FEATURE_TAR_LONG_OPTIONS=y | ||
180 | # CONFIG_FEATURE_TAR_TO_COMMAND is not set | ||
181 | # CONFIG_FEATURE_TAR_UNAME_GNAME is not set | ||
182 | CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y | ||
183 | # CONFIG_FEATURE_TAR_SELINUX is not set | ||
184 | CONFIG_UNZIP=y | ||
185 | |||
186 | # | ||
187 | # Coreutils | ||
188 | # | ||
189 | CONFIG_BASENAME=y | ||
190 | CONFIG_CAL=y | ||
191 | CONFIG_CAT=y | ||
192 | CONFIG_CATV=y | ||
193 | # CONFIG_CHGRP is not set | ||
194 | CONFIG_CHMOD=y | ||
195 | # CONFIG_CHOWN is not set | ||
196 | # CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set | ||
197 | # CONFIG_CHROOT is not set | ||
198 | CONFIG_CKSUM=y | ||
199 | CONFIG_COMM=y | ||
200 | CONFIG_CP=y | ||
201 | CONFIG_FEATURE_CP_LONG_OPTIONS=y | ||
202 | CONFIG_CUT=y | ||
203 | CONFIG_DATE=y | ||
204 | CONFIG_FEATURE_DATE_ISOFMT=y | ||
205 | # CONFIG_FEATURE_DATE_NANO is not set | ||
206 | CONFIG_FEATURE_DATE_COMPAT=y | ||
207 | CONFIG_DD=y | ||
208 | # CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set | ||
209 | # CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set | ||
210 | CONFIG_FEATURE_DD_IBS_OBS=y | ||
211 | CONFIG_FEATURE_DD_STATUS=y | ||
212 | CONFIG_DF=y | ||
213 | # CONFIG_FEATURE_DF_FANCY is not set | ||
214 | CONFIG_DIRNAME=y | ||
215 | CONFIG_DOS2UNIX=y | ||
216 | CONFIG_UNIX2DOS=y | ||
217 | CONFIG_DU=y | ||
218 | CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y | ||
219 | CONFIG_ECHO=y | ||
220 | CONFIG_FEATURE_FANCY_ECHO=y | ||
221 | CONFIG_ENV=y | ||
222 | CONFIG_FEATURE_ENV_LONG_OPTIONS=y | ||
223 | CONFIG_EXPAND=y | ||
224 | CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y | ||
225 | CONFIG_UNEXPAND=y | ||
226 | CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y | ||
227 | CONFIG_EXPR=y | ||
228 | CONFIG_EXPR_MATH_SUPPORT_64=y | ||
229 | CONFIG_FALSE=y | ||
230 | CONFIG_FOLD=y | ||
231 | # CONFIG_FSYNC is not set | ||
232 | CONFIG_HEAD=y | ||
233 | CONFIG_FEATURE_FANCY_HEAD=y | ||
234 | # CONFIG_HOSTID is not set | ||
235 | CONFIG_ID=y | ||
236 | CONFIG_GROUPS=y | ||
237 | # CONFIG_INSTALL is not set | ||
238 | # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set | ||
239 | CONFIG_LN=y | ||
240 | CONFIG_LOGNAME=y | ||
241 | CONFIG_LS=y | ||
242 | CONFIG_FEATURE_LS_FILETYPES=y | ||
243 | CONFIG_FEATURE_LS_FOLLOWLINKS=y | ||
244 | CONFIG_FEATURE_LS_RECURSIVE=y | ||
245 | CONFIG_FEATURE_LS_SORTFILES=y | ||
246 | CONFIG_FEATURE_LS_TIMESTAMPS=y | ||
247 | CONFIG_FEATURE_LS_USERNAME=y | ||
248 | CONFIG_FEATURE_LS_COLOR=y | ||
249 | CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y | ||
250 | CONFIG_MD5SUM=y | ||
251 | CONFIG_SHA1SUM=y | ||
252 | CONFIG_SHA256SUM=y | ||
253 | CONFIG_SHA512SUM=y | ||
254 | CONFIG_SHA3SUM=y | ||
255 | |||
256 | # | ||
257 | # Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum | ||
258 | # | ||
259 | CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y | ||
260 | CONFIG_MKDIR=y | ||
261 | CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y | ||
262 | # CONFIG_MKFIFO is not set | ||
263 | # CONFIG_MKNOD is not set | ||
264 | CONFIG_MV=y | ||
265 | CONFIG_FEATURE_MV_LONG_OPTIONS=y | ||
266 | # CONFIG_NICE is not set | ||
267 | # CONFIG_NOHUP is not set | ||
268 | CONFIG_OD=y | ||
269 | CONFIG_PRINTENV=y | ||
270 | CONFIG_PRINTF=y | ||
271 | CONFIG_PWD=y | ||
272 | # CONFIG_READLINK is not set | ||
273 | # CONFIG_FEATURE_READLINK_FOLLOW is not set | ||
274 | # CONFIG_REALPATH is not set | ||
275 | CONFIG_RM=y | ||
276 | CONFIG_RMDIR=y | ||
277 | CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y | ||
278 | CONFIG_SEQ=y | ||
279 | CONFIG_SHUF=y | ||
280 | CONFIG_SLEEP=y | ||
281 | CONFIG_FEATURE_FANCY_SLEEP=y | ||
282 | # CONFIG_FEATURE_FLOAT_SLEEP is not set | ||
283 | CONFIG_SORT=y | ||
284 | CONFIG_FEATURE_SORT_BIG=y | ||
285 | CONFIG_SPLIT=y | ||
286 | CONFIG_FEATURE_SPLIT_FANCY=y | ||
287 | CONFIG_STAT=y | ||
288 | CONFIG_FEATURE_STAT_FORMAT=y | ||
289 | CONFIG_FEATURE_STAT_FILESYSTEM=y | ||
290 | # CONFIG_STTY is not set | ||
291 | CONFIG_SUM=y | ||
292 | # CONFIG_SYNC is not set | ||
293 | # CONFIG_FEATURE_SYNC_FANCY is not set | ||
294 | CONFIG_TAC=y | ||
295 | CONFIG_TAIL=y | ||
296 | CONFIG_FEATURE_FANCY_TAIL=y | ||
297 | CONFIG_TEE=y | ||
298 | CONFIG_FEATURE_TEE_USE_BLOCK_IO=y | ||
299 | CONFIG_TEST=y | ||
300 | CONFIG_TEST1=y | ||
301 | CONFIG_TEST2=y | ||
302 | CONFIG_FEATURE_TEST_64=y | ||
303 | CONFIG_TOUCH=y | ||
304 | # CONFIG_FEATURE_TOUCH_NODEREF is not set | ||
305 | CONFIG_FEATURE_TOUCH_SUSV3=y | ||
306 | CONFIG_TR=y | ||
307 | CONFIG_FEATURE_TR_CLASSES=y | ||
308 | CONFIG_FEATURE_TR_EQUIV=y | ||
309 | CONFIG_TRUE=y | ||
310 | CONFIG_TRUNCATE=y | ||
311 | # CONFIG_TTY is not set | ||
312 | CONFIG_UNAME=y | ||
313 | CONFIG_UNAME_OSNAME="MS/Windows" | ||
314 | CONFIG_UNIQ=y | ||
315 | CONFIG_UNLINK=y | ||
316 | CONFIG_USLEEP=y | ||
317 | CONFIG_UUDECODE=y | ||
318 | CONFIG_BASE64=y | ||
319 | CONFIG_UUENCODE=y | ||
320 | CONFIG_WC=y | ||
321 | CONFIG_FEATURE_WC_LARGE=y | ||
322 | CONFIG_WHOAMI=y | ||
323 | # CONFIG_WHO is not set | ||
324 | # CONFIG_USERS is not set | ||
325 | CONFIG_YES=y | ||
326 | |||
327 | # | ||
328 | # Common options | ||
329 | # | ||
330 | CONFIG_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 | # | ||
340 | CONFIG_FEATURE_AUTOWIDTH=y | ||
341 | |||
342 | # | ||
343 | # Common options for df, du, ls | ||
344 | # | ||
345 | CONFIG_FEATURE_HUMAN_READABLE=y | ||
346 | |||
347 | # | ||
348 | # Console Utilities | ||
349 | # | ||
350 | # CONFIG_CHVT is not set | ||
351 | CONFIG_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 | ||
359 | CONFIG_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 | # | ||
376 | CONFIG_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 | ||
384 | CONFIG_WHICH=y | ||
385 | |||
386 | # | ||
387 | # Editors | ||
388 | # | ||
389 | CONFIG_AWK=y | ||
390 | CONFIG_FEATURE_AWK_LIBM=y | ||
391 | CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y | ||
392 | CONFIG_CMP=y | ||
393 | CONFIG_DIFF=y | ||
394 | CONFIG_FEATURE_DIFF_LONG_OPTIONS=y | ||
395 | CONFIG_FEATURE_DIFF_DIR=y | ||
396 | CONFIG_ED=y | ||
397 | CONFIG_PATCH=y | ||
398 | CONFIG_SED=y | ||
399 | CONFIG_VI=y | ||
400 | CONFIG_FEATURE_VI_MAX_LEN=4096 | ||
401 | CONFIG_FEATURE_VI_8BIT=y | ||
402 | CONFIG_FEATURE_VI_COLON=y | ||
403 | CONFIG_FEATURE_VI_YANKMARK=y | ||
404 | CONFIG_FEATURE_VI_SEARCH=y | ||
405 | # CONFIG_FEATURE_VI_REGEX_SEARCH is not set | ||
406 | # CONFIG_FEATURE_VI_USE_SIGNALS is not set | ||
407 | CONFIG_FEATURE_VI_DOT_CMD=y | ||
408 | CONFIG_FEATURE_VI_READONLY=y | ||
409 | CONFIG_FEATURE_VI_SETOPTS=y | ||
410 | CONFIG_FEATURE_VI_SET=y | ||
411 | CONFIG_FEATURE_VI_WIN_RESIZE=y | ||
412 | CONFIG_FEATURE_VI_ASK_TERMINAL=y | ||
413 | CONFIG_FEATURE_VI_UNDO=y | ||
414 | CONFIG_FEATURE_VI_UNDO_QUEUE=y | ||
415 | CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 | ||
416 | CONFIG_FEATURE_ALLOW_EXEC=y | ||
417 | |||
418 | # | ||
419 | # Finding Utilities | ||
420 | # | ||
421 | CONFIG_FIND=y | ||
422 | CONFIG_FEATURE_FIND_PRINT0=y | ||
423 | CONFIG_FEATURE_FIND_MTIME=y | ||
424 | CONFIG_FEATURE_FIND_MMIN=y | ||
425 | CONFIG_FEATURE_FIND_PERM=y | ||
426 | CONFIG_FEATURE_FIND_TYPE=y | ||
427 | # CONFIG_FEATURE_FIND_XDEV is not set | ||
428 | CONFIG_FEATURE_FIND_MAXDEPTH=y | ||
429 | CONFIG_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 | ||
435 | CONFIG_FEATURE_FIND_NOT=y | ||
436 | CONFIG_FEATURE_FIND_DEPTH=y | ||
437 | CONFIG_FEATURE_FIND_PAREN=y | ||
438 | CONFIG_FEATURE_FIND_SIZE=y | ||
439 | CONFIG_FEATURE_FIND_PRUNE=y | ||
440 | CONFIG_FEATURE_FIND_DELETE=y | ||
441 | CONFIG_FEATURE_FIND_PATH=y | ||
442 | CONFIG_FEATURE_FIND_REGEX=y | ||
443 | # CONFIG_FEATURE_FIND_CONTEXT is not set | ||
444 | # CONFIG_FEATURE_FIND_LINKS is not set | ||
445 | CONFIG_GREP=y | ||
446 | CONFIG_EGREP=y | ||
447 | CONFIG_FGREP=y | ||
448 | CONFIG_FEATURE_GREP_CONTEXT=y | ||
449 | CONFIG_XARGS=y | ||
450 | CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y | ||
451 | CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y | ||
452 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y | ||
453 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y | ||
454 | CONFIG_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 | ||
466 | CONFIG_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 | ||
471 | CONFIG_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 | ||
476 | CONFIG_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 | ||
497 | CONFIG_LAST_ID=0 | ||
498 | CONFIG_FIRST_SYSTEM_ID=0 | ||
499 | CONFIG_LAST_SYSTEM_ID=0 | ||
500 | # CONFIG_CHPASSWD is not set | ||
501 | CONFIG_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 | ||
557 | CONFIG_DEFAULT_MODULES_DIR="" | ||
558 | CONFIG_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 | ||
591 | CONFIG_GETOPT=y | ||
592 | CONFIG_FEATURE_GETOPT_LONG=y | ||
593 | CONFIG_HEXDUMP=y | ||
594 | CONFIG_FEATURE_HEXDUMP_REVERSE=y | ||
595 | CONFIG_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 | ||
636 | CONFIG_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 | ||
687 | CONFIG_FEATURE_BEEP_FREQ=0 | ||
688 | CONFIG_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 | ||
702 | CONFIG_FEATURE_CROND_DIR="" | ||
703 | # CONFIG_CRONTAB is not set | ||
704 | CONFIG_DC=y | ||
705 | CONFIG_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 | ||
734 | CONFIG_LESS=y | ||
735 | CONFIG_FEATURE_LESS_MAXLINES=9999999 | ||
736 | CONFIG_FEATURE_LESS_BRACKETS=y | ||
737 | CONFIG_FEATURE_LESS_FLAGS=y | ||
738 | CONFIG_FEATURE_LESS_TRUNCATE=y | ||
739 | CONFIG_FEATURE_LESS_MARKS=y | ||
740 | CONFIG_FEATURE_LESS_REGEXP=y | ||
741 | # CONFIG_FEATURE_LESS_WINCH is not set | ||
742 | # CONFIG_FEATURE_LESS_ASK_TERMINAL is not set | ||
743 | CONFIG_FEATURE_LESS_DASHCMD=y | ||
744 | CONFIG_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 | ||
748 | CONFIG_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 | ||
761 | CONFIG_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 | # | ||
781 | CONFIG_FEATURE_IPV6=y | ||
782 | # CONFIG_FEATURE_UNIX_LOCAL is not set | ||
783 | CONFIG_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 | ||
796 | CONFIG_FTPGET=y | ||
797 | CONFIG_FTPPUT=y | ||
798 | CONFIG_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 | ||
823 | CONFIG_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 | ||
842 | CONFIG_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 | ||
854 | CONFIG_IPCALC=y | ||
855 | CONFIG_FEATURE_IPCALC_FANCY=y | ||
856 | CONFIG_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 | ||
861 | CONFIG_NC=y | ||
862 | CONFIG_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 | ||
900 | CONFIG_WGET=y | ||
901 | # CONFIG_FEATURE_WGET_STATUSBAR is not set | ||
902 | # CONFIG_FEATURE_WGET_AUTHENTICATION is not set | ||
903 | CONFIG_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 | ||
907 | CONFIG_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 | ||
915 | CONFIG_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 | ||
920 | CONFIG_UDHCP_DEBUG=0 | ||
921 | # CONFIG_FEATURE_UDHCP_RFC3397 is not set | ||
922 | # CONFIG_FEATURE_UDHCP_8021Q is not set | ||
923 | CONFIG_UDHCPC_DEFAULT_SCRIPT="" | ||
924 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 | ||
925 | CONFIG_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 | ||
943 | CONFIG_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 | ||
951 | CONFIG_KILL=y | ||
952 | CONFIG_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 | ||
957 | CONFIG_PGREP=y | ||
958 | # CONFIG_PKILL is not set | ||
959 | CONFIG_PIDOF=y | ||
960 | CONFIG_FEATURE_PIDOF_SINGLE=y | ||
961 | CONFIG_FEATURE_PIDOF_OMIT=y | ||
962 | # CONFIG_PMAP is not set | ||
963 | # CONFIG_POWERTOP is not set | ||
964 | CONFIG_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 | ||
999 | CONFIG_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 | # | ||
1021 | CONFIG_ASH=y | ||
1022 | CONFIG_ASH_OPTIMIZE_FOR_SIZE=y | ||
1023 | CONFIG_ASH_INTERNAL_GLOB=y | ||
1024 | CONFIG_ASH_RANDOM_SUPPORT=y | ||
1025 | CONFIG_ASH_EXPAND_PRMT=y | ||
1026 | CONFIG_ASH_BASH_COMPAT=y | ||
1027 | # CONFIG_ASH_IDLE_TIMEOUT is not set | ||
1028 | # CONFIG_ASH_JOB_CONTROL is not set | ||
1029 | CONFIG_ASH_ALIAS=y | ||
1030 | CONFIG_ASH_GETOPTS=y | ||
1031 | CONFIG_ASH_BUILTIN_ECHO=y | ||
1032 | CONFIG_ASH_BUILTIN_PRINTF=y | ||
1033 | CONFIG_ASH_BUILTIN_TEST=y | ||
1034 | CONFIG_ASH_HELP=y | ||
1035 | CONFIG_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 | ||
1055 | CONFIG_FEATURE_SH_IS_ASH=y | ||
1056 | # CONFIG_FEATURE_SH_IS_HUSH is not set | ||
1057 | # CONFIG_FEATURE_SH_IS_NONE is not set | ||
1058 | CONFIG_FEATURE_BASH_IS_ASH=y | ||
1059 | # CONFIG_FEATURE_BASH_IS_HUSH is not set | ||
1060 | # CONFIG_FEATURE_BASH_IS_NONE is not set | ||
1061 | CONFIG_SH_MATH_SUPPORT=y | ||
1062 | CONFIG_SH_MATH_SUPPORT_64=y | ||
1063 | CONFIG_FEATURE_SH_EXTRA_QUIET=y | ||
1064 | CONFIG_FEATURE_SH_STANDALONE=y | ||
1065 | CONFIG_FEATURE_SH_NOFORK=y | ||
1066 | CONFIG_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 | ||
1081 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 | ||
1082 | # CONFIG_FEATURE_IPC_SYSLOG is not set | ||
1083 | CONFIG_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 | ||
104 | enum size_spec { | 111 | enum 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]) | |||
781 | out: | 794 | out: |
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 | ||
2802 | static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready | 2802 | static 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) | |||
2961 | static int file_write(char *fn, char *first, char *last) | 2990 | static 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 ----------------------- |
3027 | static void clear_to_eos(void) | 3074 | static 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 | |||
175 | struct globals { | 183 | struct 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 | |||
5 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | 15 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
6 | 16 | ||
7 | enum { | 17 | enum { |
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 | ||
169 | extern char **environ; | 176 | extern char **environ; |
177 | #endif | ||
170 | #if defined(__GLIBC__) && __GLIBC__ < 2 | 178 | #if defined(__GLIBC__) && __GLIBC__ < 2 |
171 | int vdprintf(int d, const char *format, va_list ap); | 179 | int 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 | ||
493 | void bb_signals(int sigs, void (*f)(int)) FAST_FUNC; | 505 | void 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; | |||
507 | int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC; | 519 | int sigaction_set(int sig, const struct sigaction *act) FAST_FUNC; |
508 | /* SIG_BLOCK/SIG_UNBLOCK all signals: */ | 520 | /* SIG_BLOCK/SIG_UNBLOCK all signals: */ |
509 | int sigprocmask_allsigs(int how) FAST_FUNC; | 521 | int 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 */ |
511 | extern smallint bb_got_signal; | 527 | extern smallint bb_got_signal; |
512 | void record_signo(int signo); /* not FAST_FUNC! */ | 528 | void record_signo(int signo); /* not FAST_FUNC! */ |
@@ -586,7 +602,7 @@ char *strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC; | |||
586 | int xsocket(int domain, int type, int protocol) FAST_FUNC; | 602 | int xsocket(int domain, int type, int protocol) FAST_FUNC; |
587 | void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; | 603 | void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; |
588 | void xlisten(int s, int backlog) FAST_FUNC; | 604 | void xlisten(int s, int backlog) FAST_FUNC; |
589 | void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) FAST_FUNC; | 605 | void xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen) FAST_FUNC; |
590 | ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, | 606 | ssize_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; | |||
890 | char* str_tolower(char *str) FAST_FUNC; | 906 | char* str_tolower(char *str) FAST_FUNC; |
891 | 907 | ||
892 | char *utoa(unsigned n) FAST_FUNC; | 908 | char *utoa(unsigned n) FAST_FUNC; |
909 | #if ENABLE_PLATFORM_MINGW32 | ||
910 | # define itoa bb_itoa | ||
911 | #endif | ||
893 | char *itoa(int n) FAST_FUNC; | 912 | char *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 */ |
895 | char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; | 914 | char *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 */ |
1669 | enum { | 1691 | enum { |
@@ -1702,7 +1724,11 @@ void free_procps_scan(procps_status_t* sp) FAST_FUNC; | |||
1702 | procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; | 1724 | procps_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 | ||
1705 | void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; | 1728 | void 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 | ||
1706 | pid_t *find_pid_by_name(const char* procName) FAST_FUNC; | 1732 | pid_t *find_pid_by_name(const char* procName) FAST_FUNC; |
1707 | pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; | 1733 | pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; |
1708 | int starts_with_cpu(const char *str) FAST_FUNC; | 1734 | int 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 | ||
1845 | extern const char bb_busybox_exec_path[] ALIGN1; | 1874 | extern 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 */ |
1848 | extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ | 1878 | extern 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 | */ | ||
8 | typedef int gid_t; | ||
9 | typedef int uid_t; | ||
10 | #ifndef _WIN64 | ||
11 | typedef int pid_t; | ||
12 | #else | ||
13 | typedef __int64 pid_t; | ||
14 | #endif | ||
15 | |||
16 | #define DEFAULT_UID 1000 | ||
17 | #define DEFAULT_GID 1000 | ||
18 | |||
19 | /* | ||
20 | * arpa/inet.h | ||
21 | */ | ||
22 | static inline unsigned int git_ntohl(unsigned int x) { return (unsigned int)ntohl(x); } | ||
23 | #define ntohl git_ntohl | ||
24 | int inet_aton(const char *cp, struct in_addr *inp); | ||
25 | int 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 | |||
42 | struct group { | ||
43 | char *gr_name; | ||
44 | char *gr_passwd; | ||
45 | gid_t gr_gid; | ||
46 | char **gr_mem; | ||
47 | }; | ||
48 | IMPL(getgrnam,struct group *,NULL,const char *name UNUSED_PARAM); | ||
49 | struct group *getgrgid(gid_t gid); | ||
50 | NOIMPL(initgroups,const char *group UNUSED_PARAM,gid_t gid UNUSED_PARAM); | ||
51 | static inline void endgrent(void) {} | ||
52 | int 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 | |||
64 | typedef int sa_family_t; | ||
65 | |||
66 | /* | ||
67 | * linux/un.h | ||
68 | */ | ||
69 | struct 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 | */ | ||
77 | struct 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 | |||
87 | struct passwd *getpwnam(const char *name); | ||
88 | struct passwd *getpwuid(uid_t uid); | ||
89 | static inline void setpwent(void) {} | ||
90 | static inline void endpwent(void) {} | ||
91 | IMPL(getpwent_r,int,ENOENT,struct passwd *pwbuf UNUSED_PARAM,char *buf UNUSED_PARAM,size_t buflen UNUSED_PARAM,struct passwd **pwbufp UNUSED_PARAM); | ||
92 | IMPL(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 | |||
117 | typedef void (__cdecl *sighandler_t)(int); | ||
118 | struct 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 | |||
126 | NOIMPL(sigaction,int sig UNUSED_PARAM, struct sigaction *in UNUSED_PARAM, struct sigaction *out UNUSED_PARAM); | ||
127 | NOIMPL(sigfillset,int *mask UNUSED_PARAM); | ||
128 | NOIMPL(FAST_FUNC sigprocmask_allsigs, int how UNUSED_PARAM); | ||
129 | NOIMPL(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 | |||
137 | int fdprintf(int fd, const char *format, ...); | ||
138 | FILE* mingw_fopen(const char *filename, const char *mode); | ||
139 | int mingw_rename(const char*, const char*); | ||
140 | #define fopen mingw_fopen | ||
141 | #define rename mingw_rename | ||
142 | |||
143 | FILE *mingw_popen(const char *cmd, const char *mode); | ||
144 | int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid); | ||
145 | int 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 | |||
157 | void move_cursor_row(int n); | ||
158 | void reset_screen(void); | ||
159 | int winansi_putchar(int c); | ||
160 | int winansi_puts(const char *s); | ||
161 | size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); | ||
162 | int winansi_fputs(const char *str, FILE *stream); | ||
163 | int winansi_vfprintf(FILE *stream, const char *format, va_list list); | ||
164 | int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); | ||
165 | int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); | ||
166 | int winansi_write(int fd, const void *buf, size_t count); | ||
167 | int winansi_read(int fd, void *buf, size_t count); | ||
168 | int 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 | |||
180 | int 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 | |||
191 | int mingw_system(const char *cmd); | ||
192 | #define system mingw_system | ||
193 | |||
194 | int clearenv(void); | ||
195 | char *mingw_getenv(const char *name); | ||
196 | int mingw_putenv(const char *env); | ||
197 | char *mingw_mktemp(char *template); | ||
198 | int mkstemp(char *template); | ||
199 | char *realpath(const char *path, char *resolved_path); | ||
200 | int setenv(const char *name, const char *value, int replace); | ||
201 | #if ENABLE_SAFE_ENV | ||
202 | int unsetenv(const char *env); | ||
203 | #else | ||
204 | void 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 | */ | ||
216 | void *mempcpy(void *dest, const void *src, size_t n); | ||
217 | |||
218 | /* | ||
219 | * strings.h | ||
220 | */ | ||
221 | int ffs(int i); | ||
222 | |||
223 | /* | ||
224 | * sys/ioctl.h | ||
225 | */ | ||
226 | |||
227 | #define TIOCGWINSZ 0x5413 | ||
228 | |||
229 | int ioctl(int fd, int code, ...); | ||
230 | |||
231 | /* | ||
232 | * sys/socket.h | ||
233 | */ | ||
234 | #define hstrerror strerror | ||
235 | |||
236 | #define SHUT_WR SD_SEND | ||
237 | |||
238 | int mingw_socket(int domain, int type, int protocol); | ||
239 | int mingw_connect(int sockfd, const struct sockaddr *sa, size_t sz); | ||
240 | int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz); | ||
241 | int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen); | ||
242 | int mingw_shutdown(int sockfd, int how); | ||
243 | int mingw_listen(int sockfd, int backlog); | ||
244 | int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz); | ||
245 | int mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds, | ||
246 | struct timeval *timeout); | ||
247 | |||
248 | NOIMPL(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 | |||
284 | IMPL(fchmod,int,0,int fildes UNUSED_PARAM, mode_t mode UNUSED_PARAM); | ||
285 | NOIMPL(fchown,int fd UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM); | ||
286 | int mingw_mkdir(const char *path, int mode); | ||
287 | int 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 | |||
296 | typedef int nlink_t; | ||
297 | typedef int blksize_t; | ||
298 | typedef off_t blkcnt_t; | ||
299 | |||
300 | struct 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 | |||
316 | int mingw_lstat(const char *file_name, struct mingw_stat *buf); | ||
317 | int mingw_stat(const char *file_name, struct mingw_stat *buf); | ||
318 | int 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 | ||
338 | struct 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 | ||
349 | int waitpid(pid_t pid, int *status, int options); | ||
350 | |||
351 | /* | ||
352 | * time.h | ||
353 | */ | ||
354 | struct tm *gmtime_r(const time_t *timep, struct tm *result); | ||
355 | struct tm *localtime_r(const time_t *timep, struct tm *result); | ||
356 | char *strptime(const char *s, const char *format, struct tm *tm); | ||
357 | size_t mingw_strftime(char *buf, size_t max, const char *format, const struct tm *tm); | ||
358 | int stime(time_t *t); | ||
359 | |||
360 | #define strftime mingw_strftime | ||
361 | |||
362 | /* | ||
363 | * times.h | ||
364 | */ | ||
365 | #define clock_t long | ||
366 | |||
367 | struct 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 | |||
374 | clock_t times(struct tms *buf); | ||
375 | |||
376 | /* | ||
377 | * unistd.h | ||
378 | */ | ||
379 | #define PIPE_BUF 8192 | ||
380 | |||
381 | #define _SC_CLK_TCK 2 | ||
382 | |||
383 | IMPL(alarm,unsigned int,0,unsigned int seconds UNUSED_PARAM); | ||
384 | IMPL(chown,int,0,const char *path UNUSED_PARAM, uid_t uid UNUSED_PARAM, gid_t gid UNUSED_PARAM); | ||
385 | NOIMPL(chroot,const char *root UNUSED_PARAM); | ||
386 | NOIMPL(fchdir,int fd UNUSED_PARAM); | ||
387 | int mingw_dup2 (int fd, int fdto); | ||
388 | char *mingw_getcwd(char *pointer, int len); | ||
389 | off_t mingw_lseek(int fd, off_t offset, int whence); | ||
390 | |||
391 | |||
392 | IMPL(getgid,int,DEFAULT_GID,void); | ||
393 | int getgroups(int n, gid_t *groups); | ||
394 | IMPL(getppid,int,1,void); | ||
395 | IMPL(getegid,int,DEFAULT_GID,void); | ||
396 | IMPL(geteuid,int,DEFAULT_UID,void); | ||
397 | NOIMPL(getsid,pid_t pid UNUSED_PARAM); | ||
398 | IMPL(getuid,int,DEFAULT_UID,void); | ||
399 | int getlogin_r(char *buf, size_t len); | ||
400 | int fcntl(int fd, int cmd, ...); | ||
401 | #define fork() -1 | ||
402 | IMPL(fsync,int,0,int fd UNUSED_PARAM); | ||
403 | int kill(pid_t pid, int sig); | ||
404 | int link(const char *oldpath, const char *newpath); | ||
405 | NOIMPL(mknod,const char *name UNUSED_PARAM, mode_t mode UNUSED_PARAM, dev_t device UNUSED_PARAM); | ||
406 | int mingw_open (const char *filename, int oflags, ...); | ||
407 | int pipe(int filedes[2]); | ||
408 | NOIMPL(readlink,const char *path UNUSED_PARAM, char *buf UNUSED_PARAM, size_t bufsiz UNUSED_PARAM); | ||
409 | NOIMPL(setgid,gid_t gid UNUSED_PARAM); | ||
410 | NOIMPL(setegid,gid_t gid UNUSED_PARAM); | ||
411 | NOIMPL(setsid,void); | ||
412 | NOIMPL(setuid,uid_t gid UNUSED_PARAM); | ||
413 | NOIMPL(seteuid,uid_t gid UNUSED_PARAM); | ||
414 | unsigned int sleep(unsigned int seconds); | ||
415 | NOIMPL(symlink,const char *oldpath UNUSED_PARAM, const char *newpath UNUSED_PARAM); | ||
416 | static inline void sync(void) {} | ||
417 | long sysconf(int name); | ||
418 | NOIMPL(ttyname_r,int fd UNUSED_PARAM, char *buf UNUSED_PARAM, int sz UNUSED_PARAM); | ||
419 | int mingw_unlink(const char *pathname); | ||
420 | NOIMPL(vfork,void); | ||
421 | int mingw_access(const char *name, int mode); | ||
422 | int 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 | */ | ||
439 | int utimes(const char *file_name, const struct timeval times[2]); | ||
440 | |||
441 | /* | ||
442 | * dirent.h | ||
443 | */ | ||
444 | DIR *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 | |||
455 | pid_t FAST_FUNC mingw_spawn(char **argv); | ||
456 | intptr_t FAST_FUNC mingw_spawn_proc(char **argv); | ||
457 | int mingw_execv(const char *cmd, const char *const *argv); | ||
458 | int mingw_execvp(const char *cmd, const char *const *argv); | ||
459 | int 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 | |||
465 | const 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 | |||
473 | char **copy_environ(const char *const *env); | ||
474 | void free_environ(char **env); | ||
475 | char **env_setenv(char **env, const char *name); | ||
476 | |||
477 | const char *get_busybox_exec_path(void); | ||
478 | void init_winsock(void); | ||
479 | |||
480 | char *file_is_win32_executable(const char *p); | ||
481 | |||
482 | int 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> | ||
514 | extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC; | 551 | extern 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> | ||
573 | extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC; | 611 | extern 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 | |||
37 | lib-y += find_pid_by_name.o | 37 | lib-y += find_pid_by_name.o |
38 | lib-y += find_root_device.o | 38 | lib-y += find_root_device.o |
39 | lib-y += full_write.o | 39 | lib-y += full_write.o |
40 | lib-y += get_console.o | ||
41 | lib-y += get_last_path_component.o | 40 | lib-y += get_last_path_component.o |
42 | lib-y += get_line_from_file.o | 41 | lib-y += get_line_from_file.o |
43 | lib-y += getopt32.o | 42 | lib-y += getopt32.o |
44 | lib-y += getpty.o | ||
45 | lib-y += get_volsize.o | 43 | lib-y += get_volsize.o |
46 | lib-y += herror_msg.o | 44 | lib-y += herror_msg.o |
47 | lib-y += human_readable.o | 45 | lib-y += human_readable.o |
48 | lib-y += inet_common.o | 46 | lib-y += inet_common.o |
49 | lib-y += inode_hash.o | 47 | lib-y += inode_hash.o |
50 | lib-y += isdirectory.o | 48 | lib-y += isdirectory.o |
51 | lib-y += kernel_version.o | ||
52 | lib-y += last_char_is.o | 49 | lib-y += last_char_is.o |
53 | lib-y += lineedit.o lineedit_ptr_hack.o | 50 | lib-y += lineedit.o lineedit_ptr_hack.o |
54 | lib-y += llist.o | 51 | lib-y += llist.o |
55 | lib-y += login.o | ||
56 | lib-y += make_directory.o | 52 | lib-y += make_directory.o |
57 | lib-y += makedev.o | ||
58 | lib-y += hash_md5_sha.o | 53 | lib-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 | |||
75 | lib-y += ptr_to_globals.o | 70 | lib-y += ptr_to_globals.o |
76 | lib-y += read.o | 71 | lib-y += read.o |
77 | lib-y += read_printf.o | 72 | lib-y += read_printf.o |
78 | lib-y += read_key.o | ||
79 | lib-y += recursive_action.o | 73 | lib-y += recursive_action.o |
80 | lib-y += remove_file.o | 74 | lib-y += remove_file.o |
81 | lib-y += run_shell.o | 75 | lib-y += run_shell.o |
@@ -84,7 +78,6 @@ lib-y += safe_poll.o | |||
84 | lib-y += safe_strncpy.o | 78 | lib-y += safe_strncpy.o |
85 | lib-y += safe_write.o | 79 | lib-y += safe_write.o |
86 | lib-y += setup_environment.o | 80 | lib-y += setup_environment.o |
87 | lib-y += signals.o | ||
88 | lib-y += simplify_path.o | 81 | lib-y += simplify_path.o |
89 | lib-y += single_argv.o | 82 | lib-y += single_argv.o |
90 | lib-y += skip_whitespace.o | 83 | lib-y += skip_whitespace.o |
@@ -109,10 +102,20 @@ lib-y += xfuncs.o | |||
109 | lib-y += xfuncs_printf.o | 102 | lib-y += xfuncs_printf.o |
110 | lib-y += xfunc_die.o | 103 | lib-y += xfunc_die.o |
111 | lib-y += xgetcwd.o | 104 | lib-y += xgetcwd.o |
112 | lib-y += xgethostbyname.o | ||
113 | lib-y += xreadlink.o | 105 | lib-y += xreadlink.o |
114 | lib-y += xrealloc_vector.o | 106 | lib-y += xrealloc_vector.o |
115 | 107 | ||
108 | lib-$(CONFIG_PLATFORM_POSIX) += get_console.o | ||
109 | lib-$(CONFIG_PLATFORM_POSIX) += getpty.o | ||
110 | lib-$(CONFIG_PLATFORM_POSIX) += inet_common.o | ||
111 | lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o | ||
112 | lib-$(CONFIG_PLATFORM_POSIX) += login.o | ||
113 | lib-$(CONFIG_PLATFORM_POSIX) += makedev.o | ||
114 | lib-$(CONFIG_PLATFORM_POSIX) += read_key.o | ||
115 | lib-$(CONFIG_PLATFORM_POSIX) += signals.o | ||
116 | lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o | ||
117 | lib-$(CONFIG_PLATFORM_POSIX) += xgethostbyname.o | ||
118 | |||
116 | lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o | 119 | lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o |
117 | 120 | ||
118 | lib-$(CONFIG_FEATURE_UTMP) += utmp.o | 121 | lib-$(CONFIG_FEATURE_UTMP) += utmp.o |
@@ -124,7 +127,7 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o | |||
124 | lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o | 127 | lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o |
125 | lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o | 128 | lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o |
126 | 129 | ||
127 | lib-$(CONFIG_NC) += udp_io.o | 130 | lib-$(CONFIG_NC_110_COMPAT) += udp_io.o |
128 | lib-$(CONFIG_DNSD) += udp_io.o | 131 | lib-$(CONFIG_DNSD) += udp_io.o |
129 | lib-$(CONFIG_NTPD) += udp_io.o | 132 | lib-$(CONFIG_NTPD) += udp_io.o |
130 | lib-$(CONFIG_TFTP) += udp_io.o | 133 | lib-$(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 | ||
63 | static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; | 63 | static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; |
64 | #define BB_ARCHIVE_PUBLIC | ||
64 | # include "bb_archive.h" | 65 | # include "bb_archive.h" |
65 | static const char *unpack_usage_messages(void) | 66 | static 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 | ||
659 | static const char usr_bin [] ALIGN1 = "/usr/bin/"; | 665 | static const char usr_bin [] ALIGN1 = "/usr/bin/"; |
660 | static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; | 666 | static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; |
661 | static const char *const install_dir[] = { | 667 | static 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 */ | ||
710 | static 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 |
704 | static void install_links(const char *busybox UNUSED_PARAM, | 733 | static 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 | |||
31 | char* FAST_FUNC find_executable(const char *filename, char **PATHp) | 35 | char* 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 */ |
60 | void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) | 60 | void 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 |
358 | static void put_cur_glyph_and_inc_cursor(void) | 358 | static 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 | ||
421 | static 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) */ |
421 | static void put_till_end_and_adv_cursor(void) | 457 | static 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) | |||
610 | static void input_forward(void) | 648 | static 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 | ||
684 | static 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 | ||
36 | const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; | 36 | const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; |
37 | 37 | ||
38 | #if !ENABLE_PLATFORM_MINGW32 | ||
38 | const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; | 39 | const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; |
40 | #endif | ||
39 | const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; | 41 | const 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 | ||
34 | static void xsetenv_if_unset(const char *key, const char *value) | ||
35 | { | ||
36 | if (!getenv(key)) | ||
37 | xsetenv(key, value); | ||
38 | } | ||
39 | #endif | ||
40 | |||
33 | void FAST_FUNC setup_environment(const char *shell, int flags, const struct passwd *pw) | 41 | void 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. */ |
22 | pid_t FAST_FUNC spawn(char **argv) | 23 | pid_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. */ |
63 | pid_t FAST_FUNC xspawn(char **argv) | 65 | pid_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 | ||
101 | void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) | 101 | void 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 | ||
1053 | static int64_t getch_nowait(void) | 1085 | static 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 | ||
1147 | static int64_t getch_nowait(void) | ||
1148 | { | ||
1149 | int64_t c; | ||
1150 | |||
1151 | retry: | ||
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) | |||
1766 | int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1838 | int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1767 | int less_main(int argc, char **argv) | 1839 | int 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 | ||
293 | static void func_user(char *buf, int size, const procps_status_t *ps) | 294 | static 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 | ||
317 | static void func_comm(char *buf, int size, const procps_status_t *ps) | 319 | static 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 | ||
322 | static void func_state(char *buf, int size, const procps_status_t *ps) | 325 | static 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 | ||
332 | static void func_pid(char *buf, int size, const procps_status_t *ps) | 336 | static 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 | ||
337 | static void func_ppid(char *buf, int size, const procps_status_t *ps) | 342 | static 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 | ||
441 | static const ps_out_t out_spec[] = { | 447 | static 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 | ||
25 | struct fileblock { | 26 | struct 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 | ||
135 | void *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 | } | ||
170 | void munmap(void *p, size_t size UNUSED) | ||
171 | { | ||
172 | free(p); | ||
173 | } | ||
174 | #endif | ||
175 | |||
125 | char *target; | 176 | char *target; |
126 | char *depfile; | 177 | char *depfile; |
127 | char *cmdline; | 178 | char *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 | ||
254 | union node; | ||
255 | struct strlist; | ||
256 | struct job; | ||
257 | |||
258 | struct 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 | |||
282 | enum { | ||
283 | FS_OPENHERE, | ||
284 | FS_EVALBACKCMD, | ||
285 | FS_EVALSUBSHELL, | ||
286 | FS_EVALPIPE, | ||
287 | FS_SHELLEXEC | ||
288 | }; | ||
289 | |||
290 | static struct forkshell* forkshell_prepare(struct forkshell *fs); | ||
291 | static void forkshell_init(const char *idstr); | ||
292 | static void forkshell_child(struct forkshell *fs); | ||
293 | static void sticky_free(void *p); | ||
294 | #define free(p) sticky_free(p) | ||
295 | static 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) | |||
2512 | static const char * | 2604 | static const char * |
2513 | updatepwd(const char *dir) | 2605 | updatepwd(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 | */ |
3371 | struct procstat { | 3564 | struct 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 | ||
3399 | static struct job *makejob(/*union node *,*/ int); | 3595 | static struct job *makejob(/*union node *,*/ int); |
3596 | #if !ENABLE_PLATFORM_MINGW32 | ||
3400 | static int forkshell(struct job *, union node *, int); | 3597 | static int forkshell(struct job *, union node *, int); |
3598 | #endif | ||
3401 | static int waitforjob(struct job *); | 3599 | static 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 | |||
4178 | HANDLE hSIGINT; /* Ctrl-C is pressed */ | ||
4179 | |||
4180 | static 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 | */ | ||
4193 | static pid_t | ||
4194 | waitpid_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 | |||
3974 | static int | 4267 | static int |
3975 | wait_block_or_sig(int *status) | 4268 | wait_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 |
4900 | static void | 5201 | static void |
5202 | #if !ENABLE_PLATFORM_MINGW32 | ||
4901 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) | 5203 | forkparent(struct job *jp, union node *n, int mode, pid_t pid) |
5204 | #else | ||
5205 | forkparent(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 */ |
4940 | static int | 5252 | static int |
4941 | forkshell(struct job *jp, union node *n, int mode) | 5253 | forkshell(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 */ | 8595 | static int funcblocksize; /* size of structures in function */ |
8227 | /*static int funcstringsize; // size of strings in node */ | 8596 | static int funcstringsize; /* size of strings in node */ |
8228 | static void *funcblock; /* block to allocate function from */ | 8597 | static void *funcblock; /* block to allocate function from */ |
8229 | static char *funcstring_end; /* end of block to allocate strings from */ | 8598 | static char *funcstring; /* block to allocate strings from */ |
8599 | #if ENABLE_PLATFORM_MINGW32 | ||
8600 | static int nodeptrsize; | ||
8601 | static 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 | ||
8267 | static int calcsize(int funcblocksize, union node *n); | 8640 | static void calcsize(union node *n); |
8268 | 8641 | ||
8269 | static int | 8642 | static void |
8270 | sizenodelist(int funcblocksize, struct nodelist *lp) | 8643 | sizenodelist(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 | ||
8280 | static int | 8653 | static void |
8281 | calcsize(int funcblocksize, union node *n) | 8654 | calcsize(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 | ||
8362 | static char * | 8747 | static char * |
8363 | nodeckstrdup(char *s) | 8748 | nodeckstrdup(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 | ||
8369 | static union node *copynode(union node *); | 8759 | static 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 | |||
8371 | static struct nodelist * | 8773 | static struct nodelist * |
8372 | copynodelist(struct nodelist *lp) | 8774 | copynodelist(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) | |||
8833 | static int | 9252 | static int |
8834 | evalsubshell(union node *n, int flags) | 9253 | evalsubshell(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) | |||
8934 | static int | 9364 | static int |
8935 | evalpipe(union node *n, int flags) | 9365 | evalpipe(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 | |||
9445 | static int | 9889 | static int |
9446 | evalcommand(union node *cmd, int flags) | 9890 | evalcommand(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 | ||
13260 | static void | 13768 | static void |
13769 | #if ENABLE_PLATFORM_MINGW32 | ||
13770 | init(int xp) | ||
13771 | #else | ||
13261 | init(void) | 13772 | init(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 | ||
14186 | static void | ||
14187 | forkshell_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 | |||
14211 | static void | ||
14212 | forkshell_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 | |||
14229 | static void | ||
14230 | forkshell_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 | |||
14244 | static void | ||
14245 | forkshell_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 | |||
14268 | static void | ||
14269 | forkshell_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 | |||
14280 | static void | ||
14281 | forkshell_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 | */ | ||
14307 | static void | ||
14308 | reinitvar(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() */ | ||
14327 | static int | ||
14328 | spawn_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) \ | ||
14363 | static void \ | ||
14364 | name(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) \ | ||
14376 | static type * \ | ||
14377 | name(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 | */ | ||
14398 | SLIST_SIZE_BEGIN(var_size,struct var) | ||
14399 | funcstringsize += strlen(p->var_text) + 1; | ||
14400 | nodeptrsize++; /* p->text */ | ||
14401 | SLIST_SIZE_END() | ||
14402 | |||
14403 | SLIST_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; | ||
14411 | SAVE_PTR((*vpp)->var_text); | ||
14412 | SLIST_COPY_END() | ||
14413 | |||
14414 | /* | ||
14415 | * struct strlist | ||
14416 | */ | ||
14417 | SLIST_SIZE_BEGIN(strlist_size,struct strlist) | ||
14418 | funcstringsize += strlen(p->text) + 1; | ||
14419 | nodeptrsize++; /* p->text */ | ||
14420 | SLIST_SIZE_END() | ||
14421 | |||
14422 | SLIST_COPY_BEGIN(strlist_copy,struct strlist) | ||
14423 | (*vpp)->text = nodeckstrdup(vp->text); | ||
14424 | SAVE_PTR((*vpp)->text); | ||
14425 | SLIST_COPY_END() | ||
14426 | |||
14427 | /* | ||
14428 | * struct tblentry | ||
14429 | */ | ||
14430 | static void | ||
14431 | tblentry_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 | |||
14446 | static struct tblentry * | ||
14447 | tblentry_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 | |||
14482 | static void | ||
14483 | cmdtable_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 | |||
14492 | static struct tblentry ** | ||
14493 | cmdtable_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 | */ | ||
14509 | static void | ||
14510 | argv_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 | |||
14521 | static char ** | ||
14522 | argv_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 | */ | ||
14543 | static void | ||
14544 | redirtab_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 | |||
14553 | static struct redirtab * | ||
14554 | redirtab_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 | ||
14577 | static void | ||
14578 | globals_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 | ||
14593 | static struct globals_var * | ||
14594 | globals_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 | ||
14633 | static void | ||
14634 | globals_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 | |||
14646 | static struct globals_misc * | ||
14647 | globals_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 | |||
14662 | static void | ||
14663 | forkshell_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 | |||
14680 | static struct forkshell * | ||
14681 | forkshell_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 | |||
14702 | static struct forkshell * | ||
14703 | forkshell_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 | ||
14749 | static void *sticky_mem_start, *sticky_mem_end; | ||
14750 | static void | ||
14751 | forkshell_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 | ||
14812 | static void | ||
14813 | sticky_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 | ||
23 | const char defifsvar[] ALIGN1 = "IFS= \t\n"; | 24 | const char defifsvar[] ALIGN1 = "IFS= \t\n"; |
25 | #else | ||
26 | const char defifsvar[] ALIGN1 = "IFS= \t\n\r"; | ||
27 | #endif | ||
24 | const char defoptindvar[] ALIGN1 = "OPTIND=1"; | 28 | const 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 | ||
277 | struct limits { | 284 | struct 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 | ||
509 | int 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 */ |
34 | static void strrev(CHAR_T *s, int len) | 34 | static 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 | |||
5 | lib-y:= | ||
6 | |||
7 | lib-$(CONFIG_PLATFORM_MINGW32) += env.o | ||
8 | lib-$(CONFIG_PLATFORM_MINGW32) += fnmatch.o | ||
9 | lib-$(CONFIG_PLATFORM_MINGW32) += ioctl.o | ||
10 | lib-$(CONFIG_PLATFORM_MINGW32) += mingw.o | ||
11 | lib-$(CONFIG_PLATFORM_MINGW32) += process.o | ||
12 | lib-$(CONFIG_PLATFORM_MINGW32) += regex.o | ||
13 | lib-$(CONFIG_PLATFORM_MINGW32) += net.o | ||
14 | lib-$(CONFIG_PLATFORM_MINGW32) += inet_pton.o | ||
15 | lib-$(CONFIG_PLATFORM_MINGW32) += poll.o | ||
16 | lib-$(CONFIG_PLATFORM_MINGW32) += select.o | ||
17 | lib-$(CONFIG_PLATFORM_MINGW32) += popen.o | ||
18 | lib-$(CONFIG_PLATFORM_MINGW32) += statfs.o | ||
19 | lib-$(CONFIG_PLATFORM_MINGW32) += mempcpy.o | ||
20 | lib-$(CONFIG_PLATFORM_MINGW32) += mntent.o | ||
21 | lib-$(CONFIG_PLATFORM_MINGW32) += strptime.o | ||
22 | lib-$(CONFIG_PLATFORM_MINGW32) += system.o | ||
23 | lib-$(CONFIG_PLATFORM_MINGW32) += termios.o | ||
24 | lib-$(CONFIG_PLATFORM_MINGW32) += uname.o | ||
25 | lib-$(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 | |||
3 | char **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 | |||
16 | void free_environ(char **env) | ||
17 | { | ||
18 | int i; | ||
19 | for (i = 0; env[i]; i++) | ||
20 | free(env[i]); | ||
21 | free(env); | ||
22 | } | ||
23 | |||
24 | static 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 | ||
38 | char *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 | |||
50 | int 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 | */ | ||
86 | char **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 | ||
125 | int 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 | |||
138 | int 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 | |||
155 | int 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 | ||
171 | void unsetenv(const char *env) | ||
172 | { | ||
173 | env_setenv(environ, env); | ||
174 | } | ||
175 | |||
176 | int 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 | ||
123 | extern char *getenv (); | ||
124 | # endif | ||
125 | |||
126 | # ifndef errno | ||
127 | extern int errno; | ||
128 | # endif | ||
129 | |||
130 | /* This function doesn't exist on most systems. */ | ||
131 | |||
132 | # if !defined HAVE___STRCHRNUL && !defined _LIBC | ||
133 | static 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. */ | ||
153 | static int internal_fnmatch __P ((const char *pattern, const char *string, | ||
154 | int no_leading_period, int flags)) | ||
155 | internal_function; | ||
156 | static int | ||
157 | internal_function | ||
158 | internal_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 | |||
479 | int | ||
480 | fnmatch (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 | ||
23 | extern "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. */ | ||
77 | extern 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 | |||
54 | static int inet_pton4 (const char *src, unsigned char *dst); | ||
55 | # if HAVE_IPV6 | ||
56 | static 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 | */ | ||
70 | int | ||
71 | inet_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 | */ | ||
101 | static int | ||
102 | inet_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 | */ | ||
160 | static int | ||
161 | inet_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 | |||
3 | int 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. */ | ||
23 | void * | ||
24 | mempcpy (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 | ||
6 | int _dowildcard = -1; | ||
7 | #else | ||
8 | int _dowildcard = 0; | ||
9 | #endif | ||
10 | |||
11 | #undef _fmode | ||
12 | int _fmode = _O_BINARY; | ||
13 | #endif | ||
14 | |||
15 | #if !defined(__MINGW64_VERSION_MAJOR) | ||
16 | #if ENABLE_GLOBBING | ||
17 | int _CRT_glob = 1; | ||
18 | #else | ||
19 | int _CRT_glob = 0; | ||
20 | #endif | ||
21 | |||
22 | unsigned int _CRT_fmode = _O_BINARY; | ||
23 | #endif | ||
24 | |||
25 | smallint bb_got_signal; | ||
26 | |||
27 | int 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 | ||
142 | int 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 | ||
167 | FILE *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 | ||
175 | int 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 | */ | ||
185 | static 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 | |||
192 | static inline time_t filetime_to_time_t(const FILETIME *ft) | ||
193 | { | ||
194 | return (time_t)(filetime_to_hnsec(ft) / 10000000); | ||
195 | } | ||
196 | |||
197 | static 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 | |||
209 | static 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 | */ | ||
236 | static 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 | */ | ||
299 | static 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 | |||
326 | int mingw_lstat(const char *file_name, struct mingw_stat *buf) | ||
327 | { | ||
328 | return do_stat_internal(0, file_name, buf); | ||
329 | } | ||
330 | int mingw_stat(const char *file_name, struct mingw_stat *buf) | ||
331 | { | ||
332 | return do_stat_internal(1, file_name, buf); | ||
333 | } | ||
334 | |||
335 | int 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 | |||
387 | static 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 | |||
394 | int 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 | |||
440 | revert_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 | |||
449 | unsigned 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 | ||
460 | char *mingw_mktemp(char *template) | ||
461 | { | ||
462 | if ( mktemp(template) == NULL ) { | ||
463 | template[0] = '\0'; | ||
464 | } | ||
465 | |||
466 | return template; | ||
467 | } | ||
468 | |||
469 | int 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 | |||
477 | int 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 | |||
489 | int pipe(int filedes[2]) | ||
490 | { | ||
491 | if (_pipe(filedes, PIPE_BUF, 0) < 0) | ||
492 | return -1; | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | struct 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 | |||
503 | struct 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 | ||
511 | char *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 | ||
524 | int 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 | |||
557 | static 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 | |||
584 | static 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 | |||
607 | struct 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 | |||
619 | struct 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 | |||
636 | struct 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 | |||
652 | int 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 | |||
665 | int 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 | |||
675 | int 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 | |||
692 | long sysconf(int name) | ||
693 | { | ||
694 | if ( name == _SC_CLK_TCK ) { | ||
695 | return 100; | ||
696 | } | ||
697 | errno = EINVAL; | ||
698 | return -1; | ||
699 | } | ||
700 | |||
701 | clock_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 | |||
711 | int 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 | |||
732 | char *realpath(const char *path, char *resolved_path) | ||
733 | { | ||
734 | /* FIXME: need normalization */ | ||
735 | return strcpy(resolved_path, path); | ||
736 | } | ||
737 | |||
738 | const 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 | ||
748 | int 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 | ||
767 | int 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 | |||
779 | int 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 | ||
823 | int 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 | ||
831 | size_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 | |||
905 | int stime(time_t *t UNUSED_PARAM) | ||
906 | { | ||
907 | errno = EPERM; | ||
908 | return -1; | ||
909 | } | ||
910 | |||
911 | #undef access | ||
912 | int 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 | ||
980 | int 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 | */ | ||
993 | char *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 | ||
1020 | DIR *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 | |||
1034 | off_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 | |||
7 | struct mntdata { | ||
8 | DWORD flags; | ||
9 | int index; | ||
10 | }; | ||
11 | |||
12 | FILE *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 | |||
26 | struct 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 | |||
65 | int 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 | |||
6 | struct 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 | |||
15 | extern FILE *setmntent(const char *file, const char *mode); | ||
16 | extern struct mntent *getmntent(FILE *stream); | ||
17 | extern 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 | |||
3 | int 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 | |||
13 | void 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 | |||
22 | int 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 | ||
50 | int 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 | ||
57 | int 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 | ||
64 | int 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 | ||
71 | int mingw_shutdown(int sockfd, int how) | ||
72 | { | ||
73 | SOCKET s = (SOCKET)_get_osfhandle(sockfd); | ||
74 | return shutdown(s, how); | ||
75 | } | ||
76 | |||
77 | #undef listen | ||
78 | int mingw_listen(int sockfd, int backlog) | ||
79 | { | ||
80 | SOCKET s = (SOCKET)_get_osfhandle(sockfd); | ||
81 | return listen(s, backlog); | ||
82 | } | ||
83 | |||
84 | #undef accept | ||
85 | int 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 | |||
77 | static BOOL | ||
78 | IsSocketHandle (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. */ | ||
93 | typedef 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 | |||
106 | typedef 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 | |||
115 | typedef enum _FILE_INFORMATION_CLASS { | ||
116 | FilePipeLocalInformation = 24 | ||
117 | } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; | ||
118 | |||
119 | typedef 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 | |||
129 | static int | ||
130 | win32_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 | |||
227 | static int | ||
228 | win32_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. */ | ||
269 | static int | ||
270 | compute_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 | |||
319 | int | ||
320 | poll (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 | |||
457 | restart: | ||
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 | |||
37 | struct 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 | |||
44 | typedef unsigned long nfds_t; | ||
45 | |||
46 | extern 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 | |||
4 | typedef struct { | ||
5 | PROCESS_INFORMATION piProcInfo; | ||
6 | HANDLE pipe[2]; | ||
7 | char mode; | ||
8 | int fd; | ||
9 | } pipe_data; | ||
10 | |||
11 | static pipe_data *pipes = NULL; | ||
12 | static int num_pipes = 0; | ||
13 | |||
14 | static 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 | |||
29 | static 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 | |||
62 | FILE *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 | |||
165 | finito: | ||
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 | */ | ||
189 | int 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 | |||
261 | finito: | ||
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 | |||
281 | int 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 | |||
4 | int 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 | |||
22 | const char * | ||
23 | next_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 | |||
44 | static const char * | ||
45 | parse_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 | */ | ||
119 | static char * | ||
120 | quote_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 | |||
210 | static intptr_t | ||
211 | spawnveq(int mode, const char *path, const char *const *argv, const char *const *env) | ||
212 | { | ||
213 | char **new_argv; | ||
214 | int i, argc = 0; | ||
215 | intptr_t ret; | ||
216 | |||
217 | if (!argv) { | ||
218 | const char *empty_argv[] = { path, NULL }; | ||
219 | return spawnve(mode, path, empty_argv, env); | ||
220 | } | ||
221 | |||
222 | |||
223 | while (argv[argc]) | ||
224 | argc++; | ||
225 | |||
226 | new_argv = malloc(sizeof(*argv)*(argc+1)); | ||
227 | for (i = 0;i < argc;i++) | ||
228 | new_argv[i] = quote_arg(argv[i]); | ||
229 | new_argv[argc] = NULL; | ||
230 | ret = spawnve(mode, path, (const char *const *)new_argv, env); | ||
231 | for (i = 0;i < argc;i++) | ||
232 | if (new_argv[i] != argv[i]) | ||
233 | free(new_argv[i]); | ||
234 | free(new_argv); | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | static intptr_t | ||
239 | mingw_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 | |||
255 | static intptr_t | ||
256 | mingw_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 | |||
299 | static intptr_t | ||
300 | mingw_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 | |||
332 | pid_t FAST_FUNC | ||
333 | mingw_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 | |||
343 | intptr_t FAST_FUNC | ||
344 | mingw_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 | |||
350 | int | ||
351 | mingw_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 | |||
359 | int | ||
360 | mingw_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 | |||
382 | int | ||
383 | mingw_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 */ | ||
389 | procps_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 | |||
420 | int 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 | |||
60 | extern 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 | |||
67 | static char re_syntax_table[CHAR_SET_SIZE]; | ||
68 | |||
69 | static void | ||
70 | init_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. */ | ||
175 | char *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 | |||
211 | typedef 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 | |||
224 | typedef 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 | ||
385 | static void | ||
386 | extract_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 | ||
412 | static void | ||
413 | extract_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 | |||
443 | static 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 | |||
456 | extern void printchar (); | ||
457 | |||
458 | /* Print the fastmap in human-readable form. */ | ||
459 | |||
460 | void | ||
461 | print_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 | |||
492 | void | ||
493 | print_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 | |||
700 | void | ||
701 | print_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 | |||
727 | void | ||
728 | print_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. */ | ||
772 | reg_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 | |||
782 | reg_syntax_t | ||
783 | re_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 | |||
795 | static 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 | |||
817 | static void store_op1 (), store_op2 (); | ||
818 | static void insert_op1 (), insert_op2 (); | ||
819 | static boolean at_begline_loc_p (), at_endline_loc_p (); | ||
820 | static boolean group_in_compile_stack (); | ||
821 | static 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. */ | ||
949 | typedef 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. */ | ||
956 | typedef int pattern_offset_t; | ||
957 | |||
958 | typedef 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 | |||
968 | typedef 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 | |||
1036 | static reg_errcode_t | ||
1037 | regex_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 | |||
2041 | static void | ||
2042 | store_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 | |||
2054 | static void | ||
2055 | store_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 | |||
2069 | static void | ||
2070 | insert_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 | |||
2088 | static void | ||
2089 | insert_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 | |||
2109 | static boolean | ||
2110 | at_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 | |||
2128 | static boolean | ||
2129 | at_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 | |||
2150 | static boolean | ||
2151 | group_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 | |||
2178 | static reg_errcode_t | ||
2179 | compile_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. */ | ||
2239 | int re_max_failures = 2000; | ||
2240 | |||
2241 | typedef const unsigned char *fail_stack_elt_t; | ||
2242 | |||
2243 | typedef 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 | |||
2510 | int | ||
2511 | re_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 | |||
2795 | void | ||
2796 | re_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 | |||
2822 | int | ||
2823 | re_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 | |||
2855 | int | ||
2856 | re_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 | |||
2973 | static int bcmp_translate (); | ||
2974 | static 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. */ | ||
2989 | typedef 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 | |||
3114 | int | ||
3115 | re_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 | |||
3139 | int | ||
3140 | re_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 | |||
4335 | static boolean | ||
4336 | group_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 | |||
4444 | static boolean | ||
4445 | alt_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 | |||
4481 | static boolean | ||
4482 | common_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 | |||
4569 | static int | ||
4570 | bcmp_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 | |||
4597 | const char * | ||
4598 | re_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. */ | ||
4628 | static struct re_pattern_buffer re_comp_buf; | ||
4629 | |||
4630 | char * | ||
4631 | re_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 | |||
4668 | int | ||
4669 | re_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 | |||
4716 | int | ||
4717 | regcomp (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 | |||
4791 | int | ||
4792 | regexec (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 ? ®s : (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 | |||
4856 | size_t | ||
4857 | regerror (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 | |||
4900 | void | ||
4901 | regfree (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 | /* | ||
4924 | Local variables: | ||
4925 | make-backup-files: t | ||
4926 | version-control: t | ||
4927 | trim-versions-without-asking: nil | ||
4928 | End: | ||
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. */ | ||
38 | typedef 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. */ | ||
137 | extern 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. */ | ||
246 | typedef 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 | |||
278 | struct 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 | |||
346 | typedef 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. */ | ||
354 | typedef 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. */ | ||
359 | struct 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. */ | ||
378 | typedef 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. */ | ||
404 | extern 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. */ | ||
409 | extern 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. */ | ||
417 | extern 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). */ | ||
425 | extern 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. */ | ||
432 | extern 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. */ | ||
440 | extern 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'. */ | ||
446 | extern 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. */ | ||
464 | extern 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. */ | ||
469 | extern char *re_comp _RE_ARGS ((const char *)); | ||
470 | extern int re_exec _RE_ARGS ((const char *)); | ||
471 | |||
472 | /* POSIX compatibility. */ | ||
473 | extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags)); | ||
474 | extern int regexec | ||
475 | _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch, | ||
476 | regmatch_t pmatch[], int eflags)); | ||
477 | extern size_t regerror | ||
478 | _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf, | ||
479 | size_t errbuf_size)); | ||
480 | extern void regfree _RE_ARGS ((regex_t *preg)); | ||
481 | |||
482 | #endif /* not __REGEXP_LIBRARY_H__ */ | ||
483 | |||
484 | /* | ||
485 | Local variables: | ||
486 | make-backup-files: t | ||
487 | version-control: t | ||
488 | trim-versions-without-asking: nil | ||
489 | End: | ||
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 | |||
43 | struct 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. */ | ||
49 | typedef 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 | |||
62 | typedef 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 | |||
71 | typedef enum _FILE_INFORMATION_CLASS { | ||
72 | FilePipeLocalInformation = 24 | ||
73 | } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; | ||
74 | |||
75 | typedef 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 | |||
82 | static BOOL IsConsoleHandle (HANDLE h) | ||
83 | { | ||
84 | DWORD mode; | ||
85 | return GetConsoleMode (h, &mode) != 0; | ||
86 | } | ||
87 | |||
88 | static BOOL | ||
89 | IsSocketHandle (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 | |||
106 | static int | ||
107 | windows_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 | |||
241 | int | ||
242 | mingw_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 | |||
396 | restart: | ||
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 | |||
541 | int | ||
542 | rpl_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 | */ | ||
7 | int 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 | |||
33 | enum 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 | |||
67 | static char const weekday_name[][10] = | ||
68 | { | ||
69 | "Sunday", "Monday", "Tuesday", "Wednesday", | ||
70 | "Thursday", "Friday", "Saturday" | ||
71 | }; | ||
72 | static char const ab_weekday_name[][4] = | ||
73 | { | ||
74 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | ||
75 | }; | ||
76 | static char const month_name[][10] = | ||
77 | { | ||
78 | "January", "February", "March", "April", "May", "June", | ||
79 | "July", "August", "September", "October", "November", "December" | ||
80 | }; | ||
81 | static 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 | |||
93 | static 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. */ | ||
119 | static void | ||
120 | day_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. */ | ||
137 | static void | ||
138 | day_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 | |||
145 | static 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 | |||
634 | char * | ||
635 | strptime (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 | |||
6 | struct 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 | |||
20 | extern 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. */ | ||
45 | struct 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. */ | ||
63 | extern 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 | |||
3 | int 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 | |||
3 | int tcsetattr(int fd UNUSED_PARAM, int mode UNUSED_PARAM, const struct termios *t UNUSED_PARAM) | ||
4 | { | ||
5 | return -1; | ||
6 | } | ||
7 | |||
8 | int tcgetattr(int fd UNUSED_PARAM, struct termios *t UNUSED_PARAM) | ||
9 | { | ||
10 | return -1; | ||
11 | } | ||
12 | |||
13 | int64_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 | |||
104 | typedef unsigned char cc_t; | ||
105 | typedef unsigned int tcflag_t; | ||
106 | typedef unsigned int speed_t; | ||
107 | typedef unsigned short otcflag_t; | ||
108 | typedef unsigned char ospeed_t; | ||
109 | |||
110 | #define NCCS 18 | ||
111 | struct 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 | |||
122 | struct winsize { | ||
123 | unsigned short ws_row, ws_col; | ||
124 | unsigned short ws_xpixel, ws_ypixel; | ||
125 | }; | ||
126 | |||
127 | int tcflush(int fd, int queue_selector); | ||
128 | int tcgetattr(int fd, struct termios *t); | ||
129 | int 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 | |||
5 | int 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 | |||
30 | static HANDLE console; | ||
31 | static HANDLE console_in; | ||
32 | static WORD plain_attr; | ||
33 | static WORD attr; | ||
34 | static int negative; | ||
35 | |||
36 | static void init(void) | ||
37 | { | ||
38 | CONSOLE_SCREEN_BUFFER_INFO sbi; | ||
39 | |||
40 | static int initialized = 0; | ||
41 | if (initialized) | ||
42 | return; | ||
43 | |||
44 | console_in = GetStdHandle(STD_INPUT_HANDLE); | ||
45 | if (console_in == INVALID_HANDLE_VALUE) | ||
46 | console_in = NULL; | ||
47 | |||
48 | console = GetStdHandle(STD_OUTPUT_HANDLE); | ||
49 | if (console == INVALID_HANDLE_VALUE) | ||
50 | console = NULL; | ||
51 | |||
52 | if (!console) | ||
53 | return; | ||
54 | |||
55 | GetConsoleScreenBufferInfo(console, &sbi); | ||
56 | attr = plain_attr = sbi.wAttributes; | ||
57 | negative = 0; | ||
58 | |||
59 | initialized = 1; | ||
60 | } | ||
61 | |||
62 | static 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 | |||
79 | static 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 | |||
105 | static 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 | |||
122 | static 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 | |||
140 | void 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 | |||
159 | void 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 | |||
171 | static 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 | |||
183 | static 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 | |||
197 | static 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 | |||
381 | static 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 | |||
444 | int 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 | |||
461 | int 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 | |||
479 | size_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 | |||
508 | int 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 | |||
528 | int 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 | |||
566 | abort: | ||
567 | rv = vfprintf(stream, format, list); | ||
568 | return rv; | ||
569 | } | ||
570 | |||
571 | int 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 | |||
583 | int 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 | |||
595 | int 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 | |||
612 | static 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 | |||
680 | int 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 | |||
693 | int 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 | |||
713 | int 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 | } | ||