aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Config.src10
-rw-r--r--libbb/Kbuild.src51
-rw-r--r--libbb/appletlib.c335
-rw-r--r--libbb/bb_getgroups.c8
-rw-r--r--libbb/compare_string_array.c41
-rw-r--r--libbb/concat_path_file.c6
-rw-r--r--libbb/const_hack.c10
-rw-r--r--libbb/copy_file.c6
-rw-r--r--libbb/dump.c36
-rw-r--r--libbb/executable.c22
-rw-r--r--libbb/find_mount_point.c31
-rw-r--r--libbb/find_pid_by_name.c6
-rw-r--r--libbb/get_last_path_component.c41
-rw-r--r--libbb/get_line_from_file.c18
-rw-r--r--libbb/getopt32.c4
-rw-r--r--libbb/herror_msg.c4
-rw-r--r--libbb/human_readable.c6
-rw-r--r--libbb/inode_hash.c5
-rw-r--r--libbb/last_char_is.c11
-rw-r--r--libbb/lineedit.c252
-rw-r--r--libbb/make_directory.c8
-rw-r--r--libbb/messages.c22
-rw-r--r--libbb/mode_string.c2
-rw-r--r--libbb/parse_config.c9
-rw-r--r--libbb/perror_msg.c4
-rw-r--r--libbb/printable_string.c2
-rw-r--r--libbb/procps.c3
-rw-r--r--libbb/read_key.c5
-rw-r--r--libbb/read_printf.c5
-rw-r--r--libbb/signals.c2
-rw-r--r--libbb/time.c9
-rw-r--r--libbb/u_signal_names.c15
-rw-r--r--libbb/unicode.c13
-rw-r--r--libbb/verror_msg.c6
-rw-r--r--libbb/vfork_daemon_rexec.c6
-rw-r--r--libbb/wcwidth_alt.c506
-rw-r--r--libbb/xatonum_template.c5
-rw-r--r--libbb/xconnect.c14
-rw-r--r--libbb/xfuncs.c16
-rw-r--r--libbb/xfuncs_printf.c14
-rw-r--r--libbb/xreadlink.c45
41 files changed, 1542 insertions, 72 deletions
diff --git a/libbb/Config.src b/libbb/Config.src
index b980f19a9..61b4601d6 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -188,6 +188,16 @@ config FEATURE_EDITING_HISTORY
188 help 188 help
189 Specify command history size (0 - disable). 189 Specify command history size (0 - disable).
190 190
191config FEATURE_EDITING_HISTORY_DEFAULT
192 int "Default history size"
193 range 0 FEATURE_EDITING_HISTORY
194 default 255
195 depends on PLATFORM_MINGW32 && FEATURE_EDITING && FEATURE_SH_HISTFILESIZE
196 help
197 Specify default command history size. This may be smaller than
198 FEATURE_EDITING_HISTORY, in which case the user may increase
199 the history size by setting HISTFILESIZE.
200
191config FEATURE_EDITING_SAVEHISTORY 201config FEATURE_EDITING_SAVEHISTORY
192 bool "History saving" 202 bool "History saving"
193 default y 203 default y
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index cb8d2c2ec..32fde90e6 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -10,17 +10,14 @@ lib-y:=
10 10
11INSERT 11INSERT
12 12
13lib-y += alloc_affinity.o
14lib-y += appletlib.o 13lib-y += appletlib.o
15lib-y += ask_confirmation.o 14lib-y += ask_confirmation.o
16lib-y += bb_askpass.o
17lib-y += bb_bswap_64.o 15lib-y += bb_bswap_64.o
18lib-y += bb_do_delay.o 16lib-y += bb_do_delay.o
19lib-y += bb_pwd.o 17lib-y += bb_pwd.o
20lib-y += bb_qsort.o 18lib-y += bb_qsort.o
21#lib-y += bb_strtod.o 19#lib-y += bb_strtod.o
22lib-y += bb_strtonum.o 20lib-y += bb_strtonum.o
23lib-y += change_identity.o
24lib-y += chomp.o 21lib-y += chomp.o
25lib-y += compare_string_array.o 22lib-y += compare_string_array.o
26lib-y += concat_path_file.o 23lib-y += concat_path_file.o
@@ -30,32 +27,23 @@ lib-y += copy_file.o
30lib-y += copyfd.o 27lib-y += copyfd.o
31lib-y += crc32.o 28lib-y += crc32.o
32lib-y += default_error_retval.o 29lib-y += default_error_retval.o
33lib-y += device_open.o
34lib-y += dump.o 30lib-y += dump.o
35lib-y += executable.o 31lib-y += executable.o
36lib-y += fclose_nonstdin.o 32lib-y += fclose_nonstdin.o
37lib-y += fflush_stdout_and_exit.o 33lib-y += fflush_stdout_and_exit.o
38lib-y += fgets_str.o 34lib-y += fgets_str.o
39lib-y += find_pid_by_name.o 35lib-y += find_pid_by_name.o
40lib-y += find_root_device.o
41lib-y += full_write.o 36lib-y += full_write.o
42lib-y += get_console.o
43lib-y += get_last_path_component.o 37lib-y += get_last_path_component.o
44lib-y += get_line_from_file.o 38lib-y += get_line_from_file.o
45lib-y += getpty.o 39lib-y += getopt32.o
46lib-y += get_volsize.o
47lib-y += herror_msg.o 40lib-y += herror_msg.o
48lib-y += human_readable.o 41lib-y += human_readable.o
49lib-y += inet_common.o
50lib-y += inode_hash.o
51lib-y += isdirectory.o 42lib-y += isdirectory.o
52lib-y += kernel_version.o
53lib-y += last_char_is.o 43lib-y += last_char_is.o
54lib-y += lineedit.o lineedit_ptr_hack.o 44lib-y += lineedit.o lineedit_ptr_hack.o
55lib-y += llist.o 45lib-y += llist.o
56lib-y += login.o
57lib-y += make_directory.o 46lib-y += make_directory.o
58lib-y += makedev.o
59lib-y += hash_md5_sha.o 47lib-y += hash_md5_sha.o
60lib-y += hash_sha1_x86-64.o 48lib-y += hash_sha1_x86-64.o
61lib-y += hash_sha1_hwaccel_x86-64.o 49lib-y += hash_sha1_hwaccel_x86-64.o
@@ -68,21 +56,18 @@ lib-y += messages.o
68lib-y += mode_string.o 56lib-y += mode_string.o
69lib-y += parse_mode.o 57lib-y += parse_mode.o
70lib-y += perror_msg.o 58lib-y += perror_msg.o
71lib-y += perror_nomsg.o
72lib-y += perror_nomsg_and_die.o 59lib-y += perror_nomsg_and_die.o
73lib-y += pidfile.o
74lib-y += platform.o 60lib-y += platform.o
75lib-y += popcnt.o 61lib-y += popcnt.o
76lib-y += printable.o 62lib-y += printable.o
77lib-y += printable_string.o 63lib-y += printable_string.o
78lib-y += print_flags.o
79lib-y += process_escape_sequence.o 64lib-y += process_escape_sequence.o
80lib-y += procps.o 65lib-y += procps.o
81lib-y += progress.o 66lib-y += progress.o
82lib-y += ptr_to_globals.o 67lib-y += ptr_to_globals.o
83lib-y += read.o 68lib-y += read.o
84lib-y += read_printf.o
85lib-y += read_key.o 69lib-y += read_key.o
70lib-y += read_printf.o
86lib-y += recursive_action.o 71lib-y += recursive_action.o
87lib-y += remove_file.o 72lib-y += remove_file.o
88lib-y += run_shell.o 73lib-y += run_shell.o
@@ -91,12 +76,9 @@ lib-y += safe_poll.o
91lib-y += safe_strncpy.o 76lib-y += safe_strncpy.o
92lib-y += safe_write.o 77lib-y += safe_write.o
93lib-y += securetty.o 78lib-y += securetty.o
94lib-y += setup_environment.o
95lib-y += signals.o
96lib-y += simplify_path.o 79lib-y += simplify_path.o
97lib-y += single_argv.o 80lib-y += single_argv.o
98lib-y += skip_whitespace.o 81lib-y += skip_whitespace.o
99lib-y += speed_table.o
100lib-y += str_tolower.o 82lib-y += str_tolower.o
101lib-y += strrstr.o 83lib-y += strrstr.o
102lib-y += sysconf.o 84lib-y += sysconf.o
@@ -109,17 +91,39 @@ lib-y += vfork_daemon_rexec.o
109lib-y += warn_ignoring_args.o 91lib-y += warn_ignoring_args.o
110lib-y += wfopen.o 92lib-y += wfopen.o
111lib-y += wfopen_input.o 93lib-y += wfopen_input.o
112lib-y += write.o
113lib-y += xatonum.o 94lib-y += xatonum.o
114lib-y += xconnect.o 95lib-y += xconnect.o
115lib-y += xfuncs.o 96lib-y += xfuncs.o
116lib-y += xfuncs_printf.o 97lib-y += xfuncs_printf.o
117lib-y += xfunc_die.o 98lib-y += xfunc_die.o
118lib-y += xgetcwd.o 99lib-y += xgetcwd.o
119lib-y += xgethostbyname.o
120lib-y += xreadlink.o 100lib-y += xreadlink.o
121lib-y += xrealloc_vector.o 101lib-y += xrealloc_vector.o
122 102
103lib-$(CONFIG_PLATFORM_POSIX) += alloc_affinity.o
104lib-$(CONFIG_PLATFORM_POSIX) += bb_askpass.o
105lib-$(CONFIG_PLATFORM_POSIX) += change_identity.o
106lib-$(CONFIG_PLATFORM_POSIX) += device_open.o
107lib-$(CONFIG_PLATFORM_POSIX) += find_root_device.o
108lib-$(CONFIG_PLATFORM_POSIX) += get_console.o
109lib-$(CONFIG_PLATFORM_POSIX) += getpty.o
110lib-$(CONFIG_PLATFORM_POSIX) += get_volsize.o
111lib-$(CONFIG_PLATFORM_POSIX) += inet_common.o
112lib-$(CONFIG_PLATFORM_POSIX) += inode_hash.o
113lib-$(CONFIG_FEATURE_EXTRA_FILE_DATA) += inode_hash.o
114lib-$(CONFIG_PLATFORM_POSIX) += kernel_version.o
115lib-$(CONFIG_PLATFORM_POSIX) += login.o
116lib-$(CONFIG_PLATFORM_POSIX) += makedev.o
117lib-$(CONFIG_PLATFORM_POSIX) += perror_nomsg.o
118lib-$(CONFIG_PLATFORM_POSIX) += pidfile.o
119lib-$(CONFIG_PLATFORM_POSIX) += print_flags.o
120lib-$(CONFIG_PLATFORM_POSIX) += setup_environment.o
121lib-$(CONFIG_PLATFORM_POSIX) += signals.o
122lib-$(CONFIG_PLATFORM_POSIX) += speed_table.o
123lib-$(CONFIG_PLATFORM_POSIX) += udp_io.o
124lib-$(CONFIG_PLATFORM_POSIX) += write.o
125lib-$(CONFIG_PLATFORM_POSIX) += xgethostbyname.o
126
123lib-$(CONFIG_MOUNT) += match_fstype.o 127lib-$(CONFIG_MOUNT) += match_fstype.o
124lib-$(CONFIG_UMOUNT) += match_fstype.o 128lib-$(CONFIG_UMOUNT) += match_fstype.o
125 129
@@ -132,7 +136,7 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o
132lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o 136lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o
133lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o 137lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o
134 138
135lib-$(CONFIG_NC) += udp_io.o 139lib-$(CONFIG_NC_110_COMPAT) += udp_io.o
136lib-$(CONFIG_NETCAT) += udp_io.o 140lib-$(CONFIG_NETCAT) += udp_io.o
137lib-$(CONFIG_DNSD) += udp_io.o 141lib-$(CONFIG_DNSD) += udp_io.o
138lib-$(CONFIG_NTPD) += udp_io.o 142lib-$(CONFIG_NTPD) += udp_io.o
@@ -171,6 +175,7 @@ lib-$(CONFIG_MKE2FS) += find_mount_point.o
171lib-$(CONFIG_MKFS_REISER) += find_mount_point.o 175lib-$(CONFIG_MKFS_REISER) += find_mount_point.o
172lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o 176lib-$(CONFIG_FSCK_MINIX) += find_mount_point.o
173lib-$(CONFIG_MOUNT) += find_mount_point.o 177lib-$(CONFIG_MOUNT) += find_mount_point.o
178lib-$(CONFIG_STAT) += find_mount_point.o
174 179
175lib-$(CONFIG_HWCLOCK) += rtc.o 180lib-$(CONFIG_HWCLOCK) += rtc.o
176lib-$(CONFIG_RTCWAKE) += rtc.o 181lib-$(CONFIG_RTCWAKE) += rtc.o
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index d2e5900b5..d6e042775 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -53,6 +53,15 @@ static inline int *get_perrno(void) { return &errno; }
53# define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__ 53# define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__
54#endif 54#endif
55 55
56#if (ENABLE_FEATURE_INSTALLER && !ENABLE_PLATFORM_MINGW32) || \
57 (ENABLE_PLATFORM_MINGW32 && (ENABLE_FEATURE_PREFER_APPLETS \
58 || ENABLE_FEATURE_SH_STANDALONE \
59 || ENABLE_FEATURE_SH_NOFORK))
60# define IF_FULL_LIST_OPTION(...) __VA_ARGS__
61#else
62# define IF_FULL_LIST_OPTION(...)
63#endif
64
56#include "usage_compressed.h" 65#include "usage_compressed.h"
57 66
58#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS 67#if ENABLE_FEATURE_SH_EMBEDDED_SCRIPTS
@@ -62,6 +71,7 @@ static inline int *get_perrno(void) { return &errno; }
62# define NUM_SCRIPTS 0 71# define NUM_SCRIPTS 0
63#endif 72#endif
64#if NUM_SCRIPTS > 0 73#if NUM_SCRIPTS > 0
74# define BB_ARCHIVE_PUBLIC
65# include "bb_archive.h" 75# include "bb_archive.h"
66static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS }; 76static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS };
67#endif 77#endif
@@ -90,6 +100,12 @@ static const char packed_scripts[] ALIGN1 = { PACKED_SCRIPTS };
90# define ENABLE_FEATURE_COMPRESS_USAGE 0 100# define ENABLE_FEATURE_COMPRESS_USAGE 0
91#endif 101#endif
92 102
103#if ENABLE_PLATFORM_MINGW32 && NUM_APPLETS > 1 && \
104 ENABLE_FEATURE_SH_STANDALONE
105static int find_applet_by_name_internal(const char *name);
106#else
107# define find_applet_by_name_internal(n) find_applet_by_name(n)
108#endif
93 109
94unsigned FAST_FUNC string_array_len(char **argv) 110unsigned FAST_FUNC string_array_len(char **argv)
95{ 111{
@@ -111,6 +127,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
111#if ENABLE_FEATURE_COMPRESS_USAGE 127#if ENABLE_FEATURE_COMPRESS_USAGE
112 128
113static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; 129static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
130# define BB_ARCHIVE_PUBLIC
114# include "bb_archive.h" 131# include "bb_archive.h"
115# define unpack_usage_messages() \ 132# define unpack_usage_messages() \
116 unpack_bz2_data(packed_usage, sizeof(packed_usage), sizeof(UNPACKED_USAGE)) 133 unpack_bz2_data(packed_usage, sizeof(packed_usage), sizeof(UNPACKED_USAGE))
@@ -147,7 +164,7 @@ void FAST_FUNC bb_show_usage(void)
147#else 164#else
148 const char *p; 165 const char *p;
149 const char *usage_string = p = unpack_usage_messages(); 166 const char *usage_string = p = unpack_usage_messages();
150 int ap = find_applet_by_name(applet_name); 167 int ap = find_applet_by_name_internal(applet_name);
151 168
152 if (ap < 0 || usage_string == NULL) 169 if (ap < 0 || usage_string == NULL)
153 xfunc_die(); 170 xfunc_die();
@@ -156,7 +173,11 @@ void FAST_FUNC bb_show_usage(void)
156 ap--; 173 ap--;
157 } 174 }
158 full_write_fn(bb_banner); 175 full_write_fn(bb_banner);
176#if ENABLE_PLATFORM_MINGW32
177 full_write_fn("\n");
178#else
159 full_write_fn(" multi-call binary.\n"); /* common string */ 179 full_write_fn(" multi-call binary.\n"); /* common string */
180#endif
160 if (*p == '\b') 181 if (*p == '\b')
161 full_write_fn("\nNo help available\n"); 182 full_write_fn("\nNo help available\n");
162 else { 183 else {
@@ -176,7 +197,12 @@ void FAST_FUNC bb_show_usage(void)
176 xfunc_die(); 197 xfunc_die();
177} 198}
178 199
200#if ENABLE_PLATFORM_MINGW32 && NUM_APPLETS > 1 && \
201 ENABLE_FEATURE_SH_STANDALONE
202static int find_applet_by_name_internal(const char *name)
203#else
179int FAST_FUNC find_applet_by_name(const char *name) 204int FAST_FUNC find_applet_by_name(const char *name)
205#endif
180{ 206{
181 unsigned i; 207 unsigned i;
182 int j; 208 int j;
@@ -241,6 +267,83 @@ int FAST_FUNC find_applet_by_name(const char *name)
241 return -1; 267 return -1;
242} 268}
243 269
270#if ENABLE_PLATFORM_MINGW32 && NUM_APPLETS > 1
271# if ENABLE_FEATURE_SH_STANDALONE
272int FAST_FUNC find_applet_by_name_for_sh(const char *name, const char *path)
273{
274 int applet_no = find_applet_by_name_internal(name);
275 return applet_no >= 0 && prefer_applet(name, path) ? applet_no : -1;
276}
277
278int FAST_FUNC find_applet_by_name(const char *name)
279{
280 return find_applet_by_name_for_sh(name, NULL);
281}
282# endif
283
284# if ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS
285static int external_exists(const char *name, const char *path)
286{
287 const char *path0, *path1, *ret;
288
289 path0 = path1 = xstrdup(path ?: getenv("PATH"));
290 ret = find_executable(name, &path1);
291 free((void *)ret);
292 free((void *)path0);
293 return ret != NULL;
294}
295
296static int prefer_applet_internal(const char *name, const char *path,
297 const char *override)
298{
299 const char *s, *sep;
300 size_t len;
301
302 if (override && *override) {
303 /* '-' disables all applets */
304 if (override[0] == '-' && override[1] == '\0')
305 return FALSE;
306
307 /* '+' each applet is overridden if an external command exists */
308 if (override[0] == '+' && override[1] == '\0')
309 return !external_exists(name, path);
310
311 /* Handle applets from a list separated by spaces, commas or
312 * semicolons. Applets before the first semicolon are disabled.
313 * Applets after the first semicolon are overridden if a
314 * corresponding external command exists. */
315 sep = strchr(override, ';');
316 len = strlen(name);
317 s = override - 1;
318 while (1) {
319 s = strstr(s + 1, name);
320 if (!s)
321 break;
322 /* neither "name.." nor "xxx,name.."? */
323 if (s != override && !strchr(" ,;", s[-1]))
324 continue;
325 /* neither "..name" nor "..name,xxx"? */
326 if (s[len] != '\0' && !strchr(" ,;", s[len]))
327 continue;
328 return (sep == NULL || s < sep) ?
329 FALSE : !external_exists(name, path);
330 }
331 }
332 return TRUE;
333}
334
335int FAST_FUNC prefer_applet(const char *name, const char *path)
336{
337 int ret;
338
339 ret = prefer_applet_internal(name, path, getenv(BB_OVERRIDE_APPLETS));
340 if (sizeof(CONFIG_OVERRIDE_APPLETS) > 1 && ret)
341 ret = prefer_applet_internal(name, path, CONFIG_OVERRIDE_APPLETS);
342 return ret;
343}
344# endif
345#endif
346
244 347
245void lbb_prepare(const char *applet 348void lbb_prepare(const char *applet
246 IF_FEATURE_INDIVIDUAL(, char **argv)) 349 IF_FEATURE_INDIVIDUAL(, char **argv))
@@ -291,6 +394,18 @@ const char *applet_name;
291#if !BB_MMU 394#if !BB_MMU
292bool re_execed; 395bool re_execed;
293#endif 396#endif
397#if ENABLE_PLATFORM_MINGW32
398static int interp = 0;
399char bb_comm[COMM_LEN];
400char bb_command_line[128];
401
402# if ENABLE_FEATURE_SH_STANDALONE
403void FAST_FUNC set_interp(int i)
404{
405 interp = i;
406}
407# endif
408#endif
294 409
295 410
296/* If not built as a single-applet executable... */ 411/* If not built as a single-applet executable... */
@@ -676,15 +791,36 @@ static void install_links(const char *busybox, int use_symbolic_links,
676 const char *appname = applet_names; 791 const char *appname = applet_names;
677 unsigned i; 792 unsigned i;
678 int rc; 793 int rc;
794# if ENABLE_PLATFORM_MINGW32
795 const char *sd = "";
796
797 if (custom_install_dir != NULL) {
798 bb_make_directory(custom_install_dir, 0755, FILEUTILS_RECUR);
799 }
800 else {
801 sd = get_system_drive();
802 for (i=1; i<ARRAY_SIZE(install_dir); ++i) {
803 fpc = concat_path_file(sd, install_dir[i]);
804 bb_make_directory(fpc, 0755, FILEUTILS_RECUR);
805 free(fpc);
806 }
807 }
808# endif
679 809
680 lf = link; 810 lf = link;
681 if (use_symbolic_links) 811 if (use_symbolic_links)
682 lf = symlink; 812 lf = symlink;
683 813
684 for (i = 0; i < ARRAY_SIZE(applet_main); i++) { 814 for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
815# if ENABLE_PLATFORM_MINGW32
816 fpc = xasprintf("%s%s/%s.exe", sd,
817 custom_install_dir ?: install_dir[APPLET_INSTALL_LOC(i)],
818 appname);
819# else
685 fpc = concat_path_file( 820 fpc = concat_path_file(
686 custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)], 821 custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)],
687 appname); 822 appname);
823# endif
688 // debug: bb_error_msg("%slinking %s to busybox", 824 // debug: bb_error_msg("%slinking %s to busybox",
689 // use_symbolic_links ? "sym" : "", fpc); 825 // use_symbolic_links ? "sym" : "", fpc);
690 rc = lf(busybox, fpc); 826 rc = lf(busybox, fpc);
@@ -781,20 +917,40 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
781 output_width = get_terminal_width(2); 917 output_width = get_terminal_width(2);
782 918
783 full_write1_str(bb_banner); /* reuse const string */ 919 full_write1_str(bb_banner); /* reuse const string */
920# if ENABLE_PLATFORM_MINGW32
921 full_write1_str("\n(");
922# if defined(MINGW_VER)
923 if (sizeof(MINGW_VER) > 5) {
924 full_write1_str(MINGW_VER "; ");
925 }
926# endif
927 full_write1_str(ENABLE_GLOBBING ? "glob" : "noglob");
928# if ENABLE_FEATURE_UTF8_MANIFEST
929 full_write1_str("; Unicode");
930# endif
931 full_write1_str(")\n\n");
932# else
784 full_write1_str(" multi-call binary.\n"); /* reuse */ 933 full_write1_str(" multi-call binary.\n"); /* reuse */
934#endif
785 full_write1_str( 935 full_write1_str(
786 "BusyBox is copyrighted by many authors between 1998-2015.\n" 936 "BusyBox is copyrighted by many authors between 1998-2024.\n"
787 "Licensed under GPLv2. See source distribution for detailed\n" 937 "Licensed under GPLv2. See source distribution for detailed\n"
788 "copyright notices.\n" 938 "copyright notices.\n"
789 "\n" 939 "\n"
790 "Usage: busybox [function [arguments]...]\n" 940 "Usage: busybox [function [arguments]...]\n"
791 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" 941 " or: busybox --list"IF_FULL_LIST_OPTION("[-full]")"\n"
792# if ENABLE_FEATURE_SHOW_SCRIPT && NUM_SCRIPTS > 0 942# if ENABLE_FEATURE_SHOW_SCRIPT && NUM_SCRIPTS > 0
793 " or: busybox --show SCRIPT\n" 943 " or: busybox --show SCRIPT\n"
794# endif 944# endif
795 IF_FEATURE_INSTALLER( 945 IF_FEATURE_INSTALLER(
946 IF_NOT_PLATFORM_MINGW32(
796 " or: busybox --install [-s] [DIR]\n" 947 " or: busybox --install [-s] [DIR]\n"
797 ) 948 )
949 IF_PLATFORM_MINGW32(
950 " or: busybox --install [-s] [-u|DIR]\n"
951 " or: busybox --uninstall [-n] file\n"
952 )
953 )
798 " or: function [arguments]...\n" 954 " or: function [arguments]...\n"
799 "\n" 955 "\n"
800 IF_NOT_FEATURE_SH_STANDALONE( 956 IF_NOT_FEATURE_SH_STANDALONE(
@@ -854,9 +1010,28 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
854 unsigned i = 0; 1010 unsigned i = 0;
855 const char *a = applet_names; 1011 const char *a = applet_names;
856 while (*a) { 1012 while (*a) {
857# if ENABLE_FEATURE_INSTALLER 1013# if ENABLE_FEATURE_INSTALLER && !ENABLE_PLATFORM_MINGW32
858 if (argv[1][6]) /* --list-full? */ 1014 if (argv[1][6]) /* --list-full? */
859 full_write1_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); 1015 full_write1_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
1016# elif ENABLE_PLATFORM_MINGW32 && (ENABLE_FEATURE_PREFER_APPLETS \
1017 || ENABLE_FEATURE_SH_STANDALONE \
1018 || ENABLE_FEATURE_SH_NOFORK)
1019 if (argv[1][6]) { /* --list-full? */
1020 const char *str;
1021
1022 if (APPLET_IS_NOFORK(i))
1023 str = "NOFORK ";
1024 else if (APPLET_IS_NOEXEC(i))
1025 str = "noexec ";
1026# if NUM_SCRIPTS > 0
1027 else if (applet_main[i] == scripted_main)
1028 str = "script ";
1029# endif
1030 else
1031 str = " ";
1032 full_write1_str(str);
1033 full_write1_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
1034 }
860# endif 1035# endif
861 full_write1_str(a); 1036 full_write1_str(a);
862 full_write1_str("\n"); 1037 full_write1_str("\n");
@@ -869,6 +1044,7 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
869 1044
870 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { 1045 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
871 int use_symbolic_links; 1046 int use_symbolic_links;
1047#if !ENABLE_PLATFORM_MINGW32
872 const char *busybox; 1048 const char *busybox;
873 1049
874 busybox = xmalloc_readlink(bb_busybox_exec_path); 1050 busybox = xmalloc_readlink(bb_busybox_exec_path);
@@ -888,8 +1064,62 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
888 */ 1064 */
889 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv); 1065 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv);
890 install_links(busybox, use_symbolic_links, argv[2]); 1066 install_links(busybox, use_symbolic_links, argv[2]);
1067#else
1068 char *target;
1069 uint32_t opt;
1070 enum { OPT_s = (1 << 0), OPT_u = (1 << 1) };
1071
1072 /* busybox --install [-s] [-u|DIR]
1073 * -s: make symlinks
1074 * -u: install to Unix-style directories in system drive
1075 * DIR: directory to install links to
1076 * If no argument is provided put the links in the same directory
1077 * as busybox.
1078 */
1079 argv += 1;
1080 opt = getopt32(argv, "!su");
1081 argv += optind;
1082
1083 if (opt == (uint32_t)-1 ||
1084 (*argv != NULL && (opt & OPT_u || *(argv + 1) != NULL)))
1085 bb_simple_error_msg_and_die("busybox --install [-s] [-u|DIR]");
1086
1087 if (opt & OPT_u)
1088 target = NULL;
1089 else if (*argv != NULL)
1090 target = *argv;
1091 else
1092 target = dirname(xstrdup(bb_busybox_exec_path));
1093
1094 use_symbolic_links = opt & OPT_s;
1095 /* NULL target -> install to Unix-style dirs */
1096 install_links(bb_busybox_exec_path, use_symbolic_links, target);
1097#endif
1098 return 0;
1099 }
1100
1101#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_INSTALLER
1102 if (strcmp(argv[1], "--uninstall") == 0) {
1103 char name[PATH_MAX];
1104 int dry_run = (argv[2] && strcmp(argv[2], "-n") == 0 && ++argv);
1105 const char *file = argv[2];
1106
1107 if (!argv[2])
1108 bb_error_msg_and_die(bb_msg_requires_arg, "--uninstall");
1109
1110 while (enumerate_links(file, name)) {
1111 if (dry_run) {
1112 full_write1_str(name);
1113 full_write1_str("\n");
1114 }
1115 else if (unlink(name) != 0) {
1116 bb_simple_perror_msg(name);
1117 }
1118 file = NULL;
1119 }
891 return 0; 1120 return 0;
892 } 1121 }
1122#endif
893 1123
894 if (strcmp(argv[1], "--help") == 0) { 1124 if (strcmp(argv[1], "--help") == 0) {
895 /* "busybox --help [<applet>]" */ 1125 /* "busybox --help [<applet>]" */
@@ -902,7 +1132,7 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
902 /* convert to "<applet> --help" */ 1132 /* convert to "<applet> --help" */
903 applet_name = argv[0] = argv[2]; 1133 applet_name = argv[0] = argv[2];
904 argv[2] = NULL; 1134 argv[2] = NULL;
905 if (find_applet_by_name(applet_name) >= 0) { 1135 if (find_applet_by_name_internal(applet_name) >= 0) {
906 /* Make "--help foo" exit with 0: */ 1136 /* Make "--help foo" exit with 0: */
907 xfunc_error_retval = 0; 1137 xfunc_error_retval = 0;
908 bb_show_usage(); 1138 bb_show_usage();
@@ -913,6 +1143,10 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
913 /* We support "busybox /a/path/to/applet args..." too. Allows for 1143 /* We support "busybox /a/path/to/applet args..." too. Allows for
914 * "#!/bin/busybox"-style wrappers 1144 * "#!/bin/busybox"-style wrappers
915 */ 1145 */
1146# if ENABLE_PLATFORM_MINGW32
1147 if (interp)
1148 --interp;
1149# endif
916 applet_name = bb_get_last_path_component_nostrip(argv[0]); 1150 applet_name = bb_get_last_path_component_nostrip(argv[0]);
917 } 1151 }
918 run_applet_and_exit(applet_name, argv); 1152 run_applet_and_exit(applet_name, argv);
@@ -943,6 +1177,9 @@ void FAST_FUNC show_usage_if_dash_dash_help(int applet_no UNUSED_PARAM, char **a
943# if ENABLE_TEST1 || ENABLE_TEST2 1177# if ENABLE_TEST1 || ENABLE_TEST2
944 && argv[0][0] != '[' /* exclude [ --help ] and [[ --help ]] too */ 1178 && argv[0][0] != '[' /* exclude [ --help ] and [[ --help ]] too */
945# endif 1179# endif
1180# if ENABLE_PLATFORM_MINGW32 && defined APPLET_NO_busybox
1181 && applet_no != APPLET_NO_busybox
1182# endif
946 ) { 1183 ) {
947 if (argv[1] && strcmp(argv[1], "--help") == 0) { 1184 if (argv[1] && strcmp(argv[1], "--help") == 0) {
948 /* Make "foo --help [...]" exit with 0: */ 1185 /* Make "foo --help [...]" exit with 0: */
@@ -954,7 +1191,14 @@ void FAST_FUNC show_usage_if_dash_dash_help(int applet_no UNUSED_PARAM, char **a
954 1191
955void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) 1192void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv)
956{ 1193{
1194# if ENABLE_PLATFORM_MINGW32
1195 int argc = string_array_len(argv);
1196 int i;
1197 const char *vmask;
1198 unsigned int mask;
1199# else
957 int argc; 1200 int argc;
1201# endif
958 1202
959 /* 1203 /*
960 * We do not use argv[0]: do not want to repeat massaging of 1204 * We do not use argv[0]: do not want to repeat massaging of
@@ -967,7 +1211,23 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **ar
967 if (ENABLE_FEATURE_SUID) 1211 if (ENABLE_FEATURE_SUID)
968 check_suid(applet_no); 1212 check_suid(applet_no);
969 1213
1214# if ENABLE_PLATFORM_MINGW32
1215 safe_strncpy(bb_comm,
1216 interp ? bb_basename(argv[interp]) : applet_name,
1217 sizeof(bb_comm));
1218
1219 safe_strncpy(bb_command_line, applet_name, sizeof(bb_command_line));
1220 for (i=1; i < argc && argv[i] &&
1221 strlen(bb_command_line) + strlen(argv[i]) + 2 < 128; ++i) {
1222 strcat(strcat(bb_command_line, " "), argv[i]);
1223 }
1224
1225 vmask = getenv("BB_UMASK");
1226 if (vmask && sscanf(vmask, "%o", &mask) == 1)
1227 umask((mode_t)mask);
1228# else
970 argc = string_array_len(argv); 1229 argc = string_array_len(argv);
1230# endif
971 xfunc_error_retval = applet_main[applet_no](argc, argv); 1231 xfunc_error_retval = applet_main[applet_no](argc, argv);
972 1232
973 /* Note: applet_main() may also not return (die on a xfunc or such) */ 1233 /* Note: applet_main() may also not return (die on a xfunc or such) */
@@ -985,7 +1245,7 @@ static NORETURN void run_applet_and_exit(const char *name, char **argv)
985# if NUM_APPLETS > 0 1245# if NUM_APPLETS > 0
986 /* find_applet_by_name() search is more expensive, so goes second */ 1246 /* find_applet_by_name() search is more expensive, so goes second */
987 { 1247 {
988 int applet = find_applet_by_name(name); 1248 int applet = find_applet_by_name_internal(name);
989 if (applet >= 0) 1249 if (applet >= 0)
990 run_applet_no_and_exit(applet, name, argv); 1250 run_applet_no_and_exit(applet, name, argv);
991 } 1251 }
@@ -1077,6 +1337,44 @@ int main(int argc UNUSED_PARAM, char **argv)
1077 argv[0][0] &= 0x7f; 1337 argv[0][0] &= 0x7f;
1078 } 1338 }
1079#endif 1339#endif
1340#if ENABLE_PLATFORM_MINGW32
1341# if ENABLE_FEATURE_UTF8_MANIFEST
1342 if (GetACP() != CP_UTF8) {
1343 full_write2_str(bb_basename(argv[0]));
1344 full_write2_str(": UTF8 manifest not supported\n");
1345 return 1;
1346 }
1347# endif
1348
1349 /* detect if we're running an interpreted script */
1350 if (argv[0][1] == ':' && argv[0][2] == '/') {
1351 switch (argv[0][0]) {
1352 case '2':
1353 ++interp;
1354 /* fall through */
1355 case '1':
1356 ++interp;
1357 argv[0] += 3;
1358 break;
1359 }
1360 }
1361
1362 /* Have this process handle critical errors itself: the default
1363 * system-generated error dialogs may be inconvenient. */
1364 change_critical_error_dialogs(getenv(BB_CRITICAL_ERROR_DIALOGS));
1365#endif
1366
1367#if defined(__MINGW64_VERSION_MAJOR)
1368 if ( stdin ) {
1369 _setmode(fileno(stdin), _O_BINARY);
1370 }
1371 if ( stdout ) {
1372 _setmode(fileno(stdout), _O_BINARY);
1373 }
1374 if ( stderr ) {
1375 _setmode(fileno(stderr), _O_BINARY);
1376 }
1377#endif
1080 1378
1081#if defined(SINGLE_APPLET_MAIN) 1379#if defined(SINGLE_APPLET_MAIN)
1082 1380
@@ -1101,6 +1399,10 @@ int main(int argc UNUSED_PARAM, char **argv)
1101 1399
1102#else 1400#else
1103 1401
1402# if ENABLE_PLATFORM_MINGW32
1403 if (argv[1] && argv[2] && strcmp(argv[1], "--busybox") == 0)
1404 argv += 2;
1405# endif
1104 lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); 1406 lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
1105# if !ENABLE_BUSYBOX 1407# if !ENABLE_BUSYBOX
1106 if (argv[1] && is_prefixed_with(bb_basename(argv[0]), "busybox")) 1408 if (argv[1] && is_prefixed_with(bb_basename(argv[0]), "busybox"))
@@ -1109,6 +1411,27 @@ int main(int argc UNUSED_PARAM, char **argv)
1109 applet_name = argv[0]; 1411 applet_name = argv[0];
1110 if (applet_name[0] == '-') 1412 if (applet_name[0] == '-')
1111 applet_name++; 1413 applet_name++;
1414# if ENABLE_PLATFORM_MINGW32
1415 str_tolower(argv[0]);
1416 bs_to_slash(argv[0]);
1417 if (has_exe_suffix_or_dot(argv[0])) {
1418 char *s = strrchr(argv[0], '.');
1419 if (s)
1420 *s = '\0';
1421 }
1422
1423 if (windows_env()) {
1424 /* remove single trailing separator from PATH */
1425 for (char **envp = environ; envp && *envp; envp++) {
1426 if (is_prefixed_with_case(*envp, "PATH=")) {
1427 char *end = last_char_is(*envp, ';');
1428 if (end && end[-1] != ';')
1429 *end = '\0';
1430 break;
1431 }
1432 }
1433 }
1434# endif
1112 applet_name = bb_basename(applet_name); 1435 applet_name = bb_basename(applet_name);
1113 1436
1114 /* If we are a result of execv("/proc/self/exe"), fix ugly comm of "exe" */ 1437 /* If we are a result of execv("/proc/self/exe"), fix ugly comm of "exe" */
diff --git a/libbb/bb_getgroups.c b/libbb/bb_getgroups.c
index 31cff2b41..757b80be8 100644
--- a/libbb/bb_getgroups.c
+++ b/libbb/bb_getgroups.c
@@ -10,6 +10,7 @@
10 10
11#include "libbb.h" 11#include "libbb.h"
12 12
13#if !ENABLE_PLATFORM_MINGW32
13gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) 14gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array)
14{ 15{
15 int n = ngroups ? *ngroups : 0; 16 int n = ngroups ? *ngroups : 0;
@@ -45,6 +46,7 @@ gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array)
45 *ngroups = n; 46 *ngroups = n;
46 return group_array; 47 return group_array;
47} 48}
49#endif
48 50
49uid_t FAST_FUNC get_cached_euid(uid_t *euid) 51uid_t FAST_FUNC get_cached_euid(uid_t *euid)
50{ 52{
@@ -60,6 +62,11 @@ gid_t FAST_FUNC get_cached_egid(gid_t *egid)
60 return *egid; 62 return *egid;
61} 63}
62 64
65#if !ENABLE_PLATFORM_MINGW32
66// Both current callers of is_in_supplementary_groups() check the gid
67// first. Our implementation of getgroups() provides no additional
68// information so there's no reason to call it.
69
63/* Return non-zero if GID is in our supplementary group list. */ 70/* Return non-zero if GID is in our supplementary group list. */
64int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid) 71int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid)
65{ 72{
@@ -79,3 +86,4 @@ int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid
79 86
80 return 0; 87 return 0;
81} 88}
89#endif
diff --git a/libbb/compare_string_array.c b/libbb/compare_string_array.c
index d8cd033a3..70a4c29cf 100644
--- a/libbb/compare_string_array.c
+++ b/libbb/compare_string_array.c
@@ -27,11 +27,25 @@ char* FAST_FUNC is_prefixed_with(const char *string, const char *key)
27#endif 27#endif
28} 28}
29 29
30#if ENABLE_PLATFORM_MINGW32
31char* FAST_FUNC is_prefixed_with_case(const char *string, const char *key)
32{
33 while (*key != '\0') {
34 if (tolower(*key) != tolower(*string))
35 return NULL;
36 key++;
37 string++;
38 }
39 return (char*)string;
40}
41#endif
42
30/* 43/*
31 * Return NULL if string is not suffixed with key. Return pointer to the 44 * Return NULL if string is not suffixed with key. Return pointer to the
32 * beginning of prefix key in string. If key is an empty string return pointer 45 * beginning of prefix key in string. If key is an empty string return pointer
33 * to the end of string. 46 * to the end of string.
34 */ 47 */
48#if !ENABLE_PLATFORM_MINGW32
35char* FAST_FUNC is_suffixed_with(const char *string, const char *key) 49char* FAST_FUNC is_suffixed_with(const char *string, const char *key)
36{ 50{
37 size_t key_len = strlen(key); 51 size_t key_len = strlen(key);
@@ -46,6 +60,33 @@ char* FAST_FUNC is_suffixed_with(const char *string, const char *key)
46 60
47 return NULL; 61 return NULL;
48} 62}
63#else
64static char* FAST_FUNC is_suffixed(const char *string, const char *key,
65 int (*fn)(const char *, const char*))
66{
67 size_t key_len = strlen(key);
68 ssize_t len_diff = strlen(string) - key_len;
69
70 if (len_diff >= 0) {
71 string += len_diff;
72 if (fn(string, key) == 0) {
73 return (char*)string;
74 }
75 }
76
77 return NULL;
78}
79
80char* FAST_FUNC is_suffixed_with(const char *string, const char *key)
81{
82 return is_suffixed(string, key, strcmp);
83}
84
85char* FAST_FUNC is_suffixed_with_case(const char *string, const char *key)
86{
87 return is_suffixed(string, key, strcasecmp);
88}
89#endif
49 90
50/* returns the array index of the string */ 91/* returns the array index of the string */
51/* (index of first match is returned, or -1) */ 92/* (index of first match is returned, or -1) */
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c
index 5b4b7f113..3afb0e3a4 100644
--- a/libbb/concat_path_file.c
+++ b/libbb/concat_path_file.c
@@ -21,8 +21,14 @@ char* FAST_FUNC concat_path_file(const char *path, const char *filename)
21 21
22 if (!path) 22 if (!path)
23 path = ""; 23 path = "";
24#if ENABLE_PLATFORM_MINGW32
25 lc = last_char_is_dir_sep(path);
26 while (is_dir_sep(*filename))
27 filename++;
28#else
24 lc = last_char_is(path, '/'); 29 lc = last_char_is(path, '/');
25 while (*filename == '/') 30 while (*filename == '/')
26 filename++; 31 filename++;
32#endif
27 return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); 33 return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename);
28} 34}
diff --git a/libbb/const_hack.c b/libbb/const_hack.c
index 9575e6d67..75163fede 100644
--- a/libbb/const_hack.c
+++ b/libbb/const_hack.c
@@ -13,4 +13,14 @@ void FAST_FUNC XZALLOC_CONST_PTR(const void *pptr, size_t size)
13{ 13{
14 ASSIGN_CONST_PTR(pptr, xzalloc(size)); 14 ASSIGN_CONST_PTR(pptr, xzalloc(size));
15} 15}
16
17# if ENABLE_PLATFORM_MINGW32
18void FAST_FUNC ASSIGN_CONST_PTR(const void *pptr, const void *v)
19{
20 do {
21 *(void**)not_const_pp(pptr) = (void*)(v);
22 barrier();
23 } while (0);
24}
25# endif
16#endif 26#endif
diff --git a/libbb/copy_file.c b/libbb/copy_file.c
index 044bc3c20..c0928a5a8 100644
--- a/libbb/copy_file.c
+++ b/libbb/copy_file.c
@@ -105,12 +105,18 @@ 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_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA
108 if (source_stat.st_dev == dest_stat.st_dev 109 if (source_stat.st_dev == dest_stat.st_dev
109 && source_stat.st_ino == dest_stat.st_ino 110 && source_stat.st_ino == dest_stat.st_ino
111# if ENABLE_FEATURE_EXTRA_FILE_DATA
112 /* ignore invalid inode numbers */
113 && source_stat.st_ino != 0
114# endif
110 ) { 115 ) {
111 bb_error_msg("'%s' and '%s' are the same file", source, dest); 116 bb_error_msg("'%s' and '%s' are the same file", source, dest);
112 return -1; 117 return -1;
113 } 118 }
119#endif
114 if (flags & FILEUTILS_NO_OVERWRITE) /* cp -n */ 120 if (flags & FILEUTILS_NO_OVERWRITE) /* cp -n */
115 return 0; 121 return 0;
116 dest_exists = 1; 122 dest_exists = 1;
diff --git a/libbb/dump.c b/libbb/dump.c
index 2ca9919da..aa57eca8c 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -36,6 +36,9 @@ typedef struct priv_dumper_t {
36 off_t eaddress; /* end address */ 36 off_t eaddress; /* end address */
37 int blocksize; 37 int blocksize;
38 smallint exitval; /* final exit value */ 38 smallint exitval; /* final exit value */
39#if ENABLE_PLATFORM_MINGW32
40 FILE *fd;
41#endif
39 42
40 /* former statics */ 43 /* former statics */
41 smallint next__done; 44 smallint next__done;
@@ -59,6 +62,9 @@ dumper_t* FAST_FUNC alloc_dumper(void)
59 dumper->pub.dump_length = -1; 62 dumper->pub.dump_length = -1;
60 dumper->pub.dump_vflag = FIRST; 63 dumper->pub.dump_vflag = FIRST;
61 dumper->get__ateof = 1; 64 dumper->get__ateof = 1;
65#if ENABLE_PLATFORM_MINGW32
66 dumper->fd = stdin;
67#endif
62 return &dumper->pub; 68 return &dumper->pub;
63} 69}
64 70
@@ -335,7 +341,11 @@ static void do_skip(priv_dumper_t *dumper, const char *fname)
335{ 341{
336 struct stat sbuf; 342 struct stat sbuf;
337 343
344#if ENABLE_PLATFORM_MINGW32
345 xfstat(fileno(dumper->fd), &sbuf, fname);
346#else
338 xfstat(STDIN_FILENO, &sbuf, fname); 347 xfstat(STDIN_FILENO, &sbuf, fname);
348#endif
339 if (S_ISREG(sbuf.st_mode) 349 if (S_ISREG(sbuf.st_mode)
340 && dumper->pub.dump_skip >= sbuf.st_size 350 && dumper->pub.dump_skip >= sbuf.st_size
341 ) { 351 ) {
@@ -344,7 +354,11 @@ static void do_skip(priv_dumper_t *dumper, const char *fname)
344 dumper->pub.address += sbuf.st_size; 354 dumper->pub.address += sbuf.st_size;
345 return; 355 return;
346 } 356 }
357#if ENABLE_PLATFORM_MINGW32
358 if (fseeko(dumper->fd, dumper->pub.dump_skip, SEEK_SET)) {
359#else
347 if (fseeko(stdin, dumper->pub.dump_skip, SEEK_SET)) { 360 if (fseeko(stdin, dumper->pub.dump_skip, SEEK_SET)) {
361#endif
348 bb_simple_perror_msg_and_die(fname); 362 bb_simple_perror_msg_and_die(fname);
349 } 363 }
350 dumper->pub.address += dumper->pub.dump_skip; 364 dumper->pub.address += dumper->pub.dump_skip;
@@ -360,13 +374,23 @@ static NOINLINE int next(priv_dumper_t *dumper)
360 if (fname) { 374 if (fname) {
361 dumper->argv++; 375 dumper->argv++;
362 if (NOT_LONE_DASH(fname)) { 376 if (NOT_LONE_DASH(fname)) {
377#if ENABLE_PLATFORM_MINGW32
378 dumper->fd = fopen(fname, "r");
379 if (!dumper->fd) {
380#else
363 if (!freopen(fname, "r", stdin)) { 381 if (!freopen(fname, "r", stdin)) {
382#endif
364 bb_simple_perror_msg(fname); 383 bb_simple_perror_msg(fname);
365 dumper->exitval = 1; 384 dumper->exitval = 1;
366 dumper->next__done = 1; 385 dumper->next__done = 1;
367 continue; 386 continue;
368 } 387 }
369 } 388 }
389#if ENABLE_PLATFORM_MINGW32
390 else {
391 dumper->fd = stdin;
392 }
393#endif
370 } else { 394 } else {
371 if (dumper->next__done) 395 if (dumper->next__done)
372 return 0; /* no next file */ 396 return 0; /* no next file */
@@ -421,13 +445,25 @@ static unsigned char *get(priv_dumper_t *dumper)
421 dumper->eaddress = dumper->pub.address + nread; 445 dumper->eaddress = dumper->pub.address + nread;
422 return dumper->get__curp; 446 return dumper->get__curp;
423 } 447 }
448#if ENABLE_PLATFORM_MINGW32
449 n = fread(dumper->get__curp + nread, sizeof(unsigned char),
450 dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), dumper->fd);
451#else
424 n = fread(dumper->get__curp + nread, sizeof(unsigned char), 452 n = fread(dumper->get__curp + nread, sizeof(unsigned char),
425 dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin); 453 dumper->pub.dump_length == -1 ? need : MIN(dumper->pub.dump_length, need), stdin);
454#endif
426 if (n == 0) { 455 if (n == 0) {
456#if ENABLE_PLATFORM_MINGW32
457 if (ferror(dumper->fd)) {
458#else
427 if (ferror(stdin)) { 459 if (ferror(stdin)) {
460#endif
428 bb_simple_perror_msg(dumper->argv[-1]); 461 bb_simple_perror_msg(dumper->argv[-1]);
429 } 462 }
430 dumper->get__ateof = 1; 463 dumper->get__ateof = 1;
464#if ENABLE_PLATFORM_MINGW32
465 fclose(dumper->fd);
466#endif
431 continue; 467 continue;
432 } 468 }
433 dumper->get__ateof = 0; 469 dumper->get__ateof = 0;
diff --git a/libbb/executable.c b/libbb/executable.c
index 09bed1eaf..263141912 100644
--- a/libbb/executable.c
+++ b/libbb/executable.c
@@ -15,7 +15,12 @@
15int FAST_FUNC file_is_executable(const char *name) 15int FAST_FUNC file_is_executable(const char *name)
16{ 16{
17 struct stat s; 17 struct stat s;
18#if !ENABLE_PLATFORM_MINGW32
18 return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode)); 19 return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
20#else
21 /* expand WIN32 implementation of access(2) */
22 return (!stat(name, &s) && S_ISREG(s.st_mode) && (s.st_mode & S_IXUSR));
23#endif
19} 24}
20 25
21/* search (*PATHp) for an executable file; 26/* search (*PATHp) for an executable file;
@@ -40,8 +45,9 @@ char* FAST_FUNC find_executable(const char *name, const char **PATHp)
40 if (!p) 45 if (!p)
41 return NULL; 46 return NULL;
42 while (1) { 47 while (1) {
43 const char *end = strchrnul(p, ':'); 48 const char *end = strchrnul(p, PATH_SEP);
44 int sz = end - p; 49 int sz = end - p;
50 int ex;
45 51
46 if (sz != 0) { 52 if (sz != 0) {
47 p = xasprintf("%.*s/%s", sz, p, name); 53 p = xasprintf("%.*s/%s", sz, p, name);
@@ -55,7 +61,19 @@ char* FAST_FUNC find_executable(const char *name, const char **PATHp)
55// With -a, both skip over all colons: xxx::::yyy is the same as xxx::yyy, 61// With -a, both skip over all colons: xxx::::yyy is the same as xxx::yyy,
56// current dir is not tried the second time. 62// current dir is not tried the second time.
57 } 63 }
58 if (file_is_executable(p)) { 64#if ENABLE_PLATFORM_MINGW32
65 {
66 char *w = file_is_win32_exe(p);
67 ex = w != NULL;
68 if (ex) {
69 free(p);
70 p = w;
71 }
72 }
73#else
74 ex = file_is_executable(p);
75#endif
76 if (ex) {
59 *PATHp = (*end ? end+1 : NULL); 77 *PATHp = (*end ? end+1 : NULL);
60 return p; 78 return p;
61 } 79 }
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
index 0e1be3820..cf06c6e18 100644
--- a/libbb/find_mount_point.c
+++ b/libbb/find_mount_point.c
@@ -6,6 +6,9 @@
6 * 6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9#if ENABLE_PLATFORM_MINGW32
10# define MNTENT_PRIVATE
11#endif
9#include "libbb.h" 12#include "libbb.h"
10#include <mntent.h> 13#include <mntent.h>
11 14
@@ -19,14 +22,22 @@
19struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) 22struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
20{ 23{
21 struct stat s; 24 struct stat s;
25#if !ENABLE_PLATFORM_MINGW32
22 FILE *mtab_fp; 26 FILE *mtab_fp;
23 struct mntent *mountEntry; 27 struct mntent *mountEntry;
24 dev_t devno_of_name; 28 dev_t devno_of_name;
25 bool block_dev; 29 bool block_dev;
30#else
31 struct mntent *mountEntry;
32 static struct mntdata *data = NULL;
33 char *current;
34 const char *path;
35#endif
26 36
27 if (stat(name, &s) != 0) 37 if (stat(name, &s) != 0)
28 return NULL; 38 return NULL;
29 39
40#if !ENABLE_PLATFORM_MINGW32
30 devno_of_name = s.st_dev; 41 devno_of_name = s.st_dev;
31 block_dev = 0; 42 block_dev = 0;
32 /* Why S_ISCHR? - UBI volumes use char devices, not block */ 43 /* Why S_ISCHR? - UBI volumes use char devices, not block */
@@ -74,6 +85,26 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
74 } 85 }
75 } 86 }
76 endmntent(mtab_fp); 87 endmntent(mtab_fp);
88#else
89 mountEntry = NULL;
90 path = NULL;
91 current = NULL;
92
93 if ( isalpha(name[0]) && name[1] == ':' ) {
94 path = name;
95 } else {
96 path = current = xrealloc_getcwd_or_warn(NULL);
97 }
98
99 if ( path && isalpha(path[0]) && path[1] == ':' ) {
100 if (data == NULL)
101 data = xmalloc(sizeof(*data));
102
103 fill_mntdata(data, toupper(path[0]) - 'A');
104 mountEntry = &data->me;
105 }
106 free(current);
107#endif
77 108
78 return mountEntry; 109 return mountEntry;
79} 110}
diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c
index fe13f7211..0b6d5a206 100644
--- a/libbb/find_pid_by_name.c
+++ b/libbb/find_pid_by_name.c
@@ -39,8 +39,10 @@ and therefore comm field contains "exe".
39 39
40static int comm_match(procps_status_t *p, const char *procName) 40static int comm_match(procps_status_t *p, const char *procName)
41{ 41{
42#if !ENABLE_PLATFORM_MINGW32
42 int argv1idx; 43 int argv1idx;
43 const char *argv1; 44 const char *argv1;
45#endif
44 46
45 if (strncmp(p->comm, procName, 15) != 0) 47 if (strncmp(p->comm, procName, 15) != 0)
46 return 0; /* comm does not match */ 48 return 0; /* comm does not match */
@@ -55,6 +57,7 @@ static int comm_match(procps_status_t *p, const char *procName)
55 * This can be crazily_long_script_name.sh! 57 * This can be crazily_long_script_name.sh!
56 * The telltale sign is basename(argv[1]) == procName */ 58 * The telltale sign is basename(argv[1]) == procName */
57 59
60#if !ENABLE_PLATFORM_MINGW32
58 if (!p->argv0) 61 if (!p->argv0)
59 return 0; 62 return 0;
60 63
@@ -65,6 +68,7 @@ static int comm_match(procps_status_t *p, const char *procName)
65 68
66 if (strcmp(bb_basename(argv1), procName) != 0) 69 if (strcmp(bb_basename(argv1), procName) != 0)
67 return 0; 70 return 0;
71#endif
68 72
69 return 1; 73 return 1;
70} 74}
@@ -87,6 +91,7 @@ pid_t* FAST_FUNC find_pid_by_name(const char *procName)
87 pidList = xzalloc(sizeof(*pidList)); 91 pidList = xzalloc(sizeof(*pidList));
88 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN|PSSCAN_EXE))) { 92 while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_COMM|PSSCAN_ARGVN|PSSCAN_EXE))) {
89 if (comm_match(p, procName) 93 if (comm_match(p, procName)
94#if !ENABLE_PLATFORM_MINGW32
90 /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/ 95 /* or we require argv0 to match (essential for matching reexeced /proc/self/exe)*/
91 || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0) 96 || (p->argv0 && strcmp(bb_basename(p->argv0), procName) == 0)
92 /* or we require /proc/PID/exe link to match */ 97 /* or we require /proc/PID/exe link to match */
@@ -95,6 +100,7 @@ pid_t* FAST_FUNC find_pid_by_name(const char *procName)
95 : bb_basename(p->exe), 100 : bb_basename(p->exe),
96 procName 101 procName
97 ) == 0) 102 ) == 0)
103#endif
98 ) { 104 ) {
99 pidList = xrealloc_vector(pidList, 2, i); 105 pidList = xrealloc_vector(pidList, 2, i);
100 pidList[i++] = p->pid; 106 pidList[i++] = p->pid;
diff --git a/libbb/get_last_path_component.c b/libbb/get_last_path_component.c
index 04fdf2a3e..46a87d7fc 100644
--- a/libbb/get_last_path_component.c
+++ b/libbb/get_last_path_component.c
@@ -10,12 +10,34 @@
10 10
11const char* FAST_FUNC bb_basename(const char *name) 11const char* FAST_FUNC bb_basename(const char *name)
12{ 12{
13#if ENABLE_PLATFORM_MINGW32
14 const char *cp;
15 for (cp = name; *cp; cp++)
16 if (*cp == '/' || *cp == '\\' || *cp == ':')
17 name = cp + 1;
18#else
13 const char *cp = strrchr(name, '/'); 19 const char *cp = strrchr(name, '/');
14 if (cp) 20 if (cp)
15 return cp + 1; 21 return cp + 1;
22#endif
16 return name; 23 return name;
17} 24}
18 25
26#if ENABLE_PLATFORM_MINGW32
27char * FAST_FUNC get_last_slash(const char *path)
28{
29 const char *start = path + root_len(path);
30 char *slash = strrchr(start, '/');
31 char *bslash = strrchr(start, '\\');
32
33 if (slash && bslash)
34 slash = MAX(slash, bslash);
35 else if (!slash)
36 slash = bslash;
37 return slash;
38}
39#endif
40
19/* 41/*
20 * "/" -> "/" 42 * "/" -> "/"
21 * "abc" -> "abc" 43 * "abc" -> "abc"
@@ -24,10 +46,20 @@ const char* FAST_FUNC bb_basename(const char *name)
24 */ 46 */
25char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path) 47char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path)
26{ 48{
49#if ENABLE_PLATFORM_MINGW32
50 const char *start = path + root_len(path);
51 char *slash = get_last_slash(path);
52
53 if (!slash && has_dos_drive_prefix(path) && path[2] != '\0')
54 return (char *)path + 2;
55 if (!slash || (slash == start && !slash[1]))
56 return (char*)path;
57#else
27 char *slash = strrchr(path, '/'); 58 char *slash = strrchr(path, '/');
28 59
29 if (!slash || (slash == path && !slash[1])) 60 if (!slash || (slash == path && !slash[1]))
30 return (char*)path; 61 return (char*)path;
62#endif
31 63
32 return slash + 1; 64 return slash + 1;
33} 65}
@@ -40,11 +72,20 @@ char* FAST_FUNC bb_get_last_path_component_nostrip(const char *path)
40 */ 72 */
41char* FAST_FUNC bb_get_last_path_component_strip(char *path) 73char* FAST_FUNC bb_get_last_path_component_strip(char *path)
42{ 74{
75#if ENABLE_PLATFORM_MINGW32
76 char *slash = last_char_is_dir_sep(path);
77 const char *start = has_dos_drive_prefix(path) ? path+2 : path;
78
79 if (slash)
80 while (is_dir_sep(*slash) && slash != start)
81 *slash-- = '\0';
82#else
43 char *slash = last_char_is(path, '/'); 83 char *slash = last_char_is(path, '/');
44 84
45 if (slash) 85 if (slash)
46 while (*slash == '/' && slash != path) 86 while (*slash == '/' && slash != path)
47 *slash-- = '\0'; 87 *slash-- = '\0';
88#endif
48 89
49 return bb_get_last_path_component_nostrip(path); 90 return bb_get_last_path_component_nostrip(path);
50} 91}
diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c
index 903ff1fb6..2142ec94c 100644
--- a/libbb/get_line_from_file.c
+++ b/libbb/get_line_from_file.c
@@ -16,7 +16,11 @@ char* FAST_FUNC bb_get_chunk_from_file(FILE *file, size_t *end)
16 size_t idx = 0; 16 size_t idx = 0;
17 char *linebuf = NULL; 17 char *linebuf = NULL;
18 18
19#if ENABLE_PLATFORM_MINGW32
20 while ((ch = _getc_nolock(file)) != EOF) {
21#else
19 while ((ch = getc(file)) != EOF) { 22 while ((ch = getc(file)) != EOF) {
23#endif
20 /* grow the line buffer as necessary */ 24 /* grow the line buffer as necessary */
21 if (!(idx & 0xff)) { 25 if (!(idx & 0xff)) {
22 if (idx == ((size_t)-1) - 0xff) 26 if (idx == ((size_t)-1) - 0xff)
@@ -41,6 +45,11 @@ char* FAST_FUNC bb_get_chunk_from_file(FILE *file, size_t *end)
41 linebuf = xrealloc(linebuf, idx + 1); 45 linebuf = xrealloc(linebuf, idx + 1);
42 linebuf[idx] = '\0'; 46 linebuf[idx] = '\0';
43 } 47 }
48#if ENABLE_PLATFORM_MINGW32
49 if (idx && isatty(fileno(file)) &&
50 GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)
51 conToCharBuffA(linebuf, idx);
52#endif
44 return linebuf; 53 return linebuf;
45} 54}
46 55
@@ -57,8 +66,17 @@ char* FAST_FUNC xmalloc_fgetline(FILE *file)
57 size_t i; 66 size_t i;
58 char *c = bb_get_chunk_from_file(file, &i); 67 char *c = bb_get_chunk_from_file(file, &i);
59 68
69#if !ENABLE_PLATFORM_MINGW32
60 if (i && c[--i] == '\n') 70 if (i && c[--i] == '\n')
61 c[i] = '\0'; 71 c[i] = '\0';
72#else
73 if (i && c[--i] == '\n') {
74 c[i] = '\0';
75 if (i && c[--i] == '\r') {
76 c[i] = '\0';
77 }
78 }
79#endif
62 80
63 return c; 81 return c;
64} 82}
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index b5efa19ac..76d29d5eb 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -592,7 +592,7 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options,
592 return (int32_t)-1; 592 return (int32_t)-1;
593} 593}
594 594
595uint32_t FAST_FUNC 595uint32_t
596getopt32(char **argv, const char *applet_opts, ...) 596getopt32(char **argv, const char *applet_opts, ...)
597{ 597{
598 uint32_t opt; 598 uint32_t opt;
@@ -605,7 +605,7 @@ getopt32(char **argv, const char *applet_opts, ...)
605} 605}
606 606
607#if ENABLE_LONG_OPTS 607#if ENABLE_LONG_OPTS
608uint32_t FAST_FUNC 608uint32_t
609getopt32long(char **argv, const char *applet_opts, const char *longopts, ...) 609getopt32long(char **argv, const char *applet_opts, const char *longopts, ...)
610{ 610{
611 uint32_t opt; 611 uint32_t opt;
diff --git a/libbb/herror_msg.c b/libbb/herror_msg.c
index a7dd98679..09537ae92 100644
--- a/libbb/herror_msg.c
+++ b/libbb/herror_msg.c
@@ -8,7 +8,7 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11void FAST_FUNC bb_herror_msg(const char *s, ...) 11void bb_herror_msg(const char *s, ...)
12{ 12{
13 va_list p; 13 va_list p;
14 14
@@ -17,7 +17,7 @@ void FAST_FUNC bb_herror_msg(const char *s, ...)
17 va_end(p); 17 va_end(p);
18} 18}
19 19
20void FAST_FUNC bb_herror_msg_and_die(const char *s, ...) 20void bb_herror_msg_and_die(const char *s, ...)
21{ 21{
22 va_list p; 22 va_list p;
23 23
diff --git a/libbb/human_readable.c b/libbb/human_readable.c
index 09221a186..3199ede6e 100644
--- a/libbb/human_readable.c
+++ b/libbb/human_readable.c
@@ -38,7 +38,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
38 if (val == 0) 38 if (val == 0)
39 return "0"; 39 return "0";
40 40
41 fmt = "%llu"; 41 fmt = "%"LL_FMT"u";
42 if (block_size > 1) 42 if (block_size > 1)
43 val *= block_size; 43 val *= block_size;
44 frac = 0; 44 frac = 0;
@@ -52,7 +52,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
52 while ((val >= 1024) 52 while ((val >= 1024)
53 /* && (u < unit_chars + sizeof(unit_chars) - 1) - always true */ 53 /* && (u < unit_chars + sizeof(unit_chars) - 1) - always true */
54 ) { 54 ) {
55 fmt = "%llu.%u%c"; 55 fmt = "%"LL_FMT"u.%u%c";
56 u++; 56 u++;
57 frac = (((unsigned)val % 1024) * 10 + 1024/2) / 1024; 57 frac = (((unsigned)val % 1024) * 10 + 1024/2) / 1024;
58 val /= 1024; 58 val /= 1024;
@@ -67,7 +67,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
67 if (frac >= 5) { 67 if (frac >= 5) {
68 ++val; 68 ++val;
69 } 69 }
70 fmt = "%llu%*c"; 70 fmt = "%"LL_FMT"u%*c";
71 frac = 1; 71 frac = 1;
72 } 72 }
73#endif 73#endif
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
index a125244ca..f2cc417bc 100644
--- a/libbb/inode_hash.c
+++ b/libbb/inode_hash.c
@@ -61,6 +61,11 @@ void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *
61 int i; 61 int i;
62 ino_dev_hashtable_bucket_t *bucket; 62 ino_dev_hashtable_bucket_t *bucket;
63 63
64#if ENABLE_FEATURE_EXTRA_FILE_DATA
65 /* ignore invalid inode numbers */
66 if (statbuf->st_ino == 0)
67 return;
68#endif
64 if (!name) 69 if (!name)
65 name = ""; 70 name = "";
66 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name)); 71 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name));
diff --git a/libbb/last_char_is.c b/libbb/last_char_is.c
index fba05f974..c2cd92174 100644
--- a/libbb/last_char_is.c
+++ b/libbb/last_char_is.c
@@ -17,3 +17,14 @@ char* FAST_FUNC last_char_is(const char *s, int c)
17 s++; 17 s++;
18 return (*s == (char)c) ? (char *) s : NULL; 18 return (*s == (char)c) ? (char *) s : NULL;
19} 19}
20
21#if ENABLE_PLATFORM_MINGW32
22char* FAST_FUNC last_char_is_dir_sep(const char *s)
23{
24 if (!s[0])
25 return NULL;
26 while (s[1])
27 s++;
28 return is_dir_sep(*s)? (char *) s : NULL;
29}
30#endif
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 151208c1c..8e2b37853 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -258,8 +258,14 @@ static NOINLINE const char *get_homedir_or_NULL(void)
258# else 258# else
259 home = getenv("HOME"); 259 home = getenv("HOME");
260# endif 260# endif
261 if (home != NULL && home[0] != '\0') 261 if (home != NULL && home[0] != '\0') {
262# if ENABLE_PLATFORM_MINGW32
263 char *t = auto_string(xstrdup(home));
264 bs_to_slash(t);
265 home = t;
266# endif
262 return home; 267 return home;
268 }
263 269
264 if (!got_user_strings) 270 if (!got_user_strings)
265 get_user_strings(); 271 get_user_strings();
@@ -413,7 +419,7 @@ int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
413/* Put 'command_ps[cursor]', cursor++. 419/* Put 'command_ps[cursor]', cursor++.
414 * Advance cursor on screen. If we reached right margin, scroll text up 420 * Advance cursor on screen. If we reached right margin, scroll text up
415 * and remove terminal margin effect by printing 'next_char' */ 421 * and remove terminal margin effect by printing 'next_char' */
416#define HACK_FOR_WRONG_WIDTH 1 422#define HACK_FOR_WRONG_WIDTH 1 && !ENABLE_PLATFORM_MINGW32
417static void put_cur_glyph_and_inc_cursor(void) 423static void put_cur_glyph_and_inc_cursor(void)
418{ 424{
419 CHAR_T c = command_ps[cursor]; 425 CHAR_T c = command_ps[cursor];
@@ -476,6 +482,42 @@ static void put_cur_glyph_and_inc_cursor(void)
476 } 482 }
477} 483}
478 484
485#if ENABLE_PLATFORM_MINGW32
486static void inc_cursor(void)
487{
488 CHAR_T c = command_ps[cursor];
489 unsigned width = 0;
490 int ofs_to_right;
491
492 /* advance cursor */
493 cursor++;
494 if (unicode_status == UNICODE_ON) {
495 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
496 c = adjust_width_and_validate_wc(&cmdedit_x, c);
497 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
498 } else {
499 cmdedit_x++;
500 }
501
502 ofs_to_right = cmdedit_x - cmdedit_termw;
503 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
504 /* cursor remains on this line */
505 printf(ESC"[1C");
506 }
507
508 if (ofs_to_right >= 0) {
509 /* we go to the next line */
510 printf(ESC"[1B");
511 bb_putchar('\r');
512 cmdedit_y++;
513 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
514 width = 0;
515 }
516 cmdedit_x = width;
517 }
518}
519#endif
520
479/* Move to end of line (by printing all chars till the end) */ 521/* Move to end of line (by printing all chars till the end) */
480static void put_till_end_and_adv_cursor(void) 522static void put_till_end_and_adv_cursor(void)
481{ 523{
@@ -538,6 +580,7 @@ static void input_backward(unsigned num)
538 580
539 if (cmdedit_x >= num) { 581 if (cmdedit_x >= num) {
540 cmdedit_x -= num; 582 cmdedit_x -= num;
583#if !ENABLE_PLATFORM_MINGW32
541 if (num <= 4) { 584 if (num <= 4) {
542 /* This is longer by 5 bytes on x86. 585 /* This is longer by 5 bytes on x86.
543 * Also gets miscompiled for ARM users 586 * Also gets miscompiled for ARM users
@@ -550,6 +593,7 @@ static void input_backward(unsigned num)
550 } while (--num); 593 } while (--num);
551 return; 594 return;
552 } 595 }
596#endif
553 fprintf(stderr, ESC"[%uD", num); 597 fprintf(stderr, ESC"[%uD", num);
554 return; 598 return;
555 } 599 }
@@ -688,7 +732,23 @@ static void input_backspace(void)
688static void input_forward(void) 732static void input_forward(void)
689{ 733{
690 if (cursor < command_len) 734 if (cursor < command_len)
735#if !ENABLE_PLATFORM_MINGW32
691 put_cur_glyph_and_inc_cursor(); 736 put_cur_glyph_and_inc_cursor();
737#else
738 /*
739 * inc_cursor improves forward cursor movement appearance on
740 * win 7/8 console, but it's broken with unicode wide-glyphs,
741 * e.g. paste and move forward over: echo 开开心心过每一天
742 * so disable inc_cursor when unicode is active (which is only
743 * windows 10+, where inc_cursor is not needed anyway).
744 */
745 {
746 if (unicode_status == UNICODE_ON)
747 put_cur_glyph_and_inc_cursor();
748 else
749 inc_cursor();
750 }
751#endif
692} 752}
693 753
694#if ENABLE_FEATURE_TAB_COMPLETION 754#if ENABLE_FEATURE_TAB_COMPLETION
@@ -709,25 +769,56 @@ static void free_tab_completion_data(void)
709 } 769 }
710} 770}
711 771
712static void add_match(char *matched) 772#if !ENABLE_PLATFORM_MINGW32
773# define add_match(m, s) add_match(m)
774#endif
775
776static void add_match(char *matched, int sensitive)
713{ 777{
778# if ENABLE_PLATFORM_MINGW32
779 size_t len;
780# endif
714 unsigned char *p = (unsigned char*)matched; 781 unsigned char *p = (unsigned char*)matched;
715 while (*p) { 782 while (*p) {
716 /* ESC attack fix: drop any string with control chars */ 783 /* ESC attack fix: drop any string with control chars */
717 if (*p < ' ' 784 if (*p < ' '
785# if !ENABLE_PLATFORM_MINGW32
718 || (!ENABLE_UNICODE_SUPPORT && *p >= 0x7f) 786 || (!ENABLE_UNICODE_SUPPORT && *p >= 0x7f)
719 || (ENABLE_UNICODE_SUPPORT && *p == 0x7f) 787 || (ENABLE_UNICODE_SUPPORT && *p == 0x7f)
788# else
789 /*
790 * on Windows, *p > 0x7f is never control:
791 * without unicode active: these are normal codepage chars.
792 * with unicode active: these are UTF8 continuation bytes.
793 */
794 || *p == 0x7f
795# endif
720 ) { 796 ) {
721 free(matched); 797 free(matched);
722 return; 798 return;
723 } 799 }
724 p++; 800 p++;
725 } 801 }
802# if ENABLE_PLATFORM_MINGW32
803 /* The case-sensitivity flag is stored after NUL terminator */
804 len = strlen(matched);
805 matched = xrealloc(matched, len + 2);
806 matched[len + 1] = sensitive;
807# endif
726 matches = xrealloc_vector(matches, 4, num_matches); 808 matches = xrealloc_vector(matches, 4, num_matches);
727 matches[num_matches] = matched; 809 matches[num_matches] = matched;
728 num_matches++; 810 num_matches++;
729} 811}
730 812
813# if ENABLE_PLATFORM_MINGW32
814static int is_case_sensitive(const char *p)
815{
816 while (*p++)
817 ;
818 return *p;
819}
820# endif
821
731# if ENABLE_FEATURE_USERNAME_COMPLETION 822# if ENABLE_FEATURE_USERNAME_COMPLETION
732/* Replace "~user/..." with "/homedir/...". 823/* Replace "~user/..." with "/homedir/...".
733 * The parameter is malloced, free it or return it 824 * The parameter is malloced, free it or return it
@@ -735,13 +826,16 @@ static void add_match(char *matched)
735 */ 826 */
736static char *username_path_completion(char *ud) 827static char *username_path_completion(char *ud)
737{ 828{
829# if !ENABLE_PLATFORM_MINGW32
738 struct passwd *entry; 830 struct passwd *entry;
831#endif
739 char *tilde_name = ud; 832 char *tilde_name = ud;
740 const char *home = NULL; 833 const char *home = NULL;
741 834
742 ud++; /* skip ~ */ 835 ud++; /* skip ~ */
743 if (*ud == '/') { /* "~/..." */ 836 if (*ud == '/') { /* "~/..." */
744 home = get_homedir_or_NULL(); 837 home = get_homedir_or_NULL();
838# if !ENABLE_PLATFORM_MINGW32
745 } else { 839 } else {
746 /* "~user/..." */ 840 /* "~user/..." */
747 ud = strchr(ud, '/'); 841 ud = strchr(ud, '/');
@@ -750,6 +844,7 @@ static char *username_path_completion(char *ud)
750 *ud = '/'; /* restore "~user/..." */ 844 *ud = '/'; /* restore "~user/..." */
751 if (entry) 845 if (entry)
752 home = entry->pw_dir; 846 home = entry->pw_dir;
847# endif
753 } 848 }
754 if (home) { 849 if (home) {
755 ud = concat_path_file(home, ud); 850 ud = concat_path_file(home, ud);
@@ -759,6 +854,7 @@ static char *username_path_completion(char *ud)
759 return tilde_name; 854 return tilde_name;
760} 855}
761 856
857# if !ENABLE_PLATFORM_MINGW32
762/* ~use<tab> - find all users with this prefix. 858/* ~use<tab> - find all users with this prefix.
763 * Return the length of the prefix used for matching. 859 * Return the length of the prefix used for matching.
764 */ 860 */
@@ -774,13 +870,14 @@ static NOINLINE unsigned complete_username(const char *ud)
774 while ((pw = getpwent()) != NULL) { 870 while ((pw = getpwent()) != NULL) {
775 /* Null usernames should result in all users as possible completions. */ 871 /* Null usernames should result in all users as possible completions. */
776 if (/* !ud[0] || */ is_prefixed_with(pw->pw_name, ud)) { 872 if (/* !ud[0] || */ is_prefixed_with(pw->pw_name, ud)) {
777 add_match(xasprintf("~%s/", pw->pw_name)); 873 add_match(xasprintf("~%s/", pw->pw_name), TRUE);
778 } 874 }
779 } 875 }
780 endpwent(); /* don't keep password file open */ 876 endpwent(); /* don't keep password file open */
781 877
782 return 1 + userlen; 878 return 1 + userlen;
783} 879}
880# endif
784# endif /* FEATURE_USERNAME_COMPLETION */ 881# endif /* FEATURE_USERNAME_COMPLETION */
785 882
786enum { 883enum {
@@ -810,7 +907,7 @@ static unsigned path_parse(char ***p)
810 tmp = (char*)pth; 907 tmp = (char*)pth;
811 npth = 1; /* path component count */ 908 npth = 1; /* path component count */
812 while (1) { 909 while (1) {
813 tmp = strchr(tmp, ':'); 910 tmp = strchr(tmp, PATH_SEP);
814 if (!tmp) 911 if (!tmp)
815 break; 912 break;
816 tmp++; 913 tmp++;
@@ -821,7 +918,7 @@ static unsigned path_parse(char ***p)
821 res[0] = tmp = xstrdup(pth); 918 res[0] = tmp = xstrdup(pth);
822 npth = 1; 919 npth = 1;
823 while (1) { 920 while (1) {
824 tmp = strchr(tmp, ':'); 921 tmp = strchr(tmp, PATH_SEP);
825 if (!tmp) 922 if (!tmp)
826 break; 923 break;
827 *tmp++ = '\0'; /* ':' -> '\0' */ 924 *tmp++ = '\0'; /* ':' -> '\0' */
@@ -849,6 +946,17 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
849 path1[0] = (char*)"."; 946 path1[0] = (char*)".";
850 947
851 basecmd = strrchr(command, '/'); 948 basecmd = strrchr(command, '/');
949#if ENABLE_PLATFORM_MINGW32
950 if (!basecmd && has_dos_drive_prefix(command) && command[2] != '\0') {
951 char buffer[PATH_MAX];
952
953 /* path is of form c:path with no '/' */
954 if (get_drive_cwd(command, buffer, PATH_MAX)) {
955 basecmd = command + 2;
956 path1[0] = dirbuf = xstrdup(buffer);
957 }
958 } else
959#endif
852 if (!basecmd) { 960 if (!basecmd) {
853 if (type == FIND_EXE_ONLY) 961 if (type == FIND_EXE_ONLY)
854 npaths = path_parse(&paths); 962 npaths = path_parse(&paths);
@@ -869,9 +977,13 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
869 if (type == FIND_EXE_ONLY && !dirbuf) { 977 if (type == FIND_EXE_ONLY && !dirbuf) {
870# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 978# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
871 const char *p = applet_names; 979 const char *p = applet_names;
980# if ENABLE_PLATFORM_MINGW32
981 const char *shpath = state->flags & WITH_PATH_LOOKUP ?
982 state->path_lookup : NULL;
983# endif
872 while (*p) { 984 while (*p) {
873 if (strncmp(basecmd, p, baselen) == 0) 985 if (strncmp(basecmd, p, baselen) == 0 && prefer_applet(p, shpath))
874 add_match(xstrdup(p)); 986 add_match(xstrdup(p), TRUE);
875 while (*p++ != '\0') 987 while (*p++ != '\0')
876 continue; 988 continue;
877 } 989 }
@@ -884,7 +996,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
884 if (!b) 996 if (!b)
885 break; 997 break;
886 if (strncmp(basecmd, b, baselen) == 0) 998 if (strncmp(basecmd, b, baselen) == 0)
887 add_match(xstrdup(b)); 999 add_match(xstrdup(b), TRUE);
888 } 1000 }
889 } 1001 }
890# endif 1002# endif
@@ -918,7 +1030,11 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
918 if (!basecmd[0] && DOT_OR_DOTDOT(name_found)) 1030 if (!basecmd[0] && DOT_OR_DOTDOT(name_found))
919 continue; 1031 continue;
920 /* match? */ 1032 /* match? */
1033# if ENABLE_PLATFORM_MINGW32
1034 if (strncasecmp(basecmd, name_found, baselen) != 0)
1035# else
921 if (strncmp(basecmd, name_found, baselen) != 0) 1036 if (strncmp(basecmd, name_found, baselen) != 0)
1037# endif
922 continue; /* no */ 1038 continue; /* no */
923 1039
924 found = concat_path_file(lpath, name_found); 1040 found = concat_path_file(lpath, name_found);
@@ -928,6 +1044,16 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
928 if (stat(found, &st) && lstat(found, &st)) 1044 if (stat(found, &st) && lstat(found, &st))
929 goto cont; /* hmm, remove in progress? */ 1045 goto cont; /* hmm, remove in progress? */
930 1046
1047# if ENABLE_PLATFORM_MINGW32
1048# if ENABLE_ASH_GLOB_OPTIONS
1049 if (state->sh_accept_glob && !state->sh_accept_glob(found))
1050 goto cont;
1051# endif
1052 if (type == FIND_EXE_ONLY && S_ISREG(st.st_mode) &&
1053 !(st.st_mode & S_IXUSR))
1054 goto cont;
1055# endif
1056
931 /* Save only name */ 1057 /* Save only name */
932 len = strlen(name_found); 1058 len = strlen(name_found);
933 found = xrealloc(found, len + 2); /* +2: for slash and NUL */ 1059 found = xrealloc(found, len + 2); /* +2: for slash and NUL */
@@ -946,7 +1072,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
946 goto cont; 1072 goto cont;
947 } 1073 }
948 /* add it to the list */ 1074 /* add it to the list */
949 add_match(found); 1075 add_match(found, FALSE);
950 continue; 1076 continue;
951 cont: 1077 cont:
952 free(found); 1078 free(found);
@@ -1011,7 +1137,13 @@ static NOINLINE int build_match_prefix(char *match_buf)
1011 1137
1012 /* Mark every \c as "quoted c" */ 1138 /* Mark every \c as "quoted c" */
1013 for (i = 0; int_buf[i]; i++) { 1139 for (i = 0; int_buf[i]; i++) {
1140#if ENABLE_PLATFORM_MINGW32
1141 /* Trailing backslash is effectively removed which confuses
1142 * the code to display case-preserved filenames. */
1143 if (int_buf[i] == '\\' && int_buf[i+1] != '\0') {
1144#else
1014 if (int_buf[i] == '\\') { 1145 if (int_buf[i] == '\\') {
1146#endif
1015 remove_chunk(int_buf, i, i + 1); 1147 remove_chunk(int_buf, i, i + 1);
1016 int_buf[i] |= QUOT; 1148 int_buf[i] |= QUOT;
1017 } 1149 }
@@ -1212,6 +1344,25 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1212 size_t len_found; 1344 size_t len_found;
1213 /* Length of string used for matching */ 1345 /* Length of string used for matching */
1214 unsigned match_pfx_len = match_pfx_len; 1346 unsigned match_pfx_len = match_pfx_len;
1347# if ENABLE_PLATFORM_MINGW32
1348 int chosen_index = 0;
1349 int chosen_sens = FALSE;
1350# if !ENABLE_UNICODE_SUPPORT
1351 /*
1352 * FIXME: the next three vars are unused with ENABLE_UNICODE_SUPPORT
1353 * because the mingw code which uses them to update a tab-completion
1354 * prefix to the correct case (e.g. ~/desk<tab> to ~/Desktop/) is
1355 * not compiled, and so e.g. ~/desk<tab> completes to ~/desktop/ .
1356 */
1357 unsigned orig_pfx_len;
1358 char *target;
1359 const char *source;
1360# endif
1361# define first_match 0
1362# else
1363# define chosen_index 0
1364# define first_match 1
1365# endif
1215 int find_type; 1366 int find_type;
1216# if ENABLE_UNICODE_SUPPORT 1367# if ENABLE_UNICODE_SUPPORT
1217 /* cursor pos in command converted to multibyte form */ 1368 /* cursor pos in command converted to multibyte form */
@@ -1259,7 +1410,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1259 /* Free up any memory already allocated */ 1410 /* Free up any memory already allocated */
1260 free_tab_completion_data(); 1411 free_tab_completion_data();
1261 1412
1262# if ENABLE_FEATURE_USERNAME_COMPLETION 1413# if ENABLE_FEATURE_USERNAME_COMPLETION && !ENABLE_PLATFORM_MINGW32
1263 /* If the word starts with ~ and there is no slash in the word, 1414 /* If the word starts with ~ and there is no slash in the word,
1264 * then try completing this word as a username. */ 1415 * then try completing this word as a username. */
1265 if (state->flags & USERNAME_COMPLETION) 1416 if (state->flags & USERNAME_COMPLETION)
@@ -1276,6 +1427,9 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1276 { 1427 {
1277 const char *e = match_buf + strlen(match_buf); 1428 const char *e = match_buf + strlen(match_buf);
1278 const char *s = e - match_pfx_len; 1429 const char *s = e - match_pfx_len;
1430# if ENABLE_PLATFORM_MINGW32 && !ENABLE_UNICODE_SUPPORT
1431 orig_pfx_len = match_pfx_len;
1432# endif
1279 while (s < e) 1433 while (s < e)
1280 if (is_special_char(*s++)) 1434 if (is_special_char(*s++))
1281 match_pfx_len++; 1435 match_pfx_len++;
@@ -1306,10 +1460,29 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1306 if (!matches) 1460 if (!matches)
1307 goto ret; /* no matches at all */ 1461 goto ret; /* no matches at all */
1308 /* Find common prefix */ 1462 /* Find common prefix */
1309 chosen_match = xstrdup(matches[0]); 1463# if ENABLE_PLATFORM_MINGW32
1464 /* Any comparison involving a filename must be case-insensitive.
1465 * The chosen match should be case-sensitive, if possible */
1466 for (unsigned i = 0; i < num_matches; ++i) {
1467 if (is_case_sensitive(matches[i])) {
1468 chosen_index = i;
1469 chosen_sens = TRUE;
1470 break;
1471 }
1472 }
1473# endif
1474 chosen_match = xstrdup(matches[chosen_index]);
1310 for (cp = chosen_match; *cp; cp++) { 1475 for (cp = chosen_match; *cp; cp++) {
1311 unsigned n; 1476 unsigned n;
1312 for (n = 1; n < num_matches; n++) { 1477 for (n = first_match; n < num_matches; n++) {
1478# if ENABLE_PLATFORM_MINGW32
1479 if (!is_case_sensitive(matches[n]) || !chosen_sens) {
1480 if (tolower(matches[n][cp - chosen_match]) !=
1481 tolower(*cp)) {
1482 goto stop;
1483 }
1484 } else
1485# endif
1313 if (matches[n][cp - chosen_match] != *cp) { 1486 if (matches[n][cp - chosen_match] != *cp) {
1314 goto stop; 1487 goto stop;
1315 } 1488 }
@@ -1346,7 +1519,21 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1346 /* save tail */ 1519 /* save tail */
1347 strcpy(match_buf, &command_ps[cursor]); 1520 strcpy(match_buf, &command_ps[cursor]);
1348 /* add match and tail */ 1521 /* add match and tail */
1522# if ENABLE_PLATFORM_MINGW32
1523 if (match_pfx_len == orig_pfx_len) {
1524 /* replace match prefix to allow for altered case */
1525 target = &command_ps[cursor-match_pfx_len];
1526 source = chosen_match;
1527 }
1528 else {
1529 /* only replace tail of match if special characters are quoted */
1530 target = &command_ps[cursor];
1531 source = chosen_match + match_pfx_len;
1532 }
1533 strcpy(stpcpy(target, source), match_buf);
1534# else
1349 sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf); 1535 sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf);
1536# endif
1350 command_len = strlen(command_ps); 1537 command_len = strlen(command_ps);
1351 /* new pos */ 1538 /* new pos */
1352 pos = cursor + len_found - match_pfx_len; 1539 pos = cursor + len_found - match_pfx_len;
@@ -1382,7 +1569,6 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1382 free(chosen_match); 1569 free(chosen_match);
1383 free(match_buf); 1570 free(match_buf);
1384} 1571}
1385
1386#endif /* FEATURE_TAB_COMPLETION */ 1572#endif /* FEATURE_TAB_COMPLETION */
1387 1573
1388 1574
@@ -1402,7 +1588,11 @@ line_input_t* FAST_FUNC new_line_input_t(int flags)
1402 1588
1403unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) 1589unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp)
1404{ 1590{
1591# if ENABLE_PLATFORM_MINGW32 && DEFAULT_HISTORY > 0 && DEFAULT_HISTORY <= MAX_HISTORY
1592 int size = DEFAULT_HISTORY;
1593# else
1405 int size = MAX_HISTORY; 1594 int size = MAX_HISTORY;
1595# endif
1406 if (hp) { 1596 if (hp) {
1407 size = atoi(hp); 1597 size = atoi(hp);
1408 if (size <= 0) 1598 if (size <= 0)
@@ -2053,7 +2243,11 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2053 char *after_home_user; 2243 char *after_home_user;
2054 2244
2055 /* /home/user[/something] -> ~[/something] */ 2245 /* /home/user[/something] -> ~[/something] */
2246#if !ENABLE_PLATFORM_MINGW32
2056 after_home_user = is_prefixed_with(cwd_buf, home); 2247 after_home_user = is_prefixed_with(cwd_buf, home);
2248#else
2249 after_home_user = is_prefixed_with_case(cwd_buf, home);
2250#endif
2057 if (after_home_user 2251 if (after_home_user
2058 && (*after_home_user == '/' || *after_home_user == '\0') 2252 && (*after_home_user == '/' || *after_home_user == '\0')
2059 ) { 2253 ) {
@@ -2484,7 +2678,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2484 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 2678 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0
2485 | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */ 2679 | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */
2486 ); 2680 );
2681#if !ENABLE_PLATFORM_MINGW32
2487 if (n != 0 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON) { 2682 if (n != 0 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON) {
2683#else
2684 if (n != 0 || !isatty(0)) {
2685#endif
2488 /* Happens when e.g. stty -echo was run before. 2686 /* Happens when e.g. stty -echo was run before.
2489 * But if ICANON is not set, we don't come here. 2687 * But if ICANON is not set, we don't come here.
2490 * (example: interactive python ^Z-backgrounded, 2688 * (example: interactive python ^Z-backgrounded,
@@ -2494,8 +2692,12 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2494 fflush_all(); 2692 fflush_all();
2495 if (fgets(command, maxsize, stdin) == NULL) 2693 if (fgets(command, maxsize, stdin) == NULL)
2496 len = -1; /* EOF or error */ 2694 len = -1; /* EOF or error */
2497 else 2695 else {
2498 len = strlen(command); 2696 len = strlen(command);
2697#if ENABLE_PLATFORM_MINGW32
2698 len = remove_cr(command, len);
2699#endif
2700 }
2499 DEINIT_S(); 2701 DEINIT_S();
2500 return len; 2702 return len;
2501 } 2703 }
@@ -2577,6 +2779,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2577 } 2779 }
2578#endif 2780#endif
2579 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); 2781 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
2782#if ENABLE_PLATFORM_MINGW32
2783 /* scroll to cursor position on any keypress */
2784 if (isatty(fileno(stdin)) && isatty(fileno(stdout)))
2785 move_cursor_row(0);
2786#endif
2580 2787
2581#if ENABLE_FEATURE_REVERSE_SEARCH 2788#if ENABLE_FEATURE_REVERSE_SEARCH
2582 again: 2789 again:
@@ -2638,6 +2845,17 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2638 input_tab(&lastWasTab); 2845 input_tab(&lastWasTab);
2639 break; 2846 break;
2640#endif 2847#endif
2848#if ENABLE_PLATFORM_MINGW32
2849 case CTRL('Z'):
2850 command_ps[command_len] = '\0';
2851 #if ENABLE_UNICODE_SUPPORT
2852 bs_to_slash_u(command_ps);
2853 #else
2854 bs_to_slash(command_ps);
2855 #endif
2856 redraw(cmdedit_y, 0);
2857 break;
2858#endif
2641 case CTRL('K'): 2859 case CTRL('K'):
2642 /* Control-k -- clear to end of line */ 2860 /* Control-k -- clear to end of line */
2643 command_ps[cursor] = BB_NUL; 2861 command_ps[cursor] = BB_NUL;
@@ -2892,6 +3110,10 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2892 && ic_raw == initial_settings.c_cc[VINTR] 3110 && ic_raw == initial_settings.c_cc[VINTR]
2893 ) { 3111 ) {
2894 /* Ctrl-C (usually) - stop gathering input */ 3112 /* Ctrl-C (usually) - stop gathering input */
3113#if ENABLE_PLATFORM_MINGW32
3114 if (state->flags & IGNORE_CTRL_C)
3115 break;
3116#endif
2895 command_len = 0; 3117 command_len = 0;
2896 break_out = -1; /* "do not append '\n'" */ 3118 break_out = -1; /* "do not append '\n'" */
2897 break; 3119 break;
diff --git a/libbb/make_directory.c b/libbb/make_directory.c
index 9b03bb8d0..e0fd486d8 100644
--- a/libbb/make_directory.c
+++ b/libbb/make_directory.c
@@ -49,11 +49,19 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
49 } 49 }
50 50
51 org_mask = cur_mask = (mode_t)-1L; 51 org_mask = cur_mask = (mode_t)-1L;
52#if ENABLE_PLATFORM_MINGW32
53 /* normalise path separators, path is already assumed writable */
54 bs_to_slash(path);
55#endif
52 s = path; 56 s = path;
53 while (1) { 57 while (1) {
54 c = '\0'; 58 c = '\0';
55 59
56 if (flags & FILEUTILS_RECUR) { /* Get the parent */ 60 if (flags & FILEUTILS_RECUR) { /* Get the parent */
61#if ENABLE_PLATFORM_MINGW32
62 if (s == path)
63 s += root_len(path);
64#endif
57 /* Bypass leading non-'/'s and then subsequent '/'s */ 65 /* Bypass leading non-'/'s and then subsequent '/'s */
58 while (*s) { 66 while (*s) {
59 if (*s == '/') { 67 if (*s == '/') {
diff --git a/libbb/messages.c b/libbb/messages.c
index 6914d5701..311eda004 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -5,6 +5,9 @@
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */ 6 */
7#include "libbb.h" 7#include "libbb.h"
8#if ENABLE_PLATFORM_MINGW32
9# include "BB_VER.h"
10#endif
8 11
9/* allow version to be extended, via CFLAGS */ 12/* allow version to be extended, via CFLAGS */
10#ifndef BB_EXTRA_VERSION 13#ifndef BB_EXTRA_VERSION
@@ -27,7 +30,26 @@ const char bb_msg_standard_output[] ALIGN1 = "standard output";
27 30
28const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; 31const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
29 32
33#if !ENABLE_PLATFORM_MINGW32
30const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; 34const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH;
35#else
36/* Some special shell variables are placed in the environment immediately
37 * when they're exported.
38 *
39 * BB_GLOBBING and BB_UMASK are excluded because users shouldn't be
40 * messing with them; BB_FIX_BACKSLASH is excluded because it only
41 * affects particular applets, not the shell itself.
42 *
43 * If you change any of these you should also update the definitions in
44 * include/libbb.h.
45 */
46const char bbvar[] ALIGN1 =
47 "BB_OVERRIDE_APPLETS\0" \
48 "BB_SKIP_ANSI_EMULATION\0" \
49 "BB_TERMINAL_MODE\0" \
50 "BB_SYSTEMROOT\0" \
51 "BB_CRITICAL_ERROR_DIALOGS\0";
52#endif
31const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; 53const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
32/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, 54/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
33 * but I want to save a few bytes here. Check libbb.h before changing! */ 55 * but I want to save a few bytes here. Check libbb.h before changing! */
diff --git a/libbb/mode_string.c b/libbb/mode_string.c
index 52abe66f7..906c03964 100644
--- a/libbb/mode_string.c
+++ b/libbb/mode_string.c
@@ -19,7 +19,7 @@
19/* Generate ls-style "mode string" like "-rwsr-xr-x" or "drwxrwxrwt" */ 19/* Generate ls-style "mode string" like "-rwsr-xr-x" or "drwxrwxrwt" */
20 20
21#if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \ 21#if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \
22 || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 ) \ 22 || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 && S_IFBLK != 0030000 ) \
23 || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \ 23 || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \
24 || ( S_IFIFO != 0010000 ) 24 || ( S_IFIFO != 0010000 )
25# warning mode type bitflag value assumption(s) violated! falling back to larger version 25# warning mode type bitflag value assumption(s) violated! falling back to larger version
diff --git a/libbb/parse_config.c b/libbb/parse_config.c
index 8701b010c..bcd667c7c 100644
--- a/libbb/parse_config.c
+++ b/libbb/parse_config.c
@@ -113,8 +113,17 @@ static int get_line_with_continuation(parser_t *parser)
113 line = parser->line; 113 line = parser->line;
114 for (;;) { 114 for (;;) {
115 parser->lineno++; 115 parser->lineno++;
116#if !ENABLE_PLATFORM_MINGW32
116 if (line[len - 1] == '\n') 117 if (line[len - 1] == '\n')
117 len--; 118 len--;
119#else
120 if (line[len - 1] == '\n') {
121 len--;
122 if (len != 0 && line[len - 1] == '\r') {
123 len--;
124 }
125 }
126#endif
118 if (len == 0 || line[len - 1] != '\\') 127 if (len == 0 || line[len - 1] != '\\')
119 break; 128 break;
120 len--; 129 len--;
diff --git a/libbb/perror_msg.c b/libbb/perror_msg.c
index fa1f0d339..32adb8c38 100644
--- a/libbb/perror_msg.c
+++ b/libbb/perror_msg.c
@@ -8,7 +8,7 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11void FAST_FUNC bb_perror_msg(const char *s, ...) 11void bb_perror_msg(const char *s, ...)
12{ 12{
13 va_list p; 13 va_list p;
14 14
@@ -18,7 +18,7 @@ void FAST_FUNC bb_perror_msg(const char *s, ...)
18 va_end(p); 18 va_end(p);
19} 19}
20 20
21void FAST_FUNC bb_perror_msg_and_die(const char *s, ...) 21void bb_perror_msg_and_die(const char *s, ...)
22{ 22{
23 va_list p; 23 va_list p;
24 24
diff --git a/libbb/printable_string.c b/libbb/printable_string.c
index a814fd03c..2e8895a4f 100644
--- a/libbb/printable_string.c
+++ b/libbb/printable_string.c
@@ -42,7 +42,7 @@ const char* FAST_FUNC printable_string2(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 f56b71b21..8c9cac125 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -63,6 +63,7 @@ const char* FAST_FUNC get_cached_groupname(gid_t gid)
63 return get_cached(1, gid, gid2group_utoa); 63 return get_cached(1, gid, gid2group_utoa);
64} 64}
65 65
66#if !ENABLE_PLATFORM_MINGW32
66 67
67#define PROCPS_BUFSIZE 1024 68#define PROCPS_BUFSIZE 1024
68 69
@@ -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_key.c b/libbb/read_key.c
index cf8ed411e..54886cc9c 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -112,6 +112,11 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
112 0 112 0
113 }; 113 };
114 114
115#if ENABLE_PLATFORM_MINGW32
116 if (!(terminal_mode(FALSE) & VT_INPUT))
117 return windows_read_key(fd, buffer, timeout);
118#endif
119
115 pfd.fd = fd; 120 pfd.fd = fd;
116 pfd.events = POLLIN; 121 pfd.events = POLLIN;
117 122
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index 0cd04ab7b..379dd2448 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/signals.c b/libbb/signals.c
index 0bebc847d..c09a562ed 100644
--- a/libbb/signals.c
+++ b/libbb/signals.c
@@ -18,6 +18,7 @@ void record_signo(int signo)
18 bb_got_signal = signo; 18 bb_got_signal = signo;
19} 19}
20 20
21#if !ENABLE_PLATFORM_MINGW32
21/* Saves 2 bytes on x86! Oh my... */ 22/* Saves 2 bytes on x86! Oh my... */
22int FAST_FUNC sigaction_set(int signum, const struct sigaction *act) 23int FAST_FUNC sigaction_set(int signum, const struct sigaction *act)
23{ 24{
@@ -40,6 +41,7 @@ int FAST_FUNC sigprocmask2(int how, sigset_t *set)
40 oset = set; 41 oset = set;
41 return sigprocmask(how, set, oset); 42 return sigprocmask(how, set, oset);
42} 43}
44#endif
43 45
44void FAST_FUNC bb_signals(int sigs, void (*f)(int)) 46void FAST_FUNC bb_signals(int sigs, void (*f)(int))
45{ 47{
diff --git a/libbb/time.c b/libbb/time.c
index f09ef5d52..e7c9fa65e 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -44,12 +44,21 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
44 save = *ptm; 44 save = *ptm;
45 fmt = fmt_str; 45 fmt = fmt_str;
46 while (*fmt) { 46 while (*fmt) {
47#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_TIMEZONE
48 long gmtoff;
49 endp = mingw_strptime(date_str, fmt, ptm, &gmtoff);
50#else
47 endp = strptime(date_str, fmt, ptm); 51 endp = strptime(date_str, fmt, ptm);
52#endif
48 if (endp && *endp == '\0') { 53 if (endp && *endp == '\0') {
49# if ENABLE_FEATURE_TIMEZONE 54# if ENABLE_FEATURE_TIMEZONE
50 if (strchr(fmt, 'z')) { 55 if (strchr(fmt, 'z')) {
51 /* we have timezone offset: obtain Unix time_t */ 56 /* we have timezone offset: obtain Unix time_t */
57#if ENABLE_PLATFORM_MINGW32
58 ptm->tm_sec -= gmtoff;
59#else
52 ptm->tm_sec -= ptm->tm_gmtoff; 60 ptm->tm_sec -= ptm->tm_gmtoff;
61#endif
53 ptm->tm_isdst = 0; 62 ptm->tm_isdst = 0;
54 t = timegm(ptm); 63 t = timegm(ptm);
55 if (t == (time_t)-1) 64 if (t == (time_t)-1)
diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c
index f7d598c7a..ef2b6f891 100644
--- a/libbb/u_signal_names.c
+++ b/libbb/u_signal_names.c
@@ -27,10 +27,23 @@
27 27
28#include "libbb.h" 28#include "libbb.h"
29 29
30#if ENABLE_PLATFORM_MINGW32
31# undef SIGPIPE
32#endif
33
34#if ENABLE_PLATFORM_POSIX || defined(SIGSTKFLT) || defined(SIGVTALRM)
35# define SIGLEN 7
36#elif defined(SIGWINCH) || (ENABLE_FEATURE_RTMINMAX && \
37 !ENABLE_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS && defined(__SIGRTMIN))
38# define SIGLEN 6
39#else
40# define SIGLEN 5
41#endif
42
30/* Believe it or not, but some arches have more than 32 SIGs! 43/* Believe it or not, but some arches have more than 32 SIGs!
31 * HPPA: SIGSTKFLT == 36. */ 44 * HPPA: SIGSTKFLT == 36. */
32 45
33static const char signals[][7] ALIGN1 = { 46static const char signals[][SIGLEN] ALIGN1 = {
34 // SUSv3 says kill must support these, and specifies the numerical values, 47 // SUSv3 says kill must support these, and specifies the numerical values,
35 // http://www.opengroup.org/onlinepubs/009695399/utilities/kill.html 48 // http://www.opengroup.org/onlinepubs/009695399/utilities/kill.html
36 // {0, "EXIT"}, {1, "HUP"}, {2, "INT"}, {3, "QUIT"}, 49 // {0, "EXIT"}, {1, "HUP"}, {2, "INT"}, {3, "QUIT"},
diff --git a/libbb/unicode.c b/libbb/unicode.c
index e98cbbf35..acc7cd8df 100644
--- a/libbb/unicode.c
+++ b/libbb/unicode.c
@@ -69,8 +69,14 @@ void FAST_FUNC init_unicode(void)
69void FAST_FUNC reinit_unicode(const char *LANG) 69void FAST_FUNC reinit_unicode(const char *LANG)
70{ 70{
71 unicode_status = UNICODE_OFF; 71 unicode_status = UNICODE_OFF;
72#if ENABLE_PLATFORM_MINGW32
73 /* enable unicode only when ACP is UTF8 and the env var is not 'C' */
74 if (GetACP() != CP_UTF8 || (LANG && LANG[0] == 'C' && LANG[1] == 0))
75 return;
76#else
72 if (!LANG || !(strstr(LANG, ".utf") || strstr(LANG, ".UTF"))) 77 if (!LANG || !(strstr(LANG, ".utf") || strstr(LANG, ".UTF")))
73 return; 78 return;
79#endif
74 unicode_status = UNICODE_ON; 80 unicode_status = UNICODE_ON;
75} 81}
76 82
@@ -270,7 +276,9 @@ int FAST_FUNC iswpunct(wint_t wc)
270 return (unsigned)wc <= 0x7f && ispunct(wc); 276 return (unsigned)wc <= 0x7f && ispunct(wc);
271} 277}
272 278
279#define WCWIDTH_ALT (ENABLE_PLATFORM_MINGW32 && CONFIG_LAST_SUPPORTED_WCHAR >= 0x30000)
273 280
281# if !WCWIDTH_ALT || ENABLE_UNICODE_BIDI_SUPPORT
274# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300 282# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x300
275struct interval { 283struct interval {
276 uint16_t first; 284 uint16_t first;
@@ -327,7 +335,9 @@ static int in_uint16_table(unsigned ucs, const uint16_t *table, unsigned max)
327 return 0; 335 return 0;
328} 336}
329# endif 337# endif
338# endif /* !WCWIDTH_ALT || ENABLE_UNICODE_BIDI_SUPPORT */
330 339
340# if !WCWIDTH_ALT
331 341
332/* 342/*
333 * This is an implementation of wcwidth() and wcswidth() (defined in 343 * This is an implementation of wcwidth() and wcswidth() (defined in
@@ -697,6 +707,9 @@ int FAST_FUNC wcwidth(unsigned ucs)
697# endif /* >= 0x300 */ 707# endif /* >= 0x300 */
698} 708}
699 709
710# else /* WCWIDTH_ALT */
711# include "wcwidth_alt.c" /* simpler and more up-to-date implementation */
712# endif
700 713
701# if ENABLE_UNICODE_BIDI_SUPPORT 714# if ENABLE_UNICODE_BIDI_SUPPORT
702int FAST_FUNC unicode_bidi_isrtl(wint_t wc) 715int FAST_FUNC unicode_bidi_isrtl(wint_t wc)
diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c
index 74b608f4c..7c167d912 100644
--- a/libbb/verror_msg.c
+++ b/libbb/verror_msg.c
@@ -156,7 +156,7 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
156#endif 156#endif
157 157
158 158
159void FAST_FUNC bb_error_msg_and_die(const char *s, ...) 159void bb_error_msg_and_die(const char *s, ...)
160{ 160{
161 va_list p; 161 va_list p;
162 162
@@ -166,7 +166,7 @@ void FAST_FUNC bb_error_msg_and_die(const char *s, ...)
166 xfunc_die(); 166 xfunc_die();
167} 167}
168 168
169void FAST_FUNC bb_error_msg(const char *s, ...) 169void bb_error_msg(const char *s, ...)
170{ 170{
171 va_list p; 171 va_list p;
172 172
@@ -183,7 +183,7 @@ void FAST_FUNC bb_vinfo_msg(const char *s, va_list p)
183 syslog_level = LOG_ERR; 183 syslog_level = LOG_ERR;
184} 184}
185 185
186void FAST_FUNC bb_info_msg(const char *s, ...) 186void bb_info_msg(const char *s, ...)
187{ 187{
188 va_list p; 188 va_list p;
189 189
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 2055c4b71..dad50ddb9 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -171,6 +171,7 @@ void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv)
171 * Higher-level code, hiding optional NOFORK/NOEXEC trickery. 171 * Higher-level code, hiding optional NOFORK/NOEXEC trickery.
172 */ 172 */
173 173
174#if !ENABLE_PLATFORM_MINGW32
174/* This does a fork/exec in one call, using vfork(). Returns PID of new child, 175/* This does a fork/exec in one call, using vfork(). Returns PID of new child,
175 * -1 for failure. Runs argv[0], searching path if that has no / in it. */ 176 * -1 for failure. Runs argv[0], searching path if that has no / in it. */
176pid_t FAST_FUNC spawn(char **argv) 177pid_t FAST_FUNC spawn(char **argv)
@@ -212,6 +213,7 @@ pid_t FAST_FUNC spawn(char **argv)
212 } 213 }
213 return pid; 214 return pid;
214} 215}
216#endif
215 217
216/* Die with an error message if we can't spawn a child process. */ 218/* Die with an error message if we can't spawn a child process. */
217pid_t FAST_FUNC xspawn(char **argv) 219pid_t FAST_FUNC xspawn(char **argv)
@@ -232,6 +234,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
232 if (APPLET_IS_NOFORK(a)) 234 if (APPLET_IS_NOFORK(a))
233 return run_nofork_applet(a, argv); 235 return run_nofork_applet(a, argv);
234# if BB_MMU /* NOEXEC needs fork(), thus this is done only on MMU machines: */ 236# if BB_MMU /* NOEXEC needs fork(), thus this is done only on MMU machines: */
237# if !ENABLE_PLATFORM_MINGW32 /* and then only if not on Microsoft Windows */
235 if (APPLET_IS_NOEXEC(a)) { 238 if (APPLET_IS_NOEXEC(a)) {
236 fflush_all(); 239 fflush_all();
237 rc = fork(); 240 rc = fork();
@@ -241,6 +244,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
241 /* child */ 244 /* child */
242 run_noexec_applet_and_exit(a, argv[0], argv); 245 run_noexec_applet_and_exit(a, argv[0], argv);
243 } 246 }
247# endif
244# endif 248# endif
245 } 249 }
246#endif 250#endif
@@ -248,6 +252,7 @@ int FAST_FUNC spawn_and_wait(char **argv)
248 return wait4pid(rc); 252 return wait4pid(rc);
249} 253}
250 254
255#if !ENABLE_PLATFORM_MINGW32
251#if !BB_MMU 256#if !BB_MMU
252void FAST_FUNC re_exec(char **argv) 257void FAST_FUNC re_exec(char **argv)
253{ 258{
@@ -340,3 +345,4 @@ void FAST_FUNC bb_sanitize_stdio(void)
340{ 345{
341 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL); 346 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
342} 347}
348#endif /* !MINGW32 */
diff --git a/libbb/wcwidth_alt.c b/libbb/wcwidth_alt.c
new file mode 100644
index 000000000..9a45ab0e9
--- /dev/null
+++ b/libbb/wcwidth_alt.c
@@ -0,0 +1,506 @@
1/* wcwidth - Unicode 15.1.0, generated by scripts/mkwcwidth.
2 * Copyright (C) 2024 Avi Halachmi <avihpit at yahoo.com>
3 * License: MIT
4 *
5 * Data imported on 2024-03-29 from https://github.com/jquast/wcwidth
6 * commit 0.2.13-3-g056ee4b (2024-02-14 15:05:06 -0500)
7 */
8int FAST_FUNC wcwidth(uint32_t ucs)
9{
10 /* sorted ranges, "first" is clipped to 16 bit, and its high bits
11 * (plane) are deduced from the "planes" array below.
12 * (imported from table_zero.py and table_wide.py)
13 */
14 static const struct range {
15 uint16_t first;
16 uint16_t iswide: 1; /* bitfield order empirically faster */
17 uint16_t difflast: 15;
18 } ranges[] = {
19 #define R(first, last, width) {first & 0xffff, width/2, last-first}
20 R(0x000000, 0x000000, 0), /* nil */
21 R(0x0000ad, 0x0000ad, 0), /* Soft Hyphen */
22 R(0x000300, 0x00036f, 0), /* Combining Grave Accent ..Combining Latin Small Le */
23 R(0x000483, 0x000489, 0), /* Combining Cyrillic Titlo..Combining Cyrillic Milli */
24 R(0x000591, 0x0005bd, 0), /* Hebrew Accent Etnahta ..Hebrew Point Meteg */
25 R(0x0005bf, 0x0005bf, 0), /* Hebrew Point Rafe */
26 R(0x0005c1, 0x0005c2, 0), /* Hebrew Point Shin Dot ..Hebrew Point Sin Dot */
27 R(0x0005c4, 0x0005c5, 0), /* Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot */
28 R(0x0005c7, 0x0005c7, 0), /* Hebrew Point Qamats Qatan */
29 R(0x000600, 0x000605, 0), /* Arabic Number Sign ..Arabic Number Mark Above */
30 R(0x000610, 0x00061a, 0), /* Arabic Sign Sallallahou ..Arabic Small Kasra */
31 R(0x00061c, 0x00061c, 0), /* Arabic Letter Mark */
32 R(0x00064b, 0x00065f, 0), /* Arabic Fathatan ..Arabic Wavy Hamza Below */
33 R(0x000670, 0x000670, 0), /* Arabic Letter Superscript Alef */
34 R(0x0006d6, 0x0006dd, 0), /* Arabic Small High Ligatu..Arabic End Of Ayah */
35 R(0x0006df, 0x0006e4, 0), /* Arabic Small High Rounde..Arabic Small High Madda */
36 R(0x0006e7, 0x0006e8, 0), /* Arabic Small High Yeh ..Arabic Small High Noon */
37 R(0x0006ea, 0x0006ed, 0), /* Arabic Empty Centre Low ..Arabic Small Low Meem */
38 R(0x00070f, 0x00070f, 0), /* Syriac Abbreviation Mark */
39 R(0x000711, 0x000711, 0), /* Syriac Letter Superscript Alaph */
40 R(0x000730, 0x00074a, 0), /* Syriac Pthaha Above ..Syriac Barrekh */
41 R(0x0007a6, 0x0007b0, 0), /* Thaana Abafili ..Thaana Sukun */
42 R(0x0007eb, 0x0007f3, 0), /* Nko Combining Short High..Nko Combining Double Dot */
43 R(0x0007fd, 0x0007fd, 0), /* Nko Dantayalan */
44 R(0x000816, 0x000819, 0), /* Samaritan Mark In ..Samaritan Mark Dagesh */
45 R(0x00081b, 0x000823, 0), /* Samaritan Mark Epentheti..Samaritan Vowel Sign A */
46 R(0x000825, 0x000827, 0), /* Samaritan Vowel Sign Sho..Samaritan Vowel Sign U */
47 R(0x000829, 0x00082d, 0), /* Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa */
48 R(0x000859, 0x00085b, 0), /* Mandaic Affrication Mark..Mandaic Gemination Mark */
49 R(0x000890, 0x000891, 0), /* Arabic Pound Mark Above ..Arabic Piastre Mark Abov */
50 R(0x000898, 0x00089f, 0), /* Arabic Small High Word A..Arabic Half Madda Over M */
51 R(0x0008ca, 0x000903, 0), /* Arabic Small High Farsi ..Devanagari Sign Visarga */
52 R(0x00093a, 0x00093c, 0), /* Devanagari Vowel Sign Oe..Devanagari Sign Nukta */
53 R(0x00093e, 0x00094f, 0), /* Devanagari Vowel Sign Aa..Devanagari Vowel Sign Aw */
54 R(0x000951, 0x000957, 0), /* Devanagari Stress Sign U..Devanagari Vowel Sign Uu */
55 R(0x000962, 0x000963, 0), /* Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo */
56 R(0x000981, 0x000983, 0), /* Bengali Sign Candrabindu..Bengali Sign Visarga */
57 R(0x0009bc, 0x0009bc, 0), /* Bengali Sign Nukta */
58 R(0x0009be, 0x0009c4, 0), /* Bengali Vowel Sign Aa ..Bengali Vowel Sign Vocal */
59 R(0x0009c7, 0x0009c8, 0), /* Bengali Vowel Sign E ..Bengali Vowel Sign Ai */
60 R(0x0009cb, 0x0009cd, 0), /* Bengali Vowel Sign O ..Bengali Sign Virama */
61 R(0x0009d7, 0x0009d7, 0), /* Bengali Au Length Mark */
62 R(0x0009e2, 0x0009e3, 0), /* Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal */
63 R(0x0009fe, 0x0009fe, 0), /* Bengali Sandhi Mark */
64 R(0x000a01, 0x000a03, 0), /* Gurmukhi Sign Adak Bindi..Gurmukhi Sign Visarga */
65 R(0x000a3c, 0x000a3c, 0), /* Gurmukhi Sign Nukta */
66 R(0x000a3e, 0x000a42, 0), /* Gurmukhi Vowel Sign Aa ..Gurmukhi Vowel Sign Uu */
67 R(0x000a47, 0x000a48, 0), /* Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai */
68 R(0x000a4b, 0x000a4d, 0), /* Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama */
69 R(0x000a51, 0x000a51, 0), /* Gurmukhi Sign Udaat */
70 R(0x000a70, 0x000a71, 0), /* Gurmukhi Tippi ..Gurmukhi Addak */
71 R(0x000a75, 0x000a75, 0), /* Gurmukhi Sign Yakash */
72 R(0x000a81, 0x000a83, 0), /* Gujarati Sign Candrabind..Gujarati Sign Visarga */
73 R(0x000abc, 0x000abc, 0), /* Gujarati Sign Nukta */
74 R(0x000abe, 0x000ac5, 0), /* Gujarati Vowel Sign Aa ..Gujarati Vowel Sign Cand */
75 R(0x000ac7, 0x000ac9, 0), /* Gujarati Vowel Sign E ..Gujarati Vowel Sign Cand */
76 R(0x000acb, 0x000acd, 0), /* Gujarati Vowel Sign O ..Gujarati Sign Virama */
77 R(0x000ae2, 0x000ae3, 0), /* Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca */
78 R(0x000afa, 0x000aff, 0), /* Gujarati Sign Sukun ..Gujarati Sign Two-circle */
79 R(0x000b01, 0x000b03, 0), /* Oriya Sign Candrabindu ..Oriya Sign Visarga */
80 R(0x000b3c, 0x000b3c, 0), /* Oriya Sign Nukta */
81 R(0x000b3e, 0x000b44, 0), /* Oriya Vowel Sign Aa ..Oriya Vowel Sign Vocalic */
82 R(0x000b47, 0x000b48, 0), /* Oriya Vowel Sign E ..Oriya Vowel Sign Ai */
83 R(0x000b4b, 0x000b4d, 0), /* Oriya Vowel Sign O ..Oriya Sign Virama */
84 R(0x000b55, 0x000b57, 0), /* Oriya Sign Overline ..Oriya Au Length Mark */
85 R(0x000b62, 0x000b63, 0), /* Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic */
86 R(0x000b82, 0x000b82, 0), /* Tamil Sign Anusvara */
87 R(0x000bbe, 0x000bc2, 0), /* Tamil Vowel Sign Aa ..Tamil Vowel Sign Uu */
88 R(0x000bc6, 0x000bc8, 0), /* Tamil Vowel Sign E ..Tamil Vowel Sign Ai */
89 R(0x000bca, 0x000bcd, 0), /* Tamil Vowel Sign O ..Tamil Sign Virama */
90 R(0x000bd7, 0x000bd7, 0), /* Tamil Au Length Mark */
91 R(0x000c00, 0x000c04, 0), /* Telugu Sign Combining Ca..Telugu Sign Combining An */
92 R(0x000c3c, 0x000c3c, 0), /* Telugu Sign Nukta */
93 R(0x000c3e, 0x000c44, 0), /* Telugu Vowel Sign Aa ..Telugu Vowel Sign Vocali */
94 R(0x000c46, 0x000c48, 0), /* Telugu Vowel Sign E ..Telugu Vowel Sign Ai */
95 R(0x000c4a, 0x000c4d, 0), /* Telugu Vowel Sign O ..Telugu Sign Virama */
96 R(0x000c55, 0x000c56, 0), /* Telugu Length Mark ..Telugu Ai Length Mark */
97 R(0x000c62, 0x000c63, 0), /* Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali */
98 R(0x000c81, 0x000c83, 0), /* Kannada Sign Candrabindu..Kannada Sign Visarga */
99 R(0x000cbc, 0x000cbc, 0), /* Kannada Sign Nukta */
100 R(0x000cbe, 0x000cc4, 0), /* Kannada Vowel Sign Aa ..Kannada Vowel Sign Vocal */
101 R(0x000cc6, 0x000cc8, 0), /* Kannada Vowel Sign E ..Kannada Vowel Sign Ai */
102 R(0x000cca, 0x000ccd, 0), /* Kannada Vowel Sign O ..Kannada Sign Virama */
103 R(0x000cd5, 0x000cd6, 0), /* Kannada Length Mark ..Kannada Ai Length Mark */
104 R(0x000ce2, 0x000ce3, 0), /* Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal */
105 R(0x000cf3, 0x000cf3, 0), /* Kannada Sign Combining Anusvara Above Right */
106 R(0x000d00, 0x000d03, 0), /* Malayalam Sign Combining..Malayalam Sign Visarga */
107 R(0x000d3b, 0x000d3c, 0), /* Malayalam Sign Vertical ..Malayalam Sign Circular */
108 R(0x000d3e, 0x000d44, 0), /* Malayalam Vowel Sign Aa ..Malayalam Vowel Sign Voc */
109 R(0x000d46, 0x000d48, 0), /* Malayalam Vowel Sign E ..Malayalam Vowel Sign Ai */
110 R(0x000d4a, 0x000d4d, 0), /* Malayalam Vowel Sign O ..Malayalam Sign Virama */
111 R(0x000d57, 0x000d57, 0), /* Malayalam Au Length Mark */
112 R(0x000d62, 0x000d63, 0), /* Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc */
113 R(0x000d81, 0x000d83, 0), /* Sinhala Sign Candrabindu..Sinhala Sign Visargaya */
114 R(0x000dca, 0x000dca, 0), /* Sinhala Sign Al-lakuna */
115 R(0x000dcf, 0x000dd4, 0), /* Sinhala Vowel Sign Aela-..Sinhala Vowel Sign Ketti */
116 R(0x000dd6, 0x000dd6, 0), /* Sinhala Vowel Sign Diga Paa-pilla */
117 R(0x000dd8, 0x000ddf, 0), /* Sinhala Vowel Sign Gaett..Sinhala Vowel Sign Gayan */
118 R(0x000df2, 0x000df3, 0), /* Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga */
119 R(0x000e31, 0x000e31, 0), /* Thai Character Mai Han-akat */
120 R(0x000e34, 0x000e3a, 0), /* Thai Character Sara I ..Thai Character Phinthu */
121 R(0x000e47, 0x000e4e, 0), /* Thai Character Maitaikhu..Thai Character Yamakkan */
122 R(0x000eb1, 0x000eb1, 0), /* Lao Vowel Sign Mai Kan */
123 R(0x000eb4, 0x000ebc, 0), /* Lao Vowel Sign I ..Lao Semivowel Sign Lo */
124 R(0x000ec8, 0x000ece, 0), /* Lao Tone Mai Ek ..Lao Yamakkan */
125 R(0x000f18, 0x000f19, 0), /* Tibetan Astrological Sig..Tibetan Astrological Sig */
126 R(0x000f35, 0x000f35, 0), /* Tibetan Mark Ngas Bzung Nyi Zla */
127 R(0x000f37, 0x000f37, 0), /* Tibetan Mark Ngas Bzung Sgor Rtags */
128 R(0x000f39, 0x000f39, 0), /* Tibetan Mark Tsa -phru */
129 R(0x000f3e, 0x000f3f, 0), /* Tibetan Sign Yar Tshes ..Tibetan Sign Mar Tshes */
130 R(0x000f71, 0x000f84, 0), /* Tibetan Vowel Sign Aa ..Tibetan Mark Halanta */
131 R(0x000f86, 0x000f87, 0), /* Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags */
132 R(0x000f8d, 0x000f97, 0), /* Tibetan Subjoined Sign L..Tibetan Subjoined Letter */
133 R(0x000f99, 0x000fbc, 0), /* Tibetan Subjoined Letter..Tibetan Subjoined Letter */
134 R(0x000fc6, 0x000fc6, 0), /* Tibetan Symbol Padma Gdan */
135 R(0x00102b, 0x00103e, 0), /* Myanmar Vowel Sign Tall ..Myanmar Consonant Sign M */
136 R(0x001056, 0x001059, 0), /* Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal */
137 R(0x00105e, 0x001060, 0), /* Myanmar Consonant Sign M..Myanmar Consonant Sign M */
138 R(0x001062, 0x001064, 0), /* Myanmar Vowel Sign Sgaw ..Myanmar Tone Mark Sgaw K */
139 R(0x001067, 0x00106d, 0), /* Myanmar Vowel Sign Weste..Myanmar Sign Western Pwo */
140 R(0x001071, 0x001074, 0), /* Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah */
141 R(0x001082, 0x00108d, 0), /* Myanmar Consonant Sign S..Myanmar Sign Shan Counci */
142 R(0x00108f, 0x00108f, 0), /* Myanmar Sign Rumai Palaung Tone-5 */
143 R(0x00109a, 0x00109d, 0), /* Myanmar Sign Khamti Tone..Myanmar Vowel Sign Aiton */
144 R(0x001100, 0x00115f, 2), /* Hangul Choseong Kiyeok ..Hangul Choseong Filler */
145 R(0x001160, 0x0011ff, 0), /* Hangul Jungseong Filler ..Hangul Jongseong Ssangni */
146 R(0x00135d, 0x00135f, 0), /* Ethiopic Combining Gemin..Ethiopic Combining Gemin */
147 R(0x001712, 0x001715, 0), /* Tagalog Vowel Sign I ..Tagalog Sign Pamudpod */
148 R(0x001732, 0x001734, 0), /* Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod */
149 R(0x001752, 0x001753, 0), /* Buhid Vowel Sign I ..Buhid Vowel Sign U */
150 R(0x001772, 0x001773, 0), /* Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U */
151 R(0x0017b4, 0x0017d3, 0), /* Khmer Vowel Inherent Aq ..Khmer Sign Bathamasat */
152 R(0x0017dd, 0x0017dd, 0), /* Khmer Sign Atthacan */
153 R(0x00180b, 0x00180f, 0), /* Mongolian Free Variation..Mongolian Free Variation */
154 R(0x001885, 0x001886, 0), /* Mongolian Letter Ali Gal..Mongolian Letter Ali Gal */
155 R(0x0018a9, 0x0018a9, 0), /* Mongolian Letter Ali Gali Dagalga */
156 R(0x001920, 0x00192b, 0), /* Limbu Vowel Sign A ..Limbu Subjoined Letter W */
157 R(0x001930, 0x00193b, 0), /* Limbu Small Letter Ka ..Limbu Sign Sa-i */
158 R(0x001a17, 0x001a1b, 0), /* Buginese Vowel Sign I ..Buginese Vowel Sign Ae */
159 R(0x001a55, 0x001a5e, 0), /* Tai Tham Consonant Sign ..Tai Tham Consonant Sign */
160 R(0x001a60, 0x001a7c, 0), /* Tai Tham Sign Sakot ..Tai Tham Sign Khuen-lue */
161 R(0x001a7f, 0x001a7f, 0), /* Tai Tham Combining Cryptogrammic Dot */
162 R(0x001ab0, 0x001ace, 0), /* Combining Doubled Circum..Combining Latin Small Le */
163 R(0x001b00, 0x001b04, 0), /* Balinese Sign Ulu Ricem ..Balinese Sign Bisah */
164 R(0x001b34, 0x001b44, 0), /* Balinese Sign Rerekan ..Balinese Adeg Adeg */
165 R(0x001b6b, 0x001b73, 0), /* Balinese Musical Symbol ..Balinese Musical Symbol */
166 R(0x001b80, 0x001b82, 0), /* Sundanese Sign Panyecek ..Sundanese Sign Pangwisad */
167 R(0x001ba1, 0x001bad, 0), /* Sundanese Consonant Sign..Sundanese Consonant Sign */
168 R(0x001be6, 0x001bf3, 0), /* Batak Sign Tompi ..Batak Panongonan */
169 R(0x001c24, 0x001c37, 0), /* Lepcha Subjoined Letter ..Lepcha Sign Nukta */
170 R(0x001cd0, 0x001cd2, 0), /* Vedic Tone Karshana ..Vedic Tone Prenkha */
171 R(0x001cd4, 0x001ce8, 0), /* Vedic Sign Yajurvedic Mi..Vedic Sign Visarga Anuda */
172 R(0x001ced, 0x001ced, 0), /* Vedic Sign Tiryak */
173 R(0x001cf4, 0x001cf4, 0), /* Vedic Tone Candra Above */
174 R(0x001cf7, 0x001cf9, 0), /* Vedic Sign Atikrama ..Vedic Tone Double Ring A */
175 R(0x001dc0, 0x001dff, 0), /* Combining Dotted Grave A..Combining Right Arrowhea */
176 R(0x00200b, 0x00200f, 0), /* Zero Width Space ..Right-to-left Mark */
177 R(0x002028, 0x00202e, 0), /* Line Separator ..Right-to-left Override */
178 R(0x002060, 0x002064, 0), /* Word Joiner ..Invisible Plus */
179 R(0x002066, 0x00206f, 0), /* Left-to-right Isolate ..Nominal Digit Shapes */
180 R(0x0020d0, 0x0020f0, 0), /* Combining Left Harpoon A..Combining Asterisk Above */
181 R(0x00231a, 0x00231b, 2), /* Watch ..Hourglass */
182 R(0x002329, 0x00232a, 2), /* Left-pointing Angle Brac..Right-pointing Angle Bra */
183 R(0x0023e9, 0x0023ec, 2), /* Black Right-pointing Dou..Black Down-pointing Doub */
184 R(0x0023f0, 0x0023f0, 2), /* Alarm Clock */
185 R(0x0023f3, 0x0023f3, 2), /* Hourglass With Flowing Sand */
186 R(0x0025fd, 0x0025fe, 2), /* White Medium Small Squar..Black Medium Small Squar */
187 R(0x002614, 0x002615, 2), /* Umbrella With Rain Drops..Hot Beverage */
188 R(0x002648, 0x002653, 2), /* Aries ..Pisces */
189 R(0x00267f, 0x00267f, 2), /* Wheelchair Symbol */
190 R(0x002693, 0x002693, 2), /* Anchor */
191 R(0x0026a1, 0x0026a1, 2), /* High Voltage Sign */
192 R(0x0026aa, 0x0026ab, 2), /* Medium White Circle ..Medium Black Circle */
193 R(0x0026bd, 0x0026be, 2), /* Soccer Ball ..Baseball */
194 R(0x0026c4, 0x0026c5, 2), /* Snowman Without Snow ..Sun Behind Cloud */
195 R(0x0026ce, 0x0026ce, 2), /* Ophiuchus */
196 R(0x0026d4, 0x0026d4, 2), /* No Entry */
197 R(0x0026ea, 0x0026ea, 2), /* Church */
198 R(0x0026f2, 0x0026f3, 2), /* Fountain ..Flag In Hole */
199 R(0x0026f5, 0x0026f5, 2), /* Sailboat */
200 R(0x0026fa, 0x0026fa, 2), /* Tent */
201 R(0x0026fd, 0x0026fd, 2), /* Fuel Pump */
202 R(0x002705, 0x002705, 2), /* White Heavy Check Mark */
203 R(0x00270a, 0x00270b, 2), /* Raised Fist ..Raised Hand */
204 R(0x002728, 0x002728, 2), /* Sparkles */
205 R(0x00274c, 0x00274c, 2), /* Cross Mark */
206 R(0x00274e, 0x00274e, 2), /* Negative Squared Cross Mark */
207 R(0x002753, 0x002755, 2), /* Black Question Mark Orna..White Exclamation Mark O */
208 R(0x002757, 0x002757, 2), /* Heavy Exclamation Mark Symbol */
209 R(0x002795, 0x002797, 2), /* Heavy Plus Sign ..Heavy Division Sign */
210 R(0x0027b0, 0x0027b0, 2), /* Curly Loop */
211 R(0x0027bf, 0x0027bf, 2), /* Double Curly Loop */
212 R(0x002b1b, 0x002b1c, 2), /* Black Large Square ..White Large Square */
213 R(0x002b50, 0x002b50, 2), /* White Medium Star */
214 R(0x002b55, 0x002b55, 2), /* Heavy Large Circle */
215 R(0x002cef, 0x002cf1, 0), /* Coptic Combining Ni Abov..Coptic Combining Spiritu */
216 R(0x002d7f, 0x002d7f, 0), /* Tifinagh Consonant Joiner */
217 R(0x002de0, 0x002dff, 0), /* Combining Cyrillic Lette..Combining Cyrillic Lette */
218 R(0x002e80, 0x002e99, 2), /* Cjk Radical Repeat ..Cjk Radical Rap */
219 R(0x002e9b, 0x002ef3, 2), /* Cjk Radical Choke ..Cjk Radical C-simplified */
220 R(0x002f00, 0x002fd5, 2), /* Kangxi Radical One ..Kangxi Radical Flute */
221 R(0x002ff0, 0x003029, 2), /* Ideographic Description ..Hangzhou Numeral Nine */
222 R(0x00302a, 0x00302f, 0), /* Ideographic Level Tone M..Hangul Double Dot Tone M */
223 R(0x003030, 0x00303e, 2), /* Wavy Dash ..Ideographic Variation In */
224 R(0x003041, 0x003096, 2), /* Hiragana Letter Small A ..Hiragana Letter Small Ke */
225 R(0x003099, 0x00309a, 0), /* Combining Katakana-hirag..Combining Katakana-hirag */
226 R(0x00309b, 0x0030ff, 2), /* Katakana-hiragana Voiced..Katakana Digraph Koto */
227 R(0x003105, 0x00312f, 2), /* Bopomofo Letter B ..Bopomofo Letter Nn */
228 R(0x003131, 0x00318e, 2), /* Hangul Letter Kiyeok ..Hangul Letter Araeae */
229 R(0x003190, 0x0031e3, 2), /* Ideographic Annotation L..Cjk Stroke Q */
230 R(0x0031ef, 0x00321e, 2), /* nil ..Parenthesized Korean Cha */
231 R(0x003220, 0x003247, 2), /* Parenthesized Ideograph ..Circled Ideograph Koto */
232 R(0x003250, 0x004dbf, 2), /* Partnership Sign ..Cjk Unified Ideograph-4d */
233 R(0x004e00, 0x00a48c, 2), /* Cjk Unified Ideograph-4e..Yi Syllable Yyr */
234 R(0x00a490, 0x00a4c6, 2), /* Yi Radical Qot ..Yi Radical Ke */
235 R(0x00a66f, 0x00a672, 0), /* Combining Cyrillic Vzmet..Combining Cyrillic Thous */
236 R(0x00a674, 0x00a67d, 0), /* Combining Cyrillic Lette..Combining Cyrillic Payer */
237 R(0x00a69e, 0x00a69f, 0), /* Combining Cyrillic Lette..Combining Cyrillic Lette */
238 R(0x00a6f0, 0x00a6f1, 0), /* Bamum Combining Mark Koq..Bamum Combining Mark Tuk */
239 R(0x00a802, 0x00a802, 0), /* Syloti Nagri Sign Dvisvara */
240 R(0x00a806, 0x00a806, 0), /* Syloti Nagri Sign Hasanta */
241 R(0x00a80b, 0x00a80b, 0), /* Syloti Nagri Sign Anusvara */
242 R(0x00a823, 0x00a827, 0), /* Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign */
243 R(0x00a82c, 0x00a82c, 0), /* Syloti Nagri Sign Alternate Hasanta */
244 R(0x00a880, 0x00a881, 0), /* Saurashtra Sign Anusvara..Saurashtra Sign Visarga */
245 R(0x00a8b4, 0x00a8c5, 0), /* Saurashtra Consonant Sig..Saurashtra Sign Candrabi */
246 R(0x00a8e0, 0x00a8f1, 0), /* Combining Devanagari Dig..Combining Devanagari Sig */
247 R(0x00a8ff, 0x00a8ff, 0), /* Devanagari Vowel Sign Ay */
248 R(0x00a926, 0x00a92d, 0), /* Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop */
249 R(0x00a947, 0x00a953, 0), /* Rejang Vowel Sign I ..Rejang Virama */
250 R(0x00a960, 0x00a97c, 2), /* Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo */
251 R(0x00a980, 0x00a983, 0), /* Javanese Sign Panyangga ..Javanese Sign Wignyan */
252 R(0x00a9b3, 0x00a9c0, 0), /* Javanese Sign Cecak Telu..Javanese Pangkon */
253 R(0x00a9e5, 0x00a9e5, 0), /* Myanmar Sign Shan Saw */
254 R(0x00aa29, 0x00aa36, 0), /* Cham Vowel Sign Aa ..Cham Consonant Sign Wa */
255 R(0x00aa43, 0x00aa43, 0), /* Cham Consonant Sign Final Ng */
256 R(0x00aa4c, 0x00aa4d, 0), /* Cham Consonant Sign Fina..Cham Consonant Sign Fina */
257 R(0x00aa7b, 0x00aa7d, 0), /* Myanmar Sign Pao Karen T..Myanmar Sign Tai Laing T */
258 R(0x00aab0, 0x00aab0, 0), /* Tai Viet Mai Kang */
259 R(0x00aab2, 0x00aab4, 0), /* Tai Viet Vowel I ..Tai Viet Vowel U */
260 R(0x00aab7, 0x00aab8, 0), /* Tai Viet Mai Khit ..Tai Viet Vowel Ia */
261 R(0x00aabe, 0x00aabf, 0), /* Tai Viet Vowel Am ..Tai Viet Tone Mai Ek */
262 R(0x00aac1, 0x00aac1, 0), /* Tai Viet Tone Mai Tho */
263 R(0x00aaeb, 0x00aaef, 0), /* Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign */
264 R(0x00aaf5, 0x00aaf6, 0), /* Meetei Mayek Vowel Sign ..Meetei Mayek Virama */
265 R(0x00abe3, 0x00abea, 0), /* Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign */
266 R(0x00abec, 0x00abed, 0), /* Meetei Mayek Lum Iyek ..Meetei Mayek Apun Iyek */
267 R(0x00ac00, 0x00d7a3, 2), /* Hangul Syllable Ga ..Hangul Syllable Hih */
268 R(0x00d7b0, 0x00d7ff, 0), /* Hangul Jungseong O-yeo .. nil */
269 R(0x00f900, 0x00faff, 2), /* Cjk Compatibility Ideogr.. nil */
270 R(0x00fb1e, 0x00fb1e, 0), /* Hebrew Point Judeo-spanish Varika */
271 R(0x00fe00, 0x00fe0f, 0), /* Variation Selector-1 ..Variation Selector-16 */
272 R(0x00fe10, 0x00fe19, 2), /* Presentation Form For Ve..Presentation Form For Ve */
273 R(0x00fe20, 0x00fe2f, 0), /* Combining Ligature Left ..Combining Cyrillic Titlo */
274 R(0x00fe30, 0x00fe52, 2), /* Presentation Form For Ve..Small Full Stop */
275 R(0x00fe54, 0x00fe66, 2), /* Small Semicolon ..Small Equals Sign */
276 R(0x00fe68, 0x00fe6b, 2), /* Small Reverse Solidus ..Small Commercial At */
277 R(0x00feff, 0x00feff, 0), /* Zero Width No-break Space */
278 R(0x00ff01, 0x00ff60, 2), /* Fullwidth Exclamation Ma..Fullwidth Right White Pa */
279 R(0x00ffe0, 0x00ffe6, 2), /* Fullwidth Cent Sign ..Fullwidth Won Sign */
280 R(0x00fff9, 0x00fffb, 0), /* Interlinear Annotation A..Interlinear Annotation T */
281 R(0x0101fd, 0x0101fd, 0), /* Phaistos Disc Sign Combining Oblique Stroke */
282 R(0x0102e0, 0x0102e0, 0), /* Coptic Epact Thousands Mark */
283 R(0x010376, 0x01037a, 0), /* Combining Old Permic Let..Combining Old Permic Let */
284 R(0x010a01, 0x010a03, 0), /* Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo */
285 R(0x010a05, 0x010a06, 0), /* Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O */
286 R(0x010a0c, 0x010a0f, 0), /* Kharoshthi Vowel Length ..Kharoshthi Sign Visarga */
287 R(0x010a38, 0x010a3a, 0), /* Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo */
288 R(0x010a3f, 0x010a3f, 0), /* Kharoshthi Virama */
289 R(0x010ae5, 0x010ae6, 0), /* Manichaean Abbreviation ..Manichaean Abbreviation */
290 R(0x010d24, 0x010d27, 0), /* Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas */
291 R(0x010eab, 0x010eac, 0), /* Yezidi Combining Hamza M..Yezidi Combining Madda M */
292 R(0x010efd, 0x010eff, 0), /* Arabic Small Low Word Sa..Arabic Small Low Word Ma */
293 R(0x010f46, 0x010f50, 0), /* Sogdian Combining Dot Be..Sogdian Combining Stroke */
294 R(0x010f82, 0x010f85, 0), /* Old Uyghur Combining Dot..Old Uyghur Combining Two */
295 R(0x011000, 0x011002, 0), /* Brahmi Sign Candrabindu ..Brahmi Sign Visarga */
296 R(0x011038, 0x011046, 0), /* Brahmi Vowel Sign Aa ..Brahmi Virama */
297 R(0x011070, 0x011070, 0), /* Brahmi Sign Old Tamil Virama */
298 R(0x011073, 0x011074, 0), /* Brahmi Vowel Sign Old Ta..Brahmi Vowel Sign Old Ta */
299 R(0x01107f, 0x011082, 0), /* Brahmi Number Joiner ..Kaithi Sign Visarga */
300 R(0x0110b0, 0x0110ba, 0), /* Kaithi Vowel Sign Aa ..Kaithi Sign Nukta */
301 R(0x0110bd, 0x0110bd, 0), /* Kaithi Number Sign */
302 R(0x0110c2, 0x0110c2, 0), /* Kaithi Vowel Sign Vocalic R */
303 R(0x0110cd, 0x0110cd, 0), /* Kaithi Number Sign Above */
304 R(0x011100, 0x011102, 0), /* Chakma Sign Candrabindu ..Chakma Sign Visarga */
305 R(0x011127, 0x011134, 0), /* Chakma Vowel Sign A ..Chakma Maayyaa */
306 R(0x011145, 0x011146, 0), /* Chakma Vowel Sign Aa ..Chakma Vowel Sign Ei */
307 R(0x011173, 0x011173, 0), /* Mahajani Sign Nukta */
308 R(0x011180, 0x011182, 0), /* Sharada Sign Candrabindu..Sharada Sign Visarga */
309 R(0x0111b3, 0x0111c0, 0), /* Sharada Vowel Sign Aa ..Sharada Sign Virama */
310 R(0x0111c9, 0x0111cc, 0), /* Sharada Sandhi Mark ..Sharada Extra Short Vowe */
311 R(0x0111ce, 0x0111cf, 0), /* Sharada Vowel Sign Prish..Sharada Sign Inverted Ca */
312 R(0x01122c, 0x011237, 0), /* Khojki Vowel Sign Aa ..Khojki Sign Shadda */
313 R(0x01123e, 0x01123e, 0), /* Khojki Sign Sukun */
314 R(0x011241, 0x011241, 0), /* Khojki Vowel Sign Vocalic R */
315 R(0x0112df, 0x0112ea, 0), /* Khudawadi Sign Anusvara ..Khudawadi Sign Virama */
316 R(0x011300, 0x011303, 0), /* Grantha Sign Combining A..Grantha Sign Visarga */
317 R(0x01133b, 0x01133c, 0), /* Combining Bindu Below ..Grantha Sign Nukta */
318 R(0x01133e, 0x011344, 0), /* Grantha Vowel Sign Aa ..Grantha Vowel Sign Vocal */
319 R(0x011347, 0x011348, 0), /* Grantha Vowel Sign Ee ..Grantha Vowel Sign Ai */
320 R(0x01134b, 0x01134d, 0), /* Grantha Vowel Sign Oo ..Grantha Sign Virama */
321 R(0x011357, 0x011357, 0), /* Grantha Au Length Mark */
322 R(0x011362, 0x011363, 0), /* Grantha Vowel Sign Vocal..Grantha Vowel Sign Vocal */
323 R(0x011366, 0x01136c, 0), /* Combining Grantha Digit ..Combining Grantha Digit */
324 R(0x011370, 0x011374, 0), /* Combining Grantha Letter..Combining Grantha Letter */
325 R(0x011435, 0x011446, 0), /* Newa Vowel Sign Aa ..Newa Sign Nukta */
326 R(0x01145e, 0x01145e, 0), /* Newa Sandhi Mark */
327 R(0x0114b0, 0x0114c3, 0), /* Tirhuta Vowel Sign Aa ..Tirhuta Sign Nukta */
328 R(0x0115af, 0x0115b5, 0), /* Siddham Vowel Sign Aa ..Siddham Vowel Sign Vocal */
329 R(0x0115b8, 0x0115c0, 0), /* Siddham Vowel Sign E ..Siddham Sign Nukta */
330 R(0x0115dc, 0x0115dd, 0), /* Siddham Vowel Sign Alter..Siddham Vowel Sign Alter */
331 R(0x011630, 0x011640, 0), /* Modi Vowel Sign Aa ..Modi Sign Ardhacandra */
332 R(0x0116ab, 0x0116b7, 0), /* Takri Sign Anusvara ..Takri Sign Nukta */
333 R(0x01171d, 0x01172b, 0), /* Ahom Consonant Sign Medi..Ahom Sign Killer */
334 R(0x01182c, 0x01183a, 0), /* Dogra Vowel Sign Aa ..Dogra Sign Nukta */
335 R(0x011930, 0x011935, 0), /* Dives Akuru Vowel Sign A..Dives Akuru Vowel Sign E */
336 R(0x011937, 0x011938, 0), /* Dives Akuru Vowel Sign A..Dives Akuru Vowel Sign O */
337 R(0x01193b, 0x01193e, 0), /* Dives Akuru Sign Anusvar..Dives Akuru Virama */
338 R(0x011940, 0x011940, 0), /* Dives Akuru Medial Ya */
339 R(0x011942, 0x011943, 0), /* Dives Akuru Medial Ra ..Dives Akuru Sign Nukta */
340 R(0x0119d1, 0x0119d7, 0), /* Nandinagari Vowel Sign A..Nandinagari Vowel Sign V */
341 R(0x0119da, 0x0119e0, 0), /* Nandinagari Vowel Sign E..Nandinagari Sign Virama */
342 R(0x0119e4, 0x0119e4, 0), /* Nandinagari Vowel Sign Prishthamatra E */
343 R(0x011a01, 0x011a0a, 0), /* Zanabazar Square Vowel S..Zanabazar Square Vowel L */
344 R(0x011a33, 0x011a39, 0), /* Zanabazar Square Final C..Zanabazar Square Sign Vi */
345 R(0x011a3b, 0x011a3e, 0), /* Zanabazar Square Cluster..Zanabazar Square Cluster */
346 R(0x011a47, 0x011a47, 0), /* Zanabazar Square Subjoiner */
347 R(0x011a51, 0x011a5b, 0), /* Soyombo Vowel Sign I ..Soyombo Vowel Length Mar */
348 R(0x011a8a, 0x011a99, 0), /* Soyombo Final Consonant ..Soyombo Subjoiner */
349 R(0x011c2f, 0x011c36, 0), /* Bhaiksuki Vowel Sign Aa ..Bhaiksuki Vowel Sign Voc */
350 R(0x011c38, 0x011c3f, 0), /* Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Virama */
351 R(0x011c92, 0x011ca7, 0), /* Marchen Subjoined Letter..Marchen Subjoined Letter */
352 R(0x011ca9, 0x011cb6, 0), /* Marchen Subjoined Letter..Marchen Sign Candrabindu */
353 R(0x011d31, 0x011d36, 0), /* Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign */
354 R(0x011d3a, 0x011d3a, 0), /* Masaram Gondi Vowel Sign E */
355 R(0x011d3c, 0x011d3d, 0), /* Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign */
356 R(0x011d3f, 0x011d45, 0), /* Masaram Gondi Vowel Sign..Masaram Gondi Virama */
357 R(0x011d47, 0x011d47, 0), /* Masaram Gondi Ra-kara */
358 R(0x011d8a, 0x011d8e, 0), /* Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign */
359 R(0x011d90, 0x011d91, 0), /* Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign */
360 R(0x011d93, 0x011d97, 0), /* Gunjala Gondi Vowel Sign..Gunjala Gondi Virama */
361 R(0x011ef3, 0x011ef6, 0), /* Makasar Vowel Sign I ..Makasar Vowel Sign O */
362 R(0x011f00, 0x011f01, 0), /* Kawi Sign Candrabindu ..Kawi Sign Anusvara */
363 R(0x011f03, 0x011f03, 0), /* Kawi Sign Visarga */
364 R(0x011f34, 0x011f3a, 0), /* Kawi Vowel Sign Aa ..Kawi Vowel Sign Vocalic */
365 R(0x011f3e, 0x011f42, 0), /* Kawi Vowel Sign E ..Kawi Conjoiner */
366 R(0x013430, 0x013440, 0), /* Egyptian Hieroglyph Vert..Egyptian Hieroglyph Mirr */
367 R(0x013447, 0x013455, 0), /* Egyptian Hieroglyph Modi..Egyptian Hieroglyph Modi */
368 R(0x016af0, 0x016af4, 0), /* Bassa Vah Combining High..Bassa Vah Combining High */
369 R(0x016b30, 0x016b36, 0), /* Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta */
370 R(0x016f4f, 0x016f4f, 0), /* Miao Sign Consonant Modifier Bar */
371 R(0x016f51, 0x016f87, 0), /* Miao Sign Aspiration ..Miao Vowel Sign Ui */
372 R(0x016f8f, 0x016f92, 0), /* Miao Tone Right ..Miao Tone Below */
373 R(0x016fe0, 0x016fe3, 2), /* Tangut Iteration Mark ..Old Chinese Iteration Ma */
374 R(0x016fe4, 0x016fe4, 0), /* Khitan Small Script Filler */
375 R(0x016ff0, 0x016ff1, 0), /* Vietnamese Alternate Rea..Vietnamese Alternate Rea */
376 R(0x017000, 0x0187f7, 2), /* nil */
377 R(0x018800, 0x018cd5, 2), /* Tangut Component-001 ..Khitan Small Script Char */
378 R(0x018d00, 0x018d08, 2), /* nil */
379 R(0x01aff0, 0x01aff3, 2), /* Katakana Letter Minnan T..Katakana Letter Minnan T */
380 R(0x01aff5, 0x01affb, 2), /* Katakana Letter Minnan T..Katakana Letter Minnan N */
381 R(0x01affd, 0x01affe, 2), /* Katakana Letter Minnan N..Katakana Letter Minnan N */
382 R(0x01b000, 0x01b122, 2), /* Katakana Letter Archaic ..Katakana Letter Archaic */
383 R(0x01b132, 0x01b132, 2), /* Hiragana Letter Small Ko */
384 R(0x01b150, 0x01b152, 2), /* Hiragana Letter Small Wi..Hiragana Letter Small Wo */
385 R(0x01b155, 0x01b155, 2), /* Katakana Letter Small Ko */
386 R(0x01b164, 0x01b167, 2), /* Katakana Letter Small Wi..Katakana Letter Small N */
387 R(0x01b170, 0x01b2fb, 2), /* Nushu Character-1b170 ..Nushu Character-1b2fb */
388 R(0x01bc9d, 0x01bc9e, 0), /* Duployan Thick Letter Se..Duployan Double Mark */
389 R(0x01bca0, 0x01bca3, 0), /* Shorthand Format Letter ..Shorthand Format Up Step */
390 R(0x01cf00, 0x01cf2d, 0), /* Znamenny Combining Mark ..Znamenny Combining Mark */
391 R(0x01cf30, 0x01cf46, 0), /* Znamenny Combining Tonal..Znamenny Priznak Modifie */
392 R(0x01d165, 0x01d169, 0), /* Musical Symbol Combining..Musical Symbol Combining */
393 R(0x01d16d, 0x01d182, 0), /* Musical Symbol Combining..Musical Symbol Combining */
394 R(0x01d185, 0x01d18b, 0), /* Musical Symbol Combining..Musical Symbol Combining */
395 R(0x01d1aa, 0x01d1ad, 0), /* Musical Symbol Combining..Musical Symbol Combining */
396 R(0x01d242, 0x01d244, 0), /* Combining Greek Musical ..Combining Greek Musical */
397 R(0x01da00, 0x01da36, 0), /* Signwriting Head Rim ..Signwriting Air Sucking */
398 R(0x01da3b, 0x01da6c, 0), /* Signwriting Mouth Closed..Signwriting Excitement */
399 R(0x01da75, 0x01da75, 0), /* Signwriting Upper Body Tilting From Hip Joints */
400 R(0x01da84, 0x01da84, 0), /* Signwriting Location Head Neck */
401 R(0x01da9b, 0x01da9f, 0), /* Signwriting Fill Modifie..Signwriting Fill Modifie */
402 R(0x01daa1, 0x01daaf, 0), /* Signwriting Rotation Mod..Signwriting Rotation Mod */
403 R(0x01e000, 0x01e006, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
404 R(0x01e008, 0x01e018, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
405 R(0x01e01b, 0x01e021, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
406 R(0x01e023, 0x01e024, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
407 R(0x01e026, 0x01e02a, 0), /* Combining Glagolitic Let..Combining Glagolitic Let */
408 R(0x01e08f, 0x01e08f, 0), /* Combining Cyrillic Small Letter Byelorussian-ukr */
409 R(0x01e130, 0x01e136, 0), /* Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T */
410 R(0x01e2ae, 0x01e2ae, 0), /* Toto Sign Rising Tone */
411 R(0x01e2ec, 0x01e2ef, 0), /* Wancho Tone Tup ..Wancho Tone Koini */
412 R(0x01e4ec, 0x01e4ef, 0), /* Nag Mundari Sign Muhor ..Nag Mundari Sign Sutuh */
413 R(0x01e8d0, 0x01e8d6, 0), /* Mende Kikakui Combining ..Mende Kikakui Combining */
414 R(0x01e944, 0x01e94a, 0), /* Adlam Alif Lengthener ..Adlam Nukta */
415 R(0x01f004, 0x01f004, 2), /* Mahjong Tile Red Dragon */
416 R(0x01f0cf, 0x01f0cf, 2), /* Playing Card Black Joker */
417 R(0x01f18e, 0x01f18e, 2), /* Negative Squared Ab */
418 R(0x01f191, 0x01f19a, 2), /* Squared Cl ..Squared Vs */
419 R(0x01f200, 0x01f202, 2), /* Square Hiragana Hoka ..Squared Katakana Sa */
420 R(0x01f210, 0x01f23b, 2), /* Squared Cjk Unified Ideo..Squared Cjk Unified Ideo */
421 R(0x01f240, 0x01f248, 2), /* Tortoise Shell Bracketed..Tortoise Shell Bracketed */
422 R(0x01f250, 0x01f251, 2), /* Circled Ideograph Advant..Circled Ideograph Accept */
423 R(0x01f260, 0x01f265, 2), /* Rounded Symbol For Fu ..Rounded Symbol For Cai */
424 R(0x01f300, 0x01f320, 2), /* Cyclone ..Shooting Star */
425 R(0x01f32d, 0x01f335, 2), /* Hot Dog ..Cactus */
426 R(0x01f337, 0x01f37c, 2), /* Tulip ..Baby Bottle */
427 R(0x01f37e, 0x01f393, 2), /* Bottle With Popping Cork..Graduation Cap */
428 R(0x01f3a0, 0x01f3ca, 2), /* Carousel Horse ..Swimmer */
429 R(0x01f3cf, 0x01f3d3, 2), /* Cricket Bat And Ball ..Table Tennis Paddle And */
430 R(0x01f3e0, 0x01f3f0, 2), /* House Building ..European Castle */
431 R(0x01f3f4, 0x01f3f4, 2), /* Waving Black Flag */
432 R(0x01f3f8, 0x01f3fa, 2), /* Badminton Racquet And Sh..Amphora */
433 R(0x01f3fb, 0x01f3ff, 0), /* Emoji Modifier Fitzpatri..Emoji Modifier Fitzpatri */
434 R(0x01f400, 0x01f43e, 2), /* Rat ..Paw Prints */
435 R(0x01f440, 0x01f440, 2), /* Eyes */
436 R(0x01f442, 0x01f4fc, 2), /* Ear ..Videocassette */
437 R(0x01f4ff, 0x01f53d, 2), /* Prayer Beads ..Down-pointing Small Red */
438 R(0x01f54b, 0x01f54e, 2), /* Kaaba ..Menorah With Nine Branch */
439 R(0x01f550, 0x01f567, 2), /* Clock Face One Oclock ..Clock Face Twelve-thirty */
440 R(0x01f57a, 0x01f57a, 2), /* Man Dancing */
441 R(0x01f595, 0x01f596, 2), /* Reversed Hand With Middl..Raised Hand With Part Be */
442 R(0x01f5a4, 0x01f5a4, 2), /* Black Heart */
443 R(0x01f5fb, 0x01f64f, 2), /* Mount Fuji ..Person With Folded Hands */
444 R(0x01f680, 0x01f6c5, 2), /* Rocket ..Left Luggage */
445 R(0x01f6cc, 0x01f6cc, 2), /* Sleeping Accommodation */
446 R(0x01f6d0, 0x01f6d2, 2), /* Place Of Worship ..Shopping Trolley */
447 R(0x01f6d5, 0x01f6d7, 2), /* Hindu Temple ..Elevator */
448 R(0x01f6dc, 0x01f6df, 2), /* Wireless ..Ring Buoy */
449 R(0x01f6eb, 0x01f6ec, 2), /* Airplane Departure ..Airplane Arriving */
450 R(0x01f6f4, 0x01f6fc, 2), /* Scooter ..Roller Skate */
451 R(0x01f7e0, 0x01f7eb, 2), /* Large Orange Circle ..Large Brown Square */
452 R(0x01f7f0, 0x01f7f0, 2), /* Heavy Equals Sign */
453 R(0x01f90c, 0x01f93a, 2), /* Pinched Fingers ..Fencer */
454 R(0x01f93c, 0x01f945, 2), /* Wrestlers ..Goal Net */
455 R(0x01f947, 0x01f9ff, 2), /* First Place Medal ..Nazar Amulet */
456 R(0x01fa70, 0x01fa7c, 2), /* Ballet Shoes ..Crutch */
457 R(0x01fa80, 0x01fa88, 2), /* Yo-yo ..Flute */
458 R(0x01fa90, 0x01fabd, 2), /* Ringed Planet ..Wing */
459 R(0x01fabf, 0x01fac5, 2), /* Goose ..Person With Crown */
460 R(0x01face, 0x01fadb, 2), /* Moose ..Pea Pod */
461 R(0x01fae0, 0x01fae8, 2), /* Melting Face ..Shaking Face */
462 R(0x01faf0, 0x01faf8, 2), /* Hand With Index Finger A..Rightwards Pushing Hand */
463 R(0x020000, 0x027fff, 2), /* Cjk Unified Ideograph-20.. nil */
464 R(0x028000, 0x02fffd, 2), /* (continued...) */
465 R(0x030000, 0x037fff, 2), /* Cjk Unified Ideograph-30.. nil */
466 R(0x038000, 0x03fffd, 2), /* (continued...) */
467 R(0x0e0001, 0x0e0001, 0), /* Language Tag */
468 R(0x0e0020, 0x0e007f, 0), /* Tag Space ..Cancel Tag */
469 R(0x0e0100, 0x0e01ef, 0), /* Variation Selector-17 ..Variation Selector-256 */
470 #undef R
471 };
472
473 /* planes[p], planes[p+1] are [from, to) at "ranges" for plane p */
474 static const uint16_t planes[/* 18 */] = {
475 0, 261, 443, 445, 447, 447, 447, 447, 447, 447, 447, 447,
476 447, 447, 447, 450, 450, 450,
477 };
478
479 /******* END OF STATIC DATA *******/
480
481 uint32_t p, bot, top;
482
483 /* 0:0, 1..31:-1 (C0), 32..126:1 (isprint), 127..159:-1 (DEL, C1) */
484 if (ucs < 160)
485 return ((ucs + 1) & 127) > 32 ? 1 : ucs ? -1 : 0;
486
487 /* out of range for "planes" (and non-unicode), non-characters. */
488 /* (some also test surrogate halves, but not required by POSIX) */
489 if (ucs > 0x10ffff || (ucs & 0xfffe) == 0xfffe)
490 return -1;
491
492 p = ucs >> 16;
493 ucs &= 0xffff;
494
495 for (bot = planes[p], top = planes[p+1]; bot < top; ) {
496 uint32_t mid = (bot + top) / 2;
497 if (ucs < ranges[mid].first)
498 top = mid;
499 else if (ucs > ranges[mid].first + ranges[mid].difflast)
500 bot = mid + 1;
501 else
502 return 2 * ranges[mid].iswide;
503 }
504
505 return 1;
506} /* wcwidth - Unicode 15.1.0 */
diff --git a/libbb/xatonum_template.c b/libbb/xatonum_template.c
index e0471983c..0d5d35b47 100644
--- a/libbb/xatonum_template.c
+++ b/libbb/xatonum_template.c
@@ -67,7 +67,7 @@ unsigned type FAST_FUNC xstrtou(_range_sfx)(const char *numstr, int base,
67 if (r >= lower && r <= upper) 67 if (r >= lower && r <= upper)
68 return r; 68 return r;
69 range: 69 range:
70 bb_error_msg_and_die("number %s is not in %llu..%llu range", 70 bb_error_msg_and_die("number %s is not in %"LL_FMT"u..%"LL_FMT"u range",
71 numstr, (unsigned long long)lower, 71 numstr, (unsigned long long)lower,
72 (unsigned long long)upper); 72 (unsigned long long)upper);
73 inval: 73 inval:
@@ -144,7 +144,8 @@ type FAST_FUNC xstrto(_range_sfx)(const char *numstr, int base,
144 } 144 }
145 145
146 if (r < lower || r > upper) { 146 if (r < lower || r > upper) {
147 bb_error_msg_and_die("number %s is not in %lld..%lld range", 147 bb_error_msg_and_die("number %s is not in "
148 "%"LL_FMT"d..%"LL_FMT"d range",
148 numstr, (long long)lower, (long long)upper); 149 numstr, (long long)lower, (long long)upper);
149 } 150 }
150 151
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 0e0b247b8..65b1cb8de 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -71,6 +71,7 @@ int FAST_FUNC setsockopt_bindtodevice(int fd UNUSED_PARAM,
71} 71}
72#endif 72#endif
73 73
74#if !ENABLE_PLATFORM_MINGW32
74static len_and_sockaddr* get_lsa(int fd, int (*get_name)(int fd, struct sockaddr *addr, socklen_t *addrlen)) 75static len_and_sockaddr* get_lsa(int fd, int (*get_name)(int fd, struct sockaddr *addr, socklen_t *addrlen))
75{ 76{
76 len_and_sockaddr lsa; 77 len_and_sockaddr lsa;
@@ -99,16 +100,17 @@ len_and_sockaddr* FAST_FUNC get_peer_lsa(int fd)
99{ 100{
100 return get_lsa(fd, getpeername); 101 return get_lsa(fd, getpeername);
101} 102}
103#endif
102 104
103void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) 105void FAST_FUNC xconnect(int s, const struct sockaddr *saddr, socklen_t addrlen)
104{ 106{
105 if (connect(s, s_addr, addrlen) < 0) { 107 if (connect(s, saddr, addrlen) < 0) {
106 if (ENABLE_FEATURE_CLEAN_UP) 108 if (ENABLE_FEATURE_CLEAN_UP)
107 close(s); 109 close(s);
108 if (s_addr->sa_family == AF_INET) 110 if (saddr->sa_family == AF_INET)
109 bb_perror_msg_and_die("%s (%s)", 111 bb_perror_msg_and_die("%s (%s)",
110 "can't connect to remote host", 112 "can't connect to remote host",
111 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr)); 113 inet_ntoa(((struct sockaddr_in *)saddr)->sin_addr));
112 bb_simple_perror_msg_and_die("can't connect to remote host"); 114 bb_simple_perror_msg_and_die("can't connect to remote host");
113 } 115 }
114} 116}
@@ -348,6 +350,10 @@ int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, int family, int sock_type)
348#if ENABLE_FEATURE_IPV6 350#if ENABLE_FEATURE_IPV6
349 fd = socket(AF_INET6, sock_type, 0); 351 fd = socket(AF_INET6, sock_type, 0);
350 if (fd >= 0) { 352 if (fd >= 0) {
353#if ENABLE_PLATFORM_MINGW32
354 DWORD buffer = 0;
355 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &buffer, sizeof(DWORD));
356#endif
351 family = AF_INET6; 357 family = AF_INET6;
352 goto done; 358 goto done;
353 } 359 }
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index b03af8542..7df1a4cd3 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -23,6 +23,7 @@
23#include "libbb.h" 23#include "libbb.h"
24 24
25/* Turn on nonblocking I/O on a fd */ 25/* Turn on nonblocking I/O on a fd */
26#if !ENABLE_PLATFORM_MINGW32
26int FAST_FUNC ndelay_on(int fd) 27int FAST_FUNC ndelay_on(int fd)
27{ 28{
28 int flags = fcntl(fd, F_GETFL); 29 int flags = fcntl(fd, F_GETFL);
@@ -45,6 +46,7 @@ void FAST_FUNC close_on_exec_on(int fd)
45{ 46{
46 fcntl(fd, F_SETFD, FD_CLOEXEC); 47 fcntl(fd, F_SETFD, FD_CLOEXEC);
47} 48}
49#endif
48 50
49char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) 51char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src)
50{ 52{
@@ -219,7 +221,12 @@ off_t FAST_FUNC fdlength(int fd)
219 221
220int FAST_FUNC bb_putchar_stderr(char ch) 222int FAST_FUNC bb_putchar_stderr(char ch)
221{ 223{
224#if ENABLE_PLATFORM_MINGW32 && !defined(_UCRT)
225 // Workaround for problems with stderr in MSVCRT
226 return fputc(ch, stderr);
227#else
222 return write(STDERR_FILENO, &ch, 1); 228 return write(STDERR_FILENO, &ch, 1);
229#endif
223} 230}
224 231
225ssize_t FAST_FUNC full_write1_str(const char *str) 232ssize_t FAST_FUNC full_write1_str(const char *str)
@@ -268,6 +275,7 @@ int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *heigh
268 int err; 275 int err;
269 int close_me = -1; 276 int close_me = -1;
270 277
278#if !ENABLE_PLATFORM_MINGW32
271 if (fd == -1) { 279 if (fd == -1) {
272 if (isatty(STDOUT_FILENO)) 280 if (isatty(STDOUT_FILENO))
273 fd = STDOUT_FILENO; 281 fd = STDOUT_FILENO;
@@ -280,6 +288,7 @@ int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *heigh
280 else 288 else
281 close_me = fd = open("/dev/tty", O_RDONLY); 289 close_me = fd = open("/dev/tty", O_RDONLY);
282 } 290 }
291#endif
283 292
284 win.ws_row = 0; 293 win.ws_row = 0;
285 win.ws_col = 0; 294 win.ws_col = 0;
@@ -314,7 +323,7 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)
314 return tcsetattr(STDIN_FILENO, TCSANOW, tp); 323 return tcsetattr(STDIN_FILENO, TCSANOW, tp);
315} 324}
316 325
317int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct termios *oldterm, int flags) 326int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct termios *oldterm, int flags IF_PLATFORM_MINGW32(UNUSED_PARAM))
318{ 327{
319//TODO: slattach, shell read might be adapted to use this too: grep for "tcsetattr", "[VTIME] = 0" 328//TODO: slattach, shell read might be adapted to use this too: grep for "tcsetattr", "[VTIME] = 0"
320 int r; 329 int r;
@@ -323,6 +332,10 @@ int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct t
323 r = tcgetattr(fd, oldterm); 332 r = tcgetattr(fd, oldterm);
324 *newterm = *oldterm; 333 *newterm = *oldterm;
325 334
335#if ENABLE_PLATFORM_MINGW32
336 newterm->imode &=
337 ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
338#else
326 /* Turn off buffered input (ICANON) 339 /* Turn off buffered input (ICANON)
327 * Turn off echoing (ECHO) 340 * Turn off echoing (ECHO)
328 * and separate echoing of newline (ECHONL, normally off anyway) 341 * and separate echoing of newline (ECHONL, normally off anyway)
@@ -379,6 +392,7 @@ int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct t
379 */ 392 */
380 newterm->c_iflag &= ~(IXOFF|IXON|IXANY|BRKINT|INLCR|ICRNL|IUCLC|IMAXBEL); 393 newterm->c_iflag &= ~(IXOFF|IXON|IXANY|BRKINT|INLCR|ICRNL|IUCLC|IMAXBEL);
381 } 394 }
395#endif
382 return r; 396 return r;
383} 397}
384 398
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 842d10cd2..0ead3b2eb 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -108,6 +108,7 @@ void* FAST_FUNC xmemdup(const void *s, size_t n)
108 return memcpy(xmalloc(n), s, n); 108 return memcpy(xmalloc(n), s, n);
109} 109}
110 110
111#if !ENABLE_PLATFORM_MINGW32
111void* FAST_FUNC mmap_read(int fd, size_t size) 112void* FAST_FUNC mmap_read(int fd, size_t size)
112{ 113{
113 return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 114 return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
@@ -128,6 +129,7 @@ void* FAST_FUNC xmmap_anon(size_t size)
128 bb_die_memory_exhausted(); 129 bb_die_memory_exhausted();
129 return p; 130 return p;
130} 131}
132#endif
131 133
132// Die if we can't open a file and return a FILE* to it. 134// Die if we can't open a file and return a FILE* to it.
133// Notice we haven't got xfread(), This is for use with fscanf() and friends. 135// Notice we haven't got xfread(), This is for use with fscanf() and friends.
@@ -334,7 +336,7 @@ void FAST_FUNC xprint_and_close_file(FILE *file)
334 336
335// Die with an error message if we can't malloc() enough space and do an 337// Die with an error message if we can't malloc() enough space and do an
336// sprintf() into that space. 338// sprintf() into that space.
337char* FAST_FUNC xasprintf(const char *format, ...) 339char* xasprintf(const char *format, ...)
338{ 340{
339 va_list p; 341 va_list p;
340 int r; 342 int r;
@@ -501,6 +503,7 @@ void FAST_FUNC xlisten(int s, int backlog)
501 if (listen(s, backlog)) bb_simple_perror_msg_and_die("listen"); 503 if (listen(s, backlog)) bb_simple_perror_msg_and_die("listen");
502} 504}
503 505
506#if !ENABLE_PLATFORM_MINGW32
504/* Die with an error message if sendto failed. 507/* Die with an error message if sendto failed.
505 * Return bytes sent otherwise */ 508 * Return bytes sent otherwise */
506ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, 509ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct sockaddr *to,
@@ -514,6 +517,7 @@ ssize_t FAST_FUNC xsendto(int s, const void *buf, size_t len, const struct socka
514 } 517 }
515 return ret; 518 return ret;
516} 519}
520#endif
517 521
518// xstat() - a stat() which dies on failure with meaningful error message 522// xstat() - a stat() which dies on failure with meaningful error message
519void FAST_FUNC xstat(const char *name, struct stat *stat_buf) 523void FAST_FUNC xstat(const char *name, struct stat *stat_buf)
@@ -547,7 +551,8 @@ void FAST_FUNC selinux_or_die(void)
547/* not defined, other code must have no calls to it */ 551/* not defined, other code must have no calls to it */
548#endif 552#endif
549 553
550int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) 554#if !ENABLE_PLATFORM_MINGW32
555int ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...)
551{ 556{
552 int ret; 557 int ret;
553 va_list p; 558 va_list p;
@@ -563,7 +568,7 @@ int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, cons
563 return ret; 568 return ret;
564} 569}
565 570
566int FAST_FUNC ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...) 571int ioctl_or_perror(int fd, unsigned request, void *argp, const char *fmt,...)
567{ 572{
568 va_list p; 573 va_list p;
569 int ret = ioctl(fd, request, argp); 574 int ret = ioctl(fd, request, argp);
@@ -711,6 +716,7 @@ void FAST_FUNC xvfork_parent_waits_and_exits(void)
711 } 716 }
712 /* Child continues */ 717 /* Child continues */
713} 718}
719#endif /* !ENABLE_PLATFORM_MINGW32 */
714 720
715// Useful when we do know that pid is valid, and we just want to wait 721// Useful when we do know that pid is valid, and we just want to wait
716// for it to exit. Not existing pid is fatal. waitpid() status is not returned. 722// for it to exit. Not existing pid is fatal. waitpid() status is not returned.
@@ -724,11 +730,13 @@ int FAST_FUNC wait_for_exitstatus(pid_t pid)
724 return exit_status; 730 return exit_status;
725} 731}
726 732
733#if !ENABLE_PLATFORM_MINGW32
727void FAST_FUNC xsettimeofday(const struct timeval *tv) 734void FAST_FUNC xsettimeofday(const struct timeval *tv)
728{ 735{
729 if (settimeofday(tv, NULL)) 736 if (settimeofday(tv, NULL))
730 bb_simple_perror_msg_and_die("settimeofday"); 737 bb_simple_perror_msg_and_die("settimeofday");
731} 738}
739#endif
732 740
733void FAST_FUNC xgettimeofday(struct timeval *tv) 741void FAST_FUNC xgettimeofday(struct timeval *tv)
734{ 742{
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
index 2682f6975..fc10a2939 100644
--- a/libbb/xreadlink.c
+++ b/libbb/xreadlink.c
@@ -17,6 +17,7 @@
17 * NOTE: This function returns a malloced char* that you will have to free 17 * NOTE: This function returns a malloced char* that you will have to free
18 * yourself. 18 * yourself.
19 */ 19 */
20#if !ENABLE_PLATFORM_MINGW32
20char* FAST_FUNC xmalloc_readlink(const char *path) 21char* FAST_FUNC xmalloc_readlink(const char *path)
21{ 22{
22 enum { GROWBY = 80 }; /* how large we will grow strings by */ 23 enum { GROWBY = 80 }; /* how large we will grow strings by */
@@ -38,6 +39,7 @@ char* FAST_FUNC xmalloc_readlink(const char *path)
38 39
39 return buf; 40 return buf;
40} 41}
42#endif
41 43
42/* 44/*
43 * This routine is not the same as realpath(), which 45 * This routine is not the same as realpath(), which
@@ -64,19 +66,26 @@ char* FAST_FUNC xmalloc_follow_symlinks(const char *path)
64 linkpath = xmalloc_readlink(buf); 66 linkpath = xmalloc_readlink(buf);
65 if (!linkpath) { 67 if (!linkpath) {
66 /* not a symlink, or doesn't exist */ 68 /* not a symlink, or doesn't exist */
67 if (errno == EINVAL || errno == ENOENT) 69 if (errno == EINVAL || errno == ENOENT || (ENABLE_PLATFORM_MINGW32 && errno == ENOSYS))
68 return buf; 70 return buf;
69 goto free_buf_ret_null; 71 goto free_buf_ret_null;
70 } 72 }
71 73
72 if (!--looping) { 74 if (!--looping) {
75#if ENABLE_PLATFORM_MINGW32
76 errno = ELOOP;
77#endif
73 free(linkpath); 78 free(linkpath);
74 free_buf_ret_null: 79 free_buf_ret_null:
75 free(buf); 80 free(buf);
76 return NULL; 81 return NULL;
77 } 82 }
78 83
84#if ENABLE_PLATFORM_MINGW32
85 if (is_relative_path(linkpath)) {
86#else
79 if (*linkpath != '/') { 87 if (*linkpath != '/') {
88#endif
80 bufsize += strlen(linkpath); 89 bufsize += strlen(linkpath);
81 buf = xrealloc(buf, bufsize); 90 buf = xrealloc(buf, bufsize);
82 lpc = bb_get_last_path_component_strip(buf); 91 lpc = bb_get_last_path_component_strip(buf);
@@ -149,7 +158,11 @@ char* FAST_FUNC xmalloc_realpath_coreutils(char *path)
149 * $ realpath symlink 158 * $ realpath symlink
150 * /usr/bin/qwe 159 * /usr/bin/qwe
151 */ 160 */
161#if ENABLE_PLATFORM_MINGW32
162 if (is_relative_path(target)) {
163#else
152 if (target[0] != '/') { 164 if (target[0] != '/') {
165#endif
153 /* 166 /*
154 * $ ln -s target_does_not_exist symlink 167 * $ ln -s target_does_not_exist symlink
155 * $ readlink -f symlink 168 * $ readlink -f symlink
@@ -168,6 +181,35 @@ char* FAST_FUNC xmalloc_realpath_coreutils(char *path)
168 return buf; 181 return buf;
169 } 182 }
170 183
184#if ENABLE_PLATFORM_MINGW32
185 /* ignore leading and trailing slashes */
186 /* but keep leading slashes of UNC path */
187 if (!is_unc_path(path)) {
188 while (is_dir_sep(path[0]) && is_dir_sep(path[1]))
189 ++path;
190 }
191 i = strlen(path) - 1;
192 while (i > 0 && is_dir_sep(path[i]))
193 i--;
194 c = path[i + 1];
195 path[i + 1] = '\0';
196
197 last_slash = get_last_slash(path);
198 if (last_slash == path + root_len(path))
199 buf = xstrdup(path);
200 else if (last_slash) {
201 char c2 = *last_slash;
202 *last_slash = '\0';
203 buf = xmalloc_realpath(path);
204 *last_slash++ = c2;
205 if (buf) {
206 unsigned len = strlen(buf);
207 buf = xrealloc(buf, len + strlen(last_slash) + 2);
208 buf[len++] = c2;
209 strcpy(buf + len, last_slash);
210 }
211 }
212#else
171 /* ignore leading and trailing slashes */ 213 /* ignore leading and trailing slashes */
172 while (path[0] == '/' && path[1] == '/') 214 while (path[0] == '/' && path[1] == '/')
173 ++path; 215 ++path;
@@ -191,6 +233,7 @@ char* FAST_FUNC xmalloc_realpath_coreutils(char *path)
191 strcpy(buf + len, last_slash); 233 strcpy(buf + len, last_slash);
192 } 234 }
193 } 235 }
236#endif
194 path[i + 1] = c; 237 path[i + 1] = c;
195 } 238 }
196 239